Repository navigation
feat: check shared model dependencies against publisher in Python and C# - #537
Merged
Merged
Conversation
…23 Phase 2, S2+S7) metaobjects deps check / verify --deps (Python) and dotnet meta verify --deps (C#) re-resolve each dependency's path, hash the publisher's artifact and compare with deps.lock.json: current, drifted or unresolved, with ERR_DEPENDENCY_UPSTREAM_DRIFT. Both run the 11 expectCheck cases of fixtures/dependency-conformance.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What Changed
metaobjects deps checkandmetaobjects verify --deps(Python), anddotnet meta verify --deps(C#). Each re-resolves a dependency'spath, validates the publisher'smetaobjects.pkg.json, hashes the artifact, and compares it with.metaobjects/deps.lock.json. Results arecurrent,driftedorunresolved; drift or unresolved exits non-zero withERR_DEPENDENCY_UPSTREAM_DRIFT.pathtransport is resolved.npmandpythondependencies reportunresolvedand point to the Nodemeta deps check. The Nodemeta deps syncremains the only writer of the lock and snapshot. A bareverifydoes not run the check; it is opt-in via--deps.fixtures/dependency-conformance/expectCheckcases across Python and C# (11 cases), with new CLI tests and updated docs (docs/features/metadata-dependencies.md,docs/features/cli.md,docs/ports/python.md,docs/ports/csharp.md,docs/CONFORMANCE.md) and a CHANGELOG entry.Validation
Risk Assessment
✅ Low: Read-only opt-in dependency check in Python and C# mirrors the TS reference; the fix-round corrections are verified against the code and covered by tests that would fail on the old behavior.
Testing
Drove the shared-model dependency check live in Python and C# on disposable projects built from the conformance corpus. Current, drifted, unresolved (no lock, not in lock) and corrupt non-UTF-8 manifest scenarios all report the documented state and exit codes, with no crash. Targeted Python and full C# suites pass. The full Python suite has 19 errors from the default env missing the
integrationextra (fastapi); those pass with--extra integration. Baseline TS checks were already green.metaobjects deps check(Python) anddotnet meta verify --deps(C#) over fresh temp projects built from the corpus cases, with per-scenario CLI transcripts.Pipeline
Updates from git push no-mistakes
✅ **Intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 2 issues found → auto-fixed ✅
server/csharp/MetaObjects.Cli/Program.cs:448- The docs say thatdotnet meta verify --depsreports a declared but not-yet-synced dependency asunresolved'rather than as a stale snapshot', with theERR_DEPENDENCY_UPSTREAM_DRIFTexit. The code does not do that.RunDepsGateprints the unresolved line and returns 1. The run then reachesResolveMetadataDirOrExit, andVerifySnapshotthrowsERR_DEPENDENCY_SNAPSHOT_STALE('no deps.lock.json' or 'has no entry for it'). That path prints the stale error and callsEnvironment.Exit(2), which skips theMath.Max(..., depsExit)aggregation. Concrete case: the corpus casecheck-a-dependency-with-no-lock-file-is-unresolvedprintsacme-common: unresolvedand thenerror: ERR_DEPENDENCY_SNAPSHOT_STALE ..., and exits 2, not 1. The testVerify_deps_reports_a_dependency_not_yet_synced_as_unresolved_not_staleonly asserts NotEqual(0) and that 'unresolved' appears, so it passes either way. Narrowest remedy: correct the wording to say the check reports it as unresolved first, and the load still refuses the stale snapshot with exit 2. Other sites with the same claim: CHANGELOG.md:43-44 ('reported as such rather than as a stale snapshot'), docs/features/metadata-dependencies.md:382-385, docs/ports/csharp.md:124-125 ('the same ERR_DEPENDENCY_UPSTREAM_DRIFT exit'). Alternative: make a--deps-only run returndepsExitwhen the snapshot resolve fails, so the behavior matches the docs.server/python/src/metaobjects/config/dependency_check.py:83-_read_manifestcallsmanifest_path.read_text(encoding="utf-8")underexcept OSErroronly. If a publisher'smetaobjects.pkg.jsonis not valid UTF-8 (corrupt or binary), the call raisesUnicodeDecodeError, which is aValueErrorand not anOSError. Nothing incheck_dependenciesor_run_deps_checkcatches it, sometaobjects deps check/verify --depscrash with a traceback instead of reportingunresolved. TS (readFileutf8) and C# (File.ReadAllText) replace bad bytes, so the JSON parse fails and both reportunresolved. Fix: catchUnicodeDecodeErrorthere too, or read bytes and decode inside the existingValueErrorhandler, and report it as 'is not valid JSON'.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
scripts/ci-local.sh --only ts-fast --only ts-unit --strict-toolchainsuv run --quiet pytest -q tests/codegen/test_cli_deps_check.py tests/conformance/test_dependency_conformance.py(50 passed)dotnet testin server/csharp (Conformance 2319 passed, Cli.Tests 369 passed, Codegen.Tests 1301 passed, 1 skipped)uv run --quiet pytest -q --ignore=tests/integration --ignore=tests/codegen/test_report_credential.py(4346 passed, 5 skipped, 19 errors from missing fastapi/integration extra)uv run --quiet --extra integration pyteston test_duration_codegen, test_cli_deps_check, test_dependency_conformance (72 passed); test_tph_m2m_generated and test_report_credential (32 passed with--all-extras --group dev)A live driver materialised corpus cases into fresh temp projects and ran the realmetaobjects deps check(Python) anddotnet MetaObjects.Cli.dll verify --deps --no-field-lint(C#)Live scenario 1 (current): both reportacme-common: current, exit 0Live scenario 2 (drifted): both report drifted with ERR_DEPENDENCY_UPSTREAM_DRIFT, exit 1Live scenario 3 (no lock file): Python exit 1 with unresolved line; C# prints unresolved then ERR_DEPENDENCY_SNAPSHOT_STALE and exits 2, matching the corrected wordingLive scenario 4 (dependency not in lock): Python exit 1; C# unresolved then stale-snapshot exit 2Live scenario 5 (non-UTF-8 manifest): Python and C# both reportis not valid JSON, exit 1, no traceback✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.