Skip to content

feat(codegen-ts): make stock entity, queries and barrel generators importable again - #427

Merged
dmealing merged 10 commits into
mainfrom
fm/mo-1-1-0-stock-generators-importable
Oct 11, 2026
Merged

dmealing merged 10 commits into
mainfrom
fm/mo-1-1-0-stock-generators-importable

Conversation

@dmealing

@dmealing dmealing commented Oct 11, 2026 •

Copy link
Copy Markdown
Member

What Changed

  • Import restored (TypeScript). entityFile, queriesFile, routesFile and barrel are exported from @metaobjectsdev/codegen-ts/generators again. 1.0 removed them so that an owned copy was the only way to run them. The rule is now: import a stock generator to run it as shipped, and meta eject it to change what it emits. Both paths are supported and tested. The config loader's diagnostics for the removed imports are deleted.
  • Nothing changes for a project that owns its copies. They run as before, and meta eject --list and meta verify --codegen behave as before. meta init still wires nothing; only its scaffolded comment and next steps changed.
  • The catalog says how to import. meta gen --list prints the import line that runs each generator as shipped (wire.import on the JSON row). Registry entries carry factoryExport, gated against each package's real exports and against the symbol each reference template exports, so moving between the two paths is one import line.
  • Two more generators can be ejected. callable and trace-helper gained reference templates, thin generators over renderCallableFile and renderTraceHelper.
  • Docs. ADR-0034 Amendment 5, own-your-codegen (the import-or-own table and the steps for replacing an unmodified owned copy with the import), the CLI and codegen-ts READMEs, the codegen, audit and prompts skills and the always-on agent context with regenerated goldens, and CHANGELOG entries under 1.1.0.

Why restoring the import is safe

1.0 removed the import (ADR-0034 Decision 3) so that an adopter would not have to fork the package to customize. meta eject now copies any reference at any time, so that exit is one command away whichever path a project starts on. An imported generator is still a reference helper: its output can change in a MINOR, and meta verify --codegen reports the difference until the project regenerates.

"Everything ejectable" audit

State after this PR, rebased on main. Every port's generators run as shipped, selected by name or import.

