fix(codegen/cloudflare): format README before change-detection compare (#488) #18

Merged
stack72 merged 1 commit from worktree-488 into main 2026-05-29 18:39:14 +00:00
Owner

Summary

The Cloudflare codegen pipeline bumped every service's manifest.yaml micro version on every regeneration, even when zero models changed — causing dead-publish churn and drift between model and manifest versions.

Root cause: codegen/cloudflare/pipeline.ts computed hasChanges by comparing the on-disk README.md against the raw generateCloudflareReadme() output. But commands/generate.ts runs deno fmt over the output dir after writing, so the on-disk README is reformatted. The generated README is not deno-fmt-clean (the intro prose re-wraps at 80 cols), so existingReadme !== readmeCode was perpetually true → hasChanges always true → computeManifestVersion bumped the micro every run.

Why Cloudflare-only: The hetzner / digitalocean / aws / gcp pipelines all formatFile(readme, ".md") before comparing. Cloudflare was the only pipeline missing that step (and didn't import formatFile).

Fix

Format the candidate README with deno fmt before the change-detection comparison, mirroring the four sibling pipelines and the behavior already documented in codegen/designs/cloudflare.md §14 ("Before comparing, the pipeline formats the candidate with deno fmt … ensures idempotent regeneration").

Verification

  • generate:cloudflare0 manifest version bumps across all 70 services (Models: 0 changed, 168 unchanged).
  • Second run is fully idempotent — zero new diff.
  • deno check / deno lint / deno fmt --check pass in codegen/.
  • No model/ files hand-edited; no doc change needed.

Fixes swamp-club #488.

🤖 Generated with Claude Code

## Summary The Cloudflare codegen pipeline bumped every service's `manifest.yaml` micro version on **every** regeneration, even when zero models changed — causing dead-publish churn and drift between model and manifest versions. **Root cause:** `codegen/cloudflare/pipeline.ts` computed `hasChanges` by comparing the on-disk `README.md` against the **raw** `generateCloudflareReadme()` output. But `commands/generate.ts` runs `deno fmt` over the output dir after writing, so the on-disk README is reformatted. The generated README is not deno-fmt-clean (the intro prose re-wraps at 80 cols), so `existingReadme !== readmeCode` was perpetually true → `hasChanges` always true → `computeManifestVersion` bumped the micro every run. **Why Cloudflare-only:** The hetzner / digitalocean / aws / gcp pipelines all `formatFile(readme, ".md")` before comparing. Cloudflare was the only pipeline missing that step (and didn't import `formatFile`). ## Fix Format the candidate README with `deno fmt` before the change-detection comparison, mirroring the four sibling pipelines and the behavior already documented in `codegen/designs/cloudflare.md` §14 ("Before comparing, the pipeline formats the candidate with deno fmt … ensures idempotent regeneration"). ## Verification - `generate:cloudflare` → **0 manifest version bumps** across all 70 services (`Models: 0 changed, 168 unchanged`). - Second run is fully **idempotent** — zero new diff. - `deno check` / `deno lint` / `deno fmt --check` pass in `codegen/`. - No `model/` files hand-edited; no doc change needed. Fixes swamp-club #488. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(codegen/cloudflare): format README before change-detection compare (#488)
All checks were successful
CI / workflows/gcs-bootstrap - lockfile up to date (pull_request) Has been skipped
CI / workflows/s3-bootstrap - lockfile up to date (pull_request) Has been skipped
CI / cve/dirtyfrag - check (pull_request) Has been skipped
CI / cve/dirtyfrag - lint (pull_request) Has been skipped
CI / cve/dirtyfrag - fmt (pull_request) Has been skipped
CI / cve/mini-shai-hulud - fmt (pull_request) Has been skipped
CI / cve/mini-shai-hulud - check (pull_request) Has been skipped
CI / cve/dirtyfrag - test (pull_request) Has been skipped
CI / cve/mini-shai-hulud - lint (pull_request) Has been skipped
CI / cve/mini-shai-hulud - test (pull_request) Has been skipped
CI / cve/dirtyfrag - lockfile up to date (pull_request) Has been skipped
CI / cve/mini-shai-hulud - lockfile up to date (pull_request) Has been skipped
CI / model/hetzner-cloud - check (pull_request) Successful in 57s
CI / model/digitalocean - lockfile up to date (pull_request) Successful in 1m22s
CI / model/digitalocean - check (pull_request) Successful in 1m5s
CI / gcp models - lockfiles up to date (pull_request) Successful in 1m29s
CI / cloudflare models - lockfiles up to date (pull_request) Successful in 1m30s
CI / model/hetzner-cloud - lockfile up to date (pull_request) Successful in 1m31s
CI / codegen - fmt (pull_request) Successful in 1m29s
CI / aws models - lockfiles up to date (pull_request) Successful in 1m35s
CI / codegen - check (pull_request) Successful in 1m33s
CI / cloudflare models - sample check (pull_request) Successful in 1m38s
CI / aws models - sample check (pull_request) Successful in 1m57s
CI / CI Security Review (pull_request) Has been skipped
CI / gcp models - sample check (pull_request) Successful in 2m3s
CI / codegen - lint (pull_request) Successful in 52s
CI / codegen - lockfile up to date (pull_request) Successful in 55s
CI / Claude Code Review (pull_request) Successful in 2m1s
CI / Adversarial Code Review (pull_request) Successful in 1m56s
CI / Merge Gate (pull_request) Successful in 29s
51103dfaf1
The Cloudflare pipeline compared the on-disk README (which `deno fmt`
rewrites after every write) against the raw `generateCloudflareReadme()`
output. The generated README is not deno-fmt-clean (prose re-wraps at 80
cols), so the comparison was perpetually unequal, `hasChanges` was always
true, and `computeManifestVersion` bumped every service's manifest micro
on every regeneration even when zero models changed — causing dead-publish
churn and drift between model and manifest versions.

Format the candidate README with `deno fmt` before the comparison, matching
the hetzner/digitalocean/aws/gcp pipelines (the established convention) and
the behavior already documented in codegen/designs/cloudflare.md §14.

Verified: `generate:cloudflare` now produces zero manifest version bumps
across all 70 services, and a second run is fully idempotent (zero diff).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
Owner

Code Review

Blocking Issues

None.

Suggestions

  1. Comment length (codegen/cloudflare/pipeline.ts, lines 403–405): The three-line comment block explaining the formatting comparison is accurate and the non-obvious constraint warrants a note, but CLAUDE.md asks for one short line max. Consider condensing to something like // Format first — the on-disk README has already been run through deno fmt. The extra detail about why the on-disk file is formatted (pipeline runs fmt after writing) is already implied by formatFile's name and the surrounding context.

The change is correct and well-scoped. The root issue — comparing a raw-generated README against an already-deno fmt-formatted on-disk file, causing spurious change detection — is real, and the fix (formatting the candidate before the comparison) directly addresses it. The formatFile error path is handled correctly: if formatFile throws, the outer catch conservatively sets hasChanges = true, which is the right fallback.

## Code Review ### Blocking Issues None. ### Suggestions 1. **Comment length** (`codegen/cloudflare/pipeline.ts`, lines 403–405): The three-line comment block explaining the formatting comparison is accurate and the non-obvious constraint warrants a note, but CLAUDE.md asks for one short line max. Consider condensing to something like `// Format first — the on-disk README has already been run through deno fmt.` The extra detail about *why* the on-disk file is formatted (pipeline runs fmt after writing) is already implied by `formatFile`'s name and the surrounding context. --- The change is correct and well-scoped. The root issue — comparing a raw-generated README against an already-`deno fmt`-formatted on-disk file, causing spurious change detection — is real, and the fix (formatting the candidate before the comparison) directly addresses it. The `formatFile` error path is handled correctly: if `formatFile` throws, the outer `catch` conservatively sets `hasChanges = true`, which is the right fallback.
Author
Owner

Adversarial Review

Critical / High

None.

Medium

None.

Low

None.

Verdict

PASS — Small, targeted fix that formats the candidate README with deno fmt before comparing it against the on-disk version, eliminating false-positive hasChanges on every regeneration. The change mirrors the exact pattern already used in the AWS, GCP, Hetzner, and DigitalOcean pipelines. formatFile gracefully falls back to the original content if deno fmt fails, so there is no new failure mode introduced. The fix is correct and idempotent.

## Adversarial Review ### Critical / High None. ### Medium None. ### Low None. ### Verdict **PASS** — Small, targeted fix that formats the candidate README with `deno fmt` before comparing it against the on-disk version, eliminating false-positive `hasChanges` on every regeneration. The change mirrors the exact pattern already used in the AWS, GCP, Hetzner, and DigitalOcean pipelines. `formatFile` gracefully falls back to the original content if `deno fmt` fails, so there is no new failure mode introduced. The fix is correct and idempotent.
stack72 deleted branch worktree-488 2026-05-29 18:39:14 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
swamp-club/swamp-extensions!18
No description provided.