Commit 5a2f214
committed
backup: #904 v12 - remove stale .fsm on self-test mismatch
## Codex P2 v10: self-test mismatch leaves orphaned stale .fsm
When --output already exists from a prior successful run and the new
--self-test invocation detects a mismatch, writeAndPublish returned
errSelfTestMismatch without removing the stale <output>.fsm. encodeOne
then wrote a fresh <output>.encode_info.json with self_test.matched=false
and the NEW SHA pointing to the unpublished temp snapshot, leaving:
- <output>.fsm: STALE bytes from the prior successful run
- <output>.encode_info.json: NEW SHA + matched=false
- <output>.mismatch.txt: from the new run
The sidecar describes an FSM that does not exist on disk. This
violates the CLI contract that "a self-test failure leaves no
restore-visible FSM" and breaks runbooks that consume the sidecar's
SHA to verify FSM integrity (they would find the stale FSM's SHA
does not match the sidecar's NEW SHA).
Fix: writeAndPublish, on the self-test-mismatch branch, now
os.Remove(cfg.outputPath) before returning. After cleanup the
artifacts are internally consistent: the sidecar describes a FAILED
encode attempt, mismatch.txt has the diff, and the FSM path is
absent (matching the sidecar's intent).
errors.Is(rerr, os.ErrNotExist) is treated as success — a
self-test mismatch from a first-ever encode (no prior FSM) leaves
the path absent, which is the same end state.
## Surgical scope — only self-test mismatch wipes stale .fsm
Other exit-2 paths (manifest-floor regression, adapter-data error,
unsupported DDB layout) preserve any prior <output>.fsm because
those failures occur BEFORE writeAndPublish runs. This preserves
the runbook ergonomic of "operator typo'd --last-commit-ts; last
good FSM still on disk to retry against."
## Test infrastructure
To drive a deterministic self-test mismatch end-to-end through the
CLI's writeAndPublish, a minimal test seam was added to package
backup: EncodeOptions.SetSelfTestCorruptHookForTest(func(*os.File))
exposes the previously-package-private corruptBufferForTest field
to callers outside package backup. Production code MUST NOT call
this; the godoc explicitly names cmd/elastickv-snapshot-encode tests
as the sole intended caller.
Pinned by:
- TestCLIWriteAndPublishRemovesStaleFSMOnSelfTestMismatch: pre-places
a stale .fsm, injects corruption via the new seam, asserts
publishErr == errSelfTestMismatch, the stale .fsm is GONE, and
mismatch.txt is present.
- TestCLINonSelfTestExitTwoPreservesPriorFSM: pre-places a stale
.fsm, drives a manifest-floor regression (exit-2 BEFORE
writeAndPublish), asserts the stale .fsm is byte-for-byte
preserved. Pins the surgical scope of the cleanup.
## Caller audit per CLAUDE.md semantic-change rule
- writeAndPublish: sole production caller is encodeOne. On self-test
mismatch, encodeOne still writes the sidecar (publishErr matches
errSelfTestMismatch) and returns publishErr. The new os.Remove
happens before that, so the caller sees IDENTICAL error semantics
and the same sidecar-write path. The only difference is on-disk
state for <output>.fsm: was stale, is now absent.
- EncodeOptions.SetSelfTestCorruptHookForTest: new exported method.
No production callers anywhere; one test caller in
cmd/elastickv-snapshot-encode/main_test.go. In-package backup
tests continue to set corruptBufferForTest directly.
Tests + lint green.1 parent f075610 commit 5a2f214
3 files changed
Lines changed: 150 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
335 | 335 | | |
336 | 336 | | |
337 | 337 | | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
338 | 348 | | |
339 | 349 | | |
340 | 350 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
300 | 301 | | |
301 | 302 | | |
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 | + | |
| 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 | + | |
| 427 | + | |
303 | 428 | | |
304 | 429 | | |
305 | 430 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
135 | 135 | | |
136 | 136 | | |
137 | 137 | | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
138 | 153 | | |
139 | 154 | | |
140 | 155 | | |
| |||
0 commit comments