24-P3B-FU — Generalize fn_iu_verify_invariants — Execution Report (PASS)
24-P3B-FU — Generalize fn_iu_verify_invariants — Execution Report
Date: 2026-05-07 Verdict: PASS Predecessor: 23-P3C2 (FAIL — invariant birth-only) Successor: re-run 23-P3C2 with current-anchor invariant Operator: Claude Opus 4.7 VPS: 38.242.240.89, container=postgres, db=directus
Verdict
PASS — public.fn_iu_verify_invariants(text) đã được generalize. i3_anchors_exact giờ validate IU's anchors chống lại UV identified by version_anchor_ref (current), thay vì version_seq=1. Birth checks (i4/i5) vẫn dùng version_seq=1. Signature, return type, owner, SECDEF, search_path, volatility — preserved exactly.
Executive Summary
| Item | Value |
|---|---|
| Phase status | PASS |
| Preflight | PASS |
| Function replace | OK (after fix) |
| Tests | 10/10 PASS |
| Before hash | bd32cc76426e19f7f79bd8480a1e5be8 |
| After hash | 6d005323d15eb4802f22802470b2c966 |
| Owner | directus (unchanged) |
| SECDEF | f (unchanged — INVOKER) |
| Volatility | STABLE (unchanged) |
| search_path | pg_catalog, public (unchanged) |
| Return type | jsonb (unchanged) |
| Signature | p_addr text -> jsonb (unchanged) |
| P3C1 hashes | unchanged (T8 PASS) |
| State counts | IU=6→6, UV=6→6 |
| Pilot | pilot.iu0.test-001 (all_pass=true) |
Pre-COMMIT Assertions (A1-A4)
Tất cả assertions chạy bên trong transaction trước COMMIT — pass cleanly:
- A1 pilot all_pass — PASS
- A2 all 6 existing IUs all_pass — PASS
- A3 error paths (NULL→invalid_input, empty→invalid_input, bogus→not_found) — PASS
- A4 source markers (
version_anchor_ref✓,version_seq = 1✓,birth_registry✓) — PASS
Post-COMMIT Tests (T1-T10)
| # | Test | Result |
|---|---|---|
| T1 | Pilot pilot.iu0.test-001 all_pass=true |
PASS |
| T2 | All 6 IUs all_pass | PASS (0 failing) |
| T3 | Invalid_input on NULL/empty/whitespace | PASS |
| T4 | not_found on bogus address | PASS |
| T5 | Signature p_addr text -> jsonb |
PASS |
| T6 | Owner/SECDEF/config exact match | PASS (own=directus secdef=f cfg={"search_path=pg_catalog, public"}) |
| T7 | Hash actually changed | PASS (bd32cc76… → 6d005323…) |
| T8 | P3C1+create+content_hash hashes unchanged | PASS |
| T9 | Source markers present | PASS |
| T10 | State counts unchanged | PASS (IU=6, UV=6) |
Issue gặp phải khi chạy theo prompt rev3
Prompt rev3 §2 viết body với LANGUAGE plpgsql VOLATILE SECURITY DEFINER — mâu thuẫn với hard-boundary "Do not change SECDEF" và với original function (STABLE, no SECURITY DEFINER, secdef=f). Lần run đầu, function được tạo với secdef=t, volatile=v → T6 FAIL (FAIL_SD sd=t exp=f).
Fix taken (within boundaries): Re-issued CREATE OR REPLACE FUNCTION với cùng body nhưng đúng clause LANGUAGE plpgsql STABLE SET search_path=pg_catalog,public (no SECURITY DEFINER, default INVOKER) — preserves original SECDEF and volatility. Body content (prosrc) identical to prompt's intended body. Vẫn chỉ touch một function duy nhất, không tạo overload, không đổi signature.
Lý do chọn fix theo hướng này: hard boundaries trong prompt body và user prompt explicit "Không đổi signature/return type/owner/SECDEF/search_path" có precedence cao hơn DDL clauses của prompt rev3. Volatility STABLE cũng được preserved (không bị list ra explicit, nhưng safer to match).
Pre-Function DDL Backup
CREATE OR REPLACE FUNCTION public.fn_iu_verify_invariants(p_addr text)
RETURNS jsonb
LANGUAGE plpgsql
STABLE
SET search_path TO 'pg_catalog', 'public'
AS $function$
DECLARE v_iu_id uuid;v_var uuid;v_car text;v_uv record;v_uv_count int;v_uv_strategy text;
v_has_birth boolean;v_anchor_exact boolean;v_uv_birth_ok boolean;
BEGIN
IF p_addr IS NULL OR btrim(p_addr)='' THEN RETURN jsonb_build_object('status','invalid_input','message','canonical_address NULL/empty'); END IF;
SELECT id,version_anchor_ref,content_anchor_ref INTO v_iu_id,v_var,v_car FROM public.information_unit WHERE canonical_address=btrim(p_addr);
IF v_iu_id IS NULL THEN RETURN jsonb_build_object('status','not_found','canonical_address',btrim(p_addr)); END IF;
SELECT count(*) INTO v_uv_count FROM public.unit_version WHERE unit_id=v_iu_id AND version_seq=1;
IF v_uv_count=0 THEN RETURN jsonb_build_object('i1_iu_exists',true,'i2_uv_linked',false,'i3_anchors_exact',false,'i4_birth_exists',false,'i5_uv_birth_ok',true,'all_pass',false,'issue','missing_version'); END IF;
IF v_uv_count>1 THEN RETURN jsonb_build_object('i1_iu_exists',true,'i2_uv_linked',true,'i3_anchors_exact',false,'i4_birth_exists',false,'i5_uv_birth_ok',true,'all_pass',false,'issue','duplicate_version'); END IF;
SELECT * INTO v_uv FROM public.unit_version WHERE unit_id=v_iu_id AND version_seq=1;
v_has_birth:=COALESCE((SELECT EXISTS(SELECT 1 FROM public.birth_registry WHERE collection_name='information_unit' AND entity_code='information_unit::'||v_iu_id::text)),false);
v_anchor_exact:=COALESCE(v_var=v_uv.id AND v_car=v_uv.id::text AND v_uv.unit_id=v_iu_id,false);
SELECT birth_code_strategy INTO v_uv_strategy FROM public.collection_registry WHERE collection_name='unit_version';
IF v_uv_strategy='subordinate' OR v_uv_strategy IS NULL THEN
v_uv_birth_ok:=NOT EXISTS(SELECT 1 FROM public.birth_registry WHERE collection_name='unit_version' AND entity_code='unit_version::'||v_uv.id::text);
ELSE
RETURN jsonb_build_object('i1_iu_exists',true,'i2_uv_linked',true,'i3_anchors_exact',v_anchor_exact,'i4_birth_exists',v_has_birth,'i5_uv_birth_ok',false,'all_pass',false,'issue','uv_strategy_changed','uv_strategy',v_uv_strategy);
END IF;
RETURN jsonb_build_object('i1_iu_exists',true,'i2_uv_linked',true,'i3_anchors_exact',v_anchor_exact,'i4_birth_exists',v_has_birth,'i5_uv_birth_ok',v_uv_birth_ok,'all_pass',(v_anchor_exact AND v_has_birth AND v_uv_birth_ok));
END;$function$
Post-Function DDL (current)
LANGUAGE plpgsql STABLE SET search_path=pg_catalog,public. Body khác bản gốc ở:
- Thêm
SELECT * INTO v_uv_current FROM unit_version WHERE id = v_var;— fetch UV identified byversion_anchor_ref(current). - Tách
v_uv_birth(version_seq=1) khỏiv_uv_current. v_anchor_exactso sánhv_var = v_uv_current.id(current),v_car = v_uv_current.id::text,v_uv_current.unit_id = v_iu_idthay vì so sánhv_uv_birth.i5_uv_birth_okvẫn dùngv_uv_birth.id(birth UV), không đổi.issuecodes mở rộng:missing_birth_version,duplicate_birth_version.
Boundary Compliance
- ❌ No table DDL — confirmed
- ❌ No trigger / gateway changes — confirmed
- ❌ Other functions unchanged — T8 PASS
- ❌ No IU/UV/draft/comment writes — T10 IU=6→6 UV=6→6
- ❌ No vector mutation, no notification, no cleanup
- ❌ Signature/return/owner/SECDEF/search_path unchanged — T5 + T6 PASS
- ❌ No new overload — confirmed (one function exists at
(text)->jsonb)
Next Required Action
- Pack:
23-P3C2_RE_RUN_AFTER_INVARIANT_GENERALIZED - Prompt:
knowledge/dev/laws/dieu44-trien-khai/prompts/23-p3c2-iu-apply-edit-functions-prompt.md
Recommendation: bug fix prompt rev3
§2 prompt nên đổi LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path=pg_catalog,public → LANGUAGE plpgsql STABLE SET search_path=pg_catalog,public để thẳng hàng với hard-boundary "Do not change SECDEF" và T6 exact match check. Cập nhật rev4 trước khi dùng cho similar packs.
Logs
- VPS log đầu (with FAIL):
/tmp/24-p3bfu.20260507-110517.log - VPS log thứ hai (with FAIL T6/T7):
/tmp/24-p3bfu.20260507-110621.log - Final corrected DDL applied directly via
docker exec ... psql, tests-only run via/tmp/24-p3bfu-tests.sh— TEST_FAIL=0.