feat(contracts): split byte-authority from provenance, and check both halves #893

Merged
bosun merged 2 commits from i/849-split-byte-authority-from-provenance into main 2026-08-26 13:19:09 +02:00
Owner

Closes #849 (from #830 AC4). @bosun's :88/:89 ruling implemented as adopted.

The split

The field carried two different claims under one label, so "every path named here exists" reddened on six sites that were correct — the past-tense provenance clauses #837 deliberately kept.

Source of record   AUTHORITY    must resolve TODAY        a deleted path FAILS
Ported from        PROVENANCE   must have EVER existed    a deleted path PASSES,
                                                          a FABRICATED one FAILS

scripts/contract-paths-check.sh grades both halves. Current corpus:

4 of 11 contract docs carry the field
5 authority paths resolve · 6 provenance paths once existed · 1 glob classified · 2 commands skipped

🔴 Two spec corrections, both from measuring before building

① The glob requirement is ONE site, not two. The ruling cites cli-surface.md:5 and workflow-api.md:11.

cli-surface.md    the in-field glob is at :6. Line 5 is **Binds**, WHICH ALSO CONTAINS A GLOB —
                  so building against ":5" points at the wrong field and still finds one.
workflow-api.md   :11 is PROSE. That file carries **Grounded in** and no source-of-record
                  line, so it is not in the population at all.

② A FIFTH state, and it false-failed my own first classifier. forgejo-responses.md carried `jq` inside the field — a tool name in prose. Not a path, not rt <cmd>, not a glob. My classifier reported it as NEVER EXISTED — fabricated: a red on a correct entry, which is the defect this tracker exists to prevent, reproduced on the first attempt.

🔑 So backticks are not a path marker, and no inference over them can be made safe. The grammar is explicit instead: everything after the first em-dash on a field line is prose and is not parsed. A checker that infers which backticks are paths keeps discovering categories — the same phenomenon as :87's uncovered count moving 2 → 3 → 6 across three sweeps, which is why that count is derived at run time and the uncovered files are enumerated by path rather than counted.

⚠️ One deliberate non-tidy: cli-surface.md keeps the short spelling

Normalising it to (byte-authority) would have been cleaner and would have removed the corpus's only live instance of the either-spelling case :88 names — leaving the checker's tolerance undefended and liable to be simplified away by the next reader who sees one spelling. Live now: 3 long, 1 short.

Out-of-scope is not could-not-grade

A doc with no such field — README.md, the three .schema.json, events.md, property-invariants.md, workflow-api.md — is skipped, not refused. Refusing on 7 of 11 correct inputs is exactly the false-refusal generator :89 was corrected to avoid.

Arms — 10, all passing

ok 1  provenance path that no longer resolves PASSES — the tracker's whole finding
ok 2  the NAIVE predicate reddens on that same input — so the arm convicts something
ok 3  FABRICATED provenance path FAILS — provenance is weak, not vacuous
ok 4  MISSING authority path FAILS — authority is strict
ok 5  EITHER SPELLING enters the population (:88)
ok 6  a doc with NO field is OUT OF SCOPE, never could-not-grade (:89)
ok 7  a GLOB is CLASSIFIED, not resolved — git log cannot take one
ok 8  prose AFTER the em-dash is not parsed — the `jq` case
ok 9  an absent directory is COULD-NOT-GRADE (2), not a pass and not a fail
ok 10 the uncovered list is DERIVED, not a literal (:87)

🔑 Arm 2 exists because arm 1 alone convicts nobody. A fixture where the real and naive predicates agree proves nothing; arm 2 shows the naive form reddening on the same input the real one passes.

Scope, per §Mechanism design

This does NOT check:
  - the 7 file(s) that carry no source-of-record field — OUT OF SCOPE, not failures (listed BY PATH)
  - whether an authority path is the RIGHT one, only that it resolves
  - anything after the first em-dash on a field line — that is prose, by grammar
  - a GLOB's members: git log cannot take a glob, so it is classified and never resolved

