KB-19AC rev 21

Đ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

57 min read Revision 21
lawdieu-45queuetask-orchestrationpg-nativeoutboxtrigger-intrigger-outenactedv1.0ban-hanhban-hanh-2026-05-26council-approveduser-approvedpg-native-queuequeue-lawmot-not-executorwork-state-machineevent-vs-jobsilent-gap-heartbeatsignal-not-data

Đ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_applied thay vì _approved + enactment_approved=false + MOT loại khỏi enumeration executor ở §11.5 và §13.4 codify MOT.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:

  1. 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.
  2. Hàng đợi mang tín hiệu, không mang dữ liệu (payload_ref pattern). Body lớn, blob, vector, secret, conversation đầy đủ — KHÔNG bao giờ đặt trong outbox.
  3. 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.
  4. No-vector-in-transient — ratify cứng D36 NVSZ ở mức luật.
  5. 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ý.
  6. Compatibility hard: không sửa Điều 30/31/35/36/37/44; cross-reference rõ.
  7. 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.
  8. Substrate hiện hành (event_outbox 131,746 rows + worker iu_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_notify thay cho bảng outbox bền vững.
  • KHÔNG dùng pg_advisory_lock thay cho dead_letter / error_count (lock không phải retry).
  • KHÔNG dùng LISTEN channel 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_cron KHÔNG được cài đặt trên cluster sản xuất. Việc gọi worker tick (fn_iu_route_worker_run và 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ả:

  1. 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.
  2. Mọi job có deadline PHẢI ghi deadline_at vào bảng để observer ngoài có thể alert nếu deadline trôi qua mà chưa xử lý.
  3. 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).
  4. 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:

  1. Lifecycle change của entity có governance owner (mints, drafts, approves, applies, retires).
  2. Approval/review request mà human/AI cần action.
  3. Health/integrity alert severity ≥ warning.
  4. DOT execution result (paired theo Điều 35).
  5. System milestone (Điều 43 lifecycle).
  6. Agency/governance task assigned.
  7. 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'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_outbox rồ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ộng run_status thà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:

  1. CHECK + UNIQUE constraint cấp DB (defense-in-depth #1).
  2. SELECT ... FOR UPDATE SKIP LOCKED (defense-in-depth #2 — chỉ một worker thấy row).
  3. 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_count integer, default 0.
  • event_pending.last_error text.
  • iu_route_worker_cursor.attempts_written bigint.

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:

  1. 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).
  2. 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ó).
  3. 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).
  4. 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_count set bằng max_attempts ngay (không cần đợi attempt thực tế).
  • last_error ghi 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 count
  • attempts_written += successful count
  • dead_lettered += failed-after-attempts count
  • last_run_summary jsonb chứ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

  1. Producer KHÔNG được phép thực thi business logic của consumer. Producer enqueue rồi kết thúc.
  2. 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.
  3. 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.
  4. Cross-layer ràng buộc: producer + executor có thể là cùng process (ví dụ fn_iu_collection_create vừa mutate vừa emit) miễn là phần "emit" gọi đến fn_iu_emit_* chuẩn — không tự INSERT thẳng vào event_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_outbox ngoà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:

  1. Có idempotency log riêng (hoặc partial UNIQUE constraint trên consumer table).
  2. Sử dụng lease nếu consumer có thể chạy song song.
  3. Có dead-letter path nếu side-effect có thể fail.
  4. 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_trg trigger từ iu_lifecycle_logevent_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ở:

  1. Họ PHẢI đăng ký event_domain mới trong event_type_registry (ví dụ customer, email, chat, mot).
  2. Họ PHẢI tuân §4 (signal not data) — message body lớn lưu nơi khác, queue chỉ giữ ref.
  3. Họ PHẢI tuân §6.4 (inclusion criteria) — không phải mọi email là event.
  4. 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:

  1. event_outbox.safe_payload KHÔNG được chứa key vector hoặc embedding.
  2. iu_staging_record.vector_excluded PHẢI mặc định true.
  3. iu_vector_sync_point KHÔNG được chứa staging_record_id hoặc tham chiếu staging tier.
  4. Không có path FK từ staging tier → vector sync tier.
  5. 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:

  1. CHECK constraint (cấp DB).
  2. Sidecar collection_registry_vector_policy (cấp registry).
  3. View v_collection_vector_eligibility (cấp truy vấn).
  4. Structural absence trên iu_vector_sync_point schema (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_at timestamptz NOT NULL DEFAULT now()
  • actor_ref text NOT NULL CHECK btrim ≠ ''
  • correlation_id text nullable (nếu thuộc job/run/batch)
  • source_system text 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 → emit system/queue_worker_silent event (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) 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

  1. v0.1 DRAFT (file này) → upload KB → notify Council.
  2. GPT review round 1 → fix → v0.2.
  3. Gemini review round 1 (nếu Council yêu cầu) → fix → v0.3.
  4. User approve → ban hành v1.0 (rename: bỏ "DRAFT", thêm BAN HÀNH banner).
  5. 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_cron adoption (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.