feat: within-step dedup + Presets.throughput (F7) - #22
Merged
Merged
Conversation
Merge dedup-eligible calls that share (target.toLowerCase(), calldata, canonicalOutputSignature) within one step, across tasks, before the wire list reaches batching/bisection (src/core/engine.ts). Eligibility is per-call: TypedCallSpec calls default eligible (opt out with dedupe: false), legacy hand-authored StepCalls never carry the internal DEDUPE_ELIGIBLE stamp and so are never merged, regardless of the run's own dedupe option. Conflicting output ABIs for identical calldata are kept as separate wire calls (canonicalOutputSignature diverges), preventing first-decoder-wins corruption. A merged group's single wire result (success or a bisection-terminal failure alike) fans out to every subscribing (taskIndex, key) via a new mapping data structure in the step engine. DEDUPE_ELIGIBLE relocates from defineTask.ts to internal.ts so the engine can read it without a cross-layer import. Adds `dedupe?: boolean` to BatchOptions (default false, zero cost on the default path) and Presets.throughput (src/core/presets.ts), re-exported from index.ts. Adds src/__tests__/dedup.test.ts (13 tests) and a hit-rate section in docs/benchmarks.md with empirically-verified counting-executor numbers; bundle-size badge updated to the measured 12.8KB gzip.
…r identity, calldata case (external review) Three fixes on top of the F7 dedup key/fan-out: 1. Ambiguous-overload keying (P1): the arity-based fallback could conflate two same-arity overloads' outputs (e.g. f(uint256) and f(address) both take one input), producing identical serialized signatures for ABIs that pair inputs to outputs differently — a real merge-corruption case. Replaced with selector-based resolution: a function selector is fixed by its own name+input-types alone, so matching the calldata's own 4-byte selector against each same-named candidate's own computed selector (viem's toFunctionSelector, re-exported from src/core/abi.ts) recovers the exact matched item unambiguously, with no arity heuristic and no fallback branch needed. 2. Failure fan-out (P2): a merged group's failure was routed as the SAME DominoCallError object to every subscriber, so its `.key` field read as whichever subscriber happened to be the wire representative for every OTHER subscriber. Entries with more than one subscriber now get a fresh DominoCallError per subscriber (retargetError in engine.ts) — same message/kind/data/target/functionName, `cause` reference shared (not re-wrapped), `key` set to that subscriber's own routing key. Single-subscriber entries (the default path) are unaffected. 3. Calldata case (P2): a bytes/bytesN arg's encoded segment preserves the caller's own hex casing verbatim (unlike an address), so two calls with the same bytes value but different hex-string casing keyed differently. The key now lowercases the encoded calldata before hashing; the call's own calldata/args sent to the executor are untouched. Adds 3 regression tests to src/__tests__/dedup.test.ts (16 tests total): conflicting overload pairing, per-subscriber error key metadata, and bytes32-casing merge. Updates the two failure-fan-out tests' identity assertions for the new per-subscriber clone semantics. Bundle-size badge updated to the measured 13.0KB gzip.
halaprix
added a commit
that referenced
this pull request
Jul 24, 2026
* feat: within-step dedup + Presets.throughput (F7) Merge dedup-eligible calls that share (target.toLowerCase(), calldata, canonicalOutputSignature) within one step, across tasks, before the wire list reaches batching/bisection (src/core/engine.ts). Eligibility is per-call: TypedCallSpec calls default eligible (opt out with dedupe: false), legacy hand-authored StepCalls never carry the internal DEDUPE_ELIGIBLE stamp and so are never merged, regardless of the run's own dedupe option. Conflicting output ABIs for identical calldata are kept as separate wire calls (canonicalOutputSignature diverges), preventing first-decoder-wins corruption. A merged group's single wire result (success or a bisection-terminal failure alike) fans out to every subscribing (taskIndex, key) via a new mapping data structure in the step engine. DEDUPE_ELIGIBLE relocates from defineTask.ts to internal.ts so the engine can read it without a cross-layer import. Adds `dedupe?: boolean` to BatchOptions (default false, zero cost on the default path) and Presets.throughput (src/core/presets.ts), re-exported from index.ts. Adds src/__tests__/dedup.test.ts (13 tests) and a hit-rate section in docs/benchmarks.md with empirically-verified counting-executor numbers; bundle-size badge updated to the measured 12.8KB gzip. * fix: F7 dedup — selector-based overload matching, per-subscriber error identity, calldata case (external review) Three fixes on top of the F7 dedup key/fan-out: 1. Ambiguous-overload keying (P1): the arity-based fallback could conflate two same-arity overloads' outputs (e.g. f(uint256) and f(address) both take one input), producing identical serialized signatures for ABIs that pair inputs to outputs differently — a real merge-corruption case. Replaced with selector-based resolution: a function selector is fixed by its own name+input-types alone, so matching the calldata's own 4-byte selector against each same-named candidate's own computed selector (viem's toFunctionSelector, re-exported from src/core/abi.ts) recovers the exact matched item unambiguously, with no arity heuristic and no fallback branch needed. 2. Failure fan-out (P2): a merged group's failure was routed as the SAME DominoCallError object to every subscriber, so its `.key` field read as whichever subscriber happened to be the wire representative for every OTHER subscriber. Entries with more than one subscriber now get a fresh DominoCallError per subscriber (retargetError in engine.ts) — same message/kind/data/target/functionName, `cause` reference shared (not re-wrapped), `key` set to that subscriber's own routing key. Single-subscriber entries (the default path) are unaffected. 3. Calldata case (P2): a bytes/bytesN arg's encoded segment preserves the caller's own hex casing verbatim (unlike an address), so two calls with the same bytes value but different hex-string casing keyed differently. The key now lowercases the encoded calldata before hashing; the call's own calldata/args sent to the executor are untouched. Adds 3 regression tests to src/__tests__/dedup.test.ts (16 tests total): conflicting overload pairing, per-subscriber error key metadata, and bytes32-casing merge. Updates the two failure-fan-out tests' identity assertions for the new per-subscriber clone semantics. Bundle-size badge updated to the measured 13.0KB gzip. --------- Co-authored-by: halaprix <halaprix@users.noreply.github.com>
halaprix
added a commit
that referenced
this pull request
Jul 24, 2026
* feat: within-step dedup + Presets.throughput (F7) Merge dedup-eligible calls that share (target.toLowerCase(), calldata, canonicalOutputSignature) within one step, across tasks, before the wire list reaches batching/bisection (src/core/engine.ts). Eligibility is per-call: TypedCallSpec calls default eligible (opt out with dedupe: false), legacy hand-authored StepCalls never carry the internal DEDUPE_ELIGIBLE stamp and so are never merged, regardless of the run's own dedupe option. Conflicting output ABIs for identical calldata are kept as separate wire calls (canonicalOutputSignature diverges), preventing first-decoder-wins corruption. A merged group's single wire result (success or a bisection-terminal failure alike) fans out to every subscribing (taskIndex, key) via a new mapping data structure in the step engine. DEDUPE_ELIGIBLE relocates from defineTask.ts to internal.ts so the engine can read it without a cross-layer import. Adds `dedupe?: boolean` to BatchOptions (default false, zero cost on the default path) and Presets.throughput (src/core/presets.ts), re-exported from index.ts. Adds src/__tests__/dedup.test.ts (13 tests) and a hit-rate section in docs/benchmarks.md with empirically-verified counting-executor numbers; bundle-size badge updated to the measured 12.8KB gzip. * fix: F7 dedup — selector-based overload matching, per-subscriber error identity, calldata case (external review) Three fixes on top of the F7 dedup key/fan-out: 1. Ambiguous-overload keying (P1): the arity-based fallback could conflate two same-arity overloads' outputs (e.g. f(uint256) and f(address) both take one input), producing identical serialized signatures for ABIs that pair inputs to outputs differently — a real merge-corruption case. Replaced with selector-based resolution: a function selector is fixed by its own name+input-types alone, so matching the calldata's own 4-byte selector against each same-named candidate's own computed selector (viem's toFunctionSelector, re-exported from src/core/abi.ts) recovers the exact matched item unambiguously, with no arity heuristic and no fallback branch needed. 2. Failure fan-out (P2): a merged group's failure was routed as the SAME DominoCallError object to every subscriber, so its `.key` field read as whichever subscriber happened to be the wire representative for every OTHER subscriber. Entries with more than one subscriber now get a fresh DominoCallError per subscriber (retargetError in engine.ts) — same message/kind/data/target/functionName, `cause` reference shared (not re-wrapped), `key` set to that subscriber's own routing key. Single-subscriber entries (the default path) are unaffected. 3. Calldata case (P2): a bytes/bytesN arg's encoded segment preserves the caller's own hex casing verbatim (unlike an address), so two calls with the same bytes value but different hex-string casing keyed differently. The key now lowercases the encoded calldata before hashing; the call's own calldata/args sent to the executor are untouched. Adds 3 regression tests to src/__tests__/dedup.test.ts (16 tests total): conflicting overload pairing, per-subscriber error key metadata, and bytes32-casing merge. Updates the two failure-fan-out tests' identity assertions for the new per-subscriber clone semantics. Bundle-size badge updated to the measured 13.0KB gzip. --------- Co-authored-by: halaprix <halaprix@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements spec F7 (1.2.0):
dedupe(default false): within-step, cross-task merging of eligible calls, strictly pre-bisection. Key =(target.toLowerCase(), lowercased calldata, canonicalOutputSignature)with the spec'scanonverbatim — order-preserving, tuple-component names included (named vs unnamed tuples never collide), overloads resolved by selector so identical calldata with different decoders is never merged (the first-decoder-wins corruption the key exists to prevent — regression-tested with adversarial overload pairings).TypedCallSpec-compiled calls (internalDEDUPE_ELIGIBLE, default true, per-calldedupe: falseopt-out); legacyStepCalls never merge —Presets.throughputcannot change legacy-task semantics (tested with the full preset spread). Keying failures make a call ineligible (dedup introduces no new failure modes).DominoCallErrorinstances with each subscriber's ownkey(sharedcauseidentity preserved) so no cross-task mutable sharing or wrong metadata.Presets.throughput = { maxConcurrentBatches: 5, adaptiveBatching: true, dedupe: true } as constexported.dedupeis off (1:N mapping degrades to 1:1). Counting-executor hit-rate section added to benchmarks.md (empirically verified numbers).Test evidence
256/256 (16 dedup tests incl. the spec's conflicting-output-ABIs two-wire-calls case, adversarial overload regression, bytes hex-case merge, bisection interplay), compat-vs-dist 38/38, full gate build-first. Gzip 13.0KB (<15KB).
Spec:
spec.md§ 1.2.0 F7 + Presets.