Skip to content

test(integration): regtest coverage residuals and test-only contracts - #147

Merged
icellan merged 2 commits into
mainfrom
feat/regtest-coverage-gaps
Aug 28, 2026
Merged

test(integration): regtest coverage residuals and test-only contracts#147
icellan merged 2 commits into
mainfrom
feat/regtest-coverage-gaps

Conversation

@icellan

@icellan icellan commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add integration/contracts/ for test-only fixtures (not human examples), plus a machine-checked coverage-matrix.json / check-matrix.mjs.
  • Phase A fund-safety residuals: Palmer branch-merged locals, cond multi-field write, conditional data outputs, 1-byte ByteString state framing, addRawOutput layout, and checkMultiSig 2-of-3 — with TS/Go on-chain state/output decode (not only SDK memory).
  • Seven-tier Phase A deploy+spend ports (TS, Go, Rust, Python, Ruby, Zig, Java); Zig MultiSig deferred honestly; MultiSig multi-key PrepareCall/FinalizeCall on TS+Go.
  • Soft multi-null-Sig warning no longer fires for genuine OP_CHECKMULTISIG (TS / Python / Rust).
  • Phase B/C language + preimage/intent/asm residual contracts with TS+Go regtest spends.

Test plan

  • SV Node regtest: TS residuals + Phase B/C (vitest under integration/ts)
  • SV Node regtest: Go residuals + Phase B/C (go test -tags integration -run 'BranchMerged|…|PhaseB|PhaseC')
  • MultiSig Go SDK path logs SDK_CALL_PATH; no OR-CHECKSIG soft-warn on MultiSig happy path
  • node integration/contracts/check-matrix.mjs exit 0
  • Python / Java / Rust / Ruby Phase A residual suites green on regtest
  • Zig zig build test-phase-a — 5 PhaseA_PASS + 7/7 suite (MultiSig deferred)
  • packages/runar-sdk soft-warning unit tests green
  • CI integration job on this PR

Add integration/contracts/ for fund-safety and language-feature fixtures
outside examples/, with a machine-checked coverage matrix. Phase A pins
Palmer constructs, MultiSig, raw/data outputs, and 1-byte ByteString state
on all seven tiers; TS/Go decode on-chain state/output layout. Soft-warn
for multi-null Sig no longer fires on OP_CHECKMULTISIG. Phase B/C language
and extract/intent/asm residual contracts ship with TS+Go regtest spends.
@icellan
icellan force-pushed the feat/regtest-coverage-gaps branch from 1c9aeee to cd7a637 Compare August 27, 2026 22:19
…scoping

The must-move-a-golden gate failed on PR #147: three constructor-slot-splicing
paths changed and no pinned byte artifact moved with them.

  ✗ packages/runar-py/runar/sdk/contract.py
  ✗ packages/runar-rs/src/sdk/contract.rs
  ✗ packages/runar-sdk/src/contract.ts

The gate matched the FILES, not the change. Each has exactly two hunks: a new
read-only OR-CHECKSIG probe, and one added '&& <probe>' conjunct on the
existing 'sigIndices.length >= 2' guard around an INFORMATIONAL warning — so a
genuine OP_CHECKMULTISIG unlock is no longer told to pass EMPTY_SIG. Neither
hunk is in the splicing path, and the probe's result feeds a warn() call and
nothing else, so no encoder, offset or byte-producing branch can observe it.

Evidence produced BEFORE granting the exception, not asserted:
  * conformance sdk-output — 59 fixtures x 7 SDKs, rust OK 59 / FAIL 0,
    exit 0. This is the cross-SDK deployed-locking-hex pin.
  * conformance sdk-vertical:check — 39 matrix rows match a fresh recompile
    (the compiler<->SDK byte pin).
  * conformance corpus 72/72, full vitest 9258 passed / 0 failed.

Three earlier sdk-output runs reported rust FAILED; every one was 'Blocking
waiting for file lock on build directory' — the runner falls back to
'cargo run' when tools/rs-sdk-tool is not pre-built, and the per-fixture
invocations contend on one target dir. Pre-building that binary makes rust
pass 59/59. Not a byte divergence, and worth knowing before anyone reads a
rust FAIL there as signal.

Entries are per-exact-path, pinned to each file's reviewed sha256 (so they
authorise this version only and self-invalidate on the next edit), expire
2026-11-26, and print in full on every gate run.

The exceptions file requires the entry count to be a deliberate edit to
scripts/__tests__/wire-format-pr-audit.test.ts rather than a quiet JSON
append, so that assertion is updated to pin the paths, the expiry, the
reviewer and the sha256 shape.

Doing so surfaced a real interaction: HISTORICAL_110_WIRE_PATHS — the changed
set of the #110 incident this gate exists for — CONTAINS
packages/runar-sdk/src/contract.ts, so the exception moved it out of wireHits
and the '--json' test went 8 -> 7. Lowering that expectation to 7 would delete
the property the test holds, so it now asserts
wireHits + exceptionsUsed == the historical set, plus set equality on the
union: an exception can move a path between buckets, never make one vanish.
@icellan
icellan merged commit a3fc34d into main Aug 28, 2026
42 checks passed
icellan added a commit to E-Jacko/runar that referenced this pull request Aug 29, 2026
CI's Python SDK job went red on main at a3fc34d with

  bsv/transaction_preimage.py:77
  AttributeError: 'NoneType' object has no attribute 'serialize'

across 5 tests. Nothing in that merge touched the Python SDK: bsv-sdk 2.4.0
was PUBLISHED THE SAME DAY (2026-08-28) and pyproject declares
'bsv-sdk>=1.0' with no ceiling, so icellan#147's PR run resolved <=2.3.3 and passed
while the merge run resolved 2.4.0 and failed. Same commit content, different
dependency.

2.4.0 tightened the batch preimage path: _inputs_to_tuples now dereferences
inp.locking_script.serialize() for EVERY input, and its docstring calls a
missing one 'a caller error'. That is a legitimate tightening, so the fix
belongs here rather than in a version pin. _sign_with_bsv receives a
SERIALIZED tx, which carries no source-output data, so it populated
locking_script only on the input it was signing; on a 2-input call (contract
UTXO + funding UTXO) input 0 was left None.

Every input now gets one, with an empty Script() placeholder where unknown.
That is sound rather than a workaround: BIP-143 binds only the SIGNING input's
scriptCode into its digest, and the other inputs reach that digest solely
through hashPrevouts and hashSequence, which hash outpoints and sequence
numbers — never scripts.

Verified, not argued: signing the exact 2-input shape that broke produces a
BYTE-IDENTICAL signature under both versions —

  2.3.3  30450221008c7345754faa4fda6ec9589734205dab67a22af441aff0eaf65835...
  2.4.0  30450221008c7345754faa4fda6ec9589734205dab67a22af441aff0eaf65835...

so the placeholders provably do not enter the digest. Full suite: 746 passed
under 2.4.0 AND under 2.3.3, so this does not trade a new break for the old
one.
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