23-P1 — IU Text-as-Code Edit / Proposal / Merge Model Design (rev2)
23-P1 — IU Text-as-Code Edit / Proposal / Merge Model — Design Note (rev2)
Date: 2026-05-06 Author: Opus (Claude) Status: DESIGN rev2 — chờ GPT/User review. Không implement. Tầm nhìn: Git-like workflow cho miếng thông tin. Multi-agent proposal/review/merge. Nguyên tắc: Thiết kế full model, implement phân kỳ. Phase 1 = dùng được ngay.
§0. Terminology Map (Git ↔ IU)
| Git / Text-as-Code | IU Equivalent | Note |
|---|---|---|
| Repository | information_unit | 1 IU = 1 quản trị unit |
| Commit | unit_version (merged) | Immutable snapshot |
| HEAD | version_anchor_ref | Pointer to current merged version |
| Branch tip | unit_version (proposed) | Candidate chưa merge |
| Merge base | base_version_ref | Version gốc mà proposal dựa trên |
| Pull request | Edit proposal (proposed UV) | Candidate + review metadata |
| Merge | fn_iu_merge_edit | Accept proposal → update HEAD |
| Reject | fn_iu_reject_edit | Decline proposal |
| Revert | New UV with body = old version body | Phase 2+ |
| Build artifact | Rendered document | Assemble children → full doc |
| CI gate | Invariant verify + health check | Before merge |
| CODEOWNERS | owner_ref + edit_policy | Phase 2+ |
| .gitignore | N/A | Không applicable |
§1. Text-as-Code Principles từ ngành IT
| # | Principle | IT equivalent | IU application | Phase |
|---|---|---|---|---|
| 1 | Immutable version history | Git commit log | UV INSERT-only | 1 |
| 2 | Branch/proposal model | Git branch / PR | Proposed UV | 1 |
| 3 | Review/merge gate | Code review | Reviewer trước merge | 1 (auto), 2 (manual) |
| 4 | Optimistic concurrency | Many branches | Nhiều proposed UV cùng base | 2 |
| 5 | Diff/patch | git diff |
Compute diff base→proposed | 2 |
| 6 | Conflict detection | Merge conflict | Cùng base, khác nội dung | 2 |
| 7 | Revert | git revert |
New UV = old body | 2 |
| 8 | CI/lint/test gates | CI pipeline | Invariant verify | 1 |
| 9 | Ownership/approval | CODEOWNERS | edit_policy per IU | 2 |
| 10 | Release/render | Build artifact | Assemble children | 1 (basic) |
§2. Current Incomex Primitives
| Primitive | Status | Maps to |
|---|---|---|
| information_unit table | ✅ Exists | Repository |
| unit_version table | ✅ Exists | Commit history |
| fn_iu_create | ✅ Live | Init + first commit |
| fn_iu_create_plan | ✅ Live | Dry-run |
| Gateway guard | ✅ Enforced | Protected branch |
| canonical_address | ✅ Immutable | File path / URI |
| version_anchor_ref | ✅ FK to UV | HEAD pointer |
| parent_or_container_ref | ✅ FK nullable | Parent directory |
| content_hash | ✅ On UV | Content integrity |
| version_seq | ✅ On UV | Version numbering |
| identity_profile JSONB | ✅ On IU | Metadata |
§3. Missing Primitives
| # | Missing | Purpose | Phase |
|---|---|---|---|
| 1 | UV lifecycle_status (proposed/merged/rejected/superseded) | Proposal lifecycle | 1 |
| 2 | UV base_version_ref (FK parent UV) | Conflict detection, diff base | 1 |
| 3 | Merge function | Accept proposal → update HEAD | 1 |
| 4 | Sort order cho children | Render document | 1 |
| 5 | Diff metadata | Display changes | 2 |
| 6 | Conflict detection | Multi-agent | 2 |
| 7 | Review status/actor | Manual review | 2 |
| 8 | Revert function | Undo | 2 |
| 9 | Edit policy per IU | Auto-merge vs require review | 2 |
| 10 | Test/lint linkage | Coverage map | 3 |
§4. Parent/Child IU Model
Structure
IU-0 (parent, unit_kind=design_doc)
├── IU-0.§0 (child, sort_order=10)
├── IU-0.§1 (child, sort_order=20)
├── IU-0.§2 (child, sort_order=30)
└── IU-0.§3 (child, sort_order=40)
[rev2] Sort Order Storage Options
| Option | Pro | Con | Migration path |
|---|---|---|---|
| A. identity_profile JSONB | Không DDL, nhanh | Query phải cast JSONB, index phải expression index | → core column nếu cần |
| B. Core column sort_order INT | Query sạch, index native | Cần ALTER TABLE | Final destination |
| C. Edge metadata trên CONTAINS | Normalize, sort là property của relation | Query phức tạp hơn | → nếu edge-centric design |
Phase 1 recommendation: Option A (JSONB) — nhanh, không DDL mới. Ghi rõ: migration → Option B khi scale cần.
Quy tắc
- Sửa child: INSERT new UV cho child. Parent KHÔNG tạo version mới.
- Parent version chỉ thay đổi khi: thêm/xóa/reorder children, hoặc sửa metadata parent.
- Render parent = dynamic assembly, không cache.
- Orphan child (mất parent) → health incident, không auto-delete.
- Nesting: recursive parent_or_container_ref cho phép con có cháu.
§5. Multi-Agent Concurrent Workflow
Scenario (Phase 2+)
base version (v3, merged)
/ | \
Agent A propose Agent B propose Agent C propose
\ | /
Reviewer compare diffs
|
Accept A → merge (new merged version)
Reject B, Supersede C
[rev2] Version Sequence Semantics — 2 options
| Option X: Proposals consume version_seq | Option Y: Proposals get seq on merge only | |
|---|---|---|
| Mechanism | Mỗi proposed UV nhận version_seq khi INSERT | Proposed UV có version_seq=NULL (hoặc 0). Merge assigns next seq |
| Merged history | Gaps: v1(merged), v2(merged), v3(proposed→merged), v4(rejected), v5(superseded) | Clean: v1, v2, v3 = chỉ merged versions |
| Pro | Đơn giản, 1 sequence | Clean numbering, "version 5" = lần merge thứ 5 |
| Con | version_seq không đại diện merge history rõ ràng | Cần kiểm constraint NOT NULL / UNIQUE trên version_seq |
| Constraint risk | Low — unique(unit_id, version_seq) vẫn work | PHẢI inspect — nếu NOT NULL constraint → cần ALTER hoặc workaround |
Opus preference: Option Y (seq on merge only) — cleaner semantics. Nhưng PHẢI runtime inspection xác nhận version_seq constraints trước khi chọn.
⚠️ [rev2] Warning: UV = Proposal Object needs runtime verification
Dùng unit_version làm proposal container là gọn, nhưng phải xác nhận:
- version_seq constraint cho phép NULL hoặc nhiều proposed UV cùng unit?
- fn_iu_verify_invariants có assume exactly 1 current UV không?
- version_anchor_ref logic có bị break với nhiều proposed UV?
- Birth trigger behavior với UV lifecycle_status ≠ merged?
23-P2 read-only inspection PHẢI trả lời các câu hỏi này trước implementation.
§6. Function Set
Core (Phase 1):
fn_iu_propose_edit(address, new_body, actor)
→ INSERT UV status=proposed, base_version_ref=current HEAD
→ Return proposal_uv_id
fn_iu_merge_edit(proposal_uv_id, reviewer)
→ Verify: UV exists, status=proposed, invariants OK
→ UPDATE UV status=merged, assign version_seq
→ UPDATE IU version_anchor_ref + content_anchor_ref
→ Return merged result
fn_iu_edit(address, new_body, actor)
→ Wrapper: propose + auto-merge in 1 transaction
→ [rev2] Policy check: auto-merge allowed for this IU?
Phase 2+:
fn_iu_reject_edit(proposal_uv_id, reviewer, reason)
fn_iu_edit_plan(address, new_body, actor) — dry-run
fn_iu_revert(address, target_version_seq, actor)
[rev2] fn_iu_edit Policy Hook
fn_iu_edit wrapper KHÔNG auto-merge nếu policy nói không:
-- Pseudocode inside fn_iu_edit:
v_policy := read_edit_policy(IU);
IF v_policy = 'require_review' THEN
-- Only propose, don't merge
RETURN fn_iu_propose_edit(...) || '{"auto_merged": false, "requires_review": true}';
ELSE
-- Propose + merge
RETURN fn_iu_propose_edit(...) + fn_iu_merge_edit(...);
END IF;
Policy source: identity_profile->>'edit_policy' hoặc dot_config per unit_kind. Phase 1 default = auto_merge (single Agent). Phase 2: enacted/protected IUs → require_review.
§7. [rev2] Gateway Marker Strategy — Explicit Allow-list
Không dùng prefix fn_iu_%. Quá rộng — helper functions không intended write có thể pass guard.
Allow-list explicit:
-- dot_config key:
iu_create.gateway.allowed_marker_values = fn_iu_create,fn_iu_propose_edit,fn_iu_merge_edit,fn_iu_edit
Guard function đọc allow-list:
v_allowed := string_to_array(
(SELECT value FROM dot_config WHERE key='iu_create.gateway.allowed_marker_values'),
','
);
IF v_current = ANY(v_allowed) THEN RETURN NEW; END IF;
Thêm marker mới = thêm vào dot_config, không patch guard function.
⚠️ Guard function hiện check exact single value. Cần patch sang allow-list. Đây là scope 23-P3 (guard patch), sau 23-P2 inspection.
§8. Schema Evidence Needed (23-P2 Inspection)
| # | Question | Why |
|---|---|---|
| 1 | unit_version columns/constraints | version_seq NULL? UNIQUE? |
| 2 | lifecycle_status trên UV exists? | Nếu có → reuse. Nếu không → ALTER |
| 3 | base_version_ref exists? | Likely no → cần ALTER |
| 4 | fn_iu_verify_invariants behavior với nhiều UV | Assume 1 current? |
| 5 | Birth trigger behavior với proposed UV | Block? Warn? Ignore? |
| 6 | Guard function exact check logic | Single value vs allow-list |
| 7 | sort_order anywhere on IU | identity_profile? core column? |
| 8 | Edge table support cho CONTAINS + order metadata | Can store sort_order? |
§9. Minimum Production Workflow v1
1. Create parent IU → fn_iu_create(doc_address, title, metadata, actor)
2. Create child IUs → fn_iu_create(section_address, title, body, actor, parent_ref=parent.id)
3. Edit child → fn_iu_edit(section_address, new_body, actor)
[internally: propose + policy check + auto-merge]
4. Read/render → SELECT children WHERE parent=? ORDER BY sort_order → assemble
5. History → SELECT * FROM unit_version WHERE unit_id=? ORDER BY version_seq
§10. What NOT to Do Yet
- Full 3-way merge, vector outbox, Directus UI, role separation, detector, release builder, semantic lint, concurrent conflict auto-resolve, package system
§11. Implementation Phases
Phase 1: Miếng thông tin dùng được
| # | Deliverable | Prereq |
|---|---|---|
| 1 | 23-P2 read-only inspection (UV constraints, guard logic, etc.) | This design approved |
| 2 | Schema patch: UV add lifecycle_status + base_version_ref (if needed) | 23-P2 results |
| 3 | fn_iu_propose_edit + fn_iu_merge_edit | Schema ready |
| 4 | fn_iu_edit wrapper (with policy hook, default auto_merge) | Core functions ready |
| 5 | Guard patch: allow-list marker values | Before new functions dispatch |
| 6 | Parent/child: sort_order in identity_profile | Low effort |
| 7 | Convert 2 pilot docs → real IUs (parent + children) | Functions ready |
| 8 | Smoke test full cycle: create → edit → read → render | Data ready |
Phase 2: Multi-Agent Review
Phase 3: Advanced Text-as-Code
(Unchanged from rev1)
23-P1 Design rev2 | 2026-05-06 | 8 GPT patches applied | Chờ review