KB-3B9A

O9 first-automated-production-run readiness — 03-grant-audit-package

5 min read Revision 1
dieu44iu-cutterv0.6o9first-automated-production-runreadiness

O9 Report 03 — Grant audit & package (G3)

  • macro: v0.6-o9-first-automated-production-run-readiness
  • date_utc: 2026-05-21 · host: Contabo vmi3080463
  • gate covered: G3 — cutter_exec / cutter_verify governance grant audit
  • result: G3 PASS — grant_probe phase passes as-is; a minimal 2-grant package closes the O8F-flagged read residual

1. The orchestrator's own grant_probe gate — PASSES AS-IS

Phase 5 (grant_probe) runs discoverer.grant_matrix() and refuses to advance on any of 4 invariants. The exact deployment_grant_matrix SQL from discover.py was run against the live DB:

grant_probe invariant Live result
cutter_exec EXECUTE on fn_iu_create + fn_iu_enact TRUE
cutter_verify SELECT+INSERT on verify_result TRUE
directus SELECT on review_decision TRUE
no PUBLIC EXECUTE leak on a cutter_governance function TRUE (0 such functions exist)

➡️ grant_probe will PASS — no grant is required for the orchestrator gate. This is code-verified, not assumed.

2. Full grant matrix (S=SELECT I=INSERT U=UPDATE)

cutter_exec:
  public.information_unit               S--      # writes go via SECDEF fn_iu_create
  public.unit_version                   S--      # (cutter_exec needs EXECUTE on the fn,
  public.iu_lifecycle_log               S--      #  not direct INSERT — confirmed)
  cutter_governance.cut_change_set       SI-
  cutter_governance.cut_change_set_affected_row   -I-   <-- no SELECT
  cutter_governance.manifest_envelope    SI-
  cutter_governance.manifest_unit_block  SI-
  cutter_governance.review_decision      SI-
  cutter_governance.dot_pair_signature   SI-
  cutter_governance.decision_backlog_entry    SI
  cutter_governance.decision_backlog_history  SI
  cutter_governance.verify_result        ---      <-- no SELECT
  EXECUTE: public.fn_iu_create  Y · public.fn_iu_enact  Y
cutter_verify:
  cutter_governance.verify_result        SI-      # verify-writer path — OK
  cutter_governance.dot_pair_signature   SI-      # verifier signature — OK
  cutter_governance.cut_change_set       SI-

The leg-B recorder (runs as cutter_exec) INSERTs 8 tables — all 8 INSERT grants present. The verify recorder (runs as cutter_verify) INSERTs verify_result + dot_pair_signature — both present. The mutating write path is fully granted.

3. O8F-flagged residual — cutter_exec SELECT gap

O8F's blocker matrix flagged: cutter_exec lacks SELECT on cutter_governance.verify_result and cut_change_set_affected_row. Confirmed. This does not affect grant_probe (§1) but IS needed by three first-run read paths, all naturally run on the cutter_exec connection:

1. backup_runner pg_dump      — pg_dump of all 9 mutation-surface tables as
                                cutter_exec needs SELECT on every one, incl.
                                verify_result + cut_change_set_affected_row.
2. pre_run_snapshot_queries() — compensation.py before-run baseline includes
                                "SELECT count(*) FROM cutter_governance.verify_result".
3. GAP6 compensation plan     — compensation.py revert/snapshot SQL reads
                                cutter_governance.cut_change_set_affected_row.

4. Grant package — MINIMAL (2 single-table SELECTs, no broad grants)

Apply as the table owner / superuser workflow_admin on database directus, immediately before the first run:

-- O9 minimal grant package — closes the cutter_exec read residual.
-- Owner of cutter_governance.* = workflow_admin (superuser). Run as workflow_admin.
GRANT SELECT ON cutter_governance.verify_result              TO cutter_exec;
GRANT SELECT ON cutter_governance.cut_change_set_affected_row TO cutter_exec;

Precheck (expect both SI-/S-- to show SELECT) and post-apply verify:

SELECT 'verify_result'              AS tbl,
       has_table_privilege('cutter_exec','cutter_governance.verify_result','SELECT')
UNION ALL
SELECT 'cut_change_set_affected_row',
       has_table_privilege('cutter_exec','cutter_governance.cut_change_set_affected_row','SELECT');
-- both must return true AFTER the GRANT.

No EXECUTE grants, no schema-wide grants, no role changes. cutter_verify needs nothing. The optional fn_iu_apply_edit_draft EXECUTE for cutter_exec is not required by a create-cut first run (grant_probe does not probe it) and is intentionally excluded.

5. Verdict

grant_probe_phase:   PASSES as-is (4/4 invariants TRUE — code-verified)
residual:            cutter_exec SELECT on verify_result + cut_change_set_affected_row
grant_package:       2 single-table SELECT GRANTs (workflow_admin) — §4
authority_to_apply:  workflow_admin exists, is superuser+CREATEROLE — present
applied_by_this_macro: NO — no approval; packaged only
g3:                  PASS
Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-o9-first-automated-production-run-readiness/03-grant-audit-package.md