@@ -90,6 +90,126 @@ same blindness that let the original defect ship. `migrate-ts`'s `loadFixture` n
9090loader errors instead of discarding them — a checked-in fixture had been declaring the
9191illegal form and driving those suites green. All five ports green.
9292
93+ ### Fixed — ` meta upgrade ` rewrote nothing on a YAML estate, then called it clean ([ #339 ] ( https://github.com/metaobjectsdev/metaobjects/issues/339 ) )
94+
95+ ` meta upgrade ` is the fixer for everything ` 0.24.0 ` retired. On a ** YAML** estate it
96+ rewrote nothing, skipped every file, and finished with `no retired vocabulary found in
97+ the JSON metadata` — while ** 405 retired constructs** sat in those files (321 ×
98+ ` violation: ` alone, every one a mechanical single-token rename). The skip notice printed
99+ first, but as the header of a 161-line file list, so the line that stuck said the
100+ opposite of the truth. It also exited ** 1** , giving a script no way to tell "nothing to
101+ do" from "could not look". YAML is first-class authoring (ADR-0006), so for these
102+ adopters the tooling for a breaking change was a no-op and the whole migration manual.
103+
104+ ** YAML is now rewritten.** The arm lives in its own module behind its own package
105+ subpath, dynamic-imported by the CLI, because ` vocabulary-rewrite.ts ` is reachable from
106+ ` metadata ` 's root entry and may not import the Node-only ` yaml ` package — the same split,
107+ for the same reason, as ` yaml-positions.ts ` / ` yaml-positions-walker.ts ` .
108+
109+ It is ** parser-driven** where the JSON arm is regex-driven, and that is the whole
110+ difference: a hand-rolled YAML mode was tried in the JSON arm first and withdrawn after
111+ it corrupted files — a multi-item block sequence lost every item but the first, and the
112+ dominant authoring style (flow mappings, ` { name: x, readOnly: true } ` ) was not matched
113+ at all, so the rename silently did nothing. Both are the same failure, because YAML's
114+ value extent is not derivable by scanning. Asking the parser for each span makes a
115+ four-line block sequence and a one-line flow mapping stop being special cases. It stays
116+ ** surgical, not parse-and-reprint** — spans are located by the parse and replaced in the
117+ original text, so comments, key order and quoting survive byte-for-byte, and
118+ ` doc.toString() ` never reflows an adopter's file.
119+
120+ Reporting and exit codes, which were the other half of the report:
121+
122+ - every conclusion now names how many files it is a conclusion ** about** , so a bare
123+ "not found" can no longer stand in for "nothing was examined";
124+ - a file that does not ** parse** is reported as NOT checked rather than counted clean —
125+ the same defect arriving by a different route;
126+ - ** exit 3** now means "some files could not be read", leaving ` 1 ` for "refusals remain",
127+ ` 2 ` for bad usage and ` 0 ` for genuinely clean.
128+
129+ Gated end-to-end through the built binary and by unit cases covering both authoring
130+ styles, the multi-item sequence, flow-mapping comma handling, scope discipline,
131+ idempotence and an unparseable file. The load gate asserts the rewritten output ** loads
132+ clean** after first proving the input fails, so it cannot pass vacuously.
133+
134+ ### Fixed — a sub-project's generated tree absorbed unrelated metadata ([ #340 ] ( https://github.com/metaobjectsdev/metaobjects/issues/340 ) )
135+
136+ The gen-side remainder of #326 /#327 . Once source resolution learned to walk upward,
137+ ` meta gen ` in a package whose ` metaobjects.config.ts ` sits below the collection root
138+ loaded the ** ancestor's entire source set** : one adopter's web app went from ** 376
139+ generated files to 831** , the surplus being another module's server-side prompt payload
140+ DTOs — absent from the app's own metadata directory entirely. It fails ** open** (` tsc `
141+ passes, tests pass), so the only symptom is a generated tree that quietly doubled.
142+
143+ The rule is #326 's own principle carried to its other half: ** an ancestor
144+ ` .metaobjects/config.json ` is the DEFAULT for a package that declares no sources, never
145+ an ADDITION to one that does.** It can only ever narrow, and only where the shape could
146+ not have worked before — when the two configs sit together (every ` meta init ` project)
147+ the original collection is returned untouched, and a package that declares no sources of
148+ its own still inherits the ancestor, which is #326 's shape and is gated as its own arm.
149+
150+ ` verify --codegen ` gets the same treatment, and that is not optional: it regenerates and
151+ diffs against committed output, so narrowing ` gen ` alone would make every sub-project
152+ report the ancestor's whole contribution as drift. ` .metaobjects/ ` ** state** — migrations,
153+ snapshots, the operational block — stays keyed on the discovered collection's directory,
154+ which #326 settled; this narrows what is LOADED, not where state lives.
155+
156+ ### Fixed — generated enum types were value imports (TS1484) ([ #341 ] ( https://github.com/metaobjectsdev/metaobjects/issues/341 ) )
157+
158+ A materialized shared ` field.enum ` exports two symbols from one module — the TS type ` E `
159+ and the Zod value ` EEnum ` . The value-object emitter imported the type by bare name, so
160+ both merged into a single value import:
161+
162+ ``` ts
163+ import { DispositionEnum , DispositionEnumEnum } from " ./enums" ; // TS1484
164+ ```
165+
166+ Under ` verbatimModuleSyntax: true ` — the default in current Vite/TS templates — that is a
167+ hard error on generated code the adopter cannot edit. A regression against ` 0.23.1 ` , and
168+ invisible to any project that has not enabled the flag, which is why it shipped.
169+
170+ The regression gate for this class (#165 ) already existed and already compiled real
171+ output under that exact flag. It missed this because its fixture had no enum — and fixing
172+ it needed the right ** shape** , not just an enum: an entity types its enum column through
173+ Drizzle's ` InferSelectModel ` and only ever imports the Zod const (correctly a value), so
174+ an entity fixture compiles clean with the bug fully present. A ** value object** declares
175+ an explicit interface member and imports the type by name, which is where the defect
176+ lives and where the adopter hit it.
177+
178+ ### Fixed — generated SQLite did not compile on two minors the peer range admitted
179+
180+ Generated table calls pass ` extraConfig ` in Drizzle's ** array** form. ` pgTable ` has
181+ accepted that since ` 0.36.0 ` , but ` sqliteTable ` only since ** ` 0.38.0 ` ** — below it the
182+ only overloads take the legacy ` SQLiteTableExtraConfig ` Record, so generated SQLite fails
183+ to type-check (` Type 'CheckBuilder[]' is not assignable to type 'SQLiteTableExtraConfig' ` ).
184+ The peer range was ` >=0.36.0 <1.0.0 ` , so it admitted two minors on which our own output
185+ does not compile — the same class as the ` 0.21.5 ` peer-range work: a compatibility the
186+ package promised and never had. Floored at ` 0.38.0 ` ; Postgres is unaffected.
187+
188+ This reached no gate because nothing compiled a SQLite table that passed ` extraConfig ` at
189+ all — the compile gate's entity had a single-column inline primary key and no enum, index
190+ or table-level constraint, the one shape that avoids that argument entirely. The fixture
191+ now carries an enum, whose CHECK travels the same code path every other ` extraConfig `
192+ source uses, and the devDependency moves in lockstep so the suite type-checks generated
193+ output ** at** the declared floor rather than above it.
194+
195+ ### Fixed — the AI-facing docs taught vocabulary this release removed ([ #343 ] ( https://github.com/metaobjectsdev/metaobjects/issues/343 ) )
196+
197+ ` docs/llms/{llms.txt,llms-full.txt} ` — the entry point ` metaobjects.dev ` serves to
198+ assistants — still taught ` @verifiedBy ` as live and gave ` @status ` as the pre-` 0.24.0 `
199+ four-value enum. Both now fail the load, so an assistant scaffolding from the published
200+ index produced a ledger that ** cannot load** . Corrected to ` planned | live | partial ` ,
201+ with the retirements named AS retirements (pointing at ` meta upgrade ` ) rather than
202+ deleted silently — a reader arriving with a ` 0.23.x ` ledger needs to be told what
203+ happened to it. The other three ` 0.24.0 ` retirements appear in neither file, so the drift
204+ was confined to the requirement paragraph.
205+
206+ This is the ** third** instance of one family (#337 , #342 , #343 ): shipped documentation
207+ teaching metadata the loader rejects, each found by an adopter or a review rather than by
208+ a gate, each fixed by hand in a different file. The durable fix these keep pointing at —
209+ extracting the authored examples from shipped docs, skills and fixtures and loading them
210+ under a strict loader — is tracked separately; ` meta upgrade ` 's retirement map is already
211+ the natural source of truth for "what must no longer appear in an example".
212+
93213## [ 0.24.0] — npm ` 0.24.0 ` · PyPI ` 0.24.0 ` · NuGet ` 0.24.0 ` · Maven ` 7.24.0 `
94214
95215> ### ⚠️ BREAKING FOR METADATA AUTHORS — five vocabulary changes in ONE window
0 commit comments