audit H2/M1/M11: say what cannot be done, say what is checked, stop keeping two copies - #13
Merged
Conversation
…keeping two copies Closes the last three audit items — H2, M1 and M11 — which the audit filed as decisions rather than tasks because each had a legitimate "narrow the product" answer and a legitimate "build more" one. Reasoning, including the options refused, in DECISIONS §46. H2 — decided: report why, do not narrow the accepted set. Twelve of nineteen recognised extensions cannot produce a non-zero reduction under any flag combination, and that was indistinguishable from a file with nothing worth compressing. Rejecting `--language go` would be the stronger honesty signal and would also delete a working behaviour — pass-through is byte-identical and harmless. So every language is still accepted, and the run now says when elision cannot reduce it: `trace.languageSupport` carries `supported`, `unsupported`, `unsupportedLanguages`, `noneSupported` and a `reason`, and `validate()` raises an info issue, `LANGUAGE_NOT_ELIDIBLE`, that does not vote on the verdict. Same correction M5a made for budgets, one layer down. Three things this cost, all worth knowing. The predicate had to be derived from the gate rather than guessed: a first version asked "does the item yield symbols or markers?" and called Go supported, because a trivial Go file yields exactly one — `import:fmt`, an incidental match by the TypeScript import regex. The answer is exactly `supportsRegionElision`, since a symbol-bearing item cannot be elided whole (§43) and a symbol-free item's whole-item elision destroys every content marker and fails the same gate a step later. Measured, that predicts 3 of 17 probed languages — TypeScript, JavaScript, Python — which is the audit headline and the corpus agreeing independently. The field also had to be threaded through four separate whitelists that each enumerate their keys: `validate()`'s return, `createValidationReport`, `buildTrace` and `createOptimizationTrace`. Three dropped it silently, every time presenting as `trace.languageSupport: undefined` with everything else correct; the test asserts on the trace rather than on `validate()` for that reason. And a friendly CLI notice was written, then removed. The CLI prints the trace to stderr as a JSON document and consumers parse the whole stream — four of this repo's own tests among them. Prepending prose broke them. The explanation now lives inside the report as a `reason` field, so it is both machine-readable and readable and stderr stays parseable. M1 — decided: correct the documentation, do not wire the compiler API. The TypeScript "AST-lite validator" builds no AST; it is a lexer detecting unbalanced brackets and unterminated strings. Probed against the shipped code rather than taken from the audit — three audit claims in this project have failed that test (§40, §42, §45) — all of it reproduced: `const x = ;`, `import from "x";`, `let 123abc = 5;`, `const a = 1 +++++ 2;` and plain English prose all pass; only `super(; }` fails. Python is stronger and still passes prose; JSON is a real parser. `ts.createSourceFile` was refused on cost, not principle: `typescript` is a dev dependency today and promoting it to runtime costs install size and parse latency against a lexer running in single-digit milliseconds. Instead README and CLAUDE.md now say "bracket/quote integrity" and carry a per-language table of what each validator does and does not catch, and `test/unit/validator-guarantee.test.ts` pins every row as a characterization test — strengthen a validator and it fails on purpose, and the table moves with it. M11 — decided: retire the narratives and the root planning artifacts. Twelve files, 226 KB; markdown 31 files -> 19, markdown:src 1.40:1 -> 0.95:1. `docs/retired-documents.md` maps each file to where its conclusion lives and gives the `git show` command to read the original. The premise was stale and measuring it first changed what the decision was about. M11 was filed as 4.1:1; measured before acting it was already 1.40:1 — and not because the docs had shrunk (they had grown to 726 KB) but because src/ grew faster. Since 32.8% of src/ is comment prose, prose:code actually ran ~2.6:1. That reframes the finding: the problem is not bytes, it is two copies of an argument kept in sync by hand. In-source commentary is not that, and none of it was touched. Twenty-five source and test comments cite a retired document — the check the option called for, and the thing that nearly made this a bad change. They are marked `[retired]` rather than re-pointed: the citation names something git still holds, whereas re-pointing 25 citations at DECISIONS sections by hand would risk mapping some of them to the wrong place, trading a volume problem for a correctness one. CHANGELOG.md and DECISIONS.md keep their older citations untouched, each with a note saying why — they record what was true when written. Measurement: 574 of 574 corpus rows identical to the pre-change engine across 17 fields, same frozen corpus, varying only dist/. H2 refactored `selectElisionRegions` to derive its gate from a shared predicate, so this was a real risk rather than a formality. The corpus recipe moves again and both changes are mine: typescript 60 -> 61 (src/core/validation/language-support.ts) and prose 29 -> 18 (twelve documents retired, one added). `collect.js` refused on both before measuring anything. Suite: 599 passing (was 566), typecheck and lint clean. Every audit item is now closed. What remains is the architectural work in the status doc's §5, chiefly Phase 1c. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Closes the last three audit items — H2, M1 and M11. The audit filed these as decisions
rather than tasks, because each had a legitimate "narrow the product" answer and a legitimate
"build more" one. Reasoning, including the options refused, in DECISIONS §46.
Every audit item is now closed. What remains is the architectural work in the status doc's §5,
chiefly Phase 1c.
H2 — decided: report why, don't narrow the accepted set
Twelve of nineteen recognised extensions can't produce a non-zero reduction under any flag
combination, and that was indistinguishable from a file with nothing worth compressing.
Refused: rejecting
--language go. Stronger honesty signal, but it deletes a workingbehaviour — pass-through is byte-identical and harmless.
Taken:
trace.languageSupportcarriessupported/unsupported/unsupportedLanguages/noneSupported/reason, andvalidate()raises an info issue (LANGUAGE_NOT_ELIDIBLE)that doesn't vote on the verdict. Same correction M5a made for budgets, one layer down.
Three things worth flagging for review:
the item yield symbols or markers?" and called Go supported — a trivial Go file yields
exactly one symbol,
import:fmt, an incidental match by the TypeScript import regex. Theanswer is exactly
supportsRegionElision. Measured: 3 of 17 probed languages, which is theaudit headline and the corpus agreeing independently.
validate()'s return,createValidationReport,buildTrace,createOptimizationTrace. Three dropped it silently.The test asserts on the trace, not on
validate(), for that reason.consumers parse the whole stream — four of this repo's own tests do. Prepending prose broke
them. The explanation now lives inside the report as
reason.M1 — decided: correct the docs, don't wire the compiler API
The TypeScript "AST-lite validator" builds no AST. Probed against the shipped code rather than
copied from the audit (three audit claims here have failed that test — §40, §42, §45), all of it
reproduced:
const x = ;·import from "x";·let 123abc = 5;·const a = 1 +++++ 2;· English prosesuper(; }Refused:
ts.createSourceFile. On cost, not principle —typescriptis a dev dependencytoday; promoting it to runtime costs install size and parse latency against a lexer that runs in
single-digit milliseconds.
Taken: README and CLAUDE.md now say bracket/quote integrity, with a per-language table of
what each validator does and does not catch.
test/unit/validator-guarantee.test.tspins everyrow — strengthen a validator and it fails on purpose, and the table has to move with it.
M11 — decided: retire the narratives and root planning artifacts
Twelve files, 226 KB. Markdown 31 files → 19; markdown:src 1.40:1 → 0.95:1.
docs/retired-documents.mdmaps each file to where its conclusion lives and gives thegit showcommand to read the original.
The premise was stale, and measuring first changed what the decision was about. M11 was filed
as 4.1:1; measured before acting it was already 1.40:1 — and not because the docs had
shrunk (they'd grown to 726 KB) but because
src/grew faster. Since 32.8% ofsrc/is commentprose, prose:code actually ran ~2.6:1. So the finding isn't about bytes, it's about two copies
of an argument kept in sync by hand. In-source commentary isn't that, and none of it was touched.
Twenty-five source and test comments cite a retired document — the check this option called
for, and the thing that nearly made it a bad change. They're marked
[retired]rather thanre-pointed: the citation names something git still holds, whereas re-pointing 25 citations at
DECISIONS sections by hand risks mapping some to the wrong place — trading a volume problem for a
correctness one.
CHANGELOG.mdandDECISIONS.mdkeep their older citations untouched, each witha note saying why: they record what was true when written.
Verification
corpus, varying only
dist/. H2 refactoredselectElisionRegionsto derive its gate from ashared predicate, so this was a real risk rather than a formality.
noneSupportedwith its reason, aTypeScript file doesn't, and stderr still parses as JSON.
The corpus recipe moves again, both changes mine: typescript 60 → 61
(
src/core/validation/language-support.ts) and prose 29 → 18 (twelve retired, one added).collect.jsrefused on both before measuring anything.Left undone, deliberately
cli/bench-table-renderer.ts:97still prints ariskcolumn sourced fromriskTolerance, whichH4 established no stage reads. It's now the only reader of that field, and a benchmark column
implies the row's numbers depend on it. Small and real — left out because changing what a
benchmark reports is a measurement change, not a documentation one.
🤖 Generated with Claude Code