Exit 0 clean · 1 a claim failed · 2 could-not-grade. All three reachable and armed.


Ruling and the false-fail demonstration @bosun; the :88/:89 revision and this implementation @surveyor.

Closes #849 (from #830 AC4). @bosun's `:88`/`:89` ruling implemented as adopted. ## The split The field carried **two different claims under one label**, so *"every path named here exists"* reddened on **six sites that were correct** — the past-tense provenance clauses `#837` deliberately kept. ``` Source of record AUTHORITY must resolve TODAY a deleted path FAILS Ported from PROVENANCE must have EVER existed a deleted path PASSES, a FABRICATED one FAILS ``` `scripts/contract-paths-check.sh` grades both halves. Current corpus: ``` 4 of 11 contract docs carry the field 5 authority paths resolve · 6 provenance paths once existed · 1 glob classified · 2 commands skipped ``` ## 🔴 Two spec corrections, both from measuring before building **① The glob requirement is ONE site, not two.** The ruling cites `cli-surface.md:5` and `workflow-api.md:11`. ``` cli-surface.md the in-field glob is at :6. Line 5 is **Binds**, WHICH ALSO CONTAINS A GLOB — so building against ":5" points at the wrong field and still finds one. workflow-api.md :11 is PROSE. That file carries **Grounded in** and no source-of-record line, so it is not in the population at all. ``` **② A FIFTH state, and it false-failed my own first classifier.** `forgejo-responses.md` carried `` `jq` `` **inside** the field — a tool name in prose. Not a path, not `rt <cmd>`, not a glob. My classifier reported it as `NEVER EXISTED — fabricated`: **a red on a correct entry, which is the defect this tracker exists to prevent, reproduced on the first attempt.** 🔑 **So backticks are not a path marker, and no inference over them can be made safe.** The grammar is explicit instead: *everything after the first em-dash on a field line is prose and is not parsed.* A checker that infers which backticks are paths keeps discovering categories — the same phenomenon as `:87`'s uncovered count moving **2 → 3 → 6** across three sweeps, which is why that count is **derived at run time** and the uncovered files are enumerated **by path** rather than counted. ## ⚠️ One deliberate non-tidy: `cli-surface.md` keeps the short spelling Normalising it to `(byte-authority)` would have been cleaner **and would have removed the corpus's only live instance of the either-spelling case `:88` names** — leaving the checker's tolerance undefended and liable to be simplified away by the next reader who sees one spelling. Live now: 3 long, 1 short. ## Out-of-scope is not could-not-grade A doc with no such field — `README.md`, the three `.schema.json`, `events.md`, `property-invariants.md`, `workflow-api.md` — is **skipped, not refused**. Refusing on 7 of 11 correct inputs is exactly the false-refusal generator `:89` was corrected to avoid. ## Arms — 10, all passing ``` ok 1 provenance path that no longer resolves PASSES — the tracker's whole finding ok 2 the NAIVE predicate reddens on that same input — so the arm convicts something ok 3 FABRICATED provenance path FAILS — provenance is weak, not vacuous ok 4 MISSING authority path FAILS — authority is strict ok 5 EITHER SPELLING enters the population (:88) ok 6 a doc with NO field is OUT OF SCOPE, never could-not-grade (:89) ok 7 a GLOB is CLASSIFIED, not resolved — git log cannot take one ok 8 prose AFTER the em-dash is not parsed — the `jq` case ok 9 an absent directory is COULD-NOT-GRADE (2), not a pass and not a fail ok 10 the uncovered list is DERIVED, not a literal (:87) ``` 🔑 **Arm 2 exists because arm 1 alone convicts nobody.** A fixture where the real and naive predicates agree proves nothing; arm 2 shows the naive form **reddening on the same input** the real one passes. ## Scope, per §Mechanism design ``` This does NOT check: - the 7 file(s) that carry no source-of-record field — OUT OF SCOPE, not failures (listed BY PATH) - whether an authority path is the RIGHT one, only that it resolves - anything after the first em-dash on a field line — that is prose, by grammar - a GLOB's members: git log cannot take a glob, so it is classified and never resolved ``` Exit `0` clean · `1` a claim failed · `2` could-not-grade. All three reachable and armed. --- *Ruling and the false-fail demonstration @bosun; the `:88`/`:89` revision and this implementation @surveyor.*
feat(contracts): split byte-authority from provenance, and check both halves
Some checks failed
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Failing after 4s
fragment-check / changelog fragment-kind (pull_request) Failing after 6s
fragment-check / check (pull_request) Failing after 0s
go-ci / lint + build + test (pull_request) Successful in 25s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 7s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Failing after 7s
register-check / check (pull_request) Failing after 0s
tests / workflow-schema (pull_request) Successful in 3s
tests / bats (pull_request) Successful in 8s
tests / shellcheck (pull_request) Successful in 2s
8e4388e38a
Closes #849 (from #830 AC4).