Port Not ejectable
TypeScript template (permanent: it is the Mustache primitive and has no emit logic of its own). shared-model, docs, api-docs and mermaid-er are not yet ejectable; a sibling change covers them.
C# template
Java template (entity and extractor became ejectable in #425)
Kotlin none
Python template

TypeScript gaps closed here: entity, queries, routes and barrel are importable, and callable and trace-helper are ejectable. Gaps outside TypeScript were reported and are not fixed in this PR.

CI evidence

The gate's hosted CI step is skipped for this repository (CI is local), so the evidence is the local run:

  • scripts/ci-local.sh --quick passed on the feature commit: 36 steps covering the hygiene and drift gates, ts build and typecheck, TypeScript conformance, the ts unit suites and the mutation gate.
  • The pipeline's test and lint steps ran the same script in its two halves (--only ts-fast --only ts-unit, and --only gates) on the rebased head, and both passed.
  • Not run: the C#, Java, Kotlin and Python conformance lanes, the Java reactor and the Docker integration suite. No file under those ports changed in this PR.

Validation runs

Two. Run 1 completed review after six fix rounds, which applied the maintainer's two rulings (template is the one permanent exception; the catalog prints the import line only, with no derived call) and corrected the guidance on dropping an unmodified owned copy. It then failed in the test step: the configured test command passed, but the pipeline's evidence agent timed out and its failover failed. Run 2 rebased onto main (one conflict in ADR-0034, resolved by keeping both amendments), passed review with no findings, and passed.

Validation

Risk Assessment

✅ Low: The change restores four exports, adds two reference templates that are byte-gated against the built-ins, and removes a loader diagnostic that no longer applies; the trace-helper split is a line-for-line move, the documentation and skill wording matches the CLI source, and the remaining package-only generators follow the user's recorded decision.

Testing

Baseline ts-fast/ts-unit already green. Drove the built CLI live: importing the four stock generators from the package generates 10 files and passes verify --codegen. The integration test also covers owned-copy-equals-import output and the default-eject adapter-line delta, both through the built CLI. codegen-ts and cli suites pass. Repo-wide suite not run here. Disposable project cleaned up. Result: pass.

  • Live validation: ✅ go - 4 of 5 scenarios driven live against the product
Scenario Result Live Evidence
Adopter imports entityFile/queriesFile/routesFile/barrel from @metaobjectsdev/codegen-ts/generators and meta gen writes the per-entity files and index ✅ pass live Manual CLI run in disposable project: gen exit 0, 10 files written; integration test case 1
meta verify --codegen is clean on output produced by package-imported stock generators ✅ pass live verify --codegen exit 0; stock-generators-importable.test.ts case 1
Owned copy of the stock generators, bound back to the package HTTP-adapter runtime, emits byte-identical output to the import (and the reverse drop is a no-op) ✅ pass live stock-generators-importable.test.ts case 2 (subprocess built CLI)
A default meta eject of the stock generators changes only the HTTP-adapter import lines ✅ pass live stock-generators-importable.test.ts case 3 (subprocess built CLI)
Adversarial: adopter on a 1.0.x install importing the four from the package is refused as a blocker (migration boundary) ⏸️ untested no Would require installing a 1.0.x package alongside this build in the workspace; not driven. Not needed for the 1.1.0 import path the intent asks for.
  • Outcome: ⚠️ 1 info across 1 run (10m32s)

Pipeline

Updates from git push no-mistakes

✅ **Intent** - passed

✅ No issues found.

🔧 **Rebase** - 1 issue found → auto-fixed ✅
  • ⚠️ spec/decisions/ADR-0034-codegen-scaffold-and-own.md - merge conflict rebasing onto origin/main

🔧 Fix applied.
✅ Re-checked - no issues remain.

✅ **Review** - passed

✅ No issues found.

⚠️ **Test** - 1 info
  • ℹ️ Full server/typescript regression suite not run in this step. Ran codegen-ts (2557 pass) and cli (1470 pass, 3 skip) package suites, all green. Repo-wide conventional run exceeds the time budget here; the baseline ts-fast/ts-unit lane covers the rest.
  • Live validation: ✅ go - 4 of 5 scenarios driven live against the product
Scenario Result Live Evidence
Adopter imports entityFile/queriesFile/routesFile/barrel from @metaobjectsdev/codegen-ts/generators and meta gen writes the per-entity files and index ✅ pass live Manual CLI run in disposable project: gen exit 0, 10 files written; integration test case 1
meta verify --codegen is clean on output produced by package-imported stock generators ✅ pass live verify --codegen exit 0; stock-generators-importable.test.ts case 1
Owned copy of the stock generators, bound back to the package HTTP-adapter runtime, emits byte-identical output to the import (and the reverse drop is a no-op) ✅ pass live stock-generators-importable.test.ts case 2 (subprocess built CLI)
A default meta eject of the stock generators changes only the HTTP-adapter import lines ✅ pass live stock-generators-importable.test.ts case 3 (subprocess built CLI)
Adversarial: adopter on a 1.0.x install importing the four from the package is refused as a blocker (migration boundary) ⏸️ untested no Would require installing a 1.0.x package alongside this build in the workspace; not driven. Not needed for the 1.1.0 import path the intent asks for.
  • scripts/ci-local.sh --only ts-fast --only ts-unit --strict-toolchains
  • bun test test/integration/stock-generators-importable.test.ts (cli package, built CLI, 3 pass)
  • Manual live run: disposable adopter project under the worktree test fixtures, config imports entityFile/queriesFile/routesFile/barrel from @metaobjectsdev/codegen-ts/generators; bun packages/cli/bin/meta.ts gen exit 0, wrote 10 files (User/Post/Tag .ts, .queries.ts, .routes.ts, index.ts)
  • Manual live run: meta verify --codegen exit 0 on the generated output
  • bun test in packages/codegen-ts (2557 pass, 0 fail)
  • bun test in packages/cli (1470 pass, 3 skip, 0 fail)
  • Removed the disposable fixture directory after the run
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

…the way to customize

1.0 removed entityFile / queriesFile / routesFile / barrel from
@metaobjectsdev/codegen-ts/generators so that an owned copy was the only way to
run them. An assessment of an adopter found its owned copies were almost pure
duplication of the reference and had already fallen behind it. The rule is now
"import a stock generator to run it as shipped, eject it to change what it
emits" (ADR-0034 Amendment 5). Both paths are supported and tested.

TypeScript
- The four factories are exported from the /generators subpath again. The
  config loader's two diagnostics for the removed imports are deleted with the
  removal.
- meta gen --list prints the import line that runs each generator as shipped
  (wire.import / wire.entry on the JSON row). Registry entries carry
  factoryExport, gated against each package's real exports and against the
  symbol the reference template exports, so moving between the two paths is
  one import line.
- callable and trace-helper gain reference templates and can be ejected. The
  trace-helper module body moves to templates/trace-helper.ts so the built-in
  and the reference call one composer; output is byte-identical.
- meta init still wires nothing. Its scaffolded comment and next steps show
  the import first and eject as the way to change output.

Why the removal's problem stays solved: ADR-0034 Decision 3 removed the import
so an adopter would not have to fork the package to customize. meta eject,
which did not exist then, now copies any reference at any time, so the exit is
one command away whichever path a project starts on.

Existing adopters: owned copies run unchanged, and meta eject --list and
meta verify --codegen behave as before. Replacing an unmodified owned copy
with the import is documented in own-your-codegen, with the diff to expect:
entity and routes move their HTTP-adapter import back to the runtime package,
queries and barrel regenerate nothing.

"Everything ejectable" audit, after this change
- TypeScript: every generator is importable. Not ejectable, each for a stated
  reason: template (the Mustache primitive, same ruling as the other ports),
  shared-model (emits a hash-pinned contract artifact), and docs / api-docs /
  mermaid-er (the engine behind meta docs, which has no seam for an owned
  copy).
- C#: all ejectable except template.
- Java: all ejectable except entity, extractor and template.
- Kotlin: all ejectable.
- Python: all ejectable except template.
- Every port's generators run as shipped, selected by name.
Gaps outside TypeScript are reported here, not fixed.

Docs: ADR-0034 Amendment 5, own-your-codegen (the import-or-own table and the
migration note), codegen-concepts, the 0.x-to-1.0 guide, the CLI and
codegen-ts READMEs, the codegen / audit / prompts skills and the always-on
agent context (with regenerated conformance goldens), and the CHANGELOG.
…ange

- One CORE_CODEGEN_PACKAGE definition in the CLI; each catalog slice declares
  the module it serves factories from, so factoryModuleOf is a lookup.
- trace-helper uses the shared toPascalCase instead of a local copy (same
  body, output unchanged).
- The package-only footer names meta docs as the docs layer's door.
- A gate asserts the package wiring and the eject wiring print the same call
  for every ejectable generator.
- Header comments corrected where they contradicted the change.

Verification: scripts/ci-local.sh --quick passed locally on the feature commit
(36 steps: hygiene and drift gates, ts build + typecheck, TypeScript
conformance, ts unit suites). The codegen-ts and cli suites were rerun after
this pass and are green. The hosted ci step is skipped for this run, so that
local run is the CI evidence. The C#, Java, Kotlin and Python lanes were not
run; no file under those ports changed.
… docs

Assisted-by: no-mistakes:claude:claude-opus-5-5
…t in skills

Assisted-by: no-mistakes:claude:claude-opus-5-5
…dapter check

Assisted-by: no-mistakes:claude:claude-opus-5-5
… listings

Assisted-by: no-mistakes:claude:claude-opus-5-5
…mport-first sweep

Assisted-by: no-mistakes:claude:claude-opus-5-5
…in owning-generators skill

Assisted-by: no-mistakes:claude:claude-opus-5-5
1.1.0 has not shipped: the latest public release is 1.0.13, and the dated
[1.1.0] heading is the prepared release, not a published one. The entries this
branch added under [Unreleased] describe work that ships in 1.1.0, and the
docs, skills and ADR all say "restored in 1.1", so they belong in that
section. The Added entries go to the top of 1.1.0's Added list and the Changed
entries to its plain Changed list. [Unreleased] keeps the two fixes that were
there before this branch.
@dmealing
dmealing merged commit bf81509 into main Oct 11, 2026
1 check passed
@dmealing
dmealing deleted the fm/mo-1-1-0-stock-generators-importable branch October 11, 2026 17:05
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