Skip to content

feat(ts): cross-impl golden tests against fixtures.toml#68

Closed
TSavo wants to merge 2 commits into
mainfrom
feat/rust-ts-byte-equality-golden
Closed

feat(ts): cross-impl golden tests against fixtures.toml#68
TSavo wants to merge 2 commits into
mainfrom
feat/rust-ts-byte-equality-golden

Conversation

@TSavo
Copy link
Copy Markdown
Owner

@TSavo TSavo commented May 2, 2026

Summary

  • Adds cross-impl-golden.test.ts under implementations/typescript/src/canonicalizer/
  • Loads conformance/fixtures.toml (Rust-emitted canonical JCS bytes + BLAKE3-512 hashes) at test time
  • Constructs equivalent IrFormula inputs for each formula-level fixture
  • Runs the TS canonicalizer pipeline and asserts byte-identical JCS output against the Rust golden
  • Also asserts BLAKE3-512 hash identity

Purpose

PR #17 (TS cross-impl port) noted "TS golden is TS-vs-TS only -- Rust-side byte-equality fixture needs minting." This test consumes the authoritative fixtures.toml so TS verifies against Rust-emitted canonical bytes.

Currently the 4 formula-level tests fail, revealing structural gaps between the TS canonicalizer and the Rust reference:

  • de Bruijn indices vs named variables (Rust preserves names)
  • implies removal + NNF (TS rewrites; Rust preserves original form)
  • argument sorting on equality (TS sorts; Rust preserves input order)
  • sort fields on ctor nodes (TS adds sort: Ref; Rust omits)

The test serves as the cross-impl gap detector. Fixing these gaps is follow-up work.

No files outside the new test file were modified.

TSavo added 2 commits May 2, 2026 14:23
- provekit/lift/rspec: Pattern 1 bounded loop → forall quantifier,
  Pattern 3 multi-expect → characterization conjunction
- provekit/lift/dry_validation: walks dry-validation schemas,
  maps filled?, gteq?, lteq?, min_size?, size?, format?, one_of
  to canonical IR formulas
- Both emit JCS-alphabetical IR via Provekit::IR::Jcs
Add cross_impl_golden_test that loads conformance fixtures (Rust-emitted
JCS bytes + BLAKE3-512 hashes) and asserts TS canonicalizer produces
byte-identical output for every formula-level fixture.

Currently reveals structural gaps: TS applies de Bruijn indexing,
implies removal, NNF, argument sorting, and sort-field additions on
ctrs that differ from the Rust canonical reference. The test serves as
the cross-impl byte-equality gap detector.
Copilot AI review requested due to automatic review settings May 2, 2026 21:40
@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 47 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: ee87e1c1-d2f6-4e45-8bac-3392bfc67760

📥 Commits

Reviewing files that changed from the base of the PR and between 8399b4d and d0b39af.

📒 Files selected for processing (3)
  • implementations/ruby/lib/provekit/lift/dry_validation.rb
  • implementations/ruby/lib/provekit/lift/rspec.rb
  • implementations/typescript/src/canonicalizer/cross-impl-golden.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/rust-ts-byte-equality-golden

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 47 seconds.

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

@TSavo
Copy link
Copy Markdown
Owner Author

TSavo commented May 2, 2026

Stale-base PR: 1122 line deletions vs current main, would revert PR #67's Python pin work + v1-3-fields-probe Rust binary. Cherry-picked the legitimate cross-impl-golden.test.ts into the rebased PR.

@TSavo TSavo closed this May 2, 2026
TSavo added a commit that referenced this pull request May 2, 2026
…ebased

