Skip to content

refactor(desktop): collapse two observation clocks into one 60s clock - #692

Merged
charleslpan merged 1 commit into
brain-spikefrom
conductor/one-60s-observation-clock
Sep 4, 2026
Merged

refactor(desktop): collapse two observation clocks into one 60s clock#692
charleslpan merged 1 commit into
brain-spikefrom
conductor/one-60s-observation-clock

Conversation

@charleslpan

@charleslpancharleslpan commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • One clock at 60s: SESSION_REFRESH_INTERVAL_MS 5 000 → 60 000. The BRAIN_ROSTER_WAKE_INTERVAL_MS constant and BrainAgent's internal timer are removed entirely; the roster look is now driven by afterRun on the observation pass instead.
  • BrainAgent.rosterLook() replaces start(): the host calls it after each observation pass completes; start()/stop() are simplified — stop() remains to drain the queue at shutdown, start() is gone. The agent remains fully testable without Electron.
  • Act validation freshness: performSession calls refreshSessions() (→ sessionObservationLoop.refresh()) before reading the session list. A fresh pass before every session act closes the staleness window from ≤60 s to effectively zero for messages, renames, controls (including delete), creates, and opens. If the loop is already running, refresh() queues the next pass and returns immediately; validation then uses the most recent completed-pass data, which is close to fresh.
  • CREATED_WORKSPACE_OPEN_WINDOW_MS: 2 min → 5 min. At 60 s per pass, 2 minutes was only 2 chances; 5 minutes gives 5, covering providers that are slow to publish a deep link.

Behavioral changes

Observation gate on the roster look (deliberate)

The roster look now runs inside afterRun, which is only called when isCurrent(generation) holds — meaning runMode.observesProviders && accountCapabilitiesActive(). BrainAgent's own timer was not subject to this gate. That is believed correct — a brain looking at a roster nobody is observing is odd — but it is a deliberate change from the previous behaviour where the timer ran independently.

Codex CLI login latency

broadcastCodexCloudConnection() still rides afterRun with nothing else behind it; Codex CLI login changes now take up to 60 s to propagate. This is acceptable — the user manually ran codex login or codex logout in their own terminal, and a 60 s delay does not affect anything safety-bearing.

All session acts refresh, not only writes

The fresh pass fires before creates and opens too, not only before messages, renames, and deletes. Creates validate against project offers (which the refreshed adapters also update); opens and read-transcript are read-only but cheap to gate. The overhead of one extra observation pass per brain act is acceptable given the correctness benefit at 60 s intervals.

Test plan

  • ./scripts/check.sh passes: 0 errors (20 pre-existing CSS specificity warnings in unchanged files), all 798 desktop tests pass, 34 brain tests pass, 57 session tests pass, all typechecks clean
  • Physical-notch check not performed (no UI surface change; this is a main-process timing change only)

🤖 Generated with Claude Code


Open workspace in Conductor

Open in Alchemize

Automated visual evidence

Download the deterministic macOS evidence · workflow run

  • Commit: 809900c5f5dca85442e14d8952b84b1ac6b4798e
  • Scenario: smoke
  • Physical-notch check: not performed by CI

Merges SESSION_REFRESH_INTERVAL_MS (was 5s) and BRAIN_ROSTER_WAKE_INTERVAL_MS
(was 60s) into a single 60s observation clock. The brain's roster look is
now driven by the observation pass's completion (afterRun) rather than its
own independent timer.
**Behavioral changes to call out**
The roster look now runs under observationGate (runMode.observesProviders &&
accountCapabilitiesActive()). BrainAgent's own timer was not subject to this
gate. That is believed correct — a brain looking at a roster nobody is observing
is odd — but it is a deliberate change.
**Act validation staleness (fix)**
brainActableSessions() is validated "at the moment of the act". At 5s that was
roughly true; at 60s an act could be validated against a roster up to a minute
old. The fix: performSession now calls refreshSessions() before reading the
session list, triggering a fresh observation pass. This applies to all session
acts (messages, renames, controls/deletes, creates, opens). For creates and
opens the staleness of the session list is less critical, but a fresh pass
also updates the project offers they validate against, so the overhead is
justified. If the observation loop is already running, refresh() queues the
next pass and returns immediately; the validation then uses the most recent
completed pass's data, which is close to fresh.
**CREATED_WORKSPACE_OPEN_WINDOW_MS**
Widened from 2 minutes to 5 minutes. At 60s intervals, 2 minutes gave only 2
chances for a newly-created workspace to be reported with an address. 5 minutes
gives 5 chances, matching the tolerance for providers slow to publish their
deep link.
**broadcastCodexCloudConnection**
Still rides afterRun with nothing else behind it. Codex CLI login changes now
take up to 60s to propagate. This is acceptable — the user logged in or out
by hand, and a 60s delay in noticing does not affect anything safety-bearing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vercel

vercelBot commented Sep 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated
luke-webReadyReadyPreviewSep 4, 2026 4:29am UTC

Request Review

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 809900c. Configure here.

// is closed (observesProviders && accountCapabilitiesActive()).
afterRun: () => {
void broadcastCodexCloudConnection();
brain?.rosterLook();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hook wakes split from roster looks

Medium Severity

Hook handling awaits refresh() and only then calls wake(), but afterRun now starts rosterLook() as soon as that pass finishes. The look runs first, reads live transcripts and advances cursors, while the hook events are still queued. Those wakes then open a second turn with empty deltas, so the hook kind no longer rides with the transcript it belongs to and the brain pays for two turns instead of one.

Additional Locations (2)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 809900c. Configure here.

@charleslpan
charleslpan merged commit 5b215ae into brain-spikeSep 4, 2026
5 of 6 checks passed
@charleslpan
charleslpan deleted the conductor/one-60s-observation-clock branch September 4, 2026 19:06
Sign up for freeto 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.

1 participant

@charleslpan