Skip to content

Bob 2.0 driver observability: review-findings capture + last_dispatch health signal - #47

Merged
Joshua-Gilbert merged 3 commits into
mainfrom
feat/bob2-driver-observability
Jul 9, 2026
Merged

Bob 2.0 driver observability: review-findings capture + last_dispatch health signal#47
Joshua-Gilbert merged 3 commits into
mainfrom
feat/bob2-driver-observability

Conversation

@Joshua-Gilbert

Copy link
Copy Markdown
Collaborator

Problem

On 2.0 in-process dispatch, two things were invisible:

  • Review findings were lost. readResultText returns only Bob's closing summary, but a review's findings live in earlier assistant messages — so review-mode tasks completed with no structured bob-review note.
  • A live-but-failing drainer looked healthy. The heartbeat only says "something is beating"; a logged-out Bob keeps beating while every dispatch aborts, and board_status had no way to show it.

Changes

  • Full review-findings capture on the 2.0 driver — review-mode dispatches parse the whole transcript into the structured board note (parity with 1.x). The parser now skips a ### section with no severity and no Location/Category field, so a reasoning turn's headed markdown can't become phantom "info" findings.
  • board_status.worker_draining.last_dispatch — each live drainer's most recent dispatch outcome (status, failure detail, freshness), stamped by both the 2.0 in-process loop and the standalone CLI worker. detail is stored only for failures, so success text (task content) never reaches board_status.
  • Webhook hardening (the feature is unreleased — merged after the 2.1.0 npm publish):
    • the overflow warning re-arms when capacity returns, not only at zero in-flight (a busy-but-alive endpoint may never reach zero, which muted every later overload);
    • the payload carries worker.run (the heartbeat id) so seq scopes per process run — a receiver can tell a restart from data loss, and events correlate to board heartbeats;
    • post() survives a synchronously-throwing fetch (never-throws contract);
    • --webhook-secret without --webhook fails loud instead of silently not signing.
  • CHANGELOG correction — the --webhook entry moved out of the published 2.1.0 notes into a new Unreleased section (npm 2.1.0 was built from the pre-merge commit and does not contain it), alongside entries for last_dispatch and the review capture.

Why

The board is only trustworthy if it reflects what Bob actually did: a review that silently drops its findings, a drainer that fails every dispatch while reading "draining", or a changelog claiming a feature the published package lacks all break that. New coverage: an end-to-end test that runDriverLoop stamps its own heartbeat, detail-gating on success, warning re-arm, sync-throw, and prose-heading tests (718 tests green).

A review dispatched by the 2.0 driver landed only a one-line summary on the
board — no structured bob-review note — because two steps the 1.x worker does
were missing on the 2.0 path:

- finalize() never called persistReviewFindings, so the bob-review note was
  never written, regardless of the result text.
- readResultText returns only Bob's LAST assistant message, which for a review
  is often the closing summary rather than the findings (they sit in an earlier
  message). Added readReviewText to join the task's assistant messages so the
  parser sees the whole transcript.

The 2.0 driver now parses the full review text into reviewFindings for review
mode, and finalize() persists them via the same path the 1.x worker uses.
…atus

A logged-out Bob still heartbeats (the 2.0 in-process loop keeps running), so
worker_draining reads healthy while every dispatch aborts on a provider
auth/network error — the foreman can't tell "draining" from "draining but
failing" and dispatches into a guaranteed abort.

Record each dispatch's outcome onto the worker's heartbeat row and surface the
freshest one among live drainers as worker_draining.last_dispatch ({status,
detail, seconds_ago}). A status of "aborted" now flags "alive but not
completing work" up front. Proactive login state can't be probed (Bob exposes
no auth API), so this is the reactive signal the driver already has.

- db: three heartbeat columns + recordDispatchOutcome; getWorkerLiveness picks
  the freshest outcome among live rows (a dead worker's stale one doesn't leak).
- driver-loop: finalize() stamps every dispatch outcome via the loop's worker id.
…ning

- The standalone CLI worker never stamped last_dispatch, so the new
  board_status health signal stayed null on the documented dispatch
  path. runOne now stamps every outcome (and main's catch stamps
  error), mirroring the 2.0 loop's finalize().
- recordDispatchOutcome stores detail only for a non-completed status:
  on success the caller's text is Bob's last assistant message, and
  task content must not leak into board_status.
- parseReviewFindings skips a ### section with no severity and no
  Location/Category field: the 2.0 path feeds the whole transcript,
  where a reasoning turn's headed markdown became phantom info
  findings on the board note.
- Webhook: the overflow warning re-arms when capacity returns (below
  cap, not zero, which a busy-but-alive endpoint may never reach); the
  payload carries worker.run (the heartbeat id) so seq scopes per
  process run and a restart isn't read as data loss; post() survives a
  synchronously-throwing fetch; --webhook-secret without --webhook
  fails loud instead of silently not signing.
- CHANGELOG: --webhook moved out of the published 2.1.0 notes (it
  merged after the npm publish and is not in that package) into a new
  Unreleased section, alongside the last_dispatch and 2.0
  review-capture entries.
@Joshua-Gilbert
Joshua-Gilbert merged commit df358e1 into main Jul 9, 2026
3 checks passed
@Joshua-Gilbert
Joshua-Gilbert deleted the feat/bob2-driver-observability branch July 9, 2026 19:50
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