Skip to content

Commit 91e063b

Browse files
committed
Merge origin/main into fm/mo-deps-pkg-transports
# Conflicts: # README.md # agent-context/skills/metaobjects-codegen/references/dependencies-and-shared-models.md # docs/CONFORMANCE.md # docs/features/cli.md # docs/features/metadata-dependencies.md # fixtures/agent-context-conformance/java-kotlin-react-tanstack/expected/.claude/skills/metaobjects-codegen/references/dependencies-and-shared-models.md # fixtures/agent-context-conformance/java-react/expected/.claude/skills/metaobjects-codegen/references/dependencies-and-shared-models.md # fixtures/agent-context-conformance/python/expected/.claude/skills/metaobjects-codegen/references/dependencies-and-shared-models.md # fixtures/agent-context-conformance/ts-react-tanstack/expected/.claude/skills/metaobjects-codegen/references/dependencies-and-shared-models.md # fixtures/agent-context-conformance/ts-requirements/expected/.claude/skills/metaobjects-codegen/references/dependencies-and-shared-models.md # fixtures/dependency-conformance/README.md
2 parents f8f75d0 + 98d6823 commit 91e063b

57 files changed

Lines changed: 2343 additions & 159 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: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ here.**
1616

1717
### Added
1818

19+
- **Java and Kotlin consume a shared model (FR-023 Phase 2).** A project that declares
20+
`dependencies` in `.metaobjects/config.json` loads its committed `.metaobjects/deps/` snapshot
21+
ahead of its own files, in the Maven plugin (every rung of the source ladder) and the Java
22+
loader. The lock is checked as in TypeScript and Python (`ERR_DEPENDENCY_SNAPSHOT_STALE`,
23+
`_METAMODEL_INCOMPATIBLE`, `_NODE_COLLISION`), a local node declared into a dependency's package
24+
fails with `ERR_DEPENDENCY_PACKAGE_NOT_OWNED`, and the Java and Kotlin generators emit nothing for
25+
an imported object unless `scope.include` names its package. Runs all 24 resolution cases of
26+
`fixtures/dependency-conformance/` (the 11 check cases pin the Node `meta deps check`); Kotlin loads through the same loader and adds a codegen test.
27+
Spring runtime auto-load and `verify` drift for dependencies are later slices.
1928
- **Java, Kotlin and C# can compile and match `scope` patterns.** `com.metaobjects.config.Scope`
2029
(Java; Kotlin inherits it) and `MetaObjects.Config.Scope` (C#) port the scope-pattern grammar from
2130
TypeScript (`compilePattern` / `compileScope` / `matchesScope`), and both run the shared
@@ -130,6 +139,26 @@ here.**
130139
on any failure, so the previous state is intact. `meta deps check` also loads the model once
131140
its hashes match and exits 1 with the load error when it does not load.
132141

142+
- **`meta verify --db` no longer reports false CHECK drift on Postgres for a one-value enum, a
143+
`presentIff` validator, or a validator on a `varchar(n)` column; a changed enum-member case
144+
or regex case no longer reads as clean.** Postgres stores `"k" IN ('x')` as `k = 'x'` and
145+
`a IS NOT DISTINCT FROM b` as `NOT (a IS DISTINCT FROM b)`, and casts a `varchar` column to
146+
text (`(region)::text`) in a comparison, a `length()` and a null-safe test. The comparison now
147+
folds all three back, so a database `migrate` just built verifies clean. The same false drift
148+
reached `meta migrate --from-db`, which proposed a drop-check and add-check on every run, and
149+
the offline `migrate --dry-run` after a `baseline --from-db`. It has done so since 1.0.x. In
150+
the other direction, the comparison lower-cased quoted literals and deleted every bracket,
151+
quote and run of blanks inside them, so `IN ('OPEN')` against `IN ('open')` and `~ '^[A-Z]+$'`
152+
against `~ '^[a-z]+$'` compared as equal. Literals are now compared as written. A check
153+
stored in a different case than the model declares therefore shows as drift once: run
154+
`meta migrate` to bring it back. Separately, `char(n)` is no longer treated as a text column
155+
for the `(col)::text` fold: its own regex operator sees the blank padding the cast trims, and
156+
Postgres never adds the cast there, so an explicit `(col)::text ~ '…'` on a `char(n)` column
157+
now reads as drift. A precedence change (`(a OR b) AND c` against `a OR (b AND c)`) is still
158+
not detected; that needs Postgres to canonicalise the expected side. A new Postgres test
159+
migrates, applies and verifies every CHECK shape `migrate` generates. Schema comparison is
160+
TypeScript-owned, so no other port carries this comparison.
161+
133162
### Documentation
134163

135164
- **Two doc errors corrected against the code.** `docs/recipes/mysql.md` said Python ships a

‎README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,8 @@ sixth ships two libraries at their own stability labels:
261261
`meta eject <library>`. See [`docs/features/libraries.md`](docs/features/libraries.md).
262262

263263
**Sharing a model across your own projects** *(the TypeScript toolchain publishes;
264-
TypeScript and Python projects consume, from an installed npm or Python package or over
265-
a `path` dependency such as a sibling checkout; Java, Kotlin and C# arrive in Phase 2)* — one project publishes
264+
TypeScript, Python, Java and Kotlin projects consume, from an installed npm or Python
265+
package or over a `path` dependency such as a sibling checkout; C# arrives in Phase 2)* — one project publishes
266266
part of its model (a common `Customer`, an audited base, a set of enums) with
267267
`sharedModelFile()`, and another declares it in `dependencies`, syncs it into a
268268
committed, hash-locked snapshot and builds on it with `extends` and references. When the

‎agent-context/skills/metaobjects-codegen/references/dependencies-and-shared-models.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ as package data), run `meta gen`, then release the package as usual; consumers
4444
declare an `npm` or `python` dependency on it. With no `version` option the
4545
manifest takes the nearest `package.json` version, else a `pyproject.toml`
4646
`[project]` version — pass `version` when neither is the package consumers install.
47-
Only TypeScript can run it in Phase 1a. **Phase 1a is TypeScript and Python
48-
only, full stop** — TypeScript and Python are the only two ports that can
49-
*consume* a dependency at all today, and only the TypeScript toolchain can
50-
*publish* one; Java, Kotlin, and C# do not read `dependencies` yet (Phase 2).
47+
Only TypeScript can run it in Phase 1a. TypeScript, Python, Java and
48+
Kotlin (through Java's loader and Maven plugin) can *consume* a dependency, and
49+
only the TypeScript toolchain can *publish* one; C# does not read
50+
`dependencies` yet (Phase 2).
5151
Full detail: `docs/features/metadata-dependencies.md`.

‎docs/CONFORMANCE.md‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ regenerate with `ls -d fixtures/<corpus>/*/ | wc -l` for directory-shaped corpor
4646
| [`fixtures/provider-composition-conformance/`](../fixtures/provider-composition-conformance/) | 9 (5 error-shape + 4 compose-load) | ✓ | ✓ | — (JVM registry via Java) | ✓ | ✓ |
4747
| [`fixtures/source-resolution-conformance/`](../fixtures/source-resolution-conformance/) | 25 cases | ✓ (reference implementation) | ✓ | inherits via Java | ✓ | ✓ |
4848
| [`fixtures/scope-conformance/`](../fixtures/scope-conformance/) | 10 cases | ✓ (reference implementation) | ✓ | inherits via Java | ✓ | ✓ |
49-
| [`fixtures/dependency-conformance/`](../fixtures/dependency-conformance/) | 37 cases (26 resolution + 11 check) + 14 transport cases | ✓ (reference implementation; all three arms) | — (Phase 2) | — (Phase 2) | — (Phase 2) | ✓ (resolution arm, all 26 identically; no check yet, so the 11 check cases are not run; the transport arm is Node-only) |
49+
| [`fixtures/dependency-conformance/`](../fixtures/dependency-conformance/) | 37 cases (26 resolution + 11 check) + 14 transport cases | ✓ (reference implementation; all three arms) | ✓ (resolution arm, all 26; no check, so the 11 check cases are not run) | inherits via Java | — (Phase 2) | ✓ (resolution arm, all 26 identically; no check yet, so the 11 check cases are not run; the transport arm is Node-only) |
5050
| [`fixtures/shared-model-conformance/`](../fixtures/shared-model-conformance/) | 11 cases (7 publish + 4 refusal) | ✓ (reference implementation) | — (Phase 2) | — (Phase 2) | — (Phase 2) | ✓ (serializer arm: the 7 publish cases' document bytes; no publisher) |
5151
| [`fixtures/agent-context-conformance/`](../fixtures/agent-context-conformance/) | 4 | ✓ (the emitter is TS-owned) | — | — | — | — |
5252
| [`fixtures/metamodel-docs/`](../fixtures/metamodel-docs/) | 1 | ✓ (docs emit is TS-owned) | — | — | — | — |
@@ -450,15 +450,15 @@ above: one committed `cases.json`, no per-port fixture, no ledger. The corpus ha
450450

451451
- **Resolution (26 cases).** Every case's `expectFiles`/`expectImported`/`expectSelected`/
452452
`expectMigrateGoverned`/`expectLoadError` assertions. **TypeScript (the reference
453-
implementation) and Python both run all 26, identically**, with no exemption. The two
453+
implementation), Python and Java all run all 26, identically**, with no exemption. The two
454454
overlay cases that need a view child as incidental content use `view.currency` (the one
455455
concrete `view.*` subtype registered cross-port), not `view.text` — a prior revision used
456456
`view.text`, which Python did not register then, and carried a since-discharged allowlist
457-
for it.
457+
for it. Kotlin inherits the Java run through the same loader and Maven plugin.
458458
- **Check (11 cases, `expectCheck`).** For each declared dependency, `current`, `drifted` or
459459
`unresolved` (a missing path, a bad manifest, a hash mismatch, or not yet in the lock). Run
460-
by TypeScript only, in `cli/test/dependency-check-conformance.test.ts`; Python has no
461-
`deps check` yet and filters these cases out. The arm exists so that each port's check is
460+
by TypeScript only, in `cli/test/dependency-check-conformance.test.ts`; Python and Java have no
461+
`deps check` yet and filter these cases out. The arm exists so that each port's check is
462462
written against the same edge cases (Phase 2, #482).
463463
- **Transport (14 cases, `transport-cases.json`).** The `npm` and `python` transports `meta deps sync`
464464
uses to find an installed package: npm packages under a temp `node_modules`, Python packages on a
@@ -467,8 +467,7 @@ above: one committed `cases.json`, no per-port fixture, no ledger. The corpus ha
467467
the only writer of snapshots and the lock. `cases.json` also carries an `npm` and a `python`
468468
dependency loading from their committed snapshot with nothing installed, which both ports run.
469469

470-
Java, Kotlin and C# have no runner —
471-
Phase 1a is TypeScript + Python only; those three ports arrive in Phase 2.
470+
C# has no runner yet; it arrives in a later Phase 2 slice.
472471

473472
### `fixtures/shared-model-conformance/` (11 cases)
474473

‎docs/features/cli.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ command surface splits in two:
3333
| **Template/prompt drift** (`verify --templates`) | **Node `meta`** | `meta verify --templates` | TS reference (ADR-0021 D2) — `{{field}}`↔payload; part of the bare-`verify` default |
3434
| **Vocabulary upgrade** (`upgrade`) | **Node `meta`** | `meta upgrade [--to <version>] [--apply]` | **any backend** — rewrites RETIRED metadata vocabulary (`@violation` → `@counterexample`, `@readOnly` → `@mutability`, dropping `@verifiedBy`) and resolves ATTRIBUTE CONTRADICTIONS (`@fields` beside `@expr` on an index key). Node-only because it edits the metadata documents themselves, which every port shares; a non-TS project runs `npx meta upgrade` against its own `metaobjects/`. **Canonical JSON and YAML alike.** Previews by default. Retirements needing a human decision are refused and the run exits non-zero, so CI cannot record a partial migration as finished |
3535
| **Vocabulary search** (`types`) | **Node `meta`** | `meta types [query]` | **any backend** — apropos/`kubectl explain` over the live metamodel registry (names + descriptions + when-to-use); the vocabulary is cross-port identical (registry-conformance) |
36-
| **Dependency sync** (`deps`) | **Node `meta`** | `meta deps sync \| check \| list` | **any backend** — resolves a declared metadata dependency (`path`, or an installed `npm` / `python` package) into a committed snapshot + lock (FR-023), so `sync`/`check`/`list` themselves stay Node-only regardless of your server language. TypeScript and Python then LOAD that snapshot at every rung of their own source ladder — the two ports that implement dependency resolution in Phase 1a; Java, Kotlin, and C# don't read `dependencies` yet (Phase 2). On a project whose own metadata Node `meta` cannot read (a Maven `src/main/resources/metadata` directory, a C# metadata directory, or another port's vocabulary), `sync` and `check` prove the locked dependencies load together and say that the port's own `verify` is the full check. See [`metadata-dependencies.md`](metadata-dependencies.md) |
36+
| **Dependency sync** (`deps`) | **Node `meta`** | `meta deps sync \| check \| list` | **any backend** — resolves a declared metadata dependency (`path`, or an installed `npm` / `python` package) into a committed snapshot + lock (FR-023), so `sync`/`check`/`list` themselves stay Node-only regardless of your server language. TypeScript, Python and Java then LOAD that snapshot at every rung of their own source ladder (Kotlin loads through Java's loader and Maven plugin); C# doesn't read `dependencies` yet (Phase 2). On a project whose own metadata Node `meta` cannot read (a Maven `src/main/resources/metadata` directory, a C# metadata directory, or another port's vocabulary), `sync` and `check` prove the locked dependencies load together and say that the port's own `verify` is the full check. See [`metadata-dependencies.md`](metadata-dependencies.md) |
3737
| **Canonical format** (`fmt`) | every port | `meta fmt` / `dotnet meta fmt` / `mvn metaobjects:fmt` / `metaobjects fmt` | (#304) ships in **every** port — the canonical serializer already exists in all five, so formatting is local, not Node-only. `--check` lists non-canonical files and exits non-zero without changing anything. Formats each file STANDALONE — own-mode, declared-here layer only (ADR-0039); an `extends` onto another file's base is preserved as-is, never resolved or erred on; a file declaring `overlay: true` anywhere — whether or not a same-file base exists — is reported as skipped rather than merged (merging would drop the overlay marker, a structural change fmt never makes). A YAML file is always skipped — no canonical YAML emitter exists (ADR-0006). Before writing, every port reloads the whole project with the candidate swapped in and refuses the write unless the reloaded model's canonical form is byte-identical to the untouched baseline — fmt never changes meaning. See [Fixture corpus](#meta-fmt--canonical-formatting-304) below and `fixtures/fmt-conformance/README.md` |
3838
| TS codegen | Node `meta` | `meta gen` | TS projects. **No `--template-spec` flag, deliberately** — `metaobjects.config.ts` already takes generator VALUES, so a declarative template generator is declared there (`templateGenerator()`, or `templateSpecToGenerators(parseTemplateSpec(spec))` to reuse a C#/Python spec file). Keeping it in the config is what lets `meta verify --codegen` regenerate WITH it, since that gate re-runs the config's generator list; see [declarative template scopes](codegen-concepts.md#declarative-template-scopes) |
3939
| C# codegen | `dotnet meta` | `dotnet meta init` / `gen` / `verify --templates` / `verify --codegen` | a .NET tool (`ToolCommandName=dotnet-meta`); invoked `dotnet meta` so it never shadows the Node `meta`; ships the ADR-0021 D2 subverbs (`--db` rejected, exit 2; bare `verify` = `--templates` plus `--codegen` when an output directory (`csharp.outDir` in `.metaobjects/config.json`, or `--out`) and `codegen/Generators.cs` are present). **The generator list is `codegen/Generators.cs`** (ADR-0034 Amendment 9): `dotnet meta init` writes it with `codegen/Program.cs` (two lines that run it) and `codegen/Codegen.csproj`, and `gen` / `verify --codegen` always run it through `dotnet run --project codegen`. With no `codegen/Generators.cs` they exit 2 and write nothing; `--generators` only narrows the list to declared entries. Every entry may set its own output directory (`ApiDocsGenerator { OutDir = ... }`), and `verify --codegen` compares each one. A declarative Mustache template-spec (the cross-port JSON contract shared with Python) is one more entry, `TemplateSpecGenerator { Spec = "<json>", TemplateRoot = "<dir>" }`; `gen` no longer reads `--template-spec` or a project-root `template-spec.json`, and a run that finds either with no such entry fails before writing anything; see [declarative template scopes](codegen-concepts.md#declarative-template-scopes). `dotnet meta docs` was removed in 1.1.0: it prints the line that points at [the migration section](migrations/docs-are-generators.md#c) and exits 2 |

0 commit comments

Comments
 (0)