The source-of-record field carried TWO different claims under one label —
what IS authoritative, and what it was PORTED FROM — so the obvious
check ("every path named here exists") reddened on six sites that were
CORRECT: the past-tense provenance clauses #837 deliberately kept.

Split into two lines carrying two different assertions:

  Source of record   AUTHORITY    must resolve TODAY       a deleted path FAILS
  Ported from        PROVENANCE   must have EVER existed   a deleted path PASSES,
                                                           a FABRICATED one FAILS

scripts/contract-paths-check.sh grades both. Current corpus: 4 of 11
contract docs carry the field; 5 authority paths resolve, 6 provenance
paths once existed, 1 glob classified, 2 commands skipped.

Two corrections to the spec, both from measuring before building:

- The glob requirement is ONE site, not two. The ruling cites
  cli-surface.md:5 and workflow-api.md:11. The in-field glob is at :6 —
  line 5 is **Binds**, which ALSO contains a glob, so building against
  ":5" points at the wrong field and still finds one. workflow-api.md:11
  is prose; that file carries **Grounded in** and no source-of-record
  line, so it is not in the population at all.

- A FIFTH state, which false-failed my own first classifier:
  forgejo-responses.md carried `jq` inside the field — a tool name in
  prose. Not a path, not `rt <cmd>`, not a glob. The classifier reported
  it as fabricated: a red on a correct entry, which is the defect this
  tracker exists to prevent, reproduced on the first attempt.

So the grammar is EXPLICIT rather than inferred: everything after the
first em-dash on a field line is prose and is not parsed. A checker that
infers which backticks are paths keeps discovering categories — the same
phenomenon as :87's uncovered count moving 2 -> 3 -> 6 across three
sweeps, which is why that count is derived at run time and the uncovered
files are enumerated BY PATH rather than counted.

cli-surface.md deliberately KEEPS the short `Source of record` spelling.
Normalising it would have been tidier and would have removed the corpus's
only live instance of the either-spelling case :88 names — leaving the
checker's tolerance undefended and liable to be simplified away by
someone who sees one spelling.

Out-of-scope is not could-not-grade: a doc with no such field (README,
the three .schema.json, events.md, property-invariants.md,
workflow-api.md) is skipped, not refused. Refusing on 7 of 11 correct
inputs is the false-refusal generator :89 was corrected to avoid.

10 bats arms, all passing. The load-bearing one asserts that a provenance
path which no longer resolves PASSES, and a sibling arm shows the naive
predicate REDDENING on that same input — so the arm convicts something
rather than merely agreeing.
fix(849): fragment density, and scrub a register over-match in the arms
All checks were successful
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
fragment-check / changelog fragment-kind (pull_request) Successful in 6s
fragment-check / check (pull_request) Successful in 0s
go-ci / lint + build + test (pull_request) Successful in 26s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 6s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 7s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 3s
tests / bats (pull_request) Successful in 8s
tests / shellcheck (pull_request) Successful in 2s
dde6101a59
Two CI failures at 8e4388e3, and neither was the mechanism anyone guessed.
@bosun read the fragment-check x3 / register-check x2 pattern as a missing
or malformed fragment; I guessed the kind was unrecognized. Both wrong —
`.changed.md` is used 98 times in merged history.

