Repository navigation
Commit e8b779c
authored
fix(daemon): keep close-time script-save failures from leaking the session/device claim (#1392)
* fix(daemon): keep close-time script-save failures from leaking the session/device claim
A close-time script write (implicit from `open --save-script`, or this
close's own `--save-script`) that refuses to publish (e.g. a no-clobber
target-exists AppError) threw uncaught out of `handleCloseCommand`,
skipping lease release, device-claim release, and `sessionStore.delete`
entirely — while the `close` action had already been recorded with no
rollback.
Live-repro'd over the real CLI against an Android emulator: this single
gap explained both symptoms split out of #1384 into #1391 — a lingering
`DEVICE_IN_USE` claim after a failed `close`, and a published `.ad`
rewritten with duplicated trailing `close` lines when the same close was
retried (each attempt re-recorded a `close` action on top of the one
never rolled back from the prior failure).
Catch the write failure, roll back the just-recorded `close` action
(mirroring the existing repair-armed commit-failure pattern), and let
teardown (lease release, device-claim clear, session delete) complete
regardless — exactly as an ordinary platform-close failure already
doesn't block them. The failure is still surfaced to the caller, but
after teardown, with a corrected hint: retrying the same close is no
longer meaningful since the session is now gone.
Fixes #1391
* refactor(daemon): shrink handleCloseCommand/runSessionCloseTeardown under fallow's complexity gate
CI's fallow code-quality check flagged handleCloseCommand (126 lines,
19 cyclomatic / 16 cognitive) and runSessionCloseTeardown (73 lines) as
exceeding the large-function/high-complexity thresholds after the
prior commit's fix.
Extract runCloseTeardownAndRelease (teardown + lease release + claim
clear + delete + ordered error surfacing) and buildCloseSuccessResponse
(final response shaping) out of handleCloseCommand, and
finalizeOrdinaryCloseScript out of runSessionCloseTeardown. No behavior
change — same control flow, split into named, independently-readable
steps; fallow now reports 0 complexity findings for this diff.
* fix(daemon): preserve the write error's structured details in the close-time save failure
Review feedback on #1392 (thymikee): toOrdinaryCloseSaveScriptFailure
rebuilt the AppError from only the original message, dropping its
machine-readable details.reason ("script_target_exists"), details.path,
and cause. A caller dispatching on those fields (or reading the CLI's
--json error.details) lost them even though the underlying write
failure carried them.
Preserve the original error's details/cause, overriding only the
close-specific hint and retriable:false. Extends the #1391 regression
test to assert the routed close response still carries reason/path.
* refactor(daemon): drop the vestigial close-time rollback, add router-level #1391 coverage
Review feedback on #1392 (thymikee), P2 items:
- The close-time save-script failure's session.actions rollback
(finalizeOrdinaryCloseScript) was left over from an earlier design
where a failed save could keep the session alive for retry. It
never does now — runCloseTeardownAndRelease always tears the
session down regardless of the outcome — so there is no surviving
session for a later write to duplicate the close action on. Drop
the rollback; the durable events.ndjson entry (which the rollback
never touched anyway) and the in-memory action now agree, both
accurately recording that the close happened.
- Add a request-router-level regression (request-router-typed-error.test.ts,
alongside the existing repair-close BLOCKER 2 test it mirrors) proving
the normalized JSON error shape a real client sees: top-level
retriable:false, details.reason/path preserved, and the session torn
down — not just that handleCloseCommand throws the right AppError
when called directly.
* test(daemon): assert the durable close event survives a failed close-time save
Review feedback on #1392 (thymikee), final P2 item: the previous commit
removed the actions rollback because there's no surviving session to
duplicate the close action on, but nothing actually asserted the
durable events.ndjson action.recorded:close event stays put. Flush and
read it back so a future rollback or event-order change can't silently
recreate the in-memory/durable mismatch the removed rollback used to
paper over asymmetrically.
* test(daemon): assert the retained session's in-memory close action, not just the durable event
Review feedback on #1392 (thymikee): the durable-event assertion alone
doesn't catch a reintroduced session.actions.length = actionsBeforeClose
rollback, because that event is queued (and durable) before the write
even attempts — a regression there would leave the assertion passing
while silently reintroducing the in-memory/durable mismatch.
Retain the session object past handleCloseCommand (store.delete only
drops the map entry, not the object a local variable still points at)
and assert its actions array contains exactly one close entry, matching
the durable event count. Verified by temporarily reintroducing the old
rollback locally: this assertion fails (0 !== 1) where the prior
durable-only check did not, then reverted.
* refactor(daemon): model repair close retry as receipt
* refactor(daemon): merge blockingError to state, not explain, the save-script exclusion
Following up on the comment-trimming pass already on this branch: the
device-claim condition (!platformCloseError && !cleanupAggregate) and
the two-line throw sequence right below it both needed a paragraph
explaining why saveScriptError is excluded from one but not the other.
Merge platformCloseError and cleanupAggregate into a single named
blockingError — its name now states the exclusion the comment used to
argue for, and the throw sequence collapses from two ifs to one.
Trimmed the remaining long docblocks in this file the same way: state
what's non-obvious in 1-3 lines instead of re-deriving it in prose.
* refactor(daemon): clarify close script finalization1 parent a798976 commit e8b779c
10 files changed
Lines changed: 474 additions & 279 deletions
File tree
- scripts
- layering
- src/daemon
- __tests__
- handlers
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
155 | 155 | | |
156 | 156 | | |
157 | 157 | | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
158 | 193 | | |
159 | 194 | | |
160 | 195 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
60 | | - | |
| 60 | + | |
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
| |||
81 | 81 | | |
82 | 82 | | |
83 | 83 | | |
84 | | - | |
85 | | - | |
| 84 | + | |
86 | 85 | | |
87 | 86 | | |
88 | 87 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
167 | 168 | | |
168 | 169 | | |
169 | 170 | | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| 38 | + | |
| 39 | + | |
38 | 40 | | |
39 | 41 | | |
40 | 42 | | |
| |||
245 | 247 | | |
246 | 248 | | |
247 | 249 | | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
984 | 984 | | |
985 | 985 | | |
986 | 986 | | |
987 | | - | |
| 987 | + | |
988 | 988 | | |
989 | 989 | | |
990 | 990 | | |
| |||
1043 | 1043 | | |
1044 | 1044 | | |
1045 | 1045 | | |
1046 | | - | |
1047 | | - | |
1048 | | - | |
1049 | | - | |
1050 | | - | |
1051 | | - | |
1052 | | - | |
1053 | | - | |
1054 | 1046 | | |
1055 | 1047 | | |
1056 | 1048 | | |
| |||
1078 | 1070 | | |
1079 | 1071 | | |
1080 | 1072 | | |
1081 | | - | |
1082 | | - | |
1083 | | - | |
1084 | 1073 | | |
1085 | 1074 | | |
1086 | 1075 | | |
| |||
1126 | 1115 | | |
1127 | 1116 | | |
1128 | 1117 | | |
1129 | | - | |
| 1118 | + | |
1130 | 1119 | | |
1131 | 1120 | | |
1132 | 1121 | | |
| |||
0 commit comments