KB-77BC
dot-iu-cutter v0.4 — Cutter-Agent Write-Path Design (design only) (2026-05-16)
10 min read Revision 1
dot-iu-cutterdieu44v0.4tier2write-pathdesign-only
dot-iu-cutter v0.4 — Cutter-Agent Write-Path Design
document_path: knowledge/dev/laws/dieu44-trien-khai/v0.4-design/dot-iu-cutter-v0.4-cutter-agent-write-path-design-2026-05-16.md
revision: r1
date: 2026-05-16
author: Agent (Claude Code CLI, Opus 4.7 1M)
phase: v0.4 — Tier 2 write-path DESIGN (companion to design-master)
status: design_only_pending_gpt_review
⛔ DESIGN ONLY. No code, no SQL, no write, no GRANT. Every table-write, transaction, and privilege below is a target for a future authorized cycle, not an instruction to execute.
§1 — Single-Writer Principle
invariant W-1: the ONLY component permitted to INSERT/UPDATE any
cutter_governance base table is the cutter-agent write path, running as a
designated writer principal (cutter_exec / cutter_verify — doc 5).
invariant W-2: cutter_ro is READ-ONLY and MUST NOT appear on any write path.
invariant W-3: NO ad-hoc INSERT, no psql-by-hand, no Directus item-create,
no ETL. First and every subsequent row enters via the planned writer.
invariant W-4: enforcement is the grant model (no write grant exists to any
other principal) — but applying that grant model is a SEPARATE authorized
credential cycle (doc 5), NOT this design.
invariant W-5: schema is frozen — the write path uses ONLY existing columns;
any field the design "wants" but the schema lacks goes into an existing
jsonb/text column, never a new column.
§2 — Tables Written Per Phase
| Phase | Table | Op | Notes |
|---|---|---|---|
| MARK | decision_backlog_entry |
INSERT | new work item, status='marked' |
| MARK | decision_backlog_history |
INSERT | birth record (transition ∅→marked) |
| MARK | decision_backlog_dependency |
INSERT (0..N) | only if entry depends on other entries |
| MARK | decision_backlog_sweep_log |
INSERT | sweep pass that picked/created the entry |
| REVIEW | manifest_envelope |
INSERT | the planned cut manifest (plan, no effect) |
| REVIEW | manifest_unit_block |
INSERT (1..N) | per-unit plan, composite PK |
| REVIEW | review_decision |
INSERT | approve/reject/defer bound to manifest pair |
| REVIEW | decision_backlog_entry |
UPDATE | status scalar only → reviewed_* |
| REVIEW | decision_backlog_history |
INSERT | transition record |
| CUT | cut_change_set |
INSERT | the applied change set header |
| CUT | cut_change_set_affected_row |
INSERT (1..N) | per affected row |
| CUT | dot_pair_signature |
INSERT | executor attestation (DOT-991 lane) |
| CUT | decision_backlog_entry |
UPDATE | status scalar only → cut_applied |
| CUT | decision_backlog_history |
INSERT | transition record |
| VERIFY | verify_result |
INSERT | independent verify outcome |
| VERIFY | dot_pair_signature |
INSERT | verifier attestation (DOT-992 lane) |
| VERIFY | cut_change_set (+ affected_row) |
INSERT | ONLY on fail: compensating rollback set |
| VERIFY | decision_backlog_entry |
INSERT | ONLY on fail: escalation entry |
| VERIFY | decision_backlog_entry |
UPDATE | status scalar → verified_complete | verify_failed_escalated |
| VERIFY | decision_backlog_history |
INSERT | transition record |
mutation_policy:
- the ONLY in-place UPDATE permitted anywhere is
decision_backlog_entry.status (+ its history append). Everything else is
INSERT-only (append-only lineage via prior_*/superseded_by_*).
- canonical_address_alias: NOT written in v0.4 (OD-2, deferred).
§3 — Transaction Boundaries
TXN-MARK : { decision_backlog_entry INSERT, history INSERT,
dependency INSERT*, sweep_log INSERT } — one atomic txn.
Either the entry + its audit + its edges all commit, or none.
TXN-REVIEW : { manifest_envelope INSERT, manifest_unit_block INSERT+,
review_decision INSERT, entry.status UPDATE, history INSERT }
— one atomic txn. The manifest pair and the decision that binds
it MUST be co-committed (a review_decision must never reference
a manifest that did not commit).
TXN-CUT : { cut_change_set INSERT, cut_change_set_affected_row INSERT+,
executor dot_pair_signature INSERT, entry.status UPDATE,
history INSERT } — one atomic txn. A change set without its
affected rows and its executor signature is forbidden to exist.
TXN-VERIFY : { verify_result INSERT, verifier dot_pair_signature INSERT,
[fail: compensating cut_change_set+affected_row INSERT,
escalation decision_backlog_entry INSERT], entry.status
UPDATE, history INSERT } — one atomic txn.
isolation_target: READ COMMITTED minimum; SERIALIZABLE recommended for
TXN-CUT/TXN-VERIFY to prevent two writers racing the same entry (final
choice = OPEN, see risk doc). Belt-and-braces: a row-level guard (see §6).
no_cross_phase_txn: phases are NOT wrapped in one giant transaction; each
phase commits independently and is resumable from its persisted state.
§4 — Idempotency Keys
IK-MARK: deterministic key = canonical_hash(signal_source_id, scenario_ref,
payload_canonical_form). Stored at payload.idempotency_key (OD-1; schema
frozen → lives in existing jsonb, not a new column). Before INSERT the
writer SELECTs (via its own read, not cutter_ro) for an existing entry
with the same key; if present → no-op return that entry (MARK is
idempotent on replay of the same signal).
IK-REVIEW: natural key = (entry_id, manifest content hash). A second REVIEW
on the same entry with identical manifest content is a no-op; a different
manifest is a NEW review_decision with prior_review_decision_id set and
the old one stamped superseded_by_review_decision_id.
IK-CUT: natural key = (decision_backlog_entry_id, approved review_decision_id,
attempt_no in payload). Re-running CUT for an already-applied, non-rolled-
back change set is a no-op (return existing change_set_id).
IK-VERIFY: natural key = (change_set_id). At most one non-superseded
verify_result per change_set; a re-verify chains via prior_verify_result_id.
principle: idempotency is read-before-write keyed on a deterministic hash;
replays converge, they never duplicate or double-apply.
§5 — Retry Behaviour
transient_failure (DB deadlock, conn drop, lock timeout):
- safe to retry the SAME txn; idempotency keys (§4) guarantee convergence.
- bounded exponential backoff; max attempts = config; attempt_no recorded
in payload / change-set body (existing columns only).
semantic_retry (a phase produced a superseded result, e.g. re-review):
- NEVER mutate the old row. INSERT a new artefact, set its prior_* self-FK
to the old artefact, set the old artefact's superseded_by_* (the one
sanctioned exception: superseded_by is a forward stamp, written once).
- decision_backlog_entry.status moves back to the appropriate pending
state and a history row records the reopen with reason.
exhausted_retries:
- entry.status → a *_failed / escalated state (doc 4); history records
terminal-for-now; manual escalation entry created (VERIFY-style) so a
human/GPT loop can intervene. The agent does NOT silently drop work.
no_partial_commit_retry: because each phase is one txn (§3), a retry always
restarts from a consistent committed boundary — there is no "half-written
phase" to reconcile.
§6 — Rollback Behaviour
db_level: each phase txn either COMMITs whole or ROLLBACKs whole (PG txn).
An aborted phase leaves zero trace (except possibly a sweep_log attempt
row, which is intentionally allowed to persist as an audit of the try).
semantic_level (a committed CUT later found wrong by VERIFY):
- NO physical DELETE / no UPDATE-away of cut_change_set or affected_row.
- a COMPENSATING cut_change_set is INSERTed (a forward "undo" change set);
verify_result.rollback_change_set_id_triggered points the failing verify
at that compensating set; entry.status → rolled_back / escalated.
- rationale: the governance schema is an append-only ledger; truth is
"what happened", corrected by further recorded events, never erased.
escalation: verify_result.escalation_ref → a NEW decision_backlog_entry
(kind='escalation') so the failure is itself a tracked, sweepable work
item with its own history lineage.
guard_against_double_apply: a row-level guard (advisory lock on entry_id, or
a status precondition in the UPDATE … WHERE status=expected) ensures two
concurrent writers cannot both CUT the same entry; exact mechanism = OPEN
(risk doc) but the *requirement* is fixed here.
§7 — No-Base-Table-Writes-Outside-Planned-Writer (restated, enforced design)
target_grant_model (DESIGN; applied later under doc 5's credential cycle):
cutter_exec : INSERT on { decision_backlog_entry, _history, _dependency,
_sweep_log, manifest_envelope, manifest_unit_block,
review_decision, cut_change_set, cut_change_set_affected_row,
dot_pair_signature }; UPDATE(status) on decision_backlog_entry
cutter_verify : INSERT on { verify_result, dot_pair_signature,
cut_change_set, cut_change_set_affected_row,
decision_backlog_entry, decision_backlog_history };
UPDATE(status) on decision_backlog_entry
everyone else : 0 write privilege (incl. cutter_ro, directus app role)
DELETE/TRUNCATE/DDL/GRANT : granted to NO cutter principal
note: column-scoped UPDATE (status only) is not natively a PG table grant;
enforcement is in the writer code + a CHECK-free, app-owned invariant
(BATCH-1 model) + code review. PG grant gives table-level UPDATE;
the status-only restriction is an agent invariant, audited via history.
End of v0.4 cutter-agent write-path design (design only; nothing built).