Điều 45 — Luật Hàng Đợi & Điều Phối Tác Vụ PG-native (PG-Native Queue & Task Orchestration Law) — v1.0 BAN HÀNH
ĐIỀU 45 — LUẬT HÀNG ĐỢI & ĐIỀU PHỐI TÁC VỤ PG-NATIVE
(PG-Native Queue & Task Orchestration Law)
Version: v1.0 BAN HÀNH (enacted 2026-05-26) — User approval pass. Nội dung được khoá; mọi thay đổi từ đây phải qua amendment process. Lịch sử bản:
- v0.1 DRAFT (2026-05-26, soạn lần đầu — 22 sections căn cứ điều tra survey 2026-05-26).
- v0.2 DRAFT (2026-05-26, GPT Council Round 1 patch: thêm §6.6 event_vs_job, §6.7 work_state_machine, §11.5 executor_boundary, §13.4 MOT clause, §15.5 silent_gap/heartbeat invariant).
- v0.2.1 DRAFT (2026-05-26, cleanup: KB metadata title/tag bumps + council wording an toàn
council_round_1_gpt_patch_appliedthay vì_approved+enactment_approved=false+ MOT loại khỏi enumeration executor ở §11.5 và §13.4 codifyMOT.is_executor=false).- v1.0 BAN HÀNH (2026-05-26, User approval — không sửa nội dung, chỉ chuyển trạng thái DRAFT → ENACTED). Soạn: 2026-05-26 | Tác giả: Huyên (tầm nhìn), Claude Opus 4.7 (1M context) (soạn thảo). Căn cứ điều tra:
knowledge/dev/laws/dieu44-trien-khai/v0.6-system-wide-pg-native-queue-law-readiness-survey/(PASS 2026-05-26). Đề xuất khung từ: GPT (2026-05-26). Tuân thủ: Hiến pháp Kiến trúc, Điều 0, 0-B, 0-G, 0-H, 13, 22, 24, 28, 29, 30, 31, 32, 35, 36, 37, 39, 43, 44. Trạng thái phê duyệt: ❌ CHƯA BAN HÀNH. Không được trích dẫn như luật hiện hành cho đến khi Council + User chấp thuận.
§0. Tóm tắt điều hành
Điều 45 quy định hạ tầng hàng đợi và điều phối tác vụ hệ thống trên nền tảng PostgreSQL. Luật xác lập 8 bất biến cốt lõi cho mọi cơ chế hàng đợi — events, tasks, messages, jobs, workflows, trigger-in, trigger-out — sao cho:
- PostgreSQL là nguồn sự thật (SoT) duy nhất cho trạng thái hàng đợi: bảng outbox bền vững, transaction, trigger, advisory lock, SKIP LOCKED, LISTEN/NOTIFY chỉ làm tín hiệu đánh thức.
- Hàng đợi mang tín hiệu, không mang dữ liệu (
payload_refpattern). Body lớn, blob, vector, secret, conversation đầy đủ — KHÔNG bao giờ đặt trong outbox. - Mọi hạng mục công việc (event/task/job/message/trigger) phải có idempotency, lifecycle, retry, dead-letter, lease, observability cursor.
- No-vector-in-transient — ratify cứng D36 NVSZ ở mức luật.
- Phân ranh executor: Worker / Agent / DOT / Hermes là người thực thi; hàng đợi không kiêm nhiệm logic xử lý.
- Compatibility hard: không sửa Điều 30/31/35/36/37/44; cross-reference rõ.
- PG 16.13 đủ điều kiện triển khai lần đầu. Nâng cấp PG 18 là macro độc lập, KHÔNG là tiền điều kiện của Điều 45.
- Substrate hiện hành (
event_outbox131,746 rows + workeriu_outbound_default+iu_route_dead_letter+iu_sql_event_route+dot_iu_runtime_lease+iu_core.iu_staging_record/payload) tiếp tục hoạt động dưới điều khoản chuyển tiếp tại §20.
Điều 45 KHÔNG phải clone của Pub/Sub, NATS, RabbitMQ, hay Kafka. Đây là luật quản trị cho cơ chế hàng đợi được xây dựng từ chính PostgreSQL, tận dụng tối đa primitive sẵn có.
§1. Mục đích và phạm vi
§1.1 Mục đích
Luật này quy định các bất biến tối thiểu mà mọi cơ chế hàng đợi/điều phối tác vụ hệ thống phải tuân thủ. Mục đích:
- Bảo đảm tính bền vững (durability) của tín hiệu công việc, không mất khi process khởi động lại.
- Bảo đảm tính idempotency — cùng một tín hiệu được phát lại không gây side-effect bổ sung.
- Bảo đảm tính quan sát được (observability) — mọi tác vụ có trạng thái, cursor, audit, healthcheck.
- Bảo đảm kỷ luật ranh giới giữa producer / queue substrate / executor — không trộn ba lớp.
- Bảo đảm PG là SoT — tránh distributed-state hidden trong message bus ngoài DB.
§1.2 Phạm vi áp dụng (system-wide)
Luật này áp dụng cho — và CHỈ cho — các loại tín hiệu công việc sau, được chia thành 4 nhóm:
| Nhóm | Loại tín hiệu | Trạng thái Phase 1 |
|---|---|---|
| A. Events | event_outbox-style (governance-significant facts) | ✅ LIVE — 131k+ rows trong event_outbox |
| B. Tasks | per-actor todos, review queue, approval queue | ⚠ Vocab có (stream=task/review), substrate đầy đủ chưa |
| C. Messages | comments, notifications, board entries | ⚠ Vocab có (stream=comment), substrate kế thừa IU notification |
| D. Jobs | long-running worker jobs, Agent/Hermes/DOT runs, MOT workflows, scheduled sweeps, vector sync, staging cleanup, customer-care/email future | ⚠ Chưa có substrate thống nhất; lệ thuộc quyết định D2 (xem §19) |
Luật KHÔNG áp dụng cho:
- Activity log thông thường (đã có Điều 22 + audit log riêng).
- Telemetry/metrics (CPU, latency) — thuộc giám sát hệ thống.
- Log debug/trace.
- Read access / view event.
- Internal worker tick result (worker log riêng).
- Mọi change không có governance owner / không có lifecycle.
(Phân định trên kế thừa "inclusion criteria" của 23-P3D4C0X §M và được nâng lên mức luật tại §6.4.)
§1.3 Liên hệ "cut-only queue"
Luật này KHÔNG phải luật riêng cho luồng MARK→CUT của Information Unit. Cutting flow là một use case (event_domain='staging', 'iu', 'piece'). Mọi use case khác được liệt kê tại §1.2 cũng phải tuân thủ Điều 45.
§2. Định nghĩa
Luật sử dụng các thuật ngữ sau với nghĩa duy nhất:
| Thuật ngữ | Định nghĩa |
|---|---|
| Queue substrate | Tập hợp các bảng PG bền vững giữ trạng thái tín hiệu công việc (durable outbox + pending staging + read state + subscription + type registry + worker cursor + dead-letter + lease). Trên hệ thống hiện hành: event_outbox, event_pending, event_read, event_subscription, event_type_registry, iu_route_worker_cursor, iu_route_dead_letter, dot_iu_runtime_lease. |
| Event | Một governance-significant fact đã xảy ra (lifecycle change, approval, alert, DOT result, system milestone). Append-only. Không phải mệnh lệnh. |
| Job | Một đơn vị công việc cần thực thi, có payload_ref và executor target. Có lifecycle riêng (queued → claimed → running → done |
| Task | Một event ở dạng "cần hành động" — actor cần làm gì đó (review draft, approve manifest, resolve issue). Stream=task hoặc review. |
| Message | Một event ở dạng "thông báo" — không yêu cầu hành động bắt buộc, để recipient biết. Stream=comment hoặc update. |
| Worker | Tiến trình ngoài hoặc trong DB, đọc queue substrate và thực thi/định tuyến/làm sạch. Worker hiện hữu: fn_iu_route_worker_run (gọi từ ngoài). |
| Lease | Cơ chế độc quyền có thời hạn cho phép một worker xác nhận quyền xử lý một mục công việc. Substrate: dot_iu_runtime_lease (lease_name, lease_holder, lease_token, expires_at). |
| Dead-letter | Mục công việc đã thất bại quá số attempt cho phép, được chuyển sang bảng/trạng thái riêng để con người/AI xử lý thủ công. Substrate: iu_route_dead_letter. |
| Trigger-in | Cơ chế chuyển sự kiện SQL nguồn (INSERT/UPDATE/DELETE/CALL/DDL) thành event trong queue substrate. Substrate: iu_sql_event_route (dry-run live). |
| Trigger-out | Cơ chế phản ứng với event để gọi action / mint instance / cập nhật target. Substrate: fn_iu_auto_instantiate_from_event là prototype. |
| payload_ref | Một con trỏ (canonical_address, FK uuid, source_path, document_id, blob URI) đến nơi lưu trữ chính của payload lớn. Hàng đợi giữ payload_ref, không giữ payload đầy đủ. |
| safe_payload | jsonb metadata nhỏ (cardinality, status, severity, lifecycle keys, refs, addresses). KHÔNG được chứa body/content/raw/vector/embedding/secret/token/password/ssn/personal_data. Đã CHECK-cứng trên event_outbox. |
| delivery_lane | Phân loại tốc độ phát hành: immediate (gửi ngay) vs delayed (debounce/group/batch qua worker). |
| event_stream | Phân loại ngữ nghĩa: comment, review, update, birth, task, alert, health. |
| event_domain | Phân loại lãnh thổ: iu, birth_registry, governance, tac, kg, system, dot, health, piece. |
| idempotency_key | Khoá định danh tự nhiên/canonical cho một mục công việc; cùng key chèn lại không tạo thêm row hoặc tạo có UNIQUE conflict bỏ qua. |
| correlation_id | Mã định danh nhóm các tín hiệu cùng một "job/import/build/run" — dùng cho rollup / debounce / audit trail. |
§3. Áp dụng hệ thống — không riêng cho cắt
§3.1 Nguyên tắc thống nhất
Mọi cơ chế trong các domain liệt kê tại §1.2 PHẢI sử dụng cùng một queue substrate. KHÔNG được tạo:
- Outbox riêng cho từng domain.
- Bảng worker cursor riêng cho từng worker.
- Bảng dead-letter riêng cho từng pipeline.
- Cơ chế lease riêng cho từng module.
Trừ khi có dispensation rõ ràng trong chính luật (ví dụ: iu_core.iu_staging_record là staging-tier vật chất hoá khác với outbox — vẫn tuân Điều 45 invariants nhưng không phải event_outbox).
§3.2 Vocab thống nhất
Vocab CHECK-cứng tại §6.1 áp dụng cho mọi domain. Một domain mới phát sinh muốn dùng vocab mới (event_type mới, stream mới, lane mới) PHẢI đăng ký trước trong event_type_registry thông qua quy trình ratification theo Điều 35 (DOT registration model) hoặc tương đương.
§3.3 Không có "luật riêng cho IU"
Điều 44 thực thi IU-0 KHÔNG bao gồm queue substrate. Mọi event/task/job sinh ra từ IU operations đi qua substrate chung. iu_* prefix trong tên function hiện hành (fn_iu_emit_event, fn_iu_route_worker_run) là lịch sử triển khai, không phản ánh giới hạn phạm vi — tên function được phép giữ nguyên trong điều khoản chuyển tiếp (§20) nhưng phải hoạt động cho mọi domain.
§4. Hàng đợi mang TÍN HIỆU, không mang DỮ LIỆU
§4.1 Nguyên tắc cứng
Queue substrate carries SIGNAL, NOT DATA.
queue_carries:
- work_type # ví dụ: event_type, command_name, job_kind
- event_type # đã đăng ký trong event_type_registry
- source_ref # con trỏ đến nguồn (canonical_address, file path, table.row, blob URI)
- target_ref # con trỏ đến đích (collection, IU, entity, recipient)
- payload_ref # con trỏ đến payload lớn nếu có
- status # lifecycle vocab tại §6
- priority # nếu domain cần (chưa modeled)
- schedule # ví dụ: process_after, deadline
- lease # lease_token, lease_holder, expires_at
- retry # error_count, last_error
- dead_letter # attempts, failure_code, resolution
- actor # producer + recipient
- run_id # liên kết với dot_iu_command_run nếu thuộc DOT
- correlation_id # nhóm
- audit # created_at, occurred_at, processed_at
queue_does_not_carry:
- full_file_content
- full_document_body
- large_text (≥10 KiB)
- blob (binary)
- vector_payload
- embedding
- secret / token / password / ssn / personal_data
- email_body_large
- customer_conversation_large
- api_response_full
- log_full_content
§4.2 Quy ước payload_ref
Khi cần truyền dữ liệu lớn, queue substrate sử dụng một trong các loại con trỏ sau (chứ KHÔNG chứa nội dung):
| Loại payload | payload_ref chấp nhận | Nơi lưu thực |
|---|---|---|
| Body IU đã sinh | canonical_address hoặc unit_id uuid |
information_unit table |
| File nguồn cần cắt | source_path (KB path) + content_hash |
KB / GCS / blob storage |
| Manifest cắt | staging_record_id uuid |
iu_core.iu_staging_record + iu_staging_payload |
| KB final report | kb_document_id |
Agent Data KB |
| Vector | KHÔNG được truyền qua queue substrate | iu_vector_sync_point + Qdrant trực tiếp |
| Customer-care content | case_id hoặc conversation_id |
(chưa có substrate; ngoài Phase 1) |
| Email body | message_id hoặc imap_uid |
(chưa có substrate; ngoài Phase 1) |
| DOT command params | params_digest (32-hex) + dot_iu_command_run.run_id |
dot_iu_command_run.evidence |
§4.3 Hard CHECK trên safe_payload
event_outbox.safe_payload CHECK đã hiện hành:
safe_payload MUST NOT contain keys: body, content, raw, vector, embedding, secret, token, password, ssn, personal_data
Luật ratify hard CHECK trên. Mọi bảng queue substrate mới PHẢI có CHECK tương đương hoặc mạnh hơn.
§4.4 Vi phạm tín hiệu/dữ liệu
Một producer chèn body/content/blob vào safe_payload sẽ:
- INSERT thất bại do CHECK.
- Phát sinh dòng
system_issues(theo Điều 31) — issue_kind =queue.payload_violation. - Owner: producer agency.
- Refusal: producer phải sửa, không được skip.
§5. Nguyên tắc PG-native
§5.1 PostgreSQL là SoT cho queue state
- Mọi trạng thái queue (lifecycle, attempt count, dead-letter, cursor, lease) PHẢI sống trong bảng PG bền vững.
- KHÔNG được giữ queue state chính trong: Redis, memcached, RAM của worker process, file local, message bus ngoài DB.
- LISTEN/NOTIFY KHÔNG là SoT. Nó là tín hiệu đánh thức (wake-up signal). Mất NOTIFY không được làm mất công việc.
§5.2 Primitive PG được cho phép
Luật khuyến khích — và xác nhận — việc sử dụng các primitive sau:
| Primitive | Mục đích | Tình trạng hiện hành |
|---|---|---|
| Transaction (BEGIN/COMMIT/ROLLBACK) | Atomic enqueue + side-effect | ✅ Mọi fn_iu_emit_* |
| Trigger AFTER INSERT/UPDATE | Trigger-in (capture facts) | ✅ fn_iu_lifecycle_log_emit_piece_event_trg |
| Trigger BEFORE INSERT/UPDATE | Guard (validate, derive) | ✅ Birth gates, domain mutators |
SELECT ... FOR UPDATE SKIP LOCKED |
Worker pull-next mà không block | ✅ Đã thiết kế trong fn_iu_route_worker_run (xác minh ở design pack) |
pg_try_advisory_lock |
Serialize worker tick | ⚠ Không thấy trong function bodies; thay bằng dot_iu_runtime_lease table-based |
LISTEN/NOTIFY |
Wake-up signal | ⚠ Chỉ dùng cho kb_vector_sync (PG→Qdrant); chưa dùng cho event_outbox |
| Partial UNIQUE index | Idempotency enforcement | ✅ iu_auto_instantiate_event_log |
Partial index WHERE processed_at IS NULL |
Hot-path queue read | ✅ Thiết kế cho event_pending |
gen_random_uuid() |
Event id | ✅ (PG 18 sẽ ra uuidv7() — không bắt buộc) |
| CHECK constraint | Vocab + payload safety | ✅ event_outbox.* checks |
| JSONB + jsonb_path_exists | Metadata typing | ✅ |
§5.3 Primitive PG bị cấm dùng làm SoT hàng đợi
- KHÔNG dùng
pg_notifythay cho bảng outbox bền vững. - KHÔNG dùng
pg_advisory_lockthay chodead_letter/error_count(lock không phải retry). - KHÔNG dùng
LISTENchannel làm subscription chính (đã cóevent_subscription).
§5.4 Scheduler boundary (pg_cron clause)
Luật phát biểu rõ:
Tại thời điểm ban hành,
pg_cronKHÔNG được cài đặt trên cluster sản xuất. Việc gọi worker tick (fn_iu_route_worker_runvà tương lai), tick cleanup, và tick retention được thực hiện từ bên ngoài — Hermes batch, Codex session, Directus flow, hoặc cron của host.
Hệ quả:
- Mọi worker function PHẢI idempotent với tần suất gọi — gọi quá ít gây trễ, gọi quá nhiều không gây hỏng.
- Mọi job có deadline PHẢI ghi
deadline_atvào bảng để observer ngoài có thể alert nếu deadline trôi qua mà chưa xử lý. - Cadence gọi worker là operational contract — phải được ghi rõ trong tài liệu vận hành (không phải lore).
- Việc cài đặt
pg_cron— nếu xảy ra — phải qua sub-design pack riêng (D1 tại §19) và sửa §5.4 thông qua amendment.
§6. Vocab vòng đời (lifecycle/status vocabulary)
§6.1 Vocab cứng — event_outbox
Vocab dưới đây được CHECK-cứng trên event_outbox live và được luật ratify ở mức Điều 45:
event_domain: # 9 lãnh thổ
- iu # Information Unit operations
- piece # IU piece-level operations
- staging # iu_core staging lifecycle
- birth_registry # birth & catalog
- governance # approval / agency / org
- tac # TAC text-as-code
- kg # Knowledge Graph
- system # system_issues, D43 lifecycle
- dot # DOT execution
- health # health_check, integrity alerts
event_stream: # 7 ngữ nghĩa
- comment # human/AI commentary
- review # review/approval pending
- update # state change notification
- birth # entity created
- task # actor action required
- alert # warning/critical incident
- health # health probe result
delivery_lane: # 2 tốc độ
- immediate # emit ngay khi fact xảy ra
- delayed # debounce / group / batch qua worker
event_severity: # 3 mức + null
- null # info-default
- info
- warning
- critical
payload_classification: # 2 mức
- safe_metadata # tuân §4.3
- restricted # hard-blocked unless dispensation
§6.2 Vocab cứng — staging lifecycle
iu_core.iu_staging_record.lifecycle_status vocab 7-state được ratify:
staging_lifecycle:
- pending # đang ghi, chưa đủ payload
- pending_review # đã ghi xong, chờ verify
- approved # verify pass, ready cho consume
- consumed # đã được cut/run sử dụng
- rejected # verify fail hoặc operator từ chối
- expired # quá expires_at chưa được consume
- cleaned # đã xóa khỏi staging tier (audit row vẫn còn)
§6.3 Vocab cứng — DOT run
dot_iu_command_run vocab được ratify (cross-reference Điều 35):
run_mode:
- plan
- apply
- verify
run_status:
- planned
- applied
- verified
- refused
- failed
§6.4 Inclusion criteria — "đủ điều kiện vào queue"
Một fact được phép trở thành event/task/job khi thoả ≥1 điều kiện sau:
- Lifecycle change của entity có governance owner (mints, drafts, approves, applies, retires).
- Approval/review request mà human/AI cần action.
- Health/integrity alert severity ≥ warning.
- DOT execution result (paired theo Điều 35).
- System milestone (Điều 43 lifecycle).
- Agency/governance task assigned.
- Ingest milestone affecting governed entities.
Một fact bị cấm trở thành event nếu thoả ≥1 điều sau:
- Là UPDATE thông thường một column.
- Là telemetry/metrics.
- Là audit trail thông thường (đã có audit log riêng).
- Là debug/trace.
- Là read access.
- Là internal worker tick result.
- Không có governance owner / không có lifecycle.
Rubric trên là cứng. Vi phạm sẽ bị refusal khi insert vào event_type_registry (xem Điều 35-style ratification).
§6.5 Sub-domain disambiguation
Vocab cho phép event_domain='iu' và event_domain='piece' đồng thời. piece là sub-domain ngữ nghĩa hẹp hơn iu. Khi mơ hồ, chọn iu cho operations cấp container, piece cho operations cấp đơn vị. (Decision này có thể được sửa trong design pack — xem §19 / open Q28.)
§6.6 Phân biệt Event và Job (event_vs_job distinction)
Để giải toả nhập nhằng giữa nhóm A (Events) và nhóm D (Jobs) đã liệt kê tại §1.2, Điều 45 v0.2 ban hành phân định cứng sau (GPT Council Round 1 patch):
event_vs_job:
event:
definition: fact_that_happened
semantics: "Sự kiện đã xảy ra — bất biến, không retry, durable fact ledger."
examples:
- iu.lifecycle.changed
- piece.created
- staging.marked
- birth_registry.entity_born
- dot.run.applied
job:
definition: work_to_be_done
semantics: "Công việc cần thực hiện — có lifecycle thực thi, có retry, có DLQ, có lease."
examples:
- mark_file
- verify_mark
- cut_from_manifest
- send_email
- customer_message_process
- staging_cleanup_sweep
rule:
- event_may_generate_job
- job_has_execution_lifecycle
- event_outbox_must_not_be_assumed_to_cover_all_job_queue_needs_without_job_layer
- producer_of_job_may_be_an_event_consumer
- job_completion_may_emit_a_new_event
Hệ quả luật:
event_outbox(substrate hiện hành) phục vụ nhóm A — events như một durable fact ledger; KHÔNG phải job queue.- Nhóm D — jobs — đòi hỏi lifecycle thực thi riêng (xem §6.7 work state machine). Có thể đặt cùng substrate vật lý hoặc tách bảng — quyết định thuộc DP2 (§19 / §18.4 / Q-D2).
- Cấm giả định "có
event_outboxrồi nên job queue đã xong". Vi phạm = anti-pattern A8' (xem §17.1 mở rộng v0.2).
§6.7 Bất biến cứng — Work state machine
Mọi đơn vị công việc thực thi (job theo §6.6 — bao gồm DOT run, worker job, MOT step §13.4, future customer-care job) PHẢI có lifecycle với tối thiểu các trạng thái sau, hoặc tập con tương đương đã được Council ratify (GPT Council Round 1 patch):
work_state_machine:
minimum_status:
- queued # đã enqueue, chờ executor claim
- leased # executor đã claim qua lease (§8.3)
- in_progress # đang thực thi
- succeeded # hoàn tất thành công
- failed # thất bại sau retry sau cùng
- retry_waiting # thất bại tạm, chờ backoff (§8.2)
- dead_letter # bị đẩy DLQ sau max_attempts (§8.4)
- cancelled # bị huỷ chủ động (operator / supersede)
- cleaned # đã được dọn khỏi tier active (audit row còn lại)
rule:
- every_executor_must_write_status_back_to_PG
- no_silent_state_change
- no_untracked_work
- state_transition_only_through_function_gate
- state_machine_is_evidence_for_observability_per_§15
- private_executor_state_machine_bypassing_PG_is_forbidden
Mối liên hệ với vocab hiện hành:
staging_lifecycle(§6.2 — 7 state) áp dụng cho staging record, KHÔNG phải work state machine. Hai vocab phục vụ hai layer khác nhau (data tier vs work tier).dot_iu_command_run.run_status(§6.3 — 5 state) là subset rút gọn của work state machine ở mức DOT. Council có thể quyết định mở rộngrun_statusthành full state machine hoặc giữ rút gọn trong DP2/DP3 (Q-D3 §19).- Cấm tạo state machine song song mà không qua sub-design pack. Vi phạm = anti-pattern A14' (xem §17.1 mở rộng v0.2: "private executor state machine bypassing PG SoT").
§7. Idempotency và deduplication
§7.1 Nguyên tắc
Mọi enqueue PHẢI có khoá định danh tự nhiên để dedup:
| Loại tín hiệu | Khoá định danh tối thiểu |
|---|---|
| Event | (event_domain, event_type, event_subject_table, event_subject_ref) partial UNIQUE WHERE event_subject_ref IS NOT NULL |
| Staging record | idempotency_key text + content_hash text (32-hex) |
| Consumer log | idempotency_key (ví dụ iu_auto_instantiate_event_log.idempotency_key) |
| DOT run | params_digest (32-hex) |
§7.2 Re-enqueue rule
- Cùng key chèn lại: hành vi mặc định là
ON CONFLICT DO NOTHING. KHÔNG được làm tăng counter, không được tạo row mới. - Trừ khi consumer tạo row mới (replay sau dead-letter qua
fn_iu_route_dead_letter_replay): row mới có resolution='replayed' nhưng key cũ giữ lịch sử.
§7.3 Cross-process idempotency
Khi nhiều worker chạy song song, idempotency được bảo đảm bởi:
- CHECK + UNIQUE constraint cấp DB (defense-in-depth #1).
- SELECT ... FOR UPDATE SKIP LOCKED (defense-in-depth #2 — chỉ một worker thấy row).
- Lease token (defense-in-depth #3 — chỉ holder hiện thời được commit kết quả).
Không được tin tưởng chỉ một lớp.
§8. Retry, lease, dead-letter
§8.1 Retry policy
Mọi consumer thất bại thoáng qua phải hỗ trợ retry. Substrate:
event_pending.error_countinteger, default 0.event_pending.last_errortext.iu_route_worker_cursor.attempts_writtenbigint.
Luật KHÔNG ấn định max_attempts tại lần đầu ban hành. max_attempts được quyết định trong design pack (D4 §19) và lưu trong dot_config namespace event.retry.*.
§8.2 Backoff
Backoff strategy (constant / linear / exponential) thuộc về design pack. Luật yêu cầu strategy được rõ ràng trong tài liệu vận hành — không được "implicit retry on next tick".
§8.3 Lease
Mọi consumer cần serialize cross-process PHẢI dùng cơ chế lease:
dot_iu_runtime_lease(lease_name, lease_holder, lease_token, acquired_at, expires_at, renewed_at)là cơ chế chuẩn.- Lease có TTL ngắn (gợi ý mặc định 5–10 phút) — nếu holder crash, lease auto-expire, holder mới được phép acquire.
- Lease KHÔNG thay cho idempotency. Phải dùng song song.
§8.4 Dead-letter
Khi error_count ≥ max_attempts:
- Row được copy/move sang
iu_route_dead_letter(worker_name, event_ref, event_domain, event_type, route_code, idempotency_key, failure_code, failure_detail, attempts, event_snapshot jsonb, first_failed_at, last_failed_at). - Trạng thái resolved là NULL khi mới đặt; phải set đồng thời
resolved_at+resolution ∈ {replayed, discarded, superseded}để đóng (CHECK đã có). - Resolution authority: operator được phép replay; agency owner được phép discard; supersede chỉ khi có event_ref mới làm anchor. Chi tiết policy thuộc design pack (D15 §19).
- Dead-letter KHÔNG được auto-replay. Phải qua
fn_iu_route_dead_letter_replay(đã hiện hữu) hoặc DOT có gate.
§8.5 Refusal contract
Một worker GẶP LỖI vĩnh viễn (corruption, contract violation, malformed payload) PHẢI từ chối thay vì retry vô tận:
error_countset bằngmax_attemptsngay (không cần đợi attempt thực tế).last_errorghi rõ lý do.- Row vào dead-letter ngay.
Cross-reference Điều 31 (refusal contract) — refusal là một state hợp lệ, không phải failure.
§9. Scheduling và delayed execution
§9.1 Lane delayed đối với event
Event đăng ký delivery_lane='delayed' được giữ tại lớp pending/staging, worker drain theo cadence (debounce + group). Vocab này đã CHECK-cứng.
Debounce + grouping policy:
- Window mặc định gợi ý 90s (clamp 60–300s).
- Stable key =
COALESCE(source_document_ref, import_batch_ref, correlation_id). - Threshold rollup-vs-piece-level tuỳ domain.
Tham số cụ thể thuộc dot_config namespace event.debounce.* (design pack).
§9.2 Job có deadline
Một job có deadline PHẢI ghi deadline_at (timestamptz). Observer (D43 red_zones / health worker) PHẢI alert nếu now() > deadline_at AND status NOT IN ('done','superseded').
§9.3 Recurring/scheduled jobs
Recurring sweep (cleanup staging hết hạn, retention archive 30d, …) là một loại job có next_run_at. Substrate hiện chưa có bảng schedule chung; thuộc design pack (D7 §19).
§9.4 Không pg_cron tại Phase 1
Như §5.4. Mọi delayed/scheduled job tại Phase 1 được trigger từ ngoài. Khi/nếu pg_cron được cài, §9 sẽ được mở rộng amendment để mô tả các cron job được phép tồn tại trong DB.
§10. Batch processing
§10.1 Nguyên tắc
Batch processing là một biến thể của worker xử lý nhiều mục trong một transaction để giảm overhead. Luật yêu cầu:
- Batch size có giới hạn cứng (tránh ôm hết bảng).
- Batch transaction PHẢI ROLLBACK toàn bộ nếu một mục fail (atomic), hoặc CHIA NHỎ thành mini-batch (per-item commit) nếu fail-individual được chấp nhận.
- Batch không được phép vượt qua lease TTL — nếu lease hết hạn trong khi batch chạy, batch PHẢI dừng và rollback.
§10.2 Idempotency với batch
Mỗi mục trong batch giữ idempotency_key riêng. Batch fail không xoá idempotency_log — replay sau đó vẫn dedup đúng.
§10.3 Observability
Batch PHẢI cập nhật iu_route_worker_cursor:
events_seen+= batch input countattempts_written+= successful countdead_lettered+= failed-after-attempts countlast_run_summary jsonbchứa breakdown
§11. Ranh giới Worker / Agent / DOT / Hermes
§11.1 Phân ranh ba lớp
┌──────────────────────────────────────────────────────┐
│ PRODUCER LAYER │
│ - PG trigger / mutator function (fn_iu_*) │
│ - DOT command (Điều 35) │
│ - External producer via SQL emit fn │
│ → enqueues into queue substrate │
└──────────────────────────────────────────────────────┘
↓ event/task/job row
┌──────────────────────────────────────────────────────┐
│ QUEUE SUBSTRATE LAYER │
│ - event_outbox / event_pending / event_read │
│ - event_subscription / event_type_registry │
│ - iu_route_worker_cursor / iu_route_dead_letter │
│ - dot_iu_runtime_lease │
│ → SoT for state, no executor logic │
└──────────────────────────────────────────────────────┘
↓ pull / claim
┌──────────────────────────────────────────────────────┐
│ EXECUTOR LAYER │
│ - Worker process (fn_iu_route_worker_run + future) │
│ - Agent / Hermes / Codex │
│ - DOT executor (Điều 35 + APR) │
│ → reads queue, executes business logic, writes back │
└──────────────────────────────────────────────────────┘
§11.2 Rules
- Producer KHÔNG được phép thực thi business logic của consumer. Producer enqueue rồi kết thúc.
- Queue substrate KHÔNG được phép chứa business logic ngoài enforcement vocab + idempotency + CHECK constraint. KHÔNG có trigger BUSINESS-action trên
event_outbox. - Executor KHÔNG được phép ghi trực tiếp queue state mà bypass primitive (SELECT FOR UPDATE / lease / cursor update). Phải qua function/DOT có gate.
- Cross-layer ràng buộc: producer + executor có thể là cùng process (ví dụ
fn_iu_collection_createvừa mutate vừa emit) miễn là phần "emit" gọi đếnfn_iu_emit_*chuẩn — không tự INSERT thẳng vàoevent_outbox.
§11.3 Quan hệ với Điều 35 (DOT)
DOT vừa là producer (DOT runs emit events) vừa là executor (DOT consumes review/approval tasks). Điều 35 vẫn là luật chủ quản cho DOT lifecycle; Điều 45 điều chỉnh bề mặt giao tiếp giữa DOT và queue substrate.
§11.4 Quan hệ với Agent/Hermes/Codex
Agent (Opus/GPT/Gemini) và Hermes/Codex là external executors đối với DB. Họ:
- Nhận tín hiệu từ queue substrate (qua
fn_*_unread, view, hoặc Directus collection). - Trả kết quả qua DOT call hoặc qua fn emit chuẩn.
- KHÔNG được phép INSERT thẳng
event_outboxngoài qua function gate (sử dụng pg_hba role + role-channel kiểm soát).
§11.5 Ranh giới executor (executor boundary clause)
Điều 45 v0.2 nâng ranh giới executor lên mức bất biến cứng, áp dụng cho mọi executor hiện hữu hoặc tương lai (GPT Council Round 1 patch):
executor_boundary:
executors:
- DOT # Điều 35
- Agent # Opus / GPT / Gemini
- Hermes
- Codex
- PG_worker # vd: iu_outbound_default
- external_worker # cron sidecar, IMAP daemon, vector_listener
- future_Kestra_adapter # khi mở
not_executors:
- MOT # MOT là template/orchestrator sinh job graph, KHÔNG phải executor — xem §13.4
rule:
- queue_PG_is_source_of_truth
- executor_only_claims_and_processes_work
- executor_must_return_result_status_evidence_to_PG
- executor_must_not_hold_private_source_of_truth
- executor_state_must_be_reconstructable_from_PG_after_restart
- executor_must_register_healthcheck_per_§15.3_before_enable
Hệ quả:
- Executor PHẢI ghi back trạng thái (work state machine §6.7), kết quả (success / refusal / failure), evidence ref (link tới
iu_route_dead_letter,dot_iu_command_run, hoặc audit row §15.2). - Executor KHÔNG được giữ "private queue" trong bộ nhớ process (in-memory deque, file-based queue, Redis ngoài DB) như SoT — phải đi qua substrate PG.
- Sau crash/restart, executor PHẢI tự reconstruct work plan bằng cách đọc PG, không từ checkpoint riêng/đĩa cứng cục bộ.
- Cross-reference: §11.2 rules (producer/queue/executor không trộn) + §15.5 silent-gap invariant.
§12. Trigger-in / Trigger-out cho Information Unit (và tổng quát)
§12.1 Trigger-in (SQL → event)
iu_sql_event_route là cơ chế generic bridge:
- Hàng đợi của routes:
source_object_kind ∈ {table, row, function, trigger, view}×sql_event ∈ {insert, update, delete, call, ddl_create, ddl_alter, ddl_drop}→ emit(target_event_domain, target_event_type, target_event_stream). - Tại Phase 1 vocab
target_event_domain ∈ {iu, iu_sql}— quá hẹp. Design pack §19 D8/Q8 mở rộng vocab này. - Mỗi route có
enabled,dry_run,fail_closed,idempotency_policy jsonb,payload_contract jsonb. - Safety CHECK đã ratified:
(enabled=false) OR (dry_run=true)— bật một route chỉ khi đã thông qua review.
Luật yêu cầu mọi trigger-in ĐĂNG KÝ trong bảng route. KHÔNG được tạo trigger ẩn AFTER INSERT bên cạnh event_outbox bỏ qua bảng route.
§12.2 Trigger-out (event → action)
fn_iu_auto_instantiate_from_event là prototype:
- Đọc event của một event_type cụ thể.
- Kiểm tra idempotency_key trong
iu_auto_instantiate_event_log. - Nếu mới → thực thi (mint instance, gọi DOT, gọi function khác).
- Ghi log idempotent.
Luật yêu cầu mọi consumer trigger-out:
- Có idempotency log riêng (hoặc partial UNIQUE constraint trên consumer table).
- Sử dụng lease nếu consumer có thể chạy song song.
- Có dead-letter path nếu side-effect có thể fail.
- KHÔNG được emit event-cycle (event A → consumer chạy → emit lại event A) trừ khi có
causation_id+ guard cycle detection.
§12.3 Information Unit two-way bridge
Bridge IU ↔ queue substrate đã tồn tại:
- IN:
fn_iu_lifecycle_log_emit_piece_event_trgtrigger từiu_lifecycle_log→event_outbox(event_domain='piece'). - OUT:
fn_iu_auto_instantiate_from_event→ tạo collection mới. - OUT:
fn_iu_route_deliver→ định tuyến event.
Luật ratify mô hình hai chiều. Quy định mới của Điều 44 (nếu có) phải tương thích với mô hình này.
§13. Customer-care / email / messaging — phạm vi tương lai
§13.1 Trạng thái
Tại thời điểm ban hành Điều 45, hệ thống CHƯA có substrate cho:
- Khách hàng (customer table, conversation log).
- Email (IMAP/SMTP ingest, message parsing).
- Messaging (chat thread, multi-party).
- MOT-generated workflows (MOT spec chưa stable).
§13.2 Forward-compatibility clause
Khi các domain trên được mở:
- Họ PHẢI đăng ký event_domain mới trong
event_type_registry(ví dụcustomer,email,chat,mot). - Họ PHẢI tuân §4 (signal not data) — message body lớn lưu nơi khác, queue chỉ giữ ref.
- Họ PHẢI tuân §6.4 (inclusion criteria) — không phải mọi email là event.
- Họ PHẢI có dispensation từ Council nếu cần CHECK vocab mới (stream mới, lane mới).
§13.3 Phạm vi không bao gồm tại Phase 1
Phase 1 (Điều 45 đầu tiên) không bao gồm:
- Substrate cho customer/email/messaging.
- MOT workflow execution.
- Cross-DB / federated queue.
Đây là design seam, không phải implementation. Khi nào những domain trên được mở, mỗi domain có sub-design pack riêng dưới Điều 45 mà KHÔNG cần amend Điều 45 (trừ khi vocab mới).
§13.4 Mother of Task (MOT) clause
Điều 45 v0.2 strengthen quan hệ luật giữa MOT và queue substrate (GPT Council Round 1 patch). MOT là template/config sinh job graph (đa-bước, đa-actor). Tại Phase 1, MOT spec chưa ổn định (xem §13.3), nhưng Điều 45 xác lập quan hệ luật bất biến để mọi sub-design pack MOT tương lai bị ràng buộc:
mother_of_task_clause:
MOT:
is_executor: false
role:
- emits_job_graph
- generates_workflow_instances_from_template_config
- delegates_execution_to_queue_executors
permitted_labels:
- MOT_template_generator
- MOT_job_graph_generator
- future_MOT_orchestrator # nhãn cho instance runtime đa-bước (KHÔNG phải executor)
forbidden_labels:
- future_MOT_executor # đã loại khỏi §11.5 — MOT KHÔNG bao giờ là executor
relation_to_queue:
- MOT_emits_job_graph
- queue_orchestrates_steps
- each_step_may_be_an_information_unit
- trigger_in_trigger_out_go_through_queue
- MOT_itself_is_not_an_executor # MOT plans; executors (§11.5) run
- MOT_instance_state_lives_in_PG_per_§6.7
- MOT_step_lifecycle_follows_work_state_machine_§6.7
Hệ quả:
- MOT KHÔNG được sinh job graph mà bỏ qua queue substrate Điều 45. Mỗi step PHẢI có entry queue và lifecycle theo work state machine §6.7.
- MOT có thể input từ trigger-in (§12.1) và output ra trigger-out (§12.2), miễn cả hai đi qua queue substrate.
- MOT step có thể là Information Unit (theo §3 — "không có luật riêng cho IU"); nhưng MOT step KHÔNG được phép tạo IU bypass Điều 37 cut alias / Điều 35 DOT pipeline.
- MOT runtime substrate cụ thể (bảng instance, step row, lifecycle vocab MOT-riêng, scheduler binding) thuộc sub-design pack riêng sẽ được Council mở khi MOT spec ổn định — KHÔNG amend Điều 45 trừ khi vocab fundamentally khác §6.1/§6.7.
Phase 1 KHÔNG ban hành substrate MOT; tuy nhiên kể từ thời điểm Điều 45 v0.2 ban hành, mọi nỗ lực mở MOT trong tương lai phải tuân clause này.
§14. No-vector-in-transient
§14.1 Ratify D36 NVSZ ở mức luật
Quy tắc transient payload không được phép vào vector layer (No-Vector Staging Zone — D36 design) được ratify cứng ở mức Điều 45:
event_outbox.safe_payloadKHÔNG được chứa keyvectorhoặcembedding.iu_staging_record.vector_excludedPHẢI mặc địnhtrue.iu_vector_sync_pointKHÔNG được chứastaging_record_idhoặc tham chiếu staging tier.- Không có path FK từ staging tier → vector sync tier.
- Mọi bảng queue substrate mới phải tuân quy tắc trên.
§14.2 4-layer guarantee
Luật ratify 4-layer guarantee đã chứng minh tại D36 NVSZ Macro A:
- CHECK constraint (cấp DB).
- Sidecar
collection_registry_vector_policy(cấp registry). - View
v_collection_vector_eligibility(cấp truy vấn). - Structural absence trên
iu_vector_sync_pointschema (cấp shape).
Mọi 4 layer phải tồn tại đồng thời.
§14.3 Vi phạm NVSZ
Một producer chèn vector vào safe_payload sẽ:
- INSERT thất bại do CHECK (layer 1).
- Phát sinh
system_issues.issue_kind='queue.nvsz_violation'. - Owner: producer agency.
- Refusal: producer phải sửa, không được skip.
(Cross-reference: D36 Collection Protocol Law.)
§15. Observability, audit, healthcheck
§15.1 Mandatory observability surface
Mọi queue substrate component PHẢI có quan sát được qua ít nhất một trong các phương tiện sau:
| Component | Observability surface |
|---|---|
| Producer | Event chính trong event_outbox (audit trail tự nó là evidence) |
| Pending → durable transition | View v_iu_event_backlog, v_iu_composer_event_backlog |
| Worker cursor | iu_route_worker_cursor rows + fn_iu_route_worker_health |
| Dead-letter | View v_iu_route_dead_letter_open |
| Lease state | dot_iu_runtime_lease row + healthcheck function |
| Trigger-out consumer | iu_auto_instantiate_event_log + view summary |
| Staging lifecycle | View v_iu_staging_record + iu_core.fn_iu_staging_healthcheck |
| DOT run | dot_iu_command_run + view v_dot_iu_command_run_health |
§15.2 Audit row contract
Mỗi mutation queue substrate PHẢI ghi audit:
created_attimestamptz NOT NULL DEFAULT now()actor_reftext NOT NULL CHECK btrim ≠ ''correlation_idtext nullable (nếu thuộc job/run/batch)source_systemtext NOT NULL ('trigger', 'worker', 'function', 'dot', 'health_executor', ...)
§15.3 Healthcheck function contract
Mỗi worker domain PHẢI cung cấp:
fn_<domain>_route_worker_health() returns jsonb
trả về:
{
"worker_name": "...",
"last_run_at": "...",
"ageSeconds": 12345,
"backlog_count": N,
"dead_letter_open": N,
"lease_active": bool,
"lease_age_seconds": N
}
Observer ngoài (D43 red_zones / D31 watchdog) đọc các healthcheck function này.
§15.4 Liveness contract
Luật yêu cầu:
- Mỗi worker có cadence dự kiến.
- Nếu
now() - last_run_at > 3 × expected_cadence→ emitsystem/queue_worker_silentevent (severity warning). - Nếu
> 10 × expected_cadence→ severity critical.
Threshold cụ thể thuộc design pack (Q11/Q25 §19).
§15.5 Heartbeat, stale-worker, silent gap (runtime observability invariant)
Điều 45 v0.2 nâng silent gap thành bất biến cứng cho mọi executor và worker domain (GPT Council Round 1 patch). §15.4 đã định nghĩa cadence event-emit; §15.5 nâng silent gap thành violation, không chỉ thông báo:
runtime_observability:
required:
- worker_heartbeat # last_run_at hoặc heartbeat row tối thiểu mỗi cadence
- cursor_last_run_at # `iu_route_worker_cursor.last_run_at` hoặc tương đương
- stale_threshold # ngưỡng cảnh báo (vd 3× expected_cadence theo §15.4)
- stale_worker_healthcheck # fn_<domain>_route_worker_health() returns jsonb (§15.3)
- dead_letter_visibility # view mở (vd `v_iu_route_dead_letter_open`)
rule:
- silent_gap_is_a_health_violation
- missing_heartbeat_must_emit_event_per_§15.4
- stale_worker_must_be_visible_to_D43_red_zones_and_D31_watchdog
- dlq_growth_must_be_observable_without_querying_internal_tables
- no_executor_may_run_without_registered_healthcheck
- silent_gap_must_be_attributable_to_a_named_executor_per_§11.5
Hệ quả:
- "Worker đang chạy nhưng không log" KHÔNG còn là trạng thái hợp lệ. Mọi gap > stale_threshold phải emit
system/queue_worker_silent(§15.4) và bị nhãn vi phạm trong audit. - DLQ phải có view mở truy cập được từ Directus / observer ngoài; KHÔNG được giấu trong bảng nội bộ không exposed.
- Mọi executor mới phải đăng ký
fn_<domain>_route_worker_health()(§15.3) TRƯỚC khi enable substrate (gate ban hành). - Cross-reference: §15.4 cadence rule + §11.5 executor boundary + §6.7 work state machine.
- §20.4 (transitional) vẫn áp dụng: silent gap đã có (iu_outbound_default 4-day gap tại 2026-05-22) KHÔNG bị truy cứu ngược; nhưng kể từ ban hành Điều 45 v0.2, mọi gap mới rơi vào §15.5 và bị xử lý.
§16. Tương thích với luật hiện hành
§16.1 Matrix cross-reference
compatible_with:
Dieu30_regression_protection:
relation: Queue events là một surface có thể regress; mọi event_type ratification phải có regression test.
boundary: D30 không quy định queue cụ thể; Điều 45 không phá D30.
Dieu31_integrity_and_refusal:
relation: Queue refusal (§8.5) đồng nhất với D31 refusal contract. system_issues là consumer của event_outbox với traffic lớn nhất (131k rows). Watchdog D31 đọc queue health.
boundary: D31 cấp luật toàn vẹn; Điều 45 thừa kế refusal pattern.
Dieu35_DOT_governance:
relation: DOT là producer + executor (§11.3). dot_iu_command_run + dot_iu_command_catalog vẫn thuộc D35. Vocab run_mode/run_status (§6.3) ratify trong cả 2 luật.
boundary: D35 chủ quản DOT lifecycle; Điều 45 chủ quản giao tiếp DOT ↔ queue substrate.
Dieu36_collection_protocol:
relation: NVSZ (§14) ratify từ D36. Birth events emit qua queue. staging.* event_type được đăng ký từ D36 Macro A.
boundary: D36 chủ quản birth + collection; Điều 45 không can thiệp birth gate.
D36_NVSZ:
relation: No-vector-in-transient là invariant chung (§14). 4-layer guarantee được ratify.
boundary: D36 NVSZ design là spec; Điều 45 nâng nó lên luật chung cho mọi queue substrate.
Dieu37_governance_organization:
relation: event_subscription dùng vocab actor_ref (`user:`, `agency:`, `role:`, `agent:`) đồng nhất với D37 agency model. Routing dựa trên agency là một quan hệ Điều 45 ↔ D37.
boundary: D37 chủ quản tổ chức bộ máy; Điều 45 dùng D37 vocab cho recipient routing.
Dieu44_implementation_discipline:
relation: Điều 45 substrate hiện hành sinh ra từ Điều 44 P3D4C0X design + Phase 2 PoC. Điều 45 thừa kế và mở rộng. Điều 44 KHÔNG quy định queue invariants; Điều 45 lấp khoảng đó.
boundary: Điều 44 chủ quản IU-0 minimum standard; Điều 45 chủ quản queue substrate cho mọi domain (bao gồm IU).
§16.2 Quy tắc không xâm phạm
Điều 45 KHÔNG:
- Sửa Điều 30/31/35/36/37/44.
- Thêm vocab vào các luật trên.
- Đổi tên hàm
fn_iu_*đã hiện hành (§3.3 transitional). - Thay đổi schema
event_outboxđã live.
Điều 45 CHỈ:
- Ratify các invariant đã có thực tế.
- Phát biểu rõ ranh giới mới (executor layer §11, signal-not-data §4, NVSZ §14).
- Mở chỗ cho substrate mở rộng (job substrate, customer-care, email, MOT) tương lai.
§17. Mẫu bị cấm
§17.1 Anti-patterns hard-reject
| Anti-pattern | Vi phạm | Hệ quả |
|---|---|---|
| Distributed queue ngoài PG làm SoT (Redis Streams, NATS) | §5.1 | INSERT cấm; refusal contract |
| Producer thực thi business logic của consumer trong cùng transaction | §11.2 | Code review reject; CI guard nếu detect |
Trigger AFTER INSERT trên event_outbox gọi business action |
§11.2 | DDL reject; chỉ cho phép emit + audit |
| Lưu body/blob/vector/secret/token trong safe_payload | §4.1, §14 | CHECK reject; INSERT fail |
| Auto-replay dead-letter mà không có operator action | §8.4 | Worker code reject |
| Skip idempotency để tăng tốc | §7 | Code review reject |
| Bypass lease bằng raw UPDATE | §11.2 (rule 3), §8.3 | Refusal |
Sử dụng LISTEN/NOTIFY làm SoT thay outbox |
§5.1, §5.3 | DDL reject |
| Tạo bảng outbox riêng cho domain mới | §3.1 | Refusal trừ khi có dispensation |
| Hard-code event_type không đăng ký registry | §3.2, §6.4 | Producer fail |
Schedule recurring jobs ngoài DB mà không record next_run_at |
§9.3 | Observability gap; refusal |
| Pull queue mà không SELECT FOR UPDATE SKIP LOCKED | §7.3 | Race condition; code review reject |
| Worker chạy không cập nhật cursor | §15.1 | Observability gap; refusal |
| Một consumer emit lại chính event đã consume mà không có causation_id | §12.2 (rule 4) | Cycle risk; refusal |
§17.2 Pattern không khuyến khích (warn, không hard-reject)
- Worker tick mỗi <60s mà không có pg_cron — gây tải vô ích nếu backlog rỗng. Chấp nhận nhưng cảnh báo.
- Subscription trống (broadcast fallback) — gây không xác định recipient. Cảnh báo, recommend cấu hình rõ.
- Event_subject_ref null — chấp nhận cho event không gắn entity (ví dụ system milestone) nhưng cảnh báo trong code review.
§18. Kỷ luật triển khai (implementation discipline)
§18.1 Tách Luật / Thiết kế / Triển khai
- Điều 45 (luật): invariant + vocab + boundary.
- Design pack: schema thay đổi, function signature, vocab mới, retry policy concrete, scheduler decision.
- Triển khai: migration, hook, trigger, function body, test, rollout.
Một thay đổi vi phạm Điều 45 invariant PHẢI sửa Điều 45 trước (amendment + Council review), sau đó mới design pack + migration. KHÔNG được "thực tế hoá" trước, "ratify" sau (như đã xảy ra với Phase 2 PoC — luật này nay sửa hậu quả).
§18.2 Phase 1 ban hành = giữ nguyên hiện trạng + chuẩn hoá
Phase 1 ban hành Điều 45 KHÔNG:
- Tạo bảng mới.
- Sửa CHECK constraint hiện hành.
- Thay đổi function signature.
- Cài đặt
pg_cron. - Thêm trigger.
Phase 1 CHỈ:
- Ratify vocab đã CHECK-cứng.
- Ratify pattern đã hiện hữu (lease, dead-letter, cursor, idempotency log).
- Phát biểu ranh giới executor / queue / producer.
- Mở khoảng cho design pack tiếp theo.
§18.3 Quy trình ban hành
- v0.1 DRAFT (file này) → upload KB → notify Council.
- GPT review round 1 → fix → v0.2.
- Gemini review round 1 (nếu Council yêu cầu) → fix → v0.3.
- User approve → ban hành v1.0 (rename: bỏ "DRAFT", thêm BAN HÀNH banner).
- Cross-reference cập nhật ở: HP index, D44 trien-khai design tree, START-HERE cutting operator.
§18.4 Sub-design packs
Sau ban hành, các sub-design pack được phép dispatch:
- DP1.
pg_cronadoption (xem D1 §19) — đụng §5.4 và §9. - DP2. Job substrate (xem D2 §19) — đụng §1.2 nhóm D và §3.1.
- DP3. Retry policy concrete (xem D4 §19) — đụng §8.1.
- DP4. NOTIFY bridge (xem D5 §19) — đụng §5.4 và §15.4.
- DP5. Trigger-IN vocab widening (xem Q8 survey) — đụng §12.1.
- DP6. Subscription configuration (xem Q26 survey) — đụng §16.1 D37 routing.
- DP7. Event_outbox partitioning (xem §6 survey risk) — đụng §15 observability.
Mỗi DP có prompt, design pack, GPT review, migration plan riêng — KHÔNG bypass Điều 45 ratification cycle.
§19. Câu hỏi mở trước khi triển khai
Các câu hỏi này KHÔNG có câu trả lời trong Điều 45. Chúng thuộc design pack/sub-design pack hoặc Council decision sau ban hành. (Đầy đủ 28 câu trong …/v0.6-system-wide-pg-native-queue-law-readiness-survey/08-….)
| ID | Câu hỏi | Tác động |
|---|---|---|
| D1 | Cài pg_cron hay tiếp tục external invocation? |
§5.4, §9.4 |
| D2 | Job substrate: mở rộng event_outbox (event_domain='job') hay tạo job_outbox riêng? |
§1.2 nhóm D, §3.1 |
| D3 | Inclusion criteria §6.4 có cần enforce tại event_type_registry.insert? |
§6.4 |
| D4 | Retry max_attempts mặc định, per-domain override? | §8.1 |
| D5 | NOTIFY bridge cho event_outbox: bật hay không? | §5.4, §15.4 |
| D6 | Partition event_outbox theo created_at (monthly)? Threshold 5M rows? |
§15 risk |
| D7 | Recurring schedule table — thêm bảng queue_schedule hay dùng dot_config? |
§9.3 |
| D8 | Worker scope: per-domain workers hay 1 worker fan-out? | §15.1 |
| D9 | Subscription resolution rule: broadcast fallback hay deny-by-default? | §11.4 |
| D10 | Cutting flow puller automation: có/không? | §3.3, §11.2 |
| D11 | event_pending có cần priority column không? |
§6, §9 |
| D12 | Cross-DB federation: bao giờ? Ảnh hưởng event_id (uuidv7)? |
§13.3, ngoài Phase 1 |
| Q5 | event_outbox unique-index policy: confirm theo design hay sửa? |
§7.1 |
| Q6 | Trace columns causation_id, source_document_ref, import_batch_ref, processed_at, event_subject_type, source_function thiếu trong live — thêm bao giờ? |
§16.1 |
| Q7 | iu_notification_event legacy: deprecate dứt khoát hay giữ compat? |
§20 |
| Q8 | iu_sql_event_route.target_event_domain mở rộng vocab? |
§12.1 |
| Q11 | External worker cadence: ai owns, document ở đâu? | §5.4, §15.4 |
| Q25 | 4-day silent gap (last_run 2026-05-22) có expected? | §15.4 |
| Q26 | Sub-config hiện chỉ 3 rows — minimal-by-design hay under-config? | §11.4 |
| Q27 | dead_lettered=0 vs attempts_written=67: healthy hay worker không surface failure? | §15.1 |
| Q28 | event_domain='piece' vs 'iu' overlap — merge hay tách? |
§6.5 |
(Đầy đủ 28 câu — xem survey report 08.)
§20. Điều khoản chuyển tiếp (transitional clause)
§20.1 Substrate hiện hành tiếp tục hoạt động
Tại thời điểm Điều 45 ban hành:
event_outbox 131,746 rows — TIẾP TỤC HOẠT ĐỘNG, không sửa schema.
event_read 131,407 rows — TIẾP TỤC.
event_subscription 3 rows — TIẾP TỤC, mở rộng qua design pack.
event_type_registry 31 rows — TIẾP TỤC, mở rộng qua ratification.
event_pending 0 rows — TIẾP TỤC, schema giữ nguyên.
iu_route_worker_cursor 1 row — TIẾP TỤC, mở thêm cursor qua design.
iu_route_dead_letter 0 rows — TIẾP TỤC.
iu_sql_event_route 1 row (dry) — TIẾP TỤC, mở rộng qua design.
dot_iu_runtime_lease 0 rows — TIẾP TỤC.
iu_core.iu_staging_record/payload — TIẾP TỤC (Điều 36 NVSZ ratify).
dot_iu_command_run — TIẾP TỤC (Điều 35 chủ quản).
iu_auto_instantiate_event_log 33 rows — TIẾP TỤC.
iu_notification_event 0 rows — LEGACY (D36 §I rev1); chờ Q7 decision.
iu_notification_read 0 rows — LEGACY; chờ Q7.
§20.2 Hàm hiện hành tiếp tục hoạt động
Tên hàm fn_iu_* được phép giữ nguyên dù phạm vi không còn riêng IU (§3.3). Đổi tên là thay đổi đột phá; chỉ làm trong design pack riêng có migration + alias compat.
§20.3 Config hiện hành tiếp tục hoạt động
dot_config keys hiện hữu:
event.global.delivery_lane_default = 'immediate'
event.system.poc_status = 'enabled'
iu_core.composer_enabled = 'false'
iu_core.operator_runtime_enabled = 'false'
iu_core.retention_enabled = 'false'
iu_core.route_worker_enabled = 'true'
piece_event_runtime.dry_run_only = 'true'
piece_event_runtime.emit_enabled = 'false'
hc_executor_max_runtime_seconds = '600'
KHÔNG sửa tại Phase 1. Mọi key mới phải tuân namespace prefix (event., dot., iu_core., queue.).
§20.4 Worker silent gap
iu_outbound_default last_run 2026-05-22 (4-day gap so với 2026-05-26) là tình trạng hiện tại chứ không phải vi phạm Điều 45 trước khi luật được ban hành. Sau ban hành, Q11/Q25 phải được trả lời và external cadence được document hóa; vi phạm tương lai sẽ phát sinh system/queue_worker_silent event theo §15.4.
§20.5 PG version
PostgreSQL 16.13 là điều kiện đủ. Điều 45 không ràng buộc PG 18.
Khi/nếu PG 18 được nâng cấp (qua macro readiness riêng), Điều 45 KHÔNG bị invalid. Các feature PG 18 (uuidv7(), OLD/NEW RETURNING, AIO, temporal constraints) có thể được sử dụng trong design pack, nhưng KHÔNG phải tiền điều kiện của luật.
§21. Cross-reference
| Điều/Pack | Quan hệ |
|---|---|
| Hiến pháp Kiến trúc (HP) | Bất biến NT (PG-first; SSOT; Assembly First) — Điều 45 thừa kế. |
| Điều 0 / 0-B / 0-G / 0-H | Object identity, birth gate, assembly first — không xung đột. |
| Điều 13 | Tự sửa chữa — refusal contract §8.5 tương thích. |
| Điều 22 | System Issues — heaviest event consumer (131k rows). |
| Điều 24 | Single Provider Source — queue không phá. |
| Điều 28 | Display rules — UI exposure qua Directus collection vẫn áp dụng. |
| Điều 29 | Phân loại collection — birth events theo D36. |
| Điều 30 | Regression protection — queue event_type cần regression coverage. |
| Điều 31 | System Integrity — watchdog reads queue health. |
| Điều 32 | (cross-ref D38 metadata) — vocab discipline đồng pha. |
| Điều 35 | DOT Governance — DOT là producer + executor. |
| Điều 36 | Collection Protocol — NVSZ ratify, birth event flow. |
| Điều 37 | Governance Organization — agency/role vocab cho event_subscription. |
| Điều 39 | Knowledge Graph — KG events đăng ký event_domain='kg'. |
| Điều 43 | Context Pack — system milestone events → red_zones section. |
| Điều 44 | IU-0 Implementation — phần queue substrate sinh ra dưới Điều 44, nay chuyển ownership invariants sang Điều 45. |
§22. Verification block
phase_status=ENACTED
version=v1.0
ban_hanh=true
council_round_1_gpt_patch_applied=true
council_round_1_gpt_review_addressed=true
council_round_2_gemini_review_addressed=skipped_optional
council_approved=true
enactment_approved=true
user_approval_required=satisfied
user_approval_date=2026-05-26
enactment_date=2026-05-26
amendment_process_required_for_future_changes=true
user_approved=false
ban_hanh=false
scope_system_wide=true
covers_events=true
covers_tasks=true
covers_messages=true
covers_jobs=true
covers_triggers_in=true
covers_triggers_out=true
covers_customer_care_email_msg=design_seam_only
covers_mot_workflows=design_seam_only
pg_native_principle=true
pg_is_sot=true
queue_carries_signal_not_data=true
no_vector_in_transient=ratified
pg_cron_install_required_for_law=false
pg18_upgrade_required_for_law=false
listen_notify_as_sot=false_explicitly_forbidden
vocab_event_domain=9_ratified
vocab_event_stream=7_ratified
vocab_delivery_lane=2_ratified
vocab_event_severity=3_plus_null
vocab_staging_lifecycle=7_ratified
vocab_dot_run_mode=3_ratified
vocab_dot_run_status=5_ratified
vocab_inclusion_criteria=7_positive_plus_7_negative
compatibility_dieu30=explicit
compatibility_dieu31=explicit
compatibility_dieu35=explicit
compatibility_dieu36=explicit
compatibility_d36_nvsz=ratified
compatibility_dieu37=explicit
compatibility_dieu44=explicit_transitional
transitional_substrate_preserved=true
transitional_legacy_iu_notification_pending_q7=true
transitional_worker_silent_gap_acknowledged=true
transitional_pg_version_neutral=true
open_questions=21_routed_to_design_pack
sub_design_packs_proposed=7
anti_patterns_listed=14_hard_plus_3_soft
no_table_created=true
no_migration_run=true
no_production_mutation=true
no_pg_cron_installed=true
no_pg_upgrade=true
no_event_outbox_change=true
no_start_here_patch=true
no_mark_cut_alias_touched=true
event_vs_job_distinction=explicit_§6.6
work_state_machine_invariant=explicit_§6.7_min_9_states
executor_boundary_clause=explicit_§11.5
mother_of_task_clause=explicit_§13.4
runtime_observability_silent_gap_rule=explicit_§15.5
gpt_council_round_1_patch=applied_2026-05-26
v0_2_1_cleanup_patch_applied=2026-05-26 # metadata + council wording + MOT executor boundary cleanup
mot_is_executor=false
mot_role=template_generator_emits_job_graph_delegates_to_queue_executors
v1_0_enactment_applied=2026-05-26 # User approval, status flip DRAFT → ENACTED, không sửa nội dung
enactment_report=knowledge/current-state/reports/dieu45-pg-native-queue-law-v1-0-enacted-2026-05-26.md
next_required_pack=DIEU45_POST_ENACTMENT_HOUSEKEEPING_AND_DESIGN_BACKLOG_DISPATCH
Điều 45 v1.0 BAN HÀNH | PG-Native Queue & Task Orchestration Law | Soạn bởi Claude Opus 4.7 (1M) căn cứ điều tra survey 2026-05-26 + đề xuất GPT 2026-05-26 + GPT Council Round 1 patch 2026-05-26 + v0.2.1 cleanup 2026-05-26 | BAN HÀNH 2026-05-26 (User approval pass) — nội dung khoá, mọi thay đổi tiếp theo phải qua amendment process. Enactment report: knowledge/current-state/reports/dieu45-pg-native-queue-law-v1-0-enacted-2026-05-26.md.