Skip to content

feat: C4 metamodelVersion marker — rolled-up Metamodel spec version (all 5 ports) - #145

Merged
dmealing merged 5 commits into
mainfrom
feat/metamodel-version
Jul 2, 2026
Merged

feat: C4 metamodelVersion marker — rolled-up Metamodel spec version (all 5 ports)#145
dmealing merged 5 commits into
mainfrom
feat/metamodel-version

Conversation

@dmealing

@dmealing dmealing commented Jul 2, 2026

Copy link
Copy Markdown
Member

Adds a single rolled-up metamodelVersion string as the first key of the registry manifest, exposed per port and gated byte-for-byte by registry-conformance (all five ports emit the same value). Value "0.9" — pre-1.0/near-final, decoupled from every package line; the 1.0 cut (readiness G1) freezes it to "1.0". Not per-provider, not a per-file stamp — a version tag on the existing expected-registry.json manifest. Implements readiness C4 (design in docs/1.0-readiness.md). Additive/non-breaking. Cross-port conformance green.

🤖 Generated with Claude Code

claude added 5 commits July 2, 2026 02:21
…nifest tag

Adds a rolled-up Metamodel spec-version string to the registry manifest as the first
top-level key (`metamodelVersion: "0"` — pre-1.0/unstable; the 1.0 cut freezes it to
"1.0"). A version TAG on the existing expected-registry.json manifest, exposed via
METAMODEL_VERSION + emitted by buildRegistryManifest, gated byte-for-byte by
registry-conformance (all ports must emit the same string). Not per-provider, not
per-file. TS reference; C#/Java/Kotlin/Python fan-out follows against the shared fixture.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GF9xLEQZaPus5Y6opk398n
Emit `metamodelVersion: "0"` as the first top-level key in the C# registry
manifest, mirroring the TS reference. Byte-matches the shared fixture
`fixtures/registry-conformance/expected-registry.json`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GF9xLEQZaPus5Y6opk398n
Add METAMODEL_VERSION = "0" constant and emit metamodelVersion as the
first top-level key in build_registry_manifest(), mirroring the TS
reference. Registry-conformance byte-match now green (3/3).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GF9xLEQZaPus5Y6opk398n
Add METAMODEL_VERSION = "0" constant and emit metamodelVersion as the
first top-level JSON key in RegistryManifest.serialize(), matching the
TS reference. Both Java and Kotlin conformance runners byte-match the
shared expected-registry.json fixture.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GF9xLEQZaPus5Y6opk398n
…ts + fixture

Change the pre-1.0 spec-version value from "0" to "0.9" — still 0.x/unstable per
semver, but signals near-final going into the quiet period. Decoupled from every
package line (npm 0.15 / Maven 7.7 etc.); it's the spec version, not a package version.
Updated all 5 emitters (TS/C#/Java/Python; Kotlin shares the JVM emitter) + the shared
expected-registry.json + docs. The 1.0 cut (G1) flips it to "1.0".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GF9xLEQZaPus5Y6opk398n
@dmealing
dmealing merged commit 5757a1d into main Jul 2, 2026
11 checks passed
@dmealing
dmealing deleted the feat/metamodel-version branch July 2, 2026 06:50
dmealing pushed a commit that referenced this pull request Jul 2, 2026
dmealing added a commit that referenced this pull request Aug 21, 2026
Review + simplify pass on #322. Four findings, all real; two were the gate failing in
exactly the way it takes pains to refuse elsewhere.

**It failed open on ANY baseline error.** `manifestAt()` swallowed every exception into
`null`, and `main()` read `null` as "pre-marker tag — skipping" and exited 0. So a typo'd
`--against v9.9.9` printed `fatal: invalid object name`, then a green tick (verified). Same
for a renamed manifest path, malformed baseline JSON, or a partial clone whose objects were
never fetched. That is precisely the failure the no-baseline branch already refuses by name
— it does not get a side door. The read now distinguishes "genuinely not there yet" (skip)
from "something went wrong" (fail), asking the TREE via `git ls-tree` whether the path
exists rather than inferring absence from a failed `git show` — in a blobless clone the ref
and trees resolve while the blob does not, and that means "not fetched", not "not present".

**`satisfies()` accepted a version REGRESSION.** `cur.major > base.major || cur.minor >
base.minor` reads as "moved somehow": `1.0 → 0.11` passed it (0 > 1 false, 11 > 0 true), as
did `2.0 → 1.9`. Concretely, post-1.0 someone typing `--set 0.11` out of pre-1.0 habit — or
a bad merge resolving the manifest to an older value — would ship a release declaring a
LOWER metamodel version than the one before it, with every port byte-matching the manifest
so registry-conformance stays green too. Now a `(major, minor)` tuple compare. The existing
"0.10 → 0.9 must not satisfy" case only covered a SAME-major regression, which is what made
this look tested; the two cross-major cases and a forward `1.9 → 2.0` are pinned now.

**The pre-marker skip was keyed on the wrong marker.** It triggered when the manifest FILE
was absent, but the file predates the `metamodelVersion` key (PR #145) — so `--against
v0.15.0`, a documented flag on a real tag, died with `metamodelVersion must be
"<major>.<minor>" (got undefined)`. It now skips on the KEY's absence and says so.

**`--against --explain` silently became a ref named "--explain"**, which resolved to
nothing and (before the first fix) passed. A flag is no longer swallowed as a value.

**Stale prose that `--set` re-stales every bump.** `registry-manifest.ts`'s JSDoc said the
value is `"0.9"` directly above the line this PR set to `"0.10"`; RELEASING.md, ADR-0035
Am. 2 and the design doc each restated it too. `--set` rewrites declarations, not
sentences, so every copy in prose goes stale on the next bump. Dropped the literal from all
four rather than adding prose sites to `SITES` — matching a sentence with a regex is the
fragile half of that choice, and the value already lives authoritatively one line below.
The JSDoc now says why, so it does not come back.

Simplifier pass (behaviour-preserving): cached `Boolean(isArray)` and `min ?? 0`, each
computed twice per side, matching the `bv`/`cv` and `bMax`/`cMax` caching already in those
same functions; replaced the file's only nested ternary. It also caught a miscount in my
header comment ("6 sites" / "five port constants" against a 5-entry `SITES`) — the runtime
output was always right.

Every finding re-probed closed: bad ref → exit 1, flag-as-value → exit 1, `v0.15.0` → skip
with a clear reason, `1.0 → 0.11` and `2.0 → 1.9` → false. 43 classifier checks (was 40),
`ci-local --only gates` green, TS build + typecheck clean, metadata 2406 pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhpswkF1NvwxhFWMmdAT15
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.

2 participants