Skip to content

feat(contracts): authority-gated governance — GovernanceGate contract (#200)#209

Merged
stackbilt-admin merged 1 commit into
mainfrom
feat/governance-gate-contract
Jun 11, 2026
Merged

feat(contracts): authority-gated governance — GovernanceGate contract (#200)#209
stackbilt-admin merged 1 commit into
mainfrom
feat/governance-gate-contract

Conversation

@stackbilt-admin

Copy link
Copy Markdown
Member

Summary

Names and contracts the propose→gate→commit invariant (#200). The pattern existed as an emergent unnamed mechanism (dryRun flag on applyPolicies) but was not contracted, not enforced at the type level, and not auditable.

What changed

@stackbilt/types — new generic contract (no deps):

  • GovernanceDecision = 'approve' | 'override' | 'dismiss'
  • GovernanceProposal — stable id, alreadyCompliant, delta: string[], optional expires
  • GovernanceReceiptproposalId, decision, committedAt
  • GovernanceGate<Context, P extends GovernanceProposal>propose(context) + commit(proposal, decision)

@stackbilt/policies — concrete implementation:

  • PolicyGovernanceProposal extends GovernanceProposal (adds repoPath for commit replay)
  • PolicyGovernanceGate implements GovernanceGate<string, PolicyGovernanceProposal>
    • propose() calls applyPolicies(dryRun: true) — never writes
    • commit('approve'|'override') calls applyPolicies(dryRun: false)
    • commit('dismiss') — no-op, receipt still emitted
    • Proposal id is sha256 of resolved repoPath + delta (deterministic for same state)

Invariants enforced

Invariant How
propose() before commit() TypeScript — commit() requires a PolicyGovernanceProposal which only propose() produces
propose() is idempotent sha256 id is deterministic; same repo state → same id
dismiss leaves state unchanged commit('dismiss') skips applyPolicies entirely
every commit() emits a receipt return type GovernanceReceipt — non-nullable
autonomy ceiling externally set PolicyGovernanceGate takes opts at construction; cannot self-elevate

applyPolicies unchanged — additive only

The existing applyPolicies function and StampOptions/PolicyStampResult types are untouched. The gate wraps them. OSS additive-only policy satisfied.

Test plan

  • 6 new gate invariant tests pass (propose no-write, idempotent, approve writes, dismiss no-write, override on compliant, empty delta on compliant)
  • All 659 tests pass
  • pnpm run build clean

Closes #200

🤖 Generated with Claude Code

…tract (#200)

Names and contracts the propose→gate→commit invariant that was emerging
as an unnamed dryRun pattern across charter and colonyos. Makes the
invariants enforceable at type-check time rather than by convention.

Types in @stackbilt/types (generic, reusable):
  - GovernanceDecision = 'approve' | 'override' | 'dismiss'
  - GovernanceProposal — id (deterministic), alreadyCompliant, delta, expires?
  - GovernanceReceipt  — proposalId, decision, committedAt
  - GovernanceGate<Context, P extends GovernanceProposal> — propose + commit

Implementation in @stackbilt/policies:
  - PolicyGovernanceProposal extends GovernanceProposal (adds repoPath for
    commit replay without re-passing context through the interface)
  - PolicyGovernanceGate implements GovernanceGate<string, PolicyGovernanceProposal>
    wrapping applyPolicies; propose() never writes, commit('dismiss') is a no-op,
    proposal id is a sha256 of resolved repoPath + delta

Invariants verified by 6 new tests:
  - propose() does not write files
  - propose() is idempotent (same state → same id)
  - commit('approve') writes and emits receipt
  - commit('dismiss') does not write, still emits receipt
  - commit('override') applies even when alreadyCompliant
  - alreadyCompliant proposals have empty delta

Closes #200

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@stackbilt-admin stackbilt-admin merged commit 6001cbe into main Jun 11, 2026
3 of 4 checks passed
@stackbilt-admin stackbilt-admin deleted the feat/governance-gate-contract branch June 11, 2026 23:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[contract] Authority-gated governance — propose→gate→commit invariant

1 participant