b1d5fbefcba02fdc6c19fef85cec1c4e82fc8dea
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a7d91bf15a |
fix(876): sweep session narrative out of hooks, workflows, scripts, tests and code comments; grow the detector to the process corpus
Build ErsatzTV Image / CI toolchain image resolves (pull_request) Successful in 35s
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 57s
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 37s
PR Gates / Docs update reminder (pull_request) Successful in 1m0s
PR Gates / decisions lifecycle (pull_request) Successful in 20s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 17s
review-verdict/h10 Review-verdict: MERGEABLE @ a7d91bf (base: main)
Review verdict / Set review-verdict status (pull_request_target) Successful in 45s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 9m25s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 6m17s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Skipped
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Successful in 19m27s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Successful in 6m4s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 8s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 7s
`docs.no-session-narrative` reaches every durable artifact, but its detector scanned only `docs/**/*.md` and root markdown, and nothing had ever swept the rest. The issue named four sites from one grep and called them a floor. Deriving the population instead — a whitespace-joined sweep over every tracked file outside the detector, for the detector's own phrasings plus the attribution and review-round class #812 found — gave 453 sites in 108 files at `fb5592971`, and a second pass for phrasings the first list missed (hyphenated `round-N`, "an earlier version", "the reviewer proved") added residuals in the same files. Every site was classified with #812's three dispositions (CUT / SEVER / KEEP with its sub-kind) under the who-benefits test; the per-site manifests are on the PR. The rejected designs, tested-and-rejected fixtures, measurements and traps stay; the attribution of who found them and the round in which they were found go. The detector's population grows to `.claude/`, `.gitea/`, `.husky/` and `scripts/` regardless of extension, minus the detector and its own test (whose fixtures ARE the phrasings) and minus `scripts/tests/fixtures/` (test data, including decision-record copies — the same reasoning as the records' own exemption, and what keeps the record's depth measurement true), and `--all` lists tracked REGULAR files only — a symlink's content is its target and a gitlink has none. The #812 argument for leaving `docs/superpowers/**` in the population runs the other way here: `--diff` sees only ADDED lines, and 287 of the 453 sites were under 30 days old — this corpus is where narrative is being added, so the advisory nudge has reach. Density agrees: 56 line-mode hits over the 113 regular files the predicate admits, against 9 over 66 docs files before #812. `web/` and C# stay out on the same measurement (3 of 74 PATTERNS-matching sites, ~4,600 files). The predicate did not grow: PATTERNS matched 74 of 453 sites, and widening the word list to the attribution class is the treadmill the withdrawn parity test ran on. The population oracle is restated over segments with the new arms, the synthetic cross product gains the process heads and non-markdown extensions, a fixture witnesses that a tracked symlink is neither scanned nor counted, a `.py.bak` axis separates a by-name exemption from a `startswith` over the same tuple, and eight mutants (drop the process arm, drop the by-name exemption, exempt by `startswith`, drop or add a prefix, drop the fixtures exemption, list only markdown, drop the symlink filter, test the mode per row instead of per path) each redden it. A pre-existing silent drop in `--diff` goes with it: git tab-terminates a `+++` filename that contains a space, and the kept tab made `is_scanned_path` refuse the file with no notice — fixed, with a positive control and its own mutant. Code is unchanged by construction, measured per file type against `origin/main`: Python modules are AST-equal with docstrings stripped, except `#` lines inside the embedded fixture programs (string literals) of three test modules; workflows differ only in `#` lines inside `run:` block scalars; shell, C#, TypeScript and jq are equal with comment lines stripped. The stated exceptions: the detector and its test, 26 vitest titles that carried review-round or severity labels or a reviewer attribution (call sites whose title changed — every changed title line walked back to its `it(` / `it.each(...)(` anchor, so a `' + '` concatenation counts once), two registry note strings and the mutation manifest's prose fields. scripts/tests: 1565 passed. Web: lint, typecheck, 1319 tests green. Closes #876. Decisions-Edit: yes Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PEcBoFw7ctrf3Nb7R7x7wk |
||
|
|
3ec73f3769 |
fix(887): a pin assumes it is pinning the thing that still DECIDES
Round 6 found three more false greens and named the class they share, which is worth
more than any of the three fixes:
* `web/vitest.config.ts` OUTRANKS the pinned `vite.config.ts` — closed in the previous
commit, found by probing vitest rather than reading about it.
* A DECOY first `test: {` block. The comparison took `text.index("test: {")`, so a copy
of the pin placed above `defineConfig` satisfied it while the real block was narrowed.
Exactly one is now required — the same assertion this file already made about the
gating step's NAME, for the same reason, not carried across.
* A `needs:` edge matched by bare job id. `needs:` resolves within its own workflow, so
a SECOND workflow publishing this Dockerfile while needing its own unrelated job
called `test` satisfied it. Now bound to `GATING_WORKFLOW`. (The reviewer downgraded
this to MEDIUM on measuring that `test_remote_state_inventory.py` forces a human to
classify any new workflow — so the hole is "the guard is blind", not "silent". The
forced review asks about remote state, not about whether the image is gated, so the
one-line fix stands.)
* A vite PLUGIN can shell out to the suite from `buildStart()`. The plugin ARRAY is
pinned; the plugin BODIES are a stated residual, mitigated because
`trackedSourceFilesPlugin` is deliberately lazy — a fact its own comment now marks as
LOAD-BEARING for the image build rather than leaving as an optimisation note.
THE CLASS: **a pin assumes it is pinning the artifact that still decides.** Every route
found so far is authority moving where the pin is not looking — to another FILE, another
OCCURRENCE in the same file, another WORKFLOW, or a HOOK the pinned command invokes. That
question is now written down for the next person adding a pin, because a list of four
instances is not what generalises.
Prose, all refuted by execution: the residual naming the uncovered COPY shapes was wrong a
THIRD time at the same site (`/source/web /elsewhere` IS recognised — only the destination
is renamed — and the file's own test 700 lines below said so); "only an `ENV` is
unmodelled" was an absolute and is now a list; "Reach: N mutants, 0 missed" is restated as
a DEVELOPMENT BATTERY, since it is not in the repo, nothing re-derives it, and an
independent battery found misses against an earlier head; and `PUBLISH_ACTION` was claimed
covered by anti-vacuity, which proves the selector is non-empty and cannot prove it
complete.
Battery 61 -> 64, 0 missed.
Refs: #887
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019T79beF1Ufid3dXju4yqkF
|
||
|
|
a4df8f7958 |
fix(887): the gate must be REAL, not merely present — two cold reviews' findings
Both independent reviews (Codex GPT-5.6 cross-family, and a cold Opus agent in an isolated worktree) returned BLOCKED. Both independently confirmed the CI path itself is sound — neither found a route that publishes an image on which the suite never ran — so every finding is about the guard's reach, plus one factual error in the prose. THE STRUCTURAL ONE. The guard asserted a `needs:` edge EXISTS, never that it is load bearing. Since this change deletes the in-image run, that edge is the only remaining layer, so `continue-on-error: true`, `if: false`, a job-level `if:`, `npm test … || true`, a pipe into `tee`, and `set +e` each certified a publish over a red suite with every assertion green. `test_the_gating_suite_run_is_NOT_ADVISORY` closes all six. A filter written into `web/package.json`'s script body was invisible at the call site: `"test": "vitest --exclude x"` with a workflow saying `npm test -- --run` is a filtered gating run reading as clean — the removed defect, one level down. `vitest_scripts()` now derives each script's own narrowing arguments and `suite_args` prepends them. PARSER REACH, every case measured rather than argued. `shlex.split` yields `lint&&npm` as one token, so unspaced `&&` and `;` re-adds were invisible; `shlex` in punctuation_chars mode splits them. Added: `sh -c` payload expansion, `npm --prefix`/`npx -p` flag skipping, `xargs`, heredoc bodies as DATA (a `cat > f <<'EOF' … npm test … EOF` block counted as a real run), `ADD`/JSON-form/no-trailing-slash `COPY` in `carries_spa_source`, and redirections no longer read as spec filters. `--root` and `--config` moved to the narrowing set: both change which specs vitest collects. A FACTUAL ERROR, in five places including the mutation `expect`: "the build context is `web/` + `design-system/`, so there is no `.git`". The context is the repository root (`context: .`) and `.dockerignore` does not exclude `.git`. The true statement is about the STAGE, which copies only those two directories. The conclusion survives — bookworm slim has no git binary either — but a reader who checked would have found `.git` in the context and concluded the note was stale. ONE FINDING WAS MINE, from the mutant battery rather than from either review, and it is the reason the battery exists: `failure_suppressions` tokenised the whole multi-line `run:` body at once. A newline is not a shell separator, so a realistic two-line step — the `ci-step-ran.sh` marker line, then the suite — merged into ONE segment whose head was the marker script, and three suppression mutants passed while my single-line unit test was green. It now works per logical line, and the regression test uses the two-line shape. 17 mutants, 0 missed, each caught by the intended assertion; baseline green. The `docs/guard-inventory.md` residual list is rewritten as MEASURED reach — the previous one was wrong rather than merely short, which cold review rightly called worse than silence. Refs: #887 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019T79beF1Ufid3dXju4yqkF |
||
|
|
febaad77d7 |
fix(887): the image build builds the SPA and does not test it
`docker/Dockerfile`'s web-build stage is gitless twice over — the build context is `web/` + `design-system/` so there is no `.git`, and `node:22-bookworm-slim` ships no git binary. Members of the SPA suite need one or the other, so running the suite there required naming the ones that cannot run. That list was a population nothing derived: #883 added a third member without updating the hand-written pair of `--exclude`s, and because `Build & push image (amd64)` is `if: github.event_name != 'pull_request'` the resulting red was unreachable on a PR. It landed on `main` and on the `v*` tag path instead — every image build failed, `:latest` stopped being republished, and a release cut would have failed at the image build. Adding a third `--exclude` re-arms the trap, so the list is removed rather than extended: the stage now lints, typechecks and BUILDS the SPA, and the suite runs once, unfiltered, in `docker-build.yml`'s `test` job on a real checkout. `build` carries `needs: [test, migrations, scan]`, so no image is published past a red suite. `scripts/tests/test_image_build_delegates_the_spa_suite.py` holds both halves — the negative one alone would be satisfied by deleting the `needs:` edge. Three populations, all derived: tracked Dockerfiles and workflows from the git index, and which npm scripts ARE the suite from `web/package.json` (so `test` is in and the Playwright `test:ui-e2e` is out, with no exemption list). Publishing jobs come from the `docker/build-push-action` step and the Dockerfile each builds from that step's own `file:` input, which is why `ci-image.yml` is out of scope by derivation rather than by an entry that would outlive its reason. Four mutants witnessed red, each by the intended test: a filtered suite run put back into the Dockerfile, the `needs:` edge deleted, and the gating run narrowed in both the block and the single-line `run:` step forms. Refs: #887 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019T79beF1Ufid3dXju4yqkF |
||
|
|
8aeacd534a |
fix(819): derive the SPA page-size guard population from the git index (#875)
Build ErsatzTV Image / CI toolchain image resolves (push) Successful in 9s
Build ErsatzTV Image / Delimiter ban (release path) (push) Successful in 21s
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 8m52s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 6m23s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (push) Successful in 5m50s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (push) Skipped
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (push) Skipped
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 5m5s
The guard asserted EXACT completeness over a population enumerated by a directory walk, so an untracked .ts/.tsx under web/src/ entered it and failed as unregistered on that developer's checkout while CI — which only ever checks out tracked files — stayed green. The glob still supplies file CONTENT; the POPULATION is now the git index, read by web/vite-plugins/trackedSourceFiles.ts in Vite's own Node context and handed to the app project as a virtual module. That reaches the index without admitting @types/node to tsconfig.app.json, the obstacle that deferred this in #818. Three mechanisms carry the proof, each added because the previous was measured insufficient: a closed-form restatement of the shared scope predicate (sharing no helper at any depth with what it checks); a second independent `ls-files --others` query cross-checking the population; and real-git tests that execute the derivation against a temp repository. Six residuals are stated with their MEASURED fail-directions, and testing.guard-derives-population-from-source gains a bounded exception plus the closed-form criterion. fixes #819 Co-authored-by: Timothy <timothy@noreply.gitea.tblindustries.be> |