Parent
#1 (fleet spec)
What to build
A machine's name is settable from both ends and safely carried on the wire. Daemon: pew2 pair [--name] (default os.hostname()), persisted, re-announced via the existing ProviderAnnounce.machine. App: a sealed SetName frame renames a machine in place — and unpair is real revocation: a sealed rotate/forget request makes the daemon rotate the pairing token (existing rotation path). Name validation runs at both trust boundaries (≤64 chars, control/bidi stripped, empty/whitespace rejected) before any announcement or notification title sees the value. The app only sends new frame types after receiving machine metadata from that daemon (skew gating). Demoable: a round-trip test renames a machine; an adversarial test proves an unproven sender cannot.
Acceptance criteria
Blocked by
None — can start immediately.
Parent
#1 (fleet spec)
What to build
A machine's name is settable from both ends and safely carried on the wire. Daemon:
pew2 pair [--name](defaultos.hostname()), persisted, re-announced via the existingProviderAnnounce.machine. App: a sealedSetNameframe renames a machine in place — and unpair is real revocation: a sealed rotate/forget request makes the daemon rotate the pairing token (existing rotation path). Name validation runs at both trust boundaries (≤64 chars, control/bidi stripped, empty/whitespace rejected) before any announcement or notification title sees the value. The app only sends new frame types after receiving machine metadata from that daemon (skew gating). Demoable: a round-trip test renames a machine; an adversarial test proves an unproven sender cannot.Acceptance criteria
pew2 pair --name Xpersists X and the next announce carries it; default is the hostnameSetNamefrom a proven paired app sender renames and re-announces; idempotent; rate-limitedSetNamefrom an unproven sender refused; replayed frame refusedunknown_messagecannot clear requests or kill push registration; old app → new daemon unaffectedBlocked by
None — can start immediately.