KB-3CE8

IU b–f Execution Readiness Refactor — 01 Read-Only vs Mutation Correction Matrix

15 min read Revision 1
iutests-b-fcorrection-matrixread-only-vs-mutationexecution-classcommand-pack-refactordocument-only2026-05-28

IU b–f Execution Readiness Refactor — 01 Read-Only vs Mutation Correction Matrix (Outcome B)

Corrects every place in the baseline command pack (iu-test-b-to-f-readiness-command-pack-2026-05-28/) where a "read-only / zero gate / no approval" label permits a database write. Each row cites the source doc/section verbatim and assigns the corrected execution class (C1–C5, see doc 00 §2).


0. The three write-types the baseline mislabels as read-only

Before the matrix, the three concrete writes the baseline treats as "non-mutating":

  • W1 — Audit row. Every DOT command writes a dot_iu_command_run row (Điều 35 requires it). The baseline writes mutating=false in that row and then asserts "zero mutation". The row itself is an INSERT. A mutating=false flag describes the command's effect on IU data, not the existence of the audit write. → A run that emits an audit row is not C1.
  • W2 — Function creation. CREATE [OR REPLACE] FUNCTION filter_axis_b / filter_axis_c_subtree / sql_link wrappers. This is DDL. It changes the database catalog. → C2, never C1.
  • W3 — DOT catalog row. Each new dot_iu_* command requires an INSERT into dot_iu_command_catalog (the DOT pair, Điều 35). → C2, never C1.

Rule of thumb for the next Agent: if a step reads IU data with a bare SELECT and writes nothing — C1. The moment a DOT command is invoked, or a function/catalog row is created, the step is C2 or higher, regardless of the mutating flag.


1. Correction matrix — command pack docs

