docs: Phase 174 v0.8.139 roadmap, parity, and feature specs

Mark Phase 174 complete and plan Phase 175. Refresh SEARCH,
CHANNEL_CATEGORIES, NOTIFICATIONS, IPC, AUTOMATED_TESTING, and parity
for Home/End reveal, category label unread, dismiss describedby, and
mention-over-root guild pick.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-05-22 19:37:16 -04:00
co-authored by Cursor
parent dd537012ac
commit 34b11eb541
10 changed files with 47 additions and 16 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
# Pearcord architecture
**Current release:** v0.8.138 (desktop app `apps/pearcord`). Phase history and checklists live in [PLATFORM_ROADMAP.md](./PLATFORM_ROADMAP.md). Gap vs a centralized chat product is tracked in [PEARCORD_PARITY.md](./PEARCORD_PARITY.md).
**Current release:** v0.8.139 (desktop app `apps/pearcord`). Phase history and checklists live in [PLATFORM_ROADMAP.md](./PLATFORM_ROADMAP.md). Gap vs a centralized chat product is tracked in [PEARCORD_PARITY.md](./PEARCORD_PARITY.md).
Pearcord is a **100% peer-to-peer** community chat client on [Pear](https://pear.holepunch.to) / Bare. There is no Pearcord-operated message server: guilds, DMs, discovery listings, and bot events replicate over **Hyperswarm** topics with **protomux** framing.
+5 -1
View File
@@ -417,7 +417,11 @@ Pearcord validates itself without manual QA.
| `npm run test:channel-category-title-describedby` | Category title describedby (`CHANNEL_CATEGORY_TITLE_DESCRIBEDBY_SMOKE_OK`) |
| `npm run test:notif-mark-all-describedby` | Mark-all describedby (`NOTIF_MARK_ALL_DESCRIBEDBY_SMOKE_OK`) |
| `npm run test:guild-mixed-bucket-pick` | Mixed bucket pick (`GUILD_MIXED_BUCKET_PICK_SMOKE_OK`) |
| `npm run test:boot` | `pear run` pre-run (`BOOT_OK`) then Phase 124173 smokes + `test:companion-boot` |
| `npm run test:search-recent-chip-home-end-reveal` | Home/End reveal chips (`SEARCH_RECENT_CHIP_HOME_END_REVEAL_SMOKE_OK`) |
| `npm run test:channel-category-label-unread` | Category label unread (`CHANNEL_CATEGORY_LABEL_UNREAD_SMOKE_OK`) |
| `npm run test:notif-mark-all-dismiss-describedby` | Dismiss clears describedby (`NOTIF_MARK_ALL_DISMISS_DESCRIBEDBY_SMOKE_OK`) |
| `npm run test:guild-mention-root-bucket-pick` | Mention root bucket (`GUILD_MENTION_ROOT_BUCKET_PICK_SMOKE_OK`) |
| `npm run test:boot` | `pear run` pre-run (`BOOT_OK`) then Phase 124174 smokes + `test:companion-boot` |
| `npm run test:server-folder-prefs-mesh` | Live folder prefs mesh (optional; run manually — can exceed 150s on DHT) |
| `npm run test:profile` | Profile update + persist (`PROFILE_SMOKE_OK`) |
| `npm run test:e2e` | Full journey host+guest (`E2E_SMOKE_OK`) |
+1
View File
@@ -23,6 +23,7 @@ Gossip: existing `RPC.CHANNEL_CREATE` carries full channel row including `parent
## UI
- Category `aria-label` includes unread and mention totals when present (v0.8.139). Smoke: `npm run test:channel-category-label-unread`.
- Category `aria-describedby` pairs `category-title-{id}` with the hidden stats span (v0.8.138). Smoke: `npm run test:channel-category-title-describedby`.
- Collapsed and expanded categories: `aria-describedby` includes total unread and mention counts (v0.8.137). Smokes: `npm run test:channel-category-unread-describedby`, `npm run test:channel-category-collapsed-unread-describedby`.
- Expanded categories: `aria-describedby` includes total unread and mention counts for child channels (v0.8.136). Smoke: `npm run test:channel-category-unread-describedby`.
+1 -1
View File
@@ -1,6 +1,6 @@
# Pearcord documentation index
All project documentation lives in **`pearcord-docs`** (`/Users/raven/dev/pearcord/docs/`). **Release:** v0.8.138.
All project documentation lives in **`pearcord-docs`** (`/Users/raven/dev/pearcord/docs/`). **Release:** v0.8.139.
| Start here | Document |
|------------|----------|
+2 -2
View File
@@ -31,7 +31,7 @@ JSON lines over `pear-pipe` between `ui/app.js` and `apps/pearcord/index.js`. Ha
### Channel pick order (`select-guild` / `loadGuild`)
When a guild opens, `pearcord-platform` `_selectGuildChannelWithUnread` chooses the active text/forum/thread/announcement channel in this order (v0.8.138):
When a guild opens, `pearcord-platform` `_selectGuildChannelWithUnread` chooses the active text/forum/thread/announcement channel in this order (v0.8.139):
1. **Unread + mentions** — score `mentions × 1000 + unread` per channel. Pool selection:
- If every unread channel shares one category (`parentId`), only channels in that category compete (mention-weighted score, then lower `position` on ties). Smokes: `test:guild-single-category-pool`, `test:guild-mention-single-category-pick`, `test:guild-dual-category-isolation-pick`.
@@ -39,7 +39,7 @@ When a guild opens, `pearcord-platform` `_selectGuildChannelWithUnread` chooses
2. **`lastChannelByGuild`** — USER_PREFS last viewed channel for this guild when valid and viewable.
3. **First text channel** — lowest-position `text` channel, else first candidate.
Smokes: `test:guild-channel-pick-order` (IPC + platform source), `test:guild-unread-position-tie`, `test:guild-in-bucket-position-tie`, `test:guild-mention-in-bucket-pick`, `test:guild-mention-single-category-pick`, `test:guild-dual-category-isolation-pick`, `test:guild-mixed-bucket-pick`, `test:guild-bucket-total-over-minpos`, `test:guild-uncategorized-bucket-pick`, `test:guild-single-category-pool`, `test:guild-category-unread-pick`, `test:guild-category-bucket-pick`, `test:guild-mention-bucket-pick`, `test:guild-bucket-minpos-tie`, `test:guild-mention-channel-pick`, `test:guild-unread-over-last-channel`, `test:guild-last-channel-only-load`, `test:guild-no-unread-last-channel`, `test:guild-first-text-fallback`.
Smokes: `test:guild-channel-pick-order` (IPC + platform source), `test:guild-unread-position-tie`, `test:guild-in-bucket-position-tie`, `test:guild-mention-in-bucket-pick`, `test:guild-mention-single-category-pick`, `test:guild-dual-category-isolation-pick`, `test:guild-mixed-bucket-pick`, `test:guild-mention-root-bucket-pick`, `test:guild-bucket-total-over-minpos`, `test:guild-uncategorized-bucket-pick`, `test:guild-single-category-pool`, `test:guild-category-unread-pick`, `test:guild-category-bucket-pick`, `test:guild-mention-bucket-pick`, `test:guild-bucket-minpos-tie`, `test:guild-mention-channel-pick`, `test:guild-unread-over-last-channel`, `test:guild-last-channel-only-load`, `test:guild-no-unread-last-channel`, `test:guild-first-text-fallback`.
| `select-channel` | `channelId` | Set active text channel (voice IDs join voice) |
| `join-voice` | `channelId` | Join voice channel + gossip |
+1
View File
@@ -23,6 +23,7 @@ Skipped when:
- **Channel list** — existing unread + `@` pills
- **🔔 header** — inbox panel, prefs, mark all read; **click row jumps to message** (v0.8.35+)
- **Mark all read** — dedicated header button when unread rows exist (v0.8.115); smoke: `npm run test:notif-mark-all-header`
- **Dismiss clears describedby (v0.8.139)** — removing the mark-all status banner clears `aria-describedby` on the header button. Smoke: `npm run test:notif-mark-all-dismiss-describedby`
- **Mark-all describedby (v0.8.138)** — after mark-all, header button sets `aria-describedby="notif-mark-all-status"` on the status banner. Smoke: `npm run test:notif-mark-all-describedby`
- **Mark-all disabled label (v0.8.137)** — disabled header button sets `aria-label="Mark all read, all caught up"`; restored when unread returns. Smoke: `npm run test:notif-mark-all-btn-aria-label`
- **Mark-all full a11y (v0.8.136)** — mark-all banner smoke asserts `role`, `aria-live`, `aria-atomic`, `aria-relevant`, and `aria-label`. Smoke: `npm run test:notif-mark-all-status-full-a11y`
+13 -4
View File
@@ -4,14 +4,23 @@ Gap analysis between **Pearcord** (P2P Pear app) and a typical **centralized cha
> This is the only doc that compares against an external reference product. All other docs use Pearcord naming only.
## Summary (v0.8.139)
| Area | Reference product | Pearcord | Gap |
|------|-------------------|----------|-----|
| Search | Recent queries | Filtered nav + Home/End/arrow keys | Delete reveal (P175); no cloud |
| Channels | Categories | Label + describedby unread summary | Collapsed label unread (P175) |
| Notifications | Inbox | Mark-all describedby + dismiss cleanup | Restore describedby smoke (P175) |
| Guild open | Channel pick | Mention bucket over plain root | Root mention vs category (P175) |
## Summary (v0.8.138)
| Area | Reference product | Pearcord | Gap |
|------|-------------------|----------|-----|
| Search | Recent queries | Filtered nav + arrow/apply keys | Home/End reveal (P174); no cloud |
| Channels | Categories | Title + stats describedby | Category label unread (P174) |
| Notifications | Inbox | Mark-all label + describedby status | Status dismiss cleanup (P174) |
| Guild open | Channel pick | Mixed parent buckets | Mention bucket over root (P174) |
| Search | Recent queries | Filtered nav + arrow/apply keys | Home/End reveal (done P174); no cloud |
| Channels | Categories | Title + stats describedby | Category label unread (done P174) |
| Notifications | Inbox | Mark-all label + describedby status | Status dismiss cleanup (done P174) |
| Guild open | Channel pick | Mixed parent buckets | Mention bucket over root (done P174) |
## Summary (v0.8.137)
+20 -6
View File
@@ -803,16 +803,29 @@ When completing work, change `[ ]` → `[x]` and add a one-line note under **Cha
---
### Phase 174 — Inbox & guild depth (planned)
### Phase 174 — Inbox & guild depth (v0.8.139)
| ID | Item | Status |
|----|------|--------|
| P174-1 | Search: Home/End with filter reveal all before jump | [ ] |
| P174-2 | Channels: category `aria-label` includes unread summary | [ ] |
| P174-3 | Notifications: dismiss status clears mark-all `aria-describedby` | [ ] |
| P174-4 | Guild: smoke higher mention bucket beats plain root bucket | [ ] |
| P174-1 | Search: Home/End with filter reveal all before jump | [x] |
| P174-2 | Channels: category `aria-label` includes unread summary | [x] |
| P174-3 | Notifications: dismiss status clears mark-all `aria-describedby` | [x] |
| P174-4 | Guild: smoke higher mention bucket beats plain root bucket | [x] |
**Next:** Filtered Home/End reveal · category label unread · status dismiss · mention bucket smoke.
**Next:** ~~Filtered Home/End reveal · category label unread · status dismiss · mention root bucket smoke~~ (Phase 174).
---
### Phase 175 — Search & guild polish (planned)
| ID | Item | Status |
|----|------|--------|
| P175-1 | Search: Delete with filter reveals all before removing chip | [ ] |
| P175-2 | Channels: collapsed category `aria-label` unread summary | [ ] |
| P175-3 | Notifications: mark-all restore clears stale `aria-describedby` smoke | [ ] |
| P175-4 | Guild: smoke mention in root beats higher plain in category | [ ] |
**Next:** Filtered Delete reveal · collapsed label unread · restore describedby · root mention smoke.
---
@@ -2245,6 +2258,7 @@ When completing work, change `[ ]` → `[x]` and add a one-line note under **Cha
### Changelog
- **2026-05-22** — v0.8.139: Phase 174 — Home/End reveal filtered chips, category label unread, dismiss clears describedby, mention root bucket (`test:search-recent-chip-home-end-reveal`, `test:channel-category-label-unread`, `test:notif-mark-all-dismiss-describedby`, `test:guild-mention-root-bucket-pick`). Phase 175 planned.
- **2026-05-22** — v0.8.138: Phase 173 — Arrow reveals filtered chips, category title describedby, mark-all describedby status, mixed bucket pick (`test:search-recent-chip-arrow-reveal`, `test:channel-category-title-describedby`, `test:notif-mark-all-describedby`, `test:guild-mixed-bucket-pick`). Phase 174 planned.
- **2026-05-22** — v0.8.137: Phase 172 — Enter applies filtered chip, collapsed unread describedby, mark-all disabled label, dual-category isolation (`test:search-recent-chip-enter-apply`, `test:channel-category-collapsed-unread-describedby`, `test:notif-mark-all-btn-aria-label`, `test:guild-dual-category-isolation-pick`). Phase 173 planned.
- **2026-05-22** — v0.8.136: Phase 171 — Space applies filtered chip, category unread describedby, mark-all full a11y smoke, mention single-category pick (`test:search-recent-chip-space-apply`, `test:channel-category-unread-describedby`, `test:notif-mark-all-status-full-a11y`, `test:guild-mention-single-category-pick`). Phase 172 planned.
+1 -1
View File
@@ -2,7 +2,7 @@
Documentation for **[Pearcord](https://git.ssh.surf/pearcord)** — a 100% peer-to-peer community chat app on [Pear](https://pear.holepunch.to). No central message servers.
**Current release:** v0.8.138 (desktop app `apps/pearcord`).
**Current release:** v0.8.139 (desktop app `apps/pearcord`).
---
+2
View File
@@ -56,6 +56,8 @@ See also [FORUM_ARCHIVE_SEARCH.md](./FORUM_ARCHIVE_SEARCH.md).
**v0.8.115:** Guild-scoped recent queries persist in `userPrefs.searchRecentByGuild[guildId]` (max 8, deduped). `setSearch` records queries ≥2 chars. Desktop shows **recent chips** under the search input when scope is `guild` and the field is empty. Smokes: `npm run test:search-recent-prefs`, `npm run test:members-online-sort` (UI wiring).
**v0.8.139:** **Home** and **End** in the recent-chip listbox clear an active filter before jumping to the first or last chip. Smoke: `npm run test:search-recent-chip-home-end-reveal`.
**v0.8.138:** **Arrow** keys in the recent-chip listbox clear an active filter before moving roving focus. Smoke: `npm run test:search-recent-chip-arrow-reveal`.
**v0.8.137:** **Enter** with an active chip filter clears the filter and applies the focused chip (or first visible from the field). Smoke: `npm run test:search-recent-chip-enter-apply`.