Fix: the last entry in a mapping file swallowed the file's closing tables (22 junk mappings, 22 junk registry controls) - #90
Merged
Conversation
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
…bles extractSection() ended an entry's section only at the next `### ` heading, so the LAST entry in each file ran on through `## ` closing sections. Two kinds of data that were never mappings got stored as if they were: - 22 control mappings on DSGAI21, from the dsgai-2026 AIUC-1 and NHI files' summary matrices and changelog tables: control ids "Date", "2026-03-27", "DSGAI02, DSGAI09, DSGAI14", "DSGAI entries most affected" — and 352 lines of backlinks built from them. - Cross-references: LLM10, ASI10 and DSGAI21 (each the last entry in its files) claimed every sibling id mentioned in the closing summary, e.g. LLM10 → LLM01..LLM09. Only those three entries change. The 22 rows had also been extracted into the registries as 22 "controls" (9 AIUC-1, 13 OWASP NHI). They are removed where no mapping references them; inventory_completeness.included follows (and agrees with inventory-completeness.js). Counts: mappings 3,497 -> 3,475 (-0.6%); controls 1,372 -> 1,350 (-1.6%). The webapp About paragraph's hard-coded "3,497" is updated to match (C2). New test fails on any mapping or registry id shaped like a changelog or summary cell; it reports 44 such rows/items against the previous data. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
#23 moved the registry url to the final publication's DOI but did not re-run inventory-completeness.js, so inventory_completeness.source kept the previous csrc URL. The script writes source = url; re-running it changes exactly this line. The previous commit on this branch restored the stale value on the mistaken belief the script was reverting #23 — it was correcting it. Both URLs resolve to the final SP 800-218A. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR
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
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
Base automatically changed from
fix/T-ENG03-deterministic-webapp-build
to
main
September 14, 2026 21:08
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
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Plan ID: — (data integrity; found while scoping #35) Ticket: — Wave: —
Constraints honored:
docs/data.js,backlinks.jsandframeworks-registry.jsare regenerated, and one hard-coded number in the About paragraph is updated. Approval needed.The bug
extractSection()ended an entry's section only at the next###heading. The last entry in each mapping file therefore ran on through the file's##closing sections: the summary matrix, references, changelog. Two kinds of non-mapping data got stored:1. 22 mapping rows on DSGAI21, all from
dsgai-2026/DSGAI_AIUC1.mdanddsgai-2026/DSGAI_NHI.md:control_idvalues stored as controlsPrimary DSGAI entries,DSGAI02, DSGAI03, DSGAI06, …,DSGAI05, DSGAI20,DSGAI12, DSGAI19,DSGAI20, …Date,2026-03-27DSGAI entries most affected,DSGAI21,DSGAI03, DSGAI06, DSGAI16, …Date,2026-03-27Plus the 352 backlink lines built from them.
2. Cross-references on the three last-in-file entries. LLM10 claimed LLM01–LLM09, ASI10 claimed ASI01–ASI09, and DSGAI21 claimed 18 extra DSGAI ids, all mentioned only in the closing summary. No other entry changes, which fits the cause.
The same 22 junk rows had been extracted into the registries as
kind: controlitems: 9 inaiuc-1.json, 13 inowasp-nhi.json. They're removed here where no mapping references them.inventory_completeness.includedfollows, and matches whatinventory-completeness.jscomputes. Each registry gets a changelog entry.Impact
Measured against
mainafter #37, #94 (AISVS 1.0, 26th framework) and #96:kind: control)Both moves are under the playbook's 2% escalation threshold and fully explained above. Webapp: the About paragraph's hard-coded count becomes "26 industry frameworks with 3,781 individual control mappings" (was 3,803 on
main) (C2). The first version of this PR said 3,497 → 3,475; #94 has since added a framework, so the merge commit recomputed it from the data.Guard
New test in
scripts/generate.test.mjs: no mapping or registrycontrol_idmay be shaped like a changelog or summary cell (Date,Version, an ISO date, a list of entry ids, "… entries most affected"). It reports 44 such rows/items against the previous data and 0 now.Found, not fixed
NHI-1…NHI-10items. The junk items were the only ones carrying those titles, under ids likeDSGAI21. Proper NHI ids arrive with Swapped control_id / control_name: 576 mapping rows hold prose where an identifier belongs #35; details are on that issue.Corrected inscripts/inventory-completeness.jsreverts a fix(ACC-02): version currency — update what is safe, flag what is not #23 change767982d: I had this backwards. fix(ACC-02): version currency — update what is safe, flag what is not #23 moved SP 800-218A'surlto the final DOI, but never reran the script, soinventory_completeness.sourcekept the old csrc URL. The script'ssource = urlwas correcting that, and my first commit restored the stale value.767982dapplies the script's output. It changes that one line only, and both URLs resolve to the final publication.Deliberately NOT changed
exports.test.mjs: none of the removed rows were counted in them.Verify
🤖 Generated with Claude Code
https://claude.ai/code/session_014SfR2YzLxRH54DAVzDk8gR