Carry the operator identity in the pairing seed (NIP-19 nprofile) #62
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The pairing seed (
spire-seed:v1:, #52) carries the spire identity + relays + bunker URL, but the operator identity is still provisioned separately asVITE_OPERATOR_PUBKEYS. During the 2026-06-21 Sintra bunker smoke we had to hand-supply the operator pubkey (3d8eabbf…) alongside the seed. That's a second out-of-band value, and the end-goal is a single QR scan that fully provisions the machine.The operator pubkey isn't cosmetic —
operator-config.ts/operator-fees.tssubscribe to the operator's kind-30078 fee/cassette config withauthors: [operatorPubkey], and the cassette-state hello isnip44_encrypt'd to it. Without it the machine can't receive operator config.Proposal — put the operator in the seed as a NIP-19
nprofilenprofile(NIP-19) is the canonical nostr primitive for "a pubkey + where to find them": a bech32 TLV with the 32-byte pubkey (type 0) + optional relay hints (type 1). Add it to the seed JSON:Why
nprofilespecifically (vs. a bareoperator_pubkeyhex):VITE_OPERATOR_PUBKEYSto provision; one artifact, one eventual QR.VITE_RELAY_URL; the operator may publish elsewhere. The nprofile's relay TLV is exactly this hint (NIP-19 §1: relay).nostr-toolsnip19.nprofileEncode/decodeon both sides; nothing bespoke.Work
Producer (
aiolabs/spirekeeper,pairing.py): includeoperator: nprofileEncode({pubkey, relays})when minting (pair_spire); seed-contract version bump. The operator pubkey + its relays are already known operator-side.Consumer (
aiolabs/bitspire):seed.ts— parse theoperatornprofile →{ pubkey, relays }.signer-resolver.ts/lightning.ts— feed the operator pubkey intooperatorPubkeysand the relay hints into the operator-config/fees subscriptions; persist on thebunker_binding.VITE_OPERATOR_PUBKEYSwhen the seed has nooperator(v1 seeds).Robustness sub-task (independent, small): normalize
VITE_OPERATOR_PUBKEYSthroughparsePublicKey(already inidentity.ts, handles hex/npub/nprofile → hex) so operators can paste any form. Today it's a raw.split(',')and an npub silently matches nothing (confirmed during the smoke — the value must be 64-hex).Refs
nprofile—refs/repos/nostr/nostr-protocol/nips/19.md~/dev/coordination/smoke-bunker-pairing-sintra.md); legs 1+2 (pair + resume) passed with the operator hand-provisioned.aiolabs/spirekeeper.