Commit Graph
71 Commits
Author SHA1 Message Date
hoelee ec2b89130b post: when a proxy timeout returns HTML instead of JSON (EN+ZH)
Deploy / build (push) Successful in 24s
499 post-mortem: an O(n) library audit inside a polled GET on a one-core
cgroup, three reverse-proxy hops, and the status no monitor watches.

- measured: 13.6 s idle / 17.7-98.5-35.8 s probes / 76-2507 s under load
- evidence triad: 7x 499 @ portal, zero app-log entries, in-container repro
- fix: 300 s TTL cache + single-flight refresh + refreshing/cached_at flags,
  text-first client reader, ?refresh=1
- result: cached path 200 in 0.24-0.36 s (median 0.26 s)
- art: ideogram4 base frame + 4 derived targets, art-meta evidence line
- LinkedIn companion: docs/linkedin/batch-07-linkedin-posts.md
2026-10-28 09:00:11 +08:00
hoelee 8a581dc68b feat(posts): publish batch-06 posts 01 & 02, render full visual asset suites for all 5 posts 2026-10-27 22:30:31 +08:00
hoelee c51885d00a docs: finalize batch-06 consultant review pack with 5.0 full pass approval 2026-10-27 22:20:42 +08:00
hoelee c49c4ff725 feat(posts): adopt consultant rulings on decoupled slug, decoding contracts, and pillow laplacian filter 2026-10-27 21:48:24 +08:00
hoelee 0e31199510 fix(posts): apply consultant review corrections to batch-06 and update review pack v2.0 2026-10-27 20:53:31 +08:00
hoelee 041471d25e feat(listing): portfolio-first archive, case-study hero, row action links
/posts/ and /zh/posts/ become hybrid: three fixed-slug flagship cards above the
complete year/month archive, with the flagship block collapsing (inert, h=0) as
soon as the reader filters. /categories/case-studies/ becomes a portfolio: compact
two-column hero with a 21:9 deterministic topology banner, flagship ordering from
lib/portfolio.ts instead of pubDate, and one measured pill per card.

Also fixes what the screenshot review turned up: ZH archive rows and category chips
were printing raw English slugs, the two chip strips were unlabelled and read as one
list with a duplicated 'devops', card meta rows broke rhythm past four tags, the nav
had no current-section indicator, and mobile title links were under the 44px tap
minimum. scripts/probe-layout.mjs is the repeatable gate: 72/72 page x viewport
checks and the collapse test.
2026-10-27 04:06:54 +08:00
hoelee 86edd40c74 docs(review): consultant audit tracker, 10 post batches and the posts/case-studies upgrade plan
- docs/consultant-review/: review brief, per-batch post dumps (01-10),
  audit-tracker.json + AUDIT-TRACKER.md generated by scripts/manage_review.py
- scripts/manage_review.py: list/approve/approve-batch/generate over the tracker
- docs/consultant-review-2026-10-27-posts-and-casestudies-plan.md: locked
  decision register + 4 work orders for the /posts/ archive rework and the
  case-studies portfolio treatment
