Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,30 @@ here.**
Phase 2 ([#482](https://github.com/metaobjectsdev/metaobjects/issues/482)) are written against.
The feature doc records the Maven and NuGet packaged transports as a design for a later slice.

- **`meta deps sync` installs a shared model from an npm or Python package, not only from a
folder path.** A dependency can now be `{ "name": "x", "npm": "@acme/model", "dir":
"metaobjects" }` or `{ "name": "x", "python": "acme_model", "dir": "metaobjects" }`: install
the publisher's package with your own package manager, then `meta deps sync` finds it (the
way Node resolves `@acme/model` from the directory holding `.metaobjects/`, or where
`importlib.util.find_spec` puts `acme_model` in your interpreter), applies `dir`, and
snapshots and locks it exactly as a `path` dependency. `meta deps check` and `verify --deps`
resolve the same way. The Python interpreter is the first of `$METAOBJECTS_PYTHON`, the
active virtualenv, a `.venv` beside `.metaobjects/`, and `python3`, and `sync` prints the
one it used. Before this both transports were accepted in config and refused by `sync` with
"not supported by this toolchain yet". Now a package that is not installed, a missing
interpreter, or a `dir` the package does not ship is `ERR_DEPENDENCY_UNRESOLVED` naming the
`npm install` / `pip install` fix, and a `dir` holding no manifest is
`ERR_DEPENDENCY_MANIFEST_INVALID`. `sync` warns when the installed package's version differs
from its manifest's (a release without regenerating the shared model). The lock format is
unchanged and records no host path or interpreter. Python already loaded such a dependency
from its committed snapshot; two new `dependency-conformance` cases prove both ports do, and
a new `transport-cases.json` arm (14 cases, Node only) pins the transports. On the publisher
side `sharedModelFile()`'s default version now also reads a `pyproject.toml` `[project]`
version, so a Python package stamps the version consumers install.
[docs/features/metadata-dependencies.md](docs/features/metadata-dependencies.md) gains the
two-step publish path for an npm and a Python package and a private-registry recipe (Gitea
and similar). `maven` / `nuget` stay Phase 2.

- **C# reads its generated-code directory from `.metaobjects/config.json`, so a plain
`dotnet meta verify` runs the codegen gate.** Set `"csharp": { "outDir": "Generated" }`
(relative to the directory holding `.metaobjects/`). `dotnet meta gen` writes there and
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ first-week wedge plan — and `meta init` picks up from there.
| Capability requirements (`requirement.*`) | `meta verify` gate + authoring lint; `requirementTests()` stubs | `mvn metaobjects:verify` gate; JUnit Jupiter `requirement-tests` | Gate via the Java Maven goal; JUnit Jupiter `requirement-tests` | `dotnet meta verify` gate; xUnit `requirement-tests` | `metaobjects verify` gate; pytest `requirement-tests` |
| Reporting vocabulary (`dimension` / `measure` / `segment` / `object.report`, FR-044) | Registered; a view-backed report becomes a SQL view in `meta migrate`, is read by `ObjectManager`, and gets generated read-only list routes and a TanStack list hook (no grid or form); the `cube-model` generator writes the vocabulary as Cube data-model files | Registered; OMDB reads a view-backed report; generates a read-only Spring controller, DTO, repository and filter allowlist | Registered (via Java); generates an Exposed table object, a row data class, a filter allowlist and a read-only Spring controller per view-backed report | Registered; generates a keyless EF Core row type, read-only routes and a filter allowlist per view-backed report | Registered; `ObjectManager` reads a view-backed report; generates a Pydantic row model, a read-only FastAPI router and a filter allowlist |
| Libraries (`libraries: [...]`) | Yes | Yes | Yes (via Java) | Yes | Yes |
| Metadata dependencies (`dependencies`) | Yes (`meta deps sync`, `path` transport) | Phase 2 | Phase 2 | Phase 2 | Yes (loads the synced snapshot) |
| Metadata dependencies (`dependencies`) | Yes (`meta deps sync`: `path`, `npm` and `python` transports) | Phase 2 | Phase 2 | Phase 2 | Yes (loads the synced snapshot) |
| Runtime metadata (ObjectManager-style) | Yes (`runtime-ts`) | Yes (OMDB) | Yes (via Java OMDB + Exposed) | Roadmap | Yes (ObjectManager) |
| React / Angular UI client (browser) | React: **published** (`@metaobjectsdev/react` + `@metaobjectsdev/tanstack`), codegen + runtime. Angular 18: **source-only by decision** ([ADR-0048](spec/decisions/ADR-0048-angular-tier-source-only.md)) — `@metaobjectsdev/angular` + `@metaobjectsdev/codegen-ts-angular` build in-repo on their own `0.6.x` line but are deliberately not on npm (`npm i @metaobjectsdev/angular` will 404) until they meet the ADR's promotion bar. Consume them from source. | Consumes TS client via REST | Consumes TS client via REST | Consumes TS client via REST | Consumes TS client via REST |
| Own a generator (`eject`) | Yes (`meta eject`) | Yes (`mvn metaobjects:eject`) | Yes (`mvn metaobjects:eject`) | Yes (`dotnet meta eject`) | Yes (`metaobjects eject`) |
Expand Down Expand Up @@ -261,8 +261,8 @@ sixth ships two libraries at their own stability labels:
`meta eject <library>`. See [`docs/features/libraries.md`](docs/features/libraries.md).

**Sharing a model across your own projects** *(the TypeScript toolchain publishes;
TypeScript, Python, Java and Kotlin projects consume, over a `path` dependency such as a sibling
checkout or submodule; C# arrives in Phase 2)* — one project publishes
TypeScript, Python, Java and Kotlin projects consume, from an installed npm or Python
package or over a `path` dependency such as a sibling checkout; C# arrives in Phase 2)* — one project publishes
part of its model (a common `Customer`, an audited base, a set of enums) with
`sharedModelFile()`, and another declares it in `dependencies`, syncs it into a
committed, hash-locked snapshot and builds on it with `extends` and references. When the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,16 @@ build on a shared model.** A project may declare `dependencies` in
`.metaobjects/config.json` and `meta deps sync` a publisher's metadata into a
committed snapshot — that snapshot loads BEFORE your own files, so a foreign
abstract resolves via `extends` and a foreign node re-opens via `overlay: true`
exactly like a local one. Two rules are specific to that boundary:
exactly like a local one. A dependency names one transport: `path` (a directory
relative to the directory holding `.metaobjects/`), `npm` (an installed npm
package, e.g. `{ "name": "acme-model", "npm": "@acme/model", "dir": "metaobjects" }`)
or `python` (an installed Python package by its import name, e.g.
`{ "name": "acme-model", "python": "acme_model", "dir": "metaobjects" }`). For
`npm`/`python`, install the package with the project's package manager first;
`meta deps sync` locates it, copies its shared model into the snapshot, and says
what to install when it is missing. Prefer the package transport over a `path` into
someone else's checkout when the publisher releases a package. Two rules are
specific to that boundary:

- **Say `overlay: true` on every amendment to a node you don't own.** Within one
project the parser merges a same-`(type, package::name)` redeclaration whether
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,13 @@ artifact is a contract whose bytes a cross-port corpus pins and whose hash
consumers verify, so everything a consumer checks stays in the package, in the two
functions the copy calls (`buildSharedModel`, `renderSharedModelFiles`). Do not
replace those calls: an unmodified copy publishes the same bytes as the packaged
generator. Only TypeScript can run it in Phase 1a. TypeScript, Python, Java and
generator. To publish through a package, point its `target` inside the package
(an npm package's directory listed in `files`; a Python package's directory shipped
as package data), run `meta gen`, then release the package as usual; consumers
declare an `npm` or `python` dependency on it. With no `version` option the
manifest takes the nearest `package.json` version, else a `pyproject.toml`
`[project]` version — pass `version` when neither is the package consumers install.
Only TypeScript can run it in Phase 1a. TypeScript, Python, Java and
Kotlin (through Java's loader and Maven plugin) can *consume* a dependency, and
only the TypeScript toolchain can *publish* one; C# does not read
`dependencies` yet (Phase 2).
Expand Down
20 changes: 13 additions & 7 deletions docs/CONFORMANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ regenerate with `ls -d fixtures/<corpus>/*/ | wc -l` for directory-shaped corpor
| [`fixtures/provider-composition-conformance/`](../fixtures/provider-composition-conformance/) | 9 (5 error-shape + 4 compose-load) | ✓ | ✓ | — (JVM registry via Java) | ✓ | ✓ |
| [`fixtures/source-resolution-conformance/`](../fixtures/source-resolution-conformance/) | 25 cases | ✓ (reference implementation) | ✓ | inherits via Java | ✓ | ✓ |
| [`fixtures/scope-conformance/`](../fixtures/scope-conformance/) | 10 cases | ✓ (reference implementation) | ✓ | inherits via Java | ✓ | ✓ |
| [`fixtures/dependency-conformance/`](../fixtures/dependency-conformance/) | 35 cases (24 resolution + 11 check) | ✓ (reference implementation; both arms) | ✓ (resolution arm, all 24; no check, so the 11 check cases are not run) | inherits via Java | — (Phase 2) | ✓ (resolution arm, all 24 identically; no check yet, so the 11 check cases are not run) |
| [`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) |
| [`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) |
| [`fixtures/agent-context-conformance/`](../fixtures/agent-context-conformance/) | 4 | ✓ (the emitter is TS-owned) | — | — | — | — |
| [`fixtures/metamodel-docs/`](../fixtures/metamodel-docs/) | 1 | ✓ (docs emit is TS-owned) | — | — | — | — |
Expand Down Expand Up @@ -440,17 +440,17 @@ also matches before a trailing newline. Kotlin has no runner of its own: it inhe
the Java loader. Each of those two guards is pinned by a test beside the corpus, since
the corpus asserts matches only and carries no invalid-pattern case.

### `fixtures/dependency-conformance/` (35 cases)
### `fixtures/dependency-conformance/` (37 cases + 14 transport cases)

All 35 cases → [features/metadata-dependencies.md](features/metadata-dependencies.md)
All 37 cases → [features/metadata-dependencies.md](features/metadata-dependencies.md)
(declaring a dependency, `meta deps sync`, the committed snapshot + lock, default
exclusion of imported metadata, overlay/extends across the boundary, every load-
and resolution-time failure, and the upstream check). File-shaped like `scope-conformance/`
above: one committed `cases.json`, no per-port fixture, no ledger. The corpus has two arms:
above: one committed `cases.json`, no per-port fixture, no ledger. The corpus has three arms:

- **Resolution (24 cases).** Every case's `expectFiles`/`expectImported`/`expectSelected`/
- **Resolution (26 cases).** Every case's `expectFiles`/`expectImported`/`expectSelected`/
`expectMigrateGoverned`/`expectLoadError` assertions. **TypeScript (the reference
implementation), Python and Java all run all 24, identically**, with no exemption. The two
implementation), Python and Java all run all 26, identically**, with no exemption. The two
overlay cases that need a view child as incidental content use `view.currency` (the one
concrete `view.*` subtype registered cross-port), not `view.text` — a prior revision used
`view.text`, which Python did not register then, and carried a since-discharged allowlist
Expand All @@ -460,6 +460,12 @@ above: one committed `cases.json`, no per-port fixture, no ledger. The corpus ha
by TypeScript only, in `cli/test/dependency-check-conformance.test.ts`; Python and Java have no
`deps check` yet and filter these cases out. The arm exists so that each port's check is
written against the same edge cases (Phase 2, #482).
- **Transport (14 cases, `transport-cases.json`).** The `npm` and `python` transports `meta deps sync`
uses to find an installed package: npm packages under a temp `node_modules`, Python packages on a
temp import path, the directory each resolves to, the exact lock written, and each refusal. Run by
Node only, in `cli/test/dependency-transport-conformance.test.ts`, because Node `meta deps sync` is
the only writer of snapshots and the lock. `cases.json` also carries an `npm` and a `python`
dependency loading from their committed snapshot with nothing installed, which both ports run.

C# has no runner yet; it arrives in a later Phase 2 slice.

Expand Down Expand Up @@ -586,7 +592,7 @@ files into a real Cube.

The fixtures in the nine corpora mapped above (metamodel 413 + yaml 16 + verify 37
+ render 16 + persistence 59 + api-contract 117 + source-resolution 25 + scope 10 +
dependency 35) each map to a feature doc, and so do the two requirement corpora, `shared-model-conformance` and the
dependency 37) each map to a feature doc, and so do the two requirement corpora, `shared-model-conformance` and the
`cube-model` corpus, whose case lists live in their own READMEs. None are orphaned today. The remaining
corpora in the totals table gate tooling contracts (registry manifests, provider
composition, agent context, docs emit) rather than user-facing metamodel behaviour,
Expand Down
Loading
Loading