Skip to content

feat(compiler): M7 5+-param HashMap-order port — @contract full byte parity - #175

Merged
arkadianet merged 2 commits into
mainfrom
feat/m7-hashmap-param-order
Jul 8, 2026
Merged

feat(compiler): M7 5+-param HashMap-order port — @contract full byte parity#175
arkadianet merged 2 commits into
mainfrom
feat/m7-hashmap-param-order

Conversation

@arkadianet

@arkadianet arkadianet commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Stacked on #166 (the M7 foundation). Merge #166 first.

What this is

Closes M7's one deferral: @contract templates with ≥5 named parameters now compile byte-identically to Scala instead of returning TooManyParamsForOrdering. This was deferred because Scala assigns each param's body ConstantPlaceholder index by JVM HashMap iteration order (not declaration order) once the param map exceeds 4 entries and upgrades from Map1..Map4 to a hash HashTrieMap.

The port (ergo-compiler/src/param_order.rs)

iteration_order_2_12: JVM String.hashCode (i32-wrapping 31*h+c over UTF-16) → Scala's Hashing.improve bit-mix → the 2.12 HashTrieMap 5-bit-slice trie walk (ascending buckets, sub-tries recursed in place, collisions bottoming out to insertion order). Reproduces the recon's bit-validated p5/p8 vectors exactly.

Scala version pinned: 2.12 (2.12.21) — confirmed empirically by running the ct oracle through scala-cli (it printed Compiling project (Scala 2.12.21, JVM 17)), matching the oracle's //> using scala 2.12 pragma and ergo-appkit. The 2.13 CHAMP order is kept test-only as the documented alternative.

Correctness discipline

  • ≥5-param vectors byte-matching the oracle: 4/4five_params + three new discriminating captures (five_hashorder, six_hashorder, eight_hashorder) whose HashTrieMap order differs from BOTH declaration and alphabetical (the 8-param one includes two real root-bucket hash collisions). All captured fresh from the ct verb (sigma-state 6.0.2 / Scala 2.12.21) — never self-oracled.
  • ≤4-param path untouched — declaration order preserved; all pre-existing ≤4 corpus vectors still byte-match.
  • Crucial invariant kept: constTypes/constValues/parameters/constantIndex stay declaration-ordered for ALL arities; ONLY the body's ConstantPlaceholder substitution follows the map order.
  • Reject fully removed (TooManyParamsForOrdering gone; grep-confirmed no stale refs).

Test plan

cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace

7 new param_order unit tests (hashCode known-vectors, improve, the p5/p8 worked orders, collision→insertion-order) + the byte-exact contract_template_parity gate over the new ≥5-param vectors.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BUh2DBnAPqThdYFZW5D8wx

Summary by CodeRabbit

  • New Features

    • Contract templates now support larger parameter lists without being rejected.
    • Parameter ordering is now handled consistently for placeholder substitution, matching expected declaration order behavior.
  • Bug Fixes

    • Improved consistency in how parameter positions are assigned during compilation.
    • Updated contract parity checks so templates with 5+ parameters serialize correctly instead of failing.
  • Tests

    • Revised coverage to verify successful compilation and byte-exact output for larger templates.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Contract templates with more than 4 parameters are no longer rejected during compilation. A new param_order module reproduces Scala 2.12/2.13 HashMap iteration order to compute ConstantPlaceholder indices for ≥5-parameter templates, while declaration order is preserved for constTypes/parameters. The TooManyParamsForOrdering error variant is removed, and related tests are updated.

Changes

Parameter iteration-order parity

Layer / File(s) Summary
Scala hash/iteration-order module
ergo-compiler/src/param_order.rs, ergo-compiler/src/lib.rs
New public module implements JVM String.hashCode, Scala Hashing.improve mixing, 5-bit trie bucketing, and iteration_order_2_12/iteration_order_2_13 functions with unit tests; module is exposed via pub mod param_order;.
Wire iteration order into compile_contract
ergo-compiler/src/contract_template.rs
compile_contract no longer rejects >4-parameter templates; placeholder indices use enumerate() for ≤4 params or iteration_order_2_12 for ≥5 params. ContractError::TooManyParamsForOrdering is removed, docs updated, and the rejection test replaced with a 5-parameter success test.
Parity test updates for >=5 param vectors
ergo-compiler/tests/contract_template_parity.rs
Test now expects byte-exact serialization for >=5-param vectors via a new byte_exact_ge5 counter, replacing the prior deferred-rejection handling and updating gate docs/assertions.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant compile_contract
  participant param_order

  Caller->>compile_contract: compile_contract(template)
  compile_contract->>compile_contract: check params.len()
  alt params.len() <= 4
    compile_contract->>compile_contract: enumerate() for placeholder indices
  else params.len() >= 5
    compile_contract->>param_order: iteration_order_2_12(names)
    param_order-->>compile_contract: permutation of indices
  end
  compile_contract-->>Caller: compiled contract with ConstantPlaceholder indices
Loading

Related PRs: None identified.

Suggested labels: compiler, correctness, tests

Suggested reviewers: None identified.

Poem:
A rabbit hopped through Scala's trie,
Counting hashes, bit by bit, so sly,
Five params once were turned away,
Now iteration order finds its way,
No more rejects—just bytes that match and fly.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: porting HashMap iteration order for 5+ parameter contracts to achieve byte parity.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/m7-hashmap-param-order

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

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