2026-10-27 03:28:58 +08:00
hoelee 2b495efe43 feat(posts): publish 60-song full-length YuE2 BF16 tutorial with track navigator & lazy loading
Deploy / build (push) Successful in 25s
2026-10-26 03:58:10 +08:00
hoelee 0a4fc47fce feat(categories): replace procedural SVG art with Gemini-generated WebP editorial banners
Deploy / build (push) Successful in 23s
2026-10-26 02:48:06 +08:00
hoelee fa156b0b9d feat(posts): publish 3-part agent orchestration series across historical dates with full EN+ZH assets
Deploy / build (push) Successful in 27s
2026-10-25 19:47:54 +08:00
hoelee d5ab7dec81 feat(posts): publish 4-part windows-mcp series across historical dates with full EN+ZH assets
Deploy / build (push) Successful in 22s
2026-10-25 18:45:43 +08:00
hoelee 1b795cee9d feat(posts): PHP2Shell — every PHP runtime I manage was vulnerable
Deploy / build (push) Successful in 23s
Adds EN + ZH post php2shell-patching-every-php-runtime-i-manage: measured
PHP versions across the fleet, the order the fixes shipped in, the 8.5
package trap, the OLS vhost handler switch, and the silent bot-block bug
the sweep uncovered. Ships og cards (EN/ZH), banner + webp, 2 thumbs.
2026-10-23 02:02:50 +08:00
hoelee 64e8410b3c feat(assets): replace TTS posts placeholder banners/OGs with Ideogram 4 3D cyber-bento renders
Deploy / build (push) Successful in 36s
2026-10-22 20:45:00 +08:00
hoelee 6409f751a9 feat(posts): add 2 local TTS posts (EN+ZH) on CosyVoice 2 stack and percent-encoding post-mortem
Deploy / build (push) Successful in 25s
2026-10-22 19:16:25 +08:00
hoelee 19023d2e4e feat(posts): add 3 video automation posts (EN+ZH) backdated into 2025 archive gaps with full artwork suite
Deploy / build (push) Successful in 31s
2026-10-22 18:47:41 +08:00
hoelee b5bb69937e feat(posts): publish case study on why I built a video knowledge base with generated art
Deploy / build (push) Successful in 21s
2026-10-21 07:46:44 +08:00
hoelee 0dae8b0daa fix(art): give both 2026-10-20 posts their artwork, and gate the build on it
Deploy / build (push) Successful in 34s
The YuE2 and subtitles posts shipped text-only: render_from_art.mjs only READS
ogImage/banner, and after the 2026-10-19 bulk migration no script had to write
them, so both pages advertised /og-default.jpg and rendered no hero banner.

- new metaphors (in build_captions.py, frozen here via sync_prompts_catalog.py),
  captions, art-meta evidence, banner plan and the five derived files per slug
- frontmatter: ogImage + banner in EN and ZH for both posts
- scripts/check-assets.mjs is now step 1 of npm run build, so CI fails when a
  published post lacks a language-correct og card, banner, banner .webp or
  400/800 list thumb. It reported 16 problems on the unfixed tree, all here.
2026-10-20 23:37:52 +08:00
hoelee 3efeafc567 post: running AI video locally on a 12 GB GPU (EN+ZH) with art, OG cards and banner
Deploy / build (push) Successful in 20s
2026-10-20 05:45:49 +08:00
hoelee f391682fc3 Round 7: zero-text frames, escaped/curly titles, plan-driven banner crops
Deploy / build (push) Successful in 19s
The consultant's review of the shipped set found two defects, both ours, and both fixed
at the source rather than in the output:

1. The banner/thumb crop re-framing detected only the glowing core of the object. Column
   brightness measures 2-6 levels above the background on dark glass, so it boxed 8 % of
   the frame for an object group spanning 35 %+. The detector is now a background-plane
   deviation plus the largest connected components (`plan_banner_crops.py`, detector in
   `probe_band_crop.py`), 0 % false-positive on the frame's own negative space, stable
   across thresholds. The crop plan is frozen as `banner-plan.json` and consumed by the
   renderer; a thin subject is centred at 53.5 % of the banner width with the shortfall
   filled by the art's own edge pixels, one row at a time (a single averaged fill left a
   visible tonal step, tried and rejected). Measured on the delivered 72: 0 clipped,
   silhouette median 47.0 %, centre median 53.5 % (`verify_banner_crops.py`).

2. `art-meta.json` pinned two slugs to the hand-accepted sample frames — the very frames
   that carried the HUD readouts — which also kept them out of the crop plan. Pins removed.

Prompt side: 9 frames still printed glyphs at the consultant's bar (>=12 px and >=2
characters). Every offending noun is measured and now asserted against: a literal `marked
at 28` printed "28"; `storefront kiosk` printed "PRINATA"; `voucher card` printed
"Voucher"; `market booths` printed "10MARKET"; `glass button` printed "OC"; `gateway pylon`
printed "GATELY". 50 forbidden words, 0 hits across 72 captions, and all 9 frames
re-rendered clean.