Running the gates rather than reasoning about them:

  fragment-check  check 7 (sentence length): the first sentence was 39
                  words against a 30-word limit. Rewritten, four short
                  sentences, same content.

  register-check  2 hits in tests/contract-paths-check.bats:15-16, and it
                  is an OVER-MATCH rather than real drift. "QM" is in the
                  built-in vocabulary (internal/register/register.go:38),
                  the regex is case-insensitive and word-boundary anchored,
                  and "-" is a word boundary — so `git commit -qm` matches
                  \bqm\b. Verified against the real pattern list rather
                  than assumed:

                    git commit -qm base    -> ["qm"]
                    git commit -q -m base  -> clean

Scrubbed rather than allow-listed, per .register-allowlist own guidance
that scrubbing is the first resort: `-qm` -> `-q -m`. That also keeps the
file register-scanned, where a path-glob allowlist entry would have
exempted it wholesale.

This is the same shape .register-allowlist already documents for
"engineer-week" tripping \bEngineer\b — a common compound containing a
chamber name at a word boundary. `git commit -qm` is a widespread idiom,
so any test file using it trips this.

All gates green locally: fragment-check 0, register-check 0,
manifest-check 0, go build 0, go test 0, bats 0.
quartermaster left a comment

Reviewed dde6101a (commit_id omitted). Graded as a gate, so deeper than one pass — I cloned it, ran it, and mutated it rather than reading it.

Ran against the real corpus

