Carry-over from #40 item #2 PR (#41). The integration test
test/integration/cli-wallet-lifecycle.integration.test.ts —
`sphere init --nametag ` mints the nametag during wallet creation
intermittently fails against public testnet. The PR landed the
canonical-UX regex fix (matches `nametag : @`) but the
underlying race + transient-timeout shape remains.
This is the "right" fix split out of #40 so it can be tracked
separately.
Repro
```bash
from sphere-cli working copy
npm run build
SPHERE_ALLOW_MNEMONIC_NON_TTY=1 \
npx vitest run --config vitest.integration.config.ts \
test/integration/cli-wallet-lifecycle.integration.test.ts
```
Failing assertion (when it fails):
```
expected 'Initializing wallet on testnet...\n...' to match
/nametag\s*:\s*@it_/
with the actual identity block printing \`nametag : (none)\`. The
companion test in the same file —
> \`sphere nametag my\` reports the registered nametag after init --nametag
— **passes consistently**, which proves the mint actually went
through; only the in-process render missed it.
## Three failure modes
1. **In-process state propagation gap (the load-bearing one).**
\`Sphere.init({ nametag })\` mints on-chain, but the identity
object the CLI prints in \`src/legacy/legacy-cli.ts\` (\`case 'init':\`,
~line 1640) is read before the post-mint identity refresh
propagates. So the mint succeeded but \`identity.nametag\` is
still \`undefined\` when \`renderIdentity()\` runs.
2. **Aggregator latency.** \`goggregator-test.unicity.network\` is
shared infra; the submit → poll → inclusion-proof round-trip
can spike past the test's 240s budget under load. Real network
tail, not really a flake.
3. **Nostr publish in-band with the mint.** \`Sphere.init({ nametag })\`
also publishes the nametag-binding event to
\`nostr-relay.testnet.unicity.network\` so peers can resolve
\`@<name>\` later. If the publish stalls, the whole init await
stalls. The Nostr binding doesn't have to be in-band — peers
re-resolve lazily and the binding is republished when the
wallet next opens.
## Proposed fix
### sphere-cli — make the identity block reflect post-mint state
In \`legacy-cli.ts\` \`case 'init':\` (~1640), after the
\`Sphere.init({ nametag })\` await completes, **re-read identity from
\`sphere.identity\`** instead of using whatever was captured before
the mint. Today the print sequence and the mint sequence race; the
fix is to make the print depend on the mint.
If the SDK doesn't expose a \"identity is now fresh\" signal, fall
back to re-fetching after a single yield (\`await Promise.resolve()\`)
— ugly but bounded.
### sphere-sdk — make Nostr publish out-of-band (best-effort)
\`Sphere.init({ nametag })\` should:
- complete the on-chain mint (in-band — this IS the operation the
user asked for)
- fire-and-forget the Nostr binding publish (out-of-band, retried
by the transport layer's existing republish hooks)
Today both run in-band. Splitting them means a Nostr relay outage
doesn't fail \`init --nametag\` — the on-chain token is what matters
for ownership; the Nostr binding is a discoverability cache.
Probably one-line change in \`NametagMinter\` / \`registerNametag\`
to drop \`await\` on the publish.
### Test budget
Once the fix lands, the 240s timeout in the test should be
reduced (current value was generous specifically to absorb the
Nostr publish stall). 180s is reasonable.
## Acceptance criteria
- [ ] Identity block printed by \`sphere init --nametag <name>\`
contains \`nametag : @<name>\` synchronously after the mint
completes — no \`(none)\` race.
- [ ] \`sphere init --nametag\` does NOT block on Nostr publish
success. A stalled relay should still let init succeed (mint
is what counts).
- [ ] Test budget in
\`cli-wallet-lifecycle.integration.test.ts\` cut to 180s; test
reliably green over 5 consecutive runs.
- [ ] Companion test (\`nametag my reports\`) continues to pass
(the on-chain mint and local persistence are unchanged).
## Out of scope
- Multi-target / multi-asset selector flags (issue #40 item #3,
separately deferred).
- NFT-only \`invoice pay\` flow (issue #40 item #4, separately
deferred).
## Related
- sphere-cli #40 — parent followup bundle
- sphere-cli #41 — the regex-scrub PR that this carries forward
from (#41 made the test correctly identify the mint failure;
this issue fixes the underlying race)
- CLAUDE.md \"When nametag token is minted on-chain\" — references
the four entry points (\`Sphere.init({ nametag })\`,
\`sphere.registerNametag()\`, \`cli init --nametag\`, \`cli nametag\`).
Fix should cover all of them, not just the cli case.
Carry-over from #40 item #2 PR (#41). The integration test
test/integration/cli-wallet-lifecycle.integration.test.ts—intermittently fails against public testnet. The PR landed the
canonical-UX regex fix (matches `nametag : @`) but the
underlying race + transient-timeout shape remains.
This is the "right" fix split out of #40 so it can be tracked
separately.
Repro
```bash
from sphere-cli working copy
npm run build
SPHERE_ALLOW_MNEMONIC_NON_TTY=1 \
npx vitest run --config vitest.integration.config.ts \
test/integration/cli-wallet-lifecycle.integration.test.ts
```
Failing assertion (when it fails):
```
expected 'Initializing wallet on testnet...\n...' to match
/nametag\s*:\s*@it_/