KB-66A1 rev 2

Universal Measurement Framework — Thiết Kế Kỹ Thuật PG v2.0

20 min read Revision 2
universalmeasurementframeworkpg-designS132scalereuse

Universal Measurement Framework — Thiết Kế Kỹ Thuật PG

Version: v2.0 | Ngày: 2026-03-24 | Session: S132 Tác giả: Anh Huyên (tầm nhìn kiến trúc), Claude Desktop (thiết kế kỹ thuật) Nguyên tắc: "Tạo 1 thứ tiêu chuẩn rồi dùng lại mãi mãi" (Huyên S132) Thay thế: dieu31-pg-technical-design.md v1.0 — v1 quá hẹp (riêng Điều 31)


I. TẦM NHÌN: TẠI SAO CẦN FRAMEWORK PHỔ QUÁT

Hiện trạng — mỗi luật "tự chế"

  • Điều 26: 17 triggers + verify_counts() + v_registry_counts
  • Điều 28: birth_registry + birth triggers
  • Điều 31: system_issues + runner scripts

Tầm nhìn 1 năm — 100+ luật, 50+ loại đo lường

Nếu mỗi luật tạo riêng triggers/functions/views → PG thành "con quái vật chậm chạp" (Huyên S132).

Giải pháp — 3 lớp kiến trúc

  • Lớp A: Mỗi luật = 1 collection SSOT (đơn giản, độc lập)
  • Lớp B: 1 framework đo lường phổ quát (shared, dùng lại mãi mãi)
  • Lớp C: PG triggers real-time (giữ 17 trigger đếm, ổn định, KHÔNG tạo thêm)

Thêm luật mới = 1 collection + rows config. KHÔNG viết code. Thêm đo lường mới = 1 row config. KHÔNG viết code.


II. LỚP A — MỖI LUẬT = 1 COLLECTION SSOT

Mỗi luật sở hữu data riêng trong collection riêng. Đơn giản, trực quan, dễ code, độc lập.

Luật Collection SSOT Chứa gì
Điều 26 (Đếm) meta_catalog Danh mục + số lượng entities
Điều 28 (Khai sinh) birth_registry Bản khai sinh mọi entity
Điều 29 (Species) species_collection_map Mapping loài↔collection
Điều 31 (Toàn vẹn) system_issues Vấn đề phát hiện
Điều 32 (Layer) (tương lai) Config 5 layer cho mọi dòng
... ... ...

law_catalog — Bảng danh mục luật (meta-SSOT)

CREATE TABLE law_catalog (
    law_code        TEXT PRIMARY KEY,       -- 'dieu26', 'dieu31', 'dieu32'
    law_name        TEXT NOT NULL,          -- 'Luật Đếm', 'Luật Toàn Vẹn'
    law_version     TEXT NOT NULL,          -- 'v2.1.1', 'v1.3'
    ssot_collection TEXT,                   -- 'meta_catalog', 'system_issues'
    ssot_document   TEXT,                   -- path trong Agent Data
    status          TEXT NOT NULL DEFAULT 'active'
                    CHECK (status IN ('draft', 'active', 'deprecated')),
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

Ý nghĩa: 1 nơi tra cứu mọi luật, collection của nó, document SSOT. Agent mới → SELECT * FROM law_catalog → biết hệ thống có gì.


III. LỚP B — UNIVERSAL MEASUREMENT FRAMEWORK

Nguyên tắc cốt lõi

Thêm đo lường mới = thêm 1 row. KHÔNG viết trigger/function/view mới. Framework code viết 1 lần, chạy mãi mãi.

Bảng 1: measurement_registry — "Cần đo gì?"

CREATE TABLE measurement_registry (
    -- Identity
    measurement_id  TEXT PRIMARY KEY,       -- 'MSR-D26-001'
    measurement_name TEXT NOT NULL,         -- 'meta_catalog count vs SELECT COUNT'
    law_code        TEXT NOT NULL REFERENCES law_catalog(law_code),
    
    -- PHƯƠNG PHÁP (★ từ methodology v2.0)
    method          SMALLINT NOT NULL CHECK (method IN (1, 2)),
    -- 1 = PG kiểm PG (Bài toán 1 — chạy hoàn toàn trong PG)
    -- 2 = PG vs External (Bài toán 2 — cần runner bên ngoài)
    
    -- Nguồn chân lý (LUÔN là PG)
    source_query    TEXT NOT NULL,          -- SQL lấy giá trị chân lý
    
    -- So sánh với
    target_type     TEXT NOT NULL CHECK (target_type IN (
        'pg_query',     -- Bài toán 1: PG query khác
        'pg_function',  -- Bài toán 1: PG function
        'nuxt_api',     -- Bài toán 2: Nuxt endpoint  
        'nuxt_page',    -- Bài toán 2: Nuxt rendered page
        'agent_data',   -- Bài toán 2: Agent Data API
        'directus_api'  -- Bài toán 2: Directus API
    )),
    target_query    TEXT NOT NULL,          -- SQL, URL, hoặc endpoint
    
    -- Phân loại (taxonomy chuẩn ngành — bao quát)
    category        TEXT NOT NULL CHECK (category IN (
        'completeness',     -- ĐỦ chưa?
        'consistency',      -- KHỚP chưa?
        'currency',         -- MỚI chưa?
        'validity',         -- HỢP LỆ chưa?
        'liveness'          -- SỐNG chưa?
    )),
    
    -- Vận hành
    severity        TEXT NOT NULL DEFAULT 'warning'
                    CHECK (severity IN ('critical', 'warning', 'info')),
    comparison      TEXT NOT NULL DEFAULT 'strict_equals'
                    CHECK (comparison IN (
                        'strict_equals', 'eventual_equals',
                        'exists', 'not_exists', 'within_window', 'always_fail'
                    )),
    enabled         BOOLEAN NOT NULL DEFAULT true,
    auto_generated  BOOLEAN NOT NULL DEFAULT false,
    
    -- Trạng thái run gần nhất (trigger tự cập nhật)
    last_run_at     TIMESTAMPTZ,
    last_result     TEXT CHECK (last_result IN ('pass', 'fail', 'error', NULL)),
    last_evidence   JSONB,
    
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_msr_law ON measurement_registry(law_code);
CREATE INDEX idx_msr_method ON measurement_registry(method);
CREATE INDEX idx_msr_enabled ON measurement_registry(enabled) WHERE enabled = true;

Bảng 2: measurement_log — "Kết quả đo"

CREATE TABLE measurement_log (
    -- Identity
    run_id          TEXT NOT NULL,
    measurement_id  TEXT NOT NULL REFERENCES measurement_registry(measurement_id),
    run_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    
    -- Kết quả
    result          TEXT NOT NULL CHECK (result IN ('pass', 'fail', 'error')),
    source_value    TEXT,           -- Giá trị PG (chân lý)
    target_value    TEXT,           -- Giá trị so sánh
    delta           TEXT,           -- Sai lệch cụ thể
    evidence        JSONB,          -- Chi tiết đầy đủ
    
    PRIMARY KEY (run_id, measurement_id)
);

-- Partition theo tháng (tránh bảng phình to)
-- Phase 2: ALTER TABLE measurement_log PARTITION BY RANGE (run_at);

-- Trigger: sau mỗi log → tự cập nhật measurement_registry.last_*
CREATE OR REPLACE FUNCTION update_measurement_status()
RETURNS TRIGGER AS $$
BEGIN
    UPDATE measurement_registry SET
        last_run_at = NEW.run_at,
        last_result = NEW.result,
        last_evidence = jsonb_build_object(
            'source', NEW.source_value,
            'target', NEW.target_value,
            'delta', NEW.delta
        ),
        updated_at = NOW()
    WHERE measurement_id = NEW.measurement_id;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_update_measurement
AFTER INSERT ON measurement_log
FOR EACH ROW EXECUTE FUNCTION update_measurement_status();

Function 1: run_internal_measurements() — Bài toán 1, chạy TRONG PG

CREATE OR REPLACE FUNCTION run_internal_measurements(
    p_law_code TEXT DEFAULT NULL,   -- NULL = chạy tất cả
    p_run_id TEXT DEFAULT NULL      -- NULL = auto-generate
)
RETURNS TABLE (
    measurement_id TEXT,
    measurement_name TEXT,
    law_code TEXT,
    source_value TEXT,
    target_value TEXT,
    result TEXT,
    delta TEXT
) AS $$
DECLARE
    rec RECORD;
    src_val TEXT;
    tgt_val TEXT;
    v_run_id TEXT;
BEGIN
    v_run_id := COALESCE(p_run_id, 'internal-' || to_char(NOW(), 'YYYYMMDD-HH24MISS'));
    
    FOR rec IN 
        SELECT * FROM measurement_registry 
        WHERE enabled = true 
          AND method = 1  -- Chỉ Bài toán 1
          AND (p_law_code IS NULL OR measurement_registry.law_code = p_law_code)
    LOOP
        BEGIN
            EXECUTE rec.source_query INTO src_val;
            EXECUTE rec.target_query INTO tgt_val;
            
            measurement_id := rec.measurement_id;
            measurement_name := rec.measurement_name;
            law_code := rec.law_code;
            source_value := src_val;
            target_value := tgt_val;
            
            IF src_val = tgt_val THEN
                result := 'pass';
                delta := '0';
            ELSE
                result := 'fail';
                delta := COALESCE(src_val, 'NULL') || ' ≠ ' || COALESCE(tgt_val, 'NULL');
            END IF;
            
            -- Ghi log (trigger tự cập nhật measurement_registry)
            INSERT INTO measurement_log (run_id, measurement_id, run_at, result, source_value, target_value, delta)
            VALUES (v_run_id, rec.measurement_id, NOW(), result, src_val, tgt_val, delta);
            
            RETURN NEXT;
        EXCEPTION WHEN OTHERS THEN
            measurement_id := rec.measurement_id;
            measurement_name := rec.measurement_name;
            law_code := rec.law_code;
            source_value := SQLERRM;
            target_value := NULL;
            result := 'error';
            delta := 'QUERY ERROR';
            
            INSERT INTO measurement_log (run_id, measurement_id, run_at, result, source_value, target_value, delta)
            VALUES (v_run_id, rec.measurement_id, NOW(), 'error', SQLERRM, NULL, 'QUERY ERROR');
            
            RETURN NEXT;
        END;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

Cách dùng:

-- Chạy TẤT CẢ measurements Bài toán 1 (mọi luật)
SELECT * FROM run_internal_measurements();

-- Chỉ chạy measurements của Điều 26
SELECT * FROM run_internal_measurements('dieu26');

-- Chỉ chạy measurements của Điều 31
SELECT * FROM run_internal_measurements('dieu31');

Function 2: verify_framework_health() — SSOT tự kiểm tra

CREATE OR REPLACE FUNCTION verify_framework_health()
RETURNS TABLE (
    issue_type TEXT,
    severity TEXT,
    detail TEXT
) AS $$
BEGIN
    -- 1. Luật active nhưng không có measurement nào
    RETURN QUERY
    SELECT 'law_no_measurements'::TEXT, 'warning'::TEXT,
        'Luật ' || lc.law_code || ' không có measurement nào'
    FROM law_catalog lc
    LEFT JOIN measurement_registry mr ON mr.law_code = lc.law_code AND mr.enabled = true
    WHERE lc.status = 'active' AND mr.measurement_id IS NULL;
    
    -- 2. Collection governed không có measurement nào
    RETURN QUERY
    SELECT 'collection_blind_spot'::TEXT, 'critical'::TEXT,
        'Collection ' || mc.collection_name || ' (' || mc.code || ') không có measurement'
    FROM meta_catalog mc
    LEFT JOIN measurement_registry mr ON mr.source_query LIKE '%' || mc.collection_name || '%'
    WHERE mc.governed = true AND mr.measurement_id IS NULL;
    
    -- 3. Measurement enabled nhưng stale >26h
    RETURN QUERY
    SELECT 'stale_measurement'::TEXT, 'warning'::TEXT,
        'Measurement ' || mr.measurement_id || ' không chạy ' || 
            ROUND(EXTRACT(EPOCH FROM NOW() - mr.last_run_at)/3600)::TEXT || 'h'
    FROM measurement_registry mr
    WHERE mr.enabled = true AND mr.last_run_at < NOW() - INTERVAL '26 hours';
    
    -- 4. Measurement trỏ vào bảng không tồn tại
    RETURN QUERY
    SELECT 'orphan_measurement'::TEXT, 'critical'::TEXT,
        'Measurement ' || mr.measurement_id || ' source_query tham chiếu bảng không tồn tại'
    FROM measurement_registry mr
    WHERE mr.enabled = true
      AND NOT EXISTS (
          SELECT 1 FROM information_schema.tables t
          WHERE mr.source_query LIKE '%' || t.table_name || '%'
            AND t.table_schema = 'public'
      );
    
    -- 5. Bảng mới trong PG chưa có trong meta_catalog
    RETURN QUERY
    SELECT 'untracked_table'::TEXT, 'warning'::TEXT,
        'Bảng ' || t.table_name || ' mới trong PG, chưa có trong meta_catalog'
    FROM information_schema.tables t
    LEFT JOIN meta_catalog mc ON mc.collection_name = t.table_name
    WHERE t.table_schema = 'public' AND t.table_type = 'BASE TABLE'
      AND mc.code IS NULL
      AND t.table_name NOT LIKE 'directus_%'
      AND t.table_name NOT LIKE 'pg_%'
      AND t.table_name NOT IN ('spatial_ref_sys', 'measurement_registry', 
          'measurement_log', 'law_catalog');
    
    -- 6. Coverage tổng
    RETURN QUERY
    SELECT 'coverage_report'::TEXT, 'info'::TEXT,
        'Coverage: ' || 
        (SELECT COUNT(DISTINCT law_code) FROM measurement_registry WHERE enabled = true) || 
        ' luật, ' ||
        (SELECT COUNT(*) FROM measurement_registry WHERE enabled = true) || 
        ' measurements, ' ||
        (SELECT COUNT(*) FROM measurement_registry WHERE enabled = true AND last_result = 'pass') ||
        ' pass, ' ||
        (SELECT COUNT(*) FROM measurement_registry WHERE enabled = true AND last_result = 'fail') ||
        ' fail';
END;
$$ LANGUAGE plpgsql;

Cách dùng:

-- 1 câu lệnh → biết toàn bộ framework có đúng không
SELECT * FROM verify_framework_health();
-- 0 rows severity='critical' = FRAMEWORK ĐÚNG ✓

Materialized View: Dashboard tổng hợp

CREATE MATERIALIZED VIEW mv_measurement_dashboard AS
SELECT 
    mr.law_code,
    lc.law_name,
    COUNT(*) FILTER (WHERE mr.enabled) AS total_measurements,
    COUNT(*) FILTER (WHERE mr.last_result = 'pass') AS pass_count,
    COUNT(*) FILTER (WHERE mr.last_result = 'fail') AS fail_count,
    COUNT(*) FILTER (WHERE mr.last_result IS NULL) AS never_run,
    CASE 
        WHEN COUNT(*) FILTER (WHERE mr.last_result IS NOT NULL) > 0
        THEN ROUND(100.0 * COUNT(*) FILTER (WHERE mr.last_result = 'pass') / 
             COUNT(*) FILTER (WHERE mr.last_result IS NOT NULL), 1)
        ELSE 0
    END AS pass_rate_pct,
    MIN(mr.last_run_at) AS oldest_run,
    MAX(mr.last_run_at) AS newest_run
FROM measurement_registry mr
JOIN law_catalog lc ON lc.law_code = mr.law_code
WHERE mr.enabled = true
GROUP BY mr.law_code, lc.law_name;

CREATE OR REPLACE FUNCTION refresh_measurement_dashboard()
RETURNS VOID AS $$
BEGIN
    REFRESH MATERIALIZED VIEW mv_measurement_dashboard;
END;
$$ LANGUAGE plpgsql;

Nuxt chỉ cần: SELECT * FROM mv_measurement_dashboard → dashboard toàn bộ hệ thống.


IV. LỚP C — PG TRIGGERS REAL-TIME (GIỮ NGUYÊN)

17 triggers đếm hiện có = HIỆU QUẢ, GIỮ NGUYÊN.

Phân biệt rõ:

Triggers (Lớp C) Measurements (Lớp B)
Khi nào Data thay đổi (INSERT/DELETE) Theo lịch hoặc on-demand
Mục đích Đếm real-time (entity_count) Verify, compare, check
Số lượng 17-20 (ổn định, ít thay đổi) 50→500+ (thêm config rows)
PG load Rất nhỏ (1 UPDATE per event) Nhỏ (scheduled SELECTs)
Thêm mới Chỉ khi thêm collection mới Thêm 1 row, không viết code

KHÔNG tạo thêm triggers cho loại đo lường mới. Triggers = chỉ đếm. Mọi thứ khác = measurement_registry.


V. SCALING — TẠI SAO PG KHÔNG THÀNH QUÁI VẬT

Yếu tố Số lượng hiện tại Dự kiến 1 năm PG load
Triggers (Lớp C) 17 ~25 Tiny — mỗi trigger = 1 UPDATE
measurement_registry rows 0 (chưa tạo) 500+ Zero khi idle — chỉ là DATA
measurement_log rows 0 ~500/ngày Nhỏ — partition theo tháng
run_internal_measurements() - 1-2 lần/ngày ~500 SELECTs = <1 giây trên PG 16
mv_measurement_dashboard - REFRESH 1-2 lần/ngày <100ms

So sánh: 500 rows trong measurement_registry = giống 500 rows trong meta_catalog. PG xử lý hàng triệu rows dễ dàng. Không tạo triggers mới = không tạo overhead mới.


VI. SEED DATA — DÙN LẠI CÁI ĐÃ CÓ

Existing infrastructure → đăng ký vào framework phổ quát:

-- Law catalog
INSERT INTO law_catalog VALUES
('dieu26', 'Luật Đếm', 'v2.1.1', 'meta_catalog', 'knowledge/dev/architecture/counting-law.md', 'active'),
('dieu28', 'Luật Khai Sinh', 'v1.0', 'birth_registry', 'knowledge/dev/architecture/birth-registry-law.md', 'active'),
('dieu29', 'Luật Species', 'v1.1', 'species_collection_map', 'knowledge/dev/architecture/species-taxonomy-complete.md', 'active'),
('dieu31', 'Luật Toàn Vẹn', 'v1.3', 'system_issues', 'knowledge/dev/architecture/system-integrity-law.md', 'active');

-- Dùng lại verify_counts() (đã có, chỉ đăng ký)
INSERT INTO measurement_registry VALUES
('MSR-D26-001', 'verify_counts = 0 mismatch', 'dieu26', 1,
 'SELECT COUNT(*) FROM verify_counts() WHERE status != ''OK''',
 'pg_query', 'SELECT 0',
 'consistency', 'critical', 'strict_equals', true, false),

-- Dùng lại meta_catalog coverage (đã có)
('MSR-D26-002', 'meta_catalog coverage = governed collections', 'dieu26', 1,
 'SELECT COUNT(*) FROM meta_catalog WHERE governed = true',
 'pg_function', 'SELECT COUNT(DISTINCT collection_name) FROM meta_catalog WHERE governed = true AND entity_count > 0',
 'completeness', 'warning', 'strict_equals', true, false),

-- Dùng lại birth_registry check
('MSR-D28-001', 'birth_registry tổng = meta_catalog tổng', 'dieu28', 1,
 'SELECT COUNT(*) FROM birth_registry',
 'pg_query', 'SELECT SUM(entity_count) FROM meta_catalog WHERE governed = true',
 'consistency', 'warning', 'strict_equals', true, false),

-- Điều 31: PG vs Nuxt (Bài toán 2 — cần runner)
('MSR-D31-001', 'Registries L1 total khớp PG', 'dieu31', 2,
 'SELECT SUM(entity_count) FROM meta_catalog WHERE governed = true',
 'nuxt_api', '/api/registry/counts',
 'consistency', 'critical', 'strict_equals', true, false),

('MSR-D31-002', 'Species count UI khớp PG', 'dieu31', 2,
 'SELECT COUNT(*) FROM meta_catalog WHERE species_code IS NOT NULL',
 'nuxt_api', '/api/registry/species-summary',
 'consistency', 'warning', 'strict_equals', true, false),

-- WATCHDOG
('MSR-D31-WATCHDOG', 'WATCHDOG — runner sống', 'dieu31', 2,
 'SELECT 1', 'nuxt_api', 'ALWAYS_FAIL',
 'liveness', 'critical', 'always_fail', true, false);

Ý nghĩa: verify_counts(), meta_catalog checks, birth_registry checks — tất cả ĐÃ CÓ, chỉ ĐĂNG KÝ vào framework. Không viết lại. Vẻ đẹp = dùng lại.


VII. TÓM TẮT KIẾN TRÚC

┌─────────────────────────────────────────────────┐
│           LỚP A: LAW COLLECTIONS (SSOT)          │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───┐  │
│  │meta_cata.│ │birth_reg.│ │species_  │ │...│  │
│  │(Điều 26) │ │(Điều 28) │ │map (Đ29) │ │   │  │
│  └────┬─────┘ └────┬─────┘ └────┬─────┘ └─┬─┘  │
│       └────────────┼────────────┼──────────┘    │
│                    ▼                             │
│  ┌─────────────────────────────────────────┐    │
│  │        law_catalog (danh mục luật)       │    │
│  └─────────────────┬───────────────────────┘    │
└────────────────────┼────────────────────────────┘
                     │
┌────────────────────▼────────────────────────────┐
│        LỚP B: UNIVERSAL MEASUREMENT              │
│  ┌─────────────────────────────────────────┐    │
│  │     measurement_registry (config)        │    │
│  │  MSR-D26-001, MSR-D31-001, ... 500+     │    │
│  └──────────────────┬──────────────────────┘    │
│                     │                            │
│  ┌──────────────────▼──────────────────────┐    │
│  │  run_internal_measurements() — Bài toán 1│    │
│  │  (runner bên ngoài)         — Bài toán 2│    │
│  └──────────────────┬──────────────────────┘    │
│                     │                            │
│  ┌──────────────────▼──────────────────────┐    │
│  │        measurement_log (kết quả)         │    │
│  └──────────────────┬──────────────────────┘    │
│                     │                            │
│  ┌──────────────────▼──────────────────────┐    │
│  │  verify_framework_health() — tự kiểm tra │    │
│  │  mv_measurement_dashboard — tổng hợp     │    │
│  └─────────────────────────────────────────┘    │
└─────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────┐
│     LỚP C: PG TRIGGERS (real-time, giữ nguyên)  │
│  17 triggers: entity_count++ / entity_count--    │
│  KHÔNG thêm triggers mới cho measurements mới   │
└─────────────────────────────────────────────────┘

VIII. THAM CHIẾU

  • Phương pháp luận 2 bài toán: search_knowledge("dieu31 methodology 2 bài toán")
  • Luật Điều 31: search_knowledge("system integrity verification law")
  • Nguyên tắc: "Tạo 1 thứ tiêu chuẩn dùng lại mãi mãi" (Huyên S132)
  • Nguyên tắc: "PG không thành quái vật" — triggers ổn định, measurements = config (Huyên S132)
  • Tiền lệ: DirectusTable.vue (1 component → mọi bảng), Điều 32 (1 khung → mọi dòng)