Also: YAML escapes are honoured in the frontmatter reader and straight quotes become
curly ones (the ZH cards shipped a literal backslash), the evidence line is capped at 65
characters, and the light theme gives dark artwork a hairline border plus a soft shadow
(consultant option A) so it reads as a dark display case instead of a black slab.

OCR gate at the consultant's bar: 72/72 frames clean (16 carry sub-threshold single
glyphs, exempt as geometry noise).
2026-10-19 11:02:28 +08:00
hoelee 327d516ed9 feat(art): replace all 72 posts' artwork with the v2 pipeline
Deploy / build (push) Successful in 17s
Every post now carries one unique local-ComfyUI/Ideogram 4 base frame, composited
into EN + ZH share cards, a banner and list thumbs.

- the shipped prompts_catalog held only 21 distinct metaphors for 72 posts (16
  shared one visual), so all 72 were rewritten as unique object+state metaphors
  and 10 frames re-rolled after OCR found pseudo-text rendered at legible size
- render_from_art.mjs emits JPEG by default (558 KB PNG -> 84 KB mozjpeg q85);
  the ZH 1200x630 card did not exist before this batch
- 288 frontmatter fields migrated; the 144 v1 PNGs are gone
- PostList's thumb helper keys off the base slug (a ZH card is zh-<slug>.jpg while
  the thumb is <slug>-800.webp, which 404'd the whole ZH listing)
- [...slug].astro's <picture> regex accepts .jpg
- the repo now carries the art inputs (metaphors.json, captions/<slug>.json,
  refreshed prompts_catalog.json) so a frame is reproducible from git alone
2026-10-19 04:18:59 +08:00
hoelee 0d7384224d post: 30 days of agent churn kept 23.5万 of 51.8万 lines (EN + ZH)
Deploy / build (push) Successful in 56s
The commit-churn post the owner read and approved today, published in the
first-person voice he asked for.

- Voice rewrite before publishing: the draft opened on "when managers or
  recruiters ask how productive an engineer is" and addressed the reader in the
  second person throughout (you/your 12 -> 2, both in the CTA; ZH 你 5 -> 2).
  It now reads as a log entry: "Last week I did something I almost never bother
  to do: I counted my own commits." Headings moved from essay titles to actions.
  Numbers, the 5-repo table and every claim are unchanged.
- Title changed at the owner's request:
  "Why 500,000 Lines of Commit Churn Only Left 230,000 Lines in Production"
  -> "I Committed 518,000 Lines in 30 Days. Production Kept 235,000."
  (ZH: 30 天提交 51.8 万行,生产环境只留下 23.5 万行), pubDate 2026-10-18.
- Fixed two real defects found while making the card: the draft claimed "four
  automated gates" and listed three; and og-gen split titles at the word-count
  midpoint, breaking at "…Lines in / 30 Days" — the splitter now prefers a
  sentence boundary near the middle and falls back to the midpoint.
- og PNG regenerated for the new title, thumbs and banner WebP re-derived.
  Measured: card 2 title lines, overflowY 0, measure_og_banner PASS (tags 1 row,
  banner delta 2), build clean, /posts/ monotonic with this post on top.

Also queued the post at the head of the dev.to drip (queue 69 -> 70).
2026-10-18 17:46:50 +08:00
hoelee 2060aaa166 docs(project-state): truth-up four stale statuses, record the batch blockers
Deploy / build (push) Successful in 1m4s
Measured against the live site and the cron outputs today, not carried over:

- A1 (author photo) and A3 (featured strip) were still ⬜ although both shipped
  (B4 and 6e9d58b) — marked done with the evidence, /start-here left as a
  deliberate deferral.
- E3 is fully automated: the LinkedIn half was already a daily no_agent cron
  (id 35f8985f609a). 5 posts published as of today's 12:30 tick; its silence is
  not proof of work, so the output files are the record.
- E6 closed: HSTS waived by the owner ("无视吧"), re-measured still max-age=0.
  Do not re-open.
- E1: CF Web Analytics re-measured absent (0 cloudflareinsights hits, one Umami
  tag). It is an owner dashboard action — no token here can enable it and CF
  injects the beacon itself, so there is no repo change to make.
