02 — governance_build_authorization LIVE schema 2026-06-23
02 — governance_build_authorization LIVE schema (fresh-read 2026-06-23)
Source: information_schema.columns + pg_constraint on public.governance_build_authorization,
read-only via query_pg against VPS SSOT directus. No invented schema. The old staged payload
(13 non-existent columns) is discarded.
A. Columns (exact, in order)
| col | type | nullable | default | grant-payload mapping (handler) |
|---|---|---|---|---|
| auth_code | text | NO | — | PK; deterministic GBA-C1-<apr_code> (idempotent) |
| request_ref | text | NO | — | FK → approval_requests(code); the proposing APR's code |
| approval_ref | jsonb | NO | — | {apr_code, quorum:'passed', manifest_hash} |
| step_name | text | NO | — | from proposed_action.step_name |
| scope | jsonb | NO | — | from proposed_action.scope (jsonb object, not a string) |
| risk_level | text | NO | — | 'high' (CHECK low/medium/high/sovereign) |
| commit_allowed | boolean | NO | false | hard-coded false (dry-run only) |
| requires_sovereign_esign | boolean | NO | false | hard-coded false |
| sovereign_esign_ref | text | YES | — | null (allowed when esign=false) |
| rollback_plan_ref | text | NO | — | from proposed_action.rollback_plan_ref |
| granted_by | text | NO | — | 'dot-apr-execute:authorize_build_step' |
| granted_at | timestamptz | NO | now() | default |
| expires_at | timestamptz | NO | — | now() + ttl_seconds (default 7200) |
| consumed_at | timestamptz | YES | — | null at mint |
| consumed_by | text | YES | — | null at mint |
| revoked_at | timestamptz | YES | — | null at mint |
| revoked_by | text | YES | — | null at mint |
| revoked_reason | text | YES | — | null at mint |
| status | text | NO | 'draft' | 'active' at mint (CHECK draft/active/consumed/expired/revoked) |
| evidence | jsonb | YES | — | {plan_ref, manifest_hash, step_name, mode:'dry-run'} |
| created_by | text | NO | — | 'dot-apr-execute:authorize_build_step' |
| created_at | timestamptz | NO | now() | default |
B. Constraints (exact, pg_get_constraintdef)
| name | type | def |
|---|---|---|
| governance_build_authorization_pkey | PRIMARY KEY | (auth_code) |
| governance_build_authorization_request_ref_fkey | FOREIGN KEY | (request_ref) REFERENCES approval_requests(code) |
| chk_expiry | CHECK | expires_at > granted_at |
| chk_consumed_pair | CHECK | (consumed_at IS NULL) = (consumed_by IS NULL) |
| chk_revoked_pair | CHECK | num_nulls(revoked_at, revoked_by, revoked_reason) = ANY (ARRAY[0,3]) |
| chk_sov_esign | CHECK | requires_sovereign_esign=false OR sovereign_esign_ref IS NOT NULL |
| …_risk_level_check | CHECK | risk_level IN ('low','medium','high','sovereign') |
| …_status_check | CHECK | status IN ('draft','active','consumed','expired','revoked') |
Triggers on the table: only the two internal RI FK-check triggers (request_ref → approval_requests). No business trigger on the grant table itself.
C. Decisive facts the handler design depends on
governance_build_authorizationis NOT a Directus collection (absent fromdirectus_collections;to_regclass='governance_build_authorization' = raw PG table). ⇒ the handler MUST write viarun_pg INSERT. A DirectusPOST /items/…(old skeleton) is impossible (404) and is a forbidden bypass pattern.request_refFK → approval_requests(code) ⇒ a grant cannot exist without an approval request. The handler runs insidedot-apr-executewhile applying that very APR, sorequest_ref = APR.codealways satisfies the FK. (No APR ⇒ no grant. Structural anti-bypass.)- All NOT-NULL columns are derivable from (a) the approved APR payload, (b) fixed handler
constants (
commit_allowed=false,requires_sovereign_esign=false,granted_by/created_by), (c) defaults (granted_at,created_at,statusoverridden to 'active'). Mapping is COMPLETE ⇒C1_AUTH_HANDLER_HOLD_LIVE_SCHEMA_MAPPING_INCOMPLETEdoes not fire.
D. Defect cross-check vs old staged payload
Old governance_build_authorization_grant.json posted: grant_id, action, scope(string), build_step, single_use, lease_ttl, manifest_bound_hash, owner, revocable, plan_ref, reject_on, status. Only status exists as a real column (and scope exists but as jsonb not string).
The other 10 keys are non-columns. Corrected mapping → payloads/governance_build_authorization_grant.live-schema.json.