Branch A — P0 Post-Cut Axis Autowire Fix (FIXED, live) (2026-05-29)
Branch A — P0 Post-Cut Axis Autowire Fix
Doc 01 (2026-05-29) — Status: FIXED, committed live, reversible
1. Precise root cause (refined from the audit)
The audit said "post-cut axis autowire is not wired." Live investigation pinned the exact defect:
fn_cut_complete(p_cut_request_id uuid, p_actor text)finalizes a cut (statuscut_verified→completed→cleanup_scheduled, signalscut.complete). It had no call tofn_iu_post_cut_axis_materialize. Confirmed: a scan of all PL/pgSQL functions found none referencingpost_cut_axis_materializeexcept the materialize function itself, and no function callsfn_cut_complete(it is invoked externally).- A statement-level trigger
trg_iu_three_axis_envelope_auto_refresh_iu(AFTER INS/UPD/DEL oninformation_unit, gated byiu_core.three_axis_auto_refresh_enabled) already refreshes the three-axis envelope on IU writes. So envelope refresh was NOT the gap. - The gap is specifically the axis-B tag application that only
fn_iu_post_cut_axis_materializeperforms: ensuringiu_metadata_tag_registryrows and applyingdoc:,kind:,sectype:tags to the cut's IUs. No trigger or function applied these automatically after a cut — only a manual DOT (iu.post_cut.axis_materialize) did. Hence "new cuts may not auto-refresh axis B."
Current drift: none. The two completed cuts (DIEU-39, DIEU-38) had their tags applied manually — DIEU-39: 16/16 IUs tagged; DIEU-38: 8/8 tagged. The bug is mechanism (manual, not auto), not present data corruption.
2. Deterministic doc_code resolution (the enabler)
fn_iu_post_cut_axis_materialize is keyed by doc_code; cut_request has no doc_code column. Discovery: information_unit.doc_code == cut_request.source_ref (both = e.g. knowledge/dev/laws/dieu39-knowledge-graph-law.md). Verified live:
| cut_request | source_ref | IUs with matching doc_code | already doc-tagged |
|---|---|---|---|
| e15cabe9 (DIEU-39) | …dieu39…md | 16 | 16 |
| 777b1297 (DIEU-38) | …dieu38…md | 8 | 8 |
⇒ fn_iu_post_cut_axis_materialize(v_req.source_ref, p_actor) is the correct, deterministic wire.
3. The fix (minimal, gated, best-effort, idempotent)
CREATE OR REPLACE FUNCTION public.fn_cut_complete(...) — identical to the original through the cut.complete signal, then inserts before RETURN:
IF (SELECT value = 'true' FROM public.dot_config
WHERE key = 'iu_core.three_axis_auto_refresh_enabled') THEN
BEGIN
v_axis_autowire := public.fn_iu_post_cut_axis_materialize(v_req.source_ref, p_actor)
|| jsonb_build_object('attempted', true);
EXCEPTION WHEN OTHERS THEN
v_axis_autowire := jsonb_build_object('attempted', true, 'ok', false, 'error', SQLERRM);
RAISE WARNING 'fn_cut_complete: post-cut axis materialize failed for source_ref=% (cut %): %',
v_req.source_ref, p_cut_request_id, SQLERRM;
END;
END IF;
and adds 'axis_autowire', v_axis_autowire to the returned JSON. (Full DDL in Doc 07.)
Design properties:
- Gated on the existing governable gate
iu_core.three_axis_auto_refresh_enabled— no new config key. Defaultfalse⇒ runtime behaviour unchanged. This also makes that gate meaningful for cuts (previously it governed only the envelope trigger; now it also governs post-cut tag materialization). Activation = open the gate via the normal protocol. - Best-effort: the materialize runs in a PL/pgSQL sub-transaction; any failure is caught, logged as a WARNING, and cannot roll back or block cut completion.
- Idempotent: materialize uses
ON CONFLICT DO NOTHING(tags) +NOT EXISTS(registry) + upsert envelope refresh — safe to re-run; no double execution. - No vector / no body / no law mutation: touches only
iu_metadata_tag(_registry)+iu_three_axis_envelope.
4. Evidence (dress-rehearse → commit → fresh-verify)
Rehearsal (BEGIN..ROLLBACK):
- Standalone determinism+idempotency:
fn_iu_post_cut_axis_materialize('…dieu39…md','canary')→ok=true, iu_count=16, new_tags_total=0, envelope 219/219. - Gate value
false(deployment behaviour-preserving). - Full-wire canary: gate set
truein-tx, cut e15cabe9 reset tocut_verifiedin-tx,fn_cut_complete(e15cabe9,'canary')→axis_autowire={attempted:true, ok:true, iu_count:16, new_tags_total:0}. ROLLBACK → gate back tofalse, all reverted.
Commit: CREATE OR REPLACE inside BEGIN/COMMIT.
Fresh-connection verify (read-only MCP): autowire_present=true, gate_guarded=true, gate_value=false, all_safe=true, never_flip_intact=true, idle-tx 0, iu 219 / iu_metadata_tag 536 unchanged.
5. Activation (for a human, later)
To turn post-cut axis-B auto-materialization ON: open the governable gate iu_core.three_axis_auto_refresh_enabled via fn_iu_gate_open(...) (bounded TTL). From then, every fn_cut_complete auto-applies axis-B tags for the cut source. To turn off: fn_iu_gate_close(...). No code change needed either way.
6. Rollback
Restore the original fn_cut_complete via CREATE OR REPLACE with the verbatim pre-fix definition (Doc 07 §1). Reversible at any time; no data migration involved.