C5F P5 Option A: C5DEngine.apply_commit() uebernimmt einen extern
bereits vollstaendig korrekt rebuildeten Suchzustand bei UPDATING_SEARCH
idempotent (ADOPT_ALREADY_AT_TARGET) ohne zweiten Rebuild.
- Neues evaluate_external_adoption(): read-only, exakte Set-Gleichheit
(ids, paths, count, source_head), kein object_count-only shortcut
- apply_commit(): UPDATING_SEARCH -> Adoption-Check -> bei exaktem Match
direkt VERIFYING_SEARCH ohne rebuild() -> verify -> APPLIED
- Neuer Report-Feld 'adoption' mit Status + rebuild_count
- Testsuite test_c5d_adoption.py (Faelle A-O, 15 Tests)
Kein zweiter Rebuild, kein manueller State-Set, kein Tolaria-/Forgejo-Write.
C5F canary commit parked in PROPAGATING_TOLARIA with objects already written
to Tolaria (real write before crash). C5EEngine.replay() delegates the pending
case to propagate_commit, whose entry guard only accepted READY/RETRY_PENDING,
so the commit could never resume past the crash window and the ALREADY_AT_TARGET
idempotency (pre_write_drift_check) was never reached.
Minimal fix: accept PROPAGATING_TOLARIA as a resume entry state (idempotency
still determined per-object via pre_write_drift_check -> no double write; read-back
verify() remains the mandatory gate) and skip the READY->PROPAGATING_TOLARIA
transition on resume (no self-transition entry exists in _ALLOWED_TRANSITIONS).
Adds 2 regression tests covering the crash-window resume (already-at-target and
pending-create). Full C5A-E suite: 190 tests, 0 failures.
FRESH CHECKER-VERDICT (deleg_3ea8ed5a): FAIL.
Defekt: rq_c5e.py Replay 'alle Objekte bereits propagated' rief
transition_commit(ST_UPDATING_SEARCH) aus PROPAGATING_TOLARIA/READY direkt auf,
was InvalidTransitionError warf (Transition nicht in _ALLOWED_TRANSITIONS).
Reparatur (invarianten-treu): statt den VERIFYING_TOLARIA-Schritt zu ueberspringen
(wuerde Read-Back/DRIFT-Check verletzen), wird der formale State-Pfad
READY->PROPAGATING->VERIFYING->UPDATING_SEARCH durchlaufen. Nutzt nur bereits
erlaubte Transitions; keine _ALLOWED_TRANSITIONS-Aenderung, kein C5A/C5C-Risiko.
Kein Tolaria-Doppel-Write (prop_calls=0), kein verfrühter Search (search_calls=0).
+ 2 Regressionstests (test_c5e.py): crash-window + ready-edge-case.
Volle Suite: C5A 25/0 + B/C/D/E 170/0 = 195 OK. Guarantees true.
- C5A objects table: object_id nullable + reason_code column so HUMAN_REVIEW/
SECRET_DETECTED object changes (object_id=None) are persisted, not silently
dropped (was: object_id TEXT NOT NULL, no reason_code field)
- C5B poll_once: content_before now read from parent_sha (state BEFORE the
change) instead of sha, so MODIFIED changes classify as CONTENT_UPDATE
instead of being misclassified (Checker-Befund)
- test_c5b: add test_modified_content_reads_parent regression test
C5B 40/40, C5A 25/25, real-repo dry run: 233 object changes (109 IN_SCOPE
with valid id, 124 HUMAN_REVIEW), idempotent.
server.py resolved SOURCE_JSON to ../c4a_evidence/index_source.json which does not exist in the deployed container. The C4B service ships index_source.json in its own directory. Fix resolves robustly relative to the service root.