KB-37F7
dot-iu-cutter v0.4 — Transaction Mapping Design (design only)
11 min read Revision 1
dot-iu-cutterdieu44v0.4db-adapterdesign-onlytransaction-mapping
dot-iu-cutter v0.4 — Transaction Mapping Design
document_path: knowledge/dev/laws/dieu44-trien-khai/v0.4-db-adapter-design/dot-iu-cutter-v0.4-transaction-mapping-design-2026-05-17.md
revision: r1
date: 2026-05-17
author: Agent (Claude Code CLI, Opus 4.7 1M)
phase: v0.4 — REAL DB ADAPTER DESIGN (companion to design-master)
status: design_only_pending_gpt_review
⛔ DESIGN ONLY. No SQL executed, no write, no connection. Every txn below is a target boundary for a future authorized cycle. Faithful to the v0.4 write-path & flow designs and the v0.2/v0.3 frozen schema (12 tables, 19 FKs, no CHECK/trigger/DEFAULT).
§1 — Invariant: One Atomic Transaction Per Phase
TX-1 each of MARK / REVIEW / CUT / VERIFY = exactly ONE BEGIN…COMMIT.
TX-2 no cross-phase transaction; phases commit independently and are
resumable from the persisted decision_backlog_entry.status.
TX-3 no nested transaction (mirrors PASSed skeleton transaction(): a second
BEGIN on an open txn raises TransactionError; no SAVEPOINT-as-subtxn).
TX-4 a phase txn COMMITs whole or ROLLBACKs whole. A partially-written phase
is forbidden to exist on disk.
TX-5 autocommit OFF; the adapter owns BEGIN/COMMIT/ROLLBACK explicitly
(the skeleton transaction() context manager maps 1:1 to this).
§2 — TXN-MARK (principal: cutter_exec)
writes (in order):
1. INSERT decision_backlog_entry (entry_id uuid, kind, status='marked',
payload jsonb{idempotency_key,…},
emitted_at, scenario_ref)
2. INSERT decision_backlog_history (∅→marked transition; FK entry_id)
3. INSERT decision_backlog_dependency (0..N) (from_entry_id=this, to_entry_id=blocker)
4. INSERT decision_backlog_sweep_log (one row: this sweep pass; soft uuid refs)
idempotency (pre-write, same txn or a preceding read):
read-before-write find(decision_backlog_entry where payload.idempotency_key=K).
if present → COMMIT nothing new, return existing entry (replay = no dup).
commit boundary: all 1..4 commit together or none.
retry vs escalate:
- 40001/40P01/53300/08xxx → bounded retry of the WHOLE txn (idempotent).
- 23505 on idempotency_key → another worker won the race → SELECT & return
the existing entry (success, dedup), do not retry as new.
- 23503 FK / 23502 NOT NULL → STOP (design bug or bad input), NEEDS_HUMAN.
§3 — TXN-REVIEW (principal: cutter_exec)
writes:
1. INSERT manifest_envelope (envelope_id, scope, content hash)
2. INSERT manifest_unit_block (1..N) (composite PK envelope_id,unit_local_id)
3. INSERT review_decision (FK manifest_id→envelope; composite FK
(manifest_id,manifest_unit_local_id)
→manifest_unit_block; decision text)
4. [re-review only] UPDATE review_decision SET superseded_by_review_decision_id
on the PRIOR row (write-once; the ONLY non-status UPDATE column granted
to cutter_exec) AND new row carries prior_review_decision_id
5. UPDATE decision_backlog_entry SET status (column-scoped) → reviewed_*
6. INSERT decision_backlog_history (transition row)
commit boundary: the manifest pair + the review_decision that binds it +
the status move + history co-commit. G-REVIEW-MANIFEST: a review_decision
must NEVER reference a manifest that did not commit (same txn guarantees it).
retry vs escalate:
- transient (40001/40P01/53300/08xxx) → bounded retry whole txn.
- re-review chaining must be deterministic on replay: prior/superseded
stamping is write-once; a replay that finds the stamp already set is a
no-op success, not a second supersede.
- 23503 composite FK miss (unit block not committed) → STOP design bug.
§4 — TXN-CUT (principal: cutter_exec)
precondition guards (read-only checks INSIDE the txn before writes):
G-CUT-APPROVED non-superseded review_decision.decision='approve' exists
G-CUT-DEPS every decision_backlog_dependency.to_entry_id for entry is
verified_complete (DAG gate)
G-CUT-ONCE no existing non-rolled-back cut_change_set for
(entry, approved review_decision) [IK-CUT + row guard §7]
writes:
1. INSERT dot_pair_signature (executor / DOT-991 lane;
prior_signature_id chains)
2. INSERT cut_change_set (FK decision_backlog_entry_id,
FK executor_signature_id=the
row from step 1;
verifier_signature_id LEFT NULL
— OD-6, CUT writes only CUT)
3. INSERT cut_change_set_affected_row (1..N) (FK change_set_id)
4. UPDATE decision_backlog_entry SET status (column-scoped) → cut_applied
5. INSERT decision_backlog_history (transition row)
commit boundary: a cut_change_set without its affected rows and its executor
signature is forbidden to exist → all co-commit.
retry vs escalate:
- transient → bounded retry whole txn; G-CUT-ONCE + IK-CUT make a retried
CUT converge (returns the existing change_set, no double-apply).
- 23505 on the CUT idempotency natural key → already applied → return
existing change_set_id (success).
- guard failure (not approved / deps unmet / already cut) → NOT an error
to retry: STOP this phase, leave entry pre-CUT, let sweep/escalation
own it.
note: cutter_exec has NO grant to write verify_result / verifier signature
(matrix); verifier_signature_id stays NULL here by both design AND
privilege (defence in depth).
§5 — TXN-VERIFY (principal: cutter_verify)
precondition guards (read-only, in txn):
G-VERIFY-CUT a cut_change_set with a valid DOT-991 executor signature exists
G-VERIFY-SOD verifier principal (cutter_verify) ≠ executor principal
(cutter_exec) — enforced structurally by principal routing (doc 4)
writes:
1. INSERT dot_pair_signature (verifier / DOT-992 lane)
2. INSERT verify_result (FK change_set_id,
FK executor_signature_id=checked,
FK verifier_signature_id=step 1,
outcome pass|fail,
prior_verify_result_id on re-verify)
on PASS:
3a. UPDATE decision_backlog_entry SET status → verified_complete (TERMINAL)
on FAIL:
3b. INSERT compensating cut_change_set + cut_change_set_affected_row
(forward "undo"; NO physical delete of the original)
3c. verify_result.rollback_change_set_id_triggered → that compensating set
3d. INSERT escalation decision_backlog_entry (kind='escalation',
status='marked') + its ∅→marked history
3e. UPDATE decision_backlog_entry SET status → verify_failed_escalated
4. INSERT decision_backlog_history (pass/fail transition row)
commit boundary: verify_result + verifier signature + (on fail) the whole
compensating+escalation bundle + status + history co-commit. A verify_result
must never exist without its verifier signature.
matrix note: cutter_verify is granted INSERT on cut_change_set,
cut_change_set_affected_row, decision_backlog_entry, decision_backlog_history,
verify_result, dot_pair_signature + UPDATE(status) on decision_backlog_entry
— EXACTLY what 3b/3d/3e/4 require. It has NO INSERT on review_decision/
manifest_*, NO UPDATE on superseded_by → it physically cannot do REVIEW/CUT
authoring work (separation of duty backed by the live grant matrix).
retry vs escalate:
- transient → bounded retry whole txn (idempotent on change_set_id key).
- verification MISMATCH (the semantic pass/fail itself = fail) is NOT a DB
error: it is the designed FAIL path (3b–3e) → status verify_failed_escalated
→ a human/GPT loop owns the escalation entry (NEEDS_HUMAN).
- 23505 on (change_set_id) verify key → a verify_result already exists →
return it (dedup); a re-verify must chain via prior_verify_result_id, not
duplicate.
§6 — Exact Commit / Rollback Boundary Table
phase principal COMMIT iff ROLLBACK on
MARK cutter_exec entry+history(+dep*)(+sweep) all ok any exception → whole
REVIEW cutter_exec manifest pair+decision+status+hist any exception → whole
CUT cutter_exec sig+changeset+affrows+status+hist any exception → whole
VERIFY cutter_verify result+sig(+comp+esc on fail)+stat any exception → whole
global: ROLLBACK leaves zero trace of that phase EXCEPT decision_backlog_sweep_log
may intentionally retain an attempt row (audit of the try) IF it was a
prior committed sweep pass — a sweep_log row inside a rolled-back TXN-MARK
is itself rolled back; only previously-committed sweep passes persist.
§7 — Concurrency Guard (what makes multi-worker safe)
guard-1 status CAS: every status move is UPDATE decision_backlog_entry SET
status=new WHERE entry_id=? AND status=expected. 0 rows updated → another
worker moved it → this phase aborts (no force). Maps 1:1 to the PASSed
skeleton cas_status().
guard-2 advisory lock: pg_advisory_xact_lock(hashtext(entry_id)) at phase
entry serialises same-entry phases within their txn lifetime; auto-released
at COMMIT/ROLLBACK (xact-scoped, no leak). (DA-7: advisory-lock vs rely
solely on CAS — recommend BOTH belt-and-braces.)
guard-3 isolation: READ COMMITTED default; SERIALIZABLE for TXN-CUT &
TXN-VERIFY (write-path doc recommendation) to prevent two writers racing
the same entry's effect set; 40001 → bounded retry (doc 5 / error doc).
(DA-8: SERIALIZABLE everywhere vs only CUT/VERIFY — recommend only
CUT/VERIFY to limit retry churn on MARK/REVIEW.)
guard-4 idempotency keys (doc: write-path §4) make any retried/replayed
phase converge instead of duplicating — the ultimate backstop.
no_single_worker_assumption: guards 1–4 hold for N workers; the only
external limit is CONNECTION_LIMIT 2/principal (doc 2 §5 / DA-6).
§8 — Open Decisions (this doc)
DA-7 advisory xact lock + CAS (recommended) vs CAS only.
DA-8 SERIALIZABLE scope: CUT/VERIFY only (recommended) vs all four.
DA-10 sweep_log attempt-row persistence on rolled-back MARK: confirm
"rolled back with the txn; only committed sweeps persist" is the intended
liveness semantics (write-path doc allowed a persisted attempt row — this
design says it persists only if it was its OWN committed sweep pass).
DA-11 re-review / re-verify replay determinism acceptance criteria for the
dry-run plan (doc 5).
End of transaction mapping design (design only; no SQL; no write; no connection).