web-deploy: deploy pipeline crash + Cloudflare build reliability (5 rounds)
Section titled “web-deploy: deploy pipeline crash + Cloudflare build reliability (5 rounds)”Outcome: KB deploy (kb-business, kb-sdc) fully working again after being silently broken for the whole web-deploy-bug window; the underlying “Cloudflare build failures are invisible” gotcha (recurring since 2026-06-26, 4th occurrence) now has an actual fix instead of another advisory note. All fixes live-verified, not just claimed.
What broke, and why (in order discovered)
Section titled “What broke, and why (in order discovered)”sanitize-kb-source.tscrashed the whole deploy — uncaughtPermissionDeniedwriting to the 12strategy-lint-generated, deliberately read-onlySDC/IP/Strategies/*/index.mdfiles (made read-only 2026-09-21).deploy.sh’sset -ethen aborted before sync/transform/push ever ran. Fix: catchDeno.errors.PermissionDenied, warn, skip.- The crash just moved one step later —
sync-content.ts’sDeno.copyFilepreserves source permission bits, so the read-only files’ localsrc/content/docs/copies were read-only too, crashingtransform.ts/convert-wikilinks.tsnext. Fix:chmod(destPath, 0o644)right after every copy — the protection is for the vault source, not a disposable build copy. - The real reason the site stayed stale —
strategy-lint index()never wrotetitle:frontmatter into its generatedindex.mdfiles at all. Starlight’s content schema hard-requirestitle, so the Astro build failed on Cloudflare withInvalidContentEntryDataError— butdeploy.shprints “Push complete!” unconditionally on a successful git push, with zero visibility into the async Cloudflare build’s actual result. Every deploy since 2026-09-21 pushed fine and failed to build; the site was frozen on its last real build (pre-2026-09-17). Fix:strategy_lint.py’sindex()now writes propertitle:frontmatter into both root and per-group generated files; regenerated all 12. - Cloudflare build reliability, built for real this time (Lesson 10 in
web-deploy/LESSONS.mdhad flagged this exact gap since 2026-06-26 and 3 prior recurrences without ever being built):wait_for_cloudflare_pages_build()inweb_deploy.pypolls the Cloudflare Pages API for the deployment matching the just-pushed commit and blocks until it reaches a terminal success/failure stage, failing loudly instead of reporting done at push time. Verified both directions (known-good commit → success; known-bad024bad5→ failure, no hang) before wiring into the real CLI.kb-sdcexcluded — its synchronouswrangler pages deployalready returns an accurate result. - A second, unrelated stale-content bug found live in the same session:
generate-bases.pypicked which static table to render for a\“basequery block from a substring match against the *preceding##heading text* only.Core/DASHBOARD.mdandMBR/DASHBOARD.md's heading ("## Current Tasks/Projects") matched none of the 5 known patterns, so their query blocks shipped as raw YAML instead of a table — indefinitely, with no error. Fix: match the block's own declaredname:` field first, heading as fallback.
What shipped
Section titled “What shipped”kb-business/sanitize-kb-source.ts,kb-sdc/sanitize-kb-source.ts,kb-mbr/sanitize-kb-source.ts— permission-denied guard.kb-business/sync-content.ts,kb-sdc/sync-content.ts,kb-mbr/sync-content.ts— chmod copies writable.~/utils/strategy-lint/strategy_lint.py—title:frontmatter on generated index files (no git repo for this util — fix is live on disk, uncommitted, no history to record it in).web_deploy.py—wait_for_cloudflare_pages_build(), wired intoexecute_deployment(); a CDN-propagation-delay note printed on success; removed a 3-months-dead pre-deploy “Regenerate KB dashboard” step (called a script deleted 2026-06-26, duplicated bygenerate-bases.py’s own Step 2b) that was the source of the “‘uv’ not found” error Talbot saw.config.yaml—cf_pages_project: kb-online-site(kb-business) /kb-mbr(mothballed); dropped deadrun_kb_dashboardflag everywhere..env— addedCLOUDFLARE_ACCOUNT_ID(token already present).kb-business/generate-bases.py— match Bases views by declaredname:, not heading substring.~/ai-config/AGENTS.md— new Hard Rule: verify async external state (Cloudflare/CI builds, webhooks) programmatically rather than handing a timing-sensitive check to a human’s eyes. Deployed via thepost-commithook, confirmed.Core/Processes/Software Dev/GlobalDevRules.md§3.13 — addendum: a read-only generated file’s protection doesn’t survive being copied by a build/sync pipeline; chmod the copy writable at the copy site.web-deploy/LESSONS.md— Lesson 10 updated from “not yet built” to built-and-shipped; new Lesson 12 on matching content by declared identity over free-form prose.
Verification (live, not claimed)
Section titled “Verification (live, not claimed)”- Both known-good and known-bad Cloudflare commits tested directly against
wait_for_cloudflare_pages_build()before it was wired into the CLI. - Ran the real
web-deploy kb-business onlineandweb-deploy kb-sdc onlinecommands (not just the underlying scripts) twice each across the fix iterations; both completed with Cloudflare build success confirmed via the API. - Fresh
curl(no cache) of both live sites after the final round: zero occurrences of pre-cleanup stray content,/apps///archive/404,Core/DASHBOARD.mdandMBR/DASHBOARD.mdrender real tables (no raw YAML). - Full local Astro build run twice (before and after the Bases-matching fix): 1235 pages, exit 0 both times.
Gotcha for future work
Section titled “Gotcha for future work”~/utils/strategy-lint/ has no git repository — the title: frontmatter fix is live on disk (plain Python, takes effect immediately) but has no commit history. Worth a git init there if the tool keeps growing (Talbot’s call, not applied unilaterally this session).
Commits
Section titled “Commits”web-deploy(~/utils/web/web-deploy/):1327a51,fdf24cd,f5b3978,48d31d5,7bfcd5cweb-deploy/kb-business:b3222af,f426523,8d8f568web-deploy/kb-sdc:4edd88d,befeb00web-deploy/kb-mbr:7a94c5c,46e9177ai-config:f4af379
Closed as terminal — all 3 original asks plus 2 reliability fixes plus 1 newly-found bug are fixed and live-verified; no further web-deploy work currently identified.