godcrm/scripts/phase6-6.3-bdd-doc-gate.sql
GOD CRM Release f89e074dd1
Some checks failed
CI / Lint / Typecheck / Test / Build (push) Has been cancelled
CI / PostgreSQL Integration Tests (push) Has been cancelled
GOD CRM — public scrubbed snapshot
Governed substrate for autonomous agents: scoped identity (passports),
audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
2026-08-10 04:01:45 +03:00

100 lines
3.8 KiB
PL/PgSQL

-- ADR-0003 Phase 6 / ticket 126415 (6.3) — bdd_doc_gate read-only view.
--
-- Aggregates must-criterion gate state per (spec, source_doc). Downstream:
-- header `📐 готово` widget, status-machine watchdog (draft ↔
-- regressed-published), and future GET /api/v3/documents/:id/bdd-gate.
--
-- Substrate note: bdd_specs/bdd_criteria/bdd_tests/bdd_test_runs are CRM
-- *logical* tables (rows in public.table_rows keyed by table_id). Hard
-- table_ids are fixed: 7255 specs, 7256 criteria, 7258 tests, 7259 runs.
-- Registered in public.universal_tables — see ADR-0002 substrate.
--
-- Gate semantics:
-- must_total = # must-priority criteria under the spec
-- must_verified = # must criteria with status='verified'
-- must_failed = # must criteria with status='failed'
-- ready = must_total > 0 AND must_total = must_verified
--
-- Latest test run is joined per criterion (AC #3) but not currently folded
-- into the aggregate — status on the criterion row is the canonical flip
-- (updated via TOTP-signed verify in C-4 / ticket 126391). Exposing the
-- run join now keeps the view ready for a tighter double-gate rule later
-- without a schema churn.
--
-- Idempotent — CREATE OR REPLACE VIEW.
BEGIN;
CREATE OR REPLACE VIEW bdd_doc_gate AS
WITH specs AS (
SELECT
id AS spec_id,
(data->>'source_doc_id')::int AS source_doc_id,
updated_at AS spec_updated_at
FROM table_rows
WHERE table_id = 7255
AND data ? 'source_doc_id'
AND (data->>'source_doc_id') ~ '^-?\d+$'
),
criteria AS (
SELECT
id AS criterion_id,
(data->>'spec_id')::int AS spec_id,
data->>'priority' AS priority,
data->>'status' AS status,
updated_at AS criterion_updated_at
FROM table_rows
WHERE table_id = 7256
AND data ? 'spec_id'
AND (data->>'spec_id') ~ '^-?\d+$'
),
tests AS (
SELECT
id AS test_id,
(data->>'criterion_id')::int AS criterion_id
FROM table_rows
WHERE table_id = 7258
AND data ? 'criterion_id'
AND (data->>'criterion_id') ~ '^-?\d+$'
),
latest_runs AS (
SELECT DISTINCT ON (t.criterion_id)
t.criterion_id,
r.id AS run_id,
r.data->>'status' AS run_status,
COALESCE(
NULLIF(r.data->>'finished_at','')::timestamptz,
r.updated_at
) AS run_ts
FROM tests t
JOIN table_rows r
ON r.table_id = 7259
AND (r.data->>'test_id') ~ '^-?\d+$'
AND (r.data->>'test_id')::int = t.test_id
ORDER BY
t.criterion_id,
COALESCE(NULLIF(r.data->>'finished_at','')::timestamptz, r.updated_at) DESC
)
SELECT
s.source_doc_id,
s.spec_id,
COUNT(*) FILTER (WHERE c.priority = 'must')::int AS must_total,
COUNT(*) FILTER (WHERE c.priority = 'must' AND c.status = 'verified')::int AS must_verified,
COUNT(*) FILTER (WHERE c.priority = 'must' AND c.status = 'failed')::int AS must_failed,
(COUNT(*) FILTER (WHERE c.priority = 'must') > 0
AND COUNT(*) FILTER (WHERE c.priority = 'must')
= COUNT(*) FILTER (WHERE c.priority = 'must' AND c.status = 'verified')) AS ready,
GREATEST(
MAX(s.spec_updated_at),
MAX(c.criterion_updated_at),
MAX(lr.run_ts)
) AS updated_at
FROM specs s
LEFT JOIN criteria c ON c.spec_id = s.spec_id
LEFT JOIN latest_runs lr ON lr.criterion_id = c.criterion_id
GROUP BY s.source_doc_id, s.spec_id;
COMMENT ON VIEW bdd_doc_gate IS
'ADR-0003 Phase 6.3 / ticket 126415. Must-criterion gate aggregate per (spec, source_doc). Read-only.';
COMMIT;