Skip to content

feat(ts): port binaryCid + targetProofCid + sourceContractCid + EvidenceTerm to TypeScript kit#17

Merged
TSavo merged 1 commit into
mainfrom
feat/ts-cross-impl-binary-cid-target-proof-cid-source-contract-cid-evidence
May 2, 2026
Merged

feat(ts): port binaryCid + targetProofCid + sourceContractCid + EvidenceTerm to TypeScript kit#17
TSavo merged 1 commit into
mainfrom
feat/ts-cross-impl-binary-cid-target-proof-cid-source-contract-cid-evidence

Conversation

@TSavo
Copy link
Copy Markdown
Owner

@TSavo TSavo commented May 2, 2026

Closes a cross-impl conformance gap. The Rust reference implementation carries three protocol fields the TS kit was not modeling on the wire. This PR ports them to the TS kit at the parser/emitter/canonicalizer level so byte-for-byte JCS output can match Rust output for the same logical input.

Field-by-field

binaryCid (.proof catalog)

Spec: protocol/specs/2026-04-30-proof-file-format.md (supply-chain anchor rule).

  • Where it landed:
    • implementations/typescript/src/proofEnvelope/index.ts: added optional binaryCid to ProofEnvelopeInput and DecodedProofCatalog; threaded through the unsigned body so it is part of the signed payload (tampering breaks the catalog signature); decoded back out; added back to the signing payload during verifyProofEnvelope so signatures continue to validate when the field is set.
  • Stored or enforced? Stored + canonicalized + signed (so it is JCS-deterministic and tamper-evident). Not enforced: verifyProofEnvelope does not yet take a runningBinaryHash argument and check hash(running) == binaryCid. That wiring is out of scope here and called out below.
  • Cross-impl JCS golden added? Yes, TS-side determinism golden in proofEnvelope/index.test.ts (emits deterministic bytes when binaryCid is set). It pins TS-vs-TS byte-equality and shape (blake3-512:[0-9a-f]{128}), and asserts that setting binaryCid changes the catalog CID (proof the field is in the signed payload, not silently dropped). Rust-side fixture with binaryCid populated is a follow-up; the brief did not allow touching implementations/rust/.

targetProofCid (BridgeDeclaration)

Spec: protocol/specs/2026-04-30-ir-formal-grammar.md (PR #10 promoted the attack-prevention example to normative).

  • Where it landed:
    • implementations/typescript/src/ir/symbolic/property.ts: added optional targetProofCid to BridgeDeclaration and BridgeSpec; threaded through bridge(...).
    • implementations/typescript/src/ir/grammar/parse.ts: added to BRIDGE_DECL_OPTIONAL_KEYS; parser slots it after targetContractCid per the spec-locked order; strict-mode key-order check enforces the slot only when the field is present; emitter emits it in the locked position.
    • implementations/typescript/src/ir/extensions/bridges.ts: boy-scout, PrimitiveBridgeInput and PrimitiveBridgeDeclaration also expose the field so V8/ECMA-262-style kit authors can carry it through the in-process registry.
  • Stored or enforced? Stored + canonicalized. Not enforced: the TS bridge enforcement pipeline (src/verifier/bridgeEnforcement.ts -> resolveBridgeTarget) currently resolves bridges by targetContractCid only. Pinning resolution to a specific .proof bundle CID, which is the whole point of the field per PR spec: promote targetProofCid attack-and-mitigation to normative example #10's normative attack-prevention example, is a verifier change beyond cross-impl wire conformance and is left as follow-up.

sourceContractCid (BridgeDeclaration)

Spec: same 2026-04-30-ir-formal-grammar.md v1.4 grammar.

  • Where it landed: same files as targetProofCid, slotted between sourceLayer and targetContractCid per spec lock order.
  • Stored or enforced? Stored + canonicalized. Not enforced: the verifier does not yet discharge VerifyContractImplication(sourceContractCid, targetContractCid); that is verifier-pipeline work, not wire-conformance work.

EvidenceTerm IR variant

  • Where it landed: already present in TypeScript before this PR.
    • Type: implementations/typescript/src/ir/formulas.ts (EvidenceTerm, EvidenceCertificate).
    • Parser/emitter: implementations/typescript/src/ir/grammar/parse.ts (parseEvidenceValue, emitEvidence).
    • Carrier: ContractDeclaration.evidence? in src/ir/symbolic/property.ts.
    • Documented in src/ir/invariants.ts.
  • Conformance check: TS shape {kind: "evidence", proofType, certificate: {tool, version, formulaHash, proofData}} matches the Rust EvidenceTerm and EvidenceCertificate (provekit-ir-types/src/lib.rs:9-15 and provekit-ir-symbolic/src/lib.rs:300-329) byte-for-byte under JCS. Rust serializer at provekit-ir-symbolic/src/serialize.rs:29-48 confirms the same key order. No port needed; conformance verified by reading both sides.

Required-vs-optional choice for the bridge fields

Spec (2026-04-30-ir-formal-grammar.md lines 275-285) lists sourceContractCid and targetProofCid as required. Rust provekit-ir-types lib has them non-optional. The brief explicitly said "add the three optional fields" because every existing TS bridge fixture, peer-kit .proof fixture from C++/Go/Rust kit-out v1.1.0 directories, and bridges.test.ts case lacks them. Making them required in TS today would cascade-break peer-kit cross-lang tests that this PR is meant to keep green.

The chosen scope cut: parse and emit them as optional in TS, document in the doc-comment + parser code that they are normatively required by the v1.4 grammar, and flag promotion to required as follow-up coordinated with peer-kit fixture migration.

Tests

7 new tests added; all 742 tests pass (was 735 before this PR).

  • implementations/typescript/src/ir/grammar/parse.test.ts:
    • parses a v1.4 bridge with both new pins set and emits byte-identical output (round-trip).
    • rejects strict-mode bridge with pins in the wrong slot order.
    • accepts a v1.1.0-shape bridge that omits the new pins (backwards-compat).
  • implementations/typescript/src/proofEnvelope/index.test.ts:
    • threads binaryCid through build -> decode round-trip.
    • verifyProofEnvelope passes when binaryCid is set and untampered.
    • setting binaryCid changes the catalog CID (proof the field is in the signed payload).
    • emits deterministic bytes for a known input with binaryCid set (golden fingerprint).

Known follow-ups (called out for reviewers, not part of this PR)

  1. binaryCid enforcement: wire verifyProofEnvelope to take a running-binary hash and reject on mismatch per spec section 5 rule 7.
  2. targetProofCid enforcement: change resolveBridgeTarget in the bridge enforcement pipeline to pin by .proof bundle CID when the field is set, per PR spec: promote targetProofCid attack-and-mitigation to normative example #10's normative attack example.
  3. sourceContractCid enforcement: discharge VerifyContractImplication(sourceContractCid, targetContractCid) during bridge enforcement.
  4. Cross-impl byte-equality with Rust: the TS golden in proofEnvelope/index.test.ts is TS-vs-TS only. Rust-side fixture with binaryCid populated needs to be minted and pinned to the same hex; could not be done in this PR per the no-touch-Rust constraint.
  5. Promote optional -> required: once peer-kit fixtures migrate to the v1.4 bridge shape, flip the two new fields from optional to required in TS strict mode.

Pre-existing CI surface (not introduced here)

pnpm exec tsc --noEmit reports pre-existing errors in src/ir/invariants.ts and src/ir/invariants.test.ts that reference symbols (Num, StrConst, Var, property) not exported by the modules they import from. These are unrelated to this PR; CI runs pnpm test (vitest), not tsc --noEmit, and all 742 vitest tests pass.

Test plan

  • pnpm test passes (742 passed, 2 skipped, 4 todo)
  • Existing parse.test.ts and proofEnvelope/index.test.ts cases all green
  • New strict-mode key-order test covers the spec lock order
  • No em-dashes / en-dashes in any line added by this PR
  • Follow-up: mint Rust-side .proof fixture with binaryCid set and assert TS bytes equal Rust bytes for the same logical input
  • Follow-up: enforcement wiring per the four items above

Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

Brings TypeScript kit to v1.4 cross-impl conformance with the Rust
reference for three protocol fields surfaced in v1.3.0 / PR #10:

  binaryCid (.proof catalog, proof-file-format spec)
    Optional supply-chain back-pin to the compiled binary the bundle
    attests. Threaded through ProofEnvelopeInput, build, decode, and
    the catalog signing payload (so tampered pins break the catalog
    signature). Verifier accepts and surfaces the field; running-binary
    equality is documented as a follow-up.

  sourceContractCid + targetProofCid (BridgeDeclaration, ir-formal-grammar spec)
    Optional in this TS parser to remain backward-compatible with
    v1.1.0 peer-kit fixtures during migration. Spec lock order
    [kind, name, sourceSymbol, sourceLayer, sourceContractCid?,
    targetContractCid, targetProofCid?, targetLayer, notes?] enforced
    in strict mode in both parser and emitter. Surfaced in the kit
    authoring API (bridge() in property.ts) and the in-process
    primitiveBridge() registry.

  EvidenceTerm
    Already present in TypeScript (src/ir/formulas.ts +
    src/ir/grammar/parse.ts emitEvidence/parseEvidenceValue). Shape
    matches the Rust EvidenceTerm byte-for-byte under JCS. No port
    needed; conformance verified by inspection.

Adds 7 new tests:
  parse.test.ts: bridge round-trip with new pins, strict-mode key
  order rejection, v1.1.0-shape backwards-compatibility.
  proofEnvelope/index.test.ts: binaryCid round-trip, signature
  inclusion (CID changes when pin set), determinism golden.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 2, 2026 16:35
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

Warning

Rate limit exceeded

@TSavo has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 46 minutes and 24 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e040c3a0-87ff-4072-94f7-e4a679d886bd

📥 Commits

Reviewing files that changed from the base of the PR and between ede9dce and 83260e6.

📒 Files selected for processing (6)
  • implementations/typescript/src/ir/extensions/bridges.ts
  • implementations/typescript/src/ir/grammar/parse.test.ts
  • implementations/typescript/src/ir/grammar/parse.ts
  • implementations/typescript/src/ir/symbolic/property.ts
  • implementations/typescript/src/proofEnvelope/index.test.ts
  • implementations/typescript/src/proofEnvelope/index.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ts-cross-impl-binary-cid-target-proof-cid-source-contract-cid-evidence

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 46 minutes and 24 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@TSavo TSavo merged commit eb96685 into main May 2, 2026
4 of 6 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ports additional protocol fields into the TypeScript kit to close a cross-implementation wire-format conformance gap (so TS can emit/parse/canonicalize the same JCS/CBOR bytes as Rust for equivalent logical inputs).

Changes:

  • Adds optional binaryCid support to .proof envelope build/decode/verify signing payloads.
  • Extends BridgeDeclaration modeling + IR grammar parser/emitter to carry sourceContractCid and targetProofCid in spec-locked key order (strict mode enforced when present).
  • Adds/updates unit tests covering round-trip, strict key order, and determinism fingerprints.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
implementations/typescript/src/proofEnvelope/index.ts Threads binaryCid through unsigned catalog body so it’s signed and survives decode/verify.
implementations/typescript/src/proofEnvelope/index.test.ts Adds tests for binaryCid round-trip, signature verification, CID impact, and determinism.
implementations/typescript/src/ir/symbolic/property.ts Extends BridgeDeclaration / BridgeSpec with optional sourceContractCid + targetProofCid.
implementations/typescript/src/ir/grammar/parse.ts Adds new bridge optional keys; enforces strict key slot order; emits in spec-locked order.
implementations/typescript/src/ir/grammar/parse.test.ts Adds strict-mode tests for v1.4 pins + backwards-compat behavior.
implementations/typescript/src/ir/extensions/bridges.ts Extends primitive bridge records/inputs to carry the new bridge pin fields.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +45 to +47
* omit it. The verifier discharges
* `VerifyContractImplication(sourceContractCid, targetContractCid)`
* when both sides are present.
? { targetProofCid: input.targetProofCid }
: {}),
targetLayer: input.targetLayer,
...(input.notes ? { notes: input.notes } : {}),
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants