KB-15C1

GPT Review — 23-P3C2 Prompt rev1 + Notification Roadmap Directive

12 min read Revision 1
gpt-reviewpack-23p3c2rev2-requiredapply-wrappernotification-outboxhermespg-native

GPT Review — 23-P3C2 Prompt rev1 + Notification Roadmap Directive

Date: 2026-05-07
Reviewer: GPT-5.5 Thinking / Incomex Hội đồng AI
Reviewed: knowledge/dev/laws/dieu44-trien-khai/prompts/23-p3c2-iu-apply-edit-functions-prompt.md rev1
New User requirement: PG-native notification/inbox logs for new comments and updates, separate lightweight logs, future Hermes/reviewer automation.

Verdict

P3C2 rev1 is directionally correct but NOT ready to dispatch. Rev2 required.

Opus correctly framed P3C2 as the dangerous write path and kept the objective narrow: fn_iu_apply_edit_draft + fn_iu_edit. However, rev1 has several concrete blockers that must be fixed before execution.

Separately, the new notification/log requirement is accepted as an important roadmap item. It should be recorded now, but not implemented inside P3C2, because P3C2 hard boundaries prohibit new DDL/triggers.

New requirement accepted: PG-native notification/outbox logs

The User requirement is valid and strategically important:

  • Reviewers/agents should not search manually to discover what changed.
  • The system should maintain lightweight lists of recent updates and comments.
  • Comment events and update/apply events should be separated.
  • These logs are not the same as general activity logs; they are operational work queues/inboxes for downstream processing.
  • This is the beginning of automated reviewer agents such as Hermes.

Create a future pack after P3C2 PASS, likely P3D — IU Notification Outbox / Reviewer Inbox.

PG-native, simple model:

  1. iu_comment_event_log / iu_comment_inbox_log

    • append-only, lightweight
    • populated by trigger after unit_edit_comment INSERT
    • captures: comment_id, draft_id, unit_id, canonical_address, author_ref, comment_kind, created_at, maybe short preview/hash
  2. iu_update_event_log / iu_update_inbox_log

    • append-only, lightweight
    • populated by trigger after official update/apply event, likely unit_version INSERT or unit_edit_draft transition to applied
    • captures: unit_id, canonical_address, version_id, version_seq, actor, applied_draft_id, created_at/applied_at
  3. Keep this separate from general activity log.

  4. Keep payload minimal. Large body/comment content should stay in canonical tables; event log stores references and short preview only.

  5. Index for reviewer/Hermes flows:

    • newest first (created_at DESC / event_at DESC)
    • status/pending if later needed
    • actor/unit filters
  6. Later combine with per-actor watermark model:

    • reviewer sees events newer than their last-view watermark;
    • latest 3–5 viewers derived from review-state table.

Why not in P3C2

P3C2 must not add tables/triggers. It should only create apply/wrapper functions. Adding notification logs now would expand scope and risk delaying the official edit path.

But P3C2 prompt/report should explicitly record:

  • notification outbox is not implemented yet;
  • after P3C2 PASS, P3D should design the comment/update event logs;
  • no production reviewer automation/Hermes should depend on notifications until P3D exists.

Accepted P3C2 direction

  • fn_iu_apply_edit_draft is the only Pack 23 function allowed to write IU/UV.
  • fn_iu_edit is a wrapper and should delegate official writes to apply.
  • Gateway marker fn_iu_apply_edit_draft is used in apply.
  • Invariant verification is required after official writes.
  • stale_base is enough for Phase 1; no rebase/merge complexity now.
  • Actor-card and per-actor watermark remain deferred hooks.

Required rev2 fixes

P1 — CRITICAL: content_anchor_ref must follow Pack 22 invariant, not draft hash

Rev1 sets:

content_anchor_ref = v_hash

But prior IU invariant says content_anchor_ref = version_anchor_ref::text. The old schema inspection explicitly captured that L2 requires content_anchor_ref = version_anchor_ref::text.

