Repository navigation
tracking: a simpler architecture and contributor path for ir, pass, engine and the CLI #976
Copy link
Copy link
Closed
26 / 2626 of 26 issues completedClosed
26 / 2626 of 26 issues completed
Copy link
Labels
priority:P2Rarer spec shapes, or an IR decision to settle before the emitterRarer spec shapes, or an IR decision to settle before the emittertype:choreRefactor or cleanup, no behavior changeRefactor or cleanup, no behavior change
Description
The goal and context come first, then the ordered plan. Each step is a sub-issue, and the blocked-by relations are set on the issues themselves.
End goal
A contributor can change one layer without learning the others, and the rules that matter fail a test rather than a review. Done means all of the following:
- each rule and fact has one home;
- the engine holds the run policy, and the CLI is a thin shell over it;
- passes can transform the IR;
- the IR version is asserted once, against its shape;
- the normative documents are layered like the code;
- the engine and CLI boundaries are bounded and cancellable.
Context
#919's report measured the layers at c387e25c. The package layering is already enforced: the import-graph tests, the method cap, and no accidental package coupling. The cost sits elsewhere:
- Duplicated work.
irverifymakes 17 whole-document walks, 14× the allocations of one traversal. - Version churn. A version bump touches a median of 146 files, 69% of them goldens changing one line.
- Docs layering. A third of
ir-design.mdis one compiler's lowering rules, much of it on one 18,902-byte line. - Run policy in the CLI. The CLI holds the run policy (fatality, rendering, writing), and
cmd/morphicis 3× the engine's size. - Passes cannot transform. Transform passes cannot replace types.
- Unchecked contracts. A second compiler's output duties are unchecked, and the harness runs only the OpenAPI compiler.
- Onboarding. The reading before a first change is about 5.4 hours, and 48% of the root guidance's rules are prose only.
The largest single simplification, owning OpenAPI schema resolution in the compiler, is #920's.
Plan
1. Contributor path
- docs: move the OpenAPI lowering rules out of ir-design into a lowering spec beside the compiler, one rule per entry #963: OpenAPI lowering rules move beside the compiler
- docs: add a contributor guide with recipes for adding a lowering rule, a pass and a compiler #965: recipes for a lowering rule, a pass and a compiler
- docs: restate invariant 9 as the goal it is, and say how the IR may change once an emitter reads it #972: invariant 9 restated as the goal it is
- ir: assert IRVersion once, against a pin of the encoded shape, instead of in every golden #964:
IRVersionasserted once, against the shape - docs: architecture and README drift from the implementation #64: the design documents' drift from the code (the full list is in its comments)
2. Layer contracts
- pass: give transform passes a sanctioned way to replace and remove types #966: transform passes can replace and remove types
- test: normalizing passes need an idempotence oracle #689: an idempotence oracle, once a transform pass exists (blocked by pass: give transform passes a sanctioned way to replace and remove types #966)
- compilers: a compiler's output duties are checked by convention, not by the contract #967: a compiler's output duties checked
- test: the harness and the conformance matrix assume the OpenAPI compiler #968: the harness and the matrix take any compiler
- harness: the validate pass never runs under the harness #682: the harness runs the passes too
- archtest: add the emitters layering rule before the first emitter package exists #973: the
emitterslayering rule before the first package - archtest: nothing stops a pipeline stage writing to stderr or logging #974: no stage writes to stderr or logs
- engine: a compiler or pass that breaks its contract either crashes Run's caller or passes through unnoticed #975: a contract break becomes a Go error, not a crash or a pass-through
- engine: multi-file specs — bounded load-and-bundle and a sources-based entry point #74, openapi: six hand-written panic barriers share one shape and no output bound #787: a sources-based entry point and one panic barrier
3. Cost and boundaries
- irverify: run every walking check from one traversal of the document #962:
irverifyin one traversal - ir: build WalkValues paths only when a visitor reads them #813: build walk paths only when a visitor reads them
- ir: IsSubtype walks the hierarchy afresh per call, so its callers go quadratic #850:
IsSubtype's quadratic, answered by ir: decide whether derived facts (usage, subtypes, flattened properties) live in one per-document index #950's index (blocked by ir: decide whether derived facts (usage, subtypes, flattened properties) live in one per-document index #950) - compilers/openapi: the load phase never checks the context, so a cancel waits for most of the compile #970: the load phase honours cancellation
- engine: the root spec and an overlay are read with no size bound and no way to cancel #969: bounded, cancellable reads of the root spec and overlay
- cli: an interrupt can leave the temporary file -o writes, and the CLI never cancels a run #971: an interrupted CLI leaves nothing behind
4. One home for a rule
- openapi: derive a node's name from its coordinate in one function, and diff it against the names the lowering gives #980: a node's name from one function, checked as an oracle
- openapi: name every node from one function of the document and the coordinate, and remove the provisional-name machinery #981: name every node from it and remove the provisional-name machinery (blocked by openapi: derive a node's name from its coordinate in one function, and diff it against the names the lowering gives #980)
- openapi: the $dynamicAnchor memo is a parameter of 72 functions and is read by two #982: the
$dynamicAnchormemo off a 72-function parameter list (only together with openapi: name every node from one function of the document and the coordinate, and remove the provisional-name machinery #981) - openapi: Scope.DeclaredAt, Scope.ModelAt and loops.into are called only from tests #983: methods called only from tests
- ir: the rule for which struct fields declare an ID is written in ir and again in irverify, and no test runs both #984: the declared-ID rule in one place
Priority: P2, the tier of its highest open step (#970).
Metadata
Metadata
Assignees
Labels
priority:P2Rarer spec shapes, or an IR decision to settle before the emitterRarer spec shapes, or an IR decision to settle before the emittertype:choreRefactor or cleanup, no behavior changeRefactor or cleanup, no behavior change
Activity