- B6 now states the real shape of the artwork work: 0 of 72 posts rolled out,
  the live site still serves the v1 images, the 3 consultant questions are
  unanswered, the rendered OG card is measured at 558 KB PNG vs 84 KB JPEG q85,
  and the promised OCR pseudo-text gate does not exist yet.
2026-10-18 16:33:21 +08:00
hoelee a41448bb4a feat(og-gen): check in the v2 art pipeline and its batch renderer
The consultant-approved "one art, four targets" work existed only in the
working tree. Commit it so the 72-post rollout is reproducible from the repo
instead of from one session's scratch files.

- template-v2.html / v2.1 / v2.2: the iteration the consultant reviewed, plus
  the accepted frosted-bento layout (736x536 card, blueprint grid, full-width
  evidence bar, self-fitting headline script that reports "FIT <n>px").
- render_sample_suite{,_v2,_v3}.mjs + fit-title-probe.mjs: how the two sample
  posts were rendered for rounds 2-4 (kept for provenance).
- generate_prompts_catalog.py + prompts_catalog.json: the 72 per-post prompts
  and their visual metaphors, extracted from the posts themselves.
- render_from_art.mjs (new): the batch renderer. One zero-text base frame per
  post -> banner 1600x900 webp (+jpg fallback), social card 1200x630 (EN and
  zh-<slug>), thumbs 800x420 and 400x210. Cards are filled from frontmatter +
  art-meta.json; a missing evidence line or a headline that never settles is a
  hard failure, never a silently-degraded card.
- art-meta.json: the per-slug input contract. Two slugs wired; 70 still need
  base art (GPU) and a hand-written evidence line.
- README: documents the pipeline, the measured format choice (558 KB PNG ->
  84 KB mozjpeg q85) and the PostList thumb-helper trap when ogImage moves to
  .jpg.

Proof the renderer reproduces the accepted output: re-rendering the two sample
posts yields banner + 800px thumb files BYTE-IDENTICAL to the consultant's
delivery (sha256 16e6a7b0, f3b29f38, c4e28291, 8095ec6c), and all four cards
report FIT, 2-3 title lines, 2 description lines, 0 overflow in x and y.
2026-10-18 16:32:58 +08:00
hoelee 3f63150d51 feat(design): deploy default OG card (JPG/PNG), complete banner hygiene (E8), modernize CJK typography (E9), align title & hero (A2)
Deploy / build (push) Successful in 21s
2026-10-18 02:27:45 +08:00
hoelee f364084284 perf(images): WebP banners, text-only related cards, resized list thumbnails
Deploy / build (push) Successful in 56s
Measured before/after with headless Chrome + CDP (not by eye):

- article banner: <picture> WebP q78 with the PNG as fallback, because the PNG
  must stay for og:image (social scrapers do not reliably render WebP cards).
  70 banners: 6.02 MB -> 2.52 MB (42%). JPEG measured *larger* than PNG here
  (q85 = 129%) — the art is flat terminal-style with sharp text edges.
- post page related cards: dropped four 1200x630 PNGs (183 KB) to display
  526x276 where the embedded code is illegible; now text-only cards with a
  category badge, date and reading time.
- list thumbnails (home + archive): new /og/thumb/<name>-{400,800}.webp served
  via srcset/sizes. Rows display at ~398px but were pulling full 1200x630 PNGs.
  Homepage thumbnails ~450 KB -> 62 KB; archive (71 rows) ~3.2 MB -> 436 KB.
- desktop banner capped at 720px centred: 67% -> 45% of a 900px viewport,
  keeping the art intact instead of cropping it.

Post page totals: images 277 KB -> 38 KB; page height 5758 -> 5065 (desktop)
and 9423 -> 8807 (mobile). Build: 163 pages.

Script: scripts/optimize-images.py; policy: docs/design-guide.md §3; runbook
step added to docs/ops-runbook.md.
2026-10-16 17:11:27 +08:00
hoelee 08fa7a9412 post: four posts — rclone/Drive quota, DSM space reclamation, mail domain/PTR, embedded fonts (EN+ZH) + og/banner
Deploy / build (push) Successful in 32s
- my-backup-was-using-someone-elses-api-quota        (notes,       2026-10-15, pinned by its own evidence)
- space-reclamation-wasnt-stuck-it-was-waiting       (devops,      2026-10-14, pinned by its own samples)
- adding-a-domain-to-someone-elses-mail-server       (notes,       2025-05-06, backdated: no date/version pins)
- embedding-fonts-so-a-pdf-looks-the-same-everywhere (engineering, 2025-01-22, backdated: no date/version pins)
All four updatedDate 2026-10-16 so every lastmod stays honest; the two backdated posts carry no prose links
(a backdated post may only link backwards). og measured rows=1/overflow=0, banners 8 rows/delta=2/overflow=0.
2026-10-16 13:47:10 +08:00
hoelee 2394a7cbee post(engineering): two ways a JavaScript file stops working and looks fine (EN+ZH) + og/banner
Deploy / build (push) Successful in 23s
Backdated into the 2025-02 gap: pubDate 2025-02-20, updatedDate 2026-10-16 (lastmod honest).
No calendar dates or checkable version pins in the prose — the condition for backdating — and
no internal links, since every post it would cite is dated later and a backdated post may only
link backwards (see project-state B2n). Generators: additive entries only (5 + 17 lines, 0 deletions).
2026-10-16 13:32:06 +08:00
hoelee 3e354cc5db remove(ai): delete the composer-race post and its generator entries (user decision)
Deploy / build (push) Successful in 21s
- git rm src/content/posts/the-dialog-opened-in-7-seconds-my-script-waited-5.md + the zh twin
- drop its TERMINALS/BANNERS entries from both generators (pure deletions: 0 added, 17 + 5 removed,
  node --check OK, 0 remaining references to the slug, the other three slugs intact)
- build still 153 pages; no route, no listing row, no sitemap entry
2026-10-16 13:19:42 +08:00
hoelee 2295c0f5bf post(devops): publish the authentik CSS draft — the > that became u003e (EN+ZH) + og/banner
Deploy / build (push) Successful in 22s
- draft: true -> false in both files, pubDate 2026-09-20 kept, updatedDate 2026-10-16 (lastmod honest)
- fix the CTA's displayed phone number (011-797 2969 -> +60 12-797 2969)
- generate public/og + public/banners for the slug (og rows=1 overflow=0; banner delta=2 overflow=0)
- generators carry the TERMINALS/BANNERS entries for this post; three more entries for
  posts written the same session (held for review, not committed here) are inert
