Skip to content

Write the spec for S06 Phase 5: architecture contracts and a generated module graph #73

Description

@lsimons

Phase 5 of S06's rollout plan is listed as "own spec". This issue is for writing that spec, not for the implementation. Use the /spec-extension skill; mise run new-doc-number spec gives the next free number.

What the phase is

Make the architecture documented in a form that cannot go stale. R14 calls this "the part that genuinely rots".

The trap R14 already identified

The obvious version of this phase — run a code-graph tool and commit the graph — is explicitly worth resisting. A committed AI-generated graph becomes a stale second source of truth the moment a module moves, and nothing fails when it is wrong. That is the same objection S06 raises against a manual last-reviewed field: a false claim of freshness is worse than silence.

The recommendation

import-linter (2.7 at time of R14's writing, on grimp 3.14+). You write architecture contracts — "mdd.ir must not import mdd.confluence", "commands may import converters, not the reverse" — and CI enforces them. R14's argument for it: a contracts file is an architecture document that is structurally incapable of lying, which is a stronger property than any prose page or generated diagram has. It builds a directed import graph via grimp, reports violations as full import chains, caches the graph between runs, and does not require defining the whole architecture up front, so it can start with two or three contracts.

The known complaint, from Roman Imankulov's write-up that R14 cites, is that the five built-in contract types sometimes force several contracts where one would be logical; custom contract classes are the escape hatch.

Pair the contracts with exactly one hand-written explanation page — how a sync flows end to end, and why the IR exists.

Questions the spec will need to answer

  • The starting contracts, named concretely. src/mdd/ is already reasonably layered, so this is a matter of writing down what is true rather than forcing a change — but any contract that fails on today's tree is a finding the spec should record rather than hide.
  • Whether the module graph is generated and published at all, or whether the contracts file plus the one prose page replace it entirely. R14 leans hard toward the latter; if a graph is published, the spec has to say what stops it lying.
  • Where the gate runs. S06's rule puts code-coupled checks in mise run ci, and import-linter is pure Python, so ci — but note S34 already deferred "architectural enforcement (tach, import-linter)" as out of scope on the grounds that "formalising boundaries is a separate decision". This spec is that decision, and should say so explicitly, resolving S34's deferral the way S37 resolved its open question 1.
  • Whether the prose page carries a freshness marker, given S06 rejected last-reviewed site-wide. R14 suggested one for this page specifically; that is a real tension and the spec should settle it rather than inherit both positions.
  • Grandfathering: whether existing violations get a baseline in the complexipy-snapshot.json style, or whether the initial contracts are simply narrow enough to pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions