Phase 3B — Hard Gate, Baseline, Backup
Phase 3B — Hard Gate, Baseline, Backup
HARD GATE 0 — Write channel probe
SELECT current_user, current_database(), version(),
pg_has_role(current_user,'workflow_admin','MEMBER') AS is_workflow_admin;
Result:
| current_user | current_database | version | is_workflow_admin |
|---|---|---|---|
| workflow_admin | directus | PostgreSQL 16.13 (Debian 16.13-1.pgdg13+1) | t |
Channel: SSH contabo → docker exec postgres → psql -U workflow_admin -d directus.
BEGIN/ROLLBACK probe (DDL + DML on TEMP table) — PASS.
Per [[feedback-mcp-query-pg-is-context-pack-readonly-no-phase3-writes]], MCP query_pg was bypassed — all writes use the SSH→docker→psql workflow_admin channel.
Phase 1/2/3 substrate confirmed live
SELECT (SELECT COUNT(*) FROM pg_proc WHERE proname='fn_iu_create') AS fn_iu_create,
(SELECT COUNT(*) FROM pg_proc WHERE proname IN (
'fn_job_enqueue','fn_job_claim','fn_job_ack','fn_job_fail_or_retry',
'fn_job_move_to_dead_letter','fn_queue_heartbeat_tick','fn_queue_stale_check',
'fn_job_reap_stale_leases_dry_run','fn_job_reap_stale_leases_apply',
'fn_job_dead_letter_requeue_dry_run','fn_job_dead_letter_triage_update',
'fn_queue_heartbeat_register_passive')) AS queue_fns,
(SELECT COUNT(*) FROM pg_class WHERE relname IN ('job_queue','job_dead_letter','queue_heartbeat')) AS queue_tabs,
(SELECT COUNT(*) FROM pg_class WHERE relname IN ('v_queue_health','v_job_queue_backlog','v_job_dead_letter_summary')) AS queue_views;
| fn_iu_create | queue_fns | queue_tabs | queue_views |
|---|---|---|---|
| 1 | 12 | 3 | 3 |
fn_iu_create signature (pre-fix)
public.fn_iu_create(
p_canonical_address text, p_title text, p_body text, p_actor text,
p_unit_kind text DEFAULT NULL,
p_section_type text DEFAULT NULL,
p_owner_ref text DEFAULT NULL,
p_publication_type text DEFAULT NULL,
p_parent_ref uuid DEFAULT NULL
) RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER
SET search_path TO 'pg_catalog','public'
md5(pg_get_functiondef) pre-apply: dcade99af1ef096892748c9f14082e11
Key insight: vocab validation is NOT hardcoded inside fn_iu_create body. It is delegated to:
v_st := public.fn_iu_resolve_default(p_section_type,'iu_create.default_section_type','vocab.section_type.');
IF v_st->>'status' NOT IN ('explicit','default','auto_single') THEN RAISE EXCEPTION 'section_type: %',v_st->>'message'; END IF;
fn_iu_resolve_default is generic: it looks up the explicit value via dot_config WHERE key = p_vocab_prefix || v_explicit_trimmed. The "13-item hardcoded vocab" mentioned in Phase 3 carry-forward is actually the row set of dot_config keys with prefix vocab.section_type. — a data-side gap, not a code-side gap.
Live vocab divergence baseline
tac_section_type_vocab (lifecycle_status='active'): 17 codes.
dot_config WHERE key LIKE 'vocab.section_type.%': 13 keys.
tac_section_type_vocab (17) |
dot_config vocab.section_type.* (13) |
|
|---|---|---|
| present in both | appendix, article, changelog, checklist, definition, governance_process, heading, instruction_block, paragraph, principle, process, technical_spec | (same 12) |
| only in tac (governed but missing from fn_iu_create vocab) | invariant_list, matrix, open_decision_list, rationale, reference_mapping (5) | — |
| only in dot_config (orphan, not in governed tac vocab) | — | section (1) |
PRE-FIX probe via fn_iu_resolve_default for each tac vocab value:
| section_type | resolve_status (pre-fix) | expectation |
|---|---|---|
| appendix, article, changelog, checklist, definition, governance_process, heading, instruction_block, paragraph, principle, process, technical_spec | explicit | EXPECT explicit |
| invariant_list, matrix, open_decision_list, rationale, reference_mapping | invalid | EXPECT invalid |
This confirms the Phase 3 pilot incident root cause: 5 governed values rejected at fn_iu_create boundary; pilot recovered via mid-flight jsonb_set patches on iu_staging_payload.payload_json (see [[feedback-mark-pieces-live-in-iu-staging-payload-cut-manifest-not-in-iu-staging-record-metadata]]).
Baseline row counts and state
| Metric | Value |
|---|---|
| event_outbox | 134,803 |
| information_unit | 192 |
| iu_vector_sync_point | 152 |
| job_queue | 6 (Phase 3 pilot) |
| job_dead_letter | 0 |
| queue_heartbeat | 2 (dieu45_phase3_pilot + iu_outbound_default) |
| iu_route_worker_cursor | 1 (iu_outbound_default, last_run 2026-05-22 11:31:41) |
| production_documents | ABSENT |
| pg_extension count | 4 (btree_gist, pgcrypto, plpgsql, postgres_fdw) |
Heartbeat snapshot (baseline):
| executor_name | executor_kind | last_tick_at | last_tick_status | ticks_total | metadata.marker |
|---|---|---|---|---|---|
| dieu45_phase3_pilot | external_worker | 2026-05-26 15:17:39 | ok | 2 | — |
| iu_outbound_default | PG_worker | 2026-05-22 11:31:41 | warn | 0 | legacy_silent_passive |
Gate states (baseline):
hc_executor_last_run | 2026-05-26T13:01:52+00:00
iu_core.composer_enabled | false
queue.dlq.replay_enabled | false
queue.heartbeat.enabled | true
queue.heartbeat.stale_threshold_seconds | 300
queue.job_substrate.enabled | false
queue.lease.duration_sec | 300
queue.lease.reaper_dry_run_only | true
queue.lease.reaper_enabled | false
queue.notify.enabled | false
queue.retry.backoff_base_sec | 10
queue.retry.max_attempts_default | 5
queue.runtime.phase | phase2_governance
queue.worker.enabled | false
Phase 3 Điều 37 pilot intact: 17 IUs with doc_code='knowledge/dev/laws/dieu37-governance-organization-law.md', canonical_address DIEU-37-v3.3#*, created_at 2026-05-26 15:17:38.
pg_dump pre-apply
| Field | Value |
|---|---|
| path | /tmp/dieu45_phase3b_pre_apply.dump |
| size | 83,241,085 bytes |
| sha256 | 28c2a683a3c3ca6b6898d57862702410cc582f4b00d40322528dd2bf7483ddf3 |
| format | pg_dump -Fc |
| taken | 2026-05-26 (before any Phase 3B mutation) |