2026-10-16 12:46:09 +08:00
hoelee 5216f0761b post(ai): the five-step AI roadmap — what I actually run in production (EN+ZH) + og/banner
Deploy / build (push) Successful in 2m34s
2026-10-13 21:59:22 +08:00
hoelee 541b00c958 post(tutorials): does re-encoding to HEVC actually shrink your files? I measured it (EN+ZH) + og/banner
Deploy / build (push) Successful in 19s
Measured on real files with quality held fixed (SSIM vs the source, harness self-tested at 1.0000):
hevc_nvenc cq27 produced 115% and 119% of the source video bitrate on two of three files while cq30/31
landed 51-84%; libx265 crf26 landed 33.7/56.7/67.0% at min SSIM 0.988-0.993, i.e. 10-22% smaller than
NVENC at matched quality. Two sources with identical bpp (0.0437) shrank 49% vs 17%, so bpp classifies
files but does not predict the ratio. Notes the audio floor (a 33.7% video stream still yields a 53%
file because AAC dominates what is left) and why VP9/AV1 sources have no headroom (copy the video).
2026-10-08 05:19:27 +08:00
hoelee 0b523f40d6 post(devops): it reported success, nothing had changed (EN+ZH) + og/banner
Three silent failures on a network-mounted share: a 403 MB upload that wrote 12.5 MB and returned OK
(the timeout toast arrived minutes later, asynchronously), an os.replace() that never landed while
getsize()/mtime served cached metadata (the destination was still the original H.264 file), and a
byte-count source check that agreed with a length-preserving bad copy. Adds read-back hashing at all
three boundaries (source copy, upload, install) and records the metric traps that hid them: a clean
decode test on wrong pictures, SSIM on near-flat frames, input-seek decoding of open-GOP sources,
stream-copy slices dropping frames, and fixed-name scratch files colliding across concurrent runs.
Audit after the fix: reported=30 landed=29 not-landed=0.
2026-10-08 05:04:54 +08:00
hoelee e6476e1d15 post(devops): every player stuttered on the same video — the file was blameless (EN+ZH) + og/banner
Deploy / build (push) Successful in 24s
The converted HEVC stuttered in VLC, Chrome and on an iPad (offline) while the source played fine.
Container timing was perfect (5818/5818 frame intervals at exactly 0.040000 s, no dup/backward PTS,
ctts not flat) and a full decode printed nothing. Cross-decoder SSIM found the real defect: NVDEC's
legacy av1_cuvid wrapper returns frames from the wrong timestamps - 106 of 5819 frames, SSIM down to
0.330, deterministically, roughly every 30 frames - and the HEVC output was a faithful encode of those
wrong pictures (min 0.991 against the NVDEC decode, min 0.330 against a software decode). Fix is one
line (-hwaccel cuda -hwaccel_output_format cuda -c:v av1, verified 1.000000 over 1500 frames; vp9_cuvid
unaffected). Adds the content gate (structure AND pictures, defect-shaped thresholds) to the pipeline.
2026-10-08 04:52:04 +08:00
hoelee 378d55c3c8 post: two reader/gateway posts — the upstream rewrite, and the front-door pattern (EN+ZH) + og/banner images
Deploy / build (push) Successful in 22s
1) the-upstream-was-deleted-then-came-back-rewritten (devops, pubDate 2026-10-06)
   docker pull hectorqin/reader -> 404; the repo was re-initialised 2026-09-16 and now
   carries 233 commits, a TypeScript/Node rewrite, port 5888, SQLite /data, config moved
   into the admin UI, and an image on cnb.cool with no tags or releases. Covers telling
   dead from rewriting, the migration boundary, and keeping the front door outside the
   app image. Facts re-verified live 2026-10-06.

2) putting-a-front-door-on-an-app-you-cant-modify (devops, pubDate 2025-06-24 backdated
   into the empty 2025-06 window, updatedDate 2026-10-06 so lastmod stays honest)
   The reader-gateway pattern: a second nginx container owning the public port, the
   request-time resolver, why a proxy body rewrite cannot touch a client-rendered SPA,
   the gate-bounce injection with its pass token, the app's own CSS hook for branding,
   and the silent-failure check to run after every app upgrade.

Both: EN + ZH twins, TERMINALS/BANNERS entries appended via append_generator_entries.py
(additive, deletions 0, node --check OK), og/banner generated and measured PASS
(og rows=1 overflow=0 missingHash=0; banner 8 rows, delta 2, overflow 0).
2026-10-06 17:19:46 +08:00
hoelee 67b844e3a0 post(case-studies): running production infrastructure solo — 162 containers, three hosts (EN+ZH) + og/banner
Deploy / build (push) Successful in 18s
The Phase C1 keystone asset (Story B). Publishes the infra case study:
- architecture: 3 hosts / 162 containers / 78 compose stacks with the per-host split
- incident record: the monitoring panels that lied, and the Passbolt cascade
- how the numbers are re-derived (verify_infra.py) rather than remembered
- no uptime percentage: availability is not measured, so the post says 'monitored'
- hire CTA (case-study convention)

EN + ZH twins, og + banner generated and measured (OG 5 tags/1 row, banner 8 lines delta 2).
2026-10-06 08:04:02 +08:00
hoelee 1ec97706bb post: stop writing agent prompts for deterministic work (EN+ZH) + og/banner images
Deploy / build (push) Successful in 14s
2026-10-01 01:38:58 +08:00
hoelee f2d9c20207 post: loop engineering without a coding agent — the 11 cron jobs that run my business (EN+ZH) + og/banner images
Deploy / build (push) Successful in 18s
2026-10-01 01:36:32 +08:00
hoelee 54d8ccef7e post: one hostname for a public tracker and an SSO-gated dashboard (EN+ZH) + og/banner images
Deploy / build (push) Successful in 18s
2026-09-30 04:52:43 +08:00
hoelee 95b21e3456 Add 5 posts (EN + ZH): fully on-chain SVG NFTs, the CRLF art trap, a Chainlink VRF v2.5 lottery, page-by-page PDF verification, JPA @Version
Deploy / build (push) Successful in 20s
Five posts with custom OG + banner and hire CTAs. Three are web3, giving
that category its first posts — /categories/web3/ previously 404'd while the
index advertised it as '0 posts - coming soon'.

