Skip to content

Commit 545ea20

Browse files
dmealingclaude
andcommitted
chore(release): 0.23.2 coordinated (npm/PyPI/NuGet 0.23.2 · Maven 7.23.2)
Every registry carries a real changed product file, so none of the four is a version-parity bump: npm (metadata/codegen-ts/migrate-ts/runtime-ts), PyPI (loader + ObjectManager codec), NuGet (loader + DbContextGenerator), Maven (loader + OMDB JdbcCodecs + Kotlin table/type-mapper). It is a PATCH because the versioning rule changed in this cut, and that is the headline. The old policy made ANY registry addition a MINOR, which had spent 0.22.0 and 0.23.0 on changes a project declaring no requirement.* nodes could not observe at all. expected-registry.json is an INTERNAL gate — five ports byte-matching one manifest is how the ports are kept from drifting — and it says nothing about whether an adopter's project changes. Vocabulary now sorts by consumer impact: attribute => PATCH, top-level type => MINOR, subtype => PATCH when inert. This line adds one attribute (@intValueMap) and one inert attr subtype (attr.intMap). ADR-0035 Amendment 1; operative table in RELEASING.md. The feature is int-backed field.enum storage, and its lesson is about seams: the codec had to be written five times and the corpus caught two ports that looked finished and were not — Kotlin's cross-port oracle is a hand-written Exposed table nobody added the column to, and TypeScript has TWO persistence seams of which only the generated one had a codec, so generated code worked while om.create() bound the member symbol into an integer column. Docs propagated per RELEASING-docs-checklist: CLAUDE.md status + release-line paragraph, README port table, docs/llms/{llms,llms-full}.txt, docs/ports/{csharp, java,typescript}.md, and RELEASING.md's own "currently" version references. The CLAUDE.md edit is hand-written, not sed'd — a blanket version sed relabelled a HISTORICAL release paragraph the last time one was used here. Verified on the release SHA: local-ci all 9 jobs green (gates, ts-fast, ts-unit, ts-slow, java-fast, java-slow, python, csharp, detect), and the packed cli tarball pins every sibling to 0.23.2 with no workspace:* leakage. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 553782a commit 545ea20

43 files changed

Lines changed: 103 additions & 97 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,30 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
77

88
## [Unreleased]
99

10+
## [0.23.2] — npm `0.23.2` · PyPI `0.23.2` · NuGet `0.23.2` · Maven `7.23.2`
11+
12+
A coordinated **PATCH** across all four registries.
13+
14+
**It is a PATCH because the versioning rule changed in this cut, and that is the headline.**
15+
The old policy said any registry addition forces a MINOR, which had spent `0.22.0` and
16+
`0.23.0` on changes a project could not observe at all. `expected-registry.json` is an
17+
internal gate — five ports byte-matching one manifest is how we stop the ports drifting from
18+
each other — and it says nothing about whether an adopter's project changes. Vocabulary now
19+
sorts by consumer impact: **attribute ⇒ PATCH, top-level type ⇒ MINOR, subtype ⇒ PATCH when
20+
inert.** This line adds one attribute and one inert attr subtype, so it lands as a patch.
21+
22+
**The feature is int-backed `field.enum` storage**, and its own lesson is about seams. The
23+
`@intValueMap` codec had to be written five times, once per port, and the corpus caught two
24+
ports that looked finished and were not: Kotlin's cross-port oracle is a hand-written Exposed
25+
table nobody added the column to, and TypeScript has **two** persistence seams — generated
26+
Drizzle code and the metadata-driven `ObjectManager` — of which only the first had a codec, so
27+
generated code worked while `om.create()` bound the member symbol into an integer column and
28+
Postgres rejected the statement. Both were invisible until a shared fixture existed to run.
29+
Also in the cut: a design decision reversed after the ports disagreed with it (`@isArray` +
30+
`@intValueMap` is now a load error, because four of five ports got it silently wrong), a
31+
uniform throw on a stored integer that maps to no member (previously four different behaviours
32+
across five ports), and three unrelated fixes that were riding on the branch.
33+
1034
### Added — int-backed `field.enum` storage via `@intValueMap` (all five ports)
1135

1236
**This is a PATCH, not a MINOR** — and the reasoning is itself a change, so it is worth

CLAUDE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ Equal weight — all four ship per-language today across the five ports (TS / C#
1919

2020
_Last refreshed 2026-08-16._
2121

22-
**TypeScript reference implementation** is **published to npm at `0.23.1`** (14 `@metaobjectsdev/*` publish candidates on the `latest` tag, full lockstep; the two `angular` packages are versioned on their own `0.6.x` line and are **NOT published to npm — source-only by decision** (ADR-0048): they build in-repo, and stay off the registry until they meet the ADR's promotion bar). C# at `0.23.1` (NuGet); Python at `0.23.1` (PyPI); Java / Kotlin at `7.23.1` (Maven Central). **All four registries share the same `minor.patch`, and stay locked in lockstep going forward** — the `0.20.15` cut moved Maven `7.20.12``7.20.15` to close the last per-registry drift.
22+
**TypeScript reference implementation** is **published to npm at `0.23.2`** (14 `@metaobjectsdev/*` publish candidates on the `latest` tag, full lockstep; the two `angular` packages are versioned on their own `0.6.x` line and are **NOT published to npm — source-only by decision** (ADR-0048): they build in-repo, and stay off the registry until they meet the ADR's promotion bar). C# at `0.23.2` (NuGet); Python at `0.23.2` (PyPI); Java / Kotlin at `7.23.2` (Maven Central). **All four registries share the same `minor.patch`, and stay locked in lockstep going forward** — the `0.20.15` cut moved Maven `7.20.12``7.20.15` to close the last per-registry drift.
23+
24+
**The `0.23.2` line is a coordinated PATCH across all four registries** (npm `0.23.2` · PyPI `0.23.2` · NuGet `0.23.2` · Maven `7.23.2`) — **int-backed `field.enum` storage, and the versioning rule that says why this is a PATCH.** The rule change is the durable half: the old policy made ANY registry addition a MINOR, which had spent `0.22.0` and `0.23.0` on changes a project could not observe at all. `expected-registry.json` is an **internal** gate — five ports byte-matching one manifest is how the ports are kept from drifting — and it says nothing about whether an adopter's project changes. Vocabulary now sorts by consumer impact: **attribute ⇒ PATCH, top-level type ⇒ MINOR, subtype ⇒ PATCH when INERT** (nothing but authoring it can reach it; MINOR when it narrows something previously permitted, changes what existing metadata means, or headlines a release on purpose). The caret rule is not to be inverted — "`^0.22.x` resolves `<0.23.0`, so a MINOR is adopted deliberately" is a reason to CHOOSE minor when that gate is wanted, not a reason additive vocabulary must be minor. ADR-0035 Amendment 1; operative table in `docs/RELEASING.md`. **The feature:** `@intValueMap` (a `{memberSymbol: int}` map on `field.enum`) switches the column from `varchar` + string `CHECK` to `integer` + int `CHECK` while the wire format, the generated enum type and every runtime return value stay the member SYMBOL — the provenance is an integer-coded column an adopter already has, and it is a MAP rather than a positional array so reordering `@values` cannot silently re-map every member. Persistence ships in all five ports; **TypeScript needed TWO codecs** (a Drizzle `customType` for generated code, `ObjectManager` read/write/filter coercion for the metadata-driven runtime) and shipped only the first until the corpus caught it — generated code worked while `om.create()` bound the symbol into an integer column. **Two rulings close ways it could have shipped half-true:** `@isArray` + `@intValueMap` is now a LOAD ERROR (`ERR_ENUM_INT_VALUE_MAP_ARRAY`) because the original design assumed the element codec fell out of the scalar one and it does not — Python bound the symbol LIST into an `integer[]`, Java and Kotlin emitted a scalar codec, TS's sqlite branch stored symbols as JSON text, and **two ports composing while four silently get it wrong is the `field.byte`/`short`/`class` mistake**; and a stored integer mapping to no member now THROWS in all five (it previously behaved four different ways — Java surfaced `"7"`, Python the raw int, C# fell through to the LAST member, handing back `ARCHIVED` for a row that is not). Also: the filter-operator band is decided per FIELD not per subtype (an int-backed enum drops `like`), an FK into a table whose key carries `@column` stopped phantom-diffing forever, views in a table-less schema are no longer excluded from the migrate diff entirely, and a chained abstract `field.enum` is named for its OWN declaration in Kotlin. See `CHANGELOG.md` [0.23.2].
2325

2426
**The `0.23.1` line is a coordinated PATCH across all four registries** (npm `0.23.1` · PyPI `0.23.1` · NuGet `0.23.1` · Maven `7.23.1`) — every registry carries a real changed product file, so none is a version-parity bump. **The theme is a check that was confidently wrong:** not one of these is a missing feature; each is a guarantee the toolchain already made and quietly failed to keep. (1) **`{{#hasField}}` rendered as absent on a populated payload, in every port.** A prompt's conditional section is a DERIVED boolean over a declared field; the JVM has emitted `has<Field>()` onto generated payload records since 7.7.7 and accepted the section in `verify` — **no render engine implemented the other half**, so given the same payload *data* (a map, which is what the runtime and the corpus actually pass) all five ports dropped the block's contents silently, with no error. The JVM looked correct only because a generated RECORD answers `hasFoo()` by its own method, so the same payload rendered differently depending on whether it arrived as a record or as a map — the byte-identical-rendering promise failing quietly. `PayloadAccessors` now exists in all five ports with one naming rule and the JVM emitter's presence semantics (string → non-blank, collection → non-empty, reference → non-null, **number/boolean → no accessor**, since `{{#hasCount}}` over an int is drift rather than a conditional); an AUTHORED `hasFoo` always wins. Found by an adopter whose Node gate reported **157** `ERR_VAR_NOT_ON_PAYLOAD` against a JVM gate reporting none — now 0 on both. (2) **`@provided` flowed down an `extends` chain in TS/C#/Python** — it is a provenance fact about the declaration ITSELF, like `abstract`, so it must not be inherited; the resolving ports emitted a reference to a hand-written type **the adopter never declared**. ADR-0039 amended (`@provided` is chartered as the second deliberately own-only attribute; the member set it accompanies stays RESOLVING). (3) **`@verifiedBy` stopped deciding what a test file is** — its closed pattern list was a guess about someone else's repository and was wrong on Maven Failsafe (`*IT`) from the day it shipped, convicting a correct project with `ERR_REQUIREMENT_TEST_MISSING`; Failsafe's defaults are now built in, `verify.testFiles` lets a project declare its own, and an unrecognised convention WARNs instead of convicting. (4) **A requirement can now claim a `template.prompt`** — L4 means "a declared top-level model node", so the estate with the most to gain from a status (a retired prompt leaves nothing behind) can finally carry one. (5) **`verify` gates the committed schema snapshot** ([#292](https://github.com/metaobjectsdev/metaobjects/issues/292)) — that file decides what DDL the next migration contains and nothing checked it; the check is conditioned on metadata==DB, which is what makes it false-positive-free. (6) **Codegen and migrate named the same CHECK constraint two different ways** ([#293](https://github.com/metaobjectsdev/metaobjects/issues/293)) — codegen changed, not migrate, because migrate's suffix names are already in live databases. **The durable lesson is the shape they share: each survived because the thing that would have caught it did not exist** — the render corpus had NO fixture using a derived accessor at all, nothing ever compared codegen's constraint name to migrate's, and no gate read the snapshot. Every fix ships with the missing check, not just the corrected behaviour. See `CHANGELOG.md` [0.23.1].
2527

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ first-week wedge plan — and `meta init` picks up from there.
9393

9494
| Language | Status | Quickstart | Source |
9595
|---|---|---|---|
96-
| TypeScript | Published to npm at `0.23.1` (the `@metaobjectsdev/*` packages) | [`docs/ports/typescript.md`](docs/ports/typescript.md) | [`server/typescript/`](server/typescript/) · [`client/web/`](client/web/) |
96+
| TypeScript | Published to npm at `0.23.2` (the `@metaobjectsdev/*` packages) | [`docs/ports/typescript.md`](docs/ports/typescript.md) | [`server/typescript/`](server/typescript/) · [`client/web/`](client/web/) |
9797
| Java | Loader + OMDB + render + Maven plugin all shipped; full conformance green | [`docs/ports/java.md`](docs/ports/java.md) | [`server/java/`](server/java/) |
9898
| Kotlin | Codegen tier on top of Java — 14 generators (entity, Exposed table, relations, repository, payload, output-parser, output-prompt, render-helper, extractor, filter-allowlist, validator, Spring config, storedProc, Spring controller); 24 / 24 persistence-conformance | [`docs/ports/kotlin.md`](docs/ports/kotlin.md) | [`server/java/codegen-kotlin/`](server/java/codegen-kotlin/) · [`server/java/metadata-ktx/`](server/java/metadata-ktx/) |
9999
| C# | Loader + conformance + EF Core codegen + render engine + `dotnet meta` CLI all shipped | [`docs/ports/csharp.md`](docs/ports/csharp.md) | [`server/csharp/`](server/csharp/) |

0 commit comments

Comments
 (0)