@@ -10,6 +10,15 @@ here.**
1010
1111## [Unreleased]
1212
13+ **Upgrading: run `meta gen`.** Every generated file's header comment changed ([#367]), and
14+ generated routes files gain an auth-seam JSDoc block, so `meta verify --codegen` reports
15+ drift on any project that commits its generated output until it is regenerated. For most
16+ projects that regen diff is **comments only — zero non-comment lines**. Two shapes change
17+ for real: a model with two `identity.reference` nodes onto the same target gets corrected
18+ FK wiring and referential actions ([#368] — including an `ON DELETE` / `ON UPDATE` diff on
19+ the next `meta migrate`), and an M:N relationship inherited through `extends` now derives
20+ navigation that was previously dropped from the output with no error.
21+
1322### Added
1423
1524- **Libraries: reusable declared design you opt into** (FR-043, the sixth pillar).
@@ -47,6 +56,37 @@ here.**
4756 (Kotlin inherits the JVM's); one new conformance fixture takes over the unmarked-conflict
4857 error branch, so the coverage moved rather than being deleted.
4958
59+ - **`layer` joins the cross-port generator manifest** — `model` / `persistence` / `api` /
60+ `client` / `docs` / `capability` — gated by all five ports' registry-conformance tests
61+ exactly as `tier` is. Five TypeScript generators that were in no manifest at all (`form`,
62+ `hooks`, `grid`, `grid-hook`, `requirement-tests`) join it too, so the catalog describes
63+ 34 generators where the manifest described 29.
64+
65+ - **`meta gen` audits the selection.** Two self-extinguishing warnings, neither a build
66+ failure: a wired generator whose `requires` are not wired (its output will import a
67+ module nothing emits), and two `api`-layer generators declaring different frameworks
68+ (`routes` + `routes-hono` emit to different paths, so nothing conflicts and two complete
69+ HTTP surfaces appear silently). There is deliberately no equivalent rule on the `client`
70+ layer: `@metaobjectsdev/tanstack` peers on `react`, so a form generator plus the TanStack
71+ hook/grid generators is the intended composition.
72+
73+ - **The auth seam is printed in the generated routes handler's JSDoc ([#367]).** Stock
74+ CRUD is unauthenticated and no metadata attribute should change that — authentication
75+ is not derivable from a model (ADR-0023). Both frameworks already compose a guard
76+ around the generated mount; only the generated output never said so. Fastify hooks are
77+ encapsulated per plugin scope and inherited by child scopes, so wrapping the call
78+ reaches through the handler's own `register(..., { prefix })`; Hono's trailing wildcard
79+ matches the collection path itself, so one `app.use` covers list, get and every write.
80+ Both recipes are executed as tests (`runtime-ts/test/route-auth-seam.test.ts`) rather
81+ than asserted in prose, and each names the generator that emitted the file
82+ (`routesFile` / `routesFileHono`) for narrowing with `expose`. The JSDoc also states
83+ what no mount can express: a row-ownership rule is not a property of a route, so those
84+ verbs are hand-written and the generated file narrowed around them.
85+ - **`mountReadOnlyCrudRoutes` accepts `routeOptions`** (`@metaobjectsdev/runtime-ts`,
86+ Fastify), the option `mountCrudRoutes` and `mountM2mRoute` already took. A projection's
87+ generated routes could not carry a route-level hook the way an entity's could — an
88+ inconsistency, not a policy. Read-only is not public.
89+
5090### Changed
5191
5292- **`libraries` moved to `.metaobjects/config.json`**, out of `metaobjects.config.ts`,
@@ -86,6 +126,48 @@ here.**
86126 node's error envelope read differently depending on how the library was resolved — and
87127 collided with an adopter file of that name.
88128
129+ - **Codegen is OPT-IN: no port ships a default generator suite** (ADR-0034 Amendment 2).
130+ A new project got code it never asked for — TypeScript's `meta init` copied and wired
131+ five generators, C# ran nine for a caller who named none, Python eight; Java never had
132+ a default set and has been right all along. Deciding which code an application needs
133+ belongs to whoever is building it, increasingly an LLM in the repo, which is well able
134+ to make that call given a truthful catalog and is badly served by a default that
135+ pre-empts it.
136+
137+ **This is a PATCH and no existing project changes by one byte.** An adopter already has
138+ their owned copies on disk and their selection committed in their own config; `meta gen`
139+ keeps running exactly that list, `verify --codegen` keeps checking exactly that output,
140+ and re-running `init` never clobbers a file that exists. What changes is what a *new*
141+ project starts with. `docs/compatibility-policy.md` is narrowed in the same change: the
142+ scaffold-and-own promise is the LAYOUT and the INTERFACES, not which generators a fresh
143+ scaffold wires.
144+
145+ What this means per port:
146+ - **TypeScript** — `meta init` scaffolds `codegen/generators/` **empty**, a config with
147+ `generators: []`, and no dependencies. `dbImport` and the throwing `src/db.ts` stub are
148+ gone with it: both existed only because the scaffold wired `routesFile()`, whose output
149+ emits `import { db } from …`. `dbImport` is now a declared `configKey` on the `routes`
150+ catalog entry, reported by `meta eject routes` to the adopter who chose routes.
151+ - **C# / Python** — `--generators` is REQUIRED; a run that names none is a usage error
152+ and writes nothing. `verify --codegen` re-runs the SELECTION, so with none named it
153+ reports that there is nothing to check rather than regenerating a suite the project
154+ never ran. Python's `verify` gains `--generators`, matching C#.
155+
156+ - **`meta gen --list` is now the generator CATALOG, and `--probe` answers it against your
157+ own model.** `--list --format json` emits one document per generator: its `layer`,
158+ `framework`, what it emits, what it `requires`, the consolidated install set, the config
159+ keys it reads, and whether this project already owns a copy. `--probe` constructs every
160+ generator and dry-runs it against the loaded model, reporting how many files each would
161+ emit — so `output-parser: 3, callable: 0, requirement-tests: 7` replaces a category
162+ label, and cannot go stale, because it runs the generators rather than describing them.
163+
164+ - **`meta eject` takes many names and reports one consolidated install set.** A real
165+ selection is several generators, and three separate invocations produced three separate
166+ install lines for the same package. `--format json` carries, per file, the import line
167+ and the entry to wire, plus one install set with third-party ranges read from the runtime
168+ package's own `peerDependencies`. An unknown name refuses the whole call before writing
169+ anything.
170+
89171### Fixed
90172
91173- **An M:N relationship inherited through `extends` derived its junction FK columns
@@ -172,8 +254,6 @@ here.**
172254 No vocabulary change: `metamodelVersion` stays `1.0` and the registry manifest is
173255 untouched.
174256
175- ||||||| 7dafb055e
176-
177257- **Both shipped libraries failed `meta verify`'s requirement gate**, in metadata an
178258 adopter cannot fix: every L4 in `ai` claimed FIELDS (`ERR_REQUIREMENT_L4_NOT_OBJECT`),
179259 and both libraries wrote their concerns as SIBLINGS of the L2 segment their own comments
@@ -185,68 +265,6 @@ here.**
185265 warnings, zero gate findings, zero lint findings, no unruled gaps, and every entity
186266 claimed by its own ledger.
187267
188- ### Changed
189-
190- - **Codegen is OPT-IN: no port ships a default generator suite** (ADR-0034 Amendment 2).
191- A new project got code it never asked for — TypeScript's `meta init` copied and wired
192- five generators, C# ran nine for a caller who named none, Python eight; Java never had
193- a default set and has been right all along. Deciding which code an application needs
194- belongs to whoever is building it, increasingly an LLM in the repo, which is well able
195- to make that call given a truthful catalog and is badly served by a default that
196- pre-empts it.
197-
198- **This is a PATCH and no existing project changes by one byte.** An adopter already has
199- their owned copies on disk and their selection committed in their own config; `meta gen`
200- keeps running exactly that list, `verify --codegen` keeps checking exactly that output,
201- and re-running `init` never clobbers a file that exists. What changes is what a *new*
202- project starts with. `docs/compatibility-policy.md` is narrowed in the same change: the
203- scaffold-and-own promise is the LAYOUT and the INTERFACES, not which generators a fresh
204- scaffold wires.
205-
206- What this means per port:
207- - **TypeScript** — `meta init` scaffolds `codegen/generators/` **empty**, a config with
208- `generators: []`, and no dependencies. `dbImport` and the throwing `src/db.ts` stub are
209- gone with it: both existed only because the scaffold wired `routesFile()`, whose output
210- emits `import { db } from …`. `dbImport` is now a declared `configKey` on the `routes`
211- catalog entry, reported by `meta eject routes` to the adopter who chose routes.
212- - **C# / Python** — `--generators` is REQUIRED; a run that names none is a usage error
213- and writes nothing. `verify --codegen` re-runs the SELECTION, so with none named it
214- reports that there is nothing to check rather than regenerating a suite the project
215- never ran. Python's `verify` gains `--generators`, matching C#.
216-
217- - **`meta gen --list` is now the generator CATALOG, and `--probe` answers it against your
218- own model.** `--list --format json` emits one document per generator: its `layer`,
219- `framework`, what it emits, what it `requires`, the consolidated install set, the config
220- keys it reads, and whether this project already owns a copy. `--probe` constructs every
221- generator and dry-runs it against the loaded model, reporting how many files each would
222- emit — so `output-parser: 3, callable: 0, requirement-tests: 7` replaces a category
223- label, and cannot go stale, because it runs the generators rather than describing them.
224-
225- - **`meta eject` takes many names and reports one consolidated install set.** A real
226- selection is several generators, and three separate invocations produced three separate
227- install lines for the same package. `--format json` carries, per file, the import line
228- and the entry to wire, plus one install set with third-party ranges read from the runtime
229- package's own `peerDependencies`. An unknown name refuses the whole call before writing
230- anything.
231-
232- ### Added
233-
234- - **`layer` joins the cross-port generator manifest** — `model` / `persistence` / `api` /
235- `client` / `docs` / `capability` — gated by all five ports' registry-conformance tests
236- exactly as `tier` is. Five TypeScript generators that were in no manifest at all (`form`,
237- `hooks`, `grid`, `grid-hook`, `requirement-tests`) join it too, so the catalog describes
238- 34 generators where the manifest described 29.
239-
240- - **`meta gen` audits the selection.** Two self-extinguishing warnings, neither a build
241- failure: a wired generator whose `requires` are not wired (its output will import a
242- module nothing emits), and two `api`-layer generators declaring different frameworks
243- (`routes` + `routes-hono` emit to different paths, so nothing conflicts and two complete
244- HTTP surfaces appear silently). There is deliberately no equivalent rule on the `client`
245- layer: `@metaobjectsdev/tanstack` peers on `react`, so a form generator plus the TanStack
246- hook/grid generators is the intended composition.
247-
248- ### Fixed
249-
250268- **Generated files no longer point at a plugin point that does not exist ([#367]).**
251269 Every emitted header carried `Customize via <Entity>.extra.ts in this directory`, and
252270 routes files added `(e.g., auth, additional handlers)`. Nothing in any toolchain imports
@@ -316,25 +334,6 @@ here.**
316334 changed product files or not — that consequence is recorded here so it isn't a
317335 surprise at release time. `metamodelVersion` stays `1.0`.
318336
319- ### Added
320-
321- - **The auth seam is printed in the generated routes handler's JSDoc ([#367]).** Stock
322- CRUD is unauthenticated and no metadata attribute should change that — authentication
323- is not derivable from a model (ADR-0023). Both frameworks already compose a guard
324- around the generated mount; only the generated output never said so. Fastify hooks are
325- encapsulated per plugin scope and inherited by child scopes, so wrapping the call
326- reaches through the handler's own `register(..., { prefix })`; Hono's trailing wildcard
327- matches the collection path itself, so one `app.use` covers list, get and every write.
328- Both recipes are executed as tests (`runtime-ts/test/route-auth-seam.test.ts`) rather
329- than asserted in prose, and each names the generator that emitted the file
330- (`routesFile` / `routesFileHono`) for narrowing with `expose`. The JSDoc also states
331- what no mount can express: a row-ownership rule is not a property of a route, so those
332- verbs are hand-written and the generated file narrowed around them.
333- - **`mountReadOnlyCrudRoutes` accepts `routeOptions`** (`@metaobjectsdev/runtime-ts`,
334- Fastify), the option `mountCrudRoutes` and `mountM2mRoute` already took. A projection's
335- generated routes could not carry a route-level hook the way an entity's could — an
336- inconsistency, not a policy. Read-only is not public.
337-
338337[#367]: https://github.com/metaobjectsdev/metaobjects/issues/367
339338[#368]: https://github.com/metaobjectsdev/metaobjects/issues/368
340339
0 commit comments