KB-3AC5

23-P3A — IU Edit Draft Approach Note (Opus Phản biện GPT)

14 min read Revision 1
pack-23p3aapproachedit-draftcommentapplyassembly-firstpg-native

23-P3A — IU Edit Draft Approach Note (Opus Phản biện GPT)

Date: 2026-05-06 Author: Opus (Claude) Status: APPROACH NOTE — chờ GPT/User review. Không implement. Supersedes: 23-P3 design pack (Model D hybrid) — kiến trúc gốc giữ lại, thuật ngữ và framing thay đổi.


Mục tiêu bài toán

AI/Agent cần sửa miếng thông tin (IU) một cách an toàn: tạo bản nháp → thảo luận → duyệt/áp dụng → version mới tự động. Agent không cần nhớ version_seq, birth, anchor, gateway marker, hay direct table write.

Nôm na: Sổ biên tập — ai muốn sửa thì viết bản nháp lên sổ, đồng nghiệp ghi chú góp ý, tổng biên tập duyệt xong thì bản chính tự cập nhật. Ai sửa gì, ai góp ý gì, lúc nào — đều có ghi.


Non-goals (Phase 1)

  • Không xây Git: không branch, không 3-way merge, không diff engine, không rebase.
  • Không xây review UI: review qua function call, không cần giao diện phức tạp.
  • Không concurrent conflict resolution: stale base = từ chối, tạo draft mới.
  • Không vector update khi apply.
  • Không role separation (self-apply OK Phase 1).
  • Không edit/delete comment (append-only).

Opus phản biện GPT — 10 câu hỏi

Q1. Tên bảng: unit_edit_draft / unit_edit_comment hay unit_proposal?

Đồng ý GPT — dùng unit_edit_draft + unit_edit_comment.

Lý do:

  • "draft" là ngôn ngữ biên tập, Agent hiểu ngay: "tạo bản nháp, duyệt bản nháp, áp dụng bản nháp".
  • "proposal" gợi Git/PR — đúng kỹ thuật nhưng tạo kỳ vọng sai (Agent nghĩ phải có branch, diff, rebase...).
  • Tên bảng = API surface cho Agent. Dễ hiểu = ít lỗi gọi.

Namespace: unit_edit_draftunit_edit_comment nhất quán với information_unit, unit_version — prefix unit_ cho domain IU.

Q2. Reuse bảng có sẵn hay tạo mới?

Đề xuất tạo mới. Không reuse Directus internal.

Tôi đã kiểm tra qua inspection 23-P2: Directus có directus_revisions (item snapshot), directus_activity (audit log), directus_notifications. Nhưng:

  • directus_revisions gắn chặt Directus collection/item ID. IU dùng canonical_address + PG function path, không qua Directus CRUD. Reuse = phải fake Directus item context hoặc bypass Directus internal logic.
  • directus_activity là audit trail của Directus operations, không phải domain comment.
  • Coupling domain logic vào Directus internal = fragile. Directus upgrade có thể break.

Assembly First check: PG CREATE TABLE + 2 functions = chi phí thấp, ổn định, không phụ thuộc external. Đây đúng là "tận dụng PG native" — relational table là primitive cơ bản nhất.

Q3. Replacement body hay diff/patch?

Đồng ý GPT — Phase 1 = replacement body toàn phần.

Lý do Assembly First:

  • PG không có diff engine native. Muốn diff phải custom code hoặc extension → vi phạm "code custom là phương án cuối".
  • Replacement body: 1 column text, đọc thẳng, so sánh bằng content_hash, apply = copy thẳng sang UV.
  • Diff chỉ là view concern — hiển thị cho người dùng "thay đổi gì" — có thể compute runtime bằng PG regexp_split_to_array hoặc Nuxt client-side, không cần lưu.

Q4. Khi apply draft, các draft khác xử lý sao?

Không đồng ý GPT hoàn toàn. Đề xuất: mark stale_base thay vì supersede.