Patch:

content_anchor_ref = v_new_uv_id::text

Do not use content hash as the IU content anchor unless Pack 22 invariant has been changed and re-verified, which it has not.

P2 — JSON capture/parsing in tests is unsafe

Rev1 uses:

T1_JSON=$("${PSQL[@]}" <<EOSQL
SELECT public.fn_iu_apply_edit_draft(...);
EOSQL
)
T1_S=$("${PSQL[@]}" -t -A -c "SELECT ('$T1_JSON'::jsonb)->>'status';")

Plain psql output includes headers/formatting unless -t -A is used, and JSON may include quotes/newlines. This can break.

Patch tests to return status/key fields directly from SQL:

T1_P=$("${PSQL[@]}" -t -A <<EOSQL
WITH r AS (SELECT public.fn_iu_apply_edit_draft('$DRAFT_A_ID'::uuid,'agent:p3c2-test','P3C2 test apply') AS j)
SELECT j->>'status', j->>'version_id', j->>'version_seq', j FROM r;
EOSQL
)

Parse fields from T1_P. Do not echo captured JSON back into SQL.

Apply same fix to T10 and other JSON tests.

P3 — Avoid psql -c with :'var', but also avoid raw interpolation where possible

Rev1 notes the P3C1 caveat but still uses many raw shell interpolations. For UUIDs that are runtime-validated, shell interpolation is acceptable if carefully quoted. For address/body text, prefer heredoc and SQL literals generated inside SQL.

At minimum:

  • validate draft IDs with UUID regex before use;
  • validate TEST_ADDR_A is not empty and contains no single quote before raw interpolation;
  • avoid embedding arbitrary body text from shell.

P4 — Preflight Gate 5 must discover exact fn_iu_verify_invariants signature

Rev1 assumes:

public.fn_iu_verify_invariants(uuid)

This is likely correct but must be verified with to_regprocedure. If exact signature differs, STOP.

Also capture the signature in the report.

P5 — Unique constraint check must verify exact (unit_id, version_seq)

Rev1 accepts any unique constraint on unit_version, which can false-pass.

Patch using pg_index + pg_attribute exact attname array:

... i.indisunique
AND attname_array = ARRAY['unit_id','version_seq']

Expected exactly 1.

P6 — Lifecycle count uses fragile grep -c pattern

Rev1 uses:

UV_LC_COUNT=$(echo "$UV_LIFECYCLE" | grep -c . 2>/dev/null || echo "0")

This can produce 0\n0. Use SQL count directly:

SELECT count(DISTINCT lifecycle_status) FROM unit_version;

Also capture the single value separately.

P7 — Applying DRAFT_A marks DRAFT_B stale; then T10 on same address may depend on current state

This is acceptable, but rev2 should report state transitions explicitly:

  • before apply: A=open, B=open;
  • after apply A: A=applied, B=stale_base;
  • after wrapper T10: a new draft is created and applied.

This helps distinguish expected stale behavior from accidental draft closure.

P8 — fn_iu_apply_edit_draft should update IU title and updated_at in one UPDATE if possible

Rev1 performs two IU UPDATEs:

  1. anchor/update metadata;
  2. title JSON update if draft title is not null.

This is not fatal, but it fires update triggers twice and creates unnecessary churn.

Patch to one UPDATE information_unit SET ... identity_profile = CASE ... END statement.

P9 — Stale-base path mutates draft before returning; test it explicitly

Rev1 tests already-applied draft, but not stale-base due to head changed before apply. Add or adjust a test:

  • create a draft from current head;
  • move head via another apply/wrapper;
  • then apply old draft;
  • expected stale_base, no new UV, draft status becomes stale_base.

If this is too much for rev2, at minimum test that DRAFT_B is stale after applying A and cannot be applied.

P10 — fn_iu_edit wrapper must not auto-apply if policy is not exactly auto_apply

Rev1 treats all non-auto policies as require_review. Good. Add exact status field:

draft_created_review_required

