Skip to content

[adopter] The markdown layer has no compiler: governance artifacts drift from the tree because nothing mechanically rejects them #419

Description

@montfort

Adopter: Sentinel (adoption discussion)
Finding type: Pattern candidate — recurring anti-pattern or discipline worth documenting
Charter reference: CHARTER-61 (Sentinel), external audit rounds 1–2
N-context: Recurrence within one adopter: a defect class documented as prose in audit round 1 was found again, in a new form, in round 2. Rhymes with #304 (mocks encode the assumed contract) and #306 (verification fidelity).

Summary

A two-round external audit of a Sentinel Charter (multi-model auditors, evidence-cited reports) produced a diagnosis that generalizes: the code has mechanical verifiers; the governance markdown does not. Compilation, vet, tests, SAST and DI wiring all reject bad code before it lands. AILOGs, the follow-ups registry, Charters and commit messages are only checked by prose checklists that an agent must remember to run. The residual defects clustered exactly in the unguarded seams — never in the code's logic, always in the artifacts that claim to verify or describe it.

Evidence (three cases from the same audit round)

1. A phantom AILOG reference in a commit message. A remediation commit cites AILOG-2026-08-12-002. The format is right, the date is plausible, the sequence number is plausible — and the file does not exist in the tree. Nothing in the toolchain resolves id-shaped references, so a confabulated citation lands silently. This failure mode is agent-specific in kind: a human forgets to write a document; an agent invents its exact identifier with full confidence.

2. Follow-ups that contradict the tree. Two open follow-ups (FU-377, FU-379) assert that a background job "has no production caller" — while the application entrypoint wires it. The registry tracks what AILOGs say, not what the code does, and nothing re-derives the claim. The drift is invisible until a human happens to cross-check.

3. A root-cause lesson that stayed prose, and recurred. Round 1 of the audit named a root cause: test doubles encode what the domain assumes, not what the real component does — producing guards that cannot fail. It was written into an AILOG and into the round-2 audit prompt itself. Round 2 found the same class in a new form: an integration test embedding a hand-copied copy of the SQL that the query layer generates, so the test stays green even if the generated query changes. The lesson existed; the gate did not.

The adopter's own doctrine already states the principle — a rule you must remember has the same defect as the bug it watches — and its hard guards (a blocking PR-voice hook, an agent-rules sync check, a merge driver for the follow-ups registry) are all reactive, each born from one measured failure. Guard coverage grows by accident.

Why this is upstream-shaped

The framework owns the id namespaces (AILOG-, FU-, CHARTER-*), so referential integrity over them can only be enforced generically by the framework. And the CLI already has every surface the remediation needs:

  • straymark validate --include-charters already performs referential integrity — scoped to Charter frontmatter (originating_ailogs must exist). The concept exists; its scope is narrow.
  • straymark validate --staged is already designed for hook integration.
  • straymark analyze declared-vs-wired already proves the right architecture: engine upstream, rules as adopter config.
  • straymark followups owns the registry artifact whose claims drifted in case 2.

Proposed upstream changes (three, ordered by value/effort)

P1 — Generalized reference resolution: "name resolution" for the markdown layer. Extend validate's referential integrity beyond Charter frontmatter: AILOG related: fields must resolve; id-shaped tokens cited anywhere in .straymark/ must resolve; and a new mode along the lines of validate --commit-msg <file> should extract id-shaped tokens from a commit message and fail when any does not resolve — designed for commit-msg hooks the way --staged is designed for pre-commit. The id formats are framework-owned and unambiguous, so precision is total and the check can be blocking from day one. This eliminates the phantom-reference class (evidence case 1).

P2 — A guard-closure field in remediation AILOGs. When an AILOG records the remediation of audit findings, each identified root cause must close with either a named, executable gate (guard:) or an explicit, measured justification for not gating it (unguardable:) — modeled on the existing escape-hatch conventions that require a non-generic rationale. This converts "lesson as prose" into "lesson as gate, or documented exception" (evidence case 3). The audit-review skill could require the field when consolidating remediation rounds.

P3 — followups verify. A mode that re-derives code claims embedded in open follow-ups. Language-agnostic form: a follow-up that asserts something about a symbol or path names it in backticks; verify greps the tree and flags entries whose claim no longer holds — a referenced path gone, or a "no caller" claim that now has a caller. This would have flagged case 2 without knowing anything about the adopter's language. Warn-first, since claim phrasing is semi-structured; the backtick convention makes it precise over time.

What stays adopter-side

Project-semantics checks — e.g. "integration tests must execute the generated query rather than a hand-copied copy" — remain adopter guards or declared-vs-wired profiles. The division principle is the one declared-vs-wired already implements: engine upstream, rules as config downstream.

Design constraints for any implementation

  1. High-precision checks block; heuristic checks warn — follow the declared-vs-wired precedent of warning mode first, blocking flip later.
  2. All checks must live in the grep/parse tier — no build, no test execution — or the hook that hosts them becomes too slow to tolerate.
  3. Every new gate should declare the defect class it covers, so guard coverage grows deliberately rather than by accident.

Relation to existing issues


Filed from real adopter experience (Sentinel, CHARTER-61 external audit rounds 1–2, multi-model auditors). The load-bearing lesson: an agent converges to whatever a machine checks — artifacts without a mechanical verifier drift, no matter how disciplined the prose around them.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions