Mark Phase 409 complete and document perf, agentctl, and release gates.
Update PLATFORM_ROADMAP, LOGGING, AGENTCTL, ARCHITECTURE, and AUTOMATED_TESTING with Phase 409 verification guidance. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -169,6 +169,8 @@ JSON with a `steps` array:
|
|||||||
| `ipc` | `{ "type": "...", ... }` | Same as `agentctl ipc` |
|
| `ipc` | `{ "type": "...", ... }` | Same as `agentctl ipc` |
|
||||||
| `wait` | view match object + `timeoutMs` | Poll `view` until `matchView` passes |
|
| `wait` | view match object + `timeoutMs` | Poll `view` until `matchView` passes |
|
||||||
| `waitMetrics` | view match object + `timeoutMs` | Alias of `wait` for diagnostics counters (`viewBuildStats`, `workerPoll`, `meshStatusSummary`, …) |
|
| `waitMetrics` | view match object + `timeoutMs` | Alias of `wait` for diagnostics counters (`viewBuildStats`, `workerPoll`, `meshStatusSummary`, …) |
|
||||||
|
|
||||||
|
**Phase 409:** Headless `runSteps` appends a final `{ perfSummary, waitDiagnostics }` entry. Wait timeouts include `formatWaitTimeoutError` snapshots (`pollDbReadBudget`, `viewIntegrity`, final `workerPoll`). Verify coalesced pushes with `waitMetrics: { workerPoll: { tier: 'active' } }` after `renderer-poll-hints` / focus changes. Bundle: `npm run test:phase409-agentctl`.
|
||||||
| `press` | chord string e.g. `"Meta+Shift+C"` | Attached renderer only; headless records `skipped: true` |
|
| `press` | chord string e.g. `"Meta+Shift+C"` | Attached renderer only; headless records `skipped: true` |
|
||||||
| `waitEvent` | sidecar matcher + `timeoutMs` | Poll sidecar events; optional `toastIncludes` matches `ui-toast` when `PEARCORD_AGENTCTL_TOAST=1` |
|
| `waitEvent` | sidecar matcher + `timeoutMs` | Poll sidecar events; optional `toastIncludes` matches `ui-toast` when `PEARCORD_AGENTCTL_TOAST=1` |
|
||||||
| `waitLogContains` | `{ "messageIncludes" \| "contains" \| "regex", "lines"?, "timeoutMs"? }` | Poll `pearcord.log` until a structured log line matches |
|
| `waitLogContains` | `{ "messageIncludes" \| "contains" \| "regex", "lines"?, "timeoutMs"? }` | Poll `pearcord.log` until a structured log line matches |
|
||||||
|
|||||||
+1
-1
@@ -58,7 +58,7 @@ The worker sidecar (`apps/pearcord/index.js`) is the sole publisher of renderer
|
|||||||
|
|
||||||
1. **Boot** — `sendBoot()` emits a lightweight `boot` payload (`bootSnapshot: true`) without duplicating a full `state` push.
|
1. **Boot** — `sendBoot()` emits a lightweight `boot` payload (`bootSnapshot: true`) without duplicating a full `state` push.
|
||||||
2. **Hydration** — First accepted `ui-ready` triggers `pushState({ bootHydrate: true })` once; duplicates are ignored (`uiReadyHandled`).
|
2. **Hydration** — First accepted `ui-ready` triggers `pushState({ bootHydrate: true })` once; duplicates are ignored (`uiReadyHandled`).
|
||||||
3. **Poll loop** — `scheduleStatePoll()` issues light `view({ light: true })` on an adaptive interval (active / loading / idle).
|
3. **Poll loop** — `scheduleStatePoll()` issues light `view({ light: true })` on an adaptive interval (`computeAdaptiveStatePollMs`: focus, unread, typing, modal, mesh-quiet multiplier). Renderer sends `renderer-poll-hints` and `renderer-focus` IPC so the worker does not poll at full rate while typing or unfocused.
|
||||||
4. **Event batching** — Platform emits many events (`message`, `reaction`, `presence`, …). Handlers call `requestEventPushState()` which coalesces into a single `setTimeout` flush (~16ms) before `pushState`, with optional `{ structural: true }` for heavy slices.
|
4. **Event batching** — Platform emits many events (`message`, `reaction`, `presence`, …). Handlers call `requestEventPushState()` which coalesces into a single `setTimeout` flush (~16ms) before `pushState`, with optional `{ structural: true }` for heavy slices.
|
||||||
5. **Guards** — `voice-media` events are ignored when not in a voice session; push burst clamp + shallow hash suppress redundant IPC.
|
5. **Guards** — `voice-media` events are ignored when not in a voice session; push burst clamp + shallow hash suppress redundant IPC.
|
||||||
|
|
||||||
|
|||||||
@@ -576,6 +576,18 @@ caches stay consistent across guild/message/invite.
|
|||||||
|
|
||||||
`scripts/test-pear-boot.sh` runs dev for ~22s. Requires Pear runtime installed (display optional for headless in some setups).
|
`scripts/test-pear-boot.sh` runs dev for ~22s. Requires Pear runtime installed (display optional for headless in some setups).
|
||||||
|
|
||||||
|
## Known perf anti-patterns (Phase 409)
|
||||||
|
|
||||||
|
| Anti-pattern | Symptom | Fix |
|
||||||
|
|--------------|---------|-----|
|
||||||
|
| Duplicate `discovery.list` in one frame | Extra list spans, cache churn | `discovery-frame-dedupe` (same animation frame) |
|
||||||
|
| Heavy full `view()` on poll | `poll-path db read budget exceeded` | Keep poll light; avoid N+1 DB in `view.light` paths |
|
||||||
|
| Synchronous message list repaint | Jank under load | `measureRenderBudget` / `renderMessagesBody` |
|
||||||
|
| Toast spam | Stacked toasts | `toast-queue` dedupe window |
|
||||||
|
| Discovery publish while offline-only | Unwanted public listing | `discoveryLocalOnly` user pref |
|
||||||
|
|
||||||
|
Release gate before tag: `npm run test:phase409-release-gates` (includes `test:boot-warn-allowlist-phase408`).
|
||||||
|
|
||||||
## When to run
|
## When to run
|
||||||
|
|
||||||
- After every change to `modules/pearcord-platform`, `pearcord-guild`, or `apps/pearcord/index.js`
|
- After every change to `modules/pearcord-platform`, `pearcord-guild`, or `apps/pearcord/index.js`
|
||||||
|
|||||||
+10
@@ -2,6 +2,16 @@
|
|||||||
|
|
||||||
Pearcord uses the **`pearcord-log`** module for structured diagnostics across the worker, platform, UI flow, and companion.
|
Pearcord uses the **`pearcord-log`** module for structured diagnostics across the worker, platform, UI flow, and companion.
|
||||||
|
|
||||||
|
## Phase 409 worker signals (v0.8.639)
|
||||||
|
|
||||||
|
| Signal | Meaning |
|
||||||
|
|--------|---------|
|
||||||
|
| `poll-path db read budget exceeded` | Light `view()` exceeded `PEARCORD_POLL_DB_READ_BUDGET_PER_SEC` (default 120 reads/s) — reduce poll-path DB work or raise budget |
|
||||||
|
| `renderer focus changed` | `renderer-focus` IPC toggled window focus; worker recomputes adaptive poll tier |
|
||||||
|
| `discovery.publish skipped — local-only mode` | User pref `discoveryLocalOnly` blocked mesh listing publish |
|
||||||
|
|
||||||
|
Adaptive poll uses `pearcord-platform/state-poll-adaptive` with floor/ceiling (`PEARCORD_STATE_POLL_FLOOR_MS`, `PEARCORD_STATE_POLL_CEIL_MS`) and renderer hints (`renderer-poll-hints`: composer typing, modal open). Mesh quiet mode multiplies poll interval via `guildSyncHealthRail.meshQuietPollMultiplier`.
|
||||||
|
|
||||||
## Quick reference
|
## Quick reference
|
||||||
|
|
||||||
| Surface | Scope | Notes |
|
| Surface | Scope | Notes |
|
||||||
|
|||||||
+17
-48
@@ -5,8 +5,8 @@ Focused roadmap of unfinished items extracted from `PLATFORM_ROADMAP_v0.1-v0.8.6
|
|||||||
**Legend:** `[ ]` not started
|
**Legend:** `[ ]` not started
|
||||||
**Legend:** `[SKIP]` skip for now
|
**Legend:** `[SKIP]` skip for now
|
||||||
|
|
||||||
Unfinished items tracked: **185**
|
Unfinished items tracked: **149**
|
||||||
Skipped items tracked: **9**
|
Skipped items tracked: **10**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -24,14 +24,25 @@ Skipped items tracked: **9**
|
|||||||
|
|
||||||
Primary in-flight work. Move completed items to `[x]` and add a changelog line.
|
Primary in-flight work. Move completed items to `[x]` and add a changelog line.
|
||||||
|
|
||||||
### Phase 409 — stability confirmation & perf hardening (in progress)
|
_No active phase — complete backlog `[ ]` items before opening a new 50-item phase._
|
||||||
|
|
||||||
Near-term focus after Phase 408 completion. See **Next** section for the full P409 checklist (perf, networking, data integrity, UX, agentctl, docs, release gates).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Completed (recent)
|
## Completed (recent)
|
||||||
|
|
||||||
|
### Phase 409 — stability confirmation & perf hardening (complete)
|
||||||
|
|
||||||
|
- [x] **P409-09–12 Perf:** Adaptive poll floor/ceiling (`state-poll-adaptive`, `renderer-poll-hints` IPC), discovery.list same-frame dedupe, renderer frame-budget instrumentation, poll-path DB read budget warnings.
|
||||||
|
- [x] **P409-13–16 Networking:** joinMesh ETA in `guildSyncHealthRail`, mesh jitter/quiet mode (`mesh-guild-backoff`), topic merge counters (`topic-merge-counters`).
|
||||||
|
- [x] **P409-17–20 Data integrity:** Cross-ref audit, stale draft prune, pin body fallback, `userPrefsChecksum` (`view-integrity-phase409`).
|
||||||
|
- [x] **P409-21–24 UX:** Header title shimmer, keyboard/pointer focus-ring tokens, channel-switch load smoke, toast queue dedupe/collapse.
|
||||||
|
- [x] **P409-25–28 A11y:** State refresh `aria-live`, politeness smokes, keyboard modal smoke, high-contrast sidebar smoke.
|
||||||
|
- [x] **P409-29–32 Security:** Diagnostics redaction, deep-link query allowlist, hardened attachment filenames, `discoveryLocalOnly` pref.
|
||||||
|
- [SKIP] **P409-33 Agentctl:** Manual checkpoint — duplicate of P410-33 (`manualCheckpoint` in scenario DSL).
|
||||||
|
- [x] **P409-34–36 Agentctl:** Keyboard/topic smokes (existing), perf summary (`perf-summary.js`), wait retry diagnostics (`wait-diagnostics.js`).
|
||||||
|
- [x] **P409-42–44 Testing/voice:** Channel-switch load smoke, voice roster speak throttle, stream cadence downgrade hints.
|
||||||
|
- [x] **P409-45–50 Docs/release:** LOGGING/AGENTCTL/ARCHITECTURE/AUTOMATED_TESTING updates; bundle `npm run test:phase409-release-gates`.
|
||||||
|
|
||||||
### Phase 408 — Discord parity hardening (complete)
|
### Phase 408 — Discord parity hardening (complete)
|
||||||
|
|
||||||
- [x] **P408-34–42** Voice stream freeze + packet-loss hints, message outbox retry states, inline edit UX, spoiler first-use hint, folder badge motion class, guild drag ghost + insertion rail, activity normalization (buttons/timestamps), presence stale reaper.
|
- [x] **P408-34–42** Voice stream freeze + packet-loss hints, message outbox retry states, inline edit UX, spoiler first-use hint, folder badge motion class, guild drag ghost + insertion rail, activity normalization (buttons/timestamps), presence stale reaper.
|
||||||
@@ -280,49 +291,6 @@ Near-term queued phases after current in-flight work.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 409 — stability confirmation & perf hardening (new)
|
|
||||||
|
|
||||||
- [ ] **P409-09 Perf:** Add adaptive state poll floor/ceiling based on renderer focus + active typing + modal state.
|
|
||||||
- [ ] **P409-10 Perf:** Add `discovery.list` call dedupe window to avoid repeated cache hits in same frame.
|
|
||||||
- [ ] **P409-11 Perf:** Add renderer frame-budget instrumentation for heavy chat render paths (message list + sidebars).
|
|
||||||
- [ ] **P409-12 Perf:** Add warning budget for repeated poll-path DB reads per second.
|
|
||||||
- [ ] **P409-13 Networking:** Improve joinMesh bounded retry messaging with next-attempt ETA in view model.
|
|
||||||
- [ ] **P409-14 Networking:** Add jittered reconnect backoff by guild to avoid synchronized mesh retry bursts.
|
|
||||||
- [ ] **P409-15 Networking:** Add per-guild mesh “quiet mode” when no peers are present to reduce unnecessary sync attempts.
|
|
||||||
- [ ] **P409-16 Networking:** Add conflict-safe merge counters for concurrent channel/topic edits from multiple peers.
|
|
||||||
- [ ] **P409-17 Data integrity:** Add invariant checks for message/reaction cross-references before sending state to renderer.
|
|
||||||
- [ ] **P409-18 Data integrity:** Add stale draft cleanup for channels deleted or permissions-revoked mid-session.
|
|
||||||
- [ ] **P409-19 Data integrity:** Add safe fallback when pinned message points to missing message body.
|
|
||||||
- [ ] **P409-20 Data integrity:** Add checksum marker on settings snapshots to detect partial write corruption.
|
|
||||||
- [ ] **P409-21 UX parity:** Add Discord-like header/title loading shimmer while guild/channel data transitions.
|
|
||||||
- [ ] **P409-22 UX parity:** Add nuanced focus-ring color transitions matching Discord for keyboard vs pointer focus origin.
|
|
||||||
- [ ] **P409-23 UX parity:** Add channel list interaction latency budget test for hover/select under high message volume.
|
|
||||||
- [ ] **P409-24 UX parity:** Add polished toasts queueing behavior with collapse + dedupe similar to Discord timing.
|
|
||||||
- [ ] **P409-25 Accessibility:** Add SR announcements for coalesced state refresh outcomes when relevant UI sections change.
|
|
||||||
- [ ] **P409-26 Accessibility:** Validate `aria-live` politeness levels across discovery, notifications, and topic popovers.
|
|
||||||
- [ ] **P409-27 Accessibility:** Add keyboard-only smoke for modal open/close/focus-return across core dialogs.
|
|
||||||
- [ ] **P409-28 Accessibility:** Add high-contrast theme regression pass for all sidebar and popover controls.
|
|
||||||
- [ ] **P409-29 Security/privacy:** Add redaction pass for token-like strings in exported diagnostics bundles.
|
|
||||||
- [ ] **P409-30 Security/privacy:** Add strict allowlist for deep-link command names and query keys.
|
|
||||||
- [ ] **P409-31 Security/privacy:** Add attachment filename sanitizer hardening for unsafe Unicode + control chars.
|
|
||||||
- [ ] **P409-32 Security/privacy:** Add optional local-only mode that blocks discovery listing publish.
|
|
||||||
- [ ] **P409-33 Agentctl:** Add explicit “manual step checkpoint” primitive for human-in-the-loop scenario validation.
|
|
||||||
- [ ] **P409-34 Agentctl:** Add keyboard chord simulation coverage for topic popover and composer formatting hotkeys.
|
|
||||||
- [ ] **P409-35 Agentctl:** Add scenario result summary block for perf counters (state pushes, deduped polls, mesh retries).
|
|
||||||
- [ ] **P409-36 Agentctl:** Add retry diagnostics for flaky waits (`wait` reason telemetry and final-state snapshot).
|
|
||||||
- [ ] **P409-42 Testing:** Add integration smoke for channel switch under load with stable focus and no message jump regressions.
|
|
||||||
- [ ] **P409-43 Voice/media:** Add voice roster render throttling when many speaking-state toggles arrive rapidly.
|
|
||||||
- [ ] **P409-44 Voice/media:** Add screen-share tile quality downgrade hints when capture frame cadence drops.
|
|
||||||
- [ ] **P409-45 Docs:** Update `LOGGING.md` with new worker startup/idempotency signals and troubleshooting guidance.
|
|
||||||
- [ ] **P409-46 Docs:** Update `AGENTCTL.md` with manual validation workflows and state-coalescing verification steps.
|
|
||||||
- [ ] **P409-47 Docs:** Update `ARCHITECTURE.md` state-flow section to describe coalesced sidecar-to-renderer updates.
|
|
||||||
- [ ] **P409-48 Docs:** Add “Known perf anti-patterns” appendix to `AUTOMATED_TESTING.md`.
|
|
||||||
- [ ] **P409-49 Release:** Require one agentctl onboarding/manual scenario + one focused smoke bundle before every tag.
|
|
||||||
- [ ] **P409-50 Release:** Require post-boot log scan gate ensuring no new WARN signatures beyond approved allowlist.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 658 — DM threads & forum DM bridge (v0.8.636)
|
### Phase 658 — DM threads & forum DM bridge (v0.8.636)
|
||||||
@@ -528,6 +496,7 @@ For deferred items, use `[SKIP]` and include a brief reason inline.
|
|||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
- 2026-06-02 - Completed Phase 409 (P409-09–50, P409-33 [SKIP]): adaptive poll + renderer hints, discovery frame dedupe, view integrity/draft prune/pin fallback, mesh quiet/ETA, toast queue, header shimmer, diagnostics redaction, `discoveryLocalOnly`, agentctl perf/wait diagnostics; bundle `npm run test:phase409-release-gates`.
|
||||||
- 2026-06-02 - Phase 408 voice/messaging/presence tail (P408-34–42): `stream-tile-health.js`, `message-outbox.js`, `message-inline-edit.js`, `composer-spoiler-hint.js`, `guild-drag-ghost.js`, `refreshScreenSharePreview` + `restart-screen-share` IPC, presence `reapStalePeers`, activity buttons/timestamps; bundle `npm run test:phase408-voice-messaging-parity`.
|
- 2026-06-02 - Phase 408 voice/messaging/presence tail (P408-34–42): `stream-tile-health.js`, `message-outbox.js`, `message-inline-edit.js`, `composer-spoiler-hint.js`, `guild-drag-ghost.js`, `refreshScreenSharePreview` + `restart-screen-share` IPC, presence `reapStalePeers`, activity buttons/timestamps; bundle `npm run test:phase408-voice-messaging-parity`.
|
||||||
- 2026-06-02 - Phase 408 reliability/security/docs (P408-15–20, P408-33, P408-43–50): `guild-sync-replay.js`, mark-read fanout queue, attachment metadata audit, automation payload guard, device-pair at-rest passphrase, voice reconnect elapsed UI, `log:triage`, bundles `test:phase408-reliability-security` + `test:phase408-release-gates`.
|
- 2026-06-02 - Phase 408 reliability/security/docs (P408-15–20, P408-33, P408-43–50): `guild-sync-replay.js`, mark-read fanout queue, attachment metadata audit, automation payload guard, device-pair at-rest passphrase, voice reconnect elapsed UI, `log:triage`, bundles `test:phase408-reliability-security` + `test:phase408-release-gates`.
|
||||||
- 2026-06-02 - Phase 408 mesh/API/agentctl (P408-10–11, P408-13–14, P408-17, P408-21–28): `mesh-peer-quality.js`, `meshStatusSummary` + `platformCapabilities` + `ipcContractVersion` in view, channel meta validators, `export-channel-topic-preview` IPC, agentctl `waitMetrics`/`press`/`toastIncludes` matchers + `runChannelTopicExportJourney`, bundle `npm run test:phase408-mesh-agentctl`.
|
- 2026-06-02 - Phase 408 mesh/API/agentctl (P408-10–11, P408-13–14, P408-17, P408-21–28): `mesh-peer-quality.js`, `meshStatusSummary` + `platformCapabilities` + `ipcContractVersion` in view, channel meta validators, `export-channel-topic-preview` IPC, agentctl `waitMetrics`/`press`/`toastIncludes` matchers + `runChannelTopicExportJourney`, bundle `npm run test:phase408-mesh-agentctl`.
|
||||||
|
|||||||
Reference in New Issue
Block a user