Skip to content

DIAGNOSTIC — DO NOT MERGE: switch_relays → relay.nsec.app + proxy second sub#5

Closed
DocNR wants to merge 8 commits into
mainfrom
test/switch-relays-nsec-app-diagnostic
Closed

DIAGNOSTIC — DO NOT MERGE: switch_relays → relay.nsec.app + proxy second sub#5
DocNR wants to merge 8 commits into
mainfrom
test/switch-relays-nsec-app-diagnostic

Conversation

@DocNR
Copy link
Copy Markdown
Owner

@DocNR DocNR commented Apr 19, 2026

This PR is a diagnostic. It must not be merged. It will be closed and the branch deleted after the test completes, regardless of outcome.

Purpose

Validate the proxy-per-client-relay architectural direction end-to-end with minimal code before committing to the full 1-2 day backlog implementation. Two coordinated changes:

  • iOS (Shared/LightSigner.swift): switch_relays RPC now returns ["wss://relay.nsec.app"] instead of ["wss://relay.powr.build"]. For Coracle (whose nostrconnect URI already contains relay.nsec.app), welshman should treat this as a pool narrowing rather than a migration — no UI stall.
  • Proxy (relay-proxy/proxy.js): parameterized connectRelay(relayUrl, subId) and fans out over RELAY_URL + SECONDARY_RELAY_URLS (defaults to wss://relay.nsec.app). When a sign_event arrives on the secondary relay for a registered pubkey, the same APNs push pipeline fires. Adds a [Compliance] log line per kind:24133 event for per-client PRIMARY/SECONDARY classification.

Expected outcomes (truth table)

Coracle pairing UI advances Coracle sign completes Interpretation
proxy-per-client-relay architectural direction validated end-to-end
welshman narrowing hypothesis right; signing path has a distinct issue to isolate
welshman narrowing hypothesis wrong; need a different mechanism

Scope

In: one-line iOS switch_relays response change + ~60-line proxy multi-relay sub refactor + a structured [Compliance] log line.

Out: any other iOS behavior, any persistence of per-client URI relays (the full proxy-per-client-relay work this diagnostic de-risks), any switch_relays response policy change beyond the relay URL swap.

Revert plan

After the test outcome is recorded:

  1. On Dell: git checkout main && git pull --rebase origin main && sudo cp relay-proxy/proxy.js /opt/clave-proxy/proxy.js && sudo systemctl restart clave-proxy
  2. On Mac: bump pbxproj to build 16, Archive + upload to internal TestFlight from main (supersedes the diagnostic build 15)
  3. Close this PR, delete the branch

Trip-wires against accidental merge

  • This PR is marked draft
  • The iOS change carries a multi-line // DIAGNOSTIC 2026-04-19 comment naming this plan
  • The proxy change carries a matching comment at SECONDARY_RELAY_URLS

Plan

Local: `~/hq/clave/plans/2026-04-19-switch-relays-nsec-app-diagnostic.md` (not in repo — lives in the sprint docs tree)

Context docs (local):

  • `~/hq/clave/troubleshooting/2026-04-19-coracle-nostrconnect-ui-stall.md` — root-cause investigation + H1 null probe
  • `~/hq/clave/specs/nsecapp-comparison-2026-04-19.md` — why this relay choice isolates the welshman bug

Notes

  • Test relay usage: using wss://relay.nsec.app without asking. Fine for a single diagnostic session with light load; reverted before it matters.
  • TestFlight: internal-only for build 15. Never promote to external.
  • Branch protection: main has linear history + no force push, so there's no mechanical risk of this sneaking in.

DocNR added 5 commits April 19, 2026 11:27
First probe returned ["wss://relay.nsec.app"] and Coracle's UI still stalled,
disproving the welshman-narrowing hypothesis. Pivoting to return null (Amber's
responder-only pattern) + keeping the proxy's secondary sub on relay.nsec.app,
to validate whether the real architectural combo lets sign_event complete.

Plan: ~/hq/clave/plans/2026-04-19-switch-relays-nsec-app-diagnostic.md
@DocNR
Copy link
Copy Markdown
Owner Author

DocNR commented Apr 19, 2026

Pivot (2026-04-19 second probe)

Build 15 probe result: Coracle UI did not advance — disproves the welshman-narrowing hypothesis. Any non-null switch_relays response triggers migration, even if the new list is a subset.

Pivoting, not reverting yet. Two new commits pivot the iOS side to Amber's responder-only pattern (return "null") while keeping the proxy's secondary sub on relay.nsec.app. This tests the actually-right architectural combo — iOS null + proxy watches client URI relays — end-to-end on TestFlight build 16.

Commits:

  • 25e6e0b test: pivot — switch_relays returns null (Amber pattern)
  • acc29b7 chore: bump pbxproj to build 16

Proxy deploy on Dell unchanged — already running the secondary sub from the first probe.

Decision tree still applies after build 16:

  • pair ✅ + sign ✅ → proxy-per-client-relay fully validated, PR still closes, revert proceeds, real implementation gets strong evidence
  • pair ✅ + sign ❌ → surfaces a real issue with the proxy secondary sub (0 events caught in probe 1); separate follow-up
  • pair ❌ → contradicts H1 probe; deeper re-investigation

Still draft. Still do not merge.

DocNR added 3 commits April 19, 2026 13:40
…not merge)

