From 0767af804b980c23fdd759f65c0f50b499fb1bbe Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Mon, 20 Jul 2026 12:30:51 -0500 Subject: feat(sentry): a quiet fire collapses to a one-line heartbeat A sentry fire whose passes all probe-skip or no-op now writes a single "sentry at HH:MM: nothing" line instead of a full per-pass digest block. A fire that runs or queues anything writes the full digest as before. This is Phase 1 of the silent-until-signal policy. The live trial's fires 3-8 were walls of no-op digests, the noise this removes. The "no silent skip" discipline is reconciled, not broken: inside a working fire every pass still writes its ran/skipped line, and a quiet fire's heartbeat is the explicit "nothing to do" record rather than a hidden skip. --- .ai/workflows/sentry.org | 10 +++++----- claude-templates/.ai/workflows/sentry.org | 10 +++++----- docs/specs/2026-07-20-silent-until-signal-monitors-spec.org | 5 ++++- todo.org | 2 +- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.ai/workflows/sentry.org b/.ai/workflows/sentry.org index 56f0c96..bfeeffc 100644 --- a/.ai/workflows/sentry.org +++ b/.ai/workflows/sentry.org @@ -89,7 +89,7 @@ Each fire, after acquiring the single-runner lock and verifying branch state (be 2. *Work* — run the pass under the unattended contract. Quick, solo, already-agreed mechanical actions execute. Anything destructive or requiring judgment does *not* execute — it appends to the morning-approval queue (what, why, the exact command or edit that fires on approval). A pass runs fully or not at all; there is no reduced-form pass. -3. *Session-context entry* — append the pass's digest line to the =session-context.org= Session Log (path resolved via =.ai/scripts/session-context-path=). This precedes the commit so a crash between them still leaves the trail. +3. *Session-context entry* — a pass that does or queues work appends its digest line to the =session-context.org= Session Log (path resolved via =.ai/scripts/session-context-path=) before its commit, so a crash between them still leaves the trail. Per-pass lines for an all-quiet fire (every pass probe-skipped or no-op) are not written one by one — the fire collapses to a single heartbeat at fire-end (below), so an idle fire doesn't spray one skip line per pass. 4. *Commit* — if the pass wrote to disk, commit it: =chore(sentry): =. One commit per writing pass. A probe-skip or a no-op pass writes nothing and commits nothing. @@ -111,7 +111,7 @@ With no one at the terminal, any unsafe state makes the affected scope skip with - *A pass's own precondition unmet* (its probe fails, or a dependency is dirty) → skip that pass only. - *Red suite at fire-end* (see below) → the commits stay on the branch, flagged in the digest for morning review; the fire doesn't roll back. -Skips are never silent and never partial. A pass line in the digest means the pass fully ran; a skip line names why it didn't. +Skips are never silent and never partial. Inside a *working* fire, a pass line means the pass fully ran and a skip line names why it didn't. An *all-quiet* fire is not a silent skip either: its single =sentry at HH:MM: nothing= heartbeat is the explicit record that every pass found nothing, standing in for a wall of identical skip lines. The anti-silence rule targets a pass that hides work it should have surfaced; a quiet fire has surfaced that there was none. ** Multi-day stall notification @@ -153,13 +153,13 @@ After the passes: 1. *Conditional suite run.* If any pass this fire modified files *outside* the org/spine set (a code-touching pass, rare but possible via fixtures), run the full suite once. A green run confirms the fire's commits are safe; a red run flags the digest for morning review — the commits stay on the branch (nothing is pushed, so the morning gate catches it). No per-pass suite runs: the entry run is the green baseline, and hourly per-commit runs would turn a seconds-long fire into minutes all night. Fires that only touched org/spine files skip this. -2. *Digest commit.* Commit any accumulated spine writes in one sweep — =chore(sentry): digest —