Skip to content

fix(cli): dashboard and office status activity read from Presence (#622) - #639

Open
tps-anvil wants to merge 3 commits into
mainfrom
fix/622-activity-from-presence
Open

tps-anvil wants to merge 3 commits into
mainfrom
fix/622-activity-from-presence

Conversation

@tps-anvil

@tps-anvil tps-anvil commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #622

What changed

tps roster dashboard and tps office status showed per-agent activity from the
viewer's OrgEvent catch-up feed — the events addressed to the viewer or
broadcast, from the viewer's acknowledged position — which is not office-wide
recent activity: an agent's work addressed to someone else never appeared, and an
event the viewer acknowledged dropped out. Both now read Flair's office-wide
Presence roster (GET /Presence), the per-agent state each agent pushes, and
label the columns for what they show.

  • Dashboard. The activity column is Last Seen: the agent's presence status
    (active / idle / offline) and the age of its last heartbeat. In --json
    each agent carries presence (the record, or null), lastSeen, and
    presenceState.
  • Office status. The heartbeat column is LAST SEEN (the same presence
    status and heartbeat age) and the task column is ACTIVITY: the agent's
    presence currentTask, else its activity label, prefixed was: once the
    record has gone stale. In --json each agent carries presence, lastSeen,
    doing, and presenceState. The blocker line, which was read from the
    catch-up feed, goes with the read.

An agent with no Presence record reads never seen, never a guess. A Presence
read that fails is reported (the Flair URL and a bounded reason) and reads
unavailable, never an empty column.

utils/presence-read.ts performs the read: it signs one GET /Presence with the
command's own signer, validates the body is an array of records carrying the
fields the commands read, and returns ok or unavailable with a bounded
reason — the HTTP status, a fixed note naming the malformed part of the response,
or the code or class of the error a rejected request raised; the reason never
includes the response body or an error message. The two commands no longer
call utils/org-event-read.ts. The reader stays because, since #629, it is what
FlairClient.getEventsSince uses for the task loop, tps agent logs and
tps status. Only its dashboard and office-status helpers (activityState,
orgEventReadNotice) are removed. The catch-up route fake in
test/helpers/stub-flair.ts and its test flair-catchup-fake.test.ts also stay,
because #629's task-loop and agent-logs tests use that route.

Evidence

Measured on f6b7d08 (main a509aa0).

  • The dashboard and office-status tests drive each command through the shared
    verifying stub (test/helpers/stub-flair.ts) against a Presence fixture,
    exercising the real readPresence reader and its validator, not a fake of the
    client. Both files cover a roster with a record plus an agent with none
    (never seen), a stale record (offline, was: …), a refused read (HTTP 403;
    the column reads unavailable, not never seen), a rejected request reported
    by code and never its message, malformed bodies (not an array, a record missing
    a field, not JSON), and the JSON fields.
  • Mutations, one per new rule, each breaking the fix and failing an assertion,
    then restored by copying the file back (clean git status): dashboard
    last-seen ignoring Presence (3 fail); a missing record guessed (3 fail); a
    failed read labelled never seen (5 fail); the record validator disabled
    (1 fail); office status ignoring the current task (3 fail); office status
    guessing a missing record (1 fail).
  • Selected files through the isolated launcher (node scripts/test-suite.mjs):
    90 pass, 0 fail, across flair-signer-commands.test.ts,
    office-status.test.ts, flair-signer-inventory.test.ts and
    no-identity-defaults-486.test.ts.
  • Full cli suite on f6b7d08: 3238 pass, 7 skip, 0 fail (208 files). On
    unmodified origin/main (a509aa0): 3258 pass, 7 skip, 0 fail (209 files); the
    20-test, one-file difference is the deleted catch-up fake and the replaced
    feed tests.
  • bun run build (tsc, strict) exit 0; bun run lint:ci exit 0;
    node scripts/changelog-fragments.mjs check ok.
  • Merge round (b0efa40, merging main 529e99f / fix(cli): the task loop and getEventsSince read Flair's catch-up envelope #629): I resolved the
    org-event-read.ts modify/delete conflict by keeping main's reader and
    removing only the two helpers that only the dashboard and office status used.
    In office-status.test.ts, the Presence tests stay, and so does fix(cli): the task loop and getEventsSince read Flair's catch-up envelope #629's
    cli#624 cursor-format describe (either {position} or legacy {since},
    cursorSince in JSON, cursor: Nm ago in the table), now keyed to the
    agent-a/agent-b fixture. I dropped the cli#620 catch-up cases. I restored
    the catch-up fake and its test. Full cli suite on rockit: merge 3305 pass,
    4 skip, 8 fail (3317 tests, 211 files); main 529e99f 3314 pass, 4 skip, 8 fail
    (3326, 211). The same 8 tests fail on both, all in files this merge does not
    touch (facts-verify, facts-commands, nono, launch-attestation-real-nono
    and office-supervision, measured on rockit, not CI). The 9 fewer tests are
    this PR's replacements: office-status.test.ts 24 to 18 and
    flair-signer-commands.test.ts 15 to 12. Agent package 240/240 on both.
    tsc (cli and agent), lint:ci and the changelog check all exit 0.

Deliberately not changed

Both views read Flair's office-wide Presence roster instead of the viewer's
OrgEvent catch-up feed, and label the columns for what they show: the
dashboard's activity column becomes Last Seen (presence status and the age of
the agent's last heartbeat), and office status shows the same plus the agent's
current task or activity. An agent with no presence record reads "never
seen"; a read that fails reads "unavailable". The catch-up reader and its
fake go with the reads.
@tps-anvil
tps-anvil requested a review from a team as a code owner October 13, 2026 22:46
@tps-anvil

Copy link
Copy Markdown
Collaborator Author

Sweep — PR for cli#622 (every sentence the PR adds or changes)

Checked against the code on f6b7d082. Claim types: (a) outcomes/status codes on
every branch, (b) scope words (every/all/only/never/none/always), (c) coverage
(does a named test assert it).

PR body / changelog fragment

  • "Both read Flair's office-wide Presence roster (GET /Presence) … instead of the viewer's OrgEvent catch-up feed." — (a) true: both commands now call readPresence (GET /Presence); the removed reader read GET /OrgEventCatchup/<viewer>. No test claim.
  • "The dashboard's last column is Last Seen, the presence status and the age of the agent's last heartbeat." — (b) none; (c) asserted by flair-signer-commands.test.ts "shows each agent's presence status and last-seen time".
  • "office status shows the same in LAST SEEN and the agent's current task or activity in ACTIVITY." — (c) asserted by office-status.test.ts "shows each agent's last-seen presence and current activity". OK.
  • "An agent with no presence record reads never seen, never a guess." — (b) "never". True: both lastSeenText and (office status) doingText return "never seen" when presenceByAgent has no entry; no default. (c) asserted in both files. OK.
  • "a read that fails reads unavailable, not an empty column." — True: both commands return "unavailable" when presenceState is "unavailable". (c) asserted by the refused-read tests. OK.
  • "Office status prints no blocker line." — (a) true: the blocker loop was removed with the feed read. (b) "no". OK.
  • "utils/presence-read.ts … signs one GET /Presence … validates the body is an array of records carrying the fields the commands read … returns ok or unavailable with a bounded reason — the HTTP status, a fixed note naming the malformed part …, or the code or class of the error a rejected request raised; the reason never includes the response body or an error message." — (a) every branch checked in readPresence: transport throw → request failed (<code|name>); !res.ok → HTTP <status>; JSON parse fail → fixed note; not an array → fixed note; a bad record → fixed note; else ok. None embed the body/message. (b) "never". (c) the malformed/refused/rejected tests assert the fixed notes. OK.
  • "The previous utils/org-event-read.ts reader and the catch-up route fake in test/helpers/stub-flair.ts are removed; the two commands were their only callers." — (b) "only". True: grep over src/ bin/ test/ finds no remaining reference to readOrgEvents or orgEventCatchupRoute; before removal, readOrgEvents was imported only by the two commands and orgEventCatchupRoute only by the deleted fake test and the two command tests. OK.

Code comments

  • presence-read module doc: "one record per agent that has pushed presence" — replaced an earlier "every agent's own heartbeat" (over-broad; an agent that never pushed has no record). Fixed.
  • presence-read module doc: "The reason never includes the response body or an error message." — matches every branch above. OK.
  • roster.ts: "the column says 'unavailable', not 'never seen'." — true for lastSeenText. OK.
  • office-status.ts: "the columns say 'unavailable', not 'never seen' / 'idle'." — true: both lastSeenText and doingText return "unavailable". OK.
  • office-status.ts doingText: "its activity (labelled 'was: …' once the Presence record has gone stale)." — true: activityFresh ? activity : 'was: ' + (lastActivity ?? activity). OK.

Test titles (claims too)

  • "shows each agent's presence status and last-seen time, and 'never seen' for an agent with no record" (dashboard) — asserts both. OK.
  • "an agent whose record has gone stale shows the offline status and its heartbeat time" — asserts offline (3d ago). OK.
  • "a refused read (HTTP 403) is reported, and the column reads unavailable, not never seen" — asserts the notice and unavailable, and not.toContain("never seen"). OK.
  • office status "shows each agent's last-seen presence and current activity, and 'never seen' for an agent with no record" — asserts active (3m ago), reviewing a PR, and never seen. OK.
  • office status "a stale record shows the offline status and its last-known activity" — asserts offline (3d ago) and was: debugging. OK.
  • "a refused read (HTTP 403) is reported, and the columns read unavailable, not never seen" — asserts both. OK.

Operator strings

Last Seen, LAST SEEN, ACTIVITY, never seen, unavailable, was: … — each is produced by the branch it names. No guarantee word outside those covered above.

Result: one sentence fixed (the presence-read module doc's "every agent"); the rest stand on the code and the named tests.

@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 0d07599f-5cfd-48c7-ae4d-e1d9b4969d87
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

tps-flint and others added 2 commits October 13, 2026 16:44
Resolve the #629 (cli#624) / #639 (cli#622) conflicts so both hold:

- utils/org-event-read.ts: keep main's reader. FlairClient.getEventsSince
  (the task loop, tps agent logs, tps status) now reads through it. Only
  the dashboard/office-status helpers activityState, orgEventReadNotice
  and ActivityState go, since nothing else calls them, and the module docs
  now name the remaining callers.
- test/office-status.test.ts: keep #639's Presence tests and drop the
  cli#620 catch-up describe, including #629's position fix to its
  malformed-cursor case, because office status no longer reads the feed.
  Keep #629's cli#624 cursor-format describe, re-keyed to the agent-a/agent-b
  fixture.
- test/helpers/stub-flair.ts and test/flair-catchup-fake.test.ts: restore
  them from main. #629's flair-task-loop.test.ts and agent-logs.test.ts use
  orgEventCatchupRoute, and the fake's own test covers that route.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dashboard and office status activity reads from a source that matches what they show

2 participants