Skip to content

feat(overseer): query_open_loops — "what am I forgetting?" lens - #100

Open
heavygee wants to merge 2 commits into
feat/overseer-text-conversefrom
feat/overseer-open-loops
Open

feat(overseer): query_open_loops — "what am I forgetting?" lens#100
heavygee wants to merge 2 commits into
feat/overseer-text-conversefrom
feat/overseer-open-loops

Conversation

@heavygee

Copy link
Copy Markdown
Owner

Stacked on feat/overseer-text-converse. Implements the validated cold open-loops / "what am I forgetting?" lens (design + live evidence in docs/plans/2026-07-31-overseer-forgotten-open-loops-lens.md).

Why

The inbox answers urgency ("what needs me now?"). This adds the orthogonal neglect axis ("what have I abandoned?"). It is self-populating from the AGENT_NOTIFY_SUMMARY every worker turn already emits — no operator triage (the operator has disposed 0/174 inbox items, so "old + undisposed" is useless as a filter; the self-disposition signal is the substitute).

A cold open loop = a session whose latest status-bearing worker event is NOT done (needs_decision/needs_review/blocked/failed/stalled) and was never closed by a later completed.

What's in it

  • query_open_loops (8th read-only tool). Substrate = raw events (richer than the coalesced inbox), one indexed query for the latest status-bearing worker event per session (progress excluded — it doesn't close an operator-owed decision; completed is the only closer).
  • Strong filter = status != done. A no-op action ("none"/"complete"/…) is nulled but the loop still surfaces — action is a tiebreak, not the filter (kills the 108 Tier-B false positives from the spec correction).
  • Buckets: waiting_on_you (a decision the operator owes) presented before half_finished, each coldest-first.
  • System prompt: two-axes section (urgency vs neglect) + priority-direction fix (lower-is-higher — the 27B live-called p50 "highest").
  • Brain projection thins rows; identity survives session deletion (denormalized payload).
  • Zero-code weekly digest prompt documented (build-path step 1 — works today over this tool).

Not here (follow-ups)

  • Archiving hygiene / legacy stale-row sweep (build-path step 3) — coordinate with the inbox-ingest lane. (Worker-only filter already keeps those source_kind=system rows out of the lens.)

Tests / gates

  • bun typecheck clean (hub + web).
  • New: entity lens (ordering / closed-loop exclusion / no-op nulling / minAge+project+bucket filters), brain projection, shared isNoOpAction / openLoopBucket; updated tool count 7→8.

Made with Cursor

Adds a read-only neglect-axis lens, orthogonal to inbox urgency. A cold open
loop = a session whose latest status-bearing worker event is not `done`
(needs_decision/needs_review/blocked/failed/stalled) and was never closed by a
later `completed`. Self-populating from AGENT_NOTIFY_SUMMARY; no operator triage.

- shared: 8th tool query_open_loops (name, zod schema, catalog, OpenAI params,
  OverseerOpenLoop return type); isNoOpAction + openLoopBucket + open-loop
  event-type constants.
- store: latestWorkerStatusPerSession — one indexed query, latest status-bearing
  worker event per session (progress excluded; completed is the only closer).
- entity: queryOpenLoops — drops closed loops, nulls no-op actions (status!=done
  is the strong filter, action is a tiebreak), buckets waiting_on_you before
  half_finished, coldest-first; identity survives session deletion via payload.
- converse: brain-facing projection thins the rows; system prompt gains a
  two-axes section (urgency vs neglect) and fixes priority direction
  (lower-is-higher — the 27B called p50 "highest").
- docs: implementation notes + the zero-code weekly-digest converse prompt.
- tests: entity lens (ordering/closed/no-op/filters), projection, shared helpers;
  tool count 7 -> 8.

Co-authored-by: Cursor <cursoragent@cursor.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 74acbcc030

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const limit = Math.min(Math.max(args.limit ?? 50, 1), 100)

const loops: OverseerOpenLoop[] = []
for (const event of this.events.latestWorkerStatusPerSession()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Scope open loops to the caller namespace

On a multi-user hub, this reads the global EventStore without receiving or filtering by the authenticated request's namespace, so /overseer/tools/query_open_loops and the converse tool can mix another namespace's session names, projects, summaries, and actions into the response. Pass c.get('namespace') through the Overseer dispatch and restrict candidate events to sessions owned by that namespace.

AGENTS.md reference: AGENTS.md:L145-L149

Useful? React with 👍 / 👎.

Comment thread hub/src/store/events.ts
Comment on lines +319 to +320
ORDER BY e.ts ASC
LIMIT ?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Apply the cap after excluding closed sessions

Once the database contains more than 500 sessions with status-bearing events, this selects only the 500 oldest per-session statuses before the caller removes completed rows and applies bucket/project filters. Consequently, newer open decisions can disappear permanently—potentially returning an empty lens if the oldest 500 sessions are closed—and the reported counts are also truncated. Build the latest-per-session set first, exclude closers/apply filters, then limit the resulting open loops in the requested presentation order.

Useful? React with 👍 / 👎.

Comment thread hub/src/store/events.ts
Comment on lines +312 to +315
WHERE source_kind = 'worker'
AND related_session_id IS NOT NULL
AND event_type IN (
'needs_decision', 'needs_review', 'blocked', 'failed', 'stale', 'completed'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Let inferred completion close an open loop

When a session ends with reason === 'completed' but its last agent output lacks a parseable AGENT_NOTIFY_SUMMARY, OverseerEventRecorder.onSessionEnd deliberately records a later completed event with sourceKind: 'system'. This worker-only predicate ignores that definitive closer, leaving any earlier blocked, failed, or decision event surfaced as abandoned forever. Include system-generated completion fallback events when selecting the latest closing status while continuing to restrict opening statuses to worker events.

Useful? React with 👍 / 👎.

…prompt (H1/H2/H4)

Ingest-peer handoff (PR #99 -> converse/entity layer):

- H2: two-level `detail: 'lean'|'full'` (default lean) on every context tool,
  threaded into projectToolResultForBrain(tool, result, detail). Closes the
  coverage gap — get_session_state, get_session_recent_output (raw terminal text
  capped at 280 chars in lean; was a token bomb), and get_worker_health (signal
  trail dropped in lean) now have lean projections. `full` returns raw rows,
  still bounded by limit/n + the outer char clamp. No token-budget engine.
- H1: system-prompt rule — for a specific inbox item, pull explain_priority then
  query_events{sessionId} for that session's backlog as salience before answering.
- H4: confirmed query_open_loops spans all non-deleted sessions (active AND
  archived); never filters on session.active. Documented in the method + doc.
- H3: query_session_actions reader deferred (0 dispositions today).

Tests: session-state/recent-output/worker-health lean projections, detail:full
passthrough; pass-through test moved to explain_priority.

Co-authored-by: Cursor <cursoragent@cursor.com>
@heavygee

Copy link
Copy Markdown
Owner Author

Follow-up commit 6792bea07 lands the ingest-peer handoff items (PR #99 → converse/entity layer):

  • H1 — system-prompt rule: for a specific inbox item, pull explain_priority then query_events{sessionId} (that session's backlog) as salience before answering.
  • H2 — two-level detail: 'lean' | 'full' (default lean) on every context tool, threaded into projectToolResultForBrain(tool, result, detail). Closes the coverage gap: get_session_state, get_session_recent_output (raw terminal text capped at 280 chars in lean — was a token bomb) and get_worker_health (signal trail dropped in lean) now have lean shapes. full = raw rows, still bounded by limit/n + the outer char clamp. Two levels, no token-budget engine.
  • H4 — confirmed query_open_loops spans all non-deleted sessions (active AND archived); never filters on session.active. Deleted sessions drop out via detachSessionEvents (related_session_id = NULL).
  • H3query_session_actions reader deferred (~0 dispositions today).

Gates: bun typecheck clean (hub+web); projection/entity/route/shared suites green.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6792bea07e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/** Transcript chunk → role + capped text (raw terminal output would blow the window). */
function projectChunk(chunk: unknown): Record<string, unknown> {
const o = isObj(chunk) ? chunk : {}
return { role: o.role, at: o.createdAt, text: truncate(o.text, LEAN_CHUNK_TEXT_MAX) }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve the tail of truncated transcript chunks

When a worker chunk exceeds 280 characters, the default lean projection retains only its prefix. This repository's agent contract requires the status, action, and summary line at the end of every response (shared/src/overseerEvents.ts:14-18), so get_session_recent_output now routinely hides both that machine summary and often the worker's conclusion, causing the Overseer to answer from incomplete context unless the model happens to request detail: "full". Preserve a head-and-tail slice or explicitly retain the final summary line within the same cap.

Useful? React with 👍 / 👎.

heavygee added a commit that referenced this pull request Jul 31, 2026
…onverse

8th read-only Overseer tool query_open_loops ("what am I forgetting?"
cold-open-loops lens) + system-prompt two-axes framing and priority
lower-is-higher fix. Additive store query, no DDL/schema-version step.
Sits immediately after feat/overseer-text-converse (stacked on it).
Rebuilt + verified on :3006 at driver tip 002e32dcc; live query_open_loops
trace confirmed.

Co-authored-by: Cursor <cursoragent@cursor.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.

1 participant