Skip to content

fix(core): the cleanup reaper finishes its run when one action fails - #664

Merged
V3RON merged 3 commits into
mainfrom
bug/659
Oct 17, 2026
Merged

V3RON merged 3 commits into
mainfrom
bug/659

Conversation

@V3RON

@V3RON V3RON commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Closes #659

Status

Implement: done (14/14 reaper file, 1222/1222 src/core, 4379/4379 pnpm test:changed; probes 2/2) Review: round 1, 0 blocking, 0 fixed unreviewed, 0 notes Hardware: n/a Gate: merged (7bbc22e)
Next: none

Done when

  • One action that throws inside the reaper's loop is contained, logged, and the run continues, so every proposal after a device whose platform has no driver is still executed, for both the idle-shutdown and the idle-destroy verb — the carried repro (src/core/reaper.test.ts, both verbs in one run)
  • A run-level failure (a rule or the registry view that throws) still rejects the run — "A cleanup run that throws logs at error." and "a cleanup run that throws is logged once, however many triggers joined it"
  • The fix adds no third hasDriver filter and duplicates no skip predicate — the catch is at execute; nothing was added to #view()

Probes run on the final head, each reverted after:

  • Revert (the bare await restored): the repro reds on its own named assertion — promise rejected "NoDriverError: No driver registered for platform: android" … at CleanupReaper.#runOnce, and the log test reds on its resolve assertion.
  • Over-catch (the catch widened around the whole pass): both run-level tests above red on their log assertions, so they are live and the catch sits at execute, not around the pass.

New path and its test (strict area): the catch adds one path, the cleanup action failed line, proven by "logs a cleanup action that throws at error, naming the action, rule and target, and still resolves the run". The repro covers the continue side for both verbs.

Assumptions

  • Assumption: exit status of simlock cleanup with a failed action — it now exits 0 with the failure only in an error log; this follows from the fault isolation the triage chose and no doc says otherwise. docs/CLI.md's cleanup section and its exit-code table name no failure for a command whose run completes, NO_DRIVER (12) stays true of the commands that still surface it, and no e2e or client test pins a throwing cleanup.run.

For #660: NukeService.#runNuke has the same loop with the same missing catch; the shape here (catch at execute, log, continue) factors to it, but its spec decides its own fix and this PR does not touch it.

Review

Spec review: 0 blocking, 0 fixed, 0 notes. Code review: 0 blocking, 0 fixed, 0 notes. Claims review: 0 blocking, 0 fixed, 0 notes.
Rounds: 1. Tokens: n/a.

Nothing was rejected, so nothing is listed. Round 1 confirmed no src finding, so round 2 and the fix check did not run (rule 14).

Kind full, so all three reviews ran; the code reviewer with lens: both in its own worktree of cffd92ee. Inputs came from .agents/scripts/review-inputs.sh 664 (rules, ADRs and briefs from main).

How the reviews were spawned: this session sits at subagent depth and the harness refused nested spawns, as on #643, #644, #646, #649, #650 and #661. Each reviewer ran as a fresh detached claude -p session — the body of .claude/agents/<reviewer>.md as its system prompt, its model from that file's frontmatter — reading only the inputs directory and its own worktree of the reviewed commit, with no PR body, commit messages or another reviewer's output; each read .agents/briefs/calibration.md first. Nothing was reviewed by the agent that wrote the code.

Written by an agent.

@V3RON
V3RON marked this pull request as ready for review October 17, 2026 10:21
@V3RON
V3RON merged commit 7bbc22e into main Oct 17, 2026
63 checks passed
@V3RON
V3RON deleted the bug/659 branch October 17, 2026 10:22
V3RON added a commit that referenced this pull request Oct 17, 2026
…668)

Closes #660

### Status

Implement: done (8/8 in `nuke-service.test.ts`; `pnpm test:changed` 4387
passed) Review: round 1, 0 open Hardware: n/a Gate: running
Next: gate result

## What is this?

`simlock nuke` stopped at the first device whose platform has no driver:
`NoDriverError` escaped the reset loop, every device after it stayed
booted, and the command reported failure. One device that cannot be
reset is now logged and the reset goes on.

## How does it work?

`NukeService.#runNuke` catches around the per-device `#resetDevice` call
only — the inline shape #664 landed in the cleanup reaper, no shared
helper. A maintenance or release-all failure still rejects the run, and
the `finally` still reopens admission. `NukeService` had no logger; it
takes an optional one now, wired where `create-core.ts` builds it, and
the device it could not reset is logged at error with its id, platform
and error.

## Done when

- [x] The reset does not abort on a device whose platform has no driver
and still resets every device after it — the triage reproduction,
carried unchanged from `bug/660-repro`, is green: both driverless
records are passed over and the healthy device after each ends
`deleted`, across both verbs. Reverting the catch reddens it on
`NoDriverError`.
- [x] The new branch has its own path test, as a strict area needs —
"logs a device it cannot reset at error, naming the device, platform and
error". Deleting the log line reddens that test alone.
- [x] A maintenance or release-all throw still rejects the run —
"reopens admission even when reset work fails" is untouched and live:
widening the catch over the whole loop reddens it.

`src/core/AGENTS.md`'s Nuke item states the isolation and stays within
its 150-line budget. No end-user doc claimed `nuke` fails when one
device cannot be reached, so none changed; no event changed.

## Assumptions

- Assumption: exit status of `simlock nuke` with a device it could not
reach — it now exits 0 with the failure only in an error log; this
follows from the fault isolation the triage chose and no doc says
otherwise. `docs/CLI.md`'s nuke section and exit-code table checked:
neither states that nuke fails when one device cannot be reached.

## Review

Spec review: 0 blocking, 0 fixed, 1 note. Code review: 0 blocking, 0
fixed, 0 notes. Claims review: 0 blocking, 0 fixed, 0 notes.
Rounds: 1. Tokens: n/a.

Kind `full`, so all three reviews ran; the code reviewer with `lens:
both` in its own worktree of `d54b86b5`. Inputs came from
`.agents/scripts/review-inputs.sh 668` (rules, ADRs and briefs from
`main`), and the reviewers saw no PR body, no commit messages and none
another reviewer's output.

How the reviews were spawned: this session sits at subagent depth and
the harness refused nested spawns, as on #643, #644, #646, #649, #650
and #661. The `reviewer` agent ran instead as a fresh detached `claude
-p` session on `bug/660` — its definition from
`.claude/agents/reviewer.md`, its model from that file's frontmatter —
which spawned the three reviewers itself as its own fresh sub-agents,
each reading only the inputs directory and its own worktree of the
reviewed commit. Nothing was reviewed by the agent that wrote the code.

*Written by an agent.*
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.

The cleanup reaper aborts its whole run on a shutdown device whose platform has no driver

1 participant