40000x · 07 — Lessons
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 anactor_scope=NULLrow for age-based pruning — the path 40000x took. - Or extend
iu_core_retention_policywithactor_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.sql—INSERT VALUES (…)rows +expected_Nliteral + closing-comment row count.cutter_agent/iu_core/dot_commands.py—_REGISTRYentries + module docstring count.tests/test_iu_core_500x_operator_surface.py::test_twenty_governed_commands—assertEqual(len(governed), N).tests/test_iu_core_540x_operator_runtime.py::test_seed_row_count_matches_governed_registry—assertEqual(len(governed), N)ANDassertIn("= N", self.sql).
→ refreshes [[feedback-pinning-tests-bump-per-macro]] (DOT catalog → 3 sites; D9 → 1 site; both classes go in the same commit).