feat(lenses): the commit-truth lens, repo-facts, as Gate 4
Every claim in every commit message, and in the documentation the range adds or changes, proven or gone. The lens's block kinds are text, doc and slot: a message unit is keyed on its text, the base and the code up to its commit (MessageDeps); a documentation unit on its file, its normalised text, the base and the code of the whole range (DocKeyParts); a diffstat on its text alone; whole:order and whole:absent are asked in slot passes of its own, never stored. A documentation file's diff header and a part the commit writes nothing in are a mechanical n/a. Budgets 60/40 for a text or doc block, 50/35 for a slot; one read. Gate 4, after the proofs, so the messages and documents are read once the code they describe has settled; the owner's gate is 5. The goldens that follow from the lens table are derived by tests/Goldens/derive.py, which asserts that the recorded table still reproduces the recorded entries before it writes. Proven, with the opt-in commit after this one: the suite (26 passed); a dry run of a scratch range (2 commits, a README with sections) by the previous binary and this one with the three static lenses on and the rest off, 25 prompts and 4 system files byte for byte; with repo-facts on as well, those files unchanged and 10 passes and 1 system file added. The lens's firing proof in this pipeline is owed (the owner's go).
This commit is contained in:
parent
61ee4602f4
commit
febbfc3fcc
19 changed files with 2564 additions and 646 deletions
151
process/lenses/repo-facts.md
Normal file
151
process/lenses/repo-facts.md
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
# Lens: repo-facts
|
||||
|
||||
You are an adversarial fact-checker. Your job is to DISPROVE every claim made
|
||||
in the commit messages of the range under review, and in the documentation
|
||||
the range adds or changes (README, AGENTS.md: the units of a `.md` file). A
|
||||
claim you cannot verify against evidence is treated as false until proven.
|
||||
These commits go into a public repository's permanent history and into a
|
||||
release users install; its documentation is what they read.
|
||||
|
||||
Inputs: the frozen range, the repository at the range HEAD and at the base,
|
||||
its history (`git -C <tree> log`), and the evidence paths INPUTS names (the
|
||||
proof artifacts for anything tested on a device or seen on a network).
|
||||
|
||||
## Method
|
||||
|
||||
1. **Enumerate every factual claim** in each commit message — behavior
|
||||
claims ("X now does Y", "fixes Z"), claims about the previous behavior,
|
||||
claims about users, devices, carriers, networks or field observations,
|
||||
"tested" claims, version and changelog statements, references to specs,
|
||||
tickets, other projects or other people's work. For each: find the proof
|
||||
in the diff, the tree, the history, or a capture — or flag it.
|
||||
2. **Code claims are verified against the diff and the tree at HEAD** —
|
||||
what the message says the change does must be what the change does, and
|
||||
what it says about the state before must hold at the base
|
||||
(`git -C <tree> show <base>:<path>`). A message that describes the
|
||||
intended behavior rather than the implemented one is a finding.
|
||||
3. **"Tested" claims trace to a capture** naming what ran, where, and on
|
||||
which build. When INPUTS names no evidence path, a tested claim that the
|
||||
diff and tree cannot substantiate is unverifiable — a finding whose cure
|
||||
is the capture or the deletion of the claim.
|
||||
4. **Overclaims are cured by TESTING, not rewording.** If a claim is
|
||||
stronger than the evidence, the verdict is "test it or delete it" — never
|
||||
"soften the wording".
|
||||
5. **"Doesn't affect X" / "no user-visible change" requires 100% hard
|
||||
proof** — enumerate every user of the touched path in the repository and
|
||||
show each is unaffected, or the claim goes.
|
||||
6. **Negative existence claims** ("nothing else uses this", "no caller
|
||||
passes NULL", "there is no test for this", "the first X to …") are
|
||||
auditable only against a search you ran: cite the grep and its result in
|
||||
the basis.
|
||||
7. **Evidence quality rules**: exact-event match, never substring
|
||||
pattern-match; levels-vs-baseline, never mere presence; an unexplained
|
||||
nonzero baseline is evidence, not noise — attribute it before relying on
|
||||
any "nothing happens" claim.
|
||||
8. **A test of a tie-break, fallback, or "prefer X" branch must run in a
|
||||
state that FORCES that branch to decide the outcome.** "The test passed"
|
||||
and "the new code ran" are different claims. Name the state that forces
|
||||
it, and show the evidence came from that state.
|
||||
9. **References** to a spec, an RFC, a ticket, an upstream commit or another
|
||||
project: verify that what is on disk (the repository, its installed or
|
||||
vendored dependencies, the evidence paths) says what the message says it
|
||||
says; a document not on disk makes the claim unverifiable — a note naming
|
||||
what would settle it, never an assumed pass.
|
||||
10. **History claims** ("since 0.3.4", "introduced by <sha>", "reverts",
|
||||
"the previous commit"): archaeology in the repository's own history,
|
||||
cited by sha; a message in commit K that describes what commit K+1 does
|
||||
is a finding on both.
|
||||
11. **Documentation the range adds or changes** — a unit of a `.md` file: a
|
||||
diff hunk, or one heading-delimited part of it — is read like a message,
|
||||
by the rules above, with three differences. (a) The claims are the lines
|
||||
the commit adds. A context line is context and a removed line claims
|
||||
nothing — except a context sentence that this commit's own change makes
|
||||
false, which is a finding. (b) A sentence must hold for the repository
|
||||
as ITS commit leaves it (`git -C <tree> show <sha>:<path>`, the sha on
|
||||
that patch's `From` line): a later commit that makes it true does not
|
||||
cure it. Where the document at HEAD still carries the sentence it must
|
||||
hold at HEAD too: a later commit of the range that makes it false
|
||||
without updating it is a finding on the unit that wrote it. (c) An
|
||||
instruction — a command, a path, a variable, an option, a reference to a
|
||||
section — is a claim that it exists and works as written: check the
|
||||
file, the flag, the unit, the target section in the tree at that commit;
|
||||
what only a run on a device or a network can settle traces to a capture,
|
||||
or is unverifiable. This lens checks what a document says, not what it
|
||||
could also say: an omission is a finding only where the text claims
|
||||
completeness ("every", "all", "only", "never", a list given as the
|
||||
list). Documentation the range did not touch and its code makes false is
|
||||
the `whole:absent` slot's.
|
||||
|
||||
## Verdict
|
||||
|
||||
Per `prepush.md` §Verdicts — objective lens: no materiality defence. Any
|
||||
unproven or disproven claim is FIX FIRST whoever would notice — and the cure
|
||||
is evidence (a test, a capture, a read of the referenced code) or deletion of
|
||||
the claim, never a hedge word. Nothing below FIX FIRST is a finding;
|
||||
record-worthy observations go in notes. Never grade a finding.
|
||||
|
||||
## Calibration (append dated entries at the bottom)
|
||||
|
||||
- Seeded 2026-09-25 from the earlier facts lens: the 2026-07-20
|
||||
overclaim rule (Method 4), the 2026-07-24 forced-branch rule (Method 8),
|
||||
the 2026-08-30 captured-search rule for negative existence claims (Method
|
||||
6), and the 2026-09-16 coverage contract: when the prompt carries an
|
||||
INVENTORY (a mechanical partition: every non-blank line in exactly one
|
||||
unit, fixed `whole:*`/`pK:outside`/`pK:absent` slots for what is absent),
|
||||
return one `{item, verdict, basis}` per unit AFTER the review: `clear`
|
||||
only when every claim in the unit was checked at its source (basis = the
|
||||
tree ref, the command run, the capture path) — a plausible reading is not
|
||||
a check; `defect` with a finding carrying `items:[id]`; `immaterial` with
|
||||
a note carrying `items:[id]`; `n/a` with the reason (never a paragraph of
|
||||
claims). A `defect` without a finding is turned into an undischarged
|
||||
finding; a missing unit makes the run INCOMPLETE.
|
||||
- 2026-09-25 (firing proof at creation): a fixture repository with a
|
||||
planted range - commit 1 adds `median()` whose message claims an
|
||||
empty-list guard and the mean of the two middle values that the diff does
|
||||
not implement, commit 2 "fix the median crash on an empty list" adds the
|
||||
guard - and a corrected single-commit range. Single-unit `--only`/`--units`
|
||||
runs: block pass on `p1:msg` -> FIX FIRST with 3 findings: the even-count
|
||||
claim disproven against the diff, the guard claim disproven against
|
||||
`git show <sha>:stats.py` of that commit (and the next commit's message
|
||||
conceding it - cited on both units), the "as the other helpers document"
|
||||
reference unsupported (no docstring, README silent); the corrected message
|
||||
-> SEND-READY, `clear`, with an `info` note that no tested/field claim
|
||||
existed to trace. 7 / 7 turns, ~$0.45 / $0.25. No denied call.
|
||||
- 2026-10-06 (documentation is this lens's since driver 2026-10-06.3 -
|
||||
Method 11; firing proof with this charter): a fixture repository, two
|
||||
commits. Planted: commit 1's README says "`spread(xs)` returns the largest
|
||||
value minus the smallest" while spread() arrives in commit 2; commit 2's
|
||||
README says the three functions raise `TypeError` (the code raises
|
||||
ValueError); commit 2's message says "the test suite covers an unsorted
|
||||
sequence" (it does not). Single-unit `--only`/`--units` run on
|
||||
`p1:README.md#1.2`, `p2:README.md#1.2`, `p2:msg` -> FIX FIRST, three
|
||||
findings: the first disproven at commit 1's own sha (`git show
|
||||
<sha>:stats.py` has no spread; `git grep spread <sha>` hits only the
|
||||
README line) and cited on `whole:order` too, with an `info` note that the
|
||||
sentence is accurate at HEAD and only its placement is wrong; the second
|
||||
against `_require` and the tests of the same commit; the third against
|
||||
the two spread tests. The corrected range, units `p2:README.md#1.1`,
|
||||
`#1.2`, `p2:msg` -> SEND-READY, `clear` x3; that the README's list leaves
|
||||
out `is_finite()` came back as a `pre-existing` note, not a finding (the
|
||||
list does not claim to be complete). Opus 5.5 xhigh, 10 / 17 turns, $0.49
|
||||
/ $0.64, under a minute each. No denied call.
|
||||
- 2026-10-06 (Method 11(b) reworded and the `whole:absent` duty widened
|
||||
after the soundness review of the same day - driver 2026-10-06.4;
|
||||
firing proof): the same fixture repository; commit 1's README says
|
||||
median() returns "the mean of the two middle values for an even count"
|
||||
(true there), commit 2 makes median() return the lower middle value and
|
||||
touches no documentation. Run on `p1:README.md#1` and `whole:absent` ->
|
||||
FIX FIRST: the sentence flagged on the unit that wrote it ("true at the
|
||||
commit that adds it but false at HEAD ... does not update README.md"),
|
||||
the slot flagged the stale README and that spread(), which the range
|
||||
adds, is missing from the list the range itself keeps. With the sentence
|
||||
updated in commit 2, `p1:README.md#1`, `p2:README.md#1`, `whole:absent`
|
||||
-> SEND-READY: "replaced the sentence, so it does not carry to HEAD"; the
|
||||
list's old gap (is_finite) again a `pre-existing` note. Opus 5.5 xhigh,
|
||||
13 / 14 turns, $0.51 / $0.72. No denied call.
|
||||
- 2026-10-31 — carried into this pipeline with the runtime examples made
|
||||
generic (the evidence paths INPUTS names stand for a journal's ledger and
|
||||
captures; a device for a phone); the rules are the same. Here it is Gate 4, after the
|
||||
proofs, so the messages and documents are read once the code they
|
||||
describe has settled, and it is off until a repository's config turns it
|
||||
on. Its firing proof in this pipeline is still owed (the owner's go).
|
||||
|
|
@ -3,9 +3,10 @@
|
|||
Scope: every push of a commit range from a repository set up for this
|
||||
pipeline (`crafter-review init`) — a release channel with real users, where a push (or
|
||||
the pull request it opens) is the next release. The `/prepush` skill drives
|
||||
this file. The mechanics: freeze → hash → gates → the owner; four lenses,
|
||||
this file. The mechanics: freeze → hash → gates → the owner; five lenses,
|
||||
the functional one as Gate 2 (Jorijn, 2026-10-15), the security lens beside
|
||||
the bug-prover in Gate 3 (2026-10-22).
|
||||
the bug-prover in Gate 3 (2026-10-22), the commit-truth lens as Gate 4
|
||||
(2026-10-31).
|
||||
|
||||
Nothing is pushed without the owner's explicit approval of the exact frozen
|
||||
hash. Local commits parked unpushed are fine and normal.
|
||||
|
|
@ -15,7 +16,7 @@ Terms: *the pipeline* is crafter-review, the Flatpak
|
|||
`flatpak run net.catcrafts.CrafterReview <command>`, because the Bash tool sees no
|
||||
alias (a native build is run by its path instead). *The repository* is the
|
||||
consumer checkout the driver runs in; *the owner* is whoever approves the
|
||||
hash at Gate 4.
|
||||
hash at Gate 5.
|
||||
|
||||
## Inputs — what the lenses see, and nothing else
|
||||
|
||||
|
|
@ -231,7 +232,7 @@ therefore the hash: re-freeze with `--replace` into the same dir
|
|||
the new HEAD before the rerun. A fix during a run happens in another
|
||||
worktree, never in the tree the lenses read.
|
||||
|
||||
## Gates 1–3 (the driver) and Gate 4 (the owner)
|
||||
## Gates 1–4 (the driver) and Gate 5 (the owner)
|
||||
|
||||
| Gate | Lens | Question |
|
||||
|---|---|---|
|
||||
|
|
@ -239,7 +240,8 @@ therefore the hash: re-freeze with `--replace` into the same dir
|
|||
| 2 Functional | `repo-functional` (whole pass gating code blocks; the `browser` or `browser+supabase` environment; absent when the config turns it off) | in the running application, does the range do what its code and messages say, and does it leave the flows next to it working? |
|
||||
| 3 Proof | `repo-bug-prover` (code blocks, static; with the `supabase` environment a proof may also be run in the database) | a demonstrated functional defect in the range's code |
|
||||
| 3 Proof | `repo-security` (code blocks, static, beside the bug-prover; with the `supabase` or a browser environment a demonstration may also be run in the database or the application) | a demonstrated gap in a protection the repository promises: a check, policy or grant the range's code lacks, weakens or removes |
|
||||
| 4 | the owner | approves this exact hash, then the push happens |
|
||||
| 4 Commit truth | `repo-facts` (message blocks, documentation blocks and the `whole:order` / `whole:absent` slots, static) | every claim in every commit message, and in the documentation the range adds or changes, proven or gone |
|
||||
| 5 | the owner | approves this exact hash, then the push happens |
|
||||
|
||||
Every lens runs on Opus 5.5 at effort `xhigh` (`--effort` overrides).
|
||||
There is no width of the machine by default (2026-10-31, Jorijn: "there is
|
||||
|
|
@ -299,15 +301,17 @@ passes; coverage is fail-closed per inventory unit (`inventory commits`:
|
|||
outputs after a kill, budgets, `--only` / `--units` test-only runs (PARTIAL,
|
||||
never a pass), the dump at `gate-state/commits-<hash8>-run-<n>.json`.
|
||||
|
||||
**Who reads what.** The four lenses read code: hunks, file headers and (the
|
||||
static lenses) the per-commit slots `pK:outside` and `pK:absent`. The
|
||||
text units — subjects, messages, diffstats — and the units of documentation
|
||||
files (`*.md`) are read by no lens of this pipeline (the facts lens was
|
||||
removed, 2026-10-15); the dump lists them under `coverage.notReviewed` and
|
||||
the summary says so. A lens the config turns off (`lenses.<name>.run =
|
||||
false`) reads nothing: the units only it would have read (its whole slot —
|
||||
`whole:behaviour` for the functional lens) are listed there too, never as
|
||||
holes. The functional lens plans no pass on a diff header, on a
|
||||
**Who reads what.** The four code lenses read code: hunks, file headers and
|
||||
(the static lenses) the per-commit slots `pK:outside` and `pK:absent`. The
|
||||
commit-truth lens reads the prose: the text units — subjects, messages,
|
||||
diffstats — and the units of documentation files (`*.md`), each
|
||||
heading-delimited part of a hunk on its own, and it asks `whole:order` and
|
||||
`whole:absent` in slot passes of its own; a documentation file's diff header
|
||||
and a part the commit writes nothing in are a mechanical `n/a`. A lens the
|
||||
config turns off (`lenses.<name>.run = false`) reads nothing: the units only it would have read (its whole slot —
|
||||
`whole:behaviour` for the functional lens; the prose for the commit-truth
|
||||
lens) are listed under `coverage.notReviewed`, never as holes, and the
|
||||
summary says so. The functional lens plans no pass on a diff header, on a
|
||||
unit of a file matching `functional.exclude`, or on the per-commit slots (its
|
||||
whole pass judges adjacent flows and missing deliveries range-wide): each is
|
||||
a mechanical `n/a` with its basis.
|
||||
|
|
@ -334,6 +338,16 @@ the functional lens):
|
|||
range changed, or when a documentation file of their commit is added,
|
||||
deleted or renamed (`absent` also when the commit gains or loses its body).
|
||||
The commit's position is in the key;
|
||||
- a message (`pK:subject`, `pK:msg`), for the commit-truth lens: its own
|
||||
text, the base and the code of the range up to and including its commit —
|
||||
a fix to the code a message describes asks the message again; a diffstat
|
||||
its own text alone;
|
||||
- a unit of a documentation file, for the commit-truth lens: its file and
|
||||
its own text (normalised like a hunk), the base and the code of the whole
|
||||
range — a sentence must hold for the code as its commit leaves it and as
|
||||
the range leaves it;
|
||||
- the commit-truth lens's slot passes (`whole:order`, `whole:absent`): never
|
||||
stored, bought every run;
|
||||
- both whole passes: the code of every commit of the range in order, which
|
||||
commits have a body and which documentation files each touches. No message
|
||||
text and no documentation text. A whole pass that returned a finding is
|
||||
|
|
@ -371,7 +385,7 @@ from the previous rounds get run again until they reach x"; x is 3
|
|||
again after a finished run is the next round.
|
||||
- All gates clean with reads still owed is `CONFIRMING — NOT SEND-READY`
|
||||
(exit 2); run the same line again, on the same hash, until it says
|
||||
SEND-READY. Gate 4 is asked for a hash only then.
|
||||
SEND-READY. Gate 5 is asked for a hash only then.
|
||||
- Every finding in the dump carries `read`, the number of the read that
|
||||
found it.
|
||||
|
||||
|
|
@ -401,7 +415,7 @@ Each entry is dated, names what it `supersedes`, binds to a hash, records
|
|||
grounds, and lists the artifact `anchors` its grounds depend on with the
|
||||
count of occurrences at binding. The register is
|
||||
`<out>/gate-state/dispositions.json` — the authority and the record; the
|
||||
manifest's rounds table names each discharge with its grounds for Gate 4.
|
||||
manifest's rounds table names each discharge with its grounds for Gate 5.
|
||||
Carry across a hash change
|
||||
is mechanical: an entry is in force when bound to the current hash, carried
|
||||
when `carry` is true and every anchor still occurs its recorded count of
|
||||
|
|
@ -419,7 +433,7 @@ the push, the rest are banked per kind.
|
|||
A new disposition in force re-keys every unit, so a waiver costs every static
|
||||
code unit its three reads again.
|
||||
|
||||
## Gate 4 — the owner, then the push
|
||||
## Gate 5 — the owner, then the push
|
||||
|
||||
Present the frozen patches themselves (never summaries), the rounds table,
|
||||
every discharged finding with its grounds, every contest, every `unverified`
|
||||
|
|
@ -592,3 +606,6 @@ repository.
|
|||
5-hour column. Then (Jorijn: "there is no need to do a global cap anymore,
|
||||
the cap should be 128 per available account") the machine-wide width
|
||||
went: `--concurrency` caps only when given.
|
||||
- 2026-10-31 — **the commit-truth lens as Gate 4** (Jorijn: "fix that in
|
||||
Crafter.Review"). The owner's gate is 5. Its firing proof in this pipeline
|
||||
is owed (the owner's go).
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
name: prepush
|
||||
description: Pre-push gates for a repository set up for crafter-review (`crafter-review init`). Runs the pipeline's procedure end to end — Gate 0 build/tests + freeze (identity, trailers by the config's rule, clean tree, no merges, fast-forward), the application and the database under test brought up from the frozen tree, the driver run of the lenses the config enables (repo-better-solution → repo-functional with the Playwright MCP → repo-bug-prover and repo-security side by side) via crafter-review, the fix/rerun loop, the owner's approval of the hash, verify, push. Nothing is pushed unreviewed or unapproved.
|
||||
description: Pre-push gates for a repository set up for crafter-review (`crafter-review init`). Runs the pipeline's procedure end to end — Gate 0 build/tests + freeze (identity, trailers by the config's rule, clean tree, no merges, fast-forward), the application and the database under test brought up from the frozen tree, the driver run of the lenses the config enables (repo-better-solution → repo-functional with the Playwright MCP → repo-bug-prover and repo-security side by side → repo-facts, the commit truth) via crafter-review, the fix/rerun loop, the owner's approval of the hash, verify, push. Nothing is pushed unreviewed or unapproved.
|
||||
---
|
||||
|
||||
Follow the pipeline's procedure, `prepush.md`, EXACTLY — read it now, in
|
||||
|
|
@ -46,7 +46,7 @@ of running it:
|
|||
`supabase.dbUrl` does not answer or its applied migrations are not
|
||||
HEAD's: reset the stack from the frozen tree, after every
|
||||
`freeze --replace` too. Do not edit that tree while the run is on.
|
||||
4. **Gates 1–3**: run the printed command from the repository root in a
|
||||
4. **Gates 1–4**: run the printed command from the repository root in a
|
||||
detached background shell (`setsid nohup … > <log> 2>&1 < /dev/null &`);
|
||||
poll `~/.cache/review-gates/<hash8>-run-<n>/progress.json` and `log.txt`.
|
||||
Add `--context-paths` for the evidence dirs the messages' claims rest on.
|
||||
|
|
@ -68,11 +68,11 @@ of running it:
|
|||
`grounds`, `carry`). A `contests` entry is a lens claim: re-check its cited
|
||||
evidence first; a surviving contest on an owner entry goes to the owner.
|
||||
Notes never block — bank each per its kind; an `unverified` note names a
|
||||
manual check the owner sees at Gate 4. INCOMPLETE is never a pass: rerun.
|
||||
manual check the owner sees at Gate 5. INCOMPLETE is never a pass: rerun.
|
||||
6. **Rounds** go in `.review-gates/push/<slug>/manifest.md`
|
||||
(`flatpak run net.catcrafts.CrafterReview doc manifest` prints the
|
||||
template; test runs with `--only`/`--units` never).
|
||||
7. **Gate 4 — the owner**: present the frozen patches themselves, the rounds
|
||||
7. **Gate 5 — the owner**: present the frozen patches themselves, the rounds
|
||||
table, the discharged findings with grounds, every contest, all notes —
|
||||
then STOP. Nothing is pushed until they explicitly approve that exact hash.
|
||||
8. **Push**: `flatpak run net.catcrafts.CrafterReview freeze --slug <slug>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@
|
|||
"repo-security": {
|
||||
"run": true,
|
||||
"environment": "none"
|
||||
},
|
||||
"repo-facts": {
|
||||
"run": true,
|
||||
"environment": "none"
|
||||
}
|
||||
},
|
||||
"supabase": {
|
||||
|
|
|
|||
|
|
@ -25,5 +25,5 @@ repository's rule).
|
|||
|
||||
-
|
||||
|
||||
approved: <date> @ <hash> (the owner, Gate 4 — saw the frozen patches, the discharged-findings list, contests and notes)
|
||||
approved: <date> @ <hash> (the owner, Gate 5 — saw the frozen patches, the discharged-findings list, contests and notes)
|
||||
pushed: <date> <remote>/<branch> @ <sha> (PR: <url>)
|
||||
|
|
|
|||
Loading…
Reference in a new issue