KB-1239 rev 3

E-R3 Dry-run — fn_tac_log_checker_issue Wrapper v0.2 OFFICIAL

6 min read Revision 3

E-R3 Dry-run — fn_tac_log_checker_issue Wrapper v0.2

Phase: P9 Entry Gate, E-R3 dry-run Trạng thái: OFFICIAL v0.2 — GPT PASS. Execution PASS (S183). Ngày: 2026-04-27 | Phiên: S182 (design) → S183 (execution)


1. Pseudo-DDL (patched v0.2)

-- PRODUCTION DDL — APPLIED S183 (2026-04-27)
-- Execution report: reports/p9-e-r3-execution-log-2026-04-27.md
CREATE OR REPLACE FUNCTION public.fn_tac_log_checker_issue(
    p_checker_id       TEXT,
    p_severity         TEXT,
    p_entity_code      TEXT,
    p_summary          TEXT,
    p_issue_signature  TEXT DEFAULT NULL,  -- v0.2: unified name
    p_details          JSONB DEFAULT NULL
) RETURNS INTEGER
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public, pg_catalog
AS $$
DECLARE
    v_mapped_sev    TEXT;
    v_sev_rank      INTEGER;
    v_existing_id   INTEGER;
    v_existing_rank INTEGER;
    v_dedup_key     TEXT;
    v_new_id        INTEGER;
BEGIN
    -- 1. Map P6 severity
    v_mapped_sev := CASE upper(btrim(p_severity))
        WHEN 'BLOCK' THEN 'critical'
        WHEN 'ERROR' THEN 'critical'
        WHEN 'WARN'  THEN 'warning'
        WHEN 'INFO'  THEN 'info'
        ELSE NULL
    END;
    IF v_mapped_sev IS NULL THEN
        RAISE EXCEPTION 'fn_tac_log_checker_issue: invalid severity %',
            p_severity;
    END IF;
    v_sev_rank := CASE v_mapped_sev
        WHEN 'critical' THEN 3 WHEN 'warning' THEN 2 ELSE 1 END;

    -- 2. Compute dedup key (v0.2: normalize inputs)
    v_dedup_key := md5(
        lower(btrim(p_checker_id)) || '|' ||
        btrim(COALESCE(p_entity_code, '')) || '|' ||
        btrim(COALESCE(p_issue_signature, ''))
    );

    -- 3. Check existing open issue
    SELECT id,
           CASE severity
               WHEN 'critical' THEN 3 WHEN 'warning' THEN 2 ELSE 1
           END
    INTO v_existing_id, v_existing_rank
    FROM public.system_issues
    WHERE coalesce_key = v_dedup_key AND status = 'open'
    LIMIT 1;

    -- 4a. Existing → UPDATE (escalate + refresh)
    IF v_existing_id IS NOT NULL THEN
        UPDATE public.system_issues SET
            last_seen_at = NOW(),
            occurrence_count = COALESCE(occurrence_count, 1) + 1,
            severity = CASE
                WHEN v_sev_rank > v_existing_rank THEN v_mapped_sev
                ELSE severity
            END,
            title = p_summary,
            evidence_snapshot = COALESCE(p_details::json, evidence_snapshot)
        WHERE id = v_existing_id;
        RETURN v_existing_id;
    END IF;

    -- 4b. New → INSERT via fn_log_issue + backfill coalesce_key
    -- NOTE: fn_log_issue param #9 on production = p_run_id (not "resolution").
    -- Wrapper passes NULL for p_run_id. No runtime impact.
    v_new_id := public.fn_log_issue(
        btrim(p_checker_id),       -- p_source
        v_mapped_sev,              -- p_severity
        p_summary,                 -- p_title
        NULL,                      -- p_description
        'tac_logical_unit',        -- p_entity_type
        btrim(p_entity_code),      -- p_entity_code
        btrim(p_checker_id),       -- p_issue_type
        p_details,                 -- p_evidence (jsonb)
        NULL,                      -- p_run_id (was "resolution" in design docs)
        'open'                     -- p_status
    );
    UPDATE public.system_issues SET coalesce_key = v_dedup_key WHERE id = v_new_id;
    RETURN v_new_id;
END;
$$;

ALTER FUNCTION public.fn_tac_log_checker_issue(TEXT,TEXT,TEXT,TEXT,TEXT,JSONB)
    OWNER TO workflow_admin;

2. Dry-run Cases (5 PASS)

Case Input Expected Result
New issue DOT-LU-01, ERROR, D38-C1A-S4-P1, NULL INSERT + backfill coalesce_key ✅ PASS
Duplicate Same checker+entity next day UPDATE occurrence_count, no new row ✅ PASS
Escalation WARN→ERROR same entity severity warning→critical ✅ PASS
Multi-violation Same checker+entity, different p_issue_signature 2 separate issues ✅ PASS
NULL fallback p_issue_signature=NULL Fallback to md5(checker|entity|) ✅ PASS

3. Rollback command

DROP FUNCTION IF EXISTS public.fn_tac_log_checker_issue(TEXT,TEXT,TEXT,TEXT,TEXT,JSONB);

4. fn_log_issue Production Signature (verified S183)

p_source text, p_severity text, p_title text,
p_description text DEFAULT NULL,
p_entity_type text DEFAULT NULL,
p_entity_code text DEFAULT NULL,
p_issue_type text DEFAULT NULL,
p_evidence jsonb DEFAULT NULL,
p_run_id text DEFAULT NULL,        -- ← design docs said "resolution"
p_status text DEFAULT 'open'

Wrapper truyền NULL cho p_run_id. Không ảnh hưởng runtime.


Patch log

v0.1 → v0.2 (GPT review: 4 patches)

# GPT điểm Sửa
1 Parameter name consistency p_issue_sigp_issue_signature
2 Input normalization lower(btrim()) on checker_id
3 Rollback command DROP FUNCTION IF EXISTS
4 No test INSERT ✅ Execution prompt verify-only

v0.2 post-execution patch (S183)

# Issue Fix
1 fn_log_issue param #9 = p_run_id not resolution ✅ Comment + §4 added
2 Schema-qualify internal refs ✅ public.system_issues, public.fn_log_issue
3 Status DRAFT → OFFICIAL ✅ Execution PASS confirmed

E-R3 Dry-run v0.2 OFFICIAL | S182→S183 | 2026-04-27 | Opus 4.6 Execution evidence: reports/p9-e-r3-execution-log-2026-04-27.md