test(v2): re-wire bitspire cross-test fixture for v1.1 positions-keyed shape (#29 v1.1)
Some checks failed
ci.yml / test(v2): re-wire bitspire cross-test fixture for v1.1 positions-keyed shape (#29 v1.1) (pull_request) Failing after 0s

Replaces the v1 fixture (denominations-keyed, 2026-05-30T13:15Z) with
bitspire's v1.1 fixture (positions-keyed, 2026-05-30T19:00Z log entry).
Drops the class-level @pytest.mark.skip from commit 1cebefc.

The v1.1 fixture intentionally includes two positions (1 + 2) both
holding denomination=20 — exercises the multi-same-denomination round-
trip end-to-end through encrypt → wire → decrypt → payload-validate.
Pinned explicitly in test_decrypts_bitspire_sample_event:

    assert payload["positions"]["1"]["denomination"] == 20
    assert payload["positions"]["2"]["denomination"] == 20
    assert payload["positions"]["1"]["count"] != payload["positions"]["2"]["count"]

So a future "fix" that re-introduces denom-uniqueness validation
surfaces at this test instead of as a runtime rejection on real
machines (the v1.1 operational case from coord-log 18:45Z).

Other two cross-tests (test_signature_verifies_via_lnbits_helper,
test_encrypt_round_trip_via_our_impl_decrypts_with_their_keys) carry
over from v1 unchanged — same shape, just the new fixture's keys +
event flow through them.

Total: 151 passed, 0 skipped, 1 pre-existing async-plugin failure
unchanged. PR #30 is now byte-compat-verified end-to-end with the
v1.1 wire shape; bitspire side is typecheck-green + about to cache-
push (per coord-log 20:55Z). Joint re-smoke on Sintra is the
remaining v1.1 step.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-05-30 22:43:12 +02:00
commit 4b128ca53c

View file

@ -243,81 +243,77 @@ class TestPaddingFormula:
# -----------------------------------------------------------------------------
# Bitspire-side fixture, posted to ~/dev/coordination/log.md at 2026-05-30T13:15Z.
# Throwaway keypairs (one-shot, never sign anything else) — safe to embed verbatim.
# Generated by apps/machine/src/services/operator-config.ts-shape code path using
# the @bitSpire/nostr-client encryptContentV2 + createSignedEvent helpers (same
# code the production bootstrap publish uses). Round-tripped on bitspire side
# before posting.
# Bitspire-side v1.1 fixture, posted to ~/dev/coordination/log.md at
# 2026-05-30T19:00Z. Positions-keyed wire shape per the v1.1 redesign
# (18:30Z + 18:45Z); intentionally includes two positions sharing
# denomination=20 to exercise the multi-same-denom round-trip on our
# decrypt + payload-validate path. Throwaway keypairs (one-shot, never
# sign anything else) — safe to embed verbatim.
# Generated by apps/machine/src/services/operator-config.ts-shape code
# path using the @bitSpire/nostr-client encryptContentV2 +
# createSignedEvent helpers (same code the production bootstrap publish
# uses). Round-tripped on bitspire side via decryptContentV2 before posting.
# -----------------------------------------------------------------------------
_BITSPIRE_FIXTURE = {
"atm_keypair": {
"privkey_hex": (
"a1601b05967cb421056f197008eca1dfa61f0eb5b505c277a0d4ca6b053e91f2"
"814e6188d017102bbf301ba5b38fba95b2556dc79a60df4cd50605c4593578e6"
),
"pubkey_hex": (
"8db588b6431edbbc0c4f7517bc90447cec34c866b7110e63c88e20a4cccd0e5c"
"217bdc9a65b571c4d9b59da6227a7aa6ca5bbfd5280af791417c57a79d92852b"
),
},
"operator_keypair": {
"privkey_hex": (
"216030bdda5aa47c37b74117bc29612bfc18d8122f70e80cb7a6d875c8699108"
"cca7dd9fe4874f6b9f3f3fae21648da686b7e714bfd4786e8fa8745933fd3185"
),
"pubkey_hex": (
"052f27837c3c46b5086825805b8d061ed64346e61cd0c3013725e544aa2a0b49"
"49bd8e615769f8b6a5aa8ce9617b919996abecf234599ba196789461cf239146"
),
},
"expected_plaintext": {
"denominations": {
"20": {"position": 1, "count": 49},
"50": {"position": 2, "count": 100},
"positions": {
"1": {"denomination": 20, "count": 49},
"2": {"denomination": 20, "count": 38},
"3": {"denomination": 50, "count": 100},
},
},
"event": {
"kind": 30078,
"content": (
"AgUSQOlYyF7JomOKqJSyAOF/O7yR1d2DYgXvXUS7sBMqRbKPM+ACmkT/R6owFd22nRf2"
"k+KEibEi+WcK6+acBwy1ThWP2NHUlrMp8qjUYrV1XXJXwRLOlLBe0LHmioFi6jTyJxSE"
"/Z+z79o7wki60CKDoNZqSRiScRN0lT7tzEgsFXo2vFzPdzEQwy/jk154DgBoCiRIRjtX"
"kBNGGlN9ABPPfw=="
"AqOHsCcjN2W8L/Cx0uH+n++VA13W+wy7z1EcuuNX49sSagelX2lI0HEKyd+ActOc"
"iaPsHrp9ecJTkEZOD86ioldbLbEVColJwK4g1uVZSbpDeqRe+97woxVDqPnzj507"
"tFaVLF/dRmda+oKHUzkVPhE4PHQJzp9Fqji38J3nU6N68qo7KOt3qg1nSy5eDfAu"
"zt7djRBx63+/veub0rWTMMQLBgci8+Ms6Y+Zb1mki3L6NWuIR0Or+8DhcD+ZJiOu"
"WTcx"
),
"tags": [
[
"d",
"bitspire-cassettes-state:"
"8db588b6431edbbc0c4f7517bc90447cec34c866b7110e63c88e20a4cccd0e5c",
"217bdc9a65b571c4d9b59da6227a7aa6ca5bbfd5280af791417c57a79d92852b",
],
[
"p",
"052f27837c3c46b5086825805b8d061ed64346e61cd0c3013725e544aa2a0b49",
"49bd8e615769f8b6a5aa8ce9617b919996abecf234599ba196789461cf239146",
],
],
"created_at": 1780156459,
"created_at": 1780173222,
"pubkey": (
"8db588b6431edbbc0c4f7517bc90447cec34c866b7110e63c88e20a4cccd0e5c"
"217bdc9a65b571c4d9b59da6227a7aa6ca5bbfd5280af791417c57a79d92852b"
),
"id": (
"28e2bd428bca5b522c037d06e962f5c2ed2e40c398f7ecf84ed5f6272ab77ae4"
"72c09f333386dd4ad6125f8c69823824eea50d8091b694458bcd60701517eece"
),
"sig": (
"8bbde91fb39cfe7026384ca89843b3f9aaf5b9a9a90ddc20e09bc056721438b2"
"9d032435e71bb16a5ac211c951de02d8e2f5422d9ee110653f6e3df72238f6dd"
"07ecafacf0169f074e564a999ee1c31446930b43391d007c4a1f9ef7ad890d6c"
"2aa6e3ecc5318edeb5748fbd64c7ca33407099a97154e2ff7e0c626e48d71925"
),
},
}
@pytest.mark.skip(
reason=(
"v1.1 wire-shape pivot (coord-log 2026-05-30T18:30Z + 18:45Z): the "
"13:15Z fixture above is encoded with the old `{denominations: ...}` "
"wire shape; the v1.1 wire shape is `{positions: {<pos>: "
"{denomination, count}}}`. Bitspire will post a fresh fixture against "
"the v1.1 shape; once posted, swap `_BITSPIRE_FIXTURE` for the new "
"JSON and drop this skip (v1.1 commit g on the PR)."
)
)
class TestBitspireCrossTest:
"""Byte-compat cross-test between our hand-rolled NIP-44 v2 (`nip44.py`)
and the nostr-tools NIP-44 v2 impl that bitspire uses on the ATM side
@ -328,8 +324,9 @@ class TestBitspireCrossTest:
def test_decrypts_bitspire_sample_event(self):
"""The load-bearing assertion: our `decrypt_from` recovers the
expected `{"denominations": {...}}` plaintext from bitspire's
encrypted event content."""
expected `{"positions": {...}}` plaintext from bitspire's encrypted
event content. v1.1 fixture intentionally exercises the multi-same-
denomination round-trip (positions 1 + 2 both hold $20)."""
import json
event = _BITSPIRE_FIXTURE["event"]
@ -342,7 +339,16 @@ class TestBitspireCrossTest:
operator_privkey,
event["pubkey"],
)
assert json.loads(plaintext) == _BITSPIRE_FIXTURE["expected_plaintext"]
payload = json.loads(plaintext)
assert payload == _BITSPIRE_FIXTURE["expected_plaintext"]
# v1.1 invariant: two positions can carry the same denomination.
# Pin it explicitly so a future "fix" that re-introduces denom-
# uniqueness validation surfaces here instead of as a runtime
# rejection on real machines.
assert payload["positions"]["1"]["denomination"] == 20
assert payload["positions"]["2"]["denomination"] == 20
assert payload["positions"]["1"]["count"] != payload["positions"]["2"]["count"]
def test_signature_verifies_via_lnbits_helper(self):
"""Optional extra per bitspire's 13:15Z note (3). The consumer