DOCS
Authority sources.
How authority is sealed into execution — keys, constitutions, and admission checks.
Authority Source Adapter Contract v1.0
Status: Stable
Version: 1.0.0
Last Updated: 2026-02-09
---
Purpose
This contract defines the responsibilities and prohibitions for any system that wishes to become an authority source for ZAK governance infrastructure.
This is not a feature specification.
This is not a recommendation.
This is a contract.
Violating this contract means you are not an authority source — you are something else.
---
Core Principle
> ZAK does not react to the world.
> It records the world so institutions can explain themselves later.
Every authority source must preserve this principle.
---
What an Authority Source Is
An authority source is a system that:
Examples:
---
Adapter Responsibilities
An authority source adapter MUST:
1. Normalize Events
Convert platform-specific events into GovernanceEvent schema.
`` export function normalize[Platform]Event(
eventType: string,
payload: any,
eventId: string
): GovernanceEvent | null
typescript
`
Required:
, authority_change, artifact_change, signal timestamp from source for audit for unsupported events (don't guess)2. Preserve Immutability
Events are append-only.
Required:
3. Maintain Idempotency
Same event delivered twice = same result.
Required:
4. Store Raw Payloads
Original platform payload must be preserved.
Required:
field (JSONB)---
Adapter Prohibitions
An authority source adapter MUST NOT:
❌ 1. Interpret Meaning
Prohibited:
` // WRONG
if (event.type === 'admin_role_granted') {
return { ...event, recommended_action: 'tighten_constraints' };
}
typescript
`
Allowed:
` // CORRECT
return {
source: 'okta',
type: 'authority_change',
event: { name: 'privilege.granted', severity: 'high' },
// No recommendations. Just facts.
};
typescript
`
Why: Interpretation is constitutional evaluation. That lives elsewhere.
---
❌ 2. Make Decisions
Prohibited:
` // WRONG
if (severity === 'critical') {
await applyEmergencyConstitution();
}
typescript
`
Allowed:
` // CORRECT
await storeGovernanceEvent(event);
// Constitutional evaluator decides what to do (if anything)
typescript
`
Why: Adapters emit signals. Constitutions evaluate. Humans approve.
---
❌ 3. Auto-Apply Behavior Changes
Prohibited:
` // WRONG
if (productionDatabaseDeleted) {
await freezeAIBehavior(); // Automatic action
}
typescript
`
Allowed:
` // CORRECT
await emitGovernanceSignal({
recommended_action: 'freeze_mode',
requires_approval: true, // Human must approve
});
typescript
`
Why: auto_apply: false is enforced at the type level, DB constraint, and code.
---
❌ 4. Add Logic
Prohibited:
` // WRONG
if (isBusinessHours() && !isWeekend()) {
// Different behavior based on time
}
typescript
`
Allowed:
` // CORRECT
// Emit event with timestamp. Constitutional rules can reference time if needed.
typescript
`
Why: Adapters are dumb. All logic lives in constitutional evaluation.
---
❌ 5. Filter Events
Prohibited:
` // WRONG
if (event.priority === 'low') {
return null; // Silently drop
}
typescript
`
Allowed:
` // CORRECT
// Emit all events. Constitutional rules decide what matters.
return normalizeEvent(event);
typescript
`
Why: Filtering is a decision. Adapters don't decide.
---
Example Mappings
GitHub → GovernanceEvent
| GitHub Event | Event Type | Subject Kind | Event Name |
|--------------|-----------|--------------|------------|
| repository | | | (created) | state_change | repo | repository.created |
push | artifact_change | branch | push |
pull_request.opened | artifact_change | pr | pull_request.opened |
workflow_run.disabled | authority_change | workflow | workflow_run.disabled |
Okta → GovernanceEvent
| Okta Event | Event Type | Subject Kind | Event Name |
|------------|-----------|--------------|------------|
| user.account.privilege.grant | | | authority_change | identity | privilege.granted |
group.user_membership.add | authority_change | identity | group.added |
policy.lifecycle.update | authority_change | identity | policy.updated |
Jira → GovernanceEvent
| Jira Event | Event Type | Subject Kind | Event Name |
|------------|-----------|--------------|------------|
| jira:issue_created | | | state_change | ticket | issue.created |
jira:issue_updated (status) | state_change | ticket | issue.status_changed |
project_deleted | state_change | project | project.deleted |
AWS → GovernanceEvent
| AWS Event | Event Type | Subject Kind | Event Name |
|-----------|-----------|--------------|------------|
| CreateBucket | | | | state_change | environment | bucket.created |
PutBucketPolicy | authority_change | environment | bucket_policy.updated |
AssumeRole | authority_change | identity | role.assumed |
DeleteDBInstance | state_change | environment | database.deleted |
---
Webhook Handler Pattern
Every authority source follows the same flow:
` export const handler: Handler = async (event: HandlerEvent) => {
// 1. Parse platform webhook
const payload = JSON.parse(event.body || '{}');
const eventType = extractEventType(payload);
const eventId = extractEventId(payload);
// 2. Get organization (from installation mapping)
const orgId = await getOrganizationId(payload);
// 3. Normalize to GovernanceEvent
const governanceEvent = normalize[Platform]Event(eventType, payload, eventId);
if (!governanceEvent) {
return { statusCode: 200, body: 'Ignored (unsupported event)' };
}
// 4. Store event (immutable, append-only)
const storedEvent = await storeGovernanceEvent(orgId, governanceEvent);
// 5. Evaluate constitutionally (centralized, not in adapter)
const evaluation = await evaluateGovernanceEvent(governanceEvent, userTier);
// 6. Store signals (if any matched rules)
if (evaluation.recommended_actions.length > 0) {
await storeGovernanceSignals(orgId, storedEvent.id, evaluation);
}
// 7. Mark processed
await markEventProcessed(storedEvent.id);
return { statusCode: 200, body: 'Event processed' };
};
typescript
`
Critical: Steps 5-6 are never in the adapter. They live in shared infrastructure.
---
Installation Table Pattern
Every authority source has an installation table:
` CREATE TABLE IF NOT EXISTS [platform]_installations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
-- Platform-specific identifiers
[platform]_org_id TEXT NOT NULL UNIQUE,
[platform]_domain TEXT NOT NULL,
-- Access credentials (encrypted)
api_token_encrypted TEXT,
webhook_secret_encrypted TEXT,
-- Status
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'suspended', 'revoked')),
installed_at TIMESTAMPTZ DEFAULT NOW(),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
sql
`
Required:
---
Governance Rules (Separate from Adapters)
Governance rules live in governance-events.ts, not in adapters.
` export const GOVERNANCE_RESPONSE_RULES: GovernanceResponseRule[] = [
{
id: 'PRODUCTION_DATABASE_DELETED',
name: 'Production Database Deleted',
when: {
source: 'aws',
type: 'state_change',
event_name: 'database.deleted',
condition: 'event.severity === "high"',
},
then: {
action: 'freeze_mode',
reason: 'Production database deleted - freeze AI behavior',
severity: 'critical',
},
auto_apply: false, // ALWAYS false
requires_approval: true, // ALWAYS true
expires_after_hours: 4,
min_tier: 'enterprise',
},
];
typescript
`
Critical: Rules reference events by source + event_name. Adapters never see rules.
---
Testing Your Adapter
1. Emit a Test Event
` curl -X POST https://zak.example.com/api/[platform]-webhook \
-H "Content-Type: application/json" \
-d '{ /* platform event payload */ }'
bash
`
2. Verify Storage
Check that:
table preserved initially3. Verify No Auto-Apply
Check that:
(requires human)---
Checklist for New Authority Source
Before claiming compliance with this contract:
schema---
What Happens If You Violate This Contract
If an adapter:
Result: You are building something else. Not an authority source.
---
Version History
---
Contact
Questions? Clarifications? Proposed changes?
---
License
This contract is released under CC0 1.0 Universal (Public Domain).
Anyone may implement, extend, or reference this contract without restriction.
---
End of Contract