docs: Phase 165 v0.8.130 roadmap, parity, and feature specs
Mark Phase 165 complete (filtered Tab, section aria-controls, mark-all status label, bucket minPos guild pick). Document IPC bucket tie-break, add Phase 166 plan, and refresh SEARCH, CHANNEL_CATEGORIES, NOTIFICATIONS, AUTOMATED_TESTING, and parity summaries for v0.8.130. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Pearcord architecture
|
||||
|
||||
**Current release:** v0.8.129 (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.130 (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.
|
||||
|
||||
|
||||
@@ -381,7 +381,11 @@ Pearcord validates itself without manual QA.
|
||||
| `npm run test:channel-category-collapsed-current` | Collapsed category aria-current (`CHANNEL_CATEGORY_COLLAPSED_CURRENT_SMOKE_OK`) |
|
||||
| `npm run test:notif-mark-all-restore` | Mark-all re-enable (`NOTIF_MARK_ALL_RESTORE_SMOKE_OK`) |
|
||||
| `npm run test:guild-first-text-fallback` | First text fallback (`GUILD_FIRST_TEXT_FALLBACK_SMOKE_OK`) |
|
||||
| `npm run test:boot` | `pear run` pre-run (`BOOT_OK`) then Phase 124–151 smokes + `test:companion-boot` |
|
||||
| `npm run test:search-recent-chip-tab-all` | Tab reveals all chips (`SEARCH_RECENT_CHIP_TAB_ALL_SMOKE_OK`) |
|
||||
| `npm run test:channel-section-controls` | Section aria-controls (`CHANNEL_SECTION_CONTROLS_SMOKE_OK`) |
|
||||
| `npm run test:notif-mark-all-aria-label` | Mark-all status aria-label (`NOTIF_MARK_ALL_ARIA_LABEL_SMOKE_OK`) |
|
||||
| `npm run test:guild-bucket-minpos-tie` | Bucket minPos tie (`GUILD_BUCKET_MINPOS_TIE_SMOKE_OK`) |
|
||||
| `npm run test:boot` | `pear run` pre-run (`BOOT_OK`) then Phase 124–165 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`) |
|
||||
|
||||
@@ -23,6 +23,7 @@ Gossip: existing `RPC.CHANNEL_CREATE` carries full channel row including `parent
|
||||
|
||||
## UI
|
||||
|
||||
- Section headers (Text/Voice/Stage): `aria-controls` lists child channel row ids (`channel-row-{id}`) for text, voice, and stage sections (v0.8.130). Smoke: `npm run test:channel-section-controls`.
|
||||
- Section headers (Text/Voice/Stage): `aria-current` when a child channel is active (v0.8.128). Smoke: `npm run test:channel-section-aria-current`.
|
||||
- Category headers: `aria-current` when the active channel is in that category, including when the category is collapsed (v0.8.129). Smokes: `npm run test:channel-category-aria-current`, `npm run test:channel-category-collapsed-current`.
|
||||
- Level-1 tree: categories and uncategorized section headers share one `aria-posinset` / `aria-setsize` sequence (v0.8.126). Smoke: `npm run test:channel-tree-mixed-posinset`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Pearcord documentation index
|
||||
|
||||
All project documentation lives in **`pearcord-docs`** (`/Users/raven/dev/pearcord/docs/`). **Release:** v0.8.129.
|
||||
All project documentation lives in **`pearcord-docs`** (`/Users/raven/dev/pearcord/docs/`). **Release:** v0.8.130.
|
||||
|
||||
| Start here | Document |
|
||||
|------------|----------|
|
||||
|
||||
@@ -31,15 +31,15 @@ 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.129):
|
||||
When a guild opens, `pearcord-platform` `_selectGuildChannelWithUnread` chooses the active text/forum/thread/announcement channel in this order (v0.8.130):
|
||||
|
||||
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.
|
||||
- Otherwise group by parent bucket (category `parentId` or uncategorized `''`), pick the bucket with the highest **total** score (mention-weighted sum), then best channel inside the bucket (lower `position` on ties).
|
||||
- Otherwise group by parent bucket (category `parentId` or uncategorized `''`), pick the bucket with the highest **total** score (mention-weighted sum). On equal bucket totals, prefer the bucket whose unread channels have the lower **minimum** `position` (sibling index within that parent). Then pick the best channel inside the pool (lower `position` on score ties).
|
||||
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-category-unread-pick`, `test:guild-category-bucket-pick`, `test:guild-mention-bucket-pick`, `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-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 |
|
||||
|
||||
@@ -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`
|
||||
- **Mark-all status label (v0.8.130)** — “All notifications marked as read” banner sets `aria-label` for screen readers. Smoke: `npm run test:notif-mark-all-aria-label`
|
||||
- **Mark-all restore (v0.8.129)** — disabled mark-all button is re-enabled when unread returns to the open modal. Smoke: `npm run test:notif-mark-all-restore`
|
||||
- **Mark-all focus (v0.8.128)** — after mark-all, header button stays disabled and regains focus; re-enabled when unread returns. Smoke: `npm run test:notif-mark-all-focus`
|
||||
- **Status aria-live (v0.8.127)** — mark-all banner uses `aria-live="polite"`, `aria-atomic`, and `aria-relevant`; smoke: `npm run test:notif-mark-all-aria-live`
|
||||
|
||||
+13
-4
@@ -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.130)
|
||||
|
||||
| Area | Reference product | Pearcord | Gap |
|
||||
|------|-------------------|----------|-----|
|
||||
| Search | Recent queries | Home/End/ArrowUp/ArrowDown/Tab reveal all chips when filtered | Shift+Tab with filter (P166); no cloud |
|
||||
| Channels | Sidebar tree | Section `aria-controls` + category/section `aria-current` | Section aria-labelledby (P166) |
|
||||
| Notifications | Inbox | Mark-all label, focus, restore, status live | Status aria-atomic (P166) |
|
||||
| Guild open | Channel pick | Bucket minPos tie + in-bucket position tie | In-bucket position smoke (P166) |
|
||||
|
||||
## Summary (v0.8.129)
|
||||
|
||||
| Area | Reference product | Pearcord | Gap |
|
||||
|------|-------------------|----------|-----|
|
||||
| Search | Recent queries | Home/End/ArrowUp/ArrowDown reveal all chips when filtered | Tab with filter (P165); no cloud |
|
||||
| Channels | Categories | `aria-current` on active child even if category collapsed | Section aria-controls (P165) |
|
||||
| Notifications | Inbox | Mark-all focus, restore, status live, dismiss on new unread | Status aria-label (P165) |
|
||||
| Guild open | Channel pick | Last channel or first text when no unread | Bucket min-position tie (P165) |
|
||||
| Search | Recent queries | Home/End/ArrowUp/ArrowDown reveal all chips when filtered | Tab with filter (done P165); no cloud |
|
||||
| Channels | Categories | `aria-current` on active child even if category collapsed | Section aria-controls (done P165) |
|
||||
| Notifications | Inbox | Mark-all focus, restore, status live, dismiss on new unread | Status aria-label (done P165) |
|
||||
| Guild open | Channel pick | Last channel or first text when no unread | Bucket min-position tie (done P165) |
|
||||
|
||||
## Summary (v0.8.128)
|
||||
|
||||
|
||||
+20
-6
@@ -686,16 +686,29 @@ When completing work, change `[ ]` → `[x]` and add a one-line note under **Cha
|
||||
|
||||
---
|
||||
|
||||
### Phase 165 — Search & guild polish (planned)
|
||||
### Phase 165 — Search & guild polish (v0.8.130)
|
||||
|
||||
| ID | Item | Status |
|
||||
|----|------|--------|
|
||||
| P165-1 | Search: Tab with filter reveals all chips before first focus | [ ] |
|
||||
| P165-2 | Channels: `aria-controls` on section header for child rows | [ ] |
|
||||
| P165-3 | Notifications: `aria-label` on mark-all status banner | [ ] |
|
||||
| P165-4 | Guild: smoke bucket tie picks lower min position in bucket | [ ] |
|
||||
| P165-1 | Search: Tab with filter reveals all chips before first focus | [x] |
|
||||
| P165-2 | Channels: `aria-controls` on section header for child rows | [x] |
|
||||
| P165-3 | Notifications: `aria-label` on mark-all status banner | [x] |
|
||||
| P165-4 | Guild: smoke bucket tie picks lower min position in bucket | [x] |
|
||||
|
||||
**Next:** Filtered Tab · section aria-controls · status label · bucket min-pos smoke.
|
||||
**Next:** ~~Filtered Tab · section aria-controls · status label · bucket min-pos smoke~~ (Phase 165).
|
||||
|
||||
---
|
||||
|
||||
### Phase 166 — Inbox & guild depth (planned)
|
||||
|
||||
| ID | Item | Status |
|
||||
|----|------|--------|
|
||||
| P166-1 | Search: Shift+Tab with filter reveals all chips before last focus | [ ] |
|
||||
| P166-2 | Channels: `aria-labelledby` on section header from child row labels | [ ] |
|
||||
| P166-3 | Notifications: `aria-atomic` on mark-all status banner | [ ] |
|
||||
| P166-4 | Guild: smoke equal score in bucket picks lower channel position | [ ] |
|
||||
|
||||
**Next:** Filtered Shift+Tab · section aria-labelledby · status atomic · in-bucket position smoke.
|
||||
|
||||
---
|
||||
|
||||
@@ -2128,6 +2141,7 @@ When completing work, change `[ ]` → `[x]` and add a one-line note under **Cha
|
||||
|
||||
### Changelog
|
||||
|
||||
- **2026-05-22** — v0.8.130: Phase 165 — Tab reveals filtered chips, section `aria-controls`, mark-all status `aria-label`, bucket minPos tie (`test:search-recent-chip-tab-all`, `test:channel-section-controls`, `test:notif-mark-all-aria-label`, `test:guild-bucket-minpos-tie`). Phase 166 planned.
|
||||
- **2026-05-22** — v0.8.129: Phase 164 — ArrowUp reveals filtered chips, collapsed category `aria-current`, mark-all restore, first-text fallback (`test:search-recent-chip-arrow-up-all`, `test:channel-category-collapsed-current`, `test:notif-mark-all-restore`, `test:guild-first-text-fallback`). Phase 165 planned.
|
||||
- **2026-05-22** — v0.8.128: Phase 163 — End reveals filtered chips, section `aria-current`, mark-all focus, no-unread last channel (`test:search-recent-chip-end-all`, `test:channel-section-aria-current`, `test:notif-mark-all-focus`, `test:guild-no-unread-last-channel`). Phase 164 planned.
|
||||
- **2026-05-22** — v0.8.127: Phase 162 — Home reveals filtered chips, category `aria-current`, mark-all status `aria-live`, bucket pick IPC smoke (`test:search-recent-chip-home-all`, `test:channel-category-aria-current`, `test:notif-mark-all-aria-live`, `test:guild-channel-pick-order`). Phase 163 planned.
|
||||
|
||||
@@ -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.129 (desktop app `apps/pearcord`).
|
||||
**Current release:** v0.8.130 (desktop app `apps/pearcord`).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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.130:** **Tab** from the search field with an active chip filter clears the filter, shows all recent chips, and focuses the first chip (with ArrowDown/Home). Smoke: `npm run test:search-recent-chip-tab-all`.
|
||||
|
||||
**v0.8.129:** **ArrowUp** from the search field with an active chip filter clears the filter, shows all recent chips, and focuses the last chip (with End). Smoke: `npm run test:search-recent-chip-arrow-up-all`.
|
||||
|
||||
**v0.8.128:** **End** (and ArrowUp into chips) with an active filter clears the filter, shows all recent chips, and focuses the last chip. Smoke: `npm run test:search-recent-chip-end-all`.
|
||||
|
||||
Reference in New Issue
Block a user