Skip to content

feat: add durable monitor decisions - #5181

Merged
bolichen97 merged 1 commit into
mainfrom
token-monitors-core
Aug 28, 2026
Merged

feat: add durable monitor decisions#5181
bolichen97 merged 1 commit into
mainfrom
token-monitors-core

Conversation

@kyleseaman

@kyleseaman kyleseaman commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Stacked change: PR 2 of 8

Stack: #5180#5181#5182#5183#5184#5185#5186#5305
Base: #5180
Next: #5182

Problem / Motivation

AutoNudge persists scheduling data but has no typed representation of monitored state, decisions, evidence, budgets, or terminal outcomes.

Why it matters

Without a durable decision core, unchanged probes cannot be separated from costly action turns, restarts cannot recover safely, and malformed or future state can accidentally re-arm work.

What changed (motivation → approach → change)

  • Add versioned monitor state, observations, budgets, outcomes, and a pure bounded decision policy.
  • Persist optional structured monitor state alongside legacy AutoNudge records without changing legacy serialization or delivery behavior, and preserve typed live values when a registry write fails.
  • Preserve unsupported future payloads and their outer active intent for inspection while keeping them inert on older gateways, including when a generic legacy Save submits active=true.
  • Prevent malformed or terminal structured records from entering the legacy firing path.
  • Quarantine malformed current-version mappings as inactive while preserving their exact strict-JSON payload across unrelated store rewrites, including timestamp integers too large for finite arithmetic.

Tests

  • Monitor decision tables and budget precedence
  • Persistence round-trips, malformed/future-version handling, and restart behavior
  • AutoNudge scheduling, deadline, approval-stall, and legacy-compatibility coverage

Manual verification

N/A — deterministic decision and persistence coverage exercises the complete surface introduced by this PR.

Related Issues

N/A — implements the durable-state layer specified in #5180.

Checklist

  • Single commit with a Conventional Commits title
  • Existing tests pass and new tests cover the new behavior
  • Self-review completed; code follows project style guidelines
  • Documentation updated where applicable
  • No secrets, credentials, or internal references in the diff

Contribution License Agreement

N/A — the repository template does not yet supply final CLA wording.

@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ no blocking findings

GPT 5.6 completed its review of 0580ec47c97366a798da2e6eb110efa8c180fe07 and found no blocking issues.

This comment is updated in place on each push.

Review details

No findings.
[GPT-REVIEWED] 0580ec4

False positive or not applicable? A repository writer can comment:
/ai-review override gpt 0580ec47c97366a798da2e6eb110efa8c180fe07: <one-sentence reason>

@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — 🟡 CONCERNS

Design-level review of 0580ec47c97366a798da2e6eb110efa8c180fe07 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

Design-Verdict: CONCERNS

Sound substrate with careful versioning; one decision-policy ordering risk — an unchanged-fingerprint SUCCESS can never terminate the monitor.

Watch

  • In decide_monitor, the dedupe if observation.fingerprint == state.last_fingerprint: return NO_CHANGE runs before the SUCCESS check, so a probe whose status flips to SUCCESS while its fingerprint stays the same is suppressed forever: the monitor keeps probing a completed target until STOP_BUDGET, recording outcome BUDGET instead of SUCCESS. This is safe only under an unstated contract that adapters (landing in later slices) must fold status into the fingerprint — neither MonitorObservation nor the spec pins that. Either check SUCCESS before the dedupe (a met objective should stop regardless of fingerprint) or state the fingerprint-includes-status contract in monitoring/models.py and the spec so later adapter PRs can't silently violate it.

Suggestions

  • The invariant "a monitor-bearing loop never reaches legacy delivery" is enforced by loop.monitor is not None checks at five sites (_arm_from_deadline, _timer, _run_fire_cycle, _deliver_and_commit, update); redundancy makes it fail-closed today, but a future legacy-path addition that forgets the check fires structured state through prompt delivery. Consolidate into one named predicate at the timer/fire choke point before Task4 multiplies the dispatch sites.

[DESIGN-REVIEWED] 0580ec4

@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5) — 🟡 CONCERNS

Premise-level review of 0580ec47c97366a798da2e6eb110efa8c180fe07 — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

All counts verified. Writing the review now.

First-Principles-Verdict: CONCERNS

The decision policy and most of the v1 vocabulary ship with zero production consumers; only the store-preservation half must land before a writer exists.

What this change ships

Intent: give AutoNudge a restart-safe, version-tolerant typed record for probe-first monitors ahead of the controller that will drive them — an ADDITION (declared PR 2 of an 8-PR stack).

  1. AutoNudge records can carry a versioned monitor field that survives unrelated rewrites — justified
  2. Any loop carrying a monitor never arms, fires, or delivers via legacy prompts — justified
  3. Generic Save/PATCH cannot re-arm current, terminal, or future monitors — justified
  4. Future-version payloads kept byte-exact, marked blocked, outer active intent preserved — justified
  5. Malformed current-version monitors quarantined inactive with raw payload retained — justified
  6. Dashboard responses redact every nested string in monitor state — undeclared (boundary-derived)
  7. Pure decide_monitor policy plus decision/observation/provider-error enums — zero consumers
  8. Budget and cadence defaults (14,400s / 8 turns / 250k tokens / 3 errors / 300s) — zero consumers
  9. Failed registry write now rolls back typed values intact — justified
  10. Second budget/cadence spelling beside legacy max_runtime_secs / idle_secs — watch

Watch

  • decision.py is dead code in this slice: grepping decide_monitor|MonitorDecision|MonitorObservation|ProviderErrorKind across src/ hits only the two defining files (0 consumers), and MonitorState( is constructed only inside models.py's own decode/quarantine paths — no API, MCP, or CLI can create a monitor. The persistence half genuinely must ship before the writer (a monitor-unaware loader drops the key on rewrite, so every intermediate release needs preservation), but the decision policy freezes no bytes and gains nothing from shipping ahead of refactor: account for completed monitor turns #5182+.
  • 5 of 6 MonitorOutcome variants and all 5 ProviderErrorKind variants have zero production constructors; only BLOCKED is ever written until the controller lands.
  • Two runtime-budget spellings now persist on one loop record: NudgeLoop.max_runtime_secs (0 = unlimited) vs MonitorBudgets.max_runtime_secs (zero forbidden), plus idle_secs=60 vs cadence_secs=300. Deliberately different semantics, but both must stay coherent forever.
  • The redaction sink (item 6) is absent from the PR description; it is derived from the external-content boundary, though no live payload can reach it yet.

Subtractions

  • Defer src/kiro_crew/monitoring/decision.py (decide_monitor, MonitorDecision, ProviderErrorKind, _RETRYABLE_PROVIDER_ERRORS) to the stack slice that calls it — 0 consumers, no persisted bytes depend on it, freely re-addable.
  • Shrink MonitorOutcome to the variants v1 records can actually contain (BLOCKED) until the controller slice constructs the rest — 5 unconstructed variants counted.

[FIRST-PRINCIPLES-REVIEWED] 0580ec4

@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review — ✅ no blocking findings

Reviewed 0580ec47c97366a798da2e6eb110efa8c180fe07 — this comment is updated in place on each push.

Review details

No findings.

[OPUS-REVIEWED] 0580ec4

Verdict parsed from the review's SHA-scoped output markers for commit 0580ec47c97366a798da2e6eb110efa8c180fe07.

False positive or not applicable? A repository writer can comment:
/ai-review override fable 0580ec47c97366a798da2e6eb110efa8c180fe07: <one-sentence reason>

@kyleseaman
kyleseaman force-pushed the token-monitors-core branch 2 times, most recently from b37f9f7 to e1a0cc9 Compare August 23, 2026 15:55
@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Aug 23, 2026
@kyleseaman
kyleseaman force-pushed the token-monitors-core branch from e1a0cc9 to bea09c9 Compare August 23, 2026 16:17
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Aug 23, 2026
@kyleseaman
kyleseaman force-pushed the token-monitors-core branch from bea09c9 to 8d00704 Compare August 23, 2026 16:23
@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Aug 23, 2026
@kyleseaman
kyleseaman force-pushed the token-monitors-core branch from 8d00704 to 123417e Compare August 23, 2026 17:05
@kyleseaman
kyleseaman force-pushed the token-monitors-core branch from 123417e to d7dd7f8 Compare August 23, 2026 17:41
@github-actions github-actions Bot added the readiness: action required A blocking check or review needs attention label Aug 24, 2026
@kyleseaman
kyleseaman force-pushed the token-monitors-core branch from c8ef8f4 to 9d900b2 Compare August 24, 2026 11:15
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Aug 24, 2026
Base automatically changed from token-monitors-rfc to main August 25, 2026 09:04
@bolichen97
bolichen97 force-pushed the token-monitors-core branch from 9d900b2 to 32fd49a Compare August 25, 2026 09:04
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Aug 25, 2026
@kyleseaman
kyleseaman marked this pull request as ready for review August 25, 2026 13:29
@kyleseaman
kyleseaman requested a review from a team as a code owner August 25, 2026 13:29
@kyleseaman
kyleseaman requested a review from buluoray August 25, 2026 13:29
@github-actions github-actions Bot added the merge conflict Branch has merge conflicts with its base — author must resolve before merge label Aug 25, 2026
@kyleseaman
kyleseaman force-pushed the token-monitors-core branch from 32fd49a to dc52ea6 Compare August 25, 2026 16:45
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention merge conflict Branch has merge conflicts with its base — author must resolve before merge readiness: checking Automated validation is still running labels Aug 25, 2026
@kyleseaman
kyleseaman force-pushed the token-monitors-core branch from dc52ea6 to dd7be11 Compare August 25, 2026 16:57
bolichen97
bolichen97 previously approved these changes Aug 27, 2026

@bolichen97 bolichen97 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

bolichen97
bolichen97 previously approved these changes Aug 28, 2026
@kyleseaman

Copy link
Copy Markdown
Collaborator Author

Resolved the new conflict with current main by preserving both redaction-sink registry entries, then restacked all seven open descendants bottom-up with explicit leases. Focused verification passed locally (2,547 stack-related backend tests, 42 security-posture tests, 1,239 frontend tests, TypeScript, targeted ESLint, formatting, and docs lint). Fresh CI was triggered only by the necessary branch pushes.

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.

2 participants