Probe B found 0 events on relay.nsec.app secondary sub despite successful
connection. Grep confirmed Clave's own NSE/app/AppState all use narrow
kinds:24133 + #p:signerPubkey filters; the proxy was using a broad
kinds:24133 filter. Strict relays appear to drop broad subs. Probe C
narrows secondary subs to registered signer pubkeys at sub-open time to
validate that hypothesis.

Plan: ~/hq/clave/plans/2026-04-19-switch-relays-nsec-app-diagnostic.md
… not merge)

Pyramid + fevela tests showed requests arrived on their URI relays (via proxy
secondary subs), APNs fired, NSE woke and signed — but response was always
routed to SharedConstants.relayURL (relay.powr.build) because LightSigner's
bunker/NSE fallback branch hardcoded it. Clients not subscribed to
relay.powr.build timed out waiting.

Fix: thread push-payload relay_url through NotificationService +
ClaveApp (AppDelegate push handler) to LightSigner.handleRequest as
responseRelayUrl, used as the publish target when responseRelays aren't
provided. Matches the per-event relay_url the proxy already sends.

Plan: ~/hq/clave/plans/2026-04-19-switch-relays-nsec-app-diagnostic.md
@DocNR
Copy link
Copy Markdown
Owner Author

DocNR commented Apr 19, 2026

Probe E (build 17) — final-mile fix

Probes B-D established that pyramid and fevela fail to accept Clave's signed response even when the proxy catches the request on their URI relay and APNs fires successfully.

Grep revealed why: Shared/LightSigner.swift:252's else branch hardcodes SharedConstants.relayURL (relay.powr.build) as the response publish target. The NSE was already receiving the correct per-event relay_url from the push payload — it just wasn't threading it through.

Fix commits:

  • ddcb0c8 test(probe-e): NSE publishes response on relay request arrived on
  • 702f285 chore: bump pbxproj to build 17

Changes:

  • LightSigner.handleRequest + sendErrorResponse accept a new optional responseRelayUrl: String? param (no change for existing responseRelays callers — nostrconnect handshake path untouched)
  • Fallback publish branch uses responseRelayUrl ?? SharedConstants.relayURL
  • NotificationService.swift + ClaveApp.swift push handlers pass the push payload's relay_url through as responseRelayUrl

Proxy-side config (Dell .env SECONDARY_RELAY_URLS) is extended to wss://relay.nsec.app, wss://bucket.coracle.social, wss://relay.primal.net, wss://nos.lol to cover pyramid + fevela + Coracle URIs. This env override is temporary and reverts along with the rest.

Still draft. Still do not merge.

@DocNR
Copy link
Copy Markdown
Owner Author

DocNR commented Apr 19, 2026

Closing — architecture fully validated, changes upstreaming as separate PRs

