KB-B247 rev 2

IU Core 500x — 02 Operator-runtime substrate (migration 018)

4 min read Revision 2
dieu44iu-core-mvp500xoperator-runtimemigration-018command-ledgerv0.62026-05-22

02 — Migration 018: the governed operator-runtime substrate

1. The problem

The 500x macro shipped dot_commands.py — the DOT one-command operator SURFACE. But its only safe action was explain (print the governed SQL, never run it). To turn that into a guarded run the operator surface needs a durable substrate: a place to AUDIT every runtime invocation, a SQL-visible VOCABULARY, and a dedicated off-switch GATE. Migration 018 adds exactly that — all additive.

2. 018_operator_runtime.sql — what it creates

object kind role
iu_core.operator_runtime_enabled config the runtime APPLY gate — default false / inert
fn_dot_iu_operator_runtime_enabled() function the gate function (mirrors fn_iu_composer_enabled)
dot_iu_command_catalog table the dot_iu_* vocabulary as a QUERYABLE table
dot_iu_command_run table the append-only run LEDGER
fn_dot_iu_command_log(...) function the governed ledger append
v_dot_iu_command_registry view the operator surface DOT-visible in SQL
v_dot_iu_command_run_health view one-row operator-runtime health

DOT: +2 tables, +2 views, +2 functions, +1 config — 106 → 113.

3. The ledger — dot_iu_command_run

One row per runtime plan / apply / verify. run_mode is CHECK-constrained to {plan,apply,verify}; run_status to {planned,applied,verified,refused,failed}. It carries the live gate_snapshot and a structured evidence jsonb. Crucially params_digest is an md5, never raw parameter values — no body text / id / secret ever lands durably. Two btree indexes — (command_name, created_at DESC) and (run_status, created_at DESC).

4. fn_dot_iu_command_log — fail-closed on vocabulary

The ONLY way the runtime writes the ledger. It is ungated — an audit row (including a refused row recorded while every gate is shut) must always be recordable. But it is fail-closed on vocabulary: once the catalog is seeded it refuses a command_name absent from dot_iu_command_catalog. The ledger therefore cannot record an ungoverned command — gate #8 enforced at the SQL layer.

5. v_dot_iu_command_registry — the operator surface in SQL

The catalog LEFT JOIN'd to its run-ledger aggregates: per command, the total_runs / applied_runs / refused_runs / failed_runs, last_run_at, last_status. This is the durable answer to "the operator surface is itself DOT-visible in SQL" — a UI or an auditor can query the whole vocabulary and its activity without touching Python.

6. runtime/280 — the catalog seed, locked to Python

280_operator_runtime_catalog_seed.sql seeds the 17 catalog rows from dot_commands.DOT_COMMANDS — the Python registry stays the SSOT, the seed is its SQL-visible projection. test_iu_core_540x_operator_runtime.py LOCKS the two: every (command_name, category, mutating, reversible) is asserted to match. The seed is idempotent (ON CONFLICT (command_name) DO NOTHING). R280 verifies catalog size 17 and that every catalogued target_function resolves to a pg_proc row (15 distinct, all resolvable).

7. Reversibility

rollback/018 drops the 2 views, 2 functions, 2 tables and the config key (views → functions → tables order, no dependency block) and prints a pre-rollback row-count snapshot. runtime/rollback/280 clears the catalog rows alone without dropping the table.

8. Production apply

018 + runtime/280 applied to the directus DB, each self-transacted. R280_catalog = 17 rows expected_17=t; R280_targets = 15 distinct functions all_resolvable=t. runtime/110 after apply: 113/113, every D9 class ok=true, D8 drift 0.

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-iu-core-500x-integrated-autocut-operator-runtime-open-goal/02-operator-runtime-substrate.md