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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ loading. A port that reports `1.2` does not know that vocabulary; upgrade every
`Dependencies.check`, `Dependencies.SnapshotReader`, `DependencySet.ofSnapshot` and a
`MetaDataLoader.fromUris` overload that takes a `DependencySet`. See `docs/features/metadata-dependencies.md`.

- **Python and C# check a shared model against its publisher (FR-023 Phase 2).** `metaobjects deps
check`, `metaobjects verify --deps` (Python) and `dotnet meta verify --deps` (C#) re-resolve each
declared dependency's `path`, read the publisher's `metaobjects.pkg.json`, hash the artifact and
compare with `deps.lock.json`, with the same three states as `meta deps check` (`current`,
`drifted`, `unresolved`) and the same `ERR_DEPENDENCY_UPSTREAM_DRIFT` exit for anything else.
Both run the 11 `expectCheck` cases of `fixtures/dependency-conformance/`. The check writes
nothing, is never part of a bare `verify`, and resolves the `path` transport only: an `npm` or
`python` dependency reports `unresolved` and names the Node `meta deps check`. In C# it runs
before the metadata loads, so a dependency declared but not yet synced is reported `unresolved`
first (the check exits 1); the load that follows still refuses the missing or stale snapshot with
`ERR_DEPENDENCY_SNAPSHOT_STALE` and exit 2. The Node `meta deps sync` stays the only writer of the lock and the
snapshot. See [docs/features/metadata-dependencies.md](docs/features/metadata-dependencies.md).

- **A model explorer site, built by `docsSiteFile()`.** The docs site now shows what the
software does and how the model is designed: a main page with count tiles and the feature and
quality cards with their roll-ups, a model map with slices (package, requirement subtree,
Expand Down
14 changes: 8 additions & 6 deletions docs/CONFORMANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ regenerate with `ls -d fixtures/<corpus>/*/ | wc -l` for directory-shaped corpor
| [`fixtures/provider-composition-conformance/`](../fixtures/provider-composition-conformance/) | 18 (11 error-shape + 4 compose-load + 3 attr-ownership) | ✓ | ✓ | — (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/) | 37 cases (26 resolution + 11 check) + 14 transport cases | ✓ (reference implementation; all three arms) | ✓ (resolution arm, all 26; check arm, all 11) | inherits via Java | ✓ (resolution arm, all 26; no check, so the 11 check cases are not run) | ✓ (resolution arm, all 26 identically; no check yet, so the 11 check cases are not run; the transport arm is Node-only) |
| [`fixtures/dependency-conformance/`](../fixtures/dependency-conformance/) | 37 cases (26 resolution + 11 check) + 14 transport cases | ✓ (reference implementation; all three arms) | ✓ (resolution arm, all 26; check arm, all 11) | inherits via Java | ✓ (resolution arm, all 26; check arm, all 11, as `verify --deps`) | ✓ (resolution arm, all 26 identically; check arm, all 11, as `deps check` and `verify --deps`; 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 @@ -480,10 +480,12 @@ above: one committed `cases.json`, no per-port fixture, no ledger. The corpus ha
for it. Kotlin inherits the Java run through the same loader and Maven plugin.
- **Check (11 cases, `expectCheck`).** For each declared dependency, `current`, `drifted` or
`unresolved` (a missing path, a bad manifest, a hash mismatch, or not yet in the lock). Run
by TypeScript, in `cli/test/dependency-check-conformance.test.ts`, and by Java in
by TypeScript, in `cli/test/dependency-check-conformance.test.ts`, by Java in
`DependencyCheckConformanceTest` (the engine behind `metaobjects:verify -Dmeta.verify.mode=deps`;
Kotlin runs the same goal). Python has no `deps check` yet and filters these cases out. The arm
exists so that each port's check is written against the same edge cases (Phase 2, #482).
Kotlin runs the same goal), by **Python**, in `tests/conformance/test_dependency_conformance.py`
(`metaobjects deps check` and `verify --deps`), and by **C#**, in `DependencyConformanceTests`
(`dotnet meta verify --deps`). 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
Expand All @@ -494,8 +496,8 @@ above: one committed `cases.json`, no per-port fixture, no ledger. The corpus ha
**C#** (S6 of FR-023 Phase 2) runs the resolution arm on two rungs of the source ladder: the
neutral one (`Resolve(null, dir)`), and the explicit metadata directory a
`dotnet meta gen <metadataDir>` takes, where the case has one. Its runner is
`DependencyConformanceTests`; it skips the 11 check cases (C# has no `deps check` yet) and the
transport cases (C# never syncs).
`DependencyConformanceTests`; it runs the 11 check cases through `DependencyResolver.CheckDependencies`
(S7) and skips the transport cases (C# never syncs).

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

Expand Down
2 changes: 1 addition & 1 deletion docs/features/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ vocabulary everywhere, each port implementing the modes it supports.
| `verify --codegen` | **Codegen drift** — regenerate from metadata into a temp dir and fail if it differs from the committed generated output. Catches "metadata changed but `meta gen` wasn't re-run". A hand-edited generated file is NOT drift — `meta gen` three-way-merges hand edits by design, so the gate compares the *generated contribution* against the committed `.gen-state/.hashes.json` rather than the file byte-for-byte. It still LISTS every generated file carrying a hand edit (count + paths, and how to see the edit) as a notice that does not change the exit code; `--forbid-hand-edits` makes any hand edit fail the build, for teams that want generated code untouchable (Node `meta` only). | no |
| `verify --templates` | **Template/prompt drift** — `Renderer.verify` checks each `template.*` node's `{{field}}` references against its payload VO (FR-004). A Jinja body (Python and TypeScript, ADR-0061) is checked the same way. | no |
| `verify --docs` | **Removed in 1.1.0** (ADR-0034 Amendment 9). It prints where the check went and exits 2: documentation is written by entries in `generators`, so `verify --codegen` checks it with the rest of the declared output. | — |
| `verify --deps` | **Dependency drift** (FR-023) — re-resolves each declared dependency (its `path`, or its installed `npm` / `python` package) and compares its installed artifact's hash against `.metaobjects/deps.lock.json`, same comparison as `meta deps check`. Needs the publisher reachable, so it is never part of the bare-`verify` default. A `drifted` or `unresolved` dependency fails with `ERR_DEPENDENCY_UPSTREAM_DRIFT`. **Node `meta`; Java and Kotlin have the `path`-only counterpart `-Dmeta.verify.mode=deps`.** See [`metadata-dependencies.md`](metadata-dependencies.md). | no |
| `verify --deps` | **Dependency drift** (FR-023) — re-resolves each declared dependency (its `path`, or its installed `npm` / `python` package) and compares its installed artifact's hash against `.metaobjects/deps.lock.json`, same comparison as `meta deps check`. Needs the publisher reachable, so it is never part of the bare-`verify` default. A `drifted` or `unresolved` dependency fails with `ERR_DEPENDENCY_UPSTREAM_DRIFT`. **Node `meta`; Python (`metaobjects verify --deps`, plus `metaobjects deps check`), C# (`dotnet meta verify --deps`), and Java and Kotlin (`-Dmeta.verify.mode=deps`) have the `path`-only counterpart.** See [`metadata-dependencies.md`](metadata-dependencies.md). | no |

Rules of the contract:

Expand Down
19 changes: 17 additions & 2 deletions docs/features/metadata-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,16 @@ classifies those as breaking automatically — see [Deferred](#deferred).

## What fails at `meta deps check` / `verify --deps`

The check ships in TypeScript (`meta deps check`, `meta verify --deps`), Python (`metaobjects deps
check`, `metaobjects verify --deps`) and C# (`dotnet meta verify --deps`), against the same corpus
and with the same three states and the same `ERR_DEPENDENCY_UPSTREAM_DRIFT`. The Python and C#
check resolve the `path` transport only (see [Deferred](#deferred)). Python's `deps check`, like
TypeScript's, also loads the locked snapshots together once the hashes match; `verify --deps` is
the comparison alone in all three. Run `verify --deps` before `verify`'s own load: C# runs it
first, so a dependency that is declared but not yet synced is reported as `unresolved` (the
check exits 1). The load that follows still refuses the missing or stale snapshot with
`ERR_DEPENDENCY_SNAPSHOT_STALE` and exit 2.

`verify --deps` runs `meta deps check`'s comparison as one of `verify`'s gated
subverbs (never part of the bare default — it needs the publisher reachable, its
`path` or its installed package, which CI checking out only your own repo may not
Expand Down Expand Up @@ -702,6 +712,10 @@ but **not** built yet — do not assume any of the following exists:
runtime one.
- **Java, Kotlin, Python and C# as publishers** — Java, Kotlin and C# consume (S3 and S6);
publishing is TypeScript only.
- **`npm` and `python` transports in the Python and C# check.** Both ports' check resolves
`path` only; an `npm` or `python` dependency reports `unresolved` and names the Node `meta deps
check`, because resolving it needs the consumer's installed packages (a check that cannot check
must not pass).

## Verified by

Expand All @@ -712,8 +726,9 @@ but **not** built yet — do not assume any of the following exists:
resolution-time error above, run by TypeScript (the reference implementation),
Python and Java (Kotlin loads through the Java loader and Maven plugin, so it inherits the
corpus run and adds a codegen test that an imported entity emits nothing). 11 pin the upstream
check (`current`, `drifted`, `unresolved`), run by TypeScript and Java (Kotlin through the same
`metaobjects:verify` goal); Python has no check yet.
check (`current`, `drifted`, `unresolved`), run by TypeScript, Java (Kotlin through the same
`metaobjects:verify` goal), Python (`metaobjects deps check`, `verify --deps`) and C#
(`dotnet meta verify --deps`).
Three artifacts under `fixtures/dependency-conformance/artifacts/` are
pinned by sha256 in the README so the corpus itself can never silently drift.
Python's runner asserts all 26 resolution cases identically to TypeScript's, with no
Expand Down
10 changes: 10 additions & 0 deletions docs/ports/csharp.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ own metadata can `extends`, overlay or reference its nodes, but an imported node
does and does not do is in
[Metadata dependencies](../features/metadata-dependencies.md).

`dotnet meta verify --deps` asks whether the publisher has moved since you synced: it re-resolves
each dependency's `path`, reads the publisher's `metaobjects.pkg.json`, hashes the artifact beside
it and compares with the lock. `current`, `drifted` and `unresolved` (no directory, a bad
manifest, a hash that does not match, or no lock entry yet) are the same states and the same
`ERR_DEPENDENCY_UPSTREAM_DRIFT` exit as `meta deps check`. The check runs before the metadata
loads, so a dependency not yet synced is reported `unresolved` first; the load that follows still
refuses the missing or stale snapshot with `ERR_DEPENDENCY_SNAPSHOT_STALE` and exit 2. It never writes anything, it is never
part of a bare `verify`, and an `npm` or `python` dependency is reported `unresolved` (run the Node
`meta deps check` for those).

### Custom providers (optional)

When the project needs a subtype or an attribute the core does not ship, write a public class
Expand Down
11 changes: 11 additions & 0 deletions docs/ports/python.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,17 @@ metaobjects gen # runs every target's generators into its outDir
metaobjects verify # drift gate; bare verify runs --codegen, which regenerates the same list, and --templates
```

A model shared from another repository (`dependencies` in `.metaobjects/config.json`, synced by
the Node `meta deps sync`) asks one more question: has the publisher moved since you synced?
`metaobjects deps check` and `metaobjects verify --deps` re-resolve each dependency's `path`, hash
the artifact beside its `metaobjects.pkg.json` and compare with `.metaobjects/deps.lock.json`.
Each dependency is `current`, `drifted` or `unresolved` (no directory, a bad manifest, a hash that
does not match, or no lock entry yet); anything but `current` exits 1 with
`ERR_DEPENDENCY_UPSTREAM_DRIFT`, and a lock that cannot be read exits 2. `deps check` also loads
the locked snapshots together once the hashes match. Neither writes anything, `--deps` is never
part of a bare `verify`, and an `npm` or `python` dependency reports `unresolved` (run the Node
`meta deps check` for those). See [Metadata dependencies](../features/metadata-dependencies.md).

`verify --codegen` regenerates exactly the list `gen` runs and compares, so the two can
never disagree about what was generated. A target whose `generators` is empty writes
nothing and says so. With no `metaobjects.config.yaml` at all, `gen` and `verify --codegen`
Expand Down
14 changes: 8 additions & 6 deletions fixtures/dependency-conformance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,11 @@ climbs out of the package, and a Python module that is not a package are
(`sdk/test/dependency-conformance.test.ts`), the check arm
(`cli/test/dependency-check-conformance.test.ts`), and the transport arm
(`cli/test/dependency-transport-conformance.test.ts`).
- **Python** — resolution, load-time failure, lock/snapshot integrity. Not the check arm: Python
has no `deps check` yet, so its runner filters the `expectCheck` cases out. Not the transport
arm: Python never syncs.
- **Python** — resolution, load-time failure, lock/snapshot integrity, and the check arm
(`metaobjects deps check` and `metaobjects verify --deps`,
`tests/conformance/test_dependency_conformance.py`). Its check resolves the `path` transport
only; an `npm` / `python` dependency reports `unresolved` and points at the Node `meta deps
check`, which the corpus does not exercise. Not the transport arm: Python never syncs.
- **Java** — resolution, load-time failure, lock/snapshot integrity
(`DependencyConformanceTest`), the check arm (`DependencyCheckConformanceTest`, over
`Dependencies.check`, the engine of `metaobjects:verify -Dmeta.verify.mode=deps`), and the
Expand All @@ -254,9 +256,9 @@ climbs out of the package, and a Python module that is not a package are
- **C#** — the resolution arm: resolution, load-time failure, lock/snapshot integrity, on the
neutral source ladder and again through the explicit metadata directory (C# has no native
config surface, so `.metaobjects/config.json` is where a dependency is declared at every
rung). `inScope` is Python's formula, not TypeScript's. Not the check arm: C# has no
`deps check` yet (that is `verify --deps`), so its runner skips the `expectCheck` cases. Not the
transport arm: C# never syncs. The runner is
rung). `inScope` is Python's formula, not TypeScript's. Also the check arm
(`dotnet meta verify --deps`, through `DependencyResolver.CheckDependencies`), which like
Python's resolves the `path` transport only. Not the transport arm: C# never syncs. The runner is
`server/csharp/MetaObjects.Conformance.Tests/DependencyConformanceTests.cs`.

## Reference implementation
Expand Down
Loading
Loading