Five probes, three client library families, full end-to-end validation complete. Summary:

  • iOS null switch_relays — fixes UI advance for welshman-based clients (Coracle). Confirmed TestFlight.
  • Proxy secondary subs with #p filter — catches kind:24133 on strict relays like relay.nsec.app; broad filters are silently dropped.
  • NSE response-publish on origin relay — probe E's critical fix. LightSigner's bunker/NSE fallback was hardcoding SharedConstants.relayURL, routing every NSE-wake response to relay.powr.build regardless of where the request came from. Build 17 plumbs relay_url from the push payload through to the publish target. After fix: fevela + Coracle both complete full signing round-trip.

Full write-up: ~/hq/clave/troubleshooting/2026-04-19-switch-relays-nsec-app-e2e.md

Followup PRs (new branches off main, not this branch):

  • small: fix(signer): switch_relays returns null (Amber pattern)
  • small: fix(nse): publish response on relay request arrived on (probe E iOS fix)
  • larger: feat(proxy): per-client URI relay subscriptions (dynamic per-signer #p secondary subs + per-event relay_url in push payload; already largely prototyped in probe C+E)

Dell proxy reverted to main. Build 18 supersedes 15/16/17 on ASC after Archive.

Closing; branch will be deleted.

@DocNR DocNR closed this Apr 19, 2026
@DocNR DocNR deleted the test/switch-relays-nsec-app-diagnostic branch April 19, 2026 18:51
@DocNR DocNR mentioned this pull request Apr 19, 2026
4 tasks
DocNR added a commit that referenced this pull request May 2, 2026
Brainstorm review of design-system.md against shipped code surfaced 9
inconsistencies + 1 anti-pattern still present. Fixed everything in one
batch so the next TestFlight archive carries it all.

Code:
- HomeView: drop .padding(.bottom, 8) on SlimIdentityBar invocation —
  slim banner owns its outer bottom padding (12pt); stacking another 8pt
  on top was double-counting (review #4)
- HomeView: drop .padding(.bottom, 8) inside statsRow — listSectionSpacing(0)
  carries the gap to Connected Clients; the residual padding kept the
  visible gap excessive after polish round 2 (review #2)
- AccountDetailView: avatarLarge letter fallback opacity 0.25 → 0.22 to
  align with SlimIdentityBar's 0.22 (review #3)
- ConnectSheet: add .presentationBackground(Color(.systemGroupedBackground))
  — was the last sheet still defaulting to translucent (review #9)
- ApprovalSheet: rename @State capExceeded → showConnectionCapAlert for
  naming convention parity with HomeView (review #7)

design-system.md:
- New "Cross-platform applicability" section at the top — clarifies what
  carries directly to clave.casa web companion (color tokens, displayLabel
  rule, identity-vs-functional zone philosophy, avatar treatments, copy
  patterns, anti-patterns) vs what's iOS-only (SwiftUI modifiers, haptics,
  sheet/toolbar conventions)
- §3 Typography: corrected initial-letter font scale — AvatarView uses
  size*0.35 mono (pubkey) or size*0.4 proportional (name); was wrongly
  documented as a single 0.37 (review #1)
- §4 Avatars: added Treatment Selection Rule table (B on neutral bg,
  C on saturated theme gradient) + clarified 1-vs-2 letter behavior
  (review #5, #6)
- §4 Sizing scale: expanded table to include initial font + border
  thickness per slot, with the ~5% border scaling rule (review #8)
- §5 Spacing: explicit "single source of truth" note on slim banner
  bottom padding; new "Stats row" subsection capturing the
  ultraThinMaterial-on-small-cards-OK rule (review gap #10, #4)
- §6 HomeView gradient: documented palette[0] defensive fallback when
  currentAccount is nil (review #13)
- §7 Patterns: new "State variable naming" subsection with the
  showCapAlert / showAccountCapAlert / showConnectionCapAlert
  convention (review #7 doc side)
- §11 Anti-patterns: audit-point note that ConnectSheet was the last
  surface to acquire .presentationBackground (review #9 doc side)

Build green on iOS Simulator 26.4. pbxproj still 41 — assumes user hasn't
yet archived 41; bump to 42 if needed before re-archive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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