#!/usr/bin/env python3 """Generate a governance/concept-map companion packet for mapped KB proposals. The current live schema has governance gate rows but no canonical table linking claims to those gates, and it has no first-class concept-map table. This packet creates the minimal schema needed for the remaining mapped proposal fragments, then inserts exact row-level links after the mapped base packet has created the required claim rows. The packet builder is not an executor. Production apply remains a separate authorization boundary. """ from __future__ import annotations import argparse import json import sys import uuid from pathlib import Path from typing import Any HERE = Path(__file__).resolve().parent sys.path.insert(0, str(HERE)) from kb_rich_proposal_creation_plan import _sql_literal # noqa: E402 BASE_PACKET_REQUIRED_FIRST = "production-apply-packet-mapped-20260709" PROPOSAL_CONCEPT_ID = "14fa5ecc-ac7a-41c1-807d-a2e85b936617" PROPOSAL_GOVERNANCE_ID = "ac036c9d-20a0-4ffe-881f-57d6b7bacf22" CLAIM_DISTRIBUTED_MARKET_INTELLIGENCE_ID = "d009dfc4-9755-58a7-affb-80e3e842a775" CLAIM_NODES_NEED_BODIES_ID = "9bcf7e6b-4e98-52b1-91ef-96cfc15e3df0" QUALITY_GATE_ID = "fa88e31b-6fca-4801-bf72-f5db81950a11" EVIDENCE_BAR_ID = "45695897-2a9c-4279-ac25-e59f166dec6a" CONCEPT_MAP_KEY = "distributed_market_intelligence" ID_NAMESPACE = uuid.uuid5(uuid.NAMESPACE_URL, "teleo:working-leo:governance-concept-packet") def stable_id(key: str) -> str: return str(uuid.uuid5(ID_NAMESPACE, key)) CONCEPT_MAP_ID = stable_id("concept-map:distributed-market-intelligence") CONCEPT_LINK_ID = stable_id("claim-concept-map-link:capital-allocation-distributed-knowledge") QUALITY_GATE_LINK_ID = stable_id("claim-governance-link:claim-bodies:quality-gate") EVIDENCE_BAR_LINK_ID = stable_id("claim-governance-link:claim-bodies:evidence-bar") def _uuid_values(values: list[str], *, column_name: str = "id") -> str: rows = ",\n ".join(f"('{value}'::uuid)" for value in values) return f"(values\n {rows}\n ) as v({column_name})" def _jsonb(value: Any) -> str: return _sql_literal(json.dumps(value, sort_keys=True)) + "::jsonb" def concept_map_row() -> dict[str, Any]: return { "id": CONCEPT_MAP_ID, "key": CONCEPT_MAP_KEY, "title": "Distributed market intelligence", "body": ( "A concept map for how capital allocation depends on distributed knowledge, incentives, " "liquidity, feedback loops, and market signals rather than a single central planner." ), "status": "active", "source_ref": "mapped-rich-proposal-14fa5ecc:concept_map:distributed_market_intelligence", "metadata": { "base_packet_required_first": BASE_PACKET_REQUIRED_FIRST, "proposal_id": PROPOSAL_CONCEPT_ID, "source_fragment": ( "capital_allocation_depends_on_distributed_market_intelligence draws_from " "concept_map:distributed_market_intelligence" ), }, } def concept_links() -> list[dict[str, Any]]: return [ { "id": CONCEPT_LINK_ID, "claim_id": CLAIM_DISTRIBUTED_MARKET_INTELLIGENCE_ID, "concept_map_id": CONCEPT_MAP_ID, "relation": "derives_from", "weight": 0.75, "rationale": ( "Mapped proposal 14fa5ecc: the capital-allocation distributed-knowledge claim draws " "from the distributed market intelligence concept map." ), "source_ref": "mapped-rich-proposal-14fa5ecc:concept_map:distributed_market_intelligence", "metadata": {"proposal_id": PROPOSAL_CONCEPT_ID}, } ] def governance_links() -> list[dict[str, Any]]: return [ { "id": QUALITY_GATE_LINK_ID, "claim_id": CLAIM_NODES_NEED_BODIES_ID, "governance_gate_id": QUALITY_GATE_ID, "relation": "supports", "weight": 0.85, "rationale": ( "Specific enough to disagree with requires more than a compressed headline for ambiguous claims." ), "source_ref": "mapped-rich-proposal-ac036c9d:governance_gate:quality-gate", "metadata": {"proposal_id": PROPOSAL_GOVERNANCE_ID}, }, { "id": EVIDENCE_BAR_LINK_ID, "claim_id": CLAIM_NODES_NEED_BODIES_ID, "governance_gate_id": EVIDENCE_BAR_ID, "relation": "supports", "weight": 0.85, "rationale": "Bodies can state the true evidence tier and scope limits.", "source_ref": "mapped-rich-proposal-ac036c9d:governance_gate:evidence-bar", "metadata": {"proposal_id": PROPOSAL_GOVERNANCE_ID}, }, ] def build_schema_sql() -> str: return """create table if not exists public.concept_maps ( id uuid primary key default gen_random_uuid(), key text not null unique, title text not null, body text not null, status text not null default 'active' check (status = any (array['draft'::text, 'active'::text, 'retired'::text])), source_ref text, metadata jsonb not null default '{}'::jsonb, created_at timestamptz not null default now(), updated_at timestamptz not null default now() ); create table if not exists public.claim_concept_map_links ( id uuid primary key default gen_random_uuid(), claim_id uuid not null references public.claims(id) on delete cascade, concept_map_id uuid not null references public.concept_maps(id) on delete cascade, relation text not null check (relation = any (array['derives_from'::text, 'supports'::text, 'contextualizes'::text, 'contains'::text, 'requires'::text, 'relates'::text])), weight numeric check (weight >= 0 and weight <= 1), rationale text not null, source_ref text, metadata jsonb not null default '{}'::jsonb, created_at timestamptz not null default now(), unique (claim_id, concept_map_id, relation) ); create table if not exists public.claim_governance_gate_links ( id uuid primary key default gen_random_uuid(), claim_id uuid not null references public.claims(id) on delete cascade, governance_gate_id uuid not null references public.governance_gates(id) on delete cascade, relation text not null check (relation = any (array['supports'::text, 'requires'::text, 'constrains'::text, 'documents'::text])), weight numeric check (weight >= 0 and weight <= 1), rationale text not null, source_ref text, metadata jsonb not null default '{}'::jsonb, created_at timestamptz not null default now(), unique (claim_id, governance_gate_id, relation) ); create index if not exists claim_concept_map_links_claim on public.claim_concept_map_links (claim_id, relation); create index if not exists claim_concept_map_links_map on public.claim_concept_map_links (concept_map_id, relation); create index if not exists claim_governance_gate_links_claim on public.claim_governance_gate_links (claim_id, relation); create index if not exists claim_governance_gate_links_gate on public.claim_governance_gate_links (governance_gate_id, relation);""" def build_generated_counts_sql() -> str: return f"""select (select count(*) from public.concept_maps where id = {_sql_literal(CONCEPT_MAP_ID)}::uuid) as generated_concept_map_rows, (select count(*) from public.claim_concept_map_links where id = {_sql_literal(CONCEPT_LINK_ID)}::uuid) as generated_concept_link_rows, (select count(*) from public.claim_governance_gate_links where id in (select id from {_uuid_values([QUALITY_GATE_LINK_ID, EVIDENCE_BAR_LINK_ID])})) as generated_governance_link_rows; """ def _concept_map_insert_sql() -> str: row = concept_map_row() return f"""insert into public.concept_maps (id, key, title, body, status, source_ref, metadata) values ( {_sql_literal(row['id'])}::uuid, {_sql_literal(row['key'])}, {_sql_literal(row['title'])}, {_sql_literal(row['body'])}, {_sql_literal(row['status'])}, {_sql_literal(row['source_ref'])}, {_jsonb(row['metadata'])} );""" def _concept_link_insert_values() -> str: rows = [] for row in concept_links(): rows.append( "(" f"{_sql_literal(row['id'])}::uuid, " f"{_sql_literal(row['claim_id'])}::uuid, " f"{_sql_literal(row['concept_map_id'])}::uuid, " f"{_sql_literal(row['relation'])}, " f"{row['weight']}, " f"{_sql_literal(row['rationale'])}, " f"{_sql_literal(row['source_ref'])}, " f"{_jsonb(row['metadata'])}" ")" ) return ",\n ".join(rows) def _governance_link_insert_values() -> str: rows = [] for row in governance_links(): rows.append( "(" f"{_sql_literal(row['id'])}::uuid, " f"{_sql_literal(row['claim_id'])}::uuid, " f"{_sql_literal(row['governance_gate_id'])}::uuid, " f"{_sql_literal(row['relation'])}, " f"{row['weight']}, " f"{_sql_literal(row['rationale'])}, " f"{_sql_literal(row['source_ref'])}, " f"{_jsonb(row['metadata'])}" ")" ) return ",\n ".join(rows) def build_preflight_sql() -> str: required_claim_ids = [CLAIM_DISTRIBUTED_MARKET_INTELLIGENCE_ID, CLAIM_NODES_NEED_BODIES_ID] required_gate_ids = [QUALITY_GATE_ID, EVIDENCE_BAR_ID] return f"""\\set ON_ERROR_STOP on -- Governance/concept companion preflight. Read-only. -- Run after the mapped rich proposal packet has been applied. select 'schema_table' as check_name, name, to_regclass(name) as regclass from (values ('public.concept_maps'), ('public.claim_concept_map_links'), ('public.claim_governance_gate_links') ) as v(name); select 'required_base_claim' as check_name, c.id::text, c.status, left(c.text, 220) as text from public.claims c where c.id in (select id from {_uuid_values(required_claim_ids)}) order by c.id; select 'required_governance_gate' as check_name, id::text, name, left(criteria, 180) as criteria, left(evidence_bar, 180) as evidence_bar from public.governance_gates where id in (select id from {_uuid_values(required_gate_ids)}) order by name; """ def build_apply_sql(*, commit: bool) -> str: terminator = "commit;" if commit else "rollback;" required_claim_ids = [CLAIM_DISTRIBUTED_MARKET_INTELLIGENCE_ID, CLAIM_NODES_NEED_BODIES_ID] required_gate_ids = [QUALITY_GATE_ID, EVIDENCE_BAR_ID] return f"""\\set ON_ERROR_STOP on begin; {build_schema_sql()} do $$ declare inserted_concept_maps int; inserted_concept_links int; inserted_governance_links int; begin if ( select count(*) from public.claims where id in (select id from {_uuid_values(required_claim_ids)}) ) <> {len(required_claim_ids)} then raise exception 'governance/concept packet requires mapped base claims to exist before inserts'; end if; if ( select count(*) from public.governance_gates where id in (select id from {_uuid_values(required_gate_ids)}) ) <> {len(required_gate_ids)} then raise exception 'governance/concept packet requires quality/evidence governance gates to exist'; end if; if exists (select 1 from public.concept_maps where id = {_sql_literal(CONCEPT_MAP_ID)}::uuid or key = {_sql_literal(CONCEPT_MAP_KEY)}) then raise exception 'governance/concept packet generated concept map already exists'; end if; if exists (select 1 from public.claim_concept_map_links where id = {_sql_literal(CONCEPT_LINK_ID)}::uuid) then raise exception 'governance/concept packet generated concept link already exists'; end if; if exists ( select 1 from public.claim_governance_gate_links where id in (select id from {_uuid_values([QUALITY_GATE_LINK_ID, EVIDENCE_BAR_LINK_ID])}) ) then raise exception 'governance/concept packet generated governance link already exists'; end if; {_concept_map_insert_sql()} get diagnostics inserted_concept_maps = row_count; if inserted_concept_maps <> 1 then raise exception 'governance/concept packet inserted % concept map row(s), expected 1', inserted_concept_maps; end if; insert into public.claim_concept_map_links (id, claim_id, concept_map_id, relation, weight, rationale, source_ref, metadata) values {_concept_link_insert_values()}; get diagnostics inserted_concept_links = row_count; if inserted_concept_links <> {len(concept_links())} then raise exception 'governance/concept packet inserted % concept link row(s), expected {len(concept_links())}', inserted_concept_links; end if; insert into public.claim_governance_gate_links (id, claim_id, governance_gate_id, relation, weight, rationale, source_ref, metadata) values {_governance_link_insert_values()}; get diagnostics inserted_governance_links = row_count; if inserted_governance_links <> {len(governance_links())} then raise exception 'governance/concept packet inserted % governance link row(s), expected {len(governance_links())}', inserted_governance_links; end if; end $$; {terminator} """ def build_postflight_sql() -> str: return f"""\\set ON_ERROR_STOP on -- Governance/concept companion postflight row-level readback. {build_generated_counts_sql()} select id::text, key, title, status, source_ref, metadata::text from public.concept_maps where id = {_sql_literal(CONCEPT_MAP_ID)}::uuid; select id::text, claim_id::text, concept_map_id::text, relation, weight, left(rationale, 220) as rationale, source_ref from public.claim_concept_map_links where id = {_sql_literal(CONCEPT_LINK_ID)}::uuid; select id::text, claim_id::text, governance_gate_id::text, relation, weight, left(rationale, 220) as rationale, source_ref from public.claim_governance_gate_links where id in (select id from {_uuid_values([QUALITY_GATE_LINK_ID, EVIDENCE_BAR_LINK_ID])}) order by governance_gate_id; """ def build_delete_rollback_sql() -> str: return f"""\\set ON_ERROR_STOP on -- Emergency rollback for governance/concept generated rows only. -- Drops generated schema only when the generated tables are empty after row delete. begin; delete from public.claim_governance_gate_links where id in (select id from {_uuid_values([QUALITY_GATE_LINK_ID, EVIDENCE_BAR_LINK_ID])}); delete from public.claim_concept_map_links where id = {_sql_literal(CONCEPT_LINK_ID)}::uuid; delete from public.concept_maps where id = {_sql_literal(CONCEPT_MAP_ID)}::uuid; do $$ begin if to_regclass('public.claim_governance_gate_links') is not null and not exists (select 1 from public.claim_governance_gate_links) then drop table public.claim_governance_gate_links; end if; if to_regclass('public.claim_concept_map_links') is not null and not exists (select 1 from public.claim_concept_map_links) then drop table public.claim_concept_map_links; end if; if to_regclass('public.concept_maps') is not null and not exists (select 1 from public.concept_maps) then drop table public.concept_maps; end if; end $$; commit; """ def build_packet() -> dict[str, Any]: return { "packet_version": 1, "purpose": "Companion packet for mapped rich proposal governance-gate and concept-map targets.", "production_apply_status": "not_executed", "base_packet_required_first": BASE_PACKET_REQUIRED_FIRST, "schema_writes": [ "public.concept_maps", "public.claim_concept_map_links", "public.claim_governance_gate_links", ], "generated_counts": { "concept_maps": 1, "claim_concept_map_links": len(concept_links()), "claim_governance_gate_links": len(governance_links()), }, "required_existing_rows": { "public.claims": [ CLAIM_DISTRIBUTED_MARKET_INTELLIGENCE_ID, CLAIM_NODES_NEED_BODIES_ID, ], "public.governance_gates": [QUALITY_GATE_ID, EVIDENCE_BAR_ID], }, "safe_writes": [ { "table": "public.concept_maps", "operation": "insert", "rows": [concept_map_row()], }, { "table": "public.claim_concept_map_links", "operation": "insert", "rows": concept_links(), }, { "table": "public.claim_governance_gate_links", "operation": "insert", "rows": governance_links(), }, ], "represented_fragments": [ "capital_allocation_depends_on_distributed_market_intelligence draws_from concept_map:distributed_market_intelligence", "claim_nodes_need_bodies supports governance_gate:quality-gate", "claim_nodes_need_bodies supports governance_gate:evidence-bar", ], "sql": { "preflight": build_preflight_sql(), "apply_rollback_rehearsal": build_apply_sql(commit=False), "apply_commit": build_apply_sql(commit=True), "postflight": build_postflight_sql(), "delete_rollback": build_delete_rollback_sql(), }, } def write_packet_files(packet: dict[str, Any], output_dir: Path) -> None: output_dir.mkdir(parents=True, exist_ok=True) sql = packet["sql"] (output_dir / "governance-concept-preflight.sql").write_text(sql["preflight"], encoding="utf-8") (output_dir / "governance-concept-apply-rollback-rehearsal.sql").write_text( sql["apply_rollback_rehearsal"], encoding="utf-8" ) (output_dir / "governance-concept-apply-authorized-commit.sql").write_text( sql["apply_commit"], encoding="utf-8" ) (output_dir / "governance-concept-postflight.sql").write_text(sql["postflight"], encoding="utf-8") (output_dir / "governance-concept-delete-rollback.sql").write_text(sql["delete_rollback"], encoding="utf-8") summary = {key: value for key, value in packet.items() if key != "sql"} (output_dir / "governance-concept-packet.json").write_text( json.dumps(summary, indent=2, sort_keys=True) + "\n", encoding="utf-8" ) def parse_args(argv: list[str]) -> argparse.Namespace: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--output-dir", type=Path, help="directory to write packet files") return parser.parse_args(argv) def main(argv: list[str] | None = None) -> int: args = parse_args(sys.argv[1:] if argv is None else argv) packet = build_packet() if args.output_dir: write_packet_files(packet, args.output_dir) print(json.dumps({key: value for key, value in packet.items() if key != "sql"}, indent=2, sort_keys=True)) return 0 if __name__ == "__main__": raise SystemExit(main())