Rendered from docs/reviews/the-sixty-four-restored-help-strings-checked-against-the-binary.md in the Headwater
corpus. Every document on this half of the site is typed by the taxonomy
the descriptor names: corpus.json.
The sixty-four restored help strings, checked against the binary
What this is
PR #332 deleted const USAGE and the help text with it. PR #335 put the words back, and 64 of the 125 strings the binary now carries came across byte for byte from a parser that no longer exists. Those 64 describe a machine that was rebuilt underneath them: the flat pre-dispatch flag namespace they were written against was withdrawn in #332, and HW-DR-0033 now puts a flag on the verb that reads it. None of the 64 had been checked. #339 is the issue that asked, and this is the answer.
Every row below states the command that was run and what that command actually printed. Nothing here is a paraphrase of intended behavior. Where a row says a byte count or an exit status, that number came off a run.
The result
| verdict | strings |
|---|---|
| true | 60 |
| false | 3 |
| not runnable | 1 |
| total | 64 |
The three false ones are rows 7, 35 and 39, and each is corrected in the same change that carries this record:
- Row 7,
check --formatended "Each names what it could not carry". Only the SARIF artifact writes a loss set into itself.textandjsondeclare an empty loss set, andmarkdowndeclares four losses inheadwater_adapter::markdown::LOSSand deliberately writes none of them into the artifact, because a job summary is prose for a person who cannot act on a machine declaration. So a consumer who read the help and looked in the Markdown for the loss set found nothing there. - Row 35,
routeended "It is silent when nothing matches". The verb prints at least four lines and exits 0 on a task that matches no purpose. Silence is a property of the pointer set rather than of the output, andengine/crates/query/src/route.rs:619says why: a caller that could not tell "no purpose answers this" from "the corpus declares none" would debug the wrong file..claude/hooks/intent.shis the reader that acts on the empty pointer list. A caller reading the help learned the opposite. - Row 39,
captureended "it never averages readings taken under two taxonomies". It does. Over this repository's own store it prints one fraction, 685 of 780, across 76 readings taken under 17 locks, and then names all 17 and says the number is not a trend.engine/crates/cli/src/main.rs:2875is that branch. The remedy in the code was rejected in favor of the warning, and the help describes the remedy.
The one not-runnable is row 48, probe grade. No transcript this repository can grade exists, because probe plan states that no verb of this engine writes one, and the probe crate's own transcript fixtures were planned against sha256:fixture. Reaching a verdict through the verb would mean authoring a whole consumer declaration and package. The clause about six conditions returning no verdict was read against engine/crates/probe/src/grade.rs, which declares seven Refusal variants and counts six of them as places a green answer would be free, but that is a read of the source rather than a run of the behavior. Beside the verb, engine/crates/probe/fixtures/grade.txt does record a real graded result in-crate, carrying Graded by grader 0.1.0 and per-session verdicts, so the graded behavior is exercised somewhere. It is the command line that cannot reach it.
Row 46, import, was marked not runnable in the first pass, and that verdict was wrong. The first attempt wrote imports: as a sequence rather than as a mapping keyed by name, so the declaration never parsed and the run reported this repository declares no import. That is a malformed input, not an unexercisable verb. With a complete declaration the shipped binary runs the whole way through, and the row now records four runs and stands at true. Only the edge write itself stays out of reach, because the shipped taxonomy declares no relation with created_by: import.
The defect beside the 64, and the correction to the issue
The issue names check --change as one of the 64 and as the one instance already confirmed. It is not one of the 64. PR #335's own body lists check --change under "What is reworded": that string wrote a literal tab as \t, which was changed to <tab> on the way across, so it is one of the 22 reworded strings and not one of the 64 carried whole. The defect is real, and it is fixed in this change:
$ printf 'added\tdocs/spec/13-open-obligations.md\n' > m1.txt
$ headwater check --change m1.txt
headwater: the change manifest did not read
a change manifest opens with `headwater change 1`, and this one opens with `added docs/…`
exit 1
engine/crates/check/src/change.rs:91 is the authority, and the help never named the header. .githooks/change-manifest writes it, which is why the repository's own producer never hit the wall the help walked a reader into.
The correction that follows for the issue's own arithmetic is that the 64 carried no prior measurement at all, rather than one. The rate over them is now 3 false out of 64, or 5%. That is far below the 4-in-5 rate the newly written strings hit in #335's review, and the reason is structural: these sentences describe mechanisms that predate the parser rewrite and did not move with it.
--read-set is likewise reworded rather than carried, so a reader counting flags off the retired USAGE block should not expect it here.
What the correction cost twice
docs/interfaces/headwater-<verb>.md restates the same claims in its own words and nothing holds the two against each other. Two of the corrections had a twin there:
docs/interfaces/headwater-check.md, the--changerow, omitted theheadwater change 1header exactly as the help string did.- The same file's
--formatrow said "Each target states what it could not carry", which is the same false sentence.
docs/interfaces/headwater-route.md did not have the twin: it already says "A silent route writes its normal report and still exits 0", so the contract was right and only the help was wrong. docs/interfaces/headwater-capture.md makes no averaging claim.
What holds the corrections now
Four cases in engine/crates/cli/tests/wiring.rs, each of which pairs the sentence with the behavior it describes:
| case | what fails without the fix |
|---|---|
the_change_help_names_the_header_a_manifest_must_open_with |
the help does not name headwater change 1; and a manifest written from the old help is refused while the same manifest under the header reads |
route_promises_no_silence_and_is_never_silent |
the description promises a silence the verb never keeps; and a route that matches nothing still writes its report and exits 0 |
only_the_sarif_artifact_declares_its_own_loss_set |
the help claims a loss set every target writes; and only the SARIF artifact carries one |
capture_pools_across_taxonomies_and_names_every_one |
the description claims a refusal the verb never makes; and over a store carrying two readings under two locks the verb prints one pooled fraction, names the count, and names both locks |
Each was watched failing against the string as #335 restored it. All four strings were mutated back in place and the target run: all four cases failed, the other 17 passed, and the strings were restored. The first version of the --format case passed against the old text, because clap wraps a help string across lines and the sentence was not there to find as one substring; that is why every string assertion reads a whitespace-flattened form.
Three of these four cases hold a string inside the 64 — rows 7, 35 and 39. The fourth holds check --change, which this record argues is outside the set. So three of the 64 are held and the other 61 are held by nothing, and no mechanism in this repository holds them. Building one was considered and rejected: one side of the comparison is English prose and the other is engine behavior, and nothing can compare them. The issue says as much itself.
Two of the four cases assert only the absence of the old sentence rather than the presence of a particular new one. They catch a literal reversion, which is what the mutation run proved, and they would pass against some other wrong rewording. The behavioral half of each case is what carries the rest.
The gap this audit found beside its own subject
engine/crates/cli/tests/interface_contract.rs holds a contract to its headings and explicitly declines to read its content, on the ground that a kind whose whole purpose is a description must not imply that a check read the description. engine/crates/cli/tests/help.rs holds every argument to carrying help text and never to its content. So a help string and its paired interface contract can both be false with the whole suite green, which is what happened to --change for nine days across a parser rewrite. This record names it. It is not this change's work to fix.
The method
The 64 are reproducible. PR #335's body names its own rule: a string counts as carried whole when the whole of it appears in the flattened descriptive prose of USAGE at c00d12d. Reimplementing that rule against the #335 merge commit reproduces its table to the byte, at 125 sites and 22,448 bytes total, of which 64 sites and 12,115 bytes are carried. The comparison has to be case-insensitive for 20 of the 64, because the verb description strings were sentence-cased on the way onto VERBS.
Two source files hold every string. engine/crates/cli/src/lib.rs carries 68 help clauses on #[arg(…)] attributes, 30 of them carried. engine/crates/verbs/src/lib.rs carries VERBS, which is 32 summary and 32 description fields over 18 verbs and 14 second words, 33 of them carried. headwater_cli::command walks VERBS and applies each one onto the clap tree with mut_subcommand, so a verb string is printed both by the command line the table names and by the root screen.
One of the 64 has moved since #335. taxonomy publish --package had a sentence appended, so the carried prefix is intact and unverified while the whole string is no longer a USAGE substring. It is row 64, and only the prefix is audited.
Every run was against a release build of this branch, over one of five roots: this repository, a throwaway copy of it, a copy with one deliberate defect, a copy carrying a constructed import declaration, and an empty directory. --now 2026-08-28 was passed wherever a clock could move the bytes.
Every number in the table was re-measured against the tree this commit carries, and not against the commit the audit started on. The first pass ran against cdadbc5, and this change then added three documents of its own, which moved the census, the capture store and several byte counts before the branch was finished. Nine numbers were refreshed for that reason: the capture readings and the pooled fraction in rows 38 and 39, the capture byte count in row 11, the classified-document count in row 23, the report byte counts in rows 1 and 5, the audit byte count in row 56, the projection census in row 47, and the store counts and minted identifier in row 41. A reader who re-runs a row's command against this commit should get the number the row states.
The table
Sixty-four rows, in source order: engine/crates/cli/src/lib.rs by line, then engine/crates/verbs/src/lib.rs by line. site is the file and line and the field. claim is the string, flattened. A string that makes several claims keeps one row, because the string is what the issue counts, and the what it returned column then says which clause was exercised and which was not.
| # | site | printed by | claim | how it was tested | what it returned | verdict |
|---|---|---|---|---|---|---|
| 1 | cli:115 --root |
all 33 command lines | the repository to read. Defaults to the working directory | headwater check --root <repo> from /tmp; then headwater check from /tmp |
with the flag: exit 0, 63,114 bytes of report. Without it, from /tmp: exit 1, /tmp/.headwater/taxonomy.lock is not there, so the working directory was the root |
true |
| 2 | cli:129 -V / --version |
all 33 command lines | the version of this engine. It is the number a package's requires_engine range is read against, and it is the number to quote in a bug report. One line on standard output, and no repository is needed to ask |
headwater -V and headwater --version from /tmp; grep -rn requires_engine engine/crates |
both: 0.1.0, one line, 6 bytes on stdout, 0 bytes on stderr, exit 0, outside any corpus. packages/headwater-standard/release.yml states requires_engine: ">=0.1 <2" and resolve/src/release.rs reads it |
true |
| 3 | cli:190 check --strict |
headwater check |
exit non-zero when a finding is an error. Without it the run is advisory and always exits 0, which is the default spec 6 fixes | a corpus copy with organise appended to a governed document, run twice |
check: 4 findings, 1 error, exit 0. check --strict: the same 4 findings, exit 1 |
true |
| 4 | cli:196 check --fix |
headwater check |
write the patch that rides with a finding, in this working tree. A finding carries one only when the fix is mechanical and total, and a finding an author suppressed carries none. Every patch is held against the bytes it names and the result is read back before it lands, so a file whose shape this engine guessed wrong is refused with nothing written. The report that follows is the run after the write, and the account of what was written goes to standard error. It exits non-zero on a refusal | the same copy: check --fix, then a second check --format json; then the same over a target the process cannot open |
headwater: fixed docs/spec/13-open-obligations.md (1 patch) on stderr, the report on stdout, organise gone from the file, and the report that followed carried 0 errors, so it is the run after the write. Over an unopenable target: exit 1 and nothing written |
true |
| 5 | cli:207 check --no-cache |
headwater check |
read and write no cache, and evaluate every instance. This run and a cached one write the same bytes to standard output, and a difference between them is a defect in the cache rather than a result | check --now 2026-08-28 and check --no-cache --now 2026-08-28, both to files, then cmp |
63,335 bytes each, cmp clean |
true |
| 6 | cli:253 check --register |
headwater check |
write the register of this run to a file as well as to the report. Spec 4 makes it a projection of the obligations and controls declarations, generated and never authored: every obligation with its disposition, every control with its health, and what escaped under each |
check --register <file>, then read the file |
exit 0; the file holds 32 obligations: 29 verified, 2 gap, 1 unverifiable, each gap with its owner, 29 controls with posture and act, and escaped findings, in the precedence spec 4 fixes. The same block is in the report |
true |
| 7 | cli:262 check --format |
headwater check |
which vocabulary to write the run in. text is the report a person reads and the default. sarif is what a forge ingests as a check run, markdown is a job summary or a review comment, and json is the finding shape spec 4 declares, for an adapter nobody here wrote. Each names what it could not carry |
all four targets, then grep -c loss_set over each artifact, then cmp of the default against --format text |
all four exit 0 and the default is byte-identical to text. loss_set is in the SARIF artifact and in none of the other three. adapter/src/markdown.rs declares four losses in LOSS and states that it writes none of them into the artifact |
false |
| 8 | cli:298 conformance --level |
headwater conformance |
the rung to ask about, by the name the package declares. It exits non-zero on a gap under that rung that no live waiver covers. It never moves the level the report states, which is computed from met rules alone | conformance, conformance --level L0, conformance --level L1, conformance --level bogus |
bare and L0: exit 0. L1: exit 1 and the report still says the level is L0. bogus: exit 1, the rungs it declares are L0, L1, L2 |
true |
| 9 | cli:307 --now |
check, conformance, mcp, infer, taxonomy diff, taxonomy migrate |
the date to evaluate against, as YYYY-MM-DD. Defaults to today |
a default run against --now 2026-08-28; then --now 28-08-2026 |
byte-identical. The wrong shape: exit 1, invalid value '28-08-2026' for '--now <date>': a date written YYYY-MM-DD |
true |
| 10 | cli:324 route --budget |
headwater route |
how many ranked pointers it may offer. It never removes a document that governs a path the task named, and it says how many it withheld. Five by default | a corpus copy with six more tutorial documents, so purposes.procedure matches more than five candidates; then route "how do I start" and the same with --budget 1 |
the default offered 5 pointers and printed the budget withheld 21 more pointers. --budget 1 offered 1 and printed the budget withheld 25 more pointers. An anchored pointer is not cut by the budget |
true |
| 11 | cli:353 capture --format |
headwater capture |
text is the report a person reads and the default, and json is the same numbers for a program. Neither carries a reading the store does not hold |
capture, capture --format text, capture --format json |
the default is byte-identical to text at 4,028 bytes. The JSON holds "readings": 76, the same count the text reports |
true |
| 12 | cli:371 mcp --write |
headwater mcp |
register the working-tree write class, which is new and fix. Spec 5 keeps it off by default, because a client may connect to a checkout that the user did not intend to change, so the consent is a word somebody typed rather than a setting a tree carries. A tool that lands a change is registered by no switch. The first call that moves a byte ends the server: it walked the corpus once, so every later answer would be about a tree that is gone |
two JSON-RPC sessions over stdin, each initialize then tools/list then a new call then a second read |
without --write: 6 tools, no new, and the call is refused with it registers no tool that writes. With --write: 8 tools including new and fix; new wrote docs/decisions/0042-…; the next read was refused with this server walked the corpus once … so it answers none |
true |
| 13 | cli:390 new --title |
headwater new |
what the document is called. Required, because the file name and the facet in the name role both come from it |
headwater new decision with no --title |
exit 1, `new takes --title <text>. The file name and the document's own name both come from it` |
true |
| 14 | cli:428 infer --owner |
headwater infer |
who owns the debt it proposes. Required with --write, because an owner is the field that ranks declared debt above a suppression and this engine will not invent one |
headwater infer --write with no --owner |
exit 1, --write needs --owner |
true |
| 15 | cli:437 infer --until |
headwater infer |
the last day the tasks it proposes hold, as YYYY-MM-DD. Ninety days out by default |
headwater infer --now 2026-08-28 |
the payload states until: 2026-11-26, which is 2026-08-28 plus 90 days |
true |
| 16 | cli:443 infer --write |
headwater infer |
put the payload in the lock, which is committed and reviewed. Without it nothing is written | md5sum .headwater/taxonomy.lock around a bare headwater infer |
a384309724b4e0eefba572675b6eb3ad before and after |
true |
| 17 | cli:451 --now |
the six lines of row 9 | the date to evaluate against, as YYYY-MM-DD. Defaults to today |
the same string as row 9, at a second site | see row 9 | true |
| 18 | cli:491 export --profile |
headwater export |
which declared export profile to emit. Every declared profile by default, so a filtered audience is never omitted by accident | export, export --profile default, export --profile site, export --profile bogus |
bare: graph_export .headwater/export.json unchanged. default produces no file and site produces that one, so the bare run is both. bogus: exit 1, This taxonomy declares default, site |
true |
| 19 | cli:498 export --format |
headwater export |
the emitter target. json is the native property graph with no loss and jsonschema constrains front matter. The other five targets of spec 6 parse and report the consumer each one waits on. With this flag the artifact goes to standard output and no declared output path is touched |
--format json, --format shacl, --format bogus, each with --profile default; and md5sum of the declared output path around a --format run |
json wrote 468,641 bytes to stdout with a projection census on stderr. shacl: exit 1 and the shacl emitter waits on a named external consumer. bogus: exit 1 and the seven target names. .headwater/export.json unchanged either side of the --format run |
true |
| 20 | cli:508 export --at |
headwater export |
the generation time the artifact states, as YYYY-MM-DD. Absent by default, because an artifact that --check compares by byte cannot carry a clock reading. Spec 6 asks a filtered export that leaves the repository to state one, and this is where it is injected |
export --profile default --format json with and without --at 2026-08-28, grepping the artifact for generated |
without the flag the artifact carries no generated_at. With it: "generated_at": "2026-08-28" |
true |
| 21 | cli:535 init --corpus |
headwater init |
the corpus root to declare. Proposed from the tree by default | init in an empty directory, init in a directory holding one Markdown file, and init --corpus docs |
empty: exit 1, no directory under this repository holds a Markdown file, so nothing here proposes a corpus root. With a Markdown file: exit 0 and root: notes written from the tree. With the flag: root: docs |
true |
| 22 | cli:541 init --package |
headwater init |
the package to take. headwater/standard by default |
a bare init over a tree that holds Markdown, then reading .headwater/taxonomy.yml |
package: headwater/standard |
true |
| 23 | cli:643 sweep plan --under |
headwater sweep plan |
the slice, as a path prefix under the repository root. The whole corpus by default. There is no sampling rule here: a slice this engine picked would be an unreproducible sample dressed as a reproducible one, and the plan reports its own extent instead | sweep plan, sweep plan --under docs/spec, sweep plan --under nosuchdir |
bare: A coherence sweep over the whole corpus, 261 of the 261 classified documents. docs/spec: 15 of 261. nosuchdir: 0 of 261, exit 0. Each states its own extent in its first line |
true |
| 24 | cli:659 sweep report --format |
headwater sweep report |
text is the report a person reads and the default, and json is the finding shape spec 4 declares with the provenance and the evidence a sweep adds |
a written-back findings file, then sweep report <file>, --format json, and --format json --json |
text is the default and is the report a person reads. The JSON carries "mechanism": "sweep", "provenance": "agent" and the evidence. Both together: exit 1, cannot be used with --json |
true |
| 25 | cli:796 taxonomy publish --out |
headwater taxonomy publish |
where to write the artifact. The directory must be empty or absent, because a published artifact is every file under its root and a stray one would be a member the publisher never shipped. A run that cannot finish leaves it as it found it, so a second run meets the same precondition the first one did | publish --from taxonomy-source/headwater-standard --out <dir> against an absent directory, then the same directory again, then an empty existing one |
absent: exit 0, 75 files. The same directory a second time: exit 1, the output directory holds files already. Empty and existing: exit 0, 75 files |
true |
| 26 | cli:813 taxonomy vendor --expect |
headwater taxonomy vendor |
the digest to check the artifact against. It defaults to taxonomy.digest in .headwater/taxonomy.yml, and the verb refuses when neither is there. A pin the engine took from the artifact in front of it would be a pin against itself |
vendor <artifact> in a repository that pins nothing, then vendor <artifact> --expect <a wrong digest> |
no pin and no flag: exit 1, nothing pins this artifact … or pass it with --expect. Wrong digest: exit 1, naming the pin and the artifact digest |
true |
| 27 | cli:829 taxonomy diff --to |
headwater taxonomy diff |
the version the artifact is expected to be, written as a version or as a range: 4.0.0, or >=4 <5 with the quoting your shell needs. This engine fetches nothing, so the directory decides which artifact is compared and this flag holds it to what the caller meant. It is read by the one range reader the engine has, which is what reads requires_engine |
diff <artifact> --to 9.9.9 and diff <artifact> --to ">=3 <4" |
9.9.9: exit 1, `--to 9.9.9 and the artifact declares 3.4.0`. The range: exit 0 and the six dimensions reported |
true |
| 28 | cli:840 --now |
the six lines of row 9 | the date to evaluate against, as YYYY-MM-DD. Defaults to today |
the same string as row 9, at a third site | see row 9 | true |
| 29 | cli:854 taxonomy migrate --to |
headwater taxonomy migrate |
the version the artifact is expected to be, written as a version or as a range: 4.0.0, or >=4 <5 with the quoting your shell needs |
migrate <artifact> --to 9.9.9 |
exit 1, `--to 9.9.9 and the artifact declares 3.4.0` |
true |
| 30 | cli:868 --now |
the six lines of row 9 | the date to evaluate against, as YYYY-MM-DD. Defaults to today |
the same string as row 9, at a fourth site | see row 9 | true |
| 31 | verbs:152 check description |
headwater check |
Run the pipeline over the corpus, against the taxonomy in the committed lock. | a corpus copy whose overlay was made unresolvable, with the lock left standing, then check |
exit 0 and the full report, against headwater/standard 3.4.0 at the locked digest. taxonomy resolve over the same tree exits 1, so the run read the lock and not the sources |
true |
| 32 | verbs:159 gate description |
headwater gate |
Hold the read set of an earlier run against the tree in front of it, and report whether the verdicts of that run carry to this one. It reads only what the set lists, so it reports the reach of its own answer and never reports that a corpus is green. It exits non-zero on a verdict that does not carry, which is the signal to run the checks again. | check --read-set <file>, then gate --read-set <file>, then the same after a document under the set moved |
unmoved: exit 1 on two barriers. Moved: exit 1 naming the document and both digests. Both runs end this states nothing about a document this tree gained |
true |
| 33 | verbs:166 conformance description |
headwater conformance |
Evaluate this repository against the conformance rules the taxonomy package ships, and report the level that the passing rules reach. A level states what this repository wired up: it measures nothing about the corpus, no key declares one, and a waiver moves the exit status and never the level. A rule this engine holds no reading for ends the run rather than being skipped. Without --level it exits 0 whatever it finds. |
conformance bare, and conformance/src/lib.rs for the no-reading path |
exit 0 over a corpus with one gap and three rules not decided, so it exits 0 whatever it finds. conformance/src/lib.rs:201 ends the run on a rule the engine holds no reading for. The waiver clause was not exercised: this package declares no live waiver |
true |
| 34 | verbs:172 route summary |
headwater (the root screen) |
resolve a task description to the documents that govern it | route "how do I start" over the constructed corpus of row 10 |
pointers to the documents whose purpose answers the phrase | true |
| 35 | verbs:173 route description |
headwater route |
Resolve a task description to the documents that govern it, as pointers. It is silent when nothing matches. | headwater route "add a check rule for prose", and the same with --json |
129 bytes on stdout over four lines, 0 on stderr, exit 0. The last two lines are no purpose matched and no declared purpose answers this task. The JSON carries "silence": {"reason": "no_purpose_matched"}, so silence is a property of the pointer set and never of the output |
false |
| 36 | verbs:180 explain description |
headwater explain |
Why a document is the kind it is, what it serves, and what is consequently required of it. | explain docs/spec/13-open-obligations.md and explain docs/w3id/README.md |
the first: the kind, why the shelf matched, the purpose, the required facets, the relations the kind may declare, and every declared edge both ways. The second: no kind, so nothing is required of it |
true |
| 37 | verbs:191 query description |
headwater query |
Listed in spec 6, and no document states what an expression is, so this engine implements none. It states that wait and exits non-zero. It is here because a wait a caller cannot discover is a wait nobody reads. route and explain are the reads that exist. |
headwater query "anything" |
exit 1, `query <expression> is listed in spec 6 and no document states what an expression is, so this engine implements none … headwater route and headwater explain are the reads that exist` |
true |
| 38 | verbs:197 capture summary |
headwater (the root screen) |
read the capture-cost store back | headwater capture |
76 readings read back out of .headwater/capture-cost.jsonl |
true |
| 39 | verbs:198 capture description |
headwater capture |
Read the capture-cost store back: the assisted fraction over every reading it holds, the same by kind, and how far the authoring verb reaches into the corpus. It names no person and no agent, and it never averages readings taken under two taxonomies. | headwater capture over this repository, whose store holds 76 readings under 17 locks |
the report prints one fraction, 685 of 780, over all 76 readings, and then 17 taxonomies produced these readings, so the aggregate above is across two denominators and is not a trend. It pools across taxonomies and warns. cli/src/main.rs:2875 is the branch. The by kind and reach sections are as described, and no person and no agent is named |
false |
| 40 | verbs:211 new summary |
headwater (the root screen) |
scaffold a document of a kind | headwater new decision --title "…" |
wrote docs/decisions/0043-… |
true |
| 41 | verbs:212 new description |
headwater new |
Scaffold a document of a kind: the placement its shelf dictates, the front matter its facets require, the sections its contract requires, an identifier under its scheme, and the edges the taxonomy assigns to a scaffold. It writes no generated-file marker, because what it writes is an authored document from the moment it lands and every check reads it. It decides everything before it writes anything, and it never overwrites a document. Every run that writes a document appends one capture-cost reading to the store, and a run whose reading did not land exits non-zero. | the same title twice, with wc -l .headwater/capture-cost.jsonl around each run |
the second run minted 0043 rather than overwriting 0042. The store went 76, 77, 78, so each run that wrote a document appended one reading. The report names the placement, the facets, the sections, the identifier and the edges before the write. The clause about a reading that did not land was not exercised |
true |
| 42 | verbs:218 infer summary |
headwater (the root screen) |
report the debt this taxonomy raises over this corpus | headwater infer |
2 pairs of debt, in 1 task, expiring 2026-11-26 |
true |
| 43 | verbs:219 infer description |
headwater infer |
Report the debt this taxonomy raises over this corpus as an adoption payload: (document, rule) pairs under tasks that each carry an owner and an expiry. It prints the payload and writes nothing without --write. |
infer --now 2026-08-28, with the lock digest read either side |
the payload is tasks: with an id, a statement, an owner, an until and pairs of {path, rule}. The lock digest did not move |
true |
| 44 | verbs:225 generate summary |
headwater (the root screen) |
write every projection the taxonomy declares | headwater generate --check |
seven projections reported, each unchanged |
true |
| 45 | verbs:226 generate description |
headwater generate |
Write every projection the taxonomy declares, and report every one it does not write with the reason. It refuses to overwrite a file that carries no generated-file marker. | a corpus copy with the generated-file marker stripped from docs/decisions/README.md, then generate |
exit 1, and that row reads a file is there and it carries no generated-file marker, so this engine will not overwrite it. Three more are reported under what this verb does not write, and why, each with its reason |
true |
| 46 | verbs:233 import description |
headwater import |
Read a snapshot that somebody already fetched and committed, and write the edges it declares into the documents at their near ends. The snapshot is checked against a digest and a channel that a person wrote into .headwater/taxonomy.yml, and an import with neither is refused rather than recorded. Without --write it reports the edges and touches nothing. A wrong imported edge would produce a correct check result over a wrong graph, so every link is refused whole rather than reported as a finding. |
a corpus copy carrying a complete imports.ado declaration (at, digest, channel, resolver), a snapshot.yml and a release.yml, run four ways |
a wrong pin: exit 1, this repository pins sha256:0000… and the artifact is sha256:aff90beb…. The right pin: exit 0, import ado from acme/work-items … 2 items, 0 links, then 0 edge halves to write, and nothing was written. Run it again with--write. With `--write`: `wrote 0 edge halves into 0 documents`. With a `traces_to` link in the snapshot: exit 1,traces_todeclarescreated_by: hook, and this verb writes an edge only where a taxonomy expects an importer to pay for one — refused whole rather than reported as a finding. The edge write itself was not exercised, because the shipped taxonomy declares no relation with created_by: import |
true |
| 47 | verbs:240 export description |
headwater export |
Emit one declared export profile through one emitter target, with the loss set the target declares and the projection census that holds the output against the graph. With --format it writes the artifact to standard output, which is what a consumer outside this repository asks for. Without one it writes every declared export to the path its taxonomy names, and --check holds those to regeneration. |
export --profile default --format json, reading stderr, and export --check |
the census on stderr: 324 nodes: 324 carried, 0 accounted for and 535 edges: 535 carried, 0 accounted for. With no --format the declared path is written, and --check reports projections, held to regeneration |
true |
| 48 | verbs:280 probe grade description |
headwater probe grade |
The one component of this engine that returns a verdict, and three properties are why it may: its inputs carry no prose, every satisfied verdict names the event that satisfied it, and six conditions return no verdict where a green one would be free. It reports a rate over the sessions that reached a verdict, with the count that did not beside it. | probe grade over the three transcripts under engine/crates/probe/fixtures/, from this repository and from the probe fixture corpus |
from this repository: This transcript reached no grader: it was planned against taxonomy sha256:fixture and this tree carries sha256:a37aa8…. From the fixture corpus: exit 1, .headwater/probe.yml did not read. No transcript this repository can grade exists, and probe plan states that no verb of this engine writes one, so no rate and no verdict was produced. probe/src/grade.rs declares seven Refusal variants and its module comment counts six as places a green answer would be free. Beside the verb, engine/crates/probe/fixtures/grade.txt records a real graded result in-crate, so the graded behavior is exercised somewhere and the command line is what cannot reach it |
not runnable |
| 49 | verbs:284 probe stale summary |
headwater probe, headwater probe stale |
which recorded results a change voided | headwater probe stale |
This corpus holds no probe_transcript document, so no result has been recorded and a change voids nothing |
true |
| 50 | verbs:292 init summary |
headwater (the root screen) |
scaffold the consumer declaration and the overlay | headwater init over a tree holding one Markdown file |
wrote .headwater/taxonomy.yml and wrote .headwater/overlay.yml |
true |
| 51 | verbs:293 init description |
headwater init |
Scaffold the consumer declaration and the overlay for a repository that has neither, and print the questions that no tree answers. It refuses to overwrite a binding. | init over a tree with neither declaration, then init again over the same tree |
the first wrote both files and printed three questions under what it cannot read off a tree, and asked instead. The second: exit 1, .headwater/taxonomy.yml is already there, so this repository is already bound |
true |
| 52 | verbs:304 taxonomy validate summary |
headwater taxonomy |
resolve the sources and report every rule of spec 2 | headwater taxonomy validate |
sources, in application order, then the rules of spec 2's list |
true |
| 53 | verbs:305 taxonomy validate description |
headwater taxonomy validate |
Resolve the sources and report every rule of spec 2's list, and what each one did not decide. Writes nothing. | taxonomy validate over this repository and over a copy whose overlay does not resolve |
5,612 bytes of rule-by-rule report, exit 0, and no file written. Over the broken overlay: exit 1 naming the key and its line | true |
| 54 | verbs:309 taxonomy resolve summary |
headwater taxonomy |
write .headwater/taxonomy.lock |
see row 55 | see row 55 | true |
| 55 | verbs:310 taxonomy resolve description |
headwater taxonomy resolve |
Write .headwater/taxonomy.lock. It is written only when the taxonomy validates, so a lock is a validated taxonomy. |
a corpus copy with an unresolvable key appended to the overlay, md5sum of the lock either side of taxonomy resolve |
exit 1, the taxonomy did not resolve, so no lock is possible, and the lock digest unchanged at a384309724b4e0eefba572675b6eb3ad |
true |
| 56 | verbs:314 taxonomy audit summary |
headwater taxonomy |
measure the taxonomy against the corpus | headwater taxonomy audit |
11,729 bytes of readings over the schema | true |
| 57 | verbs:315 taxonomy audit description |
headwater taxonomy audit |
Measure the taxonomy against the corpus: edge counts and staleness by the creator each relation declares, relation drift by family, facet differentiation, the discriminator distribution of a heterogeneous shelf, and state dwell. It reports findings about the schema and never about a document, it gates nothing, and it always exits 0. One bar is declared and the rest of the readings are distributions with no verdict beside them. | headwater taxonomy audit |
exit 0, and the report states One bar is declared: last_verified is stale after 180 days. It is the only number a declaration states, so it is the only reading below that carries a finding. Everything else is a distribution |
true |
| 58 | verbs:319 taxonomy publish summary |
headwater taxonomy |
write the artifact of a package into a directory | see row 59 | see row 59 | true |
| 59 | verbs:320 taxonomy publish description |
headwater taxonomy publish |
Write the artifact of a package into a directory, with a release record over it: every file, the digest of its bytes, and one digest over that list. It prints the digest, which is the number the release notes state and a consumer pins. It reads every migration payload the manifest declares before it writes a file, and refuses one that the taxonomy under publication contradicts. | publish --from taxonomy-source/headwater-standard --out <dir>, then reading release.yml |
published headwater/standard 3.4.0 … 75 files … digest sha256:3db23d47…, and release.yml carries 76 sha256 values, which is one per file plus the digest over the list. The migration-payload refusal was not exercised: this manifest declares no payload |
true |
| 60 | verbs:325 taxonomy vendor description |
headwater taxonomy vendor |
Check an artifact that somebody already fetched against the digest this repository pinned, and install it under packages/. It refuses an artifact that is not the pinned one, and it names every file that moved. Nothing here fetches: no crate of this engine depends on the network, so the verb takes the path of a directory and never a location. |
vendor <artifact> against a wrong pin, then against the right pin, then against an artifact whose bytes no longer match its own record |
wrong pin: exit 1 naming both digests. Right pin: exit 0, 75 files, all of them the pinned bytes, installed under packages/. Moved bytes: exit 1, the artifact is not what its own record says it is, in 1 place: and then package.yml was published as sha256:2bf76083… and these bytes are sha256:1fd1531b…, which is the file naming the description promises |
true |
| 61 | verbs:329 taxonomy diff summary |
headwater taxonomy |
measure what a published artifact would do to this corpus | see row 62 | see row 62 | true |
| 62 | verbs:330 taxonomy diff description |
headwater taxonomy diff |
Measure what a published artifact would do to this corpus, across the six compatibility dimensions of spec 2. It resolves the artifact under this repository's own overlays and runs every phase twice over one tree, so a difference is attributable to the schema rather than to two publishes of one package differing in trivia. Where the artifact ships a migration payload for the move, it reports what each step reaches in this corpus and every document that stopped validating under no step. It writes nothing, and it fails only when it could not measure. | taxonomy diff <artifact> --now 2026-08-28 |
exit 0, nothing written, and the six dimensions of spec 2 each reported preserved. The migration-payload clause was not exercised: the artifact ships none |
true |
| 63 | verbs:334 taxonomy migrate summary |
headwater taxonomy |
apply the migration payload a published artifact ships | taxonomy migrate <artifact> --now 2026-08-28 |
exit 1, the artifact ships no migration payload for 3.4.0 to 3.4.0 … this verb applies a payload rather than deriving one |
true |
| 64 | cli:777 taxonomy publish --package, the carried prefix |
headwater taxonomy publish |
the package to publish. The one this repository's own declaration takes, by default, because a publisher usually publishes what it also consumes. | a bare taxonomy publish --out <dir>, then --package nonesuch/thing |
bare: the run took packages/headwater-standard, which is the directory this repository's own declaration names, and refused it because it carries a release record. nonesuch/thing: exit 1, no package under packages/ declares nonesuch/thing. The sentence a later change appended is outside the carried prefix and outside this audit |
true |
What this record does not establish
- Whether each of the 64 was true at
c00d12d. The issue asks about the current binary and this answers that. So afalseverdict here does not say whether the parser rewrite broke the sentence or whether it was always wrong. - Six clauses inside otherwise-true rows were not exercised, and each row says so:
--fix's refusal path was reached through a target the process could not open rather than through a document whose shape the engine guessed wrong;conformance's waiver clause has no live waiver to run against;new's "a run whose reading did not land exits non-zero";import's edge write, because the shipped taxonomy declares no relation withcreated_by: import;taxonomy publish's migration-payload refusal, andtaxonomy diff's migration-payload reporting, both of which need an artifact that ships a payload. - The 61 unheld strings are held by nothing. Three of the 64 now have a case that fails when the sentence goes wrong. The rest are true today and nothing reads them tomorrow, which is the same position every string was in before this audit. The
traces_toedges in this record's front matter reach the two files that hold every audited string and the file that holds the four cases, so a change to any of them at least names this record. That is a pointer and not a gate:taxonomy auditdeclares the one bar that will fire on this record'slast_verified, and that verb always exits 0. - One report sentence outside the 64 is imprecise and was left alone.
engine/crates/cli/src/main.rs:2876prints "the aggregate above is across two denominators" over a store that named 17 taxonomies. It is a run-report string rather than a help string, so it is outside this issue's set.