GPT đưa 3 options. Phân tích:

Option Ưu Nhược
Supersede all active Sạch, dễ hiểu Draft bị đóng vĩnh viễn. Nếu Phase 2 có rebase, phải tạo lại từ đầu.
Mark stale_base Thông tin hơn, giữ draft sống Drafts tích lũy nếu không dọn
Keep open + warning Linh hoạt nhất Phức tạp, dễ nhầm

Đề xuất: Mark stale_base — cùng đơn giản như supersede (1 UPDATE), nhưng giữ ngữ nghĩa rõ hơn:

  • stale_base = "base đã cũ, draft này không áp dụng được nữa trừ khi tạo lại".
  • Phase 1: stale_base = effectively closed (không có rebase).
  • Phase 2: stale_base có thể rebase — không cần recreate.

Status flow:

draft → open → applied
              → stale_base (khi draft khác được apply cùng IU)
              → withdrawn (tác giả tự rút, Phase 2)

Đơn giản hơn 23-P3 cũ (bỏ rejected, superseded, proposed — quá nhiều trạng thái kiểu Git).

Q5. Approval comment bắt buộc Phase 1?

Đồng ý GPT — policy hook, không bắt buộc global.

Phase 1:

  • Default = auto_apply (Agent tạo draft + apply cùng transaction qua fn_iu_edit).
  • Protected/enacted IU: require_review → draft chờ, phải có apply riêng.
  • Policy source: dot_config key iu_edit.default_apply_policy = auto_apply. Per-IU override qua identity_profile->>'edit_policy'.

Approval comment không bắt buộc cho apply. Reviewer gọi fn_iu_apply_edit_draft là đủ — review_note trong function signature ghi lý do.

Q6. Gateway allow-list cần function nào?

Đồng ý GPT — chỉ function ghi IU/UV cần marker.

Function Ghi bảng nào Cần gateway marker?
fn_iu_create IU + UV ✓ Đã có
fn_iu_apply_edit_draft UV + IU anchors ✓ Cần thêm
fn_iu_edit Wrapper gọi apply bên trong ✓ Cần thêm
fn_iu_create_edit_draft unit_edit_draft only ✗ Không
fn_iu_comment_edit_draft unit_edit_comment only ✗ Không

Allow-list = 3 markers: fn_iu_create, fn_iu_apply_edit_draft, fn_iu_edit.

Giống kết luận 23-P3 cũ, chỉ đổi tên fn_iu_merge_edit → fn_iu_apply_edit_draft.

Q7. Title edit?

Đề xuất: Phase 1 cho draft_title nullable.

Lý do: title là metadata quan trọng, sửa title cùng lúc body là use case thường xuyên. Tách thành 2 operations = phiền.

Apply logic: nếu draft_title IS NOT NULL → update identity_profile = jsonb_set(identity_profile, '{title}', to_jsonb(draft_title)) cùng transaction.

Chi phí: 1 column nullable + 1 dòng logic trong apply function. Rất thấp.

Q8. Sort order: column hay JSONB?

Giữ quan điểm 23-P3: core column sort_order INT trên information_unit.

Lý do đã nêu:

  • Greenfield 5 rows = ALTER TABLE miễn phí.
  • "Vĩnh viễn hay tạm?" → sort_order là vĩnh viễn.
  • Render hot path = ORDER BY sort_order — native index, không cast, không expression index.
  • JSONB bây giờ + migrate core column sau = effort gấp đôi.
-- Design only:
ALTER TABLE information_unit ADD COLUMN sort_order integer;
CREATE INDEX idx_iu_sort_order 
  ON information_unit(parent_or_container_ref, sort_order)
  WHERE parent_or_container_ref IS NOT NULL;

Q9. Assembly First / PG First compliance?

Đề xuất GPT đạt chuẩn Assembly First. Tốt hơn 23-P3 cũ.

Checklist:

Nguyên tắc 23-P3 cũ (Model D) GPT đề xuất mới Đánh giá
Q0: PG đã giải quyết chưa? ✓ PG function + table ✓ Tương đương Ngang
Tận dụng existing gateway ✓ Allow-list patch ✓ Tương đương Ngang
Code custom tối thiểu ⚠ 6 functions ✓ 5 functions (bỏ reject riêng) Tốt hơn
Agent API đơn giản ⚠ Thuật ngữ Git (propose/merge/reject) ✓ Thuật ngữ biên tập (draft/comment/apply) Tốt hơn
Comment system ✗ Không có trong 23-P3 ✓ Append-only comment Tốt hơn
Status model ⚠ 5 trạng thái (draft/proposed/merged/rejected/superseded) ✓ 3 trạng thái (open/applied/stale_base) Đơn giản hơn

Điểm lệch nhỏ cần lưu ý: Tạo 2 bảng mới (draft + comment) thay vì 1 (proposal). Nhưng comment append-only = bảng cực đơn giản (INSERT only, no UPDATE/DELETE), chi phí bảo trì gần zero.

Q10. Chia phase

Đồng ý GPT, điều chỉnh nhỏ:

Phase Nội dung Ghi chú
P3A Gateway allow-list patch 3 markers. Nhỏ, test riêng.
P3B DDL: unit_edit_draft + unit_edit_comment + sort_order column Schema only.
P3C Functions: create_draft, comment, apply, edit wrapper Logic chính.
P3D Pilot: tạo parent + children IU, edit 1 child, verify End-to-end.

Lý do tách B/C: schema trước, function sau = inspect schema → GPT review → viết function trên nền đã verify. Đúng pattern Pack 22.


Reuse / Existing Assets

Asset Tái dùng Ghi chú
fn_iu_create Nguyên trạng Tạo IU mới (parent/child)
fn_iu_create_plan Nguyên trạng Dry-run IU creation
fn_iu_verify_invariants Gọi trong apply Không sửa, chỉ gọi
fn_content_hash Gọi trong create_draft + apply SHA-256 compute
fn_iu_gateway_write_guard Patch allow-list Sửa nhỏ: exact → membership
dot_config Thêm keys allowed_marker_values, default_apply_policy
Gateway README Update Thêm section edit/apply path

Schema tối thiểu (design only)

unit_edit_draft

Column Type Null Default Mục đích
id uuid NO gen_random_uuid() PK
unit_id uuid NO FK → information_unit
base_version_ref uuid NO FK → unit_version — bản chính tại thời điểm tạo draft
base_content_hash text NO Fast stale detection
draft_body text NO Nội dung nháp
draft_content_hash text NO SHA-256 của draft_body
draft_title text YES NULL Title mới (NULL = giữ nguyên)
draft_status text NO 'open' open / applied / stale_base / withdrawn
author_ref text NO Ai tạo draft
reason text YES NULL Tại sao sửa
metadata jsonb NO '{}' Extensible
created_at timestamptz NO now()
applied_at timestamptz YES NULL Khi nào apply (NULL nếu chưa)
applied_by text YES NULL Ai apply
applied_version_ref uuid YES NULL FK → unit_version tạo ra khi apply

Constraints: PK(id), FK(unit_id→IU), FK(base_version_ref→UV), CHECK(draft_status IN (...)). Indexes: btree(unit_id, draft_status), btree(base_version_ref).

unit_edit_comment

Column Type Null Default Mục đích
id uuid NO gen_random_uuid() PK
draft_id uuid NO FK → unit_edit_draft
author_ref text NO Ai comment
author_type text NO 'agent' user / agent / system
comment_body text NO Nội dung
comment_kind text NO 'general' general / review / approval / change_request / system
target_path text YES NULL Vị trí cụ thể trong body (Phase 2 use)
metadata jsonb NO '{}' Extensible
created_at timestamptz NO now()

