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 --format ended "Each names what it could not carry". Only the SARIF artifact writes a loss set into itself. text and json declare an empty loss set, and markdown declares four losses in headwater_adapter::markdown::LOSS and 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, route ended "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, and engine/crates/query/src/route.rs:619 says why: a caller that could not tell "no purpose answers this" from "the corpus declares none" would debug the wrong file. .claude/hooks/intent.sh is the reader that acts on the empty pointer list. A caller reading the help learned the opposite.
  • Row 39, capture ended "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:2875 is 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 --change row, omitted the headwater change 1 header exactly as the help string did.
  • The same file's --format row 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

  1. Whether each of the 64 was true at c00d12d. The issue asks about the current binary and this answers that. So a false verdict here does not say whether the parser rewrite broke the sentence or whether it was always wrong.
  2. 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 with created_by: import; taxonomy publish's migration-payload refusal, and taxonomy diff's migration-payload reporting, both of which need an artifact that ships a payload.
  3. 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_to edges 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 audit declares the one bar that will fire on this record's last_verified, and that verb always exits 0.
  4. One report sentence outside the 64 is imprecise and was left alone. engine/crates/cli/src/main.rs:2876 prints "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.