KB-789A

dot-iu-cutter v0.4 — Credential & Principal Strategy Design (design only; no credential creation) (2026-05-16)

8 min read Revision 1
dot-iu-cutterdieu44v0.4tier2credentialprincipalleast-privilegedesign-only

dot-iu-cutter v0.4 — Credential & Principal Strategy Design

document_path: knowledge/dev/laws/dieu44-trien-khai/v0.4-design/dot-iu-cutter-v0.4-credential-and-principal-strategy-design-2026-05-16.md
revision: r1
date: 2026-05-16
author: Agent (Claude Code CLI, Opus 4.7 1M)
phase: v0.4 — Tier 2 credential/principal DESIGN (companion to design-master)
status: design_only_pending_gpt_review

⛔ DESIGN ONLY. NO credential is created. NO role is created. NO GRANT is issued. NO password is minted. NO login/member binding. Every principal named here is a target for a SEPARATE, explicitly-authorized credential cycle that runs only after this design and the flow design pass GPT review.


§1 — Non-Negotiable: cutter_ro Is Read-Only

C-1 cutter_ro is NOLOGIN, 0 memberships, SELECT-only on 12 observe views +
    schema USAGE. It has ZERO write privilege and MUST NOT appear on any
    write path, ever.
C-2 the cutter-agent write path MUST NOT authenticate as cutter_ro, MUST
    NOT be granted cutter_ro for writing, MUST NOT extend cutter_ro.
C-3 cutter_ro stays exactly as v0.3 left it. v0.4 design proposes NO change
    to cutter_ro, its grants, its views, or its (deferred) login binding.
C-4 read needs of the write path (idempotency lookups, guard checks) are
    served by the WRITER principal's own SELECT on base tables (it needs
    base-table read to enforce invariants), NOT by cutter_ro and NOT by the
    observe views (which are redacted and intended for external observers).

§2 — Proposed Writer Principals (DESIGN; not created)

recommended split = TWO writer principals (OD-3; alternative 1 or 3 below):
  cutter_exec   (LOGIN, least-privilege):
    - drives MARK, REVIEW-persistence, CUT
    - INSERT on the MARK/REVIEW/CUT family tables + executor signature
    - UPDATE(status) on decision_backlog_entry
    - identity behind the DOT-991 executor signature lane
  cutter_verify (LOGIN, least-privilege):
    - drives VERIFY independently
    - INSERT on verify_result, verifier dot_pair_signature, compensating
      cut_change_set(+affected_row), escalation decision_backlog_entry,
      decision_backlog_history; UPDATE(status) on decision_backlog_entry
    - identity behind the DOT-992 verifier signature lane
rationale: VERIFY's value is INDEPENDENCE. If the same DB principal both
  cuts and verifies, the verify attestation is not an independent control.
  Two principals = real separation of duty, mirrored at the DB layer.
alternatives for GPT (OD-3):
  A) 1 writer principal (cutter_rw): simpler secret custody, WEAKER SoD —
     SoD then rests only on code paths + signature keys, not DB identity.
  C) 3 principals (cutter_mark / cutter_cut / cutter_verify): maximal
     isolation, more secrets to custody; likely over-engineered for v0.4.
recommendation: B (two principals) — best SoD/complexity trade-off.

§3 — Least Privilege (target grant model — applied LATER, not here)

P-1 grant ONLY INSERT (+ table-level UPDATE, with status-only enforced in
    code/invariant per BATCH-1) on exactly the tables each principal writes
    (see write-path doc §7). No SELECT beyond what invariant checks need.
P-2 NO DELETE, NO TRUNCATE, NO REFERENCES, NO TRIGGER, NO DDL, NO GRANT to
    any cutter writer principal.
P-3 NO membership in workflow_admin / postgres / directus app role. The
    writers are NOT superusers and CANNOT bypass RLS (none exists anyway).
P-4 the writers get NO privilege on schema `public` or any non-
    cutter_governance object (scope strictly the governance schema).
P-5 NO ALTER DEFAULT PRIVILEGES — grants enumerated exactly, no auto-grant
    of future objects (same discipline v0.3 used for cutter_ro).
