KB-57DE
dot-iu-cutter v0.1 — P0 Rollback Test Plan
14 min read Revision 1
dot-iu-cutterimplementation-planningrollback-testp0-3p0-4dot-pairno-executionno-ddlrev5d
dot-iu-cutter v0.1 — P0 Rollback Test Plan
Date: 2026-05-15 Status: IMPLEMENTATION PLANNING — Lane "rollback-test" (X-8 authoring) Scope: PLANNING ONLY. No test executed, no DDL, no SQL, no migration, no PG mutation, no signature generated, no verify run. Master:
implementation-planning/dot-iu-cutter-v0.1-p0-implementation-planning-master-2026-05-15.md
1. Purpose
Specify the synthetic-data dry-run scenario matrix for the rollback + verify safety surface of P0-3 and P0-4 (HIGH-risk items). This plan is the authoring half of X-8; the execution dry-run is performed in a separate session before production migration execution.
The plan covers:
- rollback_key behavior
- cut_change_set state transitions including invalid_drift
- cut_change_set_affected_row before_state_snapshot fidelity
- verify_result.verdict triggering rollback (FAIL) vs no rollback (NEEDS_HUMAN)
- dot_pair_signature validation, revocation, and exactly-one-cross-reference rule
- rollback failure recovery
- signature timeout race conditions
- signature_failure / dot_pair_drift signal routing
No SQL, no DDL, no actual signatures generated, no actual rollbacks run.
2. Source Inputs
migration-design/dot-iu-cutter-v0.1-p0-3-cut-change-set-rollback-key-migration-design-2026-05-15.md§6–§12migration-design/dot-iu-cutter-v0.1-p0-4-verify-result-migration-design-2026-05-15.md§9–§15risk-review/dot-iu-cutter-v0.1-dieu32-p0-high-risk-joint-review-p0-3-p0-4-2026-05-15.md§5–§9risk-review/dot-iu-cutter-v0.1-p0-cross-cutting-decision-register-2026-05-15.md§3.8 (X-8)implementation-planning/dot-iu-cutter-v0.1-p0-cross-cutting-resolution-plan-2026-05-15.md§10 (X-8) + §8 (X-6 polish)
3. Synthetic Data Dry-Run Plan
dry_run_environment_basis: per preflight plan §6
synthetic_data_principles:
- no production data
- no live DOT-pair identifiers (use scenario-local fake DOT IDs)
- reset between scenarios — each scenario starts from a clean cutter_governance schema state
- canonicalization rule v0.1 placeholder applied (NFC + LF + trim) for any markdown source used in axis-1 scenarios
- signing scheme v0.1 hash-based pseudo-signature used (no cryptographic material)
synthetic_data_inventory:
- 3 synthetic source markdown documents (small, medium, with multi-byte chars)
- 2 synthetic manifest_envelope rows
- up to 10 synthetic manifest_unit_block rows
- up to 2 synthetic review_decision rows (PASS for the happy-path scenarios)
- synthetic dot_pair_signature rows generated per scenario
- synthetic cut_change_set + cut_change_set_affected_row rows generated per scenario
not_run_here: actual test execution
4. P0-3 / P0-4 Rollback / Verify Scenario Matrix
| # | Scenario name | Inputs | Expected behavior | Pass condition |
|---|---|---|---|---|
| S01 | Happy-path commit | synthetic CUT with both signatures valid, tool_revision_match=true, no drift | cut_change_set → committed; verify_result.verdict=PASS | committed + PASS observed |
| S02 | Missing executor signature | CUT with only verifier signature | cut_change_set stays executing; signature_failure signal to G-2 | state=executing; backlog entry present |
| S03 | Missing verifier signature | CUT with only executor signature | cut_change_set stays executing; signature_failure signal to G-2 | state=executing; backlog entry present |
| S04 | Invalid signature payload | CUT with mismatched payload_hash | cut_change_set stays executing; validation_state=invalid on signature | state=executing; signature.validation_state=invalid |
| S05 | tool_revision_match=false | executor and verifier tool_revisions differ | cut_change_set → invalid_drift; dot_pair_drift signal | state=invalid_drift; backlog entry present |
| S06 | Rollback of committed change-set | scenario S01 + manual rollback | cut_change_set → rolled_back; affected_row entries retained; audit preserved | state=rolled_back; affected_row count unchanged |
| S07 | Rollback of pending change-set | CUT enqueued but not signed; abort | cut_change_set → rolled_back (aborted); no signatures present | state=rolled_back |
| S08 | Rollback of executing change-set | CUT in progress, abort signal | cut_change_set → rolled_back (mid-execution); affected_row entries retained for already-applied rows | state=rolled_back; partial affected_row entries present |
| S09 | Rollback of already-rolled-back change-set | CUT already in rolled_back; rollback again | NO-OP; success with note "already rolled back" | no state change; idempotent return |
| S10 | Rollback cascade overlap (default ERROR) | Two change-sets A and B; B touches rows A also touched; rollback B then attempt rollback A | rollback A errors with escalation; default ERROR + reviewer escalation | error returned; backlog entry kind=rollback_cascade_blocked |
| S11 | rollback_key collision attempt | synthetic insert of duplicate rollback_key | rejected at write time (application-layer uniqueness) | reject observed |
| S12 | Idempotency key on re-submit | identical CUT submitted twice with same (manifest_id, manifest_version, review_decision_id) | second submission rejected (idempotency) | second submission rejected |
| S13 | VERIFY round-trip PASS | matching canonical_token streams | verify_result.verdict=PASS; cut_change_set → committed | verdict=PASS; committed |
| S14 | VERIFY round-trip FAIL with auto-rollback | drifting canonical_token stream beyond threshold | verify_result.verdict=FAIL; rollback_triggered=true; cut_change_set → rolled_back | FAIL + rollback chain observed |
| S15 | VERIFY NEEDS_HUMAN — disagreement | executor verdict PASS, verifier verdict FAIL | verdict=NEEDS_HUMAN; no auto-rollback; escalation_ref populated | NEEDS_HUMAN; cut_change_set stays executing |
| S16 | VERIFY NEEDS_HUMAN — tool_revision drift | both verdicts PASS but tool_revision_match=false | verdict=NEEDS_HUMAN | NEEDS_HUMAN observed |
| S17 | VERIFY both-FAIL concurrence | both executor and verifier verdicts FAIL | verdict=FAIL; auto-rollback; rollback_triggered=true | FAIL + rollback observed |
| S18 | VERIFY signature timeout (race) | executor signature arrives, verifier signature delayed past timeout | verdict=NEEDS_HUMAN; escalation_ref populated | NEEDS_HUMAN observed at timeout |
| S19 | Canonicalization rule consistency | same input run twice through canonical_token mapping | identical token streams produced | exact equality |
| S20 | Canonicalization rule mid-cycle change (rejected scenario) | attempt to apply different rule version to a previously-passing verify_result | rejected — canonicalization_rule_used field on verify_result is immutable | reject observed |
| S21 | dot_pair_signature exactly-one-cross-reference | attempt to set both cross_reference_change_set_id and cross_reference_verify_result_id non-null | rejected (application-layer X-6 polish enforcement) | reject observed |
| S22 | dot_pair_signature revocation cascade | mark a signature revoked → dependent change-sets flagged | backlog entry created; dependent change-sets receive a review flag | backlog entry present; dependent change-sets flagged |
| S23 | Rollback failure recovery | force rollback to fail (e.g., simulated DB error mid-rollback) | new health signal emitted; backlog entry kind=rollback_failed; manual recovery path documented | backlog entry present; recovery path documented |
| S24 | before_state_snapshot fidelity (Standard) | rollback a CUT and verify rows restored to snapshot state | rows match snapshot | match observed |
| S25 | before_state_snapshot fidelity (HIGH risk-class) | full-row snapshot used for HIGH risk_class CUT; rollback restores exactly | rows match full-row snapshot | match observed |
| S26 | Re-VERIFY chain via prior_verify_result_id | NEEDS_HUMAN resolved; new verify_result issued; prior chain set | new row chains to prior; prior → superseded | chain observed |
5. Rollback_key Behavior Specification
rollback_key_format_under_test:
- deterministic: "RBK-<change_set_id>"
- uniqueness: globally unique across cutter_governance.cut_change_set
- immutability: once assigned, never changes for that change_set_id
rollback_key_collision_handling:
- write-time uniqueness check at application layer
- if collision observed → reject + emit a backlog entry kind=rollback_key_collision
rollback_key_retention:
- rollback_key retained indefinitely even after change_set is rolled_back
- audit trail anchored on rollback_key
6. verify_result Behavior Specification
verify_result_verdict_paths_under_test:
PASS:
triggers: axis_1_status=pass + axis_2_status in (pass, not_applicable) + executor/verifier signatures valid + tool_revision_match=true + birth_gate_check passed
side_effects: cut_change_set → committed; REPORT emits PASS
FAIL:
triggers: any of {axis_1 fail, birth_gate fail, signature invalid, tool_revision_mismatch}
side_effects: rollback_triggered=true; cut_change_set → rolled_back; REPORT emits FAIL with verdict_rationale
NEEDS_HUMAN:
triggers: executor/verifier verdict disagreement OR axis_1 canonicalization ambiguity OR explicit needs_human flag OR signature timeout
side_effects: no auto-rollback; cut_change_set stays executing; escalation_ref populated
verify_result_canonicalization_rule_field:
required: true on every row
immutable: true after row insert
verify_result_re_verify_chain:
via: prior_verify_result_id self-FK
superseded_lifecycle: prior row state → superseded
7. dot_pair_signature Behavior Specification
dot_pair_signature_validation_state_lifecycle_under_test:
pending → valid (on validation pass)
pending → invalid (on validation fail)
valid → revoked (on revocation; revoked_at + revocation_reason populated)
dot_pair_signature_cross_reference_rule:
exactly one of cross_reference_change_set_id or cross_reference_verify_result_id is non-null
enforced at application layer (X-6 polish)
dot_pair_signature_revocation_cascade:
on revocation: emit backlog entry (kind=signature_revoked)
flag dependent change-sets / verify_results referencing the signature for Đ32 review
dot_pair_signature_signing_scheme_v0_1:
hash-based pseudo-signature
payload_envelope captures: signer_dot_id, signer_tool_revision, signed_at, cross_reference, intent
signature_payload = deterministic hash of canonical payload
v0.1 acceptance ONLY IF FUTURE upgrade to cryptographic signing scheme is committed via D4 capability intake
8. Expected Pass / Fail Distribution Across Scenarios
expected_pass_scenarios:
- S01, S06, S07, S08, S09, S13, S19, S24, S25, S26 (commit/rollback happy paths + idempotency + canonicalization + snapshot + chain)
expected_state_transition_or_reject_scenarios:
- S02, S03, S04 (signature failure paths)
- S05 (invalid_drift)
- S10 (rollback cascade overlap)
- S11 (rollback_key collision)
- S12 (idempotency)
- S20 (rule immutability)
- S21 (exactly-one cross-reference)
expected_verdict_outcome_scenarios:
- S14 (FAIL + rollback)
- S15 (NEEDS_HUMAN — disagreement)
- S16 (NEEDS_HUMAN — drift)
- S17 (FAIL — both-fail concurrence)
- S18 (NEEDS_HUMAN — timeout)
expected_signal_routing_scenarios:
- S02, S03, S04 (signature_failure signal observed in G-2 backlog channel)
- S05 (dot_pair_drift signal observed)
- S22 (revocation cascade signal observed)
- S23 (rollback_failed signal observed)
overall_acceptance_threshold: 100% of scenarios pass their expected condition; any failure BLOCKS production execution
9. Failure Escalation
on_scenario_failure:
- emit a backlog entry (kind=rollback_test_scenario_failed; scenario_id=<S##>)
- notify Đ32 (HIGH-risk path) + G-4 Custodian
- DO NOT proceed to production execution
- root-cause analysis required before retry
retest_policy:
- retry requires Đ32 sign-off
- any change to the rollback test plan after first failure requires Đ32 review (plan revision)
sign_off_after_full_dry_run_pass:
- Đ32 (HIGH-risk path) signs off
- G-4 Custodian signs off
- sign-off recorded as a closure file (separate session; not in this planning phase)
10. Coverage Map — Risks → Scenarios
| Risk (from joint review) | Scenarios |
|---|---|
| JR-1 rollback safety | S06, S07, S08, S09, S10, S24, S25 |
| JR-2 verify failure | S13, S14, S15, S16, S17, S18 |
| JR-3 dual signature | S01, S02, S03, S04 |
| JR-4 tool_revision drift | S05, S16 |
| JR-5 signature_failure | S02, S03, S04, S18 |
| JR-6 rollback test plan requirement | this plan itself; full coverage across S01–S26 |
| JR-7 canonicalization rule dependency | S13, S14, S19, S20 |
| JR-8 source_span ↔ axis_1_drift_unit (X-A) | S19, S13, S14 (indirectly) |
11. What This Plan Does NOT Do
this_file_does_NOT:
- execute any scenario
- generate any signature
- run any verify
- perform any rollback
- touch any production data
- emit any signal to a real backlog channel
- mutate any PG / Qdrant / Directus state
- write any SQL / DDL / migration script
12. Explicit Confirmation
no_test_executed: true
no_signature_generated: true
no_verify_run: true
no_rollback_run: true
no_signal_emitted: true
no_ddl_written: true
no_sql_written: true
no_migration_script_written: true
no_pg_mutation: true
no_qdrant_mutation: true
no_directus_mutation: true
no_data_writes: true
no_implementation_execution: true
no_phase_prior_file_modified: true
output_form: rollback_test_planning_only