RELEASE
planning/2.8.5/audits/AUDIT_U5_folder-reorg-css-split.md
sha256 4f63041bb87b0d45 · 11412 bytes ·
original held in the private archive
# AUDIT — U5: js/ folder reorg + css/terminal.css split (2.8.5 U-A2)
**Scope:** the two commits on `dev` after `f746675` — `69065ac` (reorg + CSS split) and `9274c75` (flatten CSS naming). Diffed against `f746675`.
**Method:** independent, diff-first. CSS concatenation reconstructed and byte-compared by hand; helper logic executed, not eyeballed; commit messages read only after forming the view below.
**Gate:** 2958 tests / 221 suites / cache r7, green (not re-run — correctness is mechanically covered; this audit targets what the gate cannot see).
---
## VERDICT: **ACCEPT**
This is a genuinely clean pure-relocation unit. The CSS cascade is **provably identical** to the pre-split monolith (independently reconstructed). The gate was **not weakened** anywhere. `readGroup` did **not** get weaker — it resolves to the full file set. Both prior-audit findings are **closed at the root**. Every finding below is NOTE-level (cosmetic / doc-hygiene). No BLOCKER, no correctness SHOULD-FIX.
Headline answers:
- **CSS cascade provably identical?** — **Yes.** Reconstructed the 12 files in `<link>` order and diffed against `f746675:css/terminal.css`: every non-blank line is byte-identical; the only differences are 10 trailing blank lines trimmed at section boundaries (cascade-neutral, and the implementer declared this). No rule moved relative to any other. No `@import`. 99-mobile.css is last.
- **Gate weakened anywhere?** — **No.** `assert()` literal count identical (2474→2474); the +5 runtime tests are real (Suite 90 widened by 5 files). Removed lines are path re-points to the new subfolders (strengthened). No test skipped, deleted, or made vacuous.
- **`readGroup` quietly weaker?** — **No.** `readGroup('ui-core')` resolves to all 6 siblings; `allJsFiles()` covers all 22 non-vendor js files with vendor correctly excluded. A genuinely-missing file hard-fails (`exit 1`) in both runners — no vacuous-pass path.
- **Prior findings closed at root, or just moved?** — **Closed at root.** Suite 62's fetched-asset scan now derives from `allJsFiles()` (full `js/**` glob, vendor excluded); Suite 90's mojibake list was widened to include all five `ui-core-*` files with correct subfolder paths.
---
## What was verified (evidence)
### 1. CSS cascade — the highest-risk item — is provably identical
- Each of the 12 files carries an 18-line header comment declaring its original line range. The ranges are **contiguous and exhaustive**: 1-494, 495-1287, 1288-1821, 1822-2601, 2602-4914, 4915-7009, 7010-8533, 8534-10023, 10024-10793, 10794-11804, 11805-13078, 13079-13169. No gaps, no overlaps.
- **Independent reconstruction:** stripped each 18-line header, concatenated content in `<link>` order, diffed against `f746675:css/terminal.css`. Result: **every non-blank line byte-identical.** The only 10 diffs are single blank lines trimmed at 10 of the 12 section boundaries — all confirmed to sit between a `}` and the next section's `/* ═══ */` banner (cascade-neutral whitespace).
- `<link>` order in `index.html` is exactly `05 → 10 → 15 → 20 → 25 → 30 → 35 → 40 → 45 → 50 → 55 → 99`. 99-mobile.css is genuinely last.
- Split-file headers are valid CSS comments (`/* … */`), no stray `*/` in any header body — so the browser (which loads whole files, headers included) sees only inert comments between sections.
- No `@import` anywhere in `css/`.
- **This order is guarded in the gate**, contrary to the runner comment (see Finding N1): `scripts/check-boot-chain.js` CHECK I asserts `index.html`'s `<link>` order equals the canonical order exactly; CHECK J asserts `css/` on disk holds exactly the 12 files (no orphan, no leftover `terminal.css`); CHECK K asserts precache coverage. `check-boot-chain.js` runs in `gate.js` on both commit and push (gate.js:303/322).
### 2. Path re-sync — all load-bearing references resolve
- `sw.js` ASSETS: all 36 js/css entries exist on disk. `index.html` script srcs + `GAME_FILES` manifest: all resolve. `tests/test.html` boot chain: all resolve. `repomix.config.json` uses recursive `js/**` / `css/**` with `js/vendor/**` ignored. CI workflows carry no css/js literal paths.
- `eslint.config.mjs` `files:` / `ignores:` arrays are correct (`js/services/cloud.js`; `js/vendor/` intact — so the vendored bundle is still excluded from lint/format). `.prettierignore` keeps `js/vendor/` intact.
- `scripts/check-boot-chain.js` was carefully rewritten for subfolders (tracks full relative paths; collapses to bare stem only for the doc LOAD-ORDER comparison) and runs in the gate.
### 3. `readGroup` / `allJsFiles` — not weaker
- Executed the helper logic directly: `readGroup('ui-core')` → 6 files (`ui-core.js` + the five `ui-core-*.js`); `readGroup('api')` → `services/api.js`; `readGroup('state')` → `core/state.js`.
- `allJsFiles()` → 22 files = exactly the physical non-vendor `.js` set; nothing missed; the 3 `js/vendor/*.js` files correctly excluded.
- Signature unchanged (`readGroup(stem)`). Both runners' file readers (`readFile` / `Read-Src`) have a legacy-flat-path → subfolder fallback resolver and **hard-fail** (`exit 1` / `Fail`) on a truly missing file, so flat-path call sites (e.g. ps1 Suite 59's `$jsFiles59`) resolve correctly and cannot silently read empty.
### 4. Prior findings closed at root
- **Suite 62 (fetched-file-published guard):** now scans `allJsFiles()` (full `js/**` glob, vendor excluded) instead of a hand-list — the ui-core-* siblings are covered by construction.
- **Suite 90 (mojibake/UTF-8 guard):** list widened from 7 js files to 12 (adds the five `ui-core-*`), with every path updated to its subfolder location. This is the source of the +5 tests (2953→2958) — genuine guards, not padding. Mirrored in the ps1 runner at parity (GATE-CORRUPT-8…12).
### 5. Move-not-change invariant holds
- All 22 `js/*.js` files are pure renames (git `R100`, 0 content lines changed).
- CSS content byte-identical modulo the 10 boundary blank lines (§1).
---
## Findings (all NOTE)
### N1 — Runner comment points to a nonexistent "Suite 220bis" CSS-order guard
**What:** In both runners, the `CSS_SPLIT_FILES` / `$CSS_SPLIT_FILES` header comment states: *"…the CSS-order guard (Suite 220bis below) all derive from/are checked against."* There is **no Suite 220bis** and no CSS link-order assertion in either test runner (grep confirms `CSS_SPLIT_FILES` is used only by `readCss()`). The actual order guard lives in `scripts/check-boot-chain.js` (CHECK I/J/K) — which the `69065ac` commit message itself correctly describes ("extended with a CSS link-order guard"). So the code's own comment contradicts where the guard really is.
**Why it matters:** A maintainer trusting the comment will search for "Suite 220bis," not find it, and may either waste time or wrongly conclude the runners guard cascade order (they don't — `readCss()` reads its own hardcoded order and is used only for order-insensitive content checks). This is exactly the "comment that now lies" class, and this project runs a whole protocol (45 / Suite 220) against docs naming things that don't exist — ironically that guard doesn't scan test-runner internal comments.
**Severity:** NOTE (misleading only; the invariant is genuinely guarded by check-boot-chain).
**Fix:** Change the comment in both runners to point at `scripts/check-boot-chain.js` CHECK I/J/K instead of "Suite 220bis below."
### N2 — Three duplicated hardcoded ordered CSS lists; only one is cross-checked
**What:** The canonical split order is hardcoded in three places: `CSS_SPLIT_FILES` (js runner), `$CSS_SPLIT_FILES` (ps1 runner), and `CANONICAL_CSS_ORDER` (check-boot-chain.js). Only `CANONICAL_CSS_ORDER` is validated against `index.html`'s `<link>` order (CHECK I). The two runner copies are unguarded duplicates.
**Why it matters:** If a runner copy drifts from `index.html` order, `readCss()` would concatenate in a different order than the browser cascade — undetected. Impact is low today because `readCss()` output is consumed only by order-insensitive `.includes()` / regex content checks, but it's a latent single-source-of-truth gap (Protocol 22 spirit).
**Severity:** NOTE.
**Fix (optional):** have the runners assert their list equals the `<link>` order parsed from `index.html` (or derive it from `index.html`), collapsing the three copies toward one checked source.
### N3 — "byte-identical to that line range" header wording vs. the trimmed boundary blank lines (DECLARED)
**What:** Each split file's header claims its content is *"byte-identical to that line range in the pre-split terminal.css."* In fact 10 of 12 declared ranges lost their single trailing blank line (e.g. `05-base.css` declares lines 1-494 but contains 1-493; original line 494 was blank and dropped). This is **declared** — the `9274c75` commit message says "byte-identical (mod Prettier's blank-line normalization)."
**Why it matters:** Zero cascade impact; purely a wording precision issue between the per-file header ("byte-identical") and the acknowledged normalization. Only flagged because the headers are the artifact a future reader trusts.
**Severity:** NOTE (declared / cosmetic).
**Fix (optional):** soften the header wording to "content of that line range, modulo trailing-blank-line normalization."
### N4 — Stale path comments left in `eslint.config.mjs` and `scripts/pre-commit`
**What:** `eslint.config.mjs`'s `globals` block has dozens of trailing comments naming old flat paths (`js/state.js`, `js/api.js`, `js/ui-render.js`, and even `js/ui.js`, which was retired in U-A1). `scripts/pre-commit`'s secret-scan comment says `js/cloud.js` (now `js/services/cloud.js`).
**Why it matters:** Non-load-bearing — eslint globals are keyed by name, not path, and the secret-scan matches the basename substring `/cloud\.js/` (still correct for `js/services/cloud.js`). Purely stale documentation inside config files. (Some `js/ui.js` comments predate this unit.)
**Severity:** NOTE.
**Fix (optional):** batch-update the path comments, or drop the paths from them.
### N5 — Suite 90 mojibake list omits the data files that actually contain non-ASCII (PRE-EXISTING)
**What:** Protocol 39 states the per-game data files (`db_nv.js` / `db_fo3.js` / `reg_nv.js` / `reg_fo3.js`) contain `æ`/`¡`, yet Suite 90's hand list (api, state, ui-*, docs) does not include them. A PowerShell-corruption of a data file would not be caught by Suite 90.
**Why it matters:** This is a **pre-existing** gap, not introduced by this unit — but the unit touched Suite 90 (widened it), so it's the natural moment to note it. Suite 90 is deliberately a fixed hand list (not a glob) to stay Protocol-2a-stable; adding the four data files would be a one-time widen.
**Severity:** NOTE (pre-existing; out of this unit's declared scope).
**Fix (optional, separate unit):** add the four data files to `srcFiles90` / the ps1 equivalent, syncing counts per Protocol 2a.
---
## Bottom line
Pure, well-executed relocation. Cascade independently proven identical; gate integrity intact; helpers verified to resolve the correct full file sets; both prior findings closed at the root. The only genuinely undiscovered issue is a stale in-code comment (N1) referencing a suite that doesn't exist — worth a one-line fix but not blocking. Everything else is cosmetic doc drift or declared/known. **ACCEPT.**
STAMP · generated for RELEASE v2.8.5 commit 06e5180 (06e51801b38a) · archive input-tree hash c07fbfbdd2e1ddeb · 754 files · no wall-clock timestamp (regenerates identically when nothing changed).