Backdated where the work genuinely is older: the foundry-nft and
hardhat-smartcontract-lottery commits date to 2024-08-15..19, so those two
posts fill the empty 2024-10 and 2024-12 archive months with updatedDate
holding the real date. The two 2026-08-19 posts use their real work date.

TERMINALS/BANNERS entries for all five slugs are committed this time (both
generators were clean; diffs verified purely additive).
2026-09-29 02:41:58 +08:00
hoelee 48472e0daa Add 3 posts (EN + ZH): the Synology Spreadsheet API container, the 401-with-correct-password gotcha, and reading a container's own API docs
Deploy / build (push) Successful in 24s
2026-09-29 01:43:00 +08:00
hoelee e8c5124db1 Add 4 monitoring posts (EN + ZH): smartctl exit 32, Grafana no-data variable, percentage alert thresholds, one Prometheus for 3 hosts
Deploy / build (push) Successful in 28s
Backdated into the 2026-03-25 -> 2026-09-04 archive gap (pubDate 2026-04-14/05-17/06-24/07-29)
with updatedDate 2026-09-29 holding the real date, so sitemap lastmod stays honest.
Custom OG + banner per post, hire CTA, language switch verified.
2026-09-29 01:37:23 +08:00
hoelee 893675e6a3 Add post: Why Chrome Forgets Its Tabs in a Container (EN + ZH)
Deploy / build (push) Successful in 17s
- docker/Chrome/CDP gotcha: the container kills the browser, so it never exits
  cleanly and no restore mechanism fires (flag, Preferences, managed policy all
  verified failing) -> 60s snapshot + replay keeper
- also covers the stale Singleton* lock and custom-cont-init.d permission traps
- custom OG + banner art, EN + ZH, backlog B2 updated
2026-09-29 01:10:39 +08:00
hoelee 87111360ce Add post: How I Vet an Open-Source Dependency Before Betting On It (EN + ZH)
Deploy / build (push) Successful in 15s
New `devops` post on vetting an upstream dependency before building on it:
the six checks that corrected six assumptions from a 1,306-line architecture
spec — repo vital signs via the GitHub API, grepping for the feature instead
of reading for it (OIDC/SSO/SAML → 0 hits), reading a feature doc's target
branch (white-label lives on `multi-tenant`, not `main`), reading the data
model rather than the feature list (percent/fixed vs five assumed rule types),
the Community-vs-Enterprise tier gate (API tokens free, SSO paid), and whether
the money rail works in-country (selfhost + manual payouts, not Stripe Connect).
Closes with the fallback question and the authentik proxy-provider answer.

- EN: src/content/posts/vetting-an-open-source-dependency-before-you-bet-on-it.md
- ZH: src/content/posts/zh/<same slug>.md (same filename → auto language switch)
- Custom OG (1200x630) + banner (1600x900) art via TERMINALS/BANNERS entries
- pubDate 2026-09-29; build verified 93 pages, 17/17 content checks, listing
  order monotonic on /posts/, / and /zh/

