Skip to content

docs(superpowers): 5 design specs from PR-E + sipher#262 follow-up list#276

Merged
rz1989s merged 6 commits into
mainfrom
docs/superpowers-spec-followups-2026-05-15
May 17, 2026
Merged

docs(superpowers): 5 design specs from PR-E + sipher#262 follow-up list#276
rz1989s merged 6 commits into
mainfrom
docs/superpowers-spec-followups-2026-05-15

Conversation

@rz1989s
Copy link
Copy Markdown
Member

@rz1989s rz1989s commented May 15, 2026

Summary

Five design specs bundled as follow-ups to PR-E (#269 canonical Torque ingest) and PR #271 (sipher#262 signing callback). All proposed in spec form — none are implementation; each is sized 1 PR (or 3 PRs for the largest) and can be picked off independently. Ordered smallest → largest below.

Specs

  1. 2026-05-15-assert-never-exhaustiveness-design.md — Compile-time exhaustiveness guards on the AgentCore.streamMessage + chunkToSSE switches. Closes the silent-drop trap caught at PR-E holistic review (sipher#262 f62b308). Small (~0.5 day). Foundation for the other specs.

  2. 2026-05-15-tool-signing-expired-sse-design.mdtool_signing_expired SSE event so SignTxCard greys out when the 5-min promise-gate TTL hits. Removes the "ghost card" UX. Small-medium (1-1.5 days).

  3. 2026-05-15-server-side-sig-verification-design.md — Three-tier getSignatureStatuses + getTransaction verification before resolvePendingSigning runs. Adds SIPHER_SIG_VERIFY=strict|advisory|off env flag mirroring the SENTINEL_MODE precedent. Medium (2-3 days).

  4. 2026-05-15-claim-phase-2-design.md — Replace the Phase 1 claim stub with real ECDH derivation + claim_transfer instruction building. Surfaces the viewing-key-shared-with-server trust step that today's stub already implicitly accepts. Medium-large (4-6 days).

  5. 2026-05-15-scheduled-op-broadcasts-design.md — Per-tool execution strategy for drip / splitSend / sweep / consolidate / recurring / scheduleSend. Three families: immediate batch, pre-signed durable nonce, wallet delegation (Squads Smart Account → custom program). Largest (3 PRs across 2-3 weeks).

Why a single bundled docs PR

The specs cross-reference each other ([[name]] Wiki-link syntax). Most of them are coupled to the same surface — pending-signing.ts, ResponseChunk, chunkToSSE, the growth-hook emission table. Reviewing together surfaces the shared concerns; merging together prevents the cross-refs from being broken Wikilink dead-ends.

If individual PRs are preferred for execution, splitting later is trivial — each spec is self-contained.

Status of each spec

All five are Proposed — awaiting RECTOR review. Nothing here ships behavior; each can be approved/revised/discarded independently.

Cross-references

Common dependencies, captured for review:

  • Spec 2 (signing_expired) depends on Spec 1 (assertNever) landing first
  • Spec 3 (sig verification) composes with Spec 4 (claim Phase 2)
  • Spec 5 (scheduled-op) composes with all four others

Test plan

  • No code change — typecheck not exercised
  • All five files exist at expected paths under docs/superpowers/specs/
  • Cross-references ([[name]]) resolve to actual filenames in this PR
  • No AI attribution trailers in commit messages
  • All commits GPG-signed
  • RECTOR review: approve / revise / defer per spec

@vercel
Copy link
Copy Markdown

vercel Bot commented May 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sipher Ready Ready Preview, Comment May 17, 2026 1:43am

@rz1989s
Copy link
Copy Markdown
Member Author

rz1989s commented May 15, 2026

Amendment added (commit 331c302)

Added a "SDK reality check (2026-05-15)" section to Spec 4 (claim Phase 2). During scoping for the implementation PR, discovered that @sip-protocol/sdk@^0.7.4 already exposes claimStealthPayment which subsumes Steps 1-3 of the original Implementation section.

What changed:

  • Original spec implied 4-6 days of building announcement parser + ECDH module + claim_transfer instruction + tool-signing wrapper extension
  • SDK reality: claimStealthPayment(viewingPrivKey, spendingPrivKey, ...) derives + builds + signs + broadcasts in one call

Two paths now documented:

  • Path A (recommended): SDK-driven claim. ~3-4 hour scope. One-shot server call. No SignTxCard. Honest Torque attribution from day one.
  • Path B: Fork SDK to separate build + broadcast to keep the original SignTxCard UX. 4-6 day scope. Flagged as "security theater" since the user has already delegated viewing+spending keys to the server — SignTxCard click doesn't gate the cryptography.

Recommendation: ship Path A. Phase 1 stub is shipping incorrect Torque attribution today (deposit-tx-sig instead of claim-tx-sig); Path A fixes that with minimum new code. Path B can be a follow-up if the consent-ceremony UX is later prioritized.

Original Implementation / Test plan sections kept intact in the spec as the Path B reference. Amendment is appended; nothing destructive.

cc @Rector — please review whether Path A's recommendation matches your judgment before any implementation PR opens against this spec.

rz1989s added 6 commits May 17, 2026 08:43
Adds compile-time exhaustiveness checks for the two discriminated-union
switches that translate streaming events between layers — AgentCore.streamMessage
and chunkToSSE in adapters/web.ts. Motivated by the cross-file plumbing drop
caught at PR-E holistic review (sipher#262 commit f62b308): adding a new
ResponseChunk variant requires coordinated edits across three files, and
today's switches silently skip unhandled cases at runtime instead of failing
at build time.

Spec covers: assertNever helper at packages/agent/src/core/assert-never.ts,
declared ChatStreamEvent union for the Pi event side, two patterns
(narrowed-discriminant vs full-variant), test plan including type-only
expectTypeOf assertions, and follow-ups (ResponseChunk → tagged union,
codebase-wide switch audit, lint rule).
Proposes a proactive expiry SSE event so SignTxCards grey out when the
promise-gate TTL hits. Today the 5-minute timeout rejects the pending
signing promise but never notifies the SSE client — cards stay in
"pending sign" state indefinitely, late signs hit 404 confirm routes,
and the chat thread shows a confusing assistant turn next to an
unmarked clickable card.

Spec covers: event shape ({type, flagId, reason}), server emission via
the existing externalQueue mechanism (same path sentinel_pause uses),
onExpire callback wired into createPendingSigning, client-side message
expiry state with greyed-out SignTxCard rendering, test plan (server +
client + integration). Depends on the assertNever spec landing first
to catch the three-switch fanout at typecheck.
Today's POST /api/tool-signing/:flagId/confirm blindly trusts the
client-supplied signature string. A compromised browser, buggy client,
or replay attack can submit syntactically-valid garbage and Torque
attribution fires for non-existent transactions. Spec adds RPC-based
verification before resolvePendingSigning runs.

Spec covers: three-tier verification (existence via getSignatureStatuses,
sender-binding via getTransaction fee-payer check, instruction-match
deferred), SIPHER_SIG_VERIFY=strict|advisory|off env flag mirroring
the SENTINEL_MODE precedent, advisory-mode soak-test rollout path,
latency budget (~250-1000ms acceptable), failure posture (closed-by-default
with operator override), and risks including RPC quota burn, replay
attack residual surface, and webhook-alternative tradeoffs.
Today's executeClaim is a Phase 1 stub — returns serializedTx: null and a
placeholder "Stealth key derived" message without performing actual ECDH
or building the on-chain claim_transfer instruction. Yet the Torque
growth-hook fires sipher_private_claim_completed with the input deposit-tx
signature as the emission key, polluting attribution.

Spec covers: ECDH stealth-private-key recovery from announcement +
viewing/spending keys, announcement parser, claim_tx builder (signs
server-side with ephemeral stealth keypair, leaves fee-payer signature
to the client via existing tool-signing wrapper), growth-hook adjustment
to emit claim-tx signature instead of deposit-tx signature, viewing-key
exposure surface analysis (sensitive — server-side ECDH delegation is
a real trust step), test plan (announcement parsing, ECDH round-trip,
end-to-end devnet flow), and follow-ups (SPL token path, client-side
ECDH variant, in-flight claim dedupe).
…+ delegation)

The crank (COURIER) ticks every 60s and picks up scheduled_ops rows,
but executeTool routes through the tool-signing wrapper that requires
real-time user signing — so scheduled ops "fail" silently after the
5-min promise-gate TTL. Spec defines per-tool execution strategies
across three families.

Spec covers:
- Immediate batch (splitSend, consolidate): user signs N txs in one
  session via wallet.signAllTransactions; minutes horizon
- Pre-signed durable nonce (scheduleSend, drip): user pre-signs N
  txs each anchored to a single-use durable nonce account at create
  time; server broadcasts at scheduled times; hours-to-weeks horizon
- Wallet delegation (sweep, recurring): scope-limited authority via
  Squads Smart Account (Phase A) or custom sipher_delegation program
  (Phase B, future); indefinite horizon

Plus: per-tool classification table, on-chain trust analysis for each
family, COURIER hardening (backoff, single-flight, observability, atomic
status CAS), test plan per family, risks (operator-key compromise,
signed-tx blob leakage, privacy regression with Squads, recipient
meta-address rotation), and a 3-PR rollout (PR-A durable nonce, PR-B
Squads delegation, PR-C COURIER hardening).
The original Spec 4 (claim Phase 2) assumed the server would build
claim_transfer from scratch — own announcement parser, own ECDH
derivation, own partial-sign + serialize for client-side fee-payer
signing via the tool-signing wrapper.

Discovered during implementation scoping that @sip-protocol/sdk@^0.7.4
already exposes the complete primitive surface:

  parseAnnouncement(memo) → SolanaAnnouncement | null
  scanForPayments(params) → SolanaScanResult[]
  claimStealthPayment(params) → { txSignature, destinationAddress, ... }
  deriveStealthPrivateKey + deriveSolanaStealthKeys

claimStealthPayment is the kicker — it accepts the user's viewing+spending
private keys and internally derives the stealth privkey, builds
claim_transfer, signs with the stealth keypair, and BROADCASTS. The
SignTxCard / tool-signing wrapper flow from the original spec doesn't fit:
no client-side signing is needed because the SDK handles everything
server-side with delegated keys.

Amendment adds:
- "SDK reality check (2026-05-15)" section to the spec
- Path A: SDK-driven claim (recommended; ~3-4 hour scope; one-shot
  server call; no SignTxCard; honest Torque attribution from day one)
- Path B: Fork SDK to separate build + broadcast (original spec's UX;
  4-6 day scope; flagged as "security theater" since the keys are
  already server-side regardless)
- Revised Implementation steps (5 steps, Path A)
- Revised test plan (5-6 tests instead of 15+)
- Revised migration / rollout (frontend changes none required)
- Path A-specific risks (stealth address resolution, SDK version drift)

The original Implementation / Test plan sections stay intact in the
document as the Path B reference if the consent-ceremony UX is later
prioritized.

Recommendation: ship Path A. Phase 1 stub is shipping incorrect Torque
attribution today (deposit-tx-sig instead of claim-tx-sig); Path A fixes
that in a small, focused PR. Path B can be a follow-up if RECTOR decides
the SignTxCard ceremony is worth the build cost.
@rz1989s rz1989s force-pushed the docs/superpowers-spec-followups-2026-05-15 branch from 331c302 to 9ec524c Compare May 17, 2026 01:43
@rz1989s rz1989s merged commit 5fe9b46 into main May 17, 2026
6 checks passed
@rz1989s rz1989s deleted the docs/superpowers-spec-followups-2026-05-15 branch May 17, 2026 01:45
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