# Source (doc · section) Unsafe / ambiguous instruction (verbatim) Why it is NOT read-only / not safe Corrected execution class Corrected next action
B-1 02 (test b) · title + banner # 02 — Test b … (READ-ONLY) / **This is a read-only test: zero mutation.** / Mutation: none. Gate: none. Approval: none. The filter logic read is C1, but the doc's own §11 implementation step creates a function + catalog row, and §5 writes an audit row per call. The banner covers all of these under "zero mutation". Split: C1 (the SELECT proof) + C2 (the DOT wrapper) Run the axis-b filter as a bare parameterised SELECT over iu_three_axis_envelope/iu_metadata_tag for the C1 proof. Defer filter_axis_b + dot_iu_filter_axis_b to the C2 additive macro.
B-2 02 (test b) · §5 dot_iu_filter_axis_b (read-only, non-mutating) — … writes a dot_iu_command_run audit row (mutating=false) Calls the wrapper "non-mutating" while it INSERTs an audit row (W1). C2 In C2, declare the wrapper as writing an audit row; the audit INSERT is the expected mutation of an additive macro, not a violation — but it must NOT appear in a C1 proof.
B-3 02 (test b) · §6 "No-mutation proof" Zero-delta asserts on information_unit, iu_three_axis_envelope, iu_metadata_tag, event_outboxdot_iu_command_run omitted from the list The proof excludes the one table the run actually writes (W1). A C1 proof that omits the audit table is not a proof of zero mutation; it's a proof of zero IU-data mutation. C1 proof must be re-scoped C1 proof runs as raw SELECT (no DOT call → genuinely zero audit write). Add dot_iu_command_run to the delta set; it must read delta = 0 because no command was invoked.
B-4 02 (test b) · §11 Implement filter_axis_b as a STABLE SQL function + dot_iu_filter_axis_b catalog entry in macro … No gate, no approval. CREATE FUNCTION (W2) + catalog INSERT (W3) placed under "No gate, no approval". Additive DDL needs a write channel + rollback even if it needs no gate. C2 C2 macro: CREATE FUNCTION via SSH workflow_admin, with before/after object diff + drop-function rollback. "No gate" is correct; "no write" is wrong.
B-5 03 (test c) · title + banner # 03 — Test c … (READ-ONLY) / Read-only: zero mutation. / Gate: none. Approval: none. Same pattern as B-1: the subtree read is C1, but §12 creates filter_axis_c_subtree + dot_iu_subtree, and §9 writes an audit row. Split: C1 + C2 Run subtree read as bare recursive SELECT over iu_relation/iu_tree_path (reuse fn_iu_subtree if it is already STABLE+live — calling an existing STABLE fn directly is a read, but doing so via a DOT wrapper writes an audit row). C1 proof: call fn_iu_subtree in a plain SELECT, no wrapper. Defer wrapper to C2.
B-6 03 (test c) · §6 dot_iu_subtree (read-only) — wraps filter_axis_c_subtree, audit row mutating=false. "read-only" command that writes an audit row (W1). C2 Same as B-2.
B-7 03 (test c) · §7 "No-mutation proof" Zero-delta on information_unit, iu_relation, iu_tree_path, iu_tree_change_log, event_outboxdot_iu_command_run omitted Same as B-3. C1 proof re-scoped Same as B-3: add audit table to delta set; C1 proof uses bare SELECT.
B-8 04 (test f) · title + §5 # 04 — Test f … (READ-ONLY FIRST, then bounded enable) / the read-only proof … needs no gate flip … zero mutation The validate/resolve reads are genuinely C1. But §11 builds two DOT wrappers (W2+W3) and §7 writes per-link audit rows (W1) inside the "read-only proof". Split: C1 + C2 (mutating enable already correctly C3, deferred) C1 proof: call fn_iu_sql_link_validate and read v_iu_sql_link_resolved as bare SELECTs over the 3 live iu_sql_link rows. Defer dot_iu_sql_link_validate/resolve wrappers to C2. This doc is the closest to correct — it already segregates the mutating _register/_capture_probe as deferred C3.
B-9 04 (test f) · §7 Per-link dot_iu_command_run (mutating=false) Audit-row write inside the read proof (W1). C2 (wrapper path) / C1 (bare path) C1 proof writes nothing; if run via wrapper it is C2. Validator fn_iu_sql_link_validate is STABLE/read — confirm via code inspection, not via a write probe.
B-10 04 (test f) · §6 dot_iu_sql_link_register (mutating, deferred) / dot_iu_sql_link_capture_probe (mutating, BEGIN/ROLLBACK proof, deferred) Correctly labeled. No correction. C3 (deferred) Keep deferred; enable/capture is governed by Điều 32 + bounded gate (enabling a live link). Confirmed correct.
B-11 05 (test d) · whole doc # 05 — Test d … (MUTATING, GATED) / Mutation: YES. / blocked behind gate protocol (08) + review_decision (U3) Correctly labeled mutating/gated. No mislabel. C3 (+ depends on C4 gate protocol) Keep as-is. One ambiguity to fix in the prompt: §3/§5 dry-run sub-tests use BEGIN…ROLLBACK; the doc does not state whether the dot_iu_command_run audit row lands inside or outside the rolled-back TX. → The C3 prompt must specify: audit row is written in a separate committed statement (so the audit survives the ROLLBACK), or explicitly accept that dry-run audit rows roll back too. Pick one and state it.
B-12 06 (test e) · whole doc # 06 — Test e … (MUTATING, DELIVERY-GATED) / Mutation: YES (event rows, route attempts; bounded). / registration is forbidden in this macro Correctly labeled mutating/gated, and it correctly recognises event-type registration as a mutation and defers it (U6). No mislabel. C3 (event delivery) + C2 (event-type registration, additive) + C4 (delivery gate) Keep as-is. Note: event-type registration (event_type_registry INSERT) is additive C2; event delivery (outbox/route/DLQ rows + delivery_enabled flip) is C3+C4. The prompt should separate these two sub-phases.
B-13 07 (DOT spec) · §1 matrix Rows mark dot_iu_filter_axis_b, dot_iu_subtree, dot_iu_sql_link_validate, dot_iu_sql_link_resolve, harness core as read-only / Gate=none / Rollback=N/A §3 simultaneously requires each to have a catalog row in dot_iu_command_catalog (pair) (W3) and to write a dot_iu_command_run row (W1). "Rollback=N/A" is wrong: dropping a created function/catalog row IS the rollback. C2 Re-label all 5 "read-only" commands as C2 additive; set Rollback = "DROP FUNCTION + DELETE catalog row (in the additive TX)". Gate stays none.
B-14 07 (DOT spec) · §3 Read-only commands assert mutating=false and are provable via BEGIN/ROLLBACK zero-delta. A BEGIN/ROLLBACK around a command that creates a catalog row + writes an audit row proves only that those writes can be rolled back, not that the command is read-only. Conflates reversibility with read-only-ness. Clarify C2 additive macros use BEGIN/ROLLBACK to prove reversibility and to dry-run; the read-only proof (C1) is a separate, earlier macro that invokes no command at all.
B-15 07 (DOT spec) · §4 New mutating (deferred): dot_iu_sql_link_register, dot_iu_sql_link_capture_probe, dot_iu_trigger_test. Correctly labeled. No correction. C3 (deferred) Keep deferred.
B-16 08 (gate protocol) · whole doc Designed here; not executed. / open command shape does UPDATE dot_config … INSERT INTO dot_iu_command_run … COMMIT; Design content is C5 (document-only) — correct. The implementation of the protocol functions is C4, not yet done. The doc is honest. C5 (this doc) → C4 (future impl) Keep. The C4 implementation macro (doc 03 prompt 4 of this pack) must carry Hard-Gate-0 and create the open/close/verify-close/watchdog functions only after the SSH channel probe passes.

