Derive It, Don't Stamp It¶
The bug was not a bug in the code. It was a shape in the work queue.
A load-bearing documentation edit -- the kind that changes how the project routes review risk -- could travel through the system as a Low-tier doc edit. The file was "just docs." The change was not. It touched the contract that tells future agents how much review a risky change earns, but the routing machinery had no doc-side equivalent of the code graph. It could see code annotations, test marks, dependency edges, churn, and policy weights. It could not yet see that a canonical doc had become part of the review control plane.
The obvious patch is also the wrong one: add a field.
edit_tier: high criticality: routing-contract
That feels responsible for about five minutes. Then the next edit lands, the field stays where it was, and the system has one more little stamp that everyone promises to keep current. The stamp becomes a second source of truth. The whole point of the risk system is to avoid that. Review routing should be computed from the current shape of the project, not from a hand-maintained label a tired author may forget.
That is the principle now written into the canonical scoring doc: derive the routing signal, don't stamp it. Stamp only the irreducible judgment. Derive the recoverable facts.
The missing graph¶
The code side already has a machine for this.
the codemap scorer does not ask a developer to write "this edit is high risk." It reads the files that changed, the annotations attached to those files, the graph edges that point into them, the test marks that claim coverage, and the policy weights in the codemap subsystem. Then it emits complexity, risk, and review route.
That is why source annotations work as infrastructure instead of decoration. A maturity: judgment may be stamped because the tool cannot infer intent perfectly. But edit tier is derived. Blast radius is derived. Review route is derived. If the code or its graph changes, the route changes with it.
Canonical docs needed the same kind of substrate.
The planned doc-side version is a regenerated doc reference index: markdown links, explicit code-path references, doc frontmatter capabilities, and doc-to-doc references become graph edges. A canonical page about risk scoring should not be important because it says criticality: high. It should be important because many review, authoring, and orchestration surfaces point at it, and the graph can show that reach.
That distinction matters. A field says, "trust me." A graph says, "here is who consumes this."
The derivation failed on itself¶
The cleanest part of the story is the part that did not work.
The same batch that proposed deriving ## Depends on edges from ticket artifacts was also the batch that disproved the naive derivation. The first rule sounded sensible: if ticket A creates a path and ticket B consumes that path, derive B -> A. Use ## Touches as the ownership signal. Backfill the edge.
On the graph-derived-routing batch, that rule found zero of the three creates->consumes edges it needed to find.
Zero of three is useful. It means the premise was falsifiable. It also explained the bug in the derivation: broad globs and shared files made "owned by exactly one ## Touches entry" ambiguous. The fact that two tickets both mention the workflow scripts does not mean both produce the same new file. One ticket may create the library. Another may consume it while also editing the wrapper. Touches are an edit surface, not a producer identity.
The fallback was worse. A raw stem-mention rule -- "if ticket B names ticket A's slug, B probably depends on A" -- came in at about 30 percent precision on that same batch, with seven false positives. Some were reversed: a predecessor named a follow-on in references or rejection prose, and the naive rule pointed the edge backwards. Some were disclaimers: the text explicitly said something was not a dependency, and the raw mention still counted it.
That is the important lesson: derivation is not magic because it is automated. A bad derivation is just a faster way to stamp the wrong thing.
Direction before mention¶
The fix was not "stop deriving." The fix was "derive less, but derive it from the right fact."
Producer identity became load-bearing. For a creates->consumes edge, the producer is the ticket that actually adds the missing artifact. The consumer is the ticket that reads, imports, edits, or otherwise relies on that artifact. The direction is consumer -> producer. Co-editing the new file does not erase the dependency; it often proves the consumer needs the producer's output.
Stem mentions became corroboration, not evidence by themselves. A mention in ## Context or ## Scope -- in can support a consumer edge. A mention in references, out-of-scope prose, rejection criteria, or a sentence that says "not a dependency" cannot create one. Text has location. Location has meaning.
That is the same lesson the doc-routing problem taught from another angle. "This doc is important" is not the fact. The recoverable fact is the set of docs, scripts, tickets, and review gates that consume it. "This ticket depends on that ticket" is not always the fact. The recoverable fact is producer, consumer, artifact, context, and basis.
Once those are present, the edge can be derived. When they are absent, the residue stays hand-authored and honest.
Why stamping loses¶
Stamped metadata is tempting because it is cheap at authoring time. Add a field. Add a label. Add a tier. Move on.
The cost arrives later, when the stamp and reality diverge. A doc says it is Low but every future risk-routing change depends on it. A ticket says it has no dependency but consumes a file created by a sibling. A comment says an invariant is covered, but the test mark never named the capability. None of those failures are dramatic. They are worse: they are quiet.
Derived metadata has the opposite cost profile. It is more expensive to build, and it is annoying when the first version fails. But the failure is inspectable. A derivation can print its basis. It can say, "I emitted B -> A because A creates this path and B consumes it from this section." It can also say, "I cannot derive the purely logical edge; keep that hand-authored."
That is a healthier contract for autonomous work. The agent does not have to remember every edge. The project regenerates the edges it can prove and names the edges it cannot.
The rule I trust now¶
I no longer trust "derive everything" as a slogan. It is too broad. The better rule is narrower:
Derive the recoverable part from current artifacts. Stamp only the irreducible judgment. Pressure-test the derivation on the artifacts it will govern before it routes anything important.
That last sentence is the part the failed dependency batch added. A derivation rule that cannot survive its own batch is not ready to become a gate. The 0/3 recall result and the about-30-percent stem-mention precision were not embarrassing side notes. They were the evidence that turned a slogan into an engineering rule.
For canonical docs, the next step is the doc dependency graph: not edit_tier: high, but a regenerated index that can show why a doc edit is load-bearing. For tickets, the next step is a direction-aware, context-scoped depends inference engine that proposes only the subset it can explain. Different surfaces, same rule.
Derive it when the project already contains the facts. Stamp it only when the project does not.
That is how a metadata system stays honest enough for agents to build on.
Or: subscribe to the newsletter for more posts on building this stuff.