Skip to content

feat(senior-unilp-manager): let a ratchet cron stay quiet when nothing happened - #235

Merged
andreapn merged 1 commit into
mainfrom
feat/ratchet-alert-only-cron
Aug 6, 2026
Merged

feat(senior-unilp-manager): let a ratchet cron stay quiet when nothing happened#235
andreapn merged 1 commit into
mainfrom
feat/ratchet-alert-only-cron

Conversation

@andreapn

@andreapn andreapn commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Closes #234

The problem

A ratchet tick wired as a cron script job delivered the full result of every mandate on every run. On a healthy ratchet that is a block of JSON saying nothing happened, every ten minutes, until nobody reads it any more.

The change

tick --json now takes --alert-only.

Quiet tick — still prints the whole payload, so the cron run history keeps it and a silent tick stays auditable — then ends on the gate line:

{
  "chain": "robinhood",
  "broadcast": true,
  "results": [ … ],
  "notable": 0,
  "quiet": 5
}
{"wakeAgent": false}

has_actionable_output() (src/agentos/scheduler/scripts.py) already reads that last line as "no news", so the run succeeds and script_run_handler delivers nothing. No core change was needed.

Notable tick — a summary line per mandate above the JSON, delivered as usual:

FIRED 7857cce2  #476498  tx 0xbeef

{ … }

Summary first and JSON last is deliberate: the gate reads the final line, and pretty-printed JSON ends in }, which is not a gate. An alert cannot accidentally silence itself.

Action Delivered
noop, skipped, waiting, deferred no
fired, adopted, halted, rejected, dry-run, expired, missing, error yes
any action, state NEEDS_ATTENTION yes, every tick

That last row is the one that matters. NEEDS_ATTENTION is terminal, so a halted mandate reports the same plain noop as a healthy one while it waits for a person. Filtering on the action alone silences the one alarm that must never go quiet — the bug in every hand-rolled action != "noop" wrapper script, and the reason this belongs in the skill.

The flag is opt-in and only affects --json, so tick run by hand prints exactly what it always did.

Verification

selftest.py                    733 assertions pass (17 new)
uv run ruff check .            All checks passed
uv run mypy src                591 files, no issues
pytest skill contract tests    11 passed

Against live mandates:

robinhood            notable 0, quiet 5  →  {"wakeAgent": false}
base                 notable 0, quiet 1  →  {"wakeAgent": false}

End to end through the gateway's own gate:

has_actionable_output(quiet tick)          False   # not delivered
has_actionable_output(without --alert-only) True   # old behaviour intact
has_actionable_output(simulated fire)       True   # delivered, with summary

Docs

SKILL.md gains the --alert-only cron recipe, an explanation of why a quiet tick is not a dead job, and an error-handling row for "this cron has said nothing for hours" — expected, and the run history proves it ran.

🤖 Generated with Claude Code

…g happened

A ratchet tick wired as a cron script job delivered the full result of every
mandate on every run, so a healthy ratchet posted a block of JSON saying nothing
happened, every ten minutes, until nobody read it any more.

`tick --json` now takes `--alert-only`. A tick that found nothing still prints the
whole payload — the cron run history keeps it, so a quiet tick stays auditable —
but ends on the line `{"wakeAgent": false}`, which `has_actionable_output()`
already reads as "no news": the run succeeds and nothing is delivered. A tick that
fired, adopted a landed fire, halted, was rejected, expired, or built a plan on a
dry run prints a one-line summary above the JSON and is delivered as usual.

NEEDS_ATTENTION is tested apart from the action, and deliberately alerts on every
tick. It is a terminal state, so a halted mandate reports the same plain `noop` as
a healthy one while it sits there waiting for a person; filtering on the action
alone would silence the one alarm that must never go quiet. Hand-rolled wrapper
scripts that filter on `action != "noop"` have exactly that bug, which is part of
why this belongs in the skill rather than in each user's shell script.

The flag is opt-in and only touches `--json` output, so running `tick` by hand
prints what it always did.

Closes #234

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@andreapn andreapn self-assigned this Aug 6, 2026
@andreapn
andreapn merged commit 5cff077 into main Aug 6, 2026
5 checks passed
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.

ratchet tick floods its cron channel with ticks that have no news

1 participant