P-6 reuse of the existing `directus` app role or `workflow_admin` as the
    writer is FORBIDDEN (privilege blast radius + audit ambiguity).

§4 — Secret Custody (strategy only — no secret minted)

SC-1 each writer principal gets its OWN distinct PG password secret —
     never shared, never the directus/workflow_admin password.
SC-2 custody pattern follows the established project convention: secrets
     live in the VPS-side env file (the /opt/incomex/docker/.env pattern
     already used for Agent Data / Directus creds), NOT in any repo, NOT in
     Agent Data, NOT in this document.
SC-3 cutter_exec secret and cutter_verify secret are stored as SEPARATE
     keys so the executor process cannot read the verifier's secret (and
     vice-versa) — process-level isolation backs the DB-level SoD.
SC-4 rotation: design assumes rotatable passwords (ALTER ROLE … PASSWORD in
     a future authorized op); no rotation schedule is set here.
SC-5 the agent NEVER prints, logs, or echoes a writer secret; harness/log
     redaction is a code-cycle requirement, recorded here as a constraint.
SC-6 minting these secrets is OUT OF SCOPE — it happens in the dedicated
     credential cycle, gated by GPT review of this design + sovereign prompt.

§5 — Executor / Verifier Separation & DOT-Pair Alignment

D-1 DOT-991 = executor lane: cutter_exec produces the executor
    dot_pair_signature on every cut_change_set. DOT-992 = verifier lane:
    cutter_verify produces the verifier dot_pair_signature on every
    verify_result. This mirrors the project's established paired pattern
    (DOT-…-EXECUTOR ↔ DOT-…-EXECUTOR-VERIFY) so cutter CUT/VERIFY aligns
    with the existing DOT governance idiom rather than inventing a new one.
D-2 the two DOT lanes use DISTINCT signing identities/keys (signing-scheme
    runtime is itself deferred — doc 6); v0.4 only fixes that the executor
    signature and verifier signature MUST be independently keyed and that
    dot_pair_signature.prior_signature_id chains each lane separately.
D-3 a verify_result whose verifier_signature shares identity with its
    checked executor_signature is INVALID by design (G-VERIFY-SOD at the
    crypto layer, not just the DB-principal layer).
D-4 mapping to schema: cut_change_set.executor_signature_id and
    verify_result.executor_signature_id reference the DOT-991 lane;
    verify_result.verifier_signature_id references the DOT-992 lane;
    cut_change_set.verifier_signature_id handling = OD-6 (recommend leave
    NULL; verifier signature recorded on verify_result only).

§6 — Interaction with Deferred B-4 (login/member binding)

B4-1 v0.3 deliberately left cutter_ro NOLOGIN with 0 memberships (B-4
     deferred). v0.4 design does NOT bind cutter_ro and does NOT create the
     writer login roles — it only specifies what they must be.
B4-2 when the credential cycle runs, the read-side B-4 (give cutter_ro a
     consumer) and the write-side (create cutter_exec/cutter_verify) are
     SEPARATE authorized steps; this design must not let one imply the other.
B4-3 no member/group binding, no GRANT cutter_ro TO …, no ALTER cutter_ro
     WITH LOGIN — all explicitly OUT OF SCOPE here.

§7 — Explicit Non-Scope (credential-specific)

NOT done here: role creation, GRANT, password mint, .env edit, login
  enablement, member/group binding, RLS, Directus role/policy/permission
  change, any connection as any writer, any test auth. This document is a
  specification of intent only. The credential cycle is a future, separately
  authorized, GPT-gated chain.

§8 — Open Decisions for GPT

OD-3  (restated) writer principal count: B=2 (recommended) vs A=1 vs C=3.
OD-6  cut_change_set.verifier_signature_id: leave NULL (recommended,
      preserves CUT-writes-only-CUT) vs VERIFY back-fills that one FK.
OD-CR-1 secret-custody substrate: confirm /opt/incomex/docker/.env-pattern
      vs a dedicated secrets store is acceptable for the later cycle.

End of v0.4 credential & principal strategy design (design only; no credential created).

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.4-design/dot-iu-cutter-v0.4-credential-and-principal-strategy-design-2026-05-16.md