feat(ts): cross-impl golden tests against fixtures.toml (rebased from #68)
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d0b39af3b4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +223 to +225
expect(actualJcs, `JCS byte mismatch for "${fixture.name}"`).toBe(
fixture.jcs,
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Gate golden assertions until canonical shapes match

These assertions compare serializeCanonicalAst(formulaToCanonicalAst(...)) against fixture bytes that still contain pre-canonical structure (for example pattern1_bounded_loop in conformance/fixtures.toml keeps named vars and an implies node), so this test will deterministically fail under the current TS pipeline (canonicalize.ts applies de-Bruijn conversion, implies removal, and NNF). As written, merging this commit will make the suite red rather than acting as an informational gap detector.

Useful? React with 👍 / 👎.

upper = inclusive ? IR.lte(v, hi_term) : IR.lt(v, hi_term)
ante = IR.and(lower, upper)

IR.forall(name: var_name, sort: IR::Sort.Int, body: ante)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve loop assertion in bounded-loop quantifier body

This builder returns forall with only the bounds antecedent as the body, so any lifted bounded-loop test drops the loop’s asserted property entirely. Pattern-1 lifting is expected to encode forall x. bounds(x) => assertion(x); emitting only bounds(x) produces a different (often unsatisfiable) contract and breaks semantic equivalence with the source test.

Useful? React with 👍 / 👎.

if key.filter_schema_dsl.respond_to?(:types)
types = key.filter_schema_dsl.types rescue []
type = types.first
opts[:type] = type&.primitive&.to_s if type&.respond_to?(:primitive)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use consistent key for inferred field type

Type inference stores the type under opts[:type], but build_formula reads opts["type"], so inferred sorts are never applied. This causes string-specific constraints (e.g., length checks and non-empty handling) to be skipped or mis-modeled because every field effectively falls back to Ref in type_to_sort.

Useful? React with 👍 / 👎.

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

Adds a TypeScript cross-implementation golden test that compares TS canonicalizer output against Rust-minted conformance/fixtures.toml bytes/hashes, and also introduces two new Ruby lift adapters.

Changes:

  • Add cross-impl-golden.test.ts to assert TS canonical JCS bytes + BLAKE3-512 hashes match Rust fixtures for formula-level fixtures.
  • Add Ruby RSpec “Layer 2” lift adapter that scans it blocks and lifts a couple of structural patterns into IR contracts.
  • Add Ruby dry-validation lift adapter that attempts to lift schema predicates into IR preconditions.

Reviewed changes

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

File Description
implementations/typescript/src/canonicalizer/cross-impl-golden.test.ts Loads conformance/fixtures.toml and asserts TS canonicalizer output matches Rust golden bytes + hashes.
implementations/ruby/lib/provekit/lift/rspec.rb New Ruby lift adapter for RSpec test files (pattern-based lifting).
implementations/ruby/lib/provekit/lift/dry_validation.rb New Ruby lift adapter for dry-validation schemas (predicate extraction + formula building).

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

Comment on lines +1 to +6
# SPDX-License-Identifier: Apache-2.0
#
# ProvekIt RSpec Layer 2 lift adapter.
#
# Walks RSpec test files and lifts structural patterns to canonical IR:
# Pattern 1 — bounded loop as universal quantifier
Comment on lines +150 to +155
lower = IR.gte(v, lo_term)
upper = inclusive ? IR.lte(v, hi_term) : IR.lt(v, hi_term)
ante = IR.and(lower, upper)

IR.forall(name: var_name, sort: IR::Sort.Int, body: ante)
end
Comment on lines +103 to +110
def self.build_formula(field, opts)
sort = type_to_sort(opts["type"])
v = IR.var(name: field)
formulas = []

# Required / filled
formulas << IR.neq(v, sort == IR::Sort.String ? IR.str("") : IR.num(0)) if opts["required"]

end

decls
rescue => e
Comment on lines +123 to +124
const allFixtures = parseFixturesToml(readFileSync(fixturesPath, "utf8"));

Comment on lines +207 to +215

describe("cross-impl golden: TS canonicalizer vs Rust-emitted fixtures", () => {
it.runIf(nonFormulaFixtures.length > 0)(
`skipped ${nonFormulaFixtures.length} non-formula fixture(s): ${nonFormulaFixtures.map((f) => f.name).join(", ")} (contract/bridge declarations are not formula-level)`,
() => {
// informational only
},
);

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