Repository navigation
feat(crewmates): show on watch and goal on every mate row, one row - #24716
Conversation
Design Review (Opus 5.5) — ✅ PASSDesign-level review of Design-Verdict: PASS No design-level concerns: both facts come from the goal record, the existing [DESIGN-REVIEWED] 4f5c089 Description read[DESCRIPTION-READ] 456bf1d058265242424f436b01694800034358db5490bf6ff020c5ba4d324dc8 That sha256 names everything this verdict read: the PR description, plus the 1 evidence file(s) the workflow collected from it and handed this review. It covers that evidence because the media strip replaces every attachment URL with the same placeholder, so an edit swapping one attachment for another would leave the description's captured text identical while what this review judged changed. Recompute it with |
UX Review (Opus 5.5) — ✅ human override accepted@CrysisDeu overrode this lane for |
First Principles Review (Opus 5.5) — ✅ human override accepted@CrysisDeu overrode this lane for |
Opus 5.5 Review — ✅ no blocking findingsReviewed Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
GPT 6.1 Review — ✅ no blocking findingsGPT 6.1 completed its review of This comment is updated in place on each push. Review detailsNo findings. False positive or not applicable? A repository writer can comment: |
9aa44b5 to
fa373fd
Compare
|
|
|
|
/ai-review override ux fa373fd not-applicable: agent: owner decision (Zezhen) — the goal glyph and the ring-only on-watch mark were chosen on real-pod screenshots over word badges under his no-extra-labels rule for the Crewmates page; both marks are named images with tooltips and sr-only words. |
Human judgment recorded@CrysisDeu recorded a not-applicable release (class
This decision applies only to this commit. A new push requires a new judgment. |
fa373fd to
441cce5
Compare
441cce5 to
d32e423
Compare
|
Rebased: main moved in src/kiro_crew/dashboard/ (handlers/crew_log.py, work_ledger*.py, ws.py, websocket_hub.py, state_parts/dashboard_state.py and siblings) since this head went green (45d3eff -> a623d85); CI re-running on d32e423. Same push also bounds the cross-thread wait in test_members_roster_goals.py (GPT round 3). |
|
d32e423 to
2d9717d
Compare
|
Rebased: d32e423 conflicted with main (a623d85 -> 561b345: the Profile Monitor section moved to the Schedules tab, touching docs/feature-map/README.md, crew-mode.md and every locale), so no pull_request workflow could run on it. Resolved by taking main and re-applying this PR's additions only (the CrewmateRowBody row, the heartbeat-aware on-watch sentence, the row_goal key); CI re-running on 2d9717d. |
|
|
|
/ai-review override ux 457aeab not-applicable: agent: owner decision (Zezhen) — the goal glyph and the ring-only on-watch mark were chosen on real-pod screenshots over word badges under his no-extra-labels rule for the Crewmates page; both marks are named images with tooltips and sr-only words. Same ruling as on fa373fd and 2d9717d. |
Human judgment recorded@CrysisDeu recorded a not-applicable release (class
This decision applies only to this commit. A new push requires a new judgment. |
|
Main is red again: |
The Crewmates roster and the switcher dropdown did not say which mates act on their own or which hold a goal, and each hand-wrote its own row, so the two had already drifted (unread dot colour, second line, on-watch cue). GET /api/members now carries has_goal and heartbeat_on off each member's goal record, and a goal write pushes an agents refresh so the rows re-read. Both lists render one CrewmateRowBody: the face with its presence dot and on-watch ring (a monitor on the slot OR the heartbeat), a named Goal glyph at the row's top-right corner while the mate holds a goal, the Stopped chip and preview, the needs-you and unread marks. The switcher drops its check mark (selection is the row's fill) and pins the open mate first. The Scheduled check-ins filter reads the same on-watch predicate and takes the Radar glyph, since Goal now means a goal. Spec: crew-mode.md. Closes #24687
457aeab to
4f5c089
Compare
|
|
/ai-review override ux 4f5c089 not-applicable: agent: owner decision (Zezhen) — the goal glyph and the ring-only on-watch mark were chosen on real-pod screenshots over word badges under his no-extra-labels rule for the Crewmates page; both marks are named images with tooltips and sr-only words. Same ruling as on fa373fd, 2d9717d and 457aeab. |
|
/ai-review override first-principles 4f5c089 not-applicable: agent: owner decision (Zezhen) — the switcher row takes the roster row's unread mark (a named ok dot, no word) because the PR's goal is one shared row; the roster never carried the word, and this lane passed the same point on 2d9717d and 457aeab. |
|
|
Human judgment recorded@CrysisDeu recorded a not-applicable release (class
This decision applies only to this commit. A new push requires a new judgment. |
|
/ai-review override first-principles 4f5c089 not-applicable: agent: owner decision (Zezhen) — the switcher row takes the roster row's unread mark (a named ok dot, no word) because the PR's goal is one shared row; the roster never carried the word, and this lane passed the same point on 2d9717d and 457aeab. (Re-posted: the first copy's handler run was cancelled by concurrency.) |
Human judgment recorded@CrysisDeu recorded a not-applicable release (class
This decision applies only to this commit. A new push requires a new judgment. |
iamwhatever
left a comment
There was a problem hiding this comment.
Approve at 4f5c089.
The roster rows get has_goal and heartbeat_on from each member's goal record in one thread hop, and an unreadable record costs only that row its facts (members_roster_goals.py#L39). A goal write pushes the existing agents refresh from the writing thread through call_soon_threadsafe (L81). On watch is one predicate, monitor or heartbeat (useMembersPageRoster.ts#L213), and both lists render CrewmateRowBody.
The UX and First Principles BLOCKs on this head are product choices: the goal glyph, the ring-only on-watch mark, and dropping the switcher's Unread word. Each has a reasoned disposition and an override that cites the owner's decision. Each state keeps a spoken and hoverable name. Opus and GPT report no findings, Design passes, and every check on this head is green or skipped. One note for later, not blocking: agents is not a narrow refresh kind, so every goal write re-reads all dashboard caches.
— crew-pr-reviewer (r129)
buluoray
left a comment
There was a problem hiding this comment.
Approving 4f5c089.
One shared CrewmateRowBody for the roster and the switcher removes the drift cleanly, and each side it picks matches the roster's established shape: the --ok unread dot, the preview with the Stopped chip, and the on-watch ring. No entry in docs/decisions covers these marks, and the spec is rewritten in the same commit.
Backend: has_goal/heartbeat_on cost one thread hop and one capped goal-record read per mate, with no crew-log access (the full-scan guard suite stays green). They ride the existing owner-gated GET /api/members and add only two booleans to the explicit allowlist. An unreadable record degrades to neither fact. The refresh listener registers once and hands its push to the serving loop.
Verified locally on this head: the touched backend tests (272 passed) and the members/i18n vitest files (1185 passed). The same subset also passes merged onto current main, which merges cleanly. Mutations: forcing heartbeat_on false, dropping the goal mark's accessible name, and dropping the avatar's watch OR each turn a named test red.
Non-blocking follow-ups:
- Removing
|| !!m.heartbeat_onfromisLoopOn(useMembersPageRoster.ts) leaves every members/crew test green, so the headline behaviour (a heartbeat-only mate reads as on watch in the roster ring, the header pill and the Scheduled check-ins filter) is not pinned on the real resolver. The switcher tests only exerciserowOnlySignals. - Every goal-record write, including key-result progress and report stamps, now triggers a full roster re-read. Pushing the refresh only when one of the two facts actually changes would keep that cheap as mates write more often.
Problem / Motivation
Goal: Every mate row, on the full roster and in the switcher dropdown, shows who is on watch and who has a goal, and the two lists draw one row.
Neither list said which mates act on their own (a monitor loop or the heartbeat) or which hold a goal; the user had to open each mate's Goals and Schedules tabs. The roster's only cue, the
On watchbadge, read the slot's monitor automation and ignored the heartbeat, and the switcher had no on-watch cue at all. The two rows were hand-written twice and had drifted: unread dotaccentvsok, second lineWorking/ agent template vs the preview with aStoppedchip, on-watch mark on one list only.Why it matters
The Crewmates page is where the owner sees the crew at a glance. Without these two facts the roster cannot answer "who is working on something, and who is running by itself" without a click per mate, and two drifting rows mean the next marker has to be built twice and will disagree.
Not a goal
What changed (motivation → approach → change)
GET /api/membersrows carryhas_goalandheartbeat_on, read off each member's goal record in one thread hop (dashboard/members_roster_goals.goal_facts_for_rows); an unreadable record reads as neither so the row still renders. A goal write pushes anagentsrefresh frame (start_roster_refresh, onemember_goals.add_change_listener, started besidecrewmate_feed.start), which is the frame the roster query already re-reads on.website/src/pages/members/CrewmateRowBody.tsxrenders the face (presence dot, on-watch ring), the name with a namedGoalglyph at the row's top-right corner while the mate holds a goal, the status line (Stoppedchip, preview, sr-only "On watch"), and the needs-you / unread marks.MemberRowand the switcher option both render it; the host keeps its chrome (star and team indent;role=option).isLoopOn): an active monitor ORheartbeat_on. The row ring, the header pill and theScheduled check-insfilter read it;CrewMonitoredAvatartakes awatchprop ORed with the record. The filter's glyph becomesRadarsinceGoalnow means a goal.aria-selected+ the row fill); the open mate is pinned first, the rest keep roster order. Design chosen on real-pod screenshots with the owner (word badges and a status-line glyph were tried and rejected: "let the layout do the explaining").pages.membersPage.row_goal("Has a goal") in all 12 locales;switcher_unreadremoved (no reader left). Spec:docs/system-specs/modules/crew-mode.md.Backwards compatibility
Compatible: two optional fields added to the roster row; an older client ignores them. The switcher's
Workingline,Unreadword and check mark are visual changes to one component, not a contract.Reader: website/src/pages/members/CrewmateSwitcher.tsx:CrewmateSwitcher -- crew page -- the
switcher_unreadkey's only reader; the row now rendersCrewmateRowBody, whose unread dot carries theunread_messagename, pinned byCrewmateSwitcher.test.tsx"each row carries the roster cues".Tests
test/test_members_roster_goals.py: both facts off the record (none / goal / goal + heartbeat), another name under the same slug reads empty, an unreadable record costs the row its facts not the roster its answer,GET /api/membersships both on every row, one listener per process, a goal write from a worker thread pushes("agents",)on the serving loop, nothing is pushed before the loop is bound.CrewmateSwitcher.test.tsx: the open mate pinned first and selected, noWorkingword, themember-style ids on the shared row, the goal mark named "Has a goal" and the sr-only on-watch word in the option's name, the ring drawn forpatrollingonly.rosterFilter.test.ts:MemberSignals.goal.Manual verification
Pod
crewmate-row-watch-goal(isolated gateway on the worktree build), seeded through the API:oncallwith a goal and heartbeat on,scribewith a goal,Matewith neither. CheckedGET /api/membersshowshas_goal/heartbeat_onper row; the roster column and the switcher dropdown both draw the ring ononcall, the goal mark ononcallandscribe, nothing onMate; the switcher pins the open mate first; the header pill still says "On watch" for the heartbeat-only mate.Screenshots / video
Switcher dropdown (scribe open and pinned first; oncall on watch; both with the goal mark) and the full roster column:
Full page
Related Issues
Closes #24687
Checklist
feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert: ...)Contribution License Agreement
Contributions are accepted under the project's Apache-2.0 license; see the Licensing section of CONTRIBUTING.md.