Constraints: PK(id), FK(draft_id→unit_edit_draft), CHECK(author_type IN (...)), CHECK(comment_kind IN (...)). Indexes: btree(draft_id, created_at).

Append-only: Không UPDATE, không DELETE trên unit_edit_comment. INSERT only.


Function surface tối thiểu

# Function Ghi IU/UV? Gateway marker? Phase
1 fn_iu_create_edit_draft(address, body, actor, reason, title) Không Không 1
2 fn_iu_comment_edit_draft(draft_id, author, author_type, body, kind) Không Không 1
3 fn_iu_apply_edit_draft(draft_id, reviewer, review_note) Có (UV + IU) 1
4 fn_iu_edit(address, body, actor, reason, title) Có (qua apply) 1
5 fn_iu_edit_plan(address, body, actor) Không (read-only) Không 1

5 functions. So với 23-P3 cũ: bỏ fn_iu_reject_edit (thay bằng status update đơn giản nếu cần), thêm comment function. Net = tương đương complexity.


Policy model

dot_config:
  iu_edit.default_apply_policy = auto_apply    -- Phase 1 default
  iu_edit.stale_draft_action = mark_stale      -- khi apply 1 draft, các draft khác cùng IU

Per-IU override:
  identity_profile->>'edit_policy' = 'require_review'  -- cho enacted/protected IU

fn_iu_edit kiểm tra policy:

  • auto_apply → create_draft + apply trong 1 transaction
  • require_review → create_draft only, return {status: 'draft_created', requires_review: true}

Scale / metadata evolution

  • JSONB trên draft + comment cho metadata mở rộng.
  • Hot-path fields (draft_status, unit_id, base_version_ref) là column riêng + index.
  • Draft/comment tích lũy theo thời gian → retention policy Phase 2 (archive applied drafts > N ngày).
  • Governance path: dot_config cho allowed metadata keys khi cần.

Multi-axis composition

Giữ nguyên từ 23-P3:

  • Document/workflow containment: parent_or_container_ref + sort_order column
  • Domain traceability: universal_edges UPPERCASE typed relations
  • Không gom: 2 trục tách biệt trong schema, đúng user directive

Risks

# Risk Mitigation
1 Birth trigger fire khi fn_iu_apply_edit_draft INSERT UV Kiểm tra P3B — birth trigger trên UV hay chỉ IU?
2 UV lifecycle_status mới ('merged' hay giữ 'draft'?) Apply set lifecycle_status = giá trị phù hợp. Cần chốt.
3 Stale drafts tích lũy Phase 2 retention/archive. Phase 1: ít agent = ít draft.
4 Comment spam Append-only + author tracking. Phase 2: rate limit nếu cần.
5 Title update qua JSONB patch jsonb_set atomic trong transaction. An toàn.

Tổng kết phản biện

Điểm Đồng ý GPT? Ghi chú Opus
Tên draft/comment thay proposal ✓ Đồng ý Dễ hiểu hơn cho Agent
Tạo bảng mới, không reuse Directus ✓ Đồng ý PG native, stable
Replacement body Phase 1 ✓ Đồng ý Diff = view concern
Supersede all active drafts ✗ Đề xuất mark stale_base Giữ draft sống, thông tin hơn
Approval không bắt buộc global ✓ Đồng ý Policy hook đủ
Gateway chỉ cho IU/UV writers ✓ Đồng ý 3 markers
Draft title nullable ✓ Đồng ý Chi phí thấp, hữu ích
Sort order ✗ Core column, không JSONB Greenfield, làm đúng từ đầu
Assembly First compliance ✓ Đề xuất GPT đạt chuẩn Tốt hơn 23-P3 cũ
Phase split ✓ Đồng ý, chỉnh nhỏ Tách schema (B) và function (C)

23-P3A Approach Note | 2026-05-06 | Opus phản biện GPT | Chờ review