Skip to content

docs: architecture and README drift from the implementation #64

Closed

Description

@OmarAlJarrah

Problem

Several places where the design docs and README no longer match the code they specify — each small, but these documents are declared normative, so drift is costly:

  1. Package layouts omit four real packages. docs/architecture.md §3 and README's layout table list only ir/ (+irtest), compilers/*, pass/, emitters/*, engine/, cmd/morphic/. Missing: cmd/morphic-harness/, internal/harness/, internal/archtest/, ir/irverify/. The code is well-placed (the archtest comment explains why internal/harness sits outside the layering) — the docs are what's stale. README's table also says cmd/morphic imports "engine", but it imports ir too.
  2. §2.1 still shows the pre-rename contract. architecture.md §2.1 shows Parse(ctx, sources, Options); the method is Compile since the frontend→compiler rename (refactor(compilers)!: rename frontend→compiler and backend→emitter #5). engine/engine.go also retains front/fronts identifiers and an "engine: parse %q" error prefix — worth renaming while touching it.
  3. emitter-design.md §2.1 contradicts the implemented registry philosophy. It prescribes a registry "populated by each target's init() — mirroring the compiler registry", but the actual compiler registry explicitly forbids init-time self-registration (compilers/compilers.go:46-47) and CLAUDE.md bans mutable globals. If uncorrected, Milestone 3 gets built against the wrong pattern citing "mirroring" as authority.
  4. architecture.md §3 lists a future compilers/swagger/ directory whose job ("2.0 lift → openapi compiler") would require the sibling import the layering rules forbid — while Milestone 2's text says the lift lives inside the OpenAPI compiler. Drop the directory from the layout.
  5. README documents one diagnostic format; the CLI prints three (path#pointer, bare IR ID, bare line:col). Document the fallback forms.

Proposed direction

One docs PR covering all five, plus the engine identifier rename if desired.

Acceptance

  • Layout listings match find . -type d; the compiler contract shown matches compilers.Compiler; emitter-design's registration section matches the engine-composed pattern; README's diagnostic-format section matches actual output.

Activity

  1. OmarAlJarrah commented on Aug 2, 2026

    @OmarAlJarrah
    MemberAuthor

    Items 1 and 4 are resolved by #227.

    Item 4 — compilers/swagger/ is dropped from architecture.md §3, with a line saying why there is no such directory: the lift normalizes to the OpenAPI 3.x shape and lives inside that compiler, so a sibling package calling into compilers/openapi is the one import the layering rules in that same section forbid.

    Item 1 — both layout listings now match the tree. architecture.md §3 was rewritten for the compiler split and includes cmd/morphic-harness/, internal/harness/, internal/archtest/, internal/testspec/ and ir/irverify/; README's table gains the same, and its cmd/morphic row says engine + ir rather than engine alone. Both now point at internal/archtest's rules map as the source of truth and give the command that derives the layout, so the next drift is a failing test rather than a stale table.

    Still open here: item 2 (§2.1 shows Parse where the method is Compile; engine retains front/fronts identifiers and an "engine: parse %q" prefix), item 3 (emitter-design.md §2.1 prescribes an init()-populated registry, which the compiler registry explicitly forbids), and item 5 (README documents one diagnostic format; the CLI prints three).

  2. added
    priority:P2Rarer spec shapes, or an IR decision to settle before the emitter
    on Oct 19, 2026
  3. OmarAlJarrah commented on Oct 19, 2026

    @OmarAlJarrah
    MemberAuthor

    More drift between the design documents and the code at c387e25c. Each row was checked against the type-checked ir package, the engine's pass list, or a compile.

    Document says Code has
    emitter-design §1.1: the engine runs link · dedup · filter · version-slice · overlay · validate; §2.4: "the engine runs version-slice before any emitter" one pass, validate (engine/passes.go); architecture.md §2.2 lists the rest as designed, not built
    emitter-design §3.2: TypePlan.Alias, "dedup alias target" no dedup pass and no alias record on Document
    emitter-design §3.4: ParamBind.Param string // Operation.Params name HTTPParamBinding.Param is a ParamID
    emitter-design §3.4: BodyPath *ir.PropPath request side HTTPParamBinding.BodyPath []PropID; response side HTTPBinding.ResponseBodyPath *PropPath
    emitter-design §3.4: Where is path | query | header | cookie | body | body_property | host also querystring
    emitter-design §3.3: readOnly → Only:[read] [read, delete, query], as ir-design §5.2 says and the compiler emits
    emitter-design §3.3: PatchImplicitOptionality == false a *bool, nil meaning the protocol default
    emitter-design §4.12: Case(words []string, …) over "Naming.Canonical word sequence" Canonical is one lower_snake string; the split is implied, not stated
    emitter-design §3.2: usage bits Input|Output|Error|Multipart|Json|Xml four bits, no Json or Xml
    emitter-design §2: "Package emitter"; §7: emitters/contract.go the contract package has two names
    ir-design §7.3: StreamingMode is none | client | server | bidi the compiler writes "" for every non-streaming operation, never "none", in all 1,521 compiled corpus documents that have operations (#978)
    ir-design §3.1: a format's ID path is its own coordinate (a protobuf name) irverify requires RFC 6901 syntax for Provenance.Pointer: /acme.v1.UserId passes, acme.v1.UserId is ir/provenance-pointer-malformed; the doc could say "one pointer segment"
    ir-design line 51: "a generated switch-completeness test" nothing is generated; the test iterates a hand-written list
    architecture.md §2.2: "every operation parameter is bound exactly once per binding" a parameter with no binding is a warning, and host labels are additive (pass/validate.go)
    compilers/openapi/internal/schema/compose.go:533: "A two-variant {X, null} set collapses" any number of null branches beside one non-null branch collapse; oneOf: [X, {type: "null"}, {type: "null"}] lowers to a nullable X

    Item 3 of this issue (emitter-design §2.1's registry "populated by each target's init()") still stands at c387e25c, lines 180–184.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority:P2Rarer spec shapes, or an IR decision to settle before the emittertype:docsDocumentation only

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions