One canonical traversal per tree, not ad hoc recursion.
Canonical walkers (one traversal per tree)
Intent — Give each tree exactly one canonical walker that owns its traversal invariants, and route all traversal through it instead of ad hoc recursion, so those invariants live in one place (our instances: one walker for the PDF structure tree, one for the checking pass, one per Office part: PdfStructTreeWalker, the RuleWalkers, DocxTopLevelPartWalker).
| Summary | One canonical traversal per tree, not ad hoc recursion. |
| Target | Product · Canonical models & seams |
| Form | typed-ir |
| Move | package — a constraint shipped with its sensors |
| Model | is-a-model — a structured model you check a system property against |
| Enforcement | Hard (deterministic) · blocking — routed via the model ban-lints; raw recursion / regex-into-tree is banned alongside raw library access |
| Derivation | model-from-code — induced from the code, reconciled at build |
Its place in the environment — a variant / known-use of One Door Enforced, under CONSTRAIN · Constrain where and how agents act. Preserved here for its technical texture; the construction kit shows how it folds.
Motivation — the failure it kills
Ad hoc tree recursion re-implements traversal at every site, and each copy is subtly wrong in its own way. One misses a node type, another visits in the wrong order, a third forgets link annotations. The same traversal bug recurs per site, and because each is hand-rolled, a fix to one never reaches the others.
Why it's not just "recurse the tree where you need it"
Hand-rolled recursion duplicates the traversal logic, and duplicated logic drifts: the invariants (visit every node type, in the right order, resolving indirect references) get re-derived, badly, at each site. A canonical walker centralizes the traversal so those invariants are fixed once and inherited everywhere. N ad hoc recursions each re-introduce the same class of omission; one canonical walker cannot, because there is only one copy of the traversal to get right. A standard DRY-plus-walker-discipline move, it keeps the structured models usable without re-opening the raw-access door.
Mechanism
Each tree type has one canonical walker that owns its traversal shape: one for the PDF structure tree, one for the checking pass, one per Office part (our instances: PdfStructTreeWalker, the RuleWalkers, DocxTopLevelPartWalker). The canonical-walker discipline routes all traversal through them; regexing into the tree or hand-recursing is banned together with raw library access.
Prerequisites
- A walker per tree type, exposing the traversal shape callers actually need.
- A discipline (and lint coverage) that routes traversal through it, closing the raw-recursion and regex-into-tree escapes.
Consequences & costs
- The walker must expose what callers need. A missing traversal shape pushes a caller back to raw recursion; coverage matters here, same as the models.
- Low novelty. This is a well-understood pattern; its value is DRY + invariant-centralization, not invention.
Known uses
PdfStructTreeWalker, theRuleWalkers,DocxTopLevelPartWalker, and the other per-tree walkers.- The canonical-walker discipline (traversal routed through the walker, raw recursion banned).
Related mechanisms
- See also — pdf-model, office-models: walkers are how you traverse those structured models; they are part of the same typed-seam discipline.
- Enabler — a canonical walker makes routing traversal through the structured models practical; without it, callers reach for raw recursion and re-open the ban-lint's door.
Governed by
The mechanisms that hold this model true — inverted from their Governs edges at build time, never hand-written. A direct governor names this model; a trunk mechanism governs every model.
- Coverage → model-node mapping (which invariants are actually tested) — Project test coverage onto model nodes (states, seams, invariants) so untested ones are visible. governs every model
- Drift & parity gates — Bidirectional model↔reality checks so models cannot drift. governs every model
- Enforce at the right semantic level — Match a mechanism's enforcement scope to the semantic scope of the property it checks. governs every model
- Executable source-of-truth models — Structured models read every run and generated from; can't drift. governs every model
- Formal invariant verification (temporal form → model checking) — Each invariant's temporal-logic form derives its checker — proven, not sampled. governs every model
- Invariant-DAG execution policy (a typed Scheduler separates correctness from resource + cost) — A DAG holds correctness + cost-gate edges only; a typed Scheduler rations load + budget per host. governs every model
- Meta-model consumption discipline (read, don't hardcode) — Read the model at runtime; never hardcode a snapshot. governs every model
- Model query surface (`repo-query`) — repo-query — the agent-facing read API over the models. governs every model
- Model-derived test-obligation census (derive what should be tested, lint the gap) — Derive the should-be-tested set from the models and lint the gap to the tests that exist. governs every model
- Model-driven codegen — Generate real artifacts from the models, provenance-headed. governs every model
- Model-graded finding severity (distance-graded gate) — A gate grades each finding block/warn/silence by its model-distance from the changed files. governs every model
- Orphan-coverage metric (walk code → governance; score the un-covered remainder) — Walk code → governing model/control; score the orphans; each orphan cluster is candidate work. governs every model
- The agent-first MBSE harness — Structured frozen-record models + five hand-rolled disciplines; adopt the schema, skip the runtime. governs every model