@arkadianet
arkadianet changed the base branch from main to feat/ergoscript-m7-contractparser July 7, 2026 22:24
@arkadianet

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@arkadianet
arkadianet force-pushed the feat/m7-hashmap-param-order branch from efab482 to 3d5f5af Compare July 7, 2026 23:07
@arkadianet
arkadianet force-pushed the feat/ergoscript-m7-contractparser branch from 422dd24 to e79d82d Compare July 7, 2026 23:12
@arkadianet
arkadianet force-pushed the feat/m7-hashmap-param-order branch from 3d5f5af to 82727a4 Compare July 7, 2026 23:12
arkadianet and others added 2 commits July 8, 2026 09:23
Ports the exact ordering Scala's immutable HashMap (`HashTrieMap`) yields for
a set of `@contract` param names, the source of `ConstantPlaceholder` indices
for ≥5-param templates: JVM `String.hashCode` + `scala.collection.Hashing.improve`
+ the 5-bit-sliced trie walk (ascending buckets, sub-tries in place). Pinned to
Scala 2.12 to match the `ct` oracle and ergo-appkit; the 2.13 CHAMP order is kept
(test-only) as the documented alternative. Both reproduce the recon's
bit-validated p5/p8 vectors exactly. Not yet wired into assembly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BUh2DBnAPqThdYFZW5D8wx
…lates

Replaces the ≥5-param `TooManyParamsForOrdering` reject with real placeholder-
index assignment via the Scala 2.12 `HashTrieMap` iteration order
(param_order::iteration_order_2_12); ≤4-param path (declaration order) untouched.
`constTypes`/`constValues`/`parameters` stay declaration-ordered — only the body's
`ConstantPlaceholder` substitution follows the map order. Error variant removed.

Adds oracle-captured 5/6/8-param vectors (five/six/eight_hashorder) whose name
sets order differently under HashTrieMap than declaration AND alphabetical, plus
the pre-existing five_params — all four ≥5-param templates now compile
BYTE-IDENTICAL to the `ct` oracle (sigma-state 6.0.2, Scala 2.12.21, JVM 17).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BUh2DBnAPqThdYFZW5D8wx
@arkadianet
arkadianet force-pushed the feat/m7-hashmap-param-order branch from 82727a4 to 2fa0c8d Compare July 7, 2026 23:23
Base automatically changed from feat/ergoscript-m7-contractparser to main July 7, 2026 23:23
@arkadianet

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@arkadianet

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
ergo-compiler/src/lib.rs (1)

1241-1241: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep param_order crate-private unless it is a supported API.

This exposes the Scala hash-order port as public crate surface. If only compile_contract needs it, prefer crate visibility to avoid downstream semver coupling.

Proposed change
-pub mod param_order;
+pub(crate) mod param_order;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ergo-compiler/src/lib.rs` at line 1241, The `param_order` module is being
exposed as public API even though it appears to be an internal implementation
detail. Change the visibility on `param_order` in `lib.rs` to crate-private
unless `compile_contract` or another supported public API truly needs it, and
keep any internal references working through the crate-visible module rather
than exporting it to downstream users.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@ergo-compiler/src/lib.rs`:
- Line 1241: The `param_order` module is being exposed as public API even though
it appears to be an internal implementation detail. Change the visibility on
`param_order` in `lib.rs` to crate-private unless `compile_contract` or another
supported public API truly needs it, and keep any internal references working
through the crate-visible module rather than exporting it to downstream users.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6ee34aa0-1c0c-440b-b4a6-786261c44dbe

📥 Commits

Reviewing files that changed from the base of the PR and between 975cc6f and 2fa0c8d.

⛔ Files ignored due to path filters (4)
  • test-vectors/ergoscript/contract/contract_seed.json is excluded by !test-vectors/**
  • test-vectors/ergoscript/contract/sources/eight_hashorder.es is excluded by !test-vectors/**
  • test-vectors/ergoscript/contract/sources/five_hashorder.es is excluded by !test-vectors/**
  • test-vectors/ergoscript/contract/sources/six_hashorder.es is excluded by !test-vectors/**
📒 Files selected for processing (4)
  • ergo-compiler/src/contract_template.rs
  • ergo-compiler/src/lib.rs
  • ergo-compiler/src/param_order.rs
  • ergo-compiler/tests/contract_template_parity.rs

@arkadianet
arkadianet merged commit d7057d3 into main Jul 8, 2026
1 check passed
@arkadianet
arkadianet deleted the feat/m7-hashmap-param-order branch July 9, 2026 06:41
arkadianet pushed a commit that referenced this pull request Jul 13, 2026
Bump workspace version to 0.5.2 and promote the changelog: the complete
v1 product API (#168-#185, #188), shadow validation as a production mode
(#193-#195), the operator observability wave (#187, #190, #192, #194),
two live accept-invalid consensus fixes (#176, #179), ErgoScript
compiler byte-parity completion (#165-#167, #175), and the #160-#163
sync/recovery fixes. Full workspace gate run on the merge result.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BUh2DBnAPqThdYFZW5D8wx
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.

1 participant