2. Correction matrix — command pack doc 10 (the author-ready prompts)

Doc 10's prompts are what the next Agent would actually paste. These are the highest-priority corrections. Doc 03 of this pack replaces them.

# Prompt (doc 10) Unsafe / ambiguous (verbatim) Why unsafe Corrected class Replacement in this pack
B-17 Prompt 1 IU_TEST_B_C_READONLY_HARNESS_IMPLEMENTATION_XHIGH Mode: implementation, READ-ONLY (SELECT + audit rows only) … Allowed: create STABLE SQL functions …; add catalog rows …; write dot_iu_command_run audit rows Self-labels READ-ONLY while authorizing W1+W2+W3. Exactly GPT criticism #4 ("audit rows are writes") and #5 ("creating SQL functions/catalog rows while calling itself read-only … is not read-only"). Split into two macros: C1 (pure proof, no DDL/no DOT) + C2 (additive wrappers) Prompt 1 (IU_B_C_AXIS_TREE_PURE_READONLY_PROOF) = C1; Prompt 3 (IU_B_C_F_ADDITIVE_DOT_WRAPPER_IMPLEMENTATION) = C2.
B-18 Prompt 2 IU_SQL_LINK_PROOF_AND_DOT_COMMAND_IMPLEMENTATION_XHIGH Mode: implementation, READ-ONLY proof first … Allowed: add read-only catalog commands dot_iu_sql_link_validate, dot_iu_sql_link_resolve; … audit rows "READ-ONLY proof first" but authorizes catalog rows (W3) + audit rows (W1). GPT criticism #6 ("Catalog rows are mutation"). Split: C1 (validate/resolve proof) + C2 (wrappers, folded into the shared additive macro) Prompt 2 (IU_F_SQL_LINK_PURE_READONLY_PROOF) = C1; the wrappers fold into Prompt 3 (additive).
B-19 Prompt 3 IU_BOUNDED_GATE_PROTOCOL_DESIGN_OR_IMPLEMENTATION_XHIGH Mode: design → implementation of gate-flip primitives ONLY. LIVE-APPLY-HARD-GATE-0 applies. Correctly mutating + has Hard-Gate-0. GPT criticism #7: "dangerous if implemented too early; it must first be a design/preflight macro with no live gate function creation unless Hard Gate 0 passes." C4 (with explicit design-first phase) Prompt 4 (IU_BOUNDED_GATE_PROTOCOL_AUTHORITY_PACK) = C4, design+preflight phase gated before any live function creation.
B-20 Prompt 4 IU_SPLIT_MERGE_REVIEW_DECISION_WIRING_XHIGH Mode: implementation, MUTATING, governed. Depends on PROMPT 3. Correctly mutating/governed. GPT criticism #8: must not run before Council approves the corrected gate protocol + read-only harness proof. C3 (depends on C4) Prompt 5 (IU_SPLIT_MERGE_REVIEW_DECISION_WIRING_AUTHORITY_PACK) = C3; hard dependency on Prompt 4 approved.
B-21 Prompt 5 IU_TRIGGER_IN_OUT_EVENT_CONTRACT_AND_TEST_PLAN_XHIGH Mode: implementation, MUTATING (event registry + bounded delivery). Depends on PROMPT 3. Correctly mutating. Same hold as B-20 (#8). C2 (registration) + C3 (delivery) + C4 (delivery gate) Prompt 6 (IU_TRIGGER_IN_OUT_EVENT_CONTRACT_AUTHORITY_PACK); internally separates registration (C2) from delivery (C3) + gate (C4).
B-22 Prompt closing note Prompts 1 and 2 are read-only and need no gate/approval → run first, in parallel. Restates the false read-only label for prompts that write. Replaced. In this pack, only the C1 proofs (Prompts 1+2 here) are truly read-only and parallel; the additive C2 work is a separate, later macro.

3. Self-review blind spot in the baseline (meta-correction)

Command-pack doc 11 (11-law-gate-risk-self-review.md) graded the pack:

PASS — document-only command pack complete, constitutionally compliant, no mutation, no gate left open … No underload — 12/12 deliverables.

But doc 11's self-review did not catch the read-only-while-writing contradiction in prompts 1 and 2 — GPT (S4) caught it independently. Correction: a self-review that asserts "no mutation" for a pack whose own prompts authorize CREATE FUNCTION + catalog rows + audit rows is itself underloaded. This pack's self-check (doc 06) adds an explicit execution-class consistency check: every prompt's stated mode must match the union of writes it authorizes, or it fails. That check is now a required gate in the self-review of all future IU macros.


4. Summary of corrections made

  • 6 read-only mislabels corrected to C1+C2 splits: B-1/B-4 (doc 02), B-5/B-7 (doc 03), B-8/B-9 (doc 04), B-13/B-14 (doc 07), B-17 (prompt 1), B-18 (prompt 2).
  • 3 audit-table omissions in zero-delta proofs corrected: B-3, B-7, B-9.
  • 2 prompts re-hardened (B-19 gate protocol design-first; B-20/B-21 governance hold).
  • 1 dry-run audit ambiguity flagged for explicit resolution in the C3 prompt: B-11.
  • Confirmed correct, no change: docs 05 (d), 06 (e) bodies; B-10, B-15 deferred mutating commands; B-16 gate-protocol design doc.
  • 1 meta-correction: baseline self-review blind spot → new execution-class consistency check added to the standard self-review.

Discard list: command-pack doc 10's prompts 1 and 2 must not be pasted as-is (they are unsafe per B-17/B-18). Prompts 3/4/5 in doc 10 are usable but superseded by the cleaner, fully execution-classed versions in doc 03 of this pack. The rest of the command pack (docs 00–09, 11) remains valid as baseline reference, not execution authority.

Back to Knowledge Hub knowledge/dev/reports/architecture/iu-b-to-f-execution-readiness-refactor-2026-05-28/01-readonly-vs-mutation-correction-matrix.md