Note: the generator maps also carry two entries belonging to parallel
in-flight posts (adding-english-mode…, and the sessions' other slugs);
their post files were left uncommitted.
2026-09-29 01:07:43 +08:00
hoelee 8a9ba6af1b Add post: No API for Browser Translation (EN + ZH)
Deploy / build (push) Successful in 23s
2026-09-29 01:02:42 +08:00
hoelee d1c040d648 Add post: A Read-Only NocoDB Dashboard for a Database on Another Machine
Deploy / build (push) Successful in 28s
EN + ZH twins. The recipe for pointing NocoDB at a MySQL/MariaDB database on
another machine: the Docker SNAT source-IP trap (the DB sees the host IP, not
the container IP), a SELECT-only grant restricted to that one host, the async
source-creation API with no job-status route, the auto-sync that makes a manual
table step unnecessary (and the create-table route that makes junk tables), and
what a read-only source costs (no metadata edits, UTC-labelled DATETIMEs).

Also adds the og-gen TERMINALS and banner-gen BANNERS entries for the slug
(keeping the sibling session's entries untouched) and the generated PNGs.
2026-09-29 00:57:57 +08:00
hoelee 473a20edf7 Add post: Why I Still Bought a GPU to Run AI When Claude and GPT Are Stronger (EN+ZH)
Deploy / build (push) Successful in 5m13s
2026-09-21 21:17:55 +08:00
hoelee a1488da2d8 Add post: When Your Database Client Lies to You (Workbench 26 / MariaDB)
Deploy / build (push) Successful in 22s
EN + ZH devops gotcha post on debugging MySQL Workbench 26.7.0's failure
to connect to MariaDB. Three patches to Oracle's bundled code, all the
same root cause: `major >= 8` is not a valid MySQL-vs-MariaDB test.

Also adds per-post OG + banner (TERMINALS/BANNERS entries).
2026-09-20 04:18:11 +08:00
hoelee daca86dc43 Add post: Replacing RDPGuard With IPBan (EN + ZH, og+banner)
Deploy / build (push) Successful in 22s
Case study of migrating from paid RDPGuard 7.8.7 to open-source IPBan
4.1.0, covering the three undocumented traps: the uninstaller that would
have silently unbanned 12 active attackers, the non-existent
--install-service flag in v4.1.0, and ExpireTime vs BanTime.

Also fixes an og-gen defect: the tag chip hardcoded KIND='DevOps', so
every non-devops post carried a wrong label (e.g. "case-studies · DevOps"
on the STT card). KIND now derives from the post category, and all 29
existing OG images are regenerated with correct badges.
2026-09-19 19:50:27 +08:00
hoelee 9fa366a0ac Add case study: self-hosted speech-to-text API (EN + ZH)
Deploy / build (push) Successful in 25s
New flagship case study covering a GPU-backed whisper.cpp transcription API
reachable from Windows, iPhone, iPad and Android behind an authenticated
gateway — framed as a service offering with the office-productivity case
(roughly 5x typing throughput, unlimited, audio never leaves the premises).

Content:
- EN + ZH posts (same slug -> auto language switch)
- "Why it matters" opener, hire CTA with clickable WhatsApp + mailto
- Four documented traps: incomplete CUDA component selection, loopback bind
  mistaken for a firewall problem, n8n Code nodes discarding binary + the
  data0 key name, and nginx default.conf hijacking port 80
- Honest scoping of the auth model (access control, not hardened public API)

Assets:
- Custom OG image + 16:9 banner (generator entries appended, not patched
  inside the template-literal maps)

Also marks Mem0 (B1) done and adds B1b to project-state.md.
2026-09-19 07:55:29 +08:00
hoelee 044ded45b3 Add TRIM corruption sequel post + publish SATA cable post (en/zh, og+banner)
Deploy / build (push) Successful in 19s
- New post: 'The Corruption Came Back on Different Drives — the Cause Was
  TRIM, Not the SSDs' — same 0x8941f998 zeros fingerprint on a second drive
  stack (IronWolf 110 SATA pair), root cause queued TRIM (FreeBSD gag 264139),
  fix diskAutotrim=off + nodiscard, scrub evidence, enterprise SATA buying
  guidance. en + zh, custom OG + banner.
- Publish formerly-draft SATA cable post (draft:false) with OG + banner.
- Correct drive identity in both: ZA960NM10001 is Seagate IronWolf 110, not
  'Samsung PM9A3' (PM9A3 is NVMe; FPDMA errors are SATA-only).
- Old RAID post (en+zh): cross-link to sequel, fix 'a Samsung' -> IronWolf 110.
2026-09-18 05:38:13 +08:00