IU Core 500x — 03 DOT one-command operator surface
03 — DOT one-command operator surface
1. The problem
The 240x/480x composer gave every operation a single SQL function, and
composer.COMPOSER_COMMANDS mapped a dot_iu_* name to it. But an operator
still had to (a) remember each function's raw signature, and (b) know the
multi-step sequences — and the third piece-disposal verb, soft-delete with
rollback, had no governed function at all.
2. migration 017 — governed soft-delete / restore
017_dot_operator_surface.sql adds the missing governed primitive — and its
inverse, so soft-delete is reversible by one command:
fn_iu_piece_soft_delete(uuid, text)— stampsdeleted_at. Gated by the composer gate. Fail-closed: refuses an unknown piece, no-ops on an already-deleted piece, refuses anenactedpiece (an enacted IU retires through the'retired'lifecycle, never soft-delete), and refuses a piece still active in any collection — the operator mustdot_iu_remove_pieceit first. This keeps the three disposal verbs crisply ordered and stops a soft-delete silently breaking a composition.fn_iu_piece_restore(uuid, text)— clearsdeleted_at; the exact inverse.
Both write information_unit the governed way: they set the IU Gateway
canonical-writer marker GUC (key discovered from dot_config, never
hardcoded) to the allow-listed 'fn_iu_structure_op' token, exactly as
fn_iu_structure_op_apply does. DOT: function 36 → 38 / total → 106.
Reversible via rollback/017.
3. The three-way piece-disposal distinction
| verb | command | mechanism | effect | reverse |
|---|---|---|---|---|
| remove from collection | dot_iu_remove_piece |
fn_iu_collection_remove_piece (015) |
membership ends; piece lives, keeps other memberships | dot_iu_add_piece |
| retire globally | dot_iu_retire_piece |
deprecate_piece structure op (012) |
lifecycle_status='deprecated' everywhere |
fn_iu_structure_op_rollback |
| soft-delete | dot_iu_delete_piece_soft |
fn_iu_piece_soft_delete (017) |
deleted_at stamped; vanishes from every render/validate/compose path |
dot_iu_restore_piece |
4. cutter_agent/iu_core/dot_commands.py — the operator surface
A pure module (no IO, no DB — the composer.py precedent). 17 dot_iu_*
commands across 5 categories (collection / piece / lifecycle / read /
health). Each resolves to a DotCommandPlan — an ordered tuple of
ready-to-run governed SQL + description + reversal note. build() is
fail-closed (rejects a missing required / unknown parameter).
dot_iu_retire_piece resolves to a self-contained DO block that runs the
deprecate_piece plan+apply and RAISE NOTICEs the op id for rollback — so
even a multi-step lifecycle op is still one statement for the operator.
sql_literal doubles every embedded quote (injection-inert). CLI:
list / help <cmd> / explain <cmd> k=v… — explain prints the SQL,
never executes. composer.COMPOSER_COMMANDS extended 12 → 17 with the
lifecycle verbs.
5. sandbox/120 — proof on the production schema
120_dot_operator_surface_probe.sql — one BEGIN…ROLLBACK, zero durable
rows, 8/8 probes pass (SANDBOX_120_VERDICT all_pass=t):
O1both functions installed;O2soft-delete stampsdeleted_at(ok=true);O3restore clears it (ok=true);O4soft-delete refuses an active collection member;O5soft-delete gated — composer gate shut ⇒ refused;O6remove-from-collection leaves the piece alive, then soft-delete succeeds — the verbs compose in the documented order;O7restore of a live piece is a safe no-op (ok=false);O8soft-delete refuses an unknown piece.
6. Tests
test_iu_core_500x_operator_surface.py — 36 tests: migration 017 shape +
gating + governed marker, sandbox/120 coverage, runtime/110 at 106, the
delayed-lane fix, the 17-command registry, the three-way distinction, the
sql_literal quoting/injection contract, every command resolving to a
DOT-visible target, the CLI. Suite 843 → 879.