Skip to content

feat(improve): self-healing notifications and lousho improve status - #999

Merged
LinuxDevil merged 3 commits into
mainfrom
s25-notify
Nov 8, 2026
Merged

LinuxDevil merged 3 commits into
mainfrom
s25-notify

Conversation

@LinuxDevil

Copy link
Copy Markdown
Owner

Why

S25 of the M4 plan (m3-notes/m4/parity.md): E8 and B4. In auto mode people learn about changes after the fact, and in manual mode they must learn that a proposal is waiting. They also need one place to see the loop's state.

Changes

  • src/observe/alerts.ts: new AlertEvent types improve.pending, improve.applied, improve.rolled_back, improve.guard_failed, improve.paused, improve.canary. details is { agent, dir, from, to, reason, cycle }, plus card (the local path of a pending proposal file).
  • src/improve/notify.ts: builds the events; the reason always goes through the audit log's plain() (no links, images, HTML or <untrusted> markers; R11). The notifier never throws: a throwing log, a throwing or rejecting alerter.post are swallowed.
  • Watcher (watch.ts, watchSteps.ts): WatchOptions.alerter and log (default one stderr line per event). Events: a cycle that ends pending, applied, guard-rolled-back or canary-failed; a new pause (kill switch, or the self-pause after three outages); a monitor rollback or an unrolled regression, once per apply (through the harvest claim); a scheduled-guard regression, once per revision. The CLI --watch posts to the alerts.json webhooks beside the observe db through createAlerter.
  • src/improve/status.ts improveStatus(dir) and lousho improve status <dir> [--json]: mode, paused (kill switch) state, active revision, last 5 audit entries, pending proposals, the monitor's verdict (an apply it hasn't judged shows pending), budget left today (cycles, automatic applies, tokens), cooldown (audited rollback or the monitor's cooldownUntil), the canary (traffic setting and the last replay verdict), the last cycle, and warnings (the monitor waiting for runs, kept unverified, an unrolled regression, an unreadable state.json, instructions not in instructions.md). Reasons are plain text, and the text form keeps each field on one line.
  • Docs: docs/cli.md (status), the alerts paragraph in docs/observability.md.

Testing

  • src/improve/watch.test.ts: an apply posts one improve.applied (and one stderr line); webhook and log failures never fail the cycle; a pause and a pending proposal post once each, the pending one with its local card path; a monitor rollback posts once across ticks with a rejecting webhook and a planted image link stripped from the reason; noticeEvent strips links, images, HTML and markers.
  • src/cli/improve.test.ts: status --json has every field (monitor pending with its warning right after an apply), the text form, a corrupt state.json becomes a warning, a missing directory is refused, a planted multi-line, markdown cycle reason prints as one plain line.
  • Independent review: no blockers; should-fix items (stale monitor state in status, unsanitized cycle/canary reasons and newline injection in the text form, a notifier path outside the try, a scheduled-guard event re-posted every run, missing tests) and the nits on a missing dir and a corrupt state.json are fixed in the second commit.
  • typecheck (src, tests, examples), lint, build, api:update + api:check, docs:llms + docs:llms:check, docs:verify-snippets -- --skip-build, docs:ratchet (1724), vitest src/improve src/cli src/observe, npx fallow audit --base origin/main after scoped coverage.

🤖 Generated with Claude Code

LinuxDevil and others added 3 commits November 9, 2026 02:19
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Status reports an unjudged apply as pending with a warning, keeps going on a
corrupt state.json, refuses a missing directory and prints reasons as one line
of plain text; the notifier can't throw; a scheduled guard failure posts once
per revision.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@LinuxDevil
LinuxDevil merged commit 66ac2a0 into main Nov 8, 2026
6 checks passed
@LinuxDevil
LinuxDevil deleted the s25-notify branch November 8, 2026 23:34
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