Commit af8c279
committed
backup: #904 v15 - two codex P2 v14 fixes
## Codex P2 v14 (1/2): mismatch cleanup must not delete directories
v12 added os.Remove(cfg.outputPath) on the self-test-mismatch branch
of writeAndPublish to keep the sidecar+FSM internally consistent.
That removal was unconditional. If --output names a directory (an
operator typo — e.g. forgot the .fsm filename and passed a directory
instead), the normal publish path would have failed at os.Rename,
but the mismatch cleanup branch would silently call os.Remove on the
directory and, for an empty one, delete it. Destructive behavior
specific to the mismatch path.
Fix: new helper removeStaleOutputFSM(outputPath, logger) performs an
os.Lstat first and only proceeds with os.Remove when info.Mode()
reports IsRegular. Non-regular files (directory, symlink, named
pipe, etc.) are logged at warn level and left alone. Stat errors
other than ErrNotExist are also warn-and-continue.
Pinned by TestCLISelfTestMismatchSkipsDirectoryAtOutputPath: pre-
places an empty directory at --output, drives a self-test mismatch
via the corruption seam, asserts publishErr == errSelfTestMismatch
AND the directory is still present + still a directory.
## Codex P2 v14 (2/2): classify corrupt manifests as data failures
readInputManifest returns backup.ErrInvalidManifest (invalid JSON or
schema-invariant violation) and backup.ErrUnsupportedFormatVersion
(format_version unknown) when the input MANIFEST.json is broken.
Neither sentinel was mapped in run(), so the CLI exited 1 — treating
a broken dump tree as an operator-flag error and breaking runbook
recovery paths that branch on exit status to triage corrupt-input
vs operator-typo.
Fix: extracted the error→exit-code mapping into classifyEncodeError
and added ErrInvalidManifest + ErrUnsupportedFormatVersion to the
exit-2 set. Switch-with-multiple-cases form keeps the function under
nestif/cyclop.
Pinned by TestCLIInvalidManifestExitsTwo (subtests: invalid JSON
body; unsupported format_version). Both subtests assert run() exits
exitDataErr.
## Caller audit per CLAUDE.md semantic-change rule
- writeAndPublish self-test mismatch branch: os.Remove call replaced
with removeStaleOutputFSM. Sole caller is encodeOne; the
publishErr contract is unchanged (still errSelfTestMismatch);
on-disk state changes ONLY when --output was a non-regular file,
in which case the prior behavior was destructive AND wrong.
No legitimate caller is impacted.
- run() error classification: extracted to classifyEncodeError.
Sole caller is run(). Two additional sentinels now classify as
exit-2 (ErrInvalidManifest, ErrUnsupportedFormatVersion); all
prior exit-2 sentinels still classify as exit-2; exit-1 paths
are strictly a subset of the prior set. No runbook that
branches on exit-2 would regress; runbooks that branch on
exit-1 will see corrupt-manifest cases move to exit-2 where
they belong.
## Lint compliance
run() had nestif complexity 5 (six sequential errors.Is branches).
classifyEncodeError uses a switch with multiple errors.Is cases per
arm, which drops the complexity score below the linter bound.
Tests + lint green.1 parent 71ecc12 commit af8c279
2 files changed
Lines changed: 190 additions & 28 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
81 | 81 | | |
82 | 82 | | |
83 | 83 | | |
84 | | - | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | | - | |
99 | | - | |
100 | | - | |
101 | | - | |
102 | | - | |
| 84 | + | |
103 | 85 | | |
104 | 86 | | |
105 | 87 | | |
106 | 88 | | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
107 | 120 | | |
108 | 121 | | |
109 | 122 | | |
| |||
312 | 325 | | |
313 | 326 | | |
314 | 327 | | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
315 | 352 | | |
316 | 353 | | |
317 | 354 | | |
| |||
338 | 375 | | |
339 | 376 | | |
340 | 377 | | |
341 | | - | |
342 | | - | |
343 | | - | |
344 | | - | |
345 | | - | |
346 | | - | |
347 | | - | |
348 | | - | |
349 | | - | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
350 | 392 | | |
351 | 393 | | |
352 | 394 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
304 | 304 | | |
305 | 305 | | |
306 | 306 | | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
307 | 427 | | |
308 | 428 | | |
309 | 429 | | |
| |||
0 commit comments