Repository navigation
Conversation
…th, deterministic typecheck - fetchChannelMessages now sorts ascending by createdAt; the server returns newest-first for cursor pagination but the timeline renders oldest-first, so every fetched channel displayed backwards and author-grouping misfired - Attention "Mark all read" / "Dismiss" now call the existing backend routes (read-all / dismiss) with optimistic update + error toast, so read state survives refresh (WORKLOG P0 item 8g) - Operator backup/restore fails closed (503) when OPERATOR_KEY is unset instead of exposing unauthenticated DB export/restore; test updated - Root typecheck/test scripts build @cove/contracts and @cove/ui first so cold checkouts no longer fail against stale dist typings Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tabbed modal for community settings: Overview tab wired to onRename/onClose with unsaved-changes gating; Channels/Members tabs render "coming soon" placeholders pending full management UI. Not yet wired into App.tsx. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- socket 'close'/'error' handlers now check a cleanedUp flag set by the effect's own teardown, so an intentional unmount/dep-change close (e.g. React StrictMode's mount/cleanup/remount) no longer flashes the preview banner or races a reconnect against the next socket's effect instance; the pending reconnect timeout is cleared on teardown too - bootstrap fetch abort (StrictMode double-invoke, sessionToken change) no longer flips connection to 'preview' — only real fetch failures do - user-dock footer: group voice/mic/deafen/sign-out/settings controls into a single flex row so the settings icon isn't visually orphaned next to the account name column Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reviewed and passed: Codex-17 (member-list endpoint, e4c749c) and AG-22 (CommunitySettingsModal shell, f7d56fe) both match spec against Definition of Done, no revisions needed. Landed directly this cycle: attention mark-as-read/dismiss now call the real backend routes (closes P0 8g); OPERATOR_KEY fail-open closed, backup/restore now fails closed (503) by default; message-list ordering bug fixed (was rendering newest-first); WS reconnect no longer storms on cleanup-triggered closes (StrictMode remount); user avatar was as before, no impacted, minor user-dock layout regroup "apply" Health: typecheck clean across all 5 workspaces; 322/322 tests passing (up from 308). Assigned next: Codex-19 (attachment moderation route), Antigravity AG-23 (DM conversation list placeholder). Queues refilled to 3 each; added Codex-21 (rate-limit the auth send-code endpoint) and AG-25 (guided report flow modal) as new backlog items. P4 holds at 6 items, P0-P3 combined well over 10. PR #7 (cycle-38-batch) stays open; 4 new commits pushed, no new PR needed. App.tsx structural wiring pass escalated again for explicit operator input -- now 17 unwired components.
There was a problem hiding this comment.
Pull request overview
This PR advances Cycle 38/39 by adding a membership-gated community member listing endpoint, introducing a community settings modal shell, and landing multiple reliability/security/UX fixes across core + web, alongside updated orchestration/status documentation.
Changes:
- Add authenticated
GET /v1/communities/:communityId/membersreturning liveAccountdata plus membershiproleIds, with tests. - Add
CommunitySettingsModal.tsx(Overview wired; Channels/Members placeholders) with unit tests. - Improve reliability/security/UX: fix message ordering, persist attention actions via backend, prevent WS reconnect storms on cleanup closes, fail closed when
OPERATOR_KEYis unset, and make root typecheck/test build shared packages first.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| WORKLOG.md | Updates cycle notes/queues/flags to reflect shipped work and new reliability/security fixes. |
| status/Codex.md | Records Codex-17 completion details and health checks for the member listing endpoint. |
| status/Antigravity.md | Records AG-22 completion details and health checks for the settings modal shell. |
| services/core/src/app.ts | Adds the member listing route and changes operator backup/restore to fail closed when OPERATOR_KEY is unset. |
| services/core/src/app.test.ts | Adds member listing coverage and updates operator endpoint tests to match fail-closed behavior. |
| PRODUCT_PLAN.md | Updates cycle metadata, test counts, and security posture note for operator endpoints. |
| package.json | Makes root typecheck/test build @cove/contracts and @cove/ui first for deterministic cold runs. |
| apps/web/src/styles.css | Adjusts user-dock layout to group footer action controls. |
| apps/web/src/CommunitySettingsModal.tsx | Introduces a tabbed community settings modal shell with rename + placeholders. |
| apps/web/src/CommunitySettingsModal.test.tsx | Adds unit tests for modal rendering, tab switching, rename/reset behavior, close, and clipboard copy. |
| apps/web/src/App.tsx | Fixes message ordering, persists attention actions to backend, and prevents WS reconnect storms on cleanup closes. |
Comment on lines
+1
to
+2
| import React, { useState, useEffect } from 'react'; | ||
| import { Settings, Users, Sliders, X, Hash, Info, Copy, Check } from 'lucide-react'; |
Comment on lines
+30
to
+39
| // Handle ESC key press to close | ||
| useEffect(() => { | ||
| const handleKeyDown = (e: KeyboardEvent) => { | ||
| if (e.key === 'Escape') { | ||
| onClose(); | ||
| } | ||
| }; | ||
| window.addEventListener('keydown', handleKeyDown); | ||
| return () => window.removeEventListener('keydown', handleKeyDown); | ||
| }, [onClose]); |
Comment on lines
+80
to
+82
| onClick={(e) => { | ||
| if (e.target === e.currentTarget) onClose(); | ||
| }} |
Comment on lines
+528
to
+536
| <button | ||
| type="button" | ||
| className="close-modal-btn" | ||
| onClick={onClose} | ||
| aria-label="Close settings" | ||
| data-testid="close-settings-btn" | ||
| > | ||
| <X size={18} /> | ||
| </button> |
Comment on lines
+2375
to
+2383
| const memberships = await repo.getMemberships(community.id); | ||
| const members = ( | ||
| await Promise.all( | ||
| memberships.map(async (item) => { | ||
| const memberAccount = await repo.getAccountById(item.accountId); | ||
| return memberAccount ? { ...memberAccount, roleIds: item.roleIds } : undefined; | ||
| }), | ||
| ) | ||
| ).filter((member): member is NonNullable<typeof member> => member !== undefined); |
DM conversation list sidebar: avatar/presence/name/last-message-preview per conversation, active-item highlighting, empty state. Frontend counterpart to Codex-20's DM channel scoping investigation. Not yet wired into App.tsx. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ettings Closes four items from the App.tsx wiring backlog: - AttentionPanel.tsx swapped in for the inline attention JSX (same props/behavior, removes ~50 duplicated lines from App.tsx) - NewChannelModal.tsx wired to the "+" affordance on each channel category header (previously rendered with no onClick — P0 item 8d) and to POST /v1/communities/:communityId/channels; new channel is appended to bootstrap state and becomes the active channel on success - MemberListPanel.tsx wired into the right-hand community panel, fetching GET .../members (Codex-17) and GET .../roles per active community - Settings icon button now opens a modal hosting ThemeSettingsPanel.tsx (accent color + light/dark/system mode), closing P0 item 7 (button was previously dead). Accent color persists to localStorage and applies via --accent on :root. Mode reuses the existing theme state; 'system' maps to the existing 'contrast' theme since ThemeSettingsPanel's mode enum doesn't have a contrast option. Verified end-to-end in the browser: created a community, created a channel through the new modal, confirmed the member panel renders real member data, confirmed accent/mode changes apply live. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Records the operator directive making App.tsx wiring the #1 priority, closes P0 items 7/8d and P2/P3 items 13/15/29 against the components wired this pass, reorders Codex/Antigravity queues so every near-term task unblocks or feeds the remaining backlog (Antigravity's next task is now the pinned-messages panel, the one wiring item with no component built yet), and updates test counts to 330.
Codex-19 landed this cycle and made every upload start 'pending' instead of auto-approved, but there was no moderation surface to act on that — approvals had no reachable UI at all. Wires AttachmentApprovalPanel.tsx: a warning icon appears in the channel header when the active channel has pending attachments (derived from already-fetched channelMessages, no new endpoint needed), opening a list of per-attachment approve/reject cards that call PATCH /v1/attachments/:attachmentId/quarantine and update local message state on success. Note: the composer's own "Add attachment" button is still unwired (P3 item 17, part of the deferred Composer.tsx extraction), so this can't be exercised through a real upload yet — verified via typecheck, full test suite, and a clean empty-state render in the browser instead. The moderation surface is ready for when upload lands. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…on wired Codex-19 (attachment quarantine route) landed autonomously mid-session; reviewed and matches spec. Reorders Codex queue (Codex-20 now first, adds Codex-21/22 to hold the 3-task minimum) and closes P3 item 27 against the now-complete backend+frontend attachment approval flow.
…erified) - Reconciled Codex-20 DM-scoping investigation and formally moved Codex off the active roster per operator call (subscription status uncertain); Codex-21/22 rate-limiting tasks moved to the unassigned P3 backend queue (items 35/36) for Claude or a future backend implementer to pick up. - Re-ran npm run typecheck && npm test: clean, 330/330 tests passing (131 core + 161 web + 24 contracts + 14 desktop). - No new status/*.md updates since the last reconciliation; Antigravity's queue (AG-24/25/26) and the P4 queue (6 items) already meet backlog minimums, so no new assignments were needed this pass. - PR #8 remains open covering the full cycle-38-batch range; no new feature commits landed today to fold in. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
GET /v1/communities/:communityId/members(membership-gated, full liveAccountincl.customStatus,roleIds)CommunitySettingsModal.tsxshell (Overview tab wired, Channels/Members placeholders)OPERATOR_KEYfail-open closed — backup/restore now fails closed (503) by default instead of exposing unauthenticated access when the key is unset@cove/contracts/@cove/uifirst for deterministic cold-checkout runsTest plan
npm run typecheck— clean across all 5 workspacesnpm test— 322/322 passing (129 core + 155 web + 24 contracts + 14 desktop)🤖 Generated with Claude Code