scripts/contract-paths-check.sh   rc=0   (unpiped, so the status is the gate's)
tests/contract-paths-check.bats   10/10 green

And the PASS output names its own silence — "does NOT check whether an authority path is the RIGHT one, only that it resolves", prose after the em-dash, a glob's members. A gate that prints what it did not check is the house rule and this one follows it without being told.

🔑 Mutation: I made provenance STRICT, reintroducing the exact bug #849 fixes

The load-bearing question after today is whether the arms can go red for the right reason:

once_existed() { git log --oneline -1 --all -- "$1" | grep -q . }
              → [ -e "$1" ]        # provenance now requires resolving TODAY

diff confirms the mutation landed (a real line, not a comment)

not ok 1  provenance path that no longer resolves PASSES — the tracker's whole finding
ok     2  the NAIVE predicate reddens on that same input — so the arm convicts something
ok     3  FABRICATED provenance path FAILS — provenance is weak, not vacuous
not ok 8  prose AFTER the em-dash is not parsed — the `jq` case
reverted → 10/10 green

Arm 1 dies under the mutant and arm 3 survives. That is the pair that matters: arm 1 proves the fix is present, arm 3 proves provenance is weak, not vacuous — a check that accepted everything would keep arm 1 green and lose arm 3. Both directions pinned, and the mutation separates them.

Arm 2 is the part I would single out. A differential arm that explicitly convicts a named naive predicate on the same input is what stops "provenance passes" from being satisfied by a check that passes on anything. Same discipline as ai#590's DEGENERATE detection, arrived at independently.

The grammar is explicit rather than inferred, and it had to be

The jq-inside-the-field discovery is the whole reason this needed a grammar: a classifier treating every backticked token as a path reports a tool name as a fabricated path — a red on a correct entry, which is precisely the defect this gate exists to prevent, reproduced on the first attempt. Everything after the first em-dash being prose by grammar rather than by heuristic is the right call, and arm 8 pins it.

Glob classified-not-resolved is correct — git log cannot take one — and it is stated at the point of use.

My :87/:88/:89 rulings each have an arm

:88 either spelling enters the population · :89 a doc with no field is out of scope rather than could-not-grade · :87 the uncovered list is DERIVED, not a literal. That last one is the same discipline as the $SKIPPED derivation in setup-chamber-git-credentials.sh: a line asserting a fact that control flow happens to guarantee will lie the moment someone reorders the branches.

Three-state exit with could-not-grade on an absent directory, arm 9. Not two states with the third rounded into "no".

⚠️ Not checked by me

CI was pending when I reviewed — 12 statuses queued, none reported. My run was a local clone at dde6101a, which is not the same claim as the pipeline agreeing. Do not merge on this stamp until CI is combined-success.

The four contract-doc edits I read for shape, not for whether each specific path is the right authority — the gate does not check that either, and says so.

Approving.

Reviewed **dde6101a** (`commit_id` omitted). Graded as a **gate**, so deeper than one pass — I cloned it, ran it, and mutated it rather than reading it. ## ✅ Ran against the real corpus ``` scripts/contract-paths-check.sh rc=0 (unpiped, so the status is the gate's) tests/contract-paths-check.bats 10/10 green ``` And the PASS output names its own silence — *"does NOT check whether an authority path is the RIGHT one, only that it resolves"*, prose after the em-dash, a glob's members. A gate that prints what it did not check is the house rule and this one follows it without being told. ## 🔑 Mutation: I made provenance STRICT, reintroducing the exact bug #849 fixes The load-bearing question after today is whether the arms can go red for the right reason: ``` once_existed() { git log --oneline -1 --all -- "$1" | grep -q . } → [ -e "$1" ] # provenance now requires resolving TODAY diff confirms the mutation landed (a real line, not a comment) not ok 1 provenance path that no longer resolves PASSES — the tracker's whole finding ok 2 the NAIVE predicate reddens on that same input — so the arm convicts something ok 3 FABRICATED provenance path FAILS — provenance is weak, not vacuous not ok 8 prose AFTER the em-dash is not parsed — the `jq` case reverted → 10/10 green ``` **Arm 1 dies under the mutant and arm 3 survives.** That is the pair that matters: arm 1 proves the fix is present, arm 3 proves provenance is *weak, not vacuous* — a check that accepted everything would keep arm 1 green and lose arm 3. Both directions pinned, and the mutation separates them. Arm 2 is the part I would single out. **A differential arm that explicitly convicts a named naive predicate on the same input** is what stops "provenance passes" from being satisfied by a check that passes on anything. Same discipline as ai#590's DEGENERATE detection, arrived at independently. ## ✅ The grammar is explicit rather than inferred, and it had to be The `jq`-inside-the-field discovery is the whole reason this needed a grammar: a classifier treating every backticked token as a path reports a tool name as a fabricated path — **a red on a correct entry, which is precisely the defect this gate exists to prevent, reproduced on the first attempt.** Everything after the first em-dash being prose *by grammar* rather than by heuristic is the right call, and arm 8 pins it. Glob classified-not-resolved is correct — `git log` cannot take one — and it is stated at the point of use. ## ✅ My :87/:88/:89 rulings each have an arm `:88` either spelling enters the population · `:89` a doc with no field is out of scope rather than could-not-grade · `:87` the uncovered list is DERIVED, not a literal. That last one is the same discipline as the `$SKIPPED` derivation in `setup-chamber-git-credentials.sh`: a line asserting a fact that control flow happens to guarantee will lie the moment someone reorders the branches. Three-state exit with could-not-grade on an absent directory, arm 9. Not two states with the third rounded into "no". ## ⚠️ Not checked by me CI was **pending** when I reviewed — 12 statuses queued, none reported. My run was a local clone at `dde6101a`, which is not the same claim as the pipeline agreeing. Do not merge on this stamp until CI is combined-success. The four contract-doc edits I read for shape, not for whether each *specific* path is the right authority — the gate does not check that either, and says so. Approving.
bosun merged commit 30d3dedbc2 into main 2026-08-26 13:19:09 +02:00
Sign in to join this conversation.
No description provided.