Repository navigation
Closed
Labels
priority:P3Later emitters, M4 and up, 3.2-only, streaming, webhooks, rare constructsLater emitters, M4 and up, 3.2-only, streaming, webhooks, rare constructstype:featureNew capability or enhancementNew capability or enhancement
Description
Problem
architecture.md §2.2 designs five transform passes: link, dedup, filter, version-slice and overlay. emitter-design §2.4 has the engine run version-slice before any emitter. At c387e25c none of them can be written as designed.
- The registry rule refuses it. A pass that replaces or removes a type writes the type registry.
TestRegistryWrites_StayInsideTheFrameworkrefuses that outsidecompilers/compileandir. - The sanctioned writer is out of reach. That writer is
compile.Types, whichpass/may not import: archtest allows itironly. - There is no copy helper.
irhas no helper to copy aTypeDef, onlyir.NewTypeDef. A throwaway pass that trims whitespace fromDocs.Summaryneededreflectto rebuild each type. - The rule is easy to dodge. It is syntactic:
out.Types[id] = …is flagged, whilemaps.Cloneinto a local variable and a write through that variable is not.
The engine side is fixed as well:
- the pass list is
defaultPasses; engine.NewWithtakes compilers only, so an embedder cannot add a pass;- two tests pin the exact list (
engine/passes_test.go,cmd/morphic/validate_test.go); - the typed per-pass settings and the passes that cannot be disabled, both decided in §2.2, have no mechanism yet.
Direction
A proposal:
- An
ir-level copy-on-write editor. For example,ir.Edit(doc)returns a builder whoseReplaceType,RemoveTypeandDoneproduce a newDocumentsharing what was not touched, and keep invariant 3's one node per ID. iralready owns the registry, so the editor needs no new owner. The archtest rule then names the editor as the way in for passes.engine.NewWithaccepts passes for embedders, and the pinned-list tests read the list rather than repeating it.- The required-pass mechanism lands with the first pass that needs it.
Done when a filter pass that removes an unused type is written without reflect and without tripping the registry rule.
Out of scope
Any particular transform. Usage may not need a pass at all (#950).
Priority: P3, rule 3 (off the golden spec: no transform changes what it compiles to today; a later emitter needs version-slice and filter). A pass writing out.Types[id] → TestRegistryWrites_StayInsideTheFramework fails (morphic @c387e25c).
Metadata
Metadata
Assignees
Labels
priority:P3Later emitters, M4 and up, 3.2-only, streaming, webhooks, rare constructsLater emitters, M4 and up, 3.2-only, streaming, webhooks, rare constructstype:featureNew capability or enhancementNew capability or enhancement
Activity
OmarAlJarrah commentedon Oct 20, 2026
Once #1001 merges, the registry rule this issue describes moves out of
internal/archtest.TestRegistryWrites_StayInsideTheFrameworkbecomes the ruleguard ruleregistryWritesininternal/lintrules/rules.go. golangci-lint runs it, andmake lint-plantedholds it to planted findings.Two parts of the Problem change with it:
maps.Cloneof a registry;irimport;make, a conversion,delete,clear,maps.Copy/Insert/DeleteFunc;out.Types[id]now fails lint instead of the test, so the probe in the Priority line becomesmake lint-planted.For the Direction: the
ireditor sits in packageir, which the rule already exempts as an owner, so it needs no new exemption.chore(skills): cite the work a failure showed in, check by the probe