Commit b52a688
committed
backup: #904 v16 - correct v14 Redis multi-DB fan-out (codex P2 v14)
v14 added an enumerate-and-fan-out path for redis/db_<N>/ to address
codex P1 v13's silent-data-loss concern. Codex's v14 follow-up
clarified that the fan-out is itself incorrect, and two P2 findings
landed (L452 + L427).
## Codex P2 v14 L452: Reject Redis DB fan-out until DBs are encoded
The Redis MVCC key prefixes (!redis|str|, !redis|hll|, !redis|ttl|,
plus the collection helpers' analogues) carry NO database component.
Feeding two distinct DBs into the same snapshotBuilder would:
- collide on same-named keys across DBs (b.Add returns ErrDuplicate),
or
- merge keys under db_0 at decode time (DecodeOptions.RedisDBIndex
defaults to 0, so a db_3-only self-test would decode under db_0
and the structural diff would fail).
In either case the produced .fsm is mis-scoped: the v14 fan-out
replaces silent-data-loss with silent-merge-or-collide.
Fix: encodeAllRedisDBs now enumerates and decides:
- 0 indices (no redis/, or empty redis/) → no-op.
- [0] only → proceed with NewRedisEncoder(_, 0) (the legacy path).
- anything else → fail closed with new sentinel
ErrRedisEncodeMultiDBUnsupported.
The sentinel is marked at the runAdapterEncoders boundary with
ErrEncodeAdapterData so the CLI routes it to exit-2. Until Phase 1
makes native keys DB-aware, multi-DB inputs are quarantined as
data-correctness failures rather than silently mis-scoped output.
## Codex P2 v14 L427: Fail closed on malformed Redis db_N entries
The v14 parseRedisDBDir(ent) returned (_, false) whenever
!ent.IsDir(), so a regular file or symlink at redis/db_0 would be
silently skipped and the encoder would publish a header-only .fsm.
Fix: split into parseRedisDBName (pure name parser) and shift the
ent.IsDir() check into enumerateRedisDBs. When the name matches the
canonical db_<N> pattern AND the entry is not a directory,
enumerateRedisDBs returns ErrRedisEncodeNotDir (mirroring the per-DB
encoder's existing Lstat guard).
## Pinned by
- TestEncodeSnapshotRedisRejectsNonZeroDB: redis/db_3-only fixture
through EncodeSnapshot → errors.Is ErrRedisEncodeMultiDBUnsupported
AND errors.Is ErrEncodeAdapterData (both fire).
- TestEncodeSnapshotRedisRejectsMultipleDBs: redis/db_0 + redis/db_3
→ errors.Is ErrRedisEncodeMultiDBUnsupported.
- TestEnumerateRedisDBsRejectsNonDirDBEntry: redis/db_2 as a regular
file → errors.Is ErrRedisEncodeNotDir.
- The replaced TestEncodeSnapshotRedisMultiDB (v14) was reformulated
as TestEncodeSnapshotRedisRejectsNonZeroDB; the prior "more bytes
than baseline" assertion no longer holds because the encoder
rejects the fixture upfront.
## Caller audit per CLAUDE.md semantic-change rule
- encodeAllRedisDBs: sole caller is adapterRunners.redis. Semantic
change: was "fan out across all db_<N>"; now "encode db_0 only,
fail closed on anything else." Error contract:
- errors.Is(err, ErrEncodeAdapterData) — still true (mark applied
at runAdapterEncoders, unchanged).
- errors.Is(err, ErrRedisEncodeMultiDBUnsupported) — new path.
- errors.Is(err, ErrRedisEncodeNotDir) — newly reachable via
enumerateRedisDBs for malformed db_<N> entries.
All in-tree NewRedisEncoder direct callers (encode_redis_test.go,
encode_redis_coll_test.go, encode_redis_hardlink_unix_test.go) are
unaffected — they bypass the adapter runner.
- enumerateRedisDBs: was "silently skip non-dir db_<N>"; now "fail
closed with ErrRedisEncodeNotDir." No production callers exist
outside encodeAllRedisDBs; tests in encode_snapshot_test.go cover
the new fail-closed path.
- parseRedisDBDir → parseRedisDBName: signature change (DirEntry →
string). Sole caller is enumerateRedisDBs (updated in lock-step).
- v14's TestEncodeSnapshotRedisMultiDB is replaced — see above.
TestEnumerateRedisDBsMixedEntries (v14) continues to pass: its
positive entries (db_0, db_1, db_5) are all directories, so the
IsDir check it never exercises remains exercised by the new
TestEnumerateRedisDBsRejectsNonDirDBEntry.
Tests + lint green.1 parent af8c279 commit b52a688
2 files changed
Lines changed: 135 additions & 50 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
44 | 60 | | |
45 | 61 | | |
46 | 62 | | |
| |||
387 | 403 | | |
388 | 404 | | |
389 | 405 | | |
390 | | - | |
391 | | - | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
392 | 409 | | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
393 | 420 | | |
394 | 421 | | |
395 | 422 | | |
| |||
416 | 443 | | |
417 | 444 | | |
418 | 445 | | |
419 | | - | |
420 | | - | |
421 | | - | |
422 | | - | |
423 | | - | |
424 | | - | |
425 | | - | |
426 | | - | |
427 | | - | |
428 | | - | |
429 | | - | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
430 | 459 | | |
431 | 460 | | |
432 | 461 | | |
| |||
438 | 467 | | |
439 | 468 | | |
440 | 469 | | |
441 | | - | |
442 | | - | |
443 | | - | |
444 | | - | |
445 | | - | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
446 | 485 | | |
447 | 486 | | |
448 | 487 | | |
449 | 488 | | |
450 | 489 | | |
451 | | - | |
452 | | - | |
453 | | - | |
454 | | - | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
455 | 499 | | |
456 | 500 | | |
457 | 501 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
459 | 459 | | |
460 | 460 | | |
461 | 461 | | |
462 | | - | |
463 | | - | |
464 | | - | |
465 | | - | |
466 | | - | |
467 | | - | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
468 | 469 | | |
469 | | - | |
470 | | - | |
471 | | - | |
472 | | - | |
473 | | - | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
474 | 475 | | |
475 | | - | |
476 | | - | |
477 | | - | |
478 | | - | |
479 | | - | |
480 | | - | |
481 | | - | |
482 | | - | |
483 | | - | |
484 | | - | |
485 | | - | |
486 | 476 | | |
487 | 477 | | |
488 | 478 | | |
| |||
493 | 483 | | |
494 | 484 | | |
495 | 485 | | |
496 | | - | |
| 486 | + | |
497 | 487 | | |
498 | 488 | | |
499 | 489 | | |
500 | 490 | | |
501 | | - | |
502 | | - | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
503 | 514 | | |
504 | | - | |
505 | | - | |
506 | | - | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
507 | 548 | | |
508 | 549 | | |
509 | 550 | | |
| |||
0 commit comments