KB-32F8

40000x · 07 — Lessons

6 min read Revision 1
iu-core40000xlessonsfeedbackchannel-driftcolumn-naming

40000x · 07 — Lessons

L1 — Channel memory drifts; verify the container/DB names live, every macro

What happened. Prior macro reports and the auto-memory consistently referenced an incomex-postgres container and an incomex_workflow database. At the start of 40000x neither existed — the IU Core schema (175 IUs, 4 templates, 13 auto-instantiate rows, …) lives in the directus database inside a single postgres container.

Why. Containers and databases get renamed / consolidated between macros without the prior macro's report being updated. Memory snapshots freeze a name that was true at write time.

Rule. Before any live channel use in a new macro, run:

ssh root@contabo "docker ps --format '{{.Names}}\t{{.Image}}'"
ssh root@contabo "docker exec <pg-container> psql -U <user> -At -c 'select datname from pg_database where datistemplate=false order by datname'"

…and pick the DB by querying for the canonical schema (e.g. select count(*) from information_unit) rather than by name. This adds ~30s of latency and saves a wasted apply on the wrong DB.

→ [[feedback-channel-memory-drifts-verify-live]]

L2 — dot_iu_command_run.command_name, not .command

What happened. The first cut of the 034 rollback file guarded against orphaning run history with a query against dot_iu_command_run.command WHERE …. Live psql refused — column "command" does not exist. The column is command_name.

Why. The DOT catalog (dot_iu_command_catalog) uses command_name as its PK; the run-audit table mirrors that. Easy to write .command from muscle memory of the more common naming.

Rule. When authoring SQL that references the operator-runtime tables, \d the table first (or grep migration 018) — both dot_iu_command_catalog and dot_iu_command_run use command_name.

→ [[feedback-dot-iu-command-tables-use-command-name]]

L3 — Retention substrate's fn_iu_core_retention_cleanup hard-codes the actor column as actor

What happened. When registering iu_auto_instantiate_event_log (which uses triggered_by, not actor) into iu_core_retention_policy, an actor-scoped policy would have generated SQL referencing a non-existent actor column and the dry-run itself would fail at parse time. 40000x sidesteps with actor_scope=NULL (age-only).

Why. Migration 025's fn was authored when every retention-eligible table happened to use the literal column name actor. The first table to break the convention is migration 033's audit log.

Rule. When adding a new append-only log table that should be retention-eligible AND uses a non-actor actor column, prefer one of:

  • Use the table's dedicated actor-scoped fn (here: fn_iu_auto_instantiate_rollback_by_actor) for actor-scoped pruning, and register an actor_scope=NULL row for age-based pruning — the path 40000x took.
  • Or extend iu_core_retention_policy with actor_column text DEFAULT 'actor' and teach the central fn to read it — clean but bigger surface, a future macro decision.

→ [[feedback-retention-fn-hardcodes-actor-column]]

L4 — Honest PARTIAL > fake PASS

What happened. The 40000x prompt sized the macro at 55–60 min and 10 objectives. After the baseline phase made clear that a single Claude response could not execute all 10 with real evidence, the macro was narrowed (with explicit user confirmation) to a focused B + C + H + I + J subset, and D / E / F / G were filed as carry-forward with package outlines.

Why. The constitution prohibits "no fake PASS". The honest move is to mark scope reality and produce real evidence on a real subset.

Rule. When the prompt's scope and the realistic single-response capacity diverge, ask once (using the AskUserQuestion tool, not chit-chat) with three concrete options (focused subset / author-only / full attempt), then proceed deterministically with the chosen option and label every phase honestly.

→ [[feedback-honest-partial-over-fake-pass]]

L5 — Pinning bump per macro is 3 sites for DOT, not 2

What happened. Memory said "pinning tests bump per macro" with one test counted. For DOT-catalog counts there are three sites, not one — test_iu_core_500x_…, test_iu_core_540x_…, and the SSOT comment block in runtime/280_…seed.sql (plus the seed's expected_N literal). All four must move in the same commit or pytest and psql -f runtime/280… will diverge.

Why. 540x added a hard pin in the SQL seed for SSOT-vs-Python lock; 500x added a separate "governed count" assertion. Both must follow the catalog row count.

Rule. For DOT-catalog count changes (24 → 26 here), update all four:

  • sql/iu-core/runtime/280_operator_runtime_catalog_seed.sqlINSERT VALUES (…) rows + expected_N literal + closing-comment row count.
  • cutter_agent/iu_core/dot_commands.py_REGISTRY entries + module docstring count.
  • tests/test_iu_core_500x_operator_surface.py::test_twenty_governed_commandsassertEqual(len(governed), N).
  • tests/test_iu_core_540x_operator_runtime.py::test_seed_row_count_matches_governed_registryassertEqual(len(governed), N) AND assertIn("= N", self.sql).

→ refreshes [[feedback-pinning-tests-bump-per-macro]] (DOT catalog → 3 sites; D9 → 1 site; both classes go in the same commit).

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-iu-core-40000x-orchestrator-dot-retention-readiness-open-goal/07-lessons.md