06 — Reworked dot-c1-grant-issue contract (governed propose path) 2026-06-23
06 — Reworked dot-c1-grant-issue contract
Reworked script: staged-artifacts/scripts/dot-c1-grant-issue.reworked.
It replaces the defective skeleton at
reports/c1-lego-…/staged-artifacts/scripts/dot-c1-grant-issue.
A. Defects of the old skeleton (confirmed against live SSOT)
curl … /items/governance_build_authorization— that Directus endpoint does not exist (gba is a raw PG table, absent fromdirectus_collections). Cannot mint anything.- Posts ~13 columns that don't exist (
grant_id, action, build_step, single_use, lease_ttl, manifest_bound_hash, owner, revocable, plan_ref, reject_on, scope-as-string). - Bypass: a direct REST POST to the grant table would skip
authorize_build_step, quorum, president vote, and the unimplemented-handler trigger ⇒GOVERNED_C1_DRYRUN_REJECT_GRANT_BYPASS. It is inert only because (1)+(2) make it fail.
B. Reworked contract (the issuer is now a PROPOSER, not a writer)
| requirement (§3.5) | how met |
|---|---|
| not POST to Directus gba | ✓ no curl to gba; no Directus write at all |
| not assume gba is a Directus collection | ✓ preflight to_regclass('public.governance_build_authorization') (raw table) |
| not use wrong columns | ✓ uses no gba columns; emits a proposed_action payload only; the handler maps live schema |
call the governed authorize_build_step path |
✓ dot-apr-propose --action-code authorize_build_step --proposed-action <C1 payload> |
| validate live schema | ✓ preflight asserts gba table + authorize_build_step action row exist; warns if handler still unimplemented |
support --dry-run |
✓ prints the APR it WOULD propose |
emit no grant in --dry-run |
✓ exits before proposing; mints nothing |
| return exact reject codes | ✓ exit 2 (missing --manifest-hash), exit 4 (gba/action absent); downstream reject codes are the handler's (file 07) |
C. Flow (governed, end to end)
dot-c1-grant-issue --manifest-hash <cser-v1> # Cấp A: propose only
└─> dot-apr-propose (authorize_build_step APR, proposed_action=C1 payload, priority=high)
└─> approvals: 1 human president + 2 ai_council (proposer excluded, no rejects) [quorum_passed]
└─> dot-apr-execute (Cấp B)
└─> dispatch_handler 'dot-apr-execute:authorize_build_step'
└─> execute_authorize_build_step -> 1 grant (run_pg), status=active
└─> trg_apr_block_unimplemented re-proves quorum on APPLY
The issuer never holds grant-mint authority; the handler does, and only behind quorum.
D. proposed_action payload (fixed C1 scope)
See payloads/authorize_build_step_apr_proposed_action.json. Key locks: c1=true,
scope={DRYRUN-NS, dot:c1:vocab, DOT_C1_VOCAB_BUILD, …}, commit_allowed=false, risk_level=high,
manifest_hash (required, from a DOT_C1_VOCAB_BUILD dry-run), ttl_seconds=7200.
E. request_type
apr_request_types (14 active) has no authorize_build_step default; dot-apr-propose accepts an
explicit --action-code (FK to apr_action_types, which DOES contain authorize_build_step). The
script uses --request-type rule_change (an active row; operator may pick another active row) +
explicit --action-code authorize_build_step.
F. Lifecycle note (honest)
The reworked issuer is still a staged script (not born/registered/cataloged as a DOT). This
macro's charter is the handler + binding + issuer redesign, staged for owner review — not the
DOT lifecycle registration of the issuer (that remains the separate, owner/operator-gated step named
in the predecessor HOLD). The issuer rework is design-complete ⇒
C1_AUTH_HANDLER_HOLD_GRANT_ISSUER_REWORK_INCOMPLETE does not fire; but "design-complete" ≠
"registered DOT".