Skip to content

T-ENG03: make the webapp data bundles deterministic - #37

Merged
emmanuelgjr merged 3 commits into
mainfrom
fix/T-ENG03-deterministic-webapp-build
Sep 14, 2026
Merged

emmanuelgjr merged 3 commits into
mainfrom
fix/T-ENG03-deterministic-webapp-build

Conversation

@emmanuelgjr

Copy link
Copy Markdown
Contributor
Plan ID: ENG-03            Ticket: T-ENG03            Wave: W4
Constraints honored: C2 (determinism only — no structural/route/layout/logo change), C1 (no names), C4 (no mapping content touched)
Files touched: scripts/generate.js, scripts/generate.test.mjs, .github/workflows/validate.yml, CONTRIBUTING.md,
               docs/data.js, docs/backlinks.js, docs/frameworks-registry.js, docs/incidents.js (8 files)
Deliberately NOT changed: no entry JSON, no mapping row, no count, no webapp HTML/CSS/JS logic; Pages source left as main:/docs
Human decisions/approvals needed: C2 approval — this PR regenerates docs/*.js (header lines only, see diff)
Verify:
  $ node scripts/generate.js && node scripts/generate.js && git diff --exit-code -- data/entries data/backlinks.json docs/*.js
  clean (header-only diff vs main is the intended change)
  $ npm test          → 51 tests, 51 pass (3 consecutive runs)
  $ node scripts/validate.js
  Summary: 0 error(s), 84 warning(s), 312 passed  ✓ Validation PASSED
  $ npm run stats:check   → data/stats.json current; README.md current
  $ actionlint / zizmor .github/workflows/validate.yml → clean
Baseline before/after: 0 err / 84 warn → 0 err / 84 warn

What was non-deterministic

Only one thing: each of the four docs/*.js bundles opened with // Generated: <today's date>. Everything else the generator emits is stable run-to-run (the existing generating twice produces byte-identical output test already proved that — on the same day).

That single line had a bigger consequence than untidy diffs: since #30, the Generator reproducibility CI job and the committed entries match a fresh generation unit test both diff docs/data.js against a fresh run. Both could only pass on the day the bundles were last committed. They were green on 2026-08-28 because every merge that day regenerated them; the next push on a later day would have failed on main with no code change.

Changes

  • scripts/generate.js — the four // Generated: lines are gone. The // Source: header now reads the version from package.json (v4.0.0) instead of a hard-coded v1.5.2 that had been stale for three majors.
  • scripts/generate.test.mjs — new test: no bundle header may name a run or carry a date.
  • .github/workflows/validate.yml — the reproducibility job now diffs every generated artefact: data/backlinks.json, docs/backlinks.js and docs/frameworks-registry.js were previously outside the check.
  • CONTRIBUTING.md — a "Generated files" section: which files are generated, the determinism requirement, and the npm run build / npm test / git diff --exit-code loop.

On "prefer generating them in the Pages deploy workflow"

There is no Pages deploy workflow: Pages is configured as build_type: legacy, source main:/docs (checked via gh api .../pages). Switching to a workflow-based deploy means changing the repository's Pages settings and adding a deploy workflow — a maintainer/infrastructure decision, not a determinism fix — so this PR keeps the bundles committed and says so in CONTRIBUTING. Happy to draft that workflow as a follow-up if wanted.

Observed, not changed

node --test runs the suite files in parallel, and generate.test.mjs rewrites data/entries/ while exports.test.mjs reads them. One run in ~6 produced a transient OSCAL component definition carries at least one implemented requirement failure; the same run passes in isolation and on pristine main. Pre-existing and out of scope here; noted for a follow-up (serialize the suites or have the exports test snapshot its input).

🤖 Generated with Claude Code

https://claude.ai/code/session_0147wBugcuzLkswKPqgofcke

Every docs/*.js bundle carried a `// Generated: <today>` header. Nothing
else in the generator output varies between runs, so that one line was
the whole reason a regenerate on a different day showed four dirty
files — and, since #30, the reason the Generator reproducibility job and
the `committed entries match a fresh generation` test could only pass on
the day the bundles were last committed.

- generate.js: drop the run-date lines; the Source header now reads the
  version from package.json instead of a hard-coded, stale `v1.5.2`.
- generate.test.mjs: assert no bundle header names a run or carries a date.
- validate.yml: the reproducibility job now diffs every generated
  artefact (backlinks.json, backlinks.js, frameworks-registry.js too).
- CONTRIBUTING.md: document the build contract — generated files, the
  determinism requirement, and why the bundles are committed (Pages
  serves docs/ from main; no deploy workflow exists).

Determinism only. No structural, route, layout or logo change (C2).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147wBugcuzLkswKPqgofcke
Conflicts were only in the four generated webapp bundles, and only in
their header lines: #92 regenerated them with a `// Generated:` date
that this branch removes. Resolved by re-running scripts/generate.js on
the merged sources; a second run is byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
Conflicts only in docs/backlinks.js and docs/frameworks-registry.js, both
generated: #94 regenerated them with a `// Generated:` date header that
this branch removes. Resolved by re-running scripts/generate.js on the
merged sources; the CI generated-output assertion passes locally.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
@emmanuelgjr
emmanuelgjr merged commit de3fc7f into main Sep 14, 2026
8 checks passed
@emmanuelgjr
emmanuelgjr deleted the fix/T-ENG03-deterministic-webapp-build branch September 14, 2026 21:09
emmanuelgjr added a commit that referenced this pull request Sep 14, 2026
#37 landed as a squash, so this branch's copies of its commits resolve as identical content. Generated files re-run on the merged sources; a second generation is byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
emmanuelgjr added a commit that referenced this pull request Sep 14, 2026
#37 landed as a squash, so this branch's copies of its commits resolve as identical content. Generated files re-run on the merged sources; a second generation is byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
emmanuelgjr added a commit that referenced this pull request Sep 14, 2026
#37 landed as a squash, so this branch's copies of its commits resolve as identical content. Generated files re-run on the merged sources; a second generation is byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
emmanuelgjr added a commit that referenced this pull request Sep 14, 2026
#37 landed as a squash, so this branch's copies of its commits resolve as identical content. Generated files re-run on the merged sources; a second generation is byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
emmanuelgjr added a commit that referenced this pull request Sep 15, 2026
One hand-resolved conflict, docs/index.html: #94 changed the About
paragraph to "26 industry frameworks with 3,803 individual control
mappings" while this branch had changed the same sentence to 3,475.
Kept #94's sentence and set the count to the merged data's own total,
3,781 (= 3,803 minus the 22 junk rows this branch removes, all on
DSGAI21; 0 rows added). Generated files re-run on the merged sources;
a second generation is byte-identical. validate 0 errors; stats current.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
emmanuelgjr added a commit that referenced this pull request Sep 15, 2026
…uracy

Generated files re-run on the merged sources; a second generation is byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
emmanuelgjr added a commit that referenced this pull request Sep 15, 2026
Generated files re-run on the merged sources; a second generation is byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
emmanuelgjr added a commit that referenced this pull request Sep 15, 2026
No conflicts. The one intermittent local test failure seen during verification is the pre-existing data/entries read/write race (Unexpected end of JSON input), fixed by #87; captured and confirmed, not caused by this merge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
emmanuelgjr added a commit that referenced this pull request Sep 15, 2026
No conflicts. The one intermittent local test failure seen during verification is the pre-existing data/entries read/write race (Unexpected end of JSON input), fixed by #87; captured and confirmed, not caused by this merge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant