Audit H6: an imperative lives in a comment, not in an expression - #6
Merged
Conversation
Closes audit H6, the largest single cause of real code not being optimized —
`CONSTRAINT_DIRECTIVE_LOST` accounted for 24 of 40 fallbacks on the audit's
corpus.
The nine-keyword scan (`must`, `must not`, `never`, `always`, `only if`,
`do not`, `required`, `except when`, `make sure to`, `critical`) is written for
natural-language system prompts, and was applied to raw content of every kind. In
source, `required` and `critical` are ordinary identifiers.
Measured over a frozen 293-file corpus at `targetReductionRatio: 0.3`,
classifying every directive a run reported as dropped by where it came from:
Python 16 from comments/docstrings, 38 from code — nearly all
`logger.critical(...)`
TypeScript 38 from comments/docstrings, 13 from code — `readonly required?`,
error-message literals
That rules out both extremes. Trusting the check everywhere keeps 51 false
positives. The audit's proposed remedy — scope extraction by content type, not
`code` — discards 54 genuine constraints, and specifically the Python docstring
case that `docs/phase-1d-semantic-gate-disposition.md` measured to be the only
thing this check actually catches. What separates the two populations is not the
content type but the region: an instruction to a reader lives in a comment or a
docstring, never in an expression.
So extraction is scoped to prose regions — line comments, block comment bodies
and Python docstrings including their interior lines, plus whole content for
prose content types. Deliberately line-oriented and syntax-approximate rather
than lexed: this is a filter on what may *raise* a constraint, so over-inclusion
costs a false positive (the pre-existing behaviour) and under-inclusion costs a
missed constraint. Requiring the comment leader at the start of a trimmed line is
what excludes `logger.critical(exc)` while keeping `# never call this twice`.
Retention is now checked per item. The check collected every item's directives
into one list and tested each against the joined content of every item, so a
directive from item A was satisfied if the string happened to appear anywhere in
item B — the check could pass for content that was in fact destroyed — and a loss
anywhere failed the whole run with no way to say where. Matching by item id fixes
both and the message names the item. An item absent from `after` is skipped, on
the same reasoning `DriftTracker.findUnwitnessedItems` records: selection is not
elision, and failing here would make any prunable item carrying an imperative
unprunable.
Measured:
python file 14.98% -> 23.14% (+8.16pp)
python stdin 14.88% -> 22.66% (+7.78pp)
typescript file 23.38% -> 27.33% (+3.95pp)
20 rows changed of 586, and none regressed — no file went from reducing to
falling back. Every other bucket is byte-identical.
TypeScript now has zero remaining code-sourced directives; every surviving
`CONSTRAINT_DIRECTIVE_LOST` is a genuine imperative in a comment or docstring
that an elision would drop. Those files still fall back, and should. That is why
the category does not go to zero.
Ordering note: this had to land after §37 (C1a). The audit observed that this
check was "currently the only thing preventing markdown documents from being
deleted" — a document survived if its author happened to use one of nine words.
Narrowing it first would have widened that data loss. With §37 in place the drift
measurement gate covers markdown on its own merits, which the corpus confirms:
the prose bucket is unchanged at 28/28 fallbacks, now attributed to drift rather
than to a coincidence of vocabulary.
New tests verified to fail 9/11 against the unfixed code; the 2 that pass are the
ones pinning behaviour H6 must preserve.
See DECISIONS §42.
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 audit H6 — the single largest cause of real code not being optimized.
CONSTRAINT_DIRECTIVE_LOSTaccounted for 24 of 40 fallbacks on the audit's corpus.The audit's proposed fix would have destroyed real protection
The nine-keyword scan (
must,must not,never,always,only if,do not,required,except when,make sure to,critical) is written for natural-language system prompts, and was applied to raw content of every kind. In source,requiredandcriticalare ordinary identifiers.The audit's remedy was "scope directive extraction by content type (prose/markdown/prompt kinds only, not
code)". I measured where the dropped directives actually come from, over a frozen 293-file corpus attargetReductionRatio: 0.3:logger.critical(...)readonly required?, error-message literalsSo neither extreme works. Trusting the check everywhere keeps 51 false positives; the audit's version discards 54 genuine constraints — and specifically the Python docstring case that
docs/phase-1d-semantic-gate-disposition.mdmeasured this check to be the only thing catching.What separates the two populations is not the content type but the region. An instruction to a reader lives in a comment or a docstring; it never lives in an expression.
Part 1 — extraction is scoped to prose regions
extractProseRegionsreturns whole content for prose content types, and for code returns line comments (//,#,--,*), block comment bodies, and Python docstrings including their interior lines.Deliberately line-oriented and syntax-approximate rather than lexed: this is a filter on what may raise a constraint, so over-inclusion costs a false positive (the pre-existing behaviour) and under-inclusion costs a missed constraint. Requiring the comment leader at the start of a trimmed line is exactly what excludes
logger.critical(exc)while keeping# never call this twice.Part 2 — retention is checked per item
The check collected every item's directives into one list and tested each against
after.items.map(i => i.content).join('\n'). Two problems:Matching by item id fixes both, and the message now names the item. An item absent from
afteris skipped, on the same reasoningDriftTracker.findUnwitnessedItemsrecords: selection is not elision, and failing here would make any prunable item carrying an imperative unprunable.Measured
20 of 586 rows changed, and none regressed — no file went from reducing to falling back. Every other bucket is byte-identical.
What deliberately remains
After the change TypeScript has zero remaining code-sourced directives. Every surviving
CONSTRAINT_DIRECTIVE_LOSTis a genuine imperative in a comment or docstring that an elision would drop, and those files still fall back — correctly, since the run would otherwise silently delete an instruction. That is why the category does not go to zero.Ordering note for reviewers
This had to land after C1a (#3). The audit observed that this check was "currently the only thing preventing markdown documents from being deleted" — a document survived if its author happened to use one of nine words. Narrowing it first would have widened that data loss.
With C1a in place the drift measurement gate covers markdown on its own merits, and the corpus confirms the handoff: the prose bucket is unchanged at 28/28 fallbacks, now attributed to drift rather than to a coincidence of vocabulary.
Verification
npm run typecheck,npm run lint— cleannpx vitest run— 518 passing, 59 files (up from 507)Cumulative across the stack
Python 14.98% → 23.14%, TypeScript 14.00% → 27.33% — while every gate got stricter: max passing symbol loss fell 66.7% → 40% (#4), and the surviving-witness rule (#3) closed whole-document deletion.
Still open
H5 / §3.1 (multi-item ingestion — the highest structural leverage left, and what would make the knapsack reachable), C4, H4, H2, and the M-tier stragglers.
🤖 Generated with Claude Code