Factored dependency pairs for review freshness
Type: kb/types/note.md · Status: seedling · Tags: kb-maintenance, observability
An accepted review is a build product and its inputs are prerequisites — make-like staleness detection. Review freshness realizes this for exactly two inputs per pair: note text and gate text. Type-conformance pairs (ADR 038) showed the cheap way to admit a new dependency: do not widen one pair's input set to N — factor each dependency into its own two-input pair where the dependency document is the gate side. This proposal holds the not-yet-adopted remainder of that direction.
Current state (as of 2026-07-04)
- Type-conformance pairs are shipped (ADR 038): the selector derives
(note, type_spec)pairs from note frontmatter, the type spec is the gate snapshot, and a type edit stales its cohort via the existinggate-changedreason. The pattern this proposal generalizes is therefore proven once, end to end, with no storage change. - Freshness compares two hashes per pair against
accepted_note_hash/accepted_gate_hash(ADR 032). The snapshot table is role-neutral — keyed by path and content hash — so any repo document can sit on the gate side. - Acknowledgement (
commonplace-ack-gate-review) re-pins the current note and gate snapshots while carrying forward completed review evidence. It is per-note: acking a cohort of N notes after one shared-gate edit takes N invocations (one per note, batching only across gates). - The selector emits JSON consumed by job creation; there is no cohort-scoped ack surface fed from selector output.
- No judgment has been identified that irreducibly reads three or more texts in one prompt; no N-ary input-set table exists.
- A fuller design for a general lineage model — lineage targets, append-only events, per-event input versions, typed resolvers — is in flight in the workshop layer at
kb/work/lineage-mechanisms/general-lineage-refresh-state-design.md(cited by path, not linked, per the no-workshop-links convention); factoring-into-pairs narrows how much of it review freshness will ever need.
The design: one pair per dependency edge
Each new review dependency becomes its own (note_path, dependency_path) pair with the dependency document as the gate:
COLLECTION.md-as-gate — a note's conformance to its collection's register and conventions. One pair per note, gate side the collection'sCOLLECTION.md.- Source-as-gate — a derived note's consistency with the source snapshot it distills. This is the multi-source invalidation case: one pair per
(note, source)edge, so each source invalidates independently with its own diff.
Each factored pair reuses the entire freshness/ack/warn stack unchanged, exactly as type-conformance pairs do. Like the type spec, neither COLLECTION.md nor a source snapshot is written as a Failure mode / Test procedure, so each needs a mechanical wrapper (or an authored review section in the dependency document, which the hash then sees).
The N-ary input-set design — acceptance pinning a variable set of (input_key, role, resolver, accepted_version) records — remains the fallback for a judgment that irreducibly reads three or more texts in one prompt. No such judgment is identified yet, which is exactly why the input-set table stays unbuilt.
Cohort-scoped ack
The force that factored pairs sharpen: cohort blast radius. A COLLECTION.md edit stales a whole collection; a type edit stales a whole type cohort — same shape as a wide gate edit. The answer is a cohort-scoped ack surface — an improvement to the existing ack command (by type, by gate, or fed from selector JSON) rather than new freshness semantics. The operator judges one gate-side diff and acknowledges the cohort in one decision instead of N per-note invocations.
Forces that keep this at planning
- Review cost. Every factored dependency adds a pair per note; the corpus-times-dependencies product is real. Type-conformance stayed opt-in for the same reason; factored pairs should expect the same discipline.
- No demand signal yet. No type edit has yet staled more pairs than per-note acking comfortably clears, and no note has needed source-consistency review badly enough to pay its pair cost.
Free choices
- Gate id scheme per dependency kind. Type pairs use a virtual
type/{name}lens;collection/{path}andsource/{name}lenses would keep the CLI uniform, but source snapshots may not have stable short names. - Wrapper prompt vs authored review section. Same trade as for type specs, and the freshness boundary weighs the same way: criteria in the dependency document are hashed, wrapper text is not.
- Cohort-ack input. By gate path, by type, or by piping selector JSON into the ack command; selector JSON is the most general and adds no new selection logic.
Adoption criteria
- Adopt cohort-scoped ack when the first real type or collection edit stales more pairs than per-note acking comfortably clears.
- Adopt
COLLECTION.md-as-gate or source-as-gate when a note's conformance to its collection, or consistency with a distilled source, is first wanted as a reviewable judgment — each is a gate source plus a wrapper, no storage change. - Adopt the N-ary input-set model only if a judgment appears that genuinely needs a third text in one prompt; the default answer to a new dependency is a new factored pair, not a wider input set.
Relevant Notes:
- link graph plus timestamps enables make-like staleness detection — rationale: the build-product/prerequisite model; factored two-input pairs are its cheapest review-side realization
- 038-type-conformance reviews use the type spec as the gate — rationale: the shipped first instance of the factoring pattern this proposal generalizes
- a derived copy of recomputable truth must be checked or absent — rationale: why each dependency document must be the gate rather than be restated in one
- review system — part-of: the freshness, acceptance, and ack concepts every factored pair reuses unchanged
- 032-review freshness uses DB snapshots, not Git — see-also: the role-neutral snapshot substrate that lets any repo document sit on the gate side