docs: complete Phase 532 invites, plan Phase 533 guild-admin (v0.8.495)

Update PLATFORM_ROADMAP, INVITES, ONBOARDING, AGENTCTL, and CONTACTS for the
second invites depth pass and the upcoming guild-admin phase.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-05-24 12:04:14 -04:00
co-authored by Cursor
parent 91f7a5298b
commit a8d2d98b23
5 changed files with 150 additions and 62 deletions
+9
View File
@@ -244,6 +244,15 @@ PEARCORD_SKIP_MESH_ROUNDTRIP=1 npm run test:agentctl-phase516-contacts
Extends `test:contacts` + `test:block-contacts` + `test:friend-presence` with split contacts guild-loading compositor (`syncContactsPanelsDuringGuildLoading`), platform `contacts.request`/`accept`/`decline` span metadata, dev-log **contacts-errors** filter + clipboard contacts meta, `#composer-contacts-hint`, `lastFriendRowId`, and Phase 515 DMs regression. Agentctl: `test:contacts` headless roundtrip.
**Invites depth (v0.8.495):** Primary Phase 532 verification — combined bundle:
```bash
npm run test:phase532-invites
PEARCORD_SKIP_MESH_ROUNDTRIP=1 npm run test:agentctl-phase532-invites
```
Extends `test:phase531-dms` regression with split invites compositor panels (`syncInvitesHubPanelDuringGuildLoading`, `syncInvitesJoinPanelDuringGuildLoading`, `syncInvitesInvitePanelDuringGuildLoading`), platform invite span metadata (`guild.invite` `spanKind`/`hasShareCode`, `invite.join` `activeChannelId`/`guildCount`), anchored **invite-errors** filter, clipboard `invitesHubBusy`/`invitesHubButtonsBusy`/`inviteCopyBusy`, invite code `aria-current=location`, ui-flow `composer-focus-channel` after `join-invite`, and headless `createGuildInvite`/`joinGuildInvite`/`revokeGuildInvite`. Agentctl: `test:invite` + `smoke-agentctl-invites-phase532`.
**DMs depth (v0.8.494):** Primary Phase 531 verification — combined bundle:
```bash
+2
View File
@@ -16,6 +16,8 @@ Outgoing requests temporarily join the peers topic (`client: true`) and gossi
**v0.8.479 (Phase 516):** `syncContactsPanelsDuringGuildLoading` — add-friend modal, pending in/out, friend list, actions; `#composer-contacts-hint`; `setFriendRowCurrent` + `lastFriendRowId`. Dev-log **contacts-errors** filter (`contacts.request|accept|decline`); **dm-errors** DM-only. Platform span metadata on all three contact RPCs. Bundle: `npm run test:phase516-contacts`.
**v0.8.495 (Phase 532):** Invites depth pass 2 — see [INVITES.md](./INVITES.md). Bundle: `npm run test:phase532-invites`.
**v0.8.494 (Phase 531):** DMs depth pass 2 — see [DM.md](./DM.md). Bundle: `npm run test:phase531-dms`.
**v0.8.478 (Phase 515):** `syncDmsPanelsDuringGuildLoading` composes sidebar, friend actions, DM composer guards; dev-log **dm-errors** tightened (no discovery); clipboard `lastDmRowId` / `dmsGuildLoading`. Platform `dm.send`, `dm.group.create`, extended `dm.open` `spanKind`/`peerDisplayNameLen`. Bundle: `npm run test:phase515-dms`. See [DM.md](./DM.md).
+24 -9
View File
@@ -6,9 +6,9 @@ Pearcord invites are **fully local and portable** — no central invite service.
| Step | API / UI | Notes |
|------|----------|-------|
| Create | `platform.createInvite()` / **Invite** header button | `guild.invite` span; 24h TTL default |
| Join | `platform.joinInvite(code)` / **Join a server** modal | Resolves portable or short code |
| Revoke | `platform.revokeInvite(code)` | Deletes local `@pearcord/invites` row (Manage Server) |
| Create | `platform.createInvite()` / **Invite** header button | `guild.invite` span (`spanKind`, `hasShareCode`); 24h TTL default |
| Join | `platform.joinInvite(code)` / **Join a server** modal | `invite.join` span (`activeChannelId`, `guildCount`); portable or short code |
| Revoke | `platform.revokeInvite(code)` | `invite.revoke` span; deletes local `@pearcord/invites` row (Manage Server) |
## Portable format
@@ -16,20 +16,35 @@ Pearcord invites are **fully local and portable** — no central invite service.
- Includes: `guildId`, `guildName`, `topic`, `channels[]`, `expiresAt`, `maxUses`, `uses`
- Module: `pearcord-invite` (`encodePortable` / `decodePortable`)
## UI (v0.8.477 Phase 514)
## UI (v0.8.495 Phase 532)
- `syncInvitesPanelsDuringGuildLoading` — hub **Invite** / **Join** buttons, invite friends modal, join modal paused during guild switch
- `syncInvitesHubPanelDuringGuildLoading` — hub **Invite** / **Join** buttons + `aria-busy` during guild switch
- `syncInvitesJoinPanelDuringGuildLoading` — join modal paused during guild load
- `syncInvitesInvitePanelDuringGuildLoading` — invite friends modal + copy panel
- `setInviteModalCurrent` — invite code box `aria-current="location"` + roving `tabindex`
- `#composer-invite-hint` — guild-loading, open invite modal, manage-server invite shortcut, needs-guild join hint
- Dev-log **invite-errors** filter: `guild.invite`, `invite.join`, `invite.revoke`
- Clipboard meta: `invitesGuildLoading`, `inviteModalBusy`, `joinModalBusy`, `lastInviteFocusCode`
- Dev-log **invite-errors** filter (anchored `$`): `guild.invite`, `invite.join`, `invite.revoke`
- Clipboard meta: `invitesHubBusy`, `invitesHubButtonsBusy`, `inviteCopyBusy`, `invitesGuildLoading`, `inviteModalBusy`, `joinModalBusy`, `lastInviteFocusCode`
## ui-flow
After `join-invite`, when `platform.mode === 'guild'` and `activeChannelId` is set, ui-flow emits `composer-focus-channel` so the message composer receives focus (Discord parity).
## Tests
```bash
npm run test:invite
npm run test:onboarding-mesh
npm run test:phase514-invites
PEARCORD_SKIP_MESH_ROUNDTRIP=1 npm run test:agentctl-phase514-invites
npm run test:phase532-invites
PEARCORD_SKIP_MESH_ROUNDTRIP=1 npm run test:agentctl-phase532-invites
```
Targeted Phase 532 smokes (no full regression chain):
```bash
npm run test:invites-panels-guild-loading-extend-532
npm run test:platform-invite-span-metadata-extend-532
npm run test:ui-flow-invite-composer-focus-extend-532
```
See also [ONBOARDING.md](./ONBOARDING.md) (join flow) and [DISCOVERY.md](./DISCOVERY.md) (public listing invite attach).
+2
View File
@@ -46,6 +46,8 @@ Expect: `ONBOARDING_SMOKE_OK`
**v0.8.419 (Phase 456):** Register autofocus `#reg-username`; after register focus **Create Server**; join modal invite autofocus + empty validation toast; device pair **Enter** submits `#device-pair-input`; empty guild banner hint polish; `register first` toast when creating guild without identity. Session boot `aria-busy`, composer autofocus on `sessionReady`, platform `session.startup` / `identity.register` / `guild.open` spans. See [SESSION.md](./SESSION.md). Bundle: `npm run test:phase456-onboarding-session`.
**v0.8.495 (Phase 532):** Second invites depth pass — split hub/join/invite compositor panels; platform `guild.invite` `spanKind`/`hasShareCode`, `invite.join` `activeChannelId`/`guildCount`; anchored **invite-errors**; clipboard invites hub busy meta; invite code `aria-current=location`; ui-flow composer focus after `join-invite`; agentctl `createGuildInvite`/`joinGuildInvite`/`revokeGuildInvite`. See [INVITES.md](./INVITES.md). Bundle: `npm run test:phase532-invites`.
**v0.8.477 (Phase 514):** Split invites guild-loading compositor (`syncInvitesPanelsDuringGuildLoading`); platform `guild.invite`/`invite.join`/`invite.revoke` spans; `PearcordInvite#revoke`; dev-log **invite-errors** filter; `#composer-invite-hint`. See [INVITES.md](./INVITES.md). Bundle: `npm run test:phase514-invites`.
**v0.8.474 (Phase 511):** Split onboarding guild-loading compositor (`syncOnboardingPanelsDuringGuildLoading` — register card, session loading, create/join modals, home-rail actions). Platform spans: `identity.register` (`usernameLen`, `displayNameLen`, `hadGuilds`), `guild.create` (`channelCount`, `isFirstGuild`, `listOnDiscovery`), `invite.join` (`inviteLen`, `guildId`). Dev log **onboarding-errors** filter; clipboard meta (`onboardingStep`, `registerPending`, `needsGuild`, modal busy flags). `#composer-onboarding-hint` for guild-loading, session boot, needs-guild, and Explore prompt. Bundle: `npm run test:phase511-onboarding` (extends Phase 456 + six `-extend-511` smokes + `test:phase510-permissions` regression).
+113 -53
View File
@@ -12869,66 +12869,125 @@ Fix guild switching, session boot gating, and theme/prefs application before mic
| P531-49 | UI: DM P2P fanout re-verify | [x] |
| P531-50 | Phase 532 invites depth (v0.8.495) | [x] |
**Next:** ~~Phase 531~~ (complete). Split DMs compositor (`syncDmsSidebarPanelDuringGuildLoading`, `syncDmsComposerPanelDuringGuildLoading`); platform `dm.open` `dmConversationCount`/`activeChannelId`, `dm.send` `sealed`/`groupDm`, `dm.group.create` `peerUserIdsLen`; anchored **dm-errors** (`$`); clipboard `dmSidebarBusy`/`dmComposerBusy`/`dmEncryptBadgeLive`; DM row `aria-current=location`; E2E badge `role=status`; agentctl `openDmWithPeer`/`createGroupDm`/`sendDmMessage`; bundle `npm run test:phase531-dms`. Phase 532 planned (50 items).
**Next:** ~~Phase 531~~ (complete). Split DMs compositor (`syncDmsSidebarPanelDuringGuildLoading`, `syncDmsComposerPanelDuringGuildLoading`); platform `dm.open` `dmConversationCount`/`activeChannelId`, `dm.send` `sealed`/`groupDm`, `dm.group.create` `peerUserIdsLen`; anchored **dm-errors** (`$`); clipboard `dmSidebarBusy`/`dmComposerBusy`/`dmEncryptBadgeLive`; DM row `aria-current=location`; E2E badge `role=status`; agentctl `openDmWithPeer`/`createGroupDm`/`sendDmMessage`; bundle `npm run test:phase531-dms`. ~~Phase 532~~ complete (v0.8.495).
---
### Phase 532 — Invites depth (v0.8.495)
### Phase 532 — Invites depth (v0.8.495)
| ID | Item | Status |
|----|------|--------|
| P532-1 | Invites: create invite roundtrip re-verify | [ ] |
| P532-2 | Invites: join invite roundtrip re-verify | [ ] |
| P532-3 | Invites: revoke invite roundtrip re-verify | [ ] |
| P532-4 | UI: split invites guild-loading compositor extend | [ ] |
| P532-5 | UI: invite modal panel guild-loading guard extend | [ ] |
| P532-6 | UI: join modal panel guild-loading guard extend | [ ] |
| P532-7 | UI: invite copy panel guild-loading guard extend | [ ] |
| P532-8 | Platform: `guild.invite` span metadata extend | [ ] |
| P532-9 | Platform: `invite.join` span metadata extend | [ ] |
| P532-10 | Platform: `invite.revoke` span metadata extend | [ ] |
| P532-11 | Logging: dev-log **invite-errors** filter tighten | [ ] |
| P532-12 | Logging: dev-log clipboard invite meta extend | [ ] |
| P532-13 | Agentctl: invite create headless re-verify | [ ] |
| P532-14 | Agentctl: invite join headless re-verify | [ ] |
| P532-15 | Agentctl: combined phase532 invites bundle | [ ] |
| P532-16 | Smoke: invites-panels-guild-loading-extend-532 | [ ] |
| P532-17 | Smoke: dev-log-invite-errors-tighten-extend-532 | [ ] |
| P532-18 | Smoke: dev-log-clipboard-invite-meta-extend-532 | [ ] |
| P532-19 | UI: composer invite hint extend | [ ] |
| P532-20 | UI: invite row aria-current polish | [ ] |
| P532-21 | UI: invite expiry copy re-verify | [ ] |
| P532-22 | UI: keyboard roving in invite list re-verify | [ ] |
| P532-23 | UI: invite modal live region re-verify | [ ] |
| P532-24 | UI: composer autofocus after invite copy re-verify | [ ] |
| P532-25 | Invites: portable code format re-verify | [ ] |
| P532-26 | Invites: deep link format re-verify | [ ] |
| P532-27 | Invites: mesh invite gossip re-verify | [ ] |
| P532-28 | Invites: discovery invite attach re-verify | [ ] |
| P532-29 | Docs: `INVITES.md` refresh | [ ] |
| P532-30 | Docs: `ONBOARDING.md` join section | [ ] |
| P532-31 | Docs: `AGENTCTL.md` phase 532 bundle | [ ] |
| P532-32 | Regression: DMs phase 531 smokes still pass | [ ] |
| P532-33 | Regression: contacts phase 530 smokes still pass | [ ] |
| P532-34 | Boot: session ready gate | [ ] |
| P532-35 | Boot: pear run gate | [ ] |
| P532-36 | Module: `pearcord-invite` README accuracy | [ ] |
| P532-37 | Module: `pearcord-platform` README invites section | [ ] |
| P532-38 | Smoke: platform-invite-span-metadata-extend-532 | [ ] |
| P532-39 | UI: invite escape focus re-verify | [ ] |
| P532-40 | UI: invite toast copy re-verify | [ ] |
| P532-41 | UI: companion invite defer re-verify | [ ] |
| P532-42 | UI: dev-log clipboard invite diff meta extend | [ ] |
| P532-43 | UI: server hub join shortcut re-verify | [ ] |
| P532-44 | UI: settings invite cross-link re-verify | [ ] |
| P532-45 | UI: audit log invite events re-verify | [ ] |
| P532-46 | UI: baseline deep link invite re-verify | [ ] |
| P532-47 | UI: invite validation copy re-verify | [ ] |
| P532-48 | UI: invite audit log entries re-verify | [ ] |
| P532-49 | UI: invite P2P fanout re-verify | [ ] |
| P532-50 | Phase 533 guild-admin depth (v0.8.496) | [ ] |
| P532-1 | Invites: create invite roundtrip re-verify | [x] |
| P532-2 | Invites: join invite roundtrip re-verify | [x] |
| P532-3 | Invites: revoke invite roundtrip re-verify | [x] |
| P532-4 | UI: split invites guild-loading compositor extend | [x] |
| P532-5 | UI: invite modal panel guild-loading guard extend | [x] |
| P532-6 | UI: join modal panel guild-loading guard extend | [x] |
| P532-7 | UI: invite copy panel guild-loading guard extend | [x] |
| P532-8 | Platform: `guild.invite` span metadata extend | [x] |
| P532-9 | Platform: `invite.join` span metadata extend | [x] |
| P532-10 | Platform: `invite.revoke` span metadata extend | [x] |
| P532-11 | Logging: dev-log **invite-errors** filter tighten | [x] |
| P532-12 | Logging: dev-log clipboard invite meta extend | [x] |
| P532-13 | Agentctl: invite create headless re-verify | [x] |
| P532-14 | Agentctl: invite join headless re-verify | [x] |
| P532-15 | Agentctl: combined phase532 invites bundle | [x] |
| P532-16 | Smoke: invites-panels-guild-loading-extend-532 | [x] |
| P532-17 | Smoke: dev-log-invite-errors-tighten-extend-532 | [x] |
| P532-18 | Smoke: dev-log-clipboard-invite-meta-extend-532 | [x] |
| P532-19 | UI: composer invite hint extend | [x] |
| P532-20 | UI: invite row aria-current polish | [x] |
| P532-21 | UI: invite expiry copy re-verify | [x] |
| P532-22 | UI: keyboard roving in invite list re-verify | [x] |
| P532-23 | UI: invite modal live region re-verify | [x] |
| P532-24 | UI: composer autofocus after invite copy re-verify | [x] |
| P532-25 | Invites: portable code format re-verify | [x] |
| P532-26 | Invites: deep link format re-verify | [x] |
| P532-27 | Invites: mesh invite gossip re-verify | [x] |
| P532-28 | Invites: discovery invite attach re-verify | [x] |
| P532-29 | Docs: `INVITES.md` refresh | [x] |
| P532-30 | Docs: `ONBOARDING.md` join section | [x] |
| P532-31 | Docs: `AGENTCTL.md` phase 532 bundle | [x] |
| P532-32 | Regression: DMs phase 531 smokes still pass | [x] |
| P532-33 | Regression: contacts phase 530 smokes still pass | [x] |
| P532-34 | Boot: session ready gate | [x] |
| P532-35 | Boot: pear run gate | [x] |
| P532-36 | Module: `pearcord-invite` README accuracy | [x] |
| P532-37 | Module: `pearcord-platform` README invites section | [x] |
| P532-38 | Smoke: platform-invite-span-metadata-extend-532 | [x] |
| P532-39 | UI: invite escape focus re-verify | [x] |
| P532-40 | UI: invite toast copy re-verify | [x] |
| P532-41 | UI: companion invite defer re-verify | [x] |
| P532-42 | UI: dev-log clipboard invite diff meta extend | [x] |
| P532-43 | UI: server hub join shortcut re-verify | [x] |
| P532-44 | UI: settings invite cross-link re-verify | [x] |
| P532-45 | UI: audit log invite events re-verify | [x] |
| P532-46 | UI: baseline deep link invite re-verify | [x] |
| P532-47 | UI: invite validation copy re-verify | [x] |
| P532-48 | UI: invite audit log entries re-verify | [x] |
| P532-49 | UI: invite P2P fanout re-verify | [x] |
| P532-50 | Phase 533 guild-admin depth (v0.8.496) | [x] |
**Next:** P532-1P532-49.
**Next:** ~~Phase 532~~ (complete). Split invites compositor (`syncInvitesHubPanelDuringGuildLoading`, `syncInvitesJoinPanelDuringGuildLoading`, `syncInvitesInvitePanelDuringGuildLoading`); platform `guild.invite` `spanKind`/`hasShareCode`, `invite.join` `activeChannelId`/`guildCount`, `invite.revoke` `spanKind`; anchored **invite-errors** (`$`); clipboard `invitesHubBusy`/`invitesHubButtonsBusy`/`inviteCopyBusy`; invite code box `aria-current=location` + roving `tabindex`; ui-flow `composer-focus-channel` after `join-invite`; agentctl `createGuildInvite`/`joinGuildInvite`/`revokeGuildInvite`; bundle `npm run test:phase532-invites`. Phase 533 planned (50 items).
---
### Phase 533 — Guild admin depth (v0.8.496)
| ID | Item | Status |
|----|------|--------|
| P533-1 | Guild admin: channel create roundtrip re-verify | [ ] |
| P533-2 | Guild admin: channel delete roundtrip re-verify | [ ] |
| P533-3 | Guild admin: category reorder roundtrip re-verify | [ ] |
| P533-4 | UI: split guild-admin guild-loading compositor extend | [ ] |
| P533-5 | UI: channel list editor guild-loading guard extend | [ ] |
| P533-6 | UI: category drag guild-loading guard extend | [ ] |
| P533-7 | UI: channel permissions shortcut guild-loading guard extend | [ ] |
| P533-8 | Platform: `channel.create` span metadata extend | [ ] |
| P533-9 | Platform: `channel.delete` span metadata extend | [ ] |
| P533-10 | Platform: `channel.reorder` span metadata extend | [ ] |
| P533-11 | Logging: dev-log **guild-admin-errors** filter tighten | [ ] |
| P533-12 | Logging: dev-log clipboard guild-admin meta extend | [ ] |
| P533-13 | Agentctl: channel create headless re-verify | [ ] |
| P533-14 | Agentctl: channel delete headless re-verify | [ ] |
| P533-15 | Agentctl: combined phase533 guild-admin bundle | [ ] |
| P533-16 | Smoke: guild-admin-panels-guild-loading-extend-533 | [ ] |
| P533-17 | Smoke: dev-log-guild-admin-errors-tighten-extend-533 | [ ] |
| P533-18 | Smoke: dev-log-clipboard-guild-admin-meta-extend-533 | [ ] |
| P533-19 | UI: composer guild-admin hint extend | [ ] |
| P533-20 | UI: channel row aria-current polish | [ ] |
| P533-21 | UI: channel type filter re-verify | [ ] |
| P533-22 | UI: keyboard roving in channel list re-verify | [ ] |
| P533-23 | UI: admin modal live region re-verify | [ ] |
| P533-24 | UI: composer autofocus after channel save re-verify | [ ] |
| P533-25 | Guild admin: NSFW channel toggle re-verify | [ ] |
| P533-26 | Guild admin: slowmode preset re-verify | [ ] |
| P533-27 | Guild admin: voice user limit re-verify | [ ] |
| P533-28 | Guild admin: forum tag palette re-verify | [ ] |
| P533-29 | Docs: `SERVER_SETTINGS.md` refresh | [ ] |
| P533-30 | Docs: `CHANNELS.md` refresh | [ ] |
| P533-31 | Docs: `AGENTCTL.md` phase 533 bundle | [ ] |
| P533-32 | Regression: invites phase 532 smokes still pass | [ ] |
| P533-33 | Regression: DMs phase 531 smokes still pass | [ ] |
| P533-34 | Boot: session ready gate | [ ] |
| P533-35 | Boot: pear run gate | [ ] |
| P533-36 | Module: `pearcord-guild` README accuracy | [ ] |
| P533-37 | Module: `pearcord-platform` README guild-admin section | [ ] |
| P533-38 | Smoke: platform-guild-admin-span-metadata-extend-533 | [ ] |
| P533-39 | UI: guild-admin escape focus re-verify | [ ] |
| P533-40 | UI: guild-admin toast copy re-verify | [ ] |
| P533-41 | UI: companion guild-admin defer re-verify | [ ] |
| P533-42 | UI: dev-log clipboard guild-admin diff meta extend | [ ] |
| P533-43 | UI: no-viewable-channels help re-verify | [ ] |
| P533-44 | UI: channel header menu cross-link re-verify | [ ] |
| P533-45 | UI: audit log channel events re-verify | [ ] |
| P533-46 | UI: deep link channel admin re-verify | [ ] |
| P533-47 | UI: guild-admin validation copy re-verify | [ ] |
| P533-48 | UI: guild-admin audit log entries re-verify | [ ] |
| P533-49 | UI: guild-admin P2P fanout re-verify | [ ] |
| P533-50 | Phase 534 roles depth (v0.8.497) | [ ] |
**Next:** P533-1P533-49.
---
@@ -14379,6 +14438,7 @@ Absorbed into Phase 273 (P273-5P273-8, P273-11P273-12). See Phase 274 for
- **2026-05-24** — v0.8.479: Phase 516 — split contacts guild-loading compositor; `contacts.request`/`accept`/`decline` span metadata; dev-log contacts-errors filter + clipboard contacts meta; bundle `test:phase516-contacts`. Phase 517 planned.
- **2026-05-24** — v0.8.478: Phase 515 — split DMs guild-loading compositor; `dm.open`/`dm.send`/`dm.group.create` span metadata; dev-log dm-errors filter tighten + clipboard DM meta; bundle `test:phase515-dms`. Phase 516 planned.
- **2026-05-24** — v0.8.477: Phase 514 — split invites guild-loading compositor; `guild.invite`/`invite.join`/`invite.revoke` span metadata; dev-log invite-errors filter + clipboard meta; bundle `test:phase514-invites`. Phase 515 planned.
- **2026-05-24** — v0.8.495: Phase 532 — split invites compositor (`syncInvitesHubPanelDuringGuildLoading`, `syncInvitesJoinPanelDuringGuildLoading`, `syncInvitesInvitePanelDuringGuildLoading`); platform invite span metadata (`guild.invite` `spanKind`/`hasShareCode`, `invite.join` `activeChannelId`/`guildCount`); anchored **invite-errors** (`$`); clipboard invites hub busy meta; invite code `aria-current=location`; ui-flow composer focus after `join-invite`; agentctl `createGuildInvite`/`joinGuildInvite`/`revokeGuildInvite`; bundle `test:phase532-invites`. Phase 533 planned (50 items).
- **2026-05-24** — v0.8.494: Phase 531 — split DMs compositor (`syncDmsSidebarPanelDuringGuildLoading`, `syncDmsComposerPanelDuringGuildLoading`); platform DM span metadata (`dmConversationCount`, `sealed`, `groupDm`); anchored **dm-errors**; clipboard DM busy meta; DM row `aria-current=location`; E2E badge live region; agentctl `openDmWithPeer`/`createGroupDm`/`sendDmMessage`; bundle `test:phase531-dms`. Phase 532 planned (50 items).
- **2026-05-24** — v0.8.493: Phase 530 — split contacts compositor (`syncContactsModalPanelDuringGuildLoading`, `syncContactsPendingPanelDuringGuildLoading`, `syncContactsFriendPanelDuringGuildLoading`); platform contact span counts; anchored **contacts-errors**; clipboard contacts busy meta; friend row `aria-current=location`; composer focus after accept-friend; agentctl friend request helpers; bundle `test:phase530-contacts`. Phase 531 planned (50 items).
- **2026-05-24** — v0.8.492: Phase 529 — split discovery compositor (`syncDiscoveryExplorePanelDuringGuildLoading`, `syncDiscoveryFilterPanelDuringGuildLoading`, `syncDiscoveryListingPanelDuringGuildLoading`); platform discovery span metadata (`peerCount`, `listingTtlMs`, `beforeListed`, `channelCount`); clipboard discovery busy meta; explore tag `aria-current=location`; agentctl `refreshPublicDiscovery`/`setDiscoveryFilter`; bundle `test:phase529-discovery`. Phase 530 planned (50 items).