23-P3C2 — Apply + Wrapper Functions — Execution Report (PASS)
23-P3C2 — Apply + Wrapper Functions — Execution Report
Date: 2026-05-07 Verdict: PASS P3D Readiness: READY Predecessor: 24-P3B-FU PASS (invariant generalized for current-anchor) Successor: P3C3 (natural save router) → P3D (notification outbox) Operator: Claude Opus 4.7 VPS: 38.242.240.89, container=postgres, db=directus
Verdict
PASS — public.fn_iu_apply_edit_draft(uuid,text,text) và public.fn_iu_edit(text,text,text,text,text,text) đã được install. Toàn bộ 19/19 tests PASS. Generalized invariant từ P3B-FU làm việc đúng — i3_anchors_exact=true post-apply (current UV anchor check), không còn FAIL như P3C2 rev7 lần đầu.
Executive Summary
| Item | Value |
|---|---|
| Phase status | PASS |
| Preflight | PASS |
| Function create | OK (atomic transaction) |
| Tests | 19/19 PASS, TEST_FAIL=0 |
| P3D readiness | READY |
| Pilot A (applied) | ea7fc2eb-d026-4e0e-bfe0-e12b0e0bc9f4 |
| Pilot B (stale_base) | f403cb0b-68f2-4e94-a972-6a889a7014fe |
| Test address | pilot.iu0.test-001 |
| New UV from T1 | afdd281a-c213-4078-9bb4-d327f7b6c735 (seq=2) |
| New UV from T11 | 36719826-3605-4834-ae2d-d681117d8211 |
| Owner | directus (verified T15) |
| Grantees | directus (PUBLIC revoked) |
| UV lifecycle | draft (count=1, deterministic) |
| State | IU 6→6, UV 6→8 (+2 from T1+T11), D 2→3, C 4→6 (+2 system comments) |
| P3C1 hashes unchanged | true (T17 PASS) |
| Invariant all_pass post-apply | true |
Generalized Invariant Verification
Invariant JSON từ T1 (fn_iu_apply_edit_draft):
{
"status": "applied",
"version_seq": 2,
"lifecycle_status": "draft",
"stale_drafts_count": 1,
"invariants": {
"all_pass": true,
"i1_iu_exists": true,
"i2_uv_linked": true,
"i3_anchors_exact": true,
"i4_birth_exists": true,
"i5_uv_birth_ok": true
}
}
i3_anchors_exact = true xác nhận: post-apply, IU's version_anchor_ref = new UV (seq=2), generalized fn validates current anchor đúng. Birth checks (i4/i5) vẫn dùng seq=1, vẫn pass.
Tests T1-T19
| # | Test | Result | Note |
|---|---|---|---|
| T1 | Apply DRAFT_A → status=applied | PASS | new UV seq=2, stale=1, inv all_pass=true |
| T2 | UV count +1 | PASS | 6→7 |
| T3 | IU anchors point to new UV | PASS | both refs = afdd281a... |
| T4 | DRAFT_A status=applied, applied_at, applied_version_ref | PASS | |
| T5 | System comment created (kind=system) | PASS | ≥1 |
| T6 | DRAFT_B → stale_base, stale_at NOT NULL | PASS | same unit_id auto-staled |
| T7 | Re-apply DRAFT_A → draft_not_open | PASS | |
| T8 | UV unchanged after T7 | PASS | |
| T9 | Apply stale DRAFT_B → draft_not_open | PASS | |
| T10 | Direct INSERT → IU Gateway blocked | PASS | |
| T11 | fn_iu_edit auto_apply → applied | PASS | new UV |
| T12 | UV +1 more from T11 | PASS | 7→8 |
| T13 | Same body again → no_change | PASS | |
| T14 | UV unchanged on no_change | PASS | |
| T15 | SECDEF + search_path + owner + PUBLIC revoke + grantees | PASS | both functions |
| T16_APPLY | apply has writer marker, UV insert, IU update, NO delete | PASS | |
| T16_WR | fn_iu_edit has NO write statements (delegates only) | PASS | |
| T17 | P3C1 hashes unchanged | PASS | edit_plan/create_edit_draft/comment_edit_draft/comment |
| T18 | IU count unchanged | PASS | |
| T19 | T1 invariant all_pass=true | PASS | i3 generalized works |
Function Bodies (deployed)
public.fn_iu_apply_edit_draft(uuid,text,text)
- LANGUAGE plpgsql VOLATILE SECURITY DEFINER, search_path=pg_catalog,public
- Owner: directus, REVOKE PUBLIC, GRANT EXECUTE TO directus
- Lifecycle self-determine (assert count(DISTINCT lifecycle_status)=1 → fail with
lifecycle_ambiguous) - Single IU UPDATE (anchors + identity_profile.title if draft_title), single UV INSERT
content_anchor_ref = new_uv_id::text- Stale-base detection (base_version_ref != current anchor) + auto-stale sibling open drafts
- Hash mismatch / no_change short-circuits before write
- Invariant call post-write; raise exception on fail
- Writer marker:
set_config('app.canonical_writer','fn_iu_apply_edit_draft',true) - Returns: applied / draft_not_found / draft_not_open / stale_base / draft_hash_mismatch / no_change / lifecycle_ambiguous / invalid_input
public.fn_iu_edit(text,text,text,text,text,text)
- LANGUAGE plpgsql VOLATILE SECURITY DEFINER, search_path=pg_catalog,public
- Owner: directus, REVOKE PUBLIC, GRANT EXECUTE TO directus
- NO direct writes (T16_WR PASS) — delegates to
fn_iu_create_edit_draftthenfn_iu_apply_edit_draft - Reads
identity_profile.edit_policy→ fallbackdot_config.iu_edit.policy.default_mode→ fallbackauto_apply - If
auto_apply→ apply automatically; else returnsdraft_created_review_required - Internal convenience layer (P3C2 prompt note: not final AI front-door — that role goes to fn_iu_save in P3C3)
Security & Boundary Compliance
- ❌ No table DDL / no trigger / no gateway changes
- ❌ No P3C1 alterations (T17 PASS)
- ❌ No direct IU/UV writes outside
fn_iu_apply_edit_draft(writer marker enforced; T10 gateway blocks raw insert) - ❌ No vector mutation, no cleanup, no notification (deferred to P3D)
- ✅ SECURITY DEFINER on both new functions (T15)
- ✅ search_path=pg_catalog,public (T15)
- ✅ Owner=directus matches
fn_iu_create(T15) - ✅ PUBLIC EXECUTE revoked, only directus has EXECUTE (T15)
State Counts
| Table | Before | After | Δ |
|---|---|---|---|
| information_unit | 6 | 6 | 0 |
| unit_version | 6 | 8 | +2 (T1 seq=2, T11 seq=3) |
| unit_edit_draft | 2 | 3 | +1 (T11 created via fn_iu_edit) |
| unit_edit_comment | 4 | 6 | +2 (system comments from T1 + T11) |
Test rows retained on PASS (no cleanup per prompt — official_test_rows_retained=true).
Roadmap Chain
- Now (this report): P3C2 PASS — apply + edit wrapper functions deployed.
- Next required:
P3C3_NATURAL_SAVE_ROUTER_BEFORE_BROAD_AGENT_USE- Design:
knowledge/dev/laws/dieu44-trien-khai/design/23-p3c3-iu-natural-save-router-design-note.md - Will introduce
fn_iu_saveas the AI front-door (auto-routes new vs edit by canonical_address presence).
- Design:
- Deferred to P3D: notification outbox before Hermes production.
- Roadmap:
knowledge/dev/laws/dieu44-trien-khai/design/23-p3d-notification-outbox-roadmap-note.md
- Roadmap:
AI Interface Surface (P3C2 — internal layer)
fn_iu_edit_plan(address, body, actor) -- preview
fn_iu_create_edit_draft(address, body, actor) -- draft
fn_iu_comment(address, author, body) -- comment (free-flow, no approval)
fn_iu_apply_edit_draft(draft_id, actor) -- apply (approval gate)
fn_iu_edit(address, body, actor, reason) -- internal convenience wrapper
Future P3C3: fn_iu_save(address, body, actor) = AI front-door (auto-route new vs edit).
Logs
- VPS log:
/tmp/23-p3c2.20260507-113813.log - Local:
/tmp/23-p3c2.sh