AI Council Review — GPT — Kiến trúc v3.0 — Vòng 3
AI Council Review — GPT — Kiến trúc v3.0 — Vòng 3
Ngày: 2026-03-19 Agent: GPT Tài liệu đã đọc:
knowledge/dev/planning/architecture-v3-consolidated.mdknowledge/dev/planning/council-synthesis-v3-round1.mdknowledge/dev/architecture/entity-lifecycle.mdknowledge/dev/planning/council-review-gpt-v3-round2.mdknowledge/dev/planning/council-review-gemini-v3.mdknowledge/dev/architecture/index.md(đọc phần chỉ mục/tóm tắt)
Đánh giá tổng thể
Kết luận: APPROVE WITH CHANGES
Bản dự thảo đã đạt mức rất gần “proposal v3.1 có thể thi hành”, và về hướng lớn tôi đồng ý với cả 3 luật mới. Tuy nhiên, nếu triển khai as-is thì sẽ gặp 3 vấn đề đáng kể:
- một số SQL/schema còn chưa đủ chặt để chạy production,
- decision tree hiện vẫn còn mờ ở ranh giới managed / derived / log / relation,
- Universal Rules Engine mới là “hàm quét”, chưa phải engine vận hành hoàn chỉnh.
Tôi khuyến nghị giữ nguyên khung Điều 27-29, nhưng sửa một số điểm ở schema, trigger strategy, measurement contracts, và lifecycle semantics trước khi ban hành chính thức.
C1. Xung đột với Hiến pháp hiện hành
1. Điều 27 vs Điều 0 — có conflict không?
Không conflict trực diện, nhưng có 2 chỗ cần viết rõ để tránh hiểu sai.
Điểm phù hợp
Điều 0 định nghĩa thực thể được quản trị dựa trên identity + registry + metadata + quan hệ + Lớp 3. Điều 27 không phá định nghĩa này; nó chỉ thêm chiều thời gian/vòng đời cho thực thể đã được quản trị. Điều đó là hợp lý.
Chỗ cần sửa
(a) draft có phải là “thực thể được quản trị đầy đủ” chưa?
Điều 27 hiện cho draft → active, nhưng Điều 0 yêu cầu entity có đủ tiêu chí để gọi là managed entity. Vì vậy nên ghi rõ:
draftlà managed entity đang trong giai đoạn chưa active, không phải “nửa entity”.- Muốn được insert ở trạng thái
draft, vẫn phải có identity tối thiểu + registry + metadata tối thiểu.
(b) merged không nên là “status thường” nếu được mô tả là terminal nhưng vẫn nằm cùng cột với draft/active/deprecated/retired.
Tôi đề nghị tách:
lifecycle_status:draft|active|deprecated|retiredterminal_reason:merged|split_replaced|archived|none
Lý do: merged không cùng bản chất với deprecated; nó là kết quả nghiệp vụ đặc biệt của một pipeline biến đổi.
2. Điều 28 vs Điều 0-B — 6 layers có map đúng không?
Về hướng thì đúng, nhưng câu chữ hiện tại dễ gây hiểu nhầm giữa “layer” và “composition level”.
Điều 0-B phân biệt rất rõ:
- Lớp = atom/molecule/compound/material/product/building
- Tầng = kiến trúc
- Layer = navigation UI
Trong universal_edges đang dùng source_layer, target_layer INT. Đây là chỗ xung đột thuật ngữ tiềm ẩn. Tôi đề nghị đổi tên cột ngay:
source_composition_level VARCHAR(20)target_composition_level VARCHAR(20)
không dùng số nguyên INT, vì:
- tránh nhầm với tầng/layer,
- phù hợp Điều 0-B hơn,
- dễ đọc và ít bug mapping hơn.
3. Điều 29 vs Điều 23 (DOT) — có trùng/conflict không?
Không conflict, nhưng có nguy cơ chồng chức năng nếu không phân vai rõ.
Phân vai nên viết cứng như sau:
- Điều 29 / Liveness = framework đo luật, lưu violation, quyết định pass/fail
- Điều 23 / DOT scanning = một trong các nguồn đo, đặc biệt cho những rule không đo hết bằng SQL (UI visibility, semantic correctness, stale presentation)
Tức là DOT không cạnh tranh với Liveness; DOT là sensor, Liveness là engine + court record.
Kết luận C1
- Không thấy xung đột hiến pháp cấp nghiêm trọng.
- Nhưng cần sửa 3 điểm thuật ngữ/semantics:
- draft phải được định nghĩa như managed-but-not-active,
- merged nên tách khỏi status chính,
source_layer/target_layerphải đổi thànhcomposition_level.
C2. Lỗ hổng logic trong schema
1. universal_edges — thiếu cột và constraint
Schema hiện tại dùng:
source_collection,source_id,target_collection,target_idsource_code,target_codesource_layer,target_layer
Thiếu các cột sau
source_status,target_statussnapshot hoặc logic active flag — để retire gate và edge filtering không phải join quá nhiều nơi.is_auto_managed BOOLEAN— phân biệt edge mirror từ FK và edge semantic/manual.valid_from,valid_to— cần cho lifecycle/history.metadata JSONB— để chứa confidence, migration_ref, symmetry_source, note.created_by,updated_byhoặc chuẩn traceability tương ứng.symmetry_group_idcho các edge đối xứng nhưGROUP_WITH,SIMILAR_TO.source_composition_level,target_composition_levelthay cho INT layer.
Constraint nên thêm
alter table universal_edges
add constraint chk_edge_type
check (edge_type in ('BELONGS_TO','CONTAINS','USES','USED_BY','GROUP_WITH','SIMILAR_TO'));
alter table universal_edges
add constraint chk_edge_status
check (status in ('active','deprecated','retired'));
alter table universal_edges
add constraint chk_weight_positive
check (weight > 0);
alter table universal_edges
add constraint chk_no_self_edge
check (not (
source_collection = target_collection
and source_id = target_id
and edge_type in ('BELONGS_TO','CONTAINS','USES','USED_BY')
));
Index strategy nên sửa
Hiện có index source, target, type, cross_layer. Tôi đề nghị thêm:
create index idx_edges_source_type_active
on universal_edges(source_collection, source_id, edge_type)
where status = 'active';
create index idx_edges_target_type_active
on universal_edges(target_collection, target_id, edge_type)
where status = 'active';
create index idx_edges_status_type
on universal_edges(status, edge_type);
create index idx_edges_source_code on universal_edges(source_code);
create index idx_edges_target_code on universal_edges(target_code);
2. lifecycle_log — thiếu linkage cho merge/split
Nên thêm:
transition_type VARCHAR(30)related_entity_collectionrelated_entity_idrelated_entity_codeapproval_ref
để lưu:
- merge from A → B
- split from A → C,D
- reactivation có approval nào
Ví dụ:
alter table lifecycle_log
add column transition_type varchar(30),
add column related_entity_collection varchar(100),
add column related_entity_id int,
add column related_entity_code varchar(50),
add column approval_ref text;
3. derived_objects_registry — thiếu freshness contract
Đây là thiếu lớn nhất của cả bản dự thảo.
Tôi đề nghị thêm:
alter table derived_objects_registry
add column freshness_sla_seconds int,
add column refresh_mode varchar(20),
add column stale_after timestamptz,
add column last_computed_at timestamptz,
add column recompute_status varchar(20) default 'ok',
add column stale_reason text,
add column inspector_dot varchar(100);
Nếu không có cụm cột này thì derived_objects_registry mới chỉ là “danh bạ object phái sinh”, chưa đủ để Điều 29 quản trị tính sống.
4. universal_rule_registry — thiếu execution contract
Nên thêm:
applies_to_classes TEXT[]execution_order INTfail_threshold INTalert_channel TEXT[]auto_create_violation BOOLEANis_blocking BOOLEAN
5. universal_rule_violations — thiếu dedupe key
Hiện dễ tạo lặp violation cùng một lỗi mỗi lần chạy rule. Cần thêm:
alter table universal_rule_violations
add column violation_hash text,
add column evidence jsonb default '{}'::jsonb;
create unique index uq_open_violation_hash
on universal_rule_violations(violation_hash)
where status = 'open';
6. birth_rejection_log — nên thêm payload và validation step
alter table birth_rejection_log
add column rejected_at_step varchar(50),
add column attempted_payload jsonb default '{}'::jsonb,
add column caller_origin varchar(100);
7. Race condition / edge case FK → edges
Có 3 race condition đáng chú ý:
(a) Update FK nhiều lần trong cùng transaction
Nếu trigger sync chạy row-by-row mà dùng insert/update đơn giản, có thể tạo churn dư thừa. Nên dùng AFTER trigger + UPSERT idempotent.
(b) Delete/retire entity trước khi edge mirror cập nhật
Retire Gate đọc universal_edges mà mirror đang trễ → kết quả sai. Vì vậy retire gate không được chỉ dựa vào edges mirror; phải đọc cả native FK/M2M source-of-truth hoặc có reconciliation function tổng hợp.
(c) Symmetric edges
SIMILAR_TO, GROUP_WITH đối xứng. Nếu sync/manual insert không có quy ước, có thể sinh 2 rows trùng logic hoặc thiếu row ngược. Cần rule cứng:
- hoặc lưu 1 row canonical với
lower(source_code,target_code) - hoặc lưu 2 rows nhưng quản bằng
symmetry_group_id
C3. Assembly First Compliance
Phase 1: Schema + Core Views
Tuân thủ tốt. Đây là phần PG nên làm.
Cần lưu ý
fn_run_all_rules()không nên cố biến function đo nào cũng thànhSELECT * FROM fn() INTO v_count; cần wrapper chuẩn hóa measurement output.- Không viết service ngoài khi PG views + functions đã làm được.
Phase 2: Sync + Triggers
Đúng hướng PG-first, nhưng có 2 điểm cần tránh code mới không cần thiết:
- Pre-Birth Check trigger chỉ hợp lý nếu insert trực tiếp DB là đường chuẩn. Trong Incomex, Birth nên đi qua DOT/PG function chuẩn. Tôi đề nghị:
- function chuẩn
fn_pre_birth_check(...) - trigger chỉ là lớp chặn cuối cùng, không phải business entrypoint chính
- FK→edge sync triggers cho tất cả collections có thể quá rộng. Nên generate có kiểm soát từ catalog thay vì viết tay từng trigger.
Phase 3: Integration
Component dễ trượt khỏi Assembly First
- “Cập nhật Registries UI Layer 5 để đọc từ universal_edges” là đúng, nhưng nên đọc qua Directus-registered view thay vì code custom query mới từ Nuxt.
- “Cập nhật DOT tools để ghi lifecycle_log” là hợp lý, nhưng tốt hơn là DOT gọi PG function chuẩn; đừng để từng DOT tự viết logic log riêng.
Phase 4: Migration
Chuẩn. Phần này không cần code dịch vụ mới; dùng SQL migration + backfill functions là đủ.
Kết luận C3
Bản dự thảo nhìn chung đúng tinh thần Assembly First. Điểm cần chỉnh là:
- ưu tiên PG function làm entrypoint chuẩn hơn là trigger-business-only,
- UI đọc từ Directus views, không mở thêm đường query riêng,
- generate trigger/view từ catalog, không hand-code rộng khắp.
C4. End-to-End Scenario: Tạo → Sử dụng → Retire một Atom
Giả sử:
- atom =
ATM-100 - molecule =
MOL-020 - product =
PRD-005
Bước 1 — User tạo atom ATM-100 qua DOT tool
Tables bị tác động
- bảng atom nghiệp vụ, ví dụ
atoms lifecycle_log- có thể
entity_labels - có thể
universal_edgesnếu có quan hệ semantic ban đầu
Function/trigger nên chạy
- DOT gọi
fn_pre_birth_check('atoms', payload) - pass →
fn_create_atom(...) - PG trigger cấp code/metadata chuẩn nếu cần
- auto-label trigger có thể gán label
lifecycle_logghinull → drafthoặcdraft → activetùy pipeline
Data được ghi
atoms: record ATM-100 status=draft/activelifecycle_log: activate evententity_labels: labels mặc định
Gap hiện có trong dự thảo
- chưa có schema bảng object nghiệp vụ mẫu với
status+_dot_originenforced bằng CHECK/trigger - chưa mô tả rõ
activatexảy ra cùng transaction hay bước sau verify
Bước 2 — ATM-100 được gán vào molecule MOL-020
Tables bị tác động
- junction native, ví dụ
molecule_atoms universal_edgesmirror- có thể
lifecycle_logcủa molecule nếu thay đổi status/structure quan trọng
Trigger/function chạy
- insert
molecule_atoms trg_sync_edge_molecule_atomstạo:- MOL-020
CONTAINSATM-100 - ATM-100
BELONGS_TOMOL-020
- MOL-020
Gap hiện có
Dự thảo chưa nói rõ 1 FK/M2M native có sinh 1 edge hay 2 edge mirror. Với 6 headings UI, tôi khuyến nghị lưu cả 2 edge hướng hoặc có view auto-expand. Không nên để UI phải tự suy diễn quá nhiều.
Bước 3 — MOL-020 được dùng trong product PRD-005
Tables bị tác động
- quan hệ native hoặc dependency table, ví dụ
product_molecules universal_edges
Trigger/function chạy
- insert native relation
- sync trigger mirror sang edges:
- PRD-005
USESMOL-020 - MOL-020
USED_BYPRD-005
- PRD-005
Gap hiện có
USES/USED_BY không phải lúc nào cũng là FK structural; nhiều chỗ là semantic/functional relation. Cần nêu rõ rule mapping nào sinh tự động từ native relation nào, và relation nào phải qua DOT semantic registration.
Bước 4 — ATM-100 cần retire
Điều gì phải xảy ra?
- request retire ATM-100
fn_retire_gate_checkchạy- phát hiện blocker:
- MOL-020 đang
CONTAINSATM-100 - gián tiếp PRD-005 đang
USESMOL-020
- MOL-020 đang
- retire phải bị chặn
Đúng quy trình
- deprecate ATM-100 trước
- migrate MOL-020 sang atom thay thế, ví dụ ATM-200
- edge mirrors cập nhật
- verify no active dependency
- retire ATM-100
- ghi
lifecycle_log
Gap hiện có
Hàm fn_retire_gate_check đang chỉ nhìn universal_edges target side. Điều này chưa đủ vì:
- có thể còn native FK chưa mirror kịp
- có thể còn dependency gián tiếp
Tôi đề nghị retire gate nên có 2 lớp:
- hard blockers từ native FK/M2M source-of-truth
- soft blockers từ
universal_edges+ recursive dependency summary
C5. Rủi ro lớn nhất
Rủi ro lớn nhất: Mirror layer (universal_edges + violations + derived registry) trở thành “hệ thống thứ hai” lệch khỏi source-of-truth
Đây là rủi ro lớn nhất. Khi thêm nhiều table quản trị meta, hệ thống có thể có:
- source native đúng
- mirror sai
- rule engine đọc mirror sai rồi chặn deploy oan hoặc bỏ sót lỗi thật
Điều này đặc biệt nguy hiểm vì bản dự thảo đang giao rất nhiều trách nhiệm cho:
universal_edgesuniversal_rule_violationsderived_objects_registry
Nếu 3 lớp này không cập nhật đúng, ta sẽ có governance theatre: nhìn có vẻ kiểm soát được, nhưng thật ra đang kiểm soát bản sao lỗi thời.
Mitigation
- Với mọi mirror/read-model, ghi rõ trong luật:
- source_of_truth là gì
- mirror chỉ dùng cho gì
- Mọi critical gate (retire, merge, deploy block) phải đọc từ source-of-truth trước, mirror chỉ bổ sung visibility.
- Tạo
reconciliation jobs:- native FK/M2M vs universal_edges
- rule registry vs actual view/function existence
- derived registry vs actual object freshness
- Thêm mirror health dashboard riêng.
- Ban hành nguyên tắc cứng:
- mirror không bao giờ được quyền sửa ngược source native.
G1. Pre-Birth Check — Đủ chưa?
Bản dự thảo có 5 validations:
- code format
- name không trùng active cùng collection
- collection hợp lệ
- caller hợp lệ
- metadata tối thiểu
Chưa đủ
Tôi đề nghị thêm 4 validations nữa:
6. Business essence duplication
Không chỉ check name, mà phải check business_hash/signature nếu object loại đó có contract bản chất.
7. Composition-level validity
Object tạo mới phải khai báo composition_level hợp lệ hoặc derive được từ type.
8. Registry contract availability
Collection/type này đã có registry wiring chưa? Nếu chưa có table_registry/meta wiring/rule coverage tối thiểu, không nên sinh đại trà.
9. Permission/actor scope
Caller hợp lệ không chỉ là DOT tool; còn phải có quyền tạo đúng collection/type đó.
Thứ tự tối ưu hơn
Tôi đề nghị thứ tự:
- collection/type hợp lệ
- caller + permission hợp lệ
- metadata tối thiểu + composition_level
- duplicate by code/name/business essence
- registry wiring / post-birth readiness
Lý do: kiểm cái rẻ và cứng trước, kiểm duplicate sâu sau.
G2. Decision Tree — Hoàn chỉnh chưa?
Chưa hoàn chỉnh
Decision tree hiện tại tốt hơn trước, nhưng còn miss 4 case.
1. Native-managed resource
Hiện tree đi từ “managed entity” hoặc “derived object” hoặc “log/action”. Nhưng còn lớp rất quan trọng theo Điều 0-B:
- field
- trigger
- view hệ thống
- permission
- flow
Đây không phải managed entity, cũng không chỉ là derived object. Cần nhánh riêng:
- Native-managed resource
2. Bond/junction object
Một junction M2M không phải derived object. Nó là bond. Tree hiện cho “nó là quan hệ giữa 2 entities?” nhưng chưa tách rõ:
- native structural bond
- semantic edge record
3. Entity chuyển lớp
Có. Điều 0-B đã cho phép một số entity nâng tầng khi complexity tăng. Decision tree nên có nhánh:
- “object hiện hữu nhưng đổi composition_level?”
- nếu có → WCR/governance + reclassify pipeline
4. Một object vừa là thực thể vừa là thành phần
Đây chính là tính lưỡng tính Huyen nêu. Tree text hiện tại chưa nói rõ. Ví dụ label group vừa là managed entity, vừa là thành phần của pattern lớn hơn. Điều này không có nghĩa nó “thuộc nhiều lớp cấu tạo cùng lúc”; nó có một composition_level chính, nhưng có thể đóng nhiều vai trò quan hệ.
Đề xuất decision tree tốt hơn
- Nó có identity quản trị độc lập không?
- Có → Managed entity hoặc native-managed resource
- Identity do ai quản lý?
- PG/Directus native natural key → Native-managed
- PREFIX-NNN → Managed entity
- Nó là liên kết cấu trúc/semantic giữa objects?
- Có → Bond/edge
- Nó là object phái sinh từ object khác?
- Có → Derived object
- Nó chỉ là log/artifact/action?
- Có → Artifact/operational stream
G3. Universal Rules Engine — fn_run_all_rules() đủ mạnh chưa?
Chưa đủ để gọi là engine thực sự. Hiện mới là iterator function.
Thiếu 6 thứ
1. Chuẩn hóa output measurement
Mọi measurement nên trả cùng schema, ví dụ:
(rule_number, entity_collection, entity_id, entity_code, violation_detail, severity, evidence_json)
Không thể vừa COUNT(*) vừa SELECT * FROM fn() lẫn lộn.
2. Violation persistence + dedupe
fn_run_all_rules() hiện chỉ trả count. Engine thực sự phải:
- insert/update open violations
- close violations đã hết
- dedupe bằng
violation_hash
3. Execution order
Một số rule phụ thuộc rule khác. Ví dụ Identity fail thì Traceability có thể fail dây chuyền. Cần execution_order.
4. Severity handling
Engine phải phân biệt:
- error → block deploy
- warning → log only
- info → trend
5. Alert hooks
Không chỉ trả kết quả SQL; phải có output cho:
- GH Actions
- dashboard
- DOT ingest
6. Snapshot/trend
Engine phải ghi lịch sử run:
- run_id
- started_at/ended_at
- total violations by rule
- delta vs previous run
Đề xuất thêm 2 bảng
create table universal_rule_runs (
id serial primary key,
started_at timestamptz default now(),
ended_at timestamptz,
triggered_by varchar(100),
status varchar(20) default 'running'
);
create table universal_rule_run_results (
run_id int references universal_rule_runs(id),
rule_number int,
violations_found int,
severity varchar(20),
primary key (run_id, rule_number)
);
G4. derived_objects_registry — Scope
Bản dự thảo đã include:
- PG views
- functions
- computed fields
Nên include thêm
- materialized views
- summary tables / refresh tables dùng như read models
- generated columns nếu phục vụ governance logic
- Directus read-only virtual collections map từ PG objects
- recommendation/inference snapshots ở Tầng 4
- matrix surfaces nếu matrix là object quản trị có SLA
Không nên include
- mọi log tạm thời
- mọi metric ad-hoc chưa có owner/SLA
Đề xuất object_type enum
check (object_type in (
'view',
'materialized_view',
'function',
'generated_column',
'computed_field',
'summary_table',
'matrix',
'inference_snapshot',
'recommendation_model'
));
G5. Proposal v3.1 — Bản dự thảo đã đủ cụ thể chưa?
Đã đủ cụ thể để review cấp hội đồng, nhưng chưa đủ cụ thể để giao thẳng implementation không có ambiguity.
Đã đạt
- có 3 luật rõ
- có schema khung
- có phases
- có decision tree sơ bộ
- có rule engine sơ bộ
Còn thiếu để đạt “implementation-ready v3.1”
- DDL hoàn chỉnh với CHECK/INDEX/FK/enum contracts
- chuẩn measurement output cho 10 rules
- chuẩn sync spec cho từng loại native relation → edge types nào
- quy tắc symmetric edges
- freshness contract đầy đủ cho derived objects
- state semantics chuẩn: merged là terminal_reason hay lifecycle_status?
- reconciliation spec giữa native truth và mirrors
Kết luận G5
Tài liệu hiện tại là APPROVE WITH CHANGES vì đã đủ tốt về kiến trúc, nhưng tôi vẫn muốn thêm một phụ lục kỹ thuật dạng:
- Appendix A: DDL final
- Appendix B: Edge sync mapping
- Appendix C: Rule measurement contract
- Appendix D: Lifecycle transition truth table
Danh sách thay đổi đề xuất (cụ thể)
Change 1 — Đổi source_layer/target_layer
alter table universal_edges
rename column source_layer to source_composition_level;
alter table universal_edges
rename column target_layer to target_composition_level;
Sau đó đổi kiểu sang varchar(20) nếu chưa triển khai.
Change 2 — Bổ sung freshness contract cho derived_objects_registry
alter table derived_objects_registry
add column freshness_sla_seconds int,
add column refresh_mode varchar(20),
add column stale_after timestamptz,
add column last_computed_at timestamptz,
add column recompute_status varchar(20) default 'ok',
add column stale_reason text;
Change 3 — Thêm dedupe cho violations
alter table universal_rule_violations
add column violation_hash text,
add column evidence jsonb default '{}'::jsonb;
create unique index uq_open_violation_hash
on universal_rule_violations(violation_hash)
where status = 'open';
Change 4 — Thêm metadata/history cho edges
alter table universal_edges
add column metadata jsonb default '{}'::jsonb,
add column valid_from timestamptz default now(),
add column valid_to timestamptz,
add column is_auto_managed boolean default false,
add column symmetry_group_id uuid;
Change 5 — Tách merged khỏi state chính
Đề nghị sửa luật từ:
- 5 trạng thái: draft → active → deprecated → retired + merged
thành:
- lifecycle_status: draft/active/deprecated/retired
- terminal_reason: merged/split_replaced/none
Change 6 — Bổ sung 4 Pre-Birth validations
- business essence duplicate
- composition level validity
- registry readiness
- permission scope
Change 7 — Thêm 2 bảng run-tracking cho Rules Engine
create table universal_rule_runs (
id serial primary key,
started_at timestamptz default now(),
ended_at timestamptz,
triggered_by varchar(100),
status varchar(20) default 'running'
);
create table universal_rule_run_results (
run_id int references universal_rule_runs(id),
rule_number int,
violations_found int,
severity varchar(20),
primary key (run_id, rule_number)
);
Kết luận cuối
Tôi ủng hộ ban hành 3 luật mới, vì đây là bước chuyển rất quan trọng từ “luật nằm trong tài liệu” sang “luật chạy trong hệ thống”. Hướng tổng thể là đúng và nhất quán với các vòng trước.
Nhưng để tránh biến universal_edges và universal_rule_* thành một lớp meta đẹp trên giấy mà yếu trong production, tôi đề nghị Claude tích hợp các thay đổi trên trước khi chốt bản cuối.
Phán quyết cuối: APPROVE WITH CHANGES
Các thay đổi bắt buộc trước khi chốt:
- sửa semantics lifecycle (
merged), - bổ sung freshness contract cho derived objects,
- sửa thuật ngữ
layer→composition_level, - tăng chặt schema của
universal_edgesvàuniversal_rule_violations, - nâng
fn_run_all_rules()từ iterator thành rules engine có persistence + dedupe + run history.