Repository navigation
fix(core): the shared rule's READER SET stops being counted by hand (#1096) - #1097
Conversation
…1096) The shared rule `scripts/tracked-files.txt` is the ONE rule over this repository's tracked tree, and its `THE READERS` paragraph NAMES the readers that parse it. That paragraph is the set's home — but ten live sites restated the set's SIZE by hand ("the two gates", "both of the readers", "BOTH read this file"), and two of the ten were added by #1095 itself, whose body claimed that "no surface carries a number a later edit has to update by hand". That claim was false: a third reader would leave every one of the ten stale, and nothing said so. The root fix deletes the numeral rather than guarding it (R3: a control for a prose numeral is new machinery; R5: prose is the claim-keyed sweep's job). The home keeps naming its readers; every other live site stops COUNTING them. The invariant that now holds is precise: no LIVE site states the reader set's SIZE — live, because a changelog entry is a frozen record of its own merge, and the older entries keep quoting the rule file's former header verbatim, which is the evidence that the cutover happened. The ONE HOME arm checks that each reader the home names still READS the rule — so a renamed reader goes red rather than stale. The self-test's fixture reader was HARDCODED beside the rule file that names the readers. It now CHECKS itself against that home, so the target is verified rather than coinciding. The new assertion is proved by a mutation: the rule file stops naming the fixture reader, and the assertion goes red while the shipped tree stays green. The merged entry CHANGELOG/2026.303.0035.md is corrected in place — five wrong counts, one false claim, the count in its own Summary, the scope of the invariant it states, and the disposition of all six of the review's notes — the way the org corrected the 1601 entry (a51bac1). Closes #1096 Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)
Review — PASSWhat the PR does, judged against the diffThe change has one coherent mechanism: delete the hand-restated size of the shared rule's reader set from every live site, and make the self-test's fixture reader accountable to the rule file that NAMES the readers. Every changed file is consistent with that goal.
Verification of the body's checkable claims
Non-blocking observations
CommentsThe comment thread is empty (0 comments). There is no maintainer sign-off and none is required to rely on the change's own evidence; the code and prose stand on the diff and the reproducible gate transcript. No stale or conflicting comment claims to disposition. Scope & securityThe change is a coherent control + prose update; no leftover legacy path, no dead code, no secrets, no injection surface (the new code only regex-scans an already-trusted committed file). The workflow/AGENTS/rule-file edits are prose coupled to the same fact. Editing the merged changelog entry is scoped to correcting that entry's own false claims and is marked in place. VerdictThe change does what it claims: the reader-set count is gone from every live site, the self-test now derives the fixture from the set's home, and the merged entry's false claim is corrected in place with a scoped invariant and a full six-note disposition. The evidence is self-consistent and reproducible. The two observations above are wording/scope clarity nits, not defects. Verdict: PASS ollama-cloud/deepseek-v4.1-flash — action-review. |
|
STATUS — the validator's two observations are both fixed in the body; nothing is pushed back. Agent: charly · session The 1. "SIX wrong COUNTS" is loose — six sites, seven quoted numerals. Fixed. The body now RCA. The mechanism is a count word applied to a list whose items are not all the same kind 2. The base sensitivity run's scope is implicit while the head run's is explicit. Fixed. RCA. The mechanism is that the base run's exclusion lived only in its command line while the No re-run. Both fixes are to the PR body only; the head does not move, the diff does not Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated) |
Summary
The shared rule
scripts/tracked-files.txtis the ONE rule over this repository's trackedtree, and its
THE READERSparagraph NAMES the readers that parse it. That paragraph is theset's ONE home — but ten live sites restated the set's SIZE by hand ("the two gates", "both
of the readers", "BOTH read this file"), and two of the ten were added by #1095
itself, whose body claimed that "no surface carries a number a later edit has to update by
hand". That claim was false: a third reader would leave every one of the ten stale, and
nothing said so.
This is #1096, filed from the
charly/pr-validator's review of#1095, and this PR implements it.
The RCA.
THE READERSparagraph is a derived fact's HOME: it namesthe readers, so the set's SIZE can be read off it. Ten live sites did not read it — they
stated the size by hand, and a hand-stated size of a derived set is a copy of it (R2).
feat(core): the shared rule's SHAPE gets a control — its grammar and its exempt-mode list have ONE home #1095's own sweep was keyed on the ARM counts only, so it proved that claim's first half
and said nothing about its second.
HOME arm controls the rule's GRAMMAR (one home), its exempt-mode LIST (one home) and the
reader set (every NAMED reader still READS the rule file) — but a prose numeral that
counts the set is none of those: no arm reads it, and no claim-keyed sweep was aimed at
it.
so a third reader is a normal future edit. Every one of the ten sites would go stale, and
the sentences that carry the INVARIANT (the readers cannot drift on WHICH modes are
exempt) would still read true — so nothing would say so.
machinery (R3), and prose is the claim-keyed sweep's job (R5). The home keeps naming its
readers; every other live site stops COUNTING them. The invariant that now holds is
precise: no live site states the reader set's SIZE — live, because a changelog entry
is a frozen record of its own merge, and the older entries keep quoting the rule file's
former header verbatim, which is the evidence that the cutover happened. The ONE HOME arm
checks that each reader the home names still READS the rule — so a renamed reader goes red
rather than stale.
What landed.
THE READERSparagraph, this repository's
AGENTS.md, the retired-knob reader's three comment sites,the control's module comment and three docstrings, and the CI workflow's header (which
also stopped counting the AGENTS.md claim-maker bullets — a second derived fact, counted
by hand in the same hunk, and not one of the ten).
the rule file's readers paragraph NAMES the readers, and the fixture must be one it names.
CHANGELOG/2026.303.0035.mdis corrected IN PLACE at SIX sites — oneerrata clause each, carrying SEVEN quoted NUMERALS: the Summary's own reader count quotes
two, "six arms, one per mutation" quotes one, "the two that were the gate script's own"
quotes one, "the four surfaces" quotes one in each of its two places, and "the four prose
surfaces" quotes one — and ONE FALSE CLAIM (the universal "no surface carries a number a
later edit has to update by hand", replaced by the scoped "no live site states the reader
set's SIZE", with the scope's reason stated in place); and the disposition of all SIX of
the review's notes is recorded in a
## Erratasection, the way the org corrected the 1601entry (
a51bac14).scripts/tracked-files.txtTHE READERSparagraph stops COUNTING the readers it names ("BOTH read this file" and "the two gates cannot drift" become "each of those readers reads this file" and "no reader can drift"); the paragraph stays the set's one home.scripts/check-pin-verb-scope.pycharly/retired_build_selector_test.goAGENTS.md.github/workflows/pin-verb-scope.ymlCHANGELOG/2026.303.0035.md## Erratasection records the disposition of all six of the review's notes.How tested
The work happened in this repository's own session worktree, on
feat/reader-set-count-1096,off fresh
origin/main(ae1cda58— the commit that records #1095's merge in the changelog,one above #1095's squash
76cc118e). Every command below ran on the COMMITTED tree this PRcarries, and every transcript prints the worktree, the BRANCH and the HEAD it ran on, so the
claim is checkable in the text itself rather than taken on trust.
The tree the evidence came from. Head
1d793cbc6d4f515c670775634b979159b49e5c7d— 6 files changed, 91 insertions(+), 30 deletions(-).The change-class gate, on the committed tree. The change class is a repo CONTROL plus
the PROSE that restates a derived fact, so the gate is the control and its own proof, the
CI-parity Go gate, the R9 build, the manifest's loadability, and the R10 bed on its
disposable: truetarget. Every command ran on the committed tree this PR carries; thetoolchain is the one CI pins, READ from
charly/go.mod(CI:actions/setup-gowithgo-version-file: charly/go.mod), and the gate refuses to run a Go step under any other.The proof that the NEW assertion can fail. The gate's proof step mutates the LIVE rule
file so that its readers paragraph names only the pin-advance control: the retired-knob
reader is then no longer in the set the arm covers, while the fixture still EXISTS and still
READS the rule. The control stays GREEN on that tree, and the new assertion — which checks
the fixture against the set's HOME — goes RED. The mutation is asserted to have APPLIED
before the assertion is credited, and the file is restored byte-equal to the committed one,
which the same transcript shows.
The claim-keyed sweep — its sensitivity, then its result. The sweep's key is a numeral
(or "both") within forty characters of a word that names the set (
gates,readers,controls read,AGENTS.md bullets). Two things make the result mean what it claims, andboth are in the transcript above.
Sensitivity — the key is not under-swept. Run on the BASE — with the SAME live scope as the
live run (the same
-- ':!CHANGELOG/'exclusion, so the two runs differ only in the tree theyread) — the same key finds fourteen lines: every one of the ten sites, the workflow's second
count, the second line of one statement the sweep prints in full, and two unrelated hits.
Every line is pasted:
A TIGHTER key would have been a defect: one that anchors on the whole phrase misses
charly/retired_build_selector_test.go:121, where the phrase wraps across the line break —so this key is deliberately the broad one, and it is a superset of every count wording the
ten sites used.
Result — on this tree the live sweep returns two hits, and NEITHER counts this rule's
reader set:
.agents/skills/plugin/references/boundary-law.md:235— "P16 lands last, with all threegates green" — the plugin boundary law's own gates.
charly/internal/pluginsgen/main_test.go:16— "generatedWiring caches ONE pluginsgen runfor the two gates below" — that package's own two test gates.
Both are a different pair (or triple) of gates, and both stay.
The whole tree, and every surviving hit classified. The sweep is run repo-wide — not
only over the live tree — and the transcript above prints every hit grouped by file: 46 hits,
44 of them in
CHANGELOG/and the two live hits just classified. The invariant's scope isthe LIVE tree, so the changelog's hits are the ones that need a reason, and each group has
one:
CHANGELOG/2026.302.2345.mdCHANGELOG/2026.302.2257.mdCHANGELOG/2026.303.0035.mdCHANGELOG/2026.241.0741.mdCHANGELOG/2026.262.1157.mdCHANGELOG/2026.296.2116.mdCHANGELOG/2026.278.0245.mdCHANGELOG/2026.250.0820.mdCHANGELOG/2026.301.1935.mdCHANGELOG/2026.227.1725.mdCHANGELOG/2026.215.1735.mdCHANGELOG/2026.190.1751.mdA changelog entry is a FROZEN record of its own merge — it is never updated when a reader is
added, which is exactly why a count in it is not a number a later edit has to keep in sync,
and why the invariant is scoped to the live tree. The scope is not this PR's invention: the
merged entry's own R5 sweep used the same scope, a claim-keyed
git grepwithCHANGELOG/excluded, and its claim is phrased the same way — "no live site says 'three arms'".
The derivation of the ten. Every site is one prose statement whose removed text applied a
count word to a word that names the reader set; two count lines inside one statement are one
site. Each site is attributed by a literal pickaxe on its removed line, and
git blameagrees with the pickaxe on all ten. The table below is the derivation's own output, in its
own order; the base line is where the STATEMENT starts, which is why the sweep above prints
AGENTS.mdat line 165 — the sweep prints every line of a multi-line statement, and onestatement spans two lines:
.github/workflows/pin-verb-scope.yml76cc118e76cc118eAGENTS.mdf93f7e7cf93f7e7ccharly/retired_build_selector_test.go771ad615771ad615charly/retired_build_selector_test.go771ad615771ad615charly/retired_build_selector_test.go771ad615771ad615scripts/check-pin-verb-scope.py76cc118e76cc118escripts/check-pin-verb-scope.pyf93f7e7cf93f7e7cscripts/check-pin-verb-scope.py771ad615771ad615scripts/check-pin-verb-scope.py771ad615771ad615scripts/tracked-files.txt771ad615771ad61576cc118eis #1095's squash commit, so two of the ten were added by the very PR whose claimthis PR corrects — the reason the claim was false at that merge. The pickaxe is reproducible
for any row, for example:
Rulebook compliance
/charly-internals:git-workflow(the git and PR mechanics),/charly-internals:root-cause-analyzer(the R1 analyses),/charly-internals:strict-policy(the discipline rules), and/charly-internals:go-quality(the Go and lint gate). This repository's own rulebook(
charly/AGENTS.md) was read before the change.this work started. feat(core): the shared rule's SHAPE gets a control — its grammar and its exempt-mode list have ONE home #1095's own review raised six notes; under R1 a finding raised on the
author's own PR is never filed away, and the disposition is recorded in the merged entry's
## Erratasection — three fixed in the merged entry's text, two fixed here in this PR'stree, one rebutted with evidence — with the per-note RCA on feat(core): the shared rule's SHAPE gets a control — its grammar and its exempt-mode list have ONE home #1095's thread. The gate
produced one anomaly of
its own — the proof step passed the BACKUP's path to the mutator, so the live tree was
never mutated and the restore then copied the mutated backup over it, leaving the tree
broken. Its RCA: the mechanism is a path handed to the mutator, the missed control is the
assertion that a mutation APPLIED (the very thing the control's own mutation arms guard),
the blast radius is a broken tree under the rest of the gate, and the root fix is in the
gate script: the mutator writes to the LIVE path, the backup lives elsewhere, and the
mutation is asserted to have changed the live file before the assertion is credited. The
tree was restored from the index and the gate re-run from the start; the transcript pasted
above is that clean run. A second finding was raised on this PR before its first push —
the merged entry stated the invariant universally ("no surface states the reader set's
SIZE") while the sweep it cites excludes
CHANGELOG/, and the entry's own Summary statedthe size — so the invariant is now scoped to the live tree, the entry's own Summary count
is corrected, and the sweep runs repo-wide with every surviving hit classified. Zero
warnings: every step of the gate reports zero.
THE READERSparagraph, andevery other live site POINTS at it instead of copying it; the new assertion checks the
self-test's fixture against that home rather than hardcoding it beside it.
fixture. The numeral is DELETED, not guarded — a control for a prose numeral would be new
machinery, and prose is the claim-keyed sweep's job.
merged entry's false claim is corrected by the FIX rather than by narrowing the claim. Every
documented command works with nothing but the
charlybinary — the gate script is ascratch script, not a documented command.
and neither counts this rule's reader set, and each surviving hit is classified above.
git statuswas run before the commit, before the gate and after it; the tree wasclean at each point; no unrelated work was touched; there is no force-push, no amend after
the first push and no hook bypass.
that turns it RED while the shipped tree stays green, and the changed paths execute live —
the control runs, the manifest loads, and the bed that witnesses the task surface runs on
its disposable target, as the transcript above shows.
charlybinary and a realdisposable local deploy, and the control reads the repository's own index and the committed
rule file.
scripts/bootstrap-charly.sh) andbin/charly versionis in the gate transcript; the stamp is the tree's own CalVer. Noruntime OS dependency changed.
so the gate is the control and its own proof, the CI-parity Go gate (the test suite, the
tools/*module sweep,go vet,gofmt,golangci-lintbuilt by the same toolchain CIuses), the R9 worktree-local build, the manifest's loadability, and the R10 bed on its
disposable: truetarget — all on the committed tree this PR carries, with zero warnings.Change classification
A repo control and the prose that states its rule — not documentation-only. The diff
changes the BEHAVIOUR of
scripts/check-pin-verb-scope.py(the self-test gains an assertion,and the control's own comment and docstrings stop counting the reader set), and it corrects the
prose of the four surfaces that restated the derived fact — the rule file's own header, the
retired-knob reader's comments, this repository's
AGENTS.md, and the CI workflow's header —plus the merged changelog entry, whose own restatement of the reader set's size and whose
universal claim about numbers were false.
AGENTS.md, the workflow's header and the rulefile's header are prose and are changed with the code; the changelog entry is HISTORY, and it
is corrected in place with an errata clause at every corrected site.
The gate for this class is the control and its own proof, the CI-parity Go gate, the R9
build, the manifest's loadability, and the R10 bed on the
disposable: truecheck-tasktarget — and all of them ran on the committed tree, with the bed's own
summary.ymlrecordingevery step green. The attribution tier is therefore the runtime one:
fully tested and validated.Filed issues
the self-test's fixture reader is not checked against the rule file that names the readers.
This PR implements it.
Nothing else is open: #1095's six review notes are all disposed of — three fixed in the
merged entry's text, two fixed here in this PR's tree, one rebutted with evidence — and that
partition is recorded in the merged entry's
## Erratasection, with the per-note RCA on#1095's thread.
Closes #1096
Agent: charly
Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)