Skip to content

fix(ergo-sigma): evaluator carrier/type/serialize fidelity (#215 findings 2, 4, 5) - #223

Merged
arkadianet merged 4 commits into
mainfrom
fix/sigma-evaluator-carriers
Jul 18, 2026
Merged

fix(ergo-sigma): evaluator carrier/type/serialize fidelity (#215 findings 2, 4, 5)#223
arkadianet merged 4 commits into
mainfrom
fix/sigma-evaluator-carriers

Conversation

@arkadianet

@arkadianet arkadianet commented Jul 18, 2026

Copy link
Copy Markdown
Owner

All three deferred #215 Critical evaluator findings. Each verified against sigmastate-interpreter v6.0.2 source and confirmed by a live JVM-oracle differential.

# Fix Kind
#5 Coll.patch accepts every element carrier (was Byte/Int/Long only → rejected valid Coll[Short]/Coll[Boolean]/tuple/box/header) via the generic updateMany path reject-valid
#4 flatMap recovers the output element type B from the mapper body for an empty receiver instead of collapsing to Coll[Byte] type divergence
#2 SGlobal.serialize resolves context-backed box carriers (SELF/INPUTS/OUTPUTS/Coll[Box]) via resolve_box → canonical OpaqueBoxBytes reject-valid

JVM-oracle validation ✅

ergo-difftest reduce-surface differential vs sigma-state 6.0.2 (cargo test -p ergo-difftest --lib reduce_diff_serialize_and_flatmap -- --ignored), all matching node==JVM on prop and JIT cost:

serialize(SELF)==SELF.bytes   node=P:d3|142  jvm=P:d3|142
serialize(INPUTS).size>0      node=P:d3|145  jvm=P:d3|145
empty flatMap type            node=P:d3|166  jvm=P:d3|166

Validation

ergo-sigma suite 499 → 504 (+5 unit tests) + the live oracle differential; clippy -D warnings + fmt clean.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved serialization of context-backed boxes and nested collection values.
    • Added clearer errors when box values are serialized without the required evaluation context.
    • Fixed flatMap on empty collections to preserve the mapper’s output type.
    • Improved patch support across collection types, including Boolean and Short collections.
    • Added runtime type validation when applying collection patches.
  • Validation
    • Expanded evaluator coverage and cross-checked reduction behavior against the JVM oracle.

arkadianet and others added 2 commits July 18, 2026 21:37
…ng 5)

Scala `Coll[A].patch` (CollsOverArrays) is generic over the element type, but
the Rust impl matched only Byte/Int/Long carriers and rejected valid
`Coll[Short]`, `Coll[Boolean]`, tuple, box, header, and generic-carrier
receivers — a reject-valid (the node would reject a spend the reference
accepts). Rewrite the carrier-specific match to the generic
collection_to_values / values_to_collection path `updateMany` already uses,
with a per-patched-element sigma_type_compatible check (Array[A] backing throws
ArrayStoreException on a foreign element; an empty patch writes nothing and is
accepted regardless of declared type, matching Scala). The oracle-verified
splice-index algorithm and the Scala-anchored PerItemCost are unchanged.

Tests: +Coll[Short] and +Coll[Boolean] carriers; all 12 existing CollInt/Byte/
Long splice-semantics tests still pass (identical results via the generic path).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi
…eceiver (#215 finding 4)

When the flatMap receiver is empty there is no inner collection to read the
output shape from, so the result collapsed to Coll[Byte] even when the static
result type is Coll[Long], Coll[Int], etc. — the wrong element-type tag, which
serializes/dispatches differently from the reference (Scala threads RType[B]).

Recover B from the mapper body's static Coll[B] type: Const{SColl(B)},
ConcreteCollection{elem_type=B}, and If-branches all determine B directly.
A recovered type is always correct (it IS the body's collection element type),
so this never introduces a new divergence; bodies whose type isn't statically
determinable from the IR node keep the legacy Coll[Byte] fallback — a
documented, strictly-smaller residual.

Tests: empty receiver with a Coll[Long] Const body and a Coll[Int]
ConcreteCollection body both yield the correctly-typed empty collection.

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

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 01a6c126-c895-40de-8feb-ceedf01d233e

📥 Commits

Reviewing files that changed from the base of the PR and between 5892073 and d48502d.

📒 Files selected for processing (6)
  • ergo-difftest/src/oracle.rs
  • ergo-sigma/src/evaluator/helpers/serialize.rs
  • ergo-sigma/src/evaluator/helpers/subst_constants.rs
  • ergo-sigma/src/evaluator/opcodes/method_call/coll.rs
  • ergo-sigma/src/evaluator/opcodes/method_call/global.rs
  • ergo-sigma/src/evaluator/tests.rs

📝 Walkthrough

Walkthrough

The evaluator now supports context-aware box serialization, preserves collection element types for empty flatMap results, generically patches collections, and adds Rust-to-JVM differential validation.

Changes

Evaluator updates

Layer / File(s) Summary
Context-aware serialization
ergo-sigma/src/evaluator/helpers/serialize.rs, ergo-sigma/src/evaluator/helpers/subst_constants.rs, ergo-sigma/src/evaluator/opcodes/method_call/global.rs, ergo-sigma/src/evaluator/tests.rs
value_to_typed_sigma propagates ReductionContext, resolves context-backed boxes to canonical SBox bytes, and rejects unsupported context-backed values without context.
Typed collection method evaluation
ergo-sigma/src/evaluator/opcodes/method_call/coll.rs, ergo-sigma/src/evaluator/tests.rs
flatMap recovers empty-result element types from mapper expressions, while patch validates compatible elements and reconstructs collections generically.
Cross-runtime validation
ergo-difftest/src/oracle.rs
An ignored integration test compares Rust reduction verdicts with the Scala JVM serde oracle across targeted ErgoTree cases.

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

Possibly related PRs

  • arkadianet/ergo#98: Introduces JVM oracle infrastructure used by the new differential test.
✨ 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 fix/sigma-evaluator-carriers

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.

…rs (#215 finding 2)

value_to_typed_sigma rejected SELF / INPUTS / OUTPUTS / DATAINPUTS / Coll[Box]
in its catch-all, so serialize(SELF), serialize(INPUTS), serialize(SELF.tokens)
etc. failed where Scala accepts — a reject-valid.

Thread an Option<&ReductionContext> through value_to_typed_sigma. On the
SGlobal.serialize path (Some) the box carriers resolve via the existing
resolve_box to their concrete boxes and emit OpaqueBoxBytes(raw_bytes) — the
SAME canonical bytes ExtractBytes (0xC3) and the InlineBox arm already use,
which is exactly what Scala DataSerializer/ErgoBox.sigmaSerializer writes, so
this is correct by analogy to those oracle-verified paths (no new byte format).
BoxCollection resolves to Coll[SBox]; CollBox resolves each element. On the
SubstConstants path (None) behavior is unchanged — a context box as a
substituted constant stays unsupported (pre-existing, narrower residual).

Test: SelfBox resolves through a context to the box's canonical bytes (matching
the InlineBox path); rejects without a context. ergo-sigma suite 503 -> 504.

NOTE: verified against the reference by analogy to ExtractBytes/InlineBox
(identical raw_bytes); a JVM-oracle differential on top-level serialize(SELF)/
serialize(INPUTS) vectors is still recommended before relying on it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi
@arkadianet arkadianet changed the title fix(ergo-sigma): Coll.patch carriers + flatMap empty output type (#215 findings 5, 4) fix(ergo-sigma): evaluator carrier/type/serialize fidelity (#215 findings 2, 4, 5) Jul 18, 2026
…tor fixes

Adds a (scala-cli-gated, #[ignore]) reduce-surface differential that pins the
#215 serialize/flatMap fixes against the sigma-state 6.0.2 reference, replacing
the "verified by source-analogy" caveat with an actual oracle run:

  serialize(SELF)==SELF.bytes   node=P:d3|142  jvm=P:d3|142
  serialize(INPUTS).size>0      node=P:d3|145  jvm=P:d3|145
  empty flatMap type            node=P:d3|166  jvm=P:d3|166

Each tree reduces to a Bool→SigmaProp that is true (P:d3) on BOTH the node and
the JVM, with matching JIT cost — confirming:
- #2: serialize(SELF) equals the canonical box bytes (ErgoBox.bytes) and
  serialize(INPUTS) resolves the box collection, both at the JVM's cost (a
  pre-fix node REJECTED these → would diverge);
- #4: the empty-flatMap output is tagged Coll[Long], not Coll[Byte] — its
  serialize bytes match an empty Coll[Long] byte-for-byte (a type mismatch
  would reduce to false / P:d2).

Run: cargo test -p ergo-difftest --lib reduce_diff_serialize_and_flatmap -- --ignored

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi
@arkadianet
arkadianet marked this pull request as ready for review July 18, 2026 21:47
@arkadianet
arkadianet merged commit 8aada6a into main Jul 18, 2026
9 checks passed
@arkadianet
arkadianet deleted the fix/sigma-evaluator-carriers branch July 18, 2026 21:47
@arkadianet arkadianet mentioned this pull request Jul 18, 2026
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