Skip to content

feat(codegen-ts): make shared-model, docs and api-docs ejectable; remove mermaid-er - #431

Merged
dmealing merged 4 commits into
mainfrom
fm/mo-1-1-0-ejectable-rest
Oct 11, 2026
Merged

dmealing merged 4 commits into
mainfrom
fm/mo-1-1-0-ejectable-rest

Conversation

@dmealing

@dmealing dmealing commented Oct 11, 2026 •

Copy link
Copy Markdown
Member

What Changed

  • shared-model, docs and api-docs can now be ejected with meta eject. The owned copies of docs and api-docs are listed in a new docs: { generators: [...] } key in metaobjects.config.ts and run by meta docs / meta verify --docs in place of the packaged generator. buildSharedModel and renderSharedModelFiles are exported from @metaobjectsdev/codegen-ts so an ejected shared-model copy keeps the same publish and verify behavior. template stays package-only.
  • The standalone mermaid-er generator is removed (mermaidErDiagram, MermaidErOptions, the "mermaid-er" name, and its registry and manifest entries). meta docs still draws the same Mermaid diagrams on the overview and entity pages. A config that still wires it fails with a removal message.
  • meta docs now stops with exit 2 on a metaobjects.config.ts that fails to load, instead of warning and writing model pages. ctx.inputRoot is added so generators can read the project's own files. meta verify --codegen now passes shared-model the project source files it needs.
  • Changelog, ADR-0022 and ADR-0034 (Amendment 7), docs, and agent-context skill references are updated to match.

Runs: 2. Run 1 passed after two review fix rounds (seven findings fixed). Run 2 re-validated the branch after main was merged in to resolve a CHANGELOG.md conflict, with no findings.

Validation

Risk Assessment

⚠️ Medium: No defects found, but the change is broad: it removes a public export (mermaidErDiagram / "mermaid-er"), makes meta docs fatal on a config that fails to load, and adds a new docs.generators seam; all three are intent- or decision-authorized, documented in the CHANGELOG and covered by end-to-end tests through the built CLI.

Testing

Drove the real TS meta CLI against a disposable project. Ejection of shared-model, docs and api-docs works. mermaid-er is removed and rejected as unknown. Docs still emits Mermaid diagrams. Owned docs copy runs when wired. A config that exists but fails to load is fatal with nothing written. An owned generator error is shown plainly. A commented-out import does not break config load. Regression suites: cli 1581 pass, codegen-ts 2633 pass, zero failures. Scratch project removed; worktree clean.

  • Live validation: ✅ go - 9 of 10 scenarios driven live against the product
Scenario Result Live Evidence
Eject shared-model, docs and api-docs into codegen/generators and own them ✅ pass live meta eject shared-model docs api-docs (exit 0) wrote codegen/generators/{shared-model,docs,api-docs}.ts
mermaid-er is removed: eject rejects it and it is not in the ejectable list ✅ pass live meta eject mermaid-er -> 'unknown name(s): mermaid-er', exit 2; eject --list shows no mermaid-er
meta docs still draws Mermaid ER diagrams in generated overview ✅ pass live docs/generated/README.md contains ```mermaid erDiagram block
Owned docs copy, when wired into config, is the generator that runs ✅ pass live marker printed to stderr from codegen/generators/docs.ts during meta docs
Adversarial: owned docs throws ENOENT -> plain error, no misleading template advice ✅ pass live meta docs -> 'meta: ENOENT: no such file or directory, open VERSION', exit 2
Adversarial: existing config that fails to load is fatal and writes nothing ✅ pass live broken config -> exit 2, ParseError shown, docs/generated absent
Missing config keeps today's behaviour (warn, still writes docs, exit 0) ✅ pass live meta docs in dir without config -> 'agent surface skipped' note, docs written, exit 0
Commented-out import of removed generator does not fail config load ✅ pass live config with // import mermaidErDiagram -> meta gen --list exit 0
eject --format json row has wire.into and no duplicate door field ✅ pass live meta eject docs --format json -> wire.into: docs.generators, no door key
Ejected shared-model/docs compile and run through meta gen with installed packages ⏸️ untested no Ejected copies import @metaobjectsdev/codegen-ts, which needs npm install from the registry; no network install done in the disposable project, so the emit-through-gen path was not driven live. Covere…

Pipeline

Updates from git push no-mistakes

✅ **Intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - medium risk

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 9 of 10 scenarios driven live against the product
Scenario Result Live Evidence
Eject shared-model, docs and api-docs into codegen/generators and own them ✅ pass live meta eject shared-model docs api-docs (exit 0) wrote codegen/generators/{shared-model,docs,api-docs}.ts
mermaid-er is removed: eject rejects it and it is not in the ejectable list ✅ pass live meta eject mermaid-er -> 'unknown name(s): mermaid-er', exit 2; eject --list shows no mermaid-er
meta docs still draws Mermaid ER diagrams in generated overview ✅ pass live docs/generated/README.md contains ```mermaid erDiagram block
Owned docs copy, when wired into config, is the generator that runs ✅ pass live marker printed to stderr from codegen/generators/docs.ts during meta docs
Adversarial: owned docs throws ENOENT -> plain error, no misleading template advice ✅ pass live meta docs -> 'meta: ENOENT: no such file or directory, open VERSION', exit 2
Adversarial: existing config that fails to load is fatal and writes nothing ✅ pass live broken config -> exit 2, ParseError shown, docs/generated absent
Missing config keeps today's behaviour (warn, still writes docs, exit 0) ✅ pass live meta docs in dir without config -> 'agent surface skipped' note, docs written, exit 0
Commented-out import of removed generator does not fail config load ✅ pass live config with // import mermaidErDiagram -> meta gen --list exit 0
eject --format json row has wire.into and no duplicate door field ✅ pass live meta eject docs --format json -> wire.into: docs.generators, no door key
Ejected shared-model/docs compile and run through meta gen with installed packages ⏸️ untested no Ejected copies import @metaobjectsdev/codegen-ts, which needs npm install from the registry; no network install done in the disposable project, so the emit-through-gen path was not driven live. Covere…
  • scripts/ci-local.sh --only ts-fast --only ts-unit --strict-toolchains
  • bun server/typescript/packages/cli/bin/meta.ts init (disposable project in /tmp, then removed)
  • meta gen --list / meta eject --list --format json|text: shared-model, docs, api-docs listed ejectable; mermaid-er absent
  • meta eject mermaid-er -> exit 2, 'unknown name(s)', ejectable list excludes it
  • meta eject shared-model docs api-docs -> codegen/generators/*.ts written, exit 0
  • meta eject docs --format json -> wire.into present, no door field
  • meta docs with owned docs wired into generators (marker run) -> owned copy executes
  • meta docs with owned docs throwing ENOENT -> 'meta: ENOENT: ...' exit 2, no template-layout advice
  • meta docs with metaobjects.config.ts syntax error -> exit 2, ParseError shown, docs/generated not written
  • config with commented-out mermaidErDiagram import -> gen --list exit 0
  • meta docs with no metaobjects.config.ts -> agent surface skipped note, exit 0
  • meta docs generates Mermaid erDiagram block in docs/generated/README.md
  • bun test in server/typescript/packages/cli (1581 pass, 0 fail, 3 skip)
  • bun test in server/typescript/packages/codegen-ts (2633 pass, 0 fail)
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

…; the standalone mermaid-er generator is removed

Every stock TypeScript generator can now be ejected except `template`, the
Mustache primitive, which has no emit logic of its own to own. ADR-0034
Amendment 7 records the rulings and the reasoning.

shared-model: the artifact a consumer's `meta deps sync` verifies stays in the
package. `buildSharedModel` (load, select, closure check, serialize,
core-vocabulary re-load) and `renderSharedModelFiles` (file names, hash,
manifest) are public; the reference template calls both and owns which source
files may contribute and where the published version comes from.

docs and api-docs: `meta docs` gained a seam. An owned copy is listed in the
docs door's own config, `docs: { generators: [...] }`, and carries a
`docsSurface` marker saying which surface it takes over. `meta docs` runs it in
place of the packaged generator and `meta verify --docs` checks against it. The
facts the door used to pass as factory options ride on `ctx.docsDoor`. A docs
generator placed in the top-level `generators` is skipped by `meta gen` with a
warning that names `docs.generators`; an entry with no marker, or two for one
surface, is refused by name. `meta eject docs` prints the docs block wiring and
never the array `meta gen` runs. `buildApiModelForRun(ctx)` gathers the run
facts the API model reads, so an owned copy picks up a new one on upgrade.

mermaid-er: removed, by maintainer ruling. The standalone generator was the
older home of a diagram `meta docs` still draws. `mermaidErDiagram()`, its
`/generators` export, its registry row and the cross-port manifest row are
gone; the diagrams `meta docs` writes are unchanged byte for byte. A config
that still names `"mermaid-er"` or imports `mermaidErDiagram` fails with a
message saying it was removed and that `meta docs` draws the diagram, whether
the import is in the config or in a module the config imports. ADR-0022 Part 2
D1 is amended to match.

The signals `meta gen`, `meta gen --list` and `meta verify` give about a doc
generator under `generators` cover an owned copy too, and tell its owner to
move it to the docs block where a packaged generator is removed: `runGen`
reports it in `skippedDocGenerators` and names it in the new
`skippedOwnedDocGenerators`, the next step and the `doc-generator-in-gen`
advisory say "move", and a copy listed in the docs block marks its catalog row
as wired there. The catalog withholds a `generators` import line by the
`docsSurface` marker, not by layer. `meta verify` reports the removed name
`"mermaid-er"` as refused, with the message `meta gen` fails with.

Fixed while proving the drift check: `meta verify --codegen` passed generators
neither the project's source files nor a way to read the project, so it failed
with "no source files to load" for any project wiring `sharedModelFile()`.
`runGen` takes `inputRoot` and generators read the project through
`ctx.inputRoot`; `ctx.projectRoot` keeps its meaning.

Packaged output is unchanged and gated to be: the byte-identity gate holds each
new reference to the packaged generator, and holds the packaged docs generators
to the same bytes under the door as from the same facts passed as options.
Brings in #429 and #430. One conflict, in CHANGELOG.md: both sides appended
entries to the end of the [1.1.0] Fixed list, and both are kept.
@dmealing
dmealing merged commit 0f8a14b into main Oct 11, 2026
1 check passed
@dmealing
dmealing deleted the fm/mo-1-1-0-ejectable-rest branch October 11, 2026 22:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant