0.25.0 — one name, one door
Coordinated MINOR across all four registries — npm 0.25.0 · PyPI 0.25.0 · NuGet 0.25.0 · Maven Central 7.25.0. Not one is a version-parity bump: each carries changed product files of its own, and expected-registry.json changed, which forces all four regardless. metamodelVersion moves 0.13 → 0.14.
The theme: a name resolved twice by two different mechanisms
The pre-1.0 breaking slot is spent on one defect class wearing different hats — two doors answering one question, disagreeing, and nothing noticing because no gate ever asked them both.
- A
<type>.basenode loaded in three ports and failed in two, so one document had two verdicts depending on which toolchain read it. The JVM refusal was accidental — its implementation classes areabstract, so instantiation threw and the message named a missing constructor rather than a rule. It survived because all tenbasesubtypes sat in the registry corpus's ownuntestedSubTypeslist, exercised by nothing in either direction. - A bare
{"object": …}was answered by four JSON parsers in three different wrong ways, none of which asked the registry for the type's declareddefaultSubTypeOf— which the YAML desugar has always used. So raw JSON and desugared YAML meant different things. - A physical database name was spelled independently by every emitter that needed it, so codegen and migrate could name the same index two different things.
$apiPrefixwas frozen into N entity descriptors atmeta gentime by a generator with no business knowing a deployment fact.- Three ports decided which source is an object's primary by declaration order rather than by role, and
views()[0]let declaration order pick a field's control.
The answer is structural: one door per name. <Entity>Names (all five ports) makes a physical data name exist once per run and generated code reference it; resolveIndexName collapses three resolvers spelling one name; all four JSON parsers consult the registry; an authored <type>.base fails the load everywhere with ERR_ABSTRACT_SUBTYPE_AUTHORED; and the client's base URL moves to the runtime provider.
Breaking changes
Six make previously-working input stop working — each has a migration note in CHANGELOG.md:
- An authored
<type>.baseno longer loads (ERR_ABSTRACT_SUBTYPE_AUTHORED). $apiPrefixleaves the entity descriptor; the base URL moves to the fetcher provider (baseUrl, optional, default"").- A TPH subtype's
$pathchanges to the address its routes actually serve — it previously named an endpoint that 404s. <Entity>Namesmirrors the metadata tree.- The
@metaobjectsdev/sdk/agent-docssubpath is removed; the agent context has one source. - Python's
GenConfig.column_namingraisesTypeErrorinstead of silently doing nothing.
Two more change what meta gen emits without breaking a load: the five @emit* attributes are retired (narrow at the generator instead), and seven attributes codegen read that no provider registers are removed.
Also in this release
An agent/ docs surface (three pages read before touching a tier) with verify --docs; meta types --format json|toon; expose on both routes generators (#348); imageCell(adapter); a columnNaming lever in the two ports that lacked one; and @schema honoured by every table, view and callable binding.
Two gate lessons are recorded on purpose: the gate over the no-magic gates counted prose as coverage and inverted its own verdict, and four of five of those gates asserted "the fixture loads clean" against a lax loader — each carrying the very line saying a gate whose fixture the loader would reject proves nothing.
Full detail: CHANGELOG.md → 0.25.0.