fix(consensus): short-circuit Coll-equality cost at first mismatch (Scala parity) - #108
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthrough
ChangesPrimitive collection equality short-circuit cost
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
ergo-sigma/src/evaluator/cost.rs (1)
680-743: 💤 Low valueConsider adding test coverage for empty collections and varying chunk sizes.
The tests comprehensively validate the short-circuit behavior for
CollBytes, but all three use the same chunk size (128). Since theprim_coll_eqfunction is generic and handles different chunk sizes (96 for Short, 64 for Int, 48 for Long), a test verifying that early-mismatch savings scale correctly with chunk size would strengthen confidence in the per-item cost formula.Additionally, the empty collection case (
k_eff = 0) is untested. While the logic appears correct, an explicit assertion thateq_cost(&[], &[])returns the expected cost (MATCH_TYPE + base cost for 0 items) would document the behavior.🤖 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-sigma/src/evaluator/cost.rs` around lines 680 - 743, Add two new test functions within the prim_coll_eq_tests module to extend coverage. First, add a test for empty collections that calls eq_cost with empty byte slices and asserts the cost matches the expected MATCH_TYPE plus base cost for zero items. Second, add a parametrized or separate test function that verifies the early-mismatch cost savings behavior with different chunk sizes (96, 64, and 48) to ensure the per-item cost formula scales correctly across different collection types, similar to the existing collbytes_eq_cost_short_circuits_at_first_mismatch test but using vectors of varying lengths appropriate to each chunk size.
🤖 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-sigma/src/evaluator/cost.rs`:
- Around line 680-743: Add two new test functions within the prim_coll_eq_tests
module to extend coverage. First, add a test for empty collections that calls
eq_cost with empty byte slices and asserts the cost matches the expected
MATCH_TYPE plus base cost for zero items. Second, add a parametrized or separate
test function that verifies the early-mismatch cost savings behavior with
different chunk sizes (96, 64, and 48) to ensure the per-item cost formula
scales correctly across different collection types, similar to the existing
collbytes_eq_cost_short_circuits_at_first_mismatch test but using vectors of
varying lengths appropriate to each chunk size.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: bc119b51-4856-4935-acff-7d33dd6c8439
📒 Files selected for processing (1)
ergo-sigma/src/evaluator/cost.rs
c2568a6 to
26dd37e
Compare
…cala parity) EQ/NEQ on a primitive collection (Coll[Byte]/Bool/Int/Long/Short, SString) charged the per-item cost over the FULL left-operand length, while Scala's DataValueComparer.equalCOA_Prim short-circuits BOTH value and cost at the first unequal element — billing PerItemCost over the elements actually compared (the loop's returned count i), via addSeqCost. For two equal-length collections that differ at index k<len, Scala bills chunks(k+1) but we billed chunks(len). This is an over-charge only (never under), so it is a reject-valid risk: an input whose true cost sits just under the tx/block cost limit but whose collection equality short-circuits early could be over-billed past the limit and rejected where Scala accepts. Coll[Byte] equality (token ids, propositionBytes, digests) is pervasive in real scripts. Split the typed-Coll arm of eq_with_cost_inner: the primitive carriers now walk both arrays, stop at the first unequal element, and charge the per-type PerItemCost over that compared prefix (mirroring eq_coll_fallback / CollSigmaProp, which already track k_eff). All-equal and length-mismatch costs are unchanged. Box/Header/Tokens colls (Scala equalColls path) are untouched. Found via SANTA: Coll.eq_compared_count_coa + 17 captured h* block-input vectors (cost +1/+2, value byte-identical). Adds RED/GREEN unit tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Addressed the test-coverage nitpick in 7790a8f: added |
26dd37e to
7790a8f
Compare
…lease cut (#126) 0.4.3 was version-cut at #117, but #106–#114 and #118–#125 landed at the same version without a CHANGELOG entry — so [0.4.3] documented only #115/#116/#117 while the deployed 0.4.3 binary actually contains all 18 PRs since the v0.4.2 cut. Backfills the section to match what shipped: - New ### Added subsection for the native /api/v1/wallet surface (#112, #113, #114). - ### Fixed now covers the signed-byte parity fixes (#106, #107), the Coll-equality cost short-circuit (#108), EIP-27 re-emission enforcement (#109 + #111, merged — the P0 fork fix, now across block/mempool/mining), and the full v6/EIP-50 + ErgoTree wire-deserialization cluster (#118–#125). - Broadened the release intro to name the EIP-27 enforcement and the native wallet surface alongside the v6/EIP-50 conformance work. - Added the missing (#117) reference to the box-deserialize entry. Docs only; no code or behavior change. Entries were drafted from each PR's own commit/description and accuracy-reviewed (e.g. the EIP-27 soak figure is the corrected 172 reward-box burns, not the repudiated 1,173). Co-authored-by: arkadianet <rkadias@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…1001 SigmaProp-root gate (#129) * test(difftest): add a reduce eval/cost differential surface The JVM-oracle fuzzer only diffed DESERIALIZE verdicts, so it was blind to the eval/cost path — exactly where the #108/#115 cost divergences lived. Add a `reduce` surface that deserializes an ErgoTree, reduces its root to the on-chain sigma proposition + raw JIT cost under a minimal dummy context, and diffs the `P:<prop>|<cost>` pair byte-for-byte against the Scala reference's reduction. This is the reject-arm layer the deserialize-only surfaces cannot reach. The Rust context mirrors EvalCore.dummyContext field-for-field: preHeader.version 4 / timestamp 3, generator miner key, AvlTreeData.dummy, cost limit = scriptCostLimitInEvaluator, and SELF = an ErgoBox (value 1M, this tree, txid zeros, index 0) with its serialized bytes + Blake2b256 id populated — so a script reading context or SELF.bytes / SELF.id reduces identically on both sides. The node half reuses the consensus box-script path via a shared `deserialize_box_script` (read_ergo_tree + the four box gates). The GroupElement on-curve check is scoped to this surface only: the node's read_ergo_tree codec defers it to tx-validation (ergo-validation tx::ge), so applying it to the bare `ergo_tree` codec surface reject-valids a body the JVM wraps-as-Unparsed. `--surface` now works in the `--oracle` campaign (validated against the oracle surface set; `--repro` keeps validating against the hermetic registry). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(consensus): reject non-SigmaProp ErgoTree root in sizeless box scripts Scala's deserializeErgoTree runs CheckDeserializedScriptIsSigmaProp (validation rule 1001): a root whose static type is not SigmaProp is a ValidationException, and WITHOUT a size bit there is no declared-size region to wrap into an UnparsedErgoTree, so it is re-raised as a hard SerializerException. The lenient read_ergo_tree codec accepted such a tree and the box readers coerced it to a trivial proposition. A block carrying such an output box would be accepted by this node and rejected by every Scala node (accept-invalid / fork). Add a `check_sigma_prop_root` gate (sizeless-only, mirroring check_resolvable_ methods; the has_size path already wraps via determinable_root_type) wired into every consensus box reader AND the nested SBox-constant inner-script path (box deserialization uses checkType=true at every level). determinable_root_type now classifies all STATICALLY-DETERMINABLE non-SigmaProp roots: - inline Const / ConstPlaceholder (segregated type), - every zero-arg leaf (True/False, Height, Self, MinerPubkey, GroupGenerator, Inputs/Outputs, LastBlockUtxoRootHash, Global, Context), - operators with an unconditionally non-SigmaProp result (relations, arithmetic, hashes, SizeOf, box-field extractors, SigmaPropIsProven/Bytes). Roots whose type DEPENDS on argument types (If, BlockValue/FuncValue, MethodCall, field/index access) stay lenient — a full root typechecker is a follow-up; a non-sigma one fails at evaluation instead. Found by the new ergo-difftest reduce eval/cost differential and pinned against the sigma-state 6.0.2 oracle (000173 / 0080 / 00a3 / 009305010501 / 00c1a7 -> reject; 0008d3, P2PK, BoolToSigmaProp -> accept). Test fixtures that used a bare-Boolean dummy script are updated to a SigmaProp root (08 d3). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(consensus): complete the rule-1001 gate for all determinable roots Extend the rule-1001 (CheckDeserializedScriptIsSigmaProp) root-type classifier so the box-script gate / has_size soft-fork-wrap judge a sizeless or wrapped root's type the same way Scala's typed deserializer does — closing the remaining accept-invalid (a non-SigmaProp-rooted output box this node accepts and every Scala node rejects). Every rule is pinned against the sigma-state 6.0.2 oracle. DETERMINABLE payload/operator roots (CodeRabbit review): - Coll / tuple literals, getVar[T]/box.RX[T] (-> Option[T]), NumericCast, and Deserialize{Context,Register}[T] (-> T verbatim: CAN be SigmaProp); - fixed-result operators: predicates / Bool logic -> Boolean; hashes/extractors/ SubstConstants/Append/Filter/MapCollection/Slice -> Coll/bytes; SizeOf -> Int; DecodePoint -> GroupElement; TreeLookup -> Option; SigmaPropIsProven/Bytes. ARG-DEPENDENT roots, typed by RECURSION into the type-determining child (Scala computes these bottom-up; a non-determinable child stays None=lenient so this can never reject a Scala-accepted tree): - If -> then-branch; BlockValue -> result; Fold -> zero/accumulator; SelectField -> tuple component; ByIndex/OptionGet/OptionGetOrElse -> element; - ArithOp (Plus/Minus/Multiply/Division/Modulo/Min/Max) -> LEFT operand: Scala types these as `left.tpe` with NO operand check, so Plus(sigma, x) IS SigmaProp (oracle-verified ACCEPT) — classifying them as fixed-numeric was a reject-valid. The has_size wrap now recurses too, so a non-SigmaProp-rooted has_size tree soft-fork-wraps verbatim exactly as the JVM does — this corrects a latent rust-canonical-vs-JVM-verbatim divergence the STypeVar parity test had pinned (its function-rooted vectors are non-SigmaProp and wrap; the UTF-8 lossy decode itself is covered by ergo-ser/src/jvm_utf8.rs unit tests). Still SigmaProp- capable / heavier arg-dependent roots (MethodCall/PropertyCall — need the method- signature registry; ValUse/FuncApply — need a binding environment) stay lenient. Verified: 0 reject-valid over the difftest reduce + ergo_tree campaigns (80k each). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(difftest): address review — oracle repro, SELF-box errors, reduce reject - `--oracle --repro <hex>` now replays the single input against the JVM oracle (run_oracle_repro) so a reduce finding is reproducible from the CLI. - build_dummy_self_box returns Result and propagates a serialization/id failure rather than masking it as empty SELF.bytes / a zero SELF.id. - the JVM oracle's reduceRepr now REJECTS (throws -> REJECT) a reduced root that is neither SigmaProp nor Bool, matching the node's reduce_verdict. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: arkadianet <rkadias@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ents Removes bare bug-tracker numbers (#97, #108/#115, bug #6), a dangling "gitignored dev-docs Autolykos note" pointer, and redundant citations into interface-contracts.md/findings-and-triage.md whose content was already stated inline, restating each as a direct technical claim. Doc-only. Preserved: all Scala/JVM-oracle protocol documentation, and the extensive Bug #N cross-references in gen/mod.rs, gen/sigma_expr.rs, ergo_tree.rs, box_candidate.rs, transaction.rs, header.rs, constant.rs, asm.rs -- these map to the checked-in ergo-difftest/docs/known-bug-catalog.md rediscovery gate and are the crate's own live API contract (Feature::bug_id()), not development history. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi
…203) * docs(ergo-compiler): reference-implementation documentation pass (remaining files) Elevates the last ~30 uncovered ergo-compiler files (parse/*, typer core, AST/type/token core, and the transform layer + lib.rs) to the same documentation standard applied in #202: strips internal planning-artifact references (dev-docs citations, milestone/task-tracker labels, dangling finding codes) while preserving all Scala source citations, oracle vectors, and the crate's deviation ledger. Doc/comment-only, no behavior changes. Also fixes one real inaccuracy found along the way: lib.rs's module doc claimed CSE was not yet wired into compile() -- it is (tree/mod.rs:217). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-crypto): strip internal-artifact citations from test comments Removes Task-N labels and a dangling internal-report/design-doc citation ("Task-4 report", "g25-pegmint-packaging §5.2.5") from group_element.rs and merkle/mod.rs, restating the same facts directly. Doc-only; all Scala/scrypto citations and oracle vectors untouched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-difftest): strip internal-artifact references from doc comments Removes bare bug-tracker numbers (#97, #108/#115, bug #6), a dangling "gitignored dev-docs Autolykos note" pointer, and redundant citations into interface-contracts.md/findings-and-triage.md whose content was already stated inline, restating each as a direct technical claim. Doc-only. Preserved: all Scala/JVM-oracle protocol documentation, and the extensive Bug #N cross-references in gen/mod.rs, gen/sigma_expr.rs, ergo_tree.rs, box_candidate.rs, transaction.rs, header.rs, constant.rs, asm.rs -- these map to the checked-in ergo-difftest/docs/known-bug-catalog.md rediscovery gate and are the crate's own live API contract (Feature::bug_id()), not development history. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-wallet): strip internal-artifact references from doc comments Removes a bare uncited bug label, "Task 38" tracker references, and roadmap-style "lands in following PRs"/"a later slice" phrasing from scan/mod.rs, scan/predicate.rs, address.rs, secret.rs, and storage.rs -- restated each as a direct statement of current scope. Doc-only. Preserved: all Fiat-Shamir/Schnorr/DHT protocol documentation, BIP32/BIP39/ EIP-3 citations, and the upstream Ergo issue #1627 legacy-derivation provenance baked into ExtendedSecretKeyLegacy/use_pre_1627. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-mining): strip internal design-doc citations from doc comments Removes dangling "v12 §N" / "design §N" internal design-plan citations from candidate.rs and handle.rs, and an uncited "audit-1" tracker label from error.rs -- restated each as a direct statement of the invariant. Doc-only. Preserved: all Scala consensus citations (CandidateGenerator.scala, EmissionRules.scala, ReemissionRules.scala), emission/coinbase/reward-script byte-layout documentation, and the "Component B" subsystem name where it functions as this crate's (and ergo-mempool's) stable cross-file name for the suspect-feed/targeted-recheck mechanism rather than a dangling doc pointer. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-mempool): strip internal-artifact references from doc comments Removes this repo's own PR #139 references, a dangling "§7"/"Phase 2A guidance" design-doc citation, and two code-review-thread references ("Item 3 of the code-review fixes", "reviewer finding 1") from lib.rs and admission/tests.rs -- restated each as a direct technical statement. Doc-only. Preserved: all Scala mempool-parity citations (OrderedTxPool, MempoolAuditor, CleanupWorker), the "Component B" and numbered admission-step naming (both confirmed stable, cross-referenced internal pipeline structure, not dangling doc pointers), and mempool invariant #7's cross-reference to its real definition in admission.rs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-p2p): strip internal-artifact references, fix stale connection-limit doc Removes dangling internal labels (Sync-S3/Lever 1/plan §240 in sync.rs, Sync-S2 in delivery.rs, an AI-audit-session narrative and a "checklist contract" pointer in peer_manager/mod.rs) and roadmap phrasing in handshake.rs test docs, restating each as a direct technical statement. Doc-only. Also fixes a real inaccuracy: peer_manager/mod.rs's module doc still said "Max 80 total / 60 outbound" connections by default; the actual Default (limits.rs) is 384 total / 96 outbound / up to 256 inbound (decoupled). Updated to match. Preserved: all Scala P2P-protocol citations, wire-format byte-layout documentation, the out96/in256/cap384 connectivity-limit rationale, and the 2026-07-04 testnet-stall regression note in throttle.rs (genuine incident documentation, not development history). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-indexer): strip internal-artifact references from doc comments Removes a dangling "audit-2 M11" milestone label from handle.rs, and an AI-agent reference plus two citations to an uncommitted internal spec file (2026-05-01-storage-rent-eligibility.md, confirmed absent from the repo) from rollback.rs -- restated each as a direct technical statement. Doc-only. Preserved: all Scala indexer-parity citations, the testnet-431,366 and h=740,362 mainnet-incident notes, and the crate's own stable Phase 0/Phase 1 rebuild-state naming. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-sync): strip internal-artifact references from doc comments Removes AI-agent/review-tool references ("Codex supervisor plan", "codex review notes", "codex round-N guard"), internal task-tracker labels ("M5 final slice tracked in audit-todo"), and dangling internal increment/design-plan labels ("Sync-S0/S1/S3", "Plan §240") from executor/mod.rs, block_proc.rs, and coordinator/{mod,tests}.rs -- restated each as a direct technical statement. Doc-only. Preserved: all Scala sync-parity citations (ToDownloadProcessor.scala, ElementPartitioner.distribute), and the operational rationale behind the real merged "headers-synced stale-tip stall" and "caught-up-to-peers fallback" fixes, which document actual observed behavior rather than development history. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-validation): strip internal-artifact references, fix mojibake Removes dangling internal-plan/spec citations across block/header, voting, popow, and tx modules ("v12 §5 step N", "spec §8.1", "2026-04-28-voted- parameters-phase2.md" (confirmed absent from the repo), "R5 security gap / §11", "14.10", "§6.3", "T4 live differential", "codex P0-1", "§3.5") and an AI-review-tool tracker label, restating each as a direct technical statement. Doc-only. Also fixes a real encoding bug: voting/votes.rs and its oracle test carried double-encoded UTF-8 em-dashes ("—" instead of "—") -- restored throughout both files. The same corruption exists in ergo-sigma and will be fixed when that crate's pass runs. Preserved: every Scala consensus citation (ErgoStateContext.scala, NipopowAlgos.scala, Parameters.scala, RuleStatusSerializer.scala, etc.), mainnet-incident-derived rationale (blocks 290684/422179/1802240, h=1821696), EIP-27/storage-rent documentation, and all oracle-pinned test vectors -- this is the workspace's consensus-validation crate and none of its correctness specification was touched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-ser): strip internal-artifact references, fix broken citation Removes AI-review-tool tracker labels ("codex P1", "codex review of the MAX_EXPR_DEPTH=110 fix") from ergo_tree.rs and sigma_value.rs, and dangling citations to internal spec files confirmed absent from the repo (.superpowers/sdd/task-1-report.md, dev-docs/context-ext-count-signedness- recon.md, dev-docs/.../recon-segregation.md, "Phase 0 §11.5") from address.rs, input.rs, opcode/tests.rs, and popow_proof.rs. Also drops dangling "sub-phase 14.3"/"§14.3" cross-crate milestone labels from popow_header.rs, matching the same cleanup already done in ergo-validation's popow module. Doc-only. Also fixes a real broken citation: extension.rs's proptest doc comment named two test functions that don't exist in the file (extension_too_many_fields_returns_invalid_data / extension_value_too_long_returns_invalid_data); corrected to the actual names (extension_field_count_above_u16_returns_invalid_data / extension_field_value_above_255_returns_invalid_data). Preserved: every Scala/sigma-state wire-format citation, opcode-by-opcode byte-layout documentation, oracle-derived test vectors, the KMZ17 interlinks-sizing rationale, and the STypeVar/JVM-UTF8 and MAX_TYPE_DEPTH divergence notes -- this crate's entire purpose is byte-exact parity with the Scala reference and none of that specification was touched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-sigma): fix mojibake, strip internal-artifact references Fixes 42 instances of double-encoded UTF-8 mojibake ("—" -> "—") in evaluator/opcodes/method_call.rs, matching the same corruption already fixed in ergo-validation. Removes AI-review-tool/PR-number dev-history references from evaluator/tests.rs (codex P1, "per CodeRabbit on PR #38", "Reviewer finding:", a bare commit hash), evaluator/opcodes/method_call.rs ("PR #13/#14 oracle vectors"), and evaluator/opcodes/binding.rs ("CodeRabbit PR #161 finding") -- restated each as a direct technical statement. Doc-only. Preserved: every Scala/sigma-state citation across the evaluator (opcode dispatch, cost accounting, method_call semantics, Schnorr/DHT proof verification, AVL+ operations, verify.rs's top-level reduction path), oracle-pinned test vectors, and the GHSA-hfj8-hjph-7r78 security-advisory citation. Left one "TODO v6.0: implement" comment untouched in evaluator/opcodes/errors.rs -- it's a verbatim quote of the Scala reference source's own class comment (trees.scala:77), not this repo's dev history. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-state): strip internal-artifact references from doc comments Removes AI-review-tool attributions (Codex flagged/identified, "codex risk flag in 2h plan"), dangling internal task/milestone labels (Task 1.6/1.7, Phase 0/1a/1b/1c/2/2a/2b/3/3a/3b/4/5, sub-phase 14.5/14.10, audit-2 M5, Task 38), and citations to internal spec/incident docs confirmed absent from the repo (spec §7.1/§7.4, "2026-05-02-voted-params-first-epoch- boundary", "dev-docs/incident-2026-06-11-adproofs/") across the store, digest, avl, wallet, and persist modules -- restated each as a direct technical statement. Doc-only. Preserved: every Scala consensus citation, the crate's own stable Mode 2/3/5/6 operational-mode naming and per-function "Phase 1/2/3" step labels (these describe a single function's own algorithm steps, not a development roadmap -- same pattern as ergo-sync's kept "Step 2.5"), the mainnet incident at height 1,805,523 (technical substance kept, only the dangling doc pointer dropped), and all AVL+/digest-mode byte-layout documentation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-api): strip internal-artifact references, fix 3 stale docs Removes a systemic pattern found across nearly every v1/* file: citations to dev-docs/v1-api-design.md and its section numbers (§N.N), work-breakdown codes (G-N/O-N used as dangling pointers), "locked decision" labels, and a sibling dev-docs/v1-design-fragments/*.md fragment doc -- all confirmed absent from the repo. Also strips compat/blockchain module citations to a nonexistent "spec inventory"/section-12 label, and AI-review-tool references (CodeRabbit #170, "codex", "see the PR report"). Doc-only. Fixes 4 real staleness bugs found along the way: - v1/mod.rs: said v1 "isn't mounted on a route yet" -- it is (server.rs). - v1/auth.rs: said tiers/boot-warn aren't wired per-group yet -- they are. - v1/mempool_depth.rs: called stats/mempool-depth "future" -- it's live. - v1/realtime/bus.rs: called webhooks "a future PR" -- webhooks is built and is itself a live RealtimeBus subscriber. Preserved: every Scala/REST-compat citation, the compat/ module's byte-for-byte quirk-compatibility documentation, T0/T1/T2 tier naming and G-N/O-N primitive-numbering (real, pervasively cross-referenced internal names, not dangling doc pointers), and all storage-rent/wallet/mempool correctness rationale. Two residuals flagged but intentionally NOT touched (would be a behavior change, out of scope for a docs-only pass): three JSON response `detail`/ `note` string literals in operator/node.rs, accounts/mod.rs, and script/handlers.rs leak the same internal jargon into live API responses; and decode/registry.rs's `rent` protocol entry has `reference: "dev-docs/demurrage"`, a nonexistent path returned live via GET /api/v1/protocols. Both are real product bugs worth a follow-up. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-node): strip internal-artifact references, fix 2 stale docs Removes AI-review-tool attributions (Codex plan finding/follow-up/audit citations, CodeRabbit PR #152), dangling internal task/milestone labels (Phase 0/1a/1b/2a/2b/2f-1/2f-3/2j/3a/3b/4/4a/4b/4d, sub-phase 14.6/14.10, Part 2 spec/§N, "M5 final slice in audit-todo", OBS-1/P2 work-item codes, bare commit hashes, "spec §7.3/§7.4"), and citations to internal design/spec docs confirmed absent from the repo (design §2/§5/§6/§6.2, "operator workload §D", "spec §2 Channel Sizing") across the wallet bridge, config, boot, api_bridge, snapshot, mining/sync, and node-identity modules. Doc-only. Fixes 2 real staleness bugs found along the way: - node/state.rs: doc comment called drive_popow_bootstrap/ handle_inbound_popow_proof "both follow-up commits" -- both are already implemented (sync_tick.rs, messaging.rs). - api_bridge/tests.rs: a monitoring-scraper note said a stale-field bug was fixed "Pre-r5" -- restated as the direct current-behavior guarantee without the version tag, since no such tag is used elsewhere in the repo. Preserved: every Scala/REST-compat citation, the crate's own stable Mode 1-6 operational-mode taxonomy and R1/R2/R5 Scala-parity validation codes, mainnet-incident rationale (h=28662 sign-flip, silent-stall and header-only-reset-stall bugs), and all consensus/sync-safety documentation (prune-sentinel gating, split-brain best_full_block_height sync, NiPoPoW resume-state classification). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * fix(ergo-api): regenerate OpenAPI golden fixtures after doc cleanup utoipa embeds doc comments directly into the generated OpenAPI spec, so the internal-artifact citations stripped from wallet/v1 doc comments in 46cdb66 changed the generated native and v1 specs, drifting them from the checked-in golden fixtures. CI caught this (openapi_native_matches_snapshot and openapi_v1_matches_snapshot both failing on all three platforms). Regenerated both fixtures via the documented `regenerate` test target; no other change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Why
EQ/NEQ on a primitive collection (
Coll[Byte]/Bool/Int/Long/Short,SString) charged the per-item cost over the full left-operand length, but Scala'sDataValueComparer.equalCOA_Primshort-circuits both value and cost at the first unequal element — billingPerItemCostover the compared prefix (the loop's returned counti, viaaddSeqCost). For two equal-length colls differing at indexk<len, Scala billschunks(k+1); we billedchunks(len).Over-charge only (never under) → a reject-valid risk: an input whose true cost sits just under the tx/block cost limit but whose collection equality short-circuits early could be over-billed past the limit and rejected where Scala accepts.
Coll[Byte]equality (token ids, propositionBytes, digests) is pervasive.What
Split the typed-Coll arm of
eq_with_cost_inner: the primitive carriers walk both arrays, stop at the first unequal element, and charge the per-typePerItemCostover that compared prefix — mirroringeq_coll_fallback/CollSigmaProp, which already trackk_eff. All-equal and length-mismatch costs are unchanged.Box/Header/Tokenscolls (ScalaequalCollspath) are untouched.Test plan
prim_coll_eq_tests): early-mismatch costs < late-mismatch; all-equal == last-element-mismatch (full length); length-mismatch bills onlyMatchType.cargo fmt✓,clippy --all-targets --all-features -D warnings✓,cargo test --all✓.Coll.eq_compared_count_coacoals (mismatch-at-0/150/300), no new coals.Note
The earlier triage lumped 17
h*block-input vectors into this cluster. Verified post-fix: their+1/+2cost deltas are unchanged by this change — they're a separate cost-model divergence (value byte-identical), not the Coll-eq short-circuit. They need their own root-cause and are not addressed here.🤖 Generated with Claude Code
Summary by CodeRabbit