refactor(monitoring): remove duplicated logic and unreachable branches - #9026
Conversation
Design Review (Fable 5) — ✅ PASSDesign-level review of All claims verified: the collapsed except clauses are order-equivalent (SetupError is Design-Verdict: PASS Deduplication targets the actual drift risk (two copies of terminal-outcome policy), ownership lands in the right modules, and equivalence was differentially proven. [DESIGN-REVIEWED] b9c6f77 |
First Principles Review (Fable 5) — 🟡 CONCERNSPremise-level review of All checks complete. I verified the unreachability claims (the first statement of First-Principles-Verdict: CONCERNS Pure subtraction, every claim verified — but one drifted inline copy of the very predicate this PR deduplicates survives in What this change shipsIntent: make
WatchThe description says "the module's three other users of that check call the helper" — I count a fourth inline copy: Subtractions
[FIRST-PRINCIPLES-REVIEWED] b9c6f77 |
GPT 5.6 Review — ✅ no blocking findingsGPT 5.6 completed its review of This comment is updated in place on each push. Review detailsNo findings. False positive or not applicable? A repository writer can comment: |
Opus 4.8 Review — ✅ no blocking findingsReviewed Review detailsAll four changes verify as behavior-preserving refactors:
Nothing survives falsification, and I found no grounded new defect. No findings. [OPUS-REVIEWED] b9c6f77 Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
Behaviour-preserving readability pass over src/kiro_crew/monitoring/. Five sites where the module said the same thing twice, or kept a branch that could not run: - shadow.py's _decision_for_outcome was a line-for-line copy of decision.py's _terminal_decision. The latter is promoted to terminal_decision_for_outcome and shared; the copy is deleted. - shadow.py's eight-line inline `now` validation reimplemented models.py's finite-non-negative predicate, which is promoted to is_finite_non_negative_number and reused. The module's three other call sites already used it, so shadow.py was the outlier. - probe()'s four except clauses each rebuilt the classification that _provider_exception_kind already performs. They collapse to one clause delegating to it. - _review_threads returned the identical tuple from inside the loop on its last iteration and again after it. The in-loop copy is removed. - _classify_cli_error tested three rate-limit markers that its own first statement had already returned on. Only "http 429" is reachable there. - monitor_state_from_dict assigned outcome=None in an else branch, which is the dataclass default and is what its four sibling handlers already rely on. Comments touched here are corrected against the code rather than restated: the docstrings now name the reachable OverflowError input, say what SETUP actually costs downstream, and stop claiming a parity with the delivery controller that autonudge does not have. One observable delta, deliberate: shadow.py no longer chains the swallowed OverflowError as __cause__. Type and message are unchanged, and the three pre-existing users of the same predicate never chained either.
7b6ae1d to
b9c6f77
Compare
Legitimate on both clauses, and verified against the code rather than accepted on The rate-limit clause was wrong for a second reason worth recording, since it is the Both comments now say so. Since this PR's purpose is partly to make these comments |
|
Correct, and reproduced rather than taken on assertion. On this head:
Deferred, on the reviewer's own grounds: the fix changes the raised exception type, The completeness claim is corrected rather than left standing. The PR body no longer |
dwu96
left a comment
There was a problem hiding this comment.
Tier 1 auto-approve: refactor (4 files). Criteria: no conflict, no requested changes, security path denylist clean, design-doc gate clean, SAST annotations clean, security checklist all-NO, AI reviewers green. Category: duplicate-helper consolidation (terminal_decision_for_outcome shared by decision.py and shadow.py, _provider_exception_error collapsing four except arms onto the existing _provider_exception_kind, is_finite_non_negative_number reused in shadow.py) plus removal of an unreachable rate-limit marker branch already returned by the top-of-function check and a redundant outcome=None assignment matching the dataclass default - verified behaviour-preserving against the head source, no runtime semantics change.
Problem / Motivation
src/kiro_crew/monitoring/says the same thing twice in several places, and keepstwo branches that cannot run. None of it is a bug — it is friction for the next
reader, and in two cases the duplication is the kind that drifts:
shadow.py's_decision_for_outcomeis a line-for-line copy ofdecision.py's_terminal_decision. Two copies of a terminal-outcome policy inone module is one edit away from the two paths disagreeing.
shadow.pyreimplementsmodels.py's finite/non-negative number check inline ineight lines, while three of the module's other users of that check call the helper.
A fourth inline copy remains in
MonitorActionCompletion.__post_init__and hasalready drifted — see "Known remaining copy" below.
probe()'s fourexceptclauses each rebuild, by hand, the classification that_provider_exception_kind— fifteen lines below, already called from two othersites in the same class — performs.
_review_threadsreturns the identical tuple from inside its loop on the lastiteration and again immediately after it.
_classify_cli_errorre-tests three rate-limit markers that its own firststatement has already returned on.
monitor_state_from_dictwritesoutcome = Nonein anelsebranch; that is thedataclass default, and its four sibling decoders already rely on it.
Why it matters
Duplicated policy is a correctness risk, not a style one: whoever fixes the
terminal-outcome mapping or the exception classification will find one copy and
leave the other. The unreachable branches cost differently — they make a reader
reason about a case that cannot occur, and in
_classify_cli_errorthey activelymislead, because reading it suggests the second block is what catches rate limits
when the first block already did.
What changed (motivation → approach → change)
Behaviour-preserving throughout. Six sites, four files, no test changes:
shadow.py_decision_for_outcomedeleted;decision.py's twin promoted toterminal_decision_for_outcomeand sharedshadow.pynowvalidation →is_finite_non_negative_number(promoted frommodels.py); drops the now-unusedimport mathgithub_pull_request.pyprobe()'s fourexceptclauses → one clause delegating to a new_provider_exception_error, which wraps the pre-existing_provider_exception_kindgithub_pull_request.py_review_threads: in-loop duplicate of the post-loopreturndeleted; the orphaned loop variable becomes_github_pull_request.py_classify_cli_error: the second rate-limit block narrowed to its only reachable marker,"http 429"models.pymonitor_state_from_dict: redundantelse: values["outcome"] = NonedeletedTwo private helpers became public because a second module in the same package now
uses them. That is the whole extent of the API change: no
__all__exists in thispackage, and no spec or doc names either symbol.
Comments in the files touched were corrected against the code, not merely
restated (three of them were wrong):
is_finite_non_negative_numbernow names the input that actually reaches itsexcept OverflowError— anintoutside float range, which is whattest_monitor_persistence.pyandtest_github_pull_request_monitor.pyalreadyexercise with
10**400. The example first written there,Decimal('Infinity'),is rejected by the preceding
isinstanceguard and does not raise anyway._provider_exception_errorsays what the TRANSIENT/SETUP split actually costs:TRANSIENT becomes
RETRY_PROVIDER, SETUP is unretryable and retires the monitor(
STOP_BLOCKED, outcomeBLOCKED). It also states plainly that only the reasonstring falls back, so a future third kind needs its own reason rather than
being stamped
"provider_setup".terminal_decision_for_outcomedoes not claim parity with the deliverycontroller. It has none:
autonudge'sapply_monitor_proberefuses a monitorwith a recorded outcome before
decide_monitorruns, flattening every terminaloutcome to
STOP_BLOCKED, sooutcome=SUCCESSyieldsSTOP_SUCCESSon theshadow path and
STOP_BLOCKEDon the delivery path. Documenting the divergence isthe point — a reader who believed the parity claim would "fix" the shadow path.
models.py'squiet_tickscomment loses an incident anecdote and a PR-scopedaside (
AGENTS.mdforbids both in code comments); every constraint it carried isretained.
Known remaining copy — deliberately not fixed here
grep math.isfinite src/kiro_crew/monitoring/leaves exactly one non-helper hit afterthis PR:
models.py:187, insideMonitorActionCompletion.__post_init__. It is a fourthinline copy of the same predicate and it has already drifted in the way this PR's
premise predicts — it omits the
OverflowErrorguard, so:It is left alone because replacing it changes the raised exception type, and this PR
is behaviour-preserving by contract. Tracked as #9045 with the repro, the one-line fix and
the regression test. Raised by
First Principles Review; deferral agreed on those grounds.One observable delta, disclosed deliberately
shadow.pyno longer chains the swallowedOverflowErroras__cause__on thenowvalidation, because the shared predicate returns a bool and has nothing tochain from. Exception type and message are unchanged, no test asserts on
__cause__, and the three pre-existing callers of that same predicate — includingMonitorState.__post_init__— never chained either, so this makesshadow.pyconsistent with its module rather than divergent. Reachable only by a caller passing
an out-of-float-range
int, which is rejected identically either way. Say the wordand I will drop that one hunk.
Overlap with in-flight work
Three open PRs touch these files: #5305 (
github_pull_request.py,models.py),#5185 (
models.py,shadow.py), #5186 (models.py). None deletes orrewrites a function this PR changes, so the file-overlap bar is not met — but #5305
inserts a
returnimmediately above theexcept SetupErrorline this PR removes,so that one adjacency will conflict. This PR should rebase behind them, not the
reverse: a readability change should absorb the conflict, never charge it to a
feature.
Tests
None added or changed — a behaviour-preserving refactor of covered code should move
no assertion. Instead, each rewrite was proven equivalent before it was kept:
exceptclauses were differentially executed old-vs-new over57 constructed exceptions (7 errno values × 7
OSErrorsubclasses,TimeoutExpired, andSetupErrorwith 6 different__cause__values): zerodivergences in the resulting
(kind, reason_code).SetupErrorisRuntimeError-derived andTimeoutExpiredisSubprocessError-derived, so theonly subtype relation among the four is
FileNotFoundError ⊂ OSError— and_provider_exception_kindtestsFileNotFoundErrorahead of theOSErrorbranch, exactly as the old clause order did.
concatenation of 27 adversarial markers under 4 separators, plus 200,000 random
strings: zero divergences.
_review_threadswas run against a stub runner on both versions: the page-capcase returns
(10, False, None)after 10 runner calls in both, the early-exitcase
(3, True, None)after 3 in both.outcomedeletion was checked for a missing key, an explicitnull, and areal value, comparing
state.outcome,monitor_state_to_dict,monitor_state_public_dictandasdict: identical in all three.shadow._decision_for_outcomewas diffed againstdecision.terminal_decision_for_outcomefromorigin/main: line-for-lineidentical bodies.
2,230 passed, 1 skipped across every test module that imports
monitoring.(22 files) plus
test_monitor_mcp.pyandtest_monitor_start_ack.py, re-run afterthe rebase onto
5767e0d9c.Manual verification
N/A — unit coverage sufficient: the change is confined to pure functions and
exception classification that the 2,230 tests above already cover, and no runtime
surface, wire format, or persisted field changes.
Screenshots / video
Why no screenshot: backend-only refactor under
src/kiro_crew/monitoring/; nofrontend file, rendered output, or user-visible string changes.
Related Issues
no linked issue: routine readability sweep of one backend module, not a tracked defect.
Checklist
learn-cron-dashboard.mddocuments this module's behaviour, which is unchanged, and names none of the touched symbols