Điều 4: Luật Sinh sản
ĐIỀU 4: LUẬT SINH SẢN — KHÔNG AI ĐƯỢC "ĐẺ BỪA BÃI"
§1. Nguyên tắc
AI/Agent xây hệ thống PHẢI tuân thủ quy trình. Lãnh đạo phải làm gương.
§2. Quy trình bắt buộc
Mọi thực thể mới PHẢI:
- Tạo qua DOT/script chuẩn (KHÔNG code trực tiếp)
- Cấp ID tự động
- Đăng ký vào registry tự động
- Gán metadata tối thiểu theo quy cách Đ3 §2. Kiểm tra description theo §2.1 bên dưới.
- Thông báo hệ thống liên quan
v4.0 bổ sung: Với Điều 0-H, "thông báo hệ thống liên quan" = DOT tự đồng bộ 5 tầng (PG + Directus + Nuxt + Agent Data + Qdrant). 1 khai báo DOT → 5 tầng tự biết.
§2.1 — Birth Description Guard (bổ sung S178 Fix 23, Đ43 Phase C Track A)
Mọi entity mới INSERT vào bảng có cột description PHẢI được kiểm tra description tại thời điểm sinh.
Mức enforce theo governance_role (Đ29) — policy axis:
| governance_role | WARN mode | BLOCK mode |
|---|---|---|
| governed | Cho qua, H11 bắt sau | RAISE EXCEPTION — reject INSERT |
| observed | Cho qua, H11 log INFO | Cho qua |
| excluded | Bỏ qua | Bỏ qua |
| NULL (chưa đăng ký) | RAISE WARNING + cho qua | RAISE EXCEPTION |
Config mode:
INSERT INTO dot_config(key, value, description) VALUES
('description_enforcement_mode', 'warn',
'Đ4 §2.1: warn=cho qua+H11 audit, block=reject. Chuyển block sau backfill + 7 ngày stable.');
PG function — fn_description_birth_guard():
CREATE OR REPLACE FUNCTION fn_description_birth_guard()
RETURNS TRIGGER AS $$
DECLARE
_mode TEXT;
_gov_role TEXT;
_min_len INT;
_table_min INT;
_desc TEXT;
BEGIN
-- Đọc mode (NT4 config-driven)
SELECT value INTO _mode FROM dot_config
WHERE key = 'description_enforcement_mode';
IF _mode IS NULL THEN _mode := 'warn'; END IF;
-- Đọc baseline min length
SELECT value::int INTO _min_len FROM dot_config
WHERE key = 'description_min_length';
IF _min_len IS NULL THEN _min_len := 30; END IF;
-- Override threshold per table nếu có (pattern: <table>_description_min_length)
BEGIN
SELECT value::int INTO _table_min FROM dot_config
WHERE key = TG_TABLE_NAME || '_description_min_length';
IF _table_min IS NOT NULL THEN
_min_len := _table_min;
END IF;
EXCEPTION WHEN OTHERS THEN NULL;
END;
-- Tìm governance_role
SELECT governance_role INTO _gov_role
FROM collection_registry
WHERE collection_name = TG_TABLE_NAME;
-- NULL = lỗi quản trị, KHÔNG bỏ qua
IF _gov_role IS NULL THEN
IF _mode = 'block' THEN
RAISE EXCEPTION
'Đ4 §2.1: Bảng % chưa đăng ký collection_registry.', TG_TABLE_NAME;
ELSE
RAISE WARNING 'Đ4 §2.1: Bảng % chưa đăng ký collection_registry.', TG_TABLE_NAME;
RETURN NEW;
END IF;
END IF;
-- excluded → bỏ qua
IF _gov_role = 'excluded' THEN RETURN NEW; END IF;
-- Chuẩn hóa description (btrim + COALESCE, generic access)
_desc := btrim(COALESCE((to_jsonb(NEW)->>'description')::text, ''));
-- Check: rỗng / ngắn / gaming
IF _desc = '' OR length(_desc) < _min_len
OR _desc ~ '^(.)\1{9,}$'
OR _desc ~ '^[.\-_\s]{10,}$' THEN
IF _gov_role = 'governed' AND _mode = 'block' THEN
RAISE EXCEPTION
'Đ4 §2.1 + Đ3 §2.1: Bảng % (governed) — description >= % ký tự, không gaming.',
TG_TABLE_NAME, _min_len;
END IF;
-- WARN mode hoặc observed: cho qua, H11 audit sau (dual-trigger NT12)
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Gắn trigger cho mỗi bảng governed có cột description:
-- Ví dụ:
CREATE TRIGGER trg_desc_guard_dot_tools
BEFORE INSERT OR UPDATE OF description ON dot_tools
FOR EACH ROW EXECUTE FUNCTION fn_description_birth_guard();
§2.1.1 — Auto-gen mô tả cơ bản + Companion trigger (bổ sung S178 Fix 28, Description Governance Package)
Birth guard mở rộng: ngoài KIỂM TRA (C1-C3), còn TỰ SINH mô tả cơ bản khi description NULL/rỗng.
Helper function 1 — fn_render_description_template() contract v1:
CREATE OR REPLACE FUNCTION fn_render_description_template(
p_template TEXT, p_row_data JSONB
) RETURNS TEXT
-- CONTRACT v1:
-- Placeholder: {key} với key phẳng [A-Za-z0-9_]+ ONLY
-- KHÔNG nested path ở v1
-- key không tồn tại / NULL → render '(chưa có)'
-- Dữ liệu chèn nguyên văn, KHÔNG eval regex
Helper function 2 — fn_description_context() cho computed placeholders:
CREATE OR REPLACE FUNCTION fn_description_context(
p_table_name TEXT, p_row JSONB
) RETURNS JSONB
-- Computed placeholders (cross-table):
-- species_code: LEFT JOIN species_collection_map WHERE collection_name = p_table_name AND is_primary = true
-- composition_level: LEFT JOIN entity_species ON species_code
-- governance_role: LEFT JOIN collection_registry WHERE collection_name = p_table_name
-- _source_table: p_table_name (inject runtime)
-- JOIN miss → key = null → fn_render renders '(chưa có)'
-- v1: KHÔNG bao gồm source_database (chưa có join chuẩn)
2 trigger tách biệt (R2 P9 CHỐT):
| Trigger | Timing | Function | Nhiệm vụ |
|---|---|---|---|
trg_desc_guard_<table> |
BEFORE INSERT OR UPDATE | fn_description_birth_guard() |
Lookup template 4 tầng → render → gán NEW.description. KHÔNG ghi entity_labels. |
trg_desc_provenance_<table> |
AFTER INSERT | fn_auto_label_provenance() |
INSERT entity_labels row PROV-DOT cho entity vừa sinh. Cùng transaction, FK safe. |
Logic mở rộng BEFORE INSERT (fn_description_birth_guard):
-- Sau khi chuẩn hóa _desc:
IF _desc = '' THEN
-- Lookup template 4 tầng (Đ3 §2.6)
_comp_level := (fn_description_context(TG_TABLE_NAME, to_jsonb(NEW)))->>'composition_level';
-- 1. desc_template_<table>_<level>
-- 2. desc_template_<table>
-- 3. desc_template_level_<level>
-- 4. desc_template_default
-- 5. NULL → fail-safe, KHÔNG gen
IF _template IS NOT NULL THEN
_row_data := to_jsonb(NEW) || fn_description_context(TG_TABLE_NAME, to_jsonb(NEW));
NEW.description := fn_render_description_template(_template, _row_data);
END IF;
END IF;
-- Sau auto-gen, kiểm tra C1-C3 như cũ
Companion trigger — fn_auto_label_provenance():
CREATE OR REPLACE FUNCTION fn_auto_label_provenance()
RETURNS TRIGGER AS $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM entity_labels
WHERE entity_code = NEW.code
AND label_code IN ('PROV-DOT','PROV-AI','PROV-HUMAN')
) THEN
INSERT INTO entity_labels(entity_code, label_code, assigned_by)
VALUES (NEW.code, 'PROV-DOT', 'fn_auto_label_provenance')
ON CONFLICT DO NOTHING;
END IF;
RETURN NEW;
END; $$ LANGUAGE plpgsql;
Quy tắc:
- Auto-gen chỉ khi description NULL/rỗng. Đã có → KHÔNG ghi đè (NT9).
- Template NULL → KHÔNG gen, fail-safe.
- 2 trigger cùng transaction — entity ra đời đã có description + PROV-DOT, 0 khoảng trống.
- Trigger ordering:
trg_auto_id<trg_desc_guard<trg_desc_provenance(alphabetically, PG convention).
Viện dẫn: Template source + lookup → Đ3 §2.6. Template nội dung → Phụ lục Đ3 §A.1. Provenance → Đ24 FAC-PROV. Context → Đ29 (loài) + Đ0-B (lớp cấu tạo).
Dual-trigger NT12:
- Chính:
fn_description_birth_guard— PG BEFORE INSERT/UPDATE — gate tại birth - Phụ: H11 health check (cron 3h) — audit legacy + bypass
Thêm bảng governed mới vào scope: CREATE TRIGGER cho bảng đó. Function generic — 0 sửa code. NT2+NT4.
Lưu ý triển khai: dot_tools sẽ có 2 BEFORE INSERT triggers (fn_birth_gate Đ35 + fn_description_birth_guard Đ4). Cả hai check field khác nhau, không deadlock.
Phân trách nhiệm SSOT:
- Đ4 §2.1 định nghĩa trigger function + logic kiểm tra → SSOT cho "kiểm tra CÁI GÌ"
- Đ22 HC-TRIGGER giám sát trigger đã gắn đủ chưa → SSOT cho "AI LÀM CHƯA"
- Bảng governed mới có cột description → Đ22 HC-TRIGGER tự phát hiện thiếu + tự gắn. Agent KHÔNG cần nhớ (NT2).
§3. Hình phạt
Tạo thực thể không qua quy trình = PR reject. Không ngoại lệ.
→ Chi tiết quy trình: birth-procedures.md, entity-lifecycle.md
CHANGELOG (inline)
| Ngày | Nội dung |
|---|---|
| S178 Fix 23 (2026-04-20) | +§2.1 Birth Description Guard: PG function fn_description_birth_guard(), governance_role policy axis (Đ29), mode WARN/BLOCK config-driven, dual-trigger NT12, anti-gaming regex, btrim, per-table threshold override. Sửa §2 bước 4 tham chiếu Đ3 §2. Hội đồng 2 vòng APPROVE FINAL (Gemini 10 + GPT 9.4). |
| S178 Fix 28 (2026-04-22) | +§2.1.1 Auto-gen mô tả cơ bản (fn_render_description_template, fn_description_context, fn_auto_label_provenance). Companion trigger trg_desc_provenance AFTER INSERT. Lookup template 4 tầng. Description Governance Package — Council 2 vòng. |