Add RFC process, specifications, layered tests, and a gated CI/CD pipeline - #1
Merged
Conversation
…eline The site deployed on every push with nothing verifying the result. For a site whose value is that it renders correctly, the interesting failures are silent ones: a path that stops resolving, a deck that stops advancing, prose that stops being true. None are caught by a build step, because there is no build step. Process (RFC 0001): substantive changes are proposed as an RFC, specified as numbered requirements carrying RFC 2119 keywords in docs/specs/, and covered by tests annotated @Req. tools/spec-trace.js fails the build when a MUST-level requirement has no test, or a test names a requirement that does not exist, so the specification and the suite cannot drift apart. Pipeline (RFC 0002): validation (static, ~1s), functional, end-to-end, regression, and visual layers. ci.yml is a reusable workflow called both by the pull-request gate and by pages.yml before it deploys, so the two gates cannot diverge. Browser tests stub external font requests for determinism and fail on any other off-origin request, which enforces the no-CDN rule at runtime. Visual comparison is pinned to the Linux runner and skips loudly rather than passing silently when no baseline exists; baselines are refreshed by a workflow that opens a pull request of images. 71 requirements, 58 mandatory, 125 tests. Two defects surfaced while writing this and are fixed here: - Windows checkouts rendered every deck blank. support.js loads the vendored React bundles with a Subresource Integrity digest, and SRI hashes exact bytes. With no .gitattributes, Git rewrote LF to CRLF on checkout, the digests stopped matching, React never loaded, and because the runtime hides the authored markup before booting, the pages rendered nothing with no visible cause. The published site was never affected. .gitattributes prevents it; SITE-016 detects it. - The five .dc.html pages and pocket-planetarium.html declared no <title> and no lang, so browser tabs, bookmarks, and print-to-PDF filenames were all unnamed on pages explicitly meant to be printed. Two known deviations are recorded rather than hidden, in docs/specs/site.spec.md: the Pocket Planetarium loads its runtime from unpkg (D-1), and the deck runtime requests un-substituted {{ }} placeholders before boot (D-2). The README no longer claims the whole site is CDN-free, which was untrue of the prototype.
Leaves configure-pages, upload-pages-artifact and deploy-pages pinned: a breaking change in those would not surface until a merge to main, so they are better reviewed as their own Dependabot pull request than bundled in here.
Protonmatter
added a commit
that referenced
this pull request
Aug 18, 2026
…undles (#2) ## What Adds `.gitattributes` to `main`, taken verbatim from the `topic/quality-gates` branch where it was written. ## Why this cannot wait for #1 Cloning this repository on Windows today produces a completely broken working copy, and the cause is invisible. `support.js` loads the vendored React, ReactDOM and Babel bundles with a Subresource Integrity digest, and SRI hashes exact bytes. Git's default on Windows (`core.autocrlf=true`) rewrites LF to CRLF on checkout, so the digests stop matching, the browser refuses to execute the bundles, and React never loads. Because the runtime hides the authored markup before booting, the result is HTTP 200, no broken links, no console error, and nothing on screen. `.gitattributes` exists on `topic/quality-gates` (#1), but that does not help anyone cloning before it merges, and it does not help the clone itself: `git clone` checks out the default branch first, so `main` having no `.gitattributes` is what does the damage. ## Verification Cloning each branch with `core.autocrlf=true` and hashing the result: | Bundle | `main` today | with this change | declared in `support.js` | | --- | --- | --- | --- | | `react.production.min.js` | `sha384-t63xaoqI4/…` | `sha384-DGyLxAyjq0f9…` | `sha384-DGyLxAyjq0f9…` | | `react-dom.production.min.js` | `sha384-8Y1L+f1y2tWR…` | `sha384-gTGxhz21lVGY…` | `sha384-gTGxhz21lVGY…` | | `babel.min.js` | `sha384-nFyaaMobkrf0…` | `sha384-m08KidiNqLdp…` | `sha384-m08KidiNqLdp…` | Serving each clone and loading `solar-system.dc.html`: - `main` today: `window.React` undefined, 0 characters rendered - with this change: React 18.3.1, page renders ## No renormalisation needed The committed blobs are already pristine LF: their SHA-384 digests match the SRI constants `support.js` declares, and they contain zero CRLF byte pairs. This change only stops the checkout filter from touching them, so no file contents change and no `git add --renormalize` is required. ## Merge order Independent of #1 and safe to merge first. The file is byte-identical to the copy on `topic/quality-gates`, so #1 will not conflict on it.
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.
What this changes
Introduces an RFC process, normative specifications, a five-layer test suite, and a CI pipeline that gates the Pages deploy on it. Also fixes two defects the work surfaced.
Why
The site deployed on every push with nothing verifying the result. For a site whose value is that it renders correctly, the interesting failures are silent ones: a path that stops resolving, a deck that stops advancing, prose that stops being true. None are caught by a build step, because there is no build step — they have to be caught by executing the pages.
Process — RFC 0001
Substantive changes are proposed as a numbered RFC, specified as requirements in
docs/specs/carrying RFC 2119 keywords and stable identifiers, and covered by tests annotated@REQ <ID>.tools/spec-trace.jsfails the build when a MUST-level requirement has no test, a test names a requirement that does not exist, or an identifier is defined twice — so the specification and the suite cannot drift apart.71 requirements, 58 mandatory, 125 tests.
Pipeline — RFC 0002
node --testci.ymlis a reusable workflow called both by the pull-request check and bypages.ymlbefore it deploys, so the merge gate and the deploy gate cannot diverge. A red gate now leaves the live site untouched.Browser tests stub external font requests for determinism and fail on any other off-origin request, enforcing the no-CDN rule at runtime as well as in source. Visual comparison is pinned to
ubuntu-24.04and skips loudly when no baseline exists rather than writing one and passing; baselines are seeded by the Update visual baselines workflow, which opens a pull request of images.Defects fixed
Every deck rendered blank on any Windows clone.
support.jsloads the vendored React bundles with a Subresource Integrity digest, and SRI hashes exact bytes. With no.gitattributes, Git's default Windows behaviour rewrote LF to CRLF on checkout, the digests stopped matching, React never loaded — and because the runtime hides the authored markup before booting, the pages rendered nothing at all, with HTTP 200 and no broken links.The published site was never affected, which is what made this so hard to diagnose: it only ever broke on a contributor's machine, with no visible cause.
.gitattributesprevents it;SITE-016detects it. Verified against a fresh clone as byte-identical to the committed blob.Six pages had no
<title>and nolang. The five.dc.htmlpages andpocket-planetarium.htmldeclared neither, leaving browser tabs, bookmarks and print-to-PDF filenames unnamed — on decks explicitly meant to be printed.Known deviations, now recorded rather than implicit
Both in
docs/specs/site.spec.md:{{ }}template placeholders before boot, producing three harmless 404s on the explorer.Each is excluded from the requirement it violates in one named place, with a reason, rather than the requirement being quietly written loose enough to pass.
Requirements touched
Adds the initial requirement set:
SITE,DOCS,DECK,LAND,BETA,EXPL,FLOW,VIS. All 58 mandatory requirements are covered; the two uncovered SHOULD-level ones (SITE-013,BETA-005) are reported as notes by design.Checklist
npm testpasses locally (21 validation, traceability OK, 104 browser)docs/specs/and annotated@REQin testsVisual impact
None. The six pages gain a
<title>andlangattribute; nothing rendered changes. No visual baselines exist yet — seed them with the Update visual baselines workflow after merge.