fix: NOD-002 envelope enforcement parity (TypeScript mirror) - #46
Merged
Conversation
added 9 commits
August 20, 2026 11:42
NOD-002 / ADR-025: cross-runtime ExecutionEnvelope enforcement parity.
The Python contracts.py is the source of truth; the TypeScript Zod schema
in @bodanglin/verdict-contracts mirrors it. This adds a verdict-node CI gate
that fails when the two runtimes disagree on the shared invalid-envelope
fixtures (1 valid + 13 invalid, byte-identical to verdict-core's
test_fixtures/envelopes/).
- test_fixtures/envelopes/*.json: canonical-shape fixtures copied verbatim
from verdict-core (eligibility_decision / execution_constraints, not the
divergent source_state / budget_usd shape an earlier draft used).
- scripts/envelope-parity-verdicts.mjs: emits JSON accept/reject verdicts
via the canonical Zod schema (parseContract('execution_envelope')).
- scripts/envelope_parity_verdicts.py: Python counterpart using
ExecutionEnvelope.from_dict.
- tests/contract-parity.test.ts: jest assertions mirroring Python
tests/test_envelope_parity.py (verdict + error substring per fixture).
- src/middleware/forwarder.ts: re-exports the canonical ExecutionEnvelope
type from @bodanglin/verdict-contracts.
- .github/workflows/ci.yml: new contract-parity job builds the contracts
package from verdict-core main and links it (the published npm release
may lag behind the source), then diffs TS vs Python verdicts and asserts
the fixture sets match verdict-core's canonical copy.
Paired with verdict-core PR #302 (Python source-of-truth enforcement fix).
… 24 for ESM - clean-install: now builds+links verdict-core contracts package before npm ci, so typecheck/lint/build/test all run against source-of-truth Zod schemas (which include execution_envelope). The published npm package v0.1.0 is stale. - contract-parity: Node version bumped to 24.x so --experimental-vm-modules supports synchronous ESM module loading (Jest 30 + ts-jest requires this). - Both jobs verified locally against rebuilt contracts dist; all 37 contract-parity tests pass.
- lint.yml now clones verdict-core, builds contracts package, links it, then runs npm run lint/format:check against source-of-truth schemas. - Bumps Node to 24.x for consistency with clean-install.
The canonical @bodanglin/verdict-contracts package is pure ESM (type: module). Jest 30 on Node 24 requires --experimental-vm-modules to synchronously load ESM dependencies via ts-jest. This updates the test script so all jest runs (clean-install, contract-parity, local) use the ESM entrypoint.
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.
NOD-002 / ADR-025 — TypeScript cross-runtime ExecutionEnvelope enforcement parity
The Python
contracts.pyis the source of truth; the TypeScript Zod schema in@bodanglin/verdict-contractsmirrors it. This PR adds the verdict-node side of the parity gate.What's here
test_fixtures/envelopes/*.json— 1 valid + 13 invalid canonical-shape fixtures, byte-identical to verdict-core'stest_fixtures/envelopes/(canonical shape:eligibility_decision/execution_constraints, not the divergentsource_state/budget_usdshape from an earlier draft).scripts/envelope-parity-verdicts.mjs— emits JSON accept/reject verdicts via the canonical Zod schema (parseContract('execution_envelope')).scripts/envelope_parity_verdicts.py— Python counterpart usingExecutionEnvelope.from_dict.tests/contract-parity.test.ts— jest assertions mirroring Pythontests/test_envelope_parity.py(verdict + error substring per fixture).src/middleware/forwarder.ts— re-exports the canonicalExecutionEnvelopetype from@bodanglin/verdict-contracts..github/workflows/ci.yml— newcontract-parityjob: builds the contracts package from verdict-coremainandnpm links it (the published npm release may lag behind source), diffs TS vs Python verdicts, and asserts the fixture sets match verdict-core's canonical copy.Published-npm-lag note
The published
@bodanglin/verdict-contracts@0.1.0on npm predates theexecution_envelopeZod schema. The CI job therefore builds the contracts package from the verdict-coremaincheckout and links it, so the TS side always tests against the canonical (source-of-truth) schemas rather than a stale npm release. Locally validated withnpm linkagainst the rebuilt dist; all 37 contract-parity jest tests pass.Pairing
TypeScript counterpart to verdict-core PR #302 (
fix: NOD-002 envelope enforcement parity (Python source of truth)[closes #286]). PR #302's CI is fully green including its owntypescript-contract-parityjob.Pre-existing failures (not this PR's scope)
The
tests/middleware/streaming-field-preservation.test.tssuite has 8 flaky abort/timeout failures on cleanmasteras well (supertest timing), unrelated to envelope enforcement; this PR is scoped to envelope parity only.refs #286.