and include policy in response. Add a test only if easily possible; otherwise report this as untested because current policy is auto_apply.

P11 — Source check should prove P3C1 function sources unchanged by hash

Rev1 only verifies P3C1 functions still exist. Since P3C2 should not alter P3C1, capture md5(prosrc) before and after for the 4 P3C1 functions.

Expected unchanged.

P12 — Security grantee checks should avoid raw role interpolation

Rev1 uses:

has_function_privilege('$R','public.$SIG','EXECUTE')

Use safer pattern via heredoc or validated role names. Since grantees are discovered from regrole::text, this is low risk, but rev2 should follow the safer P3C1 pattern if possible.

P13 — Cleanup behavior must acknowledge official writes are retained on test fail

If tests fail after successful apply, functions may be dropped but official version rows/comments remain. Do not imply full cleanup.

Report fields should include:

  • cleanup_on_test_fail=drop_p3c2_functions_only
  • official_test_rows_retained_on_fail=true
  • pilot_rows_retained=true

If this is unacceptable, redesign tests to run against dedicated pilot IU and retain it intentionally. Do not attempt destructive cleanup.

P14 — Add notification roadmap note to P3C2 prompt/report

Add a short section:

Notification / Hermes Outbox Hook (deferred)

Include:

  • comments and official updates should later feed separate lightweight PG-native logs;
  • comment log and update log must be separate;
  • logs are operational work queues, not general activity logs;
  • P3C2 does not implement them;
  • next recommended pack after P3C2 PASS: P3D notification outbox design.

P15 — Report should include invariant JSON output from apply

Rev1 returns invariants in JSON, but tests/report should capture and display it. Required for confidence.

P16 — fn_iu_edit source should be allowed to mention fn_iu_apply_edit_draft but not direct write SQL

T15 currently checks wrapper for gateway marker / INSERT UV / UPDATE IU. Good. Expand to include DELETE and INSERT INTO information_unit / UPDATE unit_version as in P3C1.

P17 — Final readiness should be p3d_readiness=READY only if notification/outbox is acknowledged as deferred

This avoids confusion: P3C2 PASS means edit workflow usable, but production reviewer automation still needs P3D notification outbox.

In report:

p3d_readiness=READY_FOR_NOTIFICATION_OUTBOX_DESIGN

or keep p3d_readiness=READY and add:

next_required_pack=P3D_NOTIFICATION_OUTBOX_BEFORE_HERMES

GPT recommendation: keep p3d_readiness=READY, add next_required_pack=P3D_NOTIFICATION_OUTBOX_BEFORE_HERMES.

Directive to Opus

Patch P3C2 prompt to rev2 with P1–P17.

Path:

knowledge/dev/laws/dieu44-trien-khai/prompts/23-p3c2-iu-apply-edit-functions-prompt.md

Additionally create or update a roadmap note:

knowledge/dev/laws/dieu44-trien-khai/design/23-p3d-notification-outbox-roadmap-note.md

Roadmap note should capture:

  • separate comment event log;
  • separate update/apply event log;
  • PG triggers are acceptable later;
  • logs are lightweight references/queues, not full body stores;
  • not the same as general activity log;
  • future Hermes/reviewer agent consumes these logs;
  • combine later with per-actor watermark review state.

Do not dispatch after patch. Return for GPT/User review.

Hard boundaries remain for P3C2 rev2 prompt

  • No dispatch.
  • No table DDL.
  • No trigger/gateway changes.
  • No vector mutation.
  • No cleanup.
  • No notification log implementation in P3C2.
  • No Pack 2C.

Summary

P3C2 is the right next step, but rev1 has one critical invariant bug (content_anchor_ref must be new UV id text, not content hash) and fragile JSON parsing in tests. The new notification requirement is accepted but should become a P3D roadmap/design item, not be squeezed into P3C2 execution.

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/reviews/gpt-review-23-p3c2-prompt-rev1-and-notification-roadmap-2026-05-07.md