Skip to content

Latest commit

 

History

History
1351 lines (1148 loc) · 75.5 KB

File metadata and controls

1351 lines (1148 loc) · 75.5 KB

Authorization Service Operations

Purpose

This runbook assigns ownership and stop conditions for the staged WS-AUTH-001 authorization rollout. The verified-token configuration and evidence commands are executable contracts. Canonical actor resolution, actor-self authorization, one-time bootstrap, administrative and project grants, and actor/link lifecycle controls are implemented. TASK claim, start and work-context operations use canonical project authority. Other feature activations remain operation-specific; consult docs/roadmap_status.md rather than inferring availability from a grant or catalogue entry.

Ownership

Area Primary owner Required evidence
Issuer/audience/algorithm configuration Platform security Approved non-secret configuration inventory and verifier tests.
JWKS endpoint, cache, and rotation Platform security/on-call Rotation drill, cache bounds, outage behavior, alerts.
Introspection/revocation policy Platform security Approved mode, endpoint trust policy, timeout/failure proof.
First Access Administrator bootstrap Restricted deployment operator Dry-run, target verification, one-time result, authority event.
Pre-v0.1 production remediation Data owner plus security reviewer Separately approved forward migration and evidence-preservation proof.
Actor/grant administration Access Administrator Supported API/command, reason, idempotency, evidence.
Project contributor grants Covered Project Manager Exact-project target and privacy-bounded candidate lookup.
Recovery operations Operator or covered Project Manager as specified Matched permission, reason, resource scope, immutable evidence.
Rollout and recovery Release owner Fresh-baseline proof, compatibility inventory, and forward-recovery stop conditions.
Live authorization proof Release owner plus security/QA API-visible drill with redacted committed evidence.

Required Configuration

Platform security owns the following inventory. Production, staging, and preview fail closed when a required value is absent or outside its bound.

Variable Accepted value Default/requirement
WORKSTREAM_TOKEN_ISSUER Canonical HTTPS URL, at most 200 characters; no userinfo, query, or fragment Required
WORKSTREAM_TOKEN_AUDIENCE Non-empty string workstream
WORKSTREAM_TOKEN_JWKS_URL Canonical HTTPS URL; no userinfo, query, or fragment Required
WORKSTREAM_TOKEN_ALGORITHMS One-family subset of RS256,RS384,RS512,ES256,ES384,ES512,EdDSA Required; no symmetric algorithms
WORKSTREAM_REQUIRED_HUMAN_SCOPE One scope token workstream:access
WORKSTREAM_REQUIRED_SERVICE_SCOPE One scope token workstream:service
WORKSTREAM_TOKEN_CLOCK_SKEW_SECONDS Integer 0..300 30
WORKSTREAM_TOKEN_MAX_BYTES Integer 512..32768 16384
WORKSTREAM_TOKEN_HEADER_MAX_BYTES Integer 128..8192, not above token max 4096
WORKSTREAM_TOKEN_PAYLOAD_MAX_BYTES Integer 256..24576, not above token max 12288
WORKSTREAM_TOKEN_JWKS_CACHE_TTL_SECONDS Integer 30..3600 300
WORKSTREAM_TOKEN_JWKS_MAX_RESPONSE_BYTES Integer 1024..1048576 262144
WORKSTREAM_TOKEN_JWKS_MAX_KEYS Integer 1..100 20
WORKSTREAM_TOKEN_UNKNOWN_KID_CACHE_TTL_SECONDS Integer 1..300 30
WORKSTREAM_TOKEN_UNKNOWN_KID_CACHE_MAX_ENTRIES Integer 1..1000 100
WORKSTREAM_TOKEN_JWKS_CONNECT_TIMEOUT_SECONDS Float 0.1..10 2
WORKSTREAM_TOKEN_JWKS_READ_TIMEOUT_SECONDS Float 0.1..10 3
WORKSTREAM_TOKEN_JWKS_WRITE_TIMEOUT_SECONDS Float 0.1..10 3
WORKSTREAM_TOKEN_JWKS_POOL_TIMEOUT_SECONDS Float 0.1..10 1
WORKSTREAM_TOKEN_JWKS_TOTAL_TIMEOUT_SECONDS Float 0.5..15 5
WORKSTREAM_TOKEN_INTROSPECTION_MODE disabled or required Required
WORKSTREAM_TOKEN_INTROSPECTION_DISABLED_REASON Issuer-policy evidence reference Required in disabled mode
WORKSTREAM_TOKEN_INTROSPECTION_URL Canonical HTTPS URL Required in required mode
WORKSTREAM_TOKEN_INTROSPECTION_CLIENT_ID Non-empty secret-backed identifier Required in required mode
WORKSTREAM_TOKEN_INTROSPECTION_CLIENT_SECRET Non-empty secret value Required in required mode
WORKSTREAM_TOKEN_INTROSPECTION_MAX_RESPONSE_BYTES Integer 256..262144 65536
WORKSTREAM_TOKEN_INTROSPECTION_CONNECT_TIMEOUT_SECONDS Float 0.1..10 2
WORKSTREAM_TOKEN_INTROSPECTION_READ_TIMEOUT_SECONDS Float 0.1..10 3
WORKSTREAM_TOKEN_INTROSPECTION_WRITE_TIMEOUT_SECONDS Float 0.1..10 3
WORKSTREAM_TOKEN_INTROSPECTION_POOL_TIMEOUT_SECONDS Float 0.1..10 1
WORKSTREAM_TOKEN_INTROSPECTION_TOTAL_TIMEOUT_SECONDS Float 0.5..15 5
WORKSTREAM_API_RATE_LIMIT_KEY_SECRET Canonical padded RFC 4648 Base64 decoding to 32..64 bytes Required
WORKSTREAM_API_FIRST_ACCESS_RATE_LIMIT Integer 1..10000 10
WORKSTREAM_API_FIRST_ACCESS_RATE_WINDOW_SECONDS Integer 1..3600 60
WORKSTREAM_API_ADMIN_MUTATION_RATE_LIMIT Integer 1..10000 30
WORKSTREAM_API_ADMIN_MUTATION_RATE_WINDOW_SECONDS Integer 1..3600 60

Secrets, private keys, bearer tokens, full claims, and raw JWKS documents must not appear in committed configuration or evidence.

Verified issuer and sub identity anchors are each limited to 200 characters across the verifier, canonical registry, compatibility storage, audit, and checker provenance. Development issuer and subject settings use the same bound. Oversized values fail verification or configuration before actor persistence.

Verification evidence:

tmp_venv="$(mktemp -d)"
python3 -m venv "$tmp_venv"
"$tmp_venv/bin/python" -m pip install -e ./backend
"$tmp_venv/bin/python" -c 'import jwt, cryptography, httpx'
"$tmp_venv/bin/python" -m pip check
rm -rf "$tmp_venv"

cd backend
.venv/bin/python -m pytest -q tests/test_auth.py tests/test_config.py
.venv/bin/python -m ruff check app tests scripts
: "${WORKSTREAM_TEST_DATABASE_URL:?set a disposable migrated test database URL}"
WORKSTREAM_DATABASE_URL="$WORKSTREAM_TEST_DATABASE_URL" \
  WORKSTREAM_TEST_DATABASE_URL="$WORKSTREAM_TEST_DATABASE_URL" \
  .venv/bin/python -m pytest -q
: "${WORKSTREAM_TEST_ADMIN_DATABASE_URL:?set a local Postgres admin URL}"
metadata_dir="$(mktemp -d)"
trap 'rm -rf "$metadata_dir"' EXIT
.venv/bin/python scripts/run_isolated_tests.py \
  --metadata-json "$metadata_dir/result.json" \
  --timeout-seconds 3600 -- \
  .venv/bin/python scripts/api_contract_e2e.py
cd ..
python3 scripts/check_stale_workstream_wording.py
python3 scripts/check_stale_authorization_docs.py
python3 scripts/check_markdown_links.py
git diff --check

Use GET /api/v1/actors/me for canonical actor self-read. The duplicate GET /api/v1/auth/me endpoint is removed. Actor admission does not copy issuer email or display name into the profile. Consumers must not treat token identity metadata or workflow eligibility as profile or authorization truth. Human-owned display data is written only through PATCH /api/v1/actors/me. Task create/screen/release require project.task.manage through a current covering Project Manager grant. Token-role and creator metadata are not authorization inputs. Each mutation requires one UUID replay key and atomically records its authorization, task change, lifecycle evidence and receipt. Draft creation checks project existence without imposing guide readiness. Screening/release retain existing approved and frozen policy checks.

Task claim/start/work-context require current canonical authority and the applicable exact project grant. Token claims and eligibility rows are not authority. The API drill ends its task journey at that supported public boundary; hidden submission creation has separate proof.

Request And Error Context

Clients may send one X-Request-ID and one X-Correlation-ID. Each supplied value must be a canonical lowercase, hyphenated, non-nil RFC 9562 UUID using the RFC variant and version 1 through 8. A missing request ID is generated as UUIDv4; a missing correlation ID reuses the effective request ID. Duplicate, comma-joined, malformed, non-ASCII, nil, or unsupported-version values stop before route/dependency execution with HTTP 400 invalid_request. That response uses one newly generated UUIDv4 for both safe headers and never reflects the rejected bytes.

Every success and error response returns the effective IDs in X-Request-ID and X-Correlation-ID. Application-supplied response values for those headers are overwritten. Status, content length, duplicate unrelated headers, WWW-Authenticate, Retry-After, streaming chunks, and background work remain unchanged.

Errors add this canonical object while retaining the existing top-level detail or domain code/details compatibility fields:

{
  "error": {
    "code": "invalid_request",
    "message": "Request validation failed",
    "details": {},
    "correlation_id": "00000000-0000-4000-8000-000000000001",
    "retryable": false
  }
}

The authentication boundary uses missing_token, invalid_token, identity_verification_unavailable, and unsupported_subject_kind for their exact branches. Verification/registry unavailability is retryable; invalid credentials, unsupported kinds, validation, permission, not-found, conflict, and internal application errors are not. The canonical nested validation summary is capped at 20 errors with type/location evidence only. Existing sanitized validator messages remain solely in the bounded compatibility detail list.

Use the correlation ID to join operator evidence. Never add bearer tokens, claims, subjects, emails, SQL, provider bodies, exception text, or secrets to responses or logs. AUTH-04A does not activate rate controls, grant APIs, or new product authority; those remain owned by later separately reviewed chunks.

Canonical Actor Resolution

Every protected human request resolves the exact verified (issuer, subject) through one ActorIdentityLink to one local ActorProfile. The first valid human access consumes the PostgreSQL first-access rate control, then creates the profile, identity link, ActorProfileProvisioned, and ActorIdentityLinked evidence in one transaction. Concurrent allowed first-access requests cannot leave duplicate profiles, links, or evidence. Rate-limited requests may still receive HTTP 429 before identity serialization.

GET /api/v1/actors/me returns the caller's privacy-bounded Contributor-domain profile plus sorted active administrative role names as a non-authoritative self projection; project grants remain empty until AUTH-10. PATCH /api/v1/actors/me accepts only display_name and contact_email; token roles, issuer metadata, actor kind, status, grants, and lifecycle fields are not writable there. Suspended and deactivated profiles cannot read or update their self profile or perform protected product operations. An authorized administrator may still inspect their status through the separate administrative API.

Unknown services require later manual provisioning and are denied without a write. Agent and Space subjects are denied without a write. Operators must not convert token roles, email shape, subject shape, or old typed profiles into actor kind or authority.

A provisioned service ActorProfile is the stable Workstream principal, similar to a Kubernetes ServiceAccount. Its immutable service_identity is one of the closed registered internal services; its identity link separately stores the configured issuer and opaque subject used to verify credentials. Display name, email, subject syntax, token role, and adapter provenance are never service identity evidence.

Service authority is a reviewed static service-to-ActionId matrix, not a grant or database assignment table. A service receives no Contributor, AdminRoleGrant, or ProjectRoleGrant authority. Every matrix action remains unavailable until merged feature behavior exists and the dedicated AUTH activation custodian integrates its evaluator and changes only that action's availability.

Existing Service Identity Custody

The v0.1 baseline and runtime fixed-service registry are the only current service-identity installation paths. The former pre-v0.1 mapping utility and revision-specific mapping procedure are historical and have been removed. Existing development databases are not upgraded or mapped forward: recreate the database and install 0001_uuid7_v01. Operators must never infer a service identity from subject syntax, email, display name, token role, or adapter provenance.

The self-activation profile route and TASK eligibility bridge have been removed. Claim and start require canonical actor/lifecycle checks and an active Submitter grant for the exact project; an authorized Operator start override uses its explicit operation and reason. Retained eligibility rows do not grant TASK authority and have not been deleted. The old public submission-packet POST is also removed. Canonical admission-backed Submission creation remains hidden; its command validates current authority, exact assignment and locked policy lineage before consuming ART admission in the same transaction. Public creation and the remaining management/read-route cutovers remain separate work, not capabilities implied by this retirement.

Contributor Attribution Runtime Guard

The v0.1 baseline uses canonical contributor_id attribution. It does not inspect issuer, subject, email, token claims, current assignment, or another table to infer a replacement for invalid attribution.

Remediate a refusal only from authoritative canonical-actor evidence. Create or repair the canonical human ActorProfile through its owning reviewed process, or correct a demonstrably wrong attribution through a separately reviewed data repair. Do not map by email or display name, select a latest profile, convert a service identity, fabricate an ActorProfile, or edit immutable audit history. Pre-v0.1 transition preflights are historical only. Current deployments install the canonical contributor shape from 0001_uuid7_v01.

The reusable primitive is public.require_human_actor_profile_reference(). Exact triggers task_assignments_contributor_human and submissions_contributor_human enforce human lineage. Exact foreign keys fk_task_assignments_contributor_id_actor_profiles and fk_submissions_contributor_id_actor_profiles enforce existence, while renamed indexes ix_task_assignments_contributor_id and ix_submissions_contributor_id preserve lookup behavior.

Both columns are non-null native PostgreSQL uuid foreign keys; their Python owners expose canonical UUID strings. PostgreSQL rejects a missing profile with SQLSTATE 23503 and a service profile with 23514. Suspended and deactivated human profiles remain valid historical references. The v0.1 baseline has no downgrade path.

Claim, start and work-context use canonical AUTH. TASK locks the task and active assignment before AUTH locks the current ActorProfile, exact identity link and applicable grant; mutation locks remain held through the transaction. Contributor commands require an active exact-project Submitter grant, not a token role or an eligibility row. The separate Operator start override requires its explicit permission and a reason. AUTH denials return HTTP 403 permission_not_granted; database failures roll back with retryable HTTP 503 task_authority_unavailable. Initial identity resolution may reject a request before command execution under its own identity-error contract.

Admission-backed Submission creation remains hidden and uses its existing TASK-first context/assignment and AUTH transaction participants. The old public packet POST and self-activated contributor-profile endpoint are removed. Stored contributor references and retained submission reads are preserved.

PostgreSQL Rate Controls

First human access now uses the AUTH-04B PostgreSQL control. Future authority-management mutations attach their separately configured control in their owning chunks. Every replica must use the same secret and settings. Missing secret or database access fails first access closed with retryable HTTP 503; an exhausted window returns retryable HTTP 429 with an integer Retry-After. Existing exact identity links do not consume first-access capacity.

AUTH-10B1 adds the closed authorization_read scope without attaching it to a route or activating an action. Configure every replica consistently:

WORKSTREAM_API_AUTHORIZATION_READ_RATE_LIMIT=120
WORKSTREAM_API_AUTHORIZATION_READ_RATE_WINDOW_SECONDS=60

The limit accepts 1 through 10,000 and the window accepts 1 through 3,600 seconds. This scope uses the existing API rate-control HMAC key; it never uses an authentication or pagination-cursor key. Missing key or database access returns the same retryable 503 when a later route attaches the dependency. Exhaustion returns 429 with Retry-After.

The current authorization-read constraint requires PostgreSQL major version 16, matching the CI-pinned database used to freeze the exact pg_get_expr rendering. Confirm the target before deployment:

SELECT current_setting('server_version_num')::integer / 10000
  AS postgres_major_version;

Stop if the result is not 16; validate a different major version through a reviewed forward migration change rather than bypassing the drift check. Inspect the exact current database-owned expression:

SELECT pg_get_expr(conbin, conrelid) AS scope_constraint
FROM pg_constraint
WHERE conrelid = 'api_rate_control_counters'::regclass
  AND conname = 'ck_api_rate_control_counters_scope_token';

The returned scope set must be exactly first_access, admin_mutation, and authorization_read. PostgreSQL may render these as an ANY (ARRAY[...]) expression with text casts; compare the complete expression and values, not a substring.

If validation reports unexpected API rate-control scope constraint, do not drop, bypass, or force the constraint. Reconcile it to the canonical expected definition through a reviewed forward repair. Diagnose current rows with:

SELECT count(*) AS authorization_read_rows
FROM api_rate_control_counters
WHERE control_scope = 'authorization_read';

Do not delete an unexpired row. Recover forward.

Generate the secret outside the repository and store it in the deployment secret manager:

python3 -c 'import base64,secrets; print(base64.b64encode(secrets.token_bytes(32)).decode())'

Counters store only the server-owned scope and an HMAC-SHA256 digest of the verified issuer/subject. They do not store raw identity, actor, token, claim, role, email, or network values. Consumption uses database time and commits in an independent session before the protected mutation may continue or return 429, so downstream rollback does not restore allowance.

Secret rotation intentionally creates a new digest space. Before rotating:

  1. Quiesce every protected write for at least the largest effective pre-rotation window configured on any replica.
  2. Rotate every replica while writes remain quiesced; mixed-secret replicas must not serve protected writes.
  3. Delete only rows expired by PostgreSQL time:
DELETE FROM api_rate_control_counters
WHERE window_expires_at <= statement_timestamp();
  1. Confirm all replicas use the new secret, then resume protected writes.

Runtime consumption opportunistically deletes at most 100 expired other rows. On idle systems, operators may run the same expired-only SQL cleanup. Never delete active rows to recover capacity. The v0.1 baseline is not downgradable.

JWKS Rotation And Outage

Rotation procedure:

  1. Confirm the new key is published by the configured issuer over trusted HTTPS.
  2. Verify algorithm and key-use constraints.
  3. Exercise unknown-key refresh once; do not create refresh loops.
  4. Verify both old and new unexpired tokens only during the issuer's approved overlap.
  5. Confirm cache, refresh-success, and refresh-failure metrics use bounded labels.
  6. Remove the retired key according to issuer policy and repeat denial tests.

During an outage, cached keys may be used only inside the configured safe window. Once verification cannot be established, protected requests fail closed. Operators must not switch to an unpinned algorithm, shared production HMAC secret, development verifier, unsigned token, or unverified claim parsing.

Introspection And Revocation Mode

Production must select an explicit mode:

  • disabled only with documented issuer revocation/short-lifetime evidence;
  • required bearer-token introspection only to a separately configured HTTPS endpoint with OAuth client-secret Basic authentication, no redirects or environment proxies, and strict time/response bounds.

Required introspection responses contain active=true, iss, sub, aud, and jti; every identity value must match the already signature-verified token. Introspection cannot provide or replace identity, kind, scope, roles, or grants. Identifier-only introspection is not supported in this chunk. Platform security owns the client ID/secret, rotation, and revocation procedure.

JWKS and introspection use separate clients and policies. Bearer tokens never reach JWKS endpoints, redirect targets, logs, traces, errors, or audit events. An introspection outage fails according to the approved mode; it cannot silently degrade to token-role authority.

Bootstrap Custody

Bootstrap is a restricted local management operation.

Before execution:

  • verify the target is the intended active human profile and identity link;
  • verify the environment and database;
  • capture a redacted dry-run result;
  • confirm the one-time bootstrap has not already completed;
  • confirm the deployment operator has restricted environment access;
  • confirm audit and database-time behavior are available.

Run the supported command from the backend with the target's canonical UUID:

WORKSTREAM_DATABASE_URL='<target async Postgres URL>' \
  .venv/bin/python -m scripts.bootstrap_access_administrator \
  --actor-profile-id '<canonical actor UUID>' --dry-run

WORKSTREAM_DATABASE_URL='<target async Postgres URL>' \
  .venv/bin/python -m scripts.bootstrap_access_administrator \
  --actor-profile-id '<canonical actor UUID>' --execute

Dry-run is read-only and does not promise later success. Execution locks AuthorityControl(id = 1) FOR UPDATE, revalidates the active human target, then commits exactly one initial grant, completed control transition, and success event. Exit code 0 is eligible/success, 2 is invalid or ineligible, 3 is already bootstrapped/concurrent loser, and 1 is infrastructure failure. Preserve the bounded JSON result and correlated authority evidence; never add issuer, subject, email, display name, token, or database URL.

If execution returns 1, leave bootstrap custody with the deployment operator, verify transaction rollback and database availability, and retry the same supported command. Later or concurrent attempts return the stable audited conflict and must not be repaired by editing the control or grant tables.

Never bootstrap through public HTTP, direct SQL, a shared secret, or a fabricated human/system role.

Legacy Actor Classification

The former AUTH-06 classification migration and private envelope workflow are historical and must not be run against v0.1. Recreate development databases from the baseline; production remediation requires a separately reviewed forward migration.

Rollback across the removed pre-v0.1 revision graph is unsupported. Production recovery must move forward through a reviewed corrective migration that preserves actor and authorization evidence. Non-production databases may be recreated from 0001_uuid7_v01. Never rewrite the Alembic stamp, delete authority evidence, or restore the retired identity-storage shape.

Staged Rollout

For each chunk:

  1. Confirm allowed files and stop conditions.
  2. Run focused tests plus the full backend suite/API drill required by the contract.
  3. Run the current migration's forward and refusal tests where applicable.
  4. Confirm the obsolete-path allowlist only shrinks and no compatibility path was added or restored.
  5. Run required internal reviewers and repair valid findings.
  6. Publish one chunk-sized PR and stop for human merge approval.

Do not cut over a resource family until its local actor, grant, permission, resource loader, lifecycle guards, negative tests, and evidence path exist.

Catalogue And Action-Evidence Staging

WS-XINT-002-01 left the catalogue at exactly 71 PermissionIds and 78 ActionIds. The two AUTH-07B actor-self actions, seven AUTH-08 administrative actions, actor.service.provision, actor.profile.read, actor.identity_link.read, the three profile lifecycle actions, and the two identity-link lifecycle actions are active. The remaining five active actions are the AUTH-10B reads project.contributor_candidate.list, project_role_grant.list, and project_role_grant.read, plus the AUTH-10C mutations project_role_grant.issue and project_role_grant.revoke. WS-XINT-002-03 also activates only the fixed verifier, pending-work scanner, and put resolver. Actions not named by a completed activation chunk remain planned and non-executable. The target post-custody invariant is that planned runtime entries contain only action, permission, exact AUTH activation owner, and availability. The availability-neutral custody reconciliation assigns all 22 ART rows to ten exact activation custodians and the original 19 REV rows to seven exact AUTH custodians without changing mappings or planned availability. The REV owner cardinalities are 2/5/3/1/1/5/2 for WS-AUTH-001-REV-05, WS-AUTH-001-REV-06, WS-AUTH-001-REV-07, WS-AUTH-001-REV-08, WS-AUTH-001-REV-09A, WS-AUTH-001-REV-11, and WS-AUTH-001-REV-12. Custodian labels grant no reviewer, Operator, or service authority; all 23 REV actions remain planned and unavailable. WS-XINT-003-02C registers the four additional actions and six closed service identities but adds no evaluator, route, job, principal row, or lifecycle behavior. The v0.1 baseline seeds no ActorProfile, identity link, grant, route, or job for REV readiness. Its closed catalogue constraints are installed directly. Their owning feature must publish the approved principal/resource/guard/surface/ transaction contract before activation, but those foreign facts do not become free-form catalogue fields. Startup validation failure is a release blocker, not a reason to relax catalogue checks.

PR #139 historically required availability-neutral transfer of 25 ART and 19 REV owner rows before feature activation. Both transfers completed; WS-XINT-002-01 then reconciles the live ART set to 22 planned rows by deleting six obsolete upload actions and adding three bundle/review actions. The ART transfer and later WS-XINT-002-01 catalogue reconciliation are included in the v0.1 baseline. The REV transfer adds no migration. The ART transfer does not grant Operator authority; its OPERATOR suffix denotes only future activation custody, and verification retry remains independently gated from read/status actions. Catalogue entries and explicit runtime composition determine availability; a planned action is not activated by its presence in the catalogue. CP01A added four initially unavailable adapter-binding actions under WS-ARCH-001-CP01A custody; it adds no evaluator, identity, grant, service matrix row, route, or activation. CP01B registered five initially unavailable contribution.policy.* actions with the same non-activation guarantees. CP05 now activates exactly those five actions through explicit human Finance Authority composition (system or exact project). Mutations require transaction-bound PREP; reads and committed replay check current authority. Default CON composition still denies access and no policy HTTP route is added. Migration 0012_contribution_policy_audit_resource adds the exact policy resource token and five existing action/permission pairs to the two closed database audit constraints, preserving their other clauses. Downgrade refuses while policy audit history exists. CP01C corrects only the unavailable binding fact shapes before CP02: binding identity and CON's unchanged instrument_type are explicit on create, unit is absent, and suspend/resume include the exact lifecycle version. AUTH does not translate the value or own CON instrument rules. AUTH-12I adds and activates only the unified compilation request/execute pair. AUTH-11C2 activates three current effective-policy and active-guide reads in addition to AUTH-11C1's five diagnostic reads. The exact route mapping is in docs/spec_authorization_service.md. WS-XINT-002-04A activates Project Manager guide-source ingest, and WS-XINT-002-04B activates only the fixed-service guide binding and read actions. WS-ARCH-001-02G activates contributor bundle preparation; 02H activates hidden human Submission creation and fixed-service submission binding. The other 14 ART actions remain planned, including every Operator artifact action. The v0.1 schema keeps each allowed or denied internal ART decision bound to the exact privacy-bounded resource-context digest in append-only audit facts.

AUTH-11A adds read-only project.setup_diagnostic.read and project.effective_policy.read. Project Manager and Audit Authority receive them at system or exact-project scope; Operator receives them at system scope. Finance Authority and Access Administrator do not. The two AUTH-11B identity/context actions, five AUTH-11C1 diagnostic-read actions, and three AUTH-11C2 current effective-policy/active-guide actions are active. AUTH-11C2 admits only covered Project Manager/Audit Authority or system Operator grants; Finance, Access Administrator, contributors, and services receive concealed denial. Its active-guide projection excludes retired compensation configuration. Four later REV registrations add exactly four planned and zero active actions. Review-evidence binding is registered planned and unavailable. WS-XINT-002-07A activates packet materialization only; it does not activate review-evidence binding. v0.1 reviewer findings/notes and contributor responses are REV-owned records with no artifact upload. Any future uploaded evidence requires separate approved REV-owned intent plus exact ART and AUTH owner work.

The v0.1 schema permits historical audit rows with null action_id. Inspect non-null action evidence only by bounded ActionId, request/correlation IDs, and resource references; do not export event payloads or actor identity-link data for routine diagnosis. Every action must carry its catalogue-mapped PermissionId, and every current permission must carry one of its mapped actions. Planned actions can record bounded denial evidence but cannot record an allowed decision through the typed writer.

The historical permission set remains exactly 49 values. The post-0020 set contains exactly 24 values, including review.queue.override, the two compilation permissions, project.setup_diagnostic.read, and project.effective_policy.read; do not derive historical status from identifier prefixes. WS-ARCH-001-02H activates the hidden base submission.create boundary; review rows remain planned. Initial and revision submission share submission.create, and no revision-specific permission or preparation action exists.

Review reads consume the request-scoped public AuthorizationService.require(action_id, typed_resource_context) boundary. The service's bound caller-owned AsyncSession is the only transaction source; the method accepts no session or uow argument. Review code must not query grants, import AUTH persistence, select raw PermissionIds, or implement permission unions. Artifact recovery remains the ART-owned artifact.verification_job.retry action through ArtifactOperatorRecoveryPort; shared outbox dispatch/retry remains outside REV ownership.

Review and other sensitive mutations must wait for WS-AUTH-001-PREP. That protocol locks AuthorityControl(id=1) first when final-admin safety applies, orders multiple principals by ActorProfile ID, then locks each human profile, exact link, and exact matched grant or each service profile and exact link. Service identity, static matrix membership, and action availability are code-owned validations, not database lock targets. Only then does AUTH create an internal, non-Pydantic PreparedAuthorizationHandle bound to the exact session, ActionId, actor reference kind, actor reference, idempotency key, and canonical request digest. It is never a route schema or caller input. Consumption matches every binding before the feature locks rows and recomposes final facts, then AUTH evaluates and stages evidence once before one route/service-command commit. Crossed tests must cover link revoke, actor suspend/deactivate, exact grant revoke, final-admin mutation, and same-session/action cross-actor or cross-request substitution. Never serialize or reuse the handle, let dependency teardown commit it, or commit AUTH evidence separately from feature state. The existing AuthorityClaimHandle is a separate idempotency-reservation contract, not this prepared authorization handle.

PREP currently supports actor-self profile update, the eight active AdminRoleGrant-backed administrative mutations, the three active fixed-service ART foundation actions, Project Manager artifact.guide_source.ingest, and the fixed-service artifact.guide_source.binding.create and artifact.guide_source.read, contributor artifact.submission_bundle.prepare, hidden human submission.create, and fixed-service artifact.submission.binding.create actions. AUTH-12F4 also supports Project Manager project.guide_compilation.review_package.read, project.submission_artifact_policy.approve, and project.guide_compilation.correction.request; POL-05B exposes these with exact Project Manager authority and manual correction dispatch. Checker, review, generic artifact-read, and the public Submission cutover remain planned. Callers begin and own one root transaction, call prepare, lock their participant rows, compose final typed facts, call consume with the independently expected ActionId and the same strict request/idempotency input, flush participant work, and commit once. AUTH never commits in dependency teardown. Roll back the caller transaction on denial, evidence/SQL failure, participant failure, timeout, or cancellation; cancellation must propagate unchanged. The handle remains consumed after every exact attempt, including a rolled-back or cancelled attempt, and dependency teardown invalidates all outstanding handles.

General human, administrative, and guide binding/read PREP callers do not restage a denial after rollback; its staged decision belongs to the failed caller transaction and rolls back with participant state. The three active internal ART foundation compositions are the deliberate exception: their adapter retains the exact denial, the composition root first rolls back ART state, and AUTH's public bounded restage operation commits the same denial in a clean AUTH-only transaction. The two guide binding/read adapters do not use that exception. Still-planned fixed-service preparation still issues no handle. XINT-06A activates the pre-submit materializer only for workstream.artifact.materializer. PREP first locks the service/action and the scalar task, assignment, project, policy, plan, catalogue, archive, generation, and storage-scheme facts before ZIP inspection. After inspection, the same process-local handle is consumed with the server-computed semantic-manifest hash before scratch reservation or checker execution. The activation binds those exact facts to workstream.artifact.materializer plus artifact.pre_submit.checker_input.materialize. The uploader's project role grant does not substitute for this fixed-service authority, and no prepared handle or scratch path is serialized into a Celery message or durable record.

When a planned foundation action enters its ART adapter with an exact resource context, its bounded action_unavailable denial follows the same rollback-then-clean-restage path.

Operationally, actor-self preparation locks profile then exact link. An administrative preparation locks AuthorityControl(id=1), request profile, exact request link, and deterministic matched AdminRoleGrant before participant locks. Do not add a feature lock ahead of that order. WS-XINT-002-03 is the first active ART fixed-service PREP consumer: the verifier, pending-work scanner, and put-attempt resolver can receive only their exact typed handles. Still-planned fixed-service actions produce no handle. ProjectRoleGrant preparation is unsupported until AUTH-10 supplies and proves its canonical lock path.

The pre-v0.1 downgrade path is removed. Preserve action evidence and recover forward rather than discarding it.

Canonical actor self-read/self-update, the seven AUTH-08 administrative actions, AUTH-09B controlled service provisioning, and the two AUTH-09C actor-registry reads are active. Project capability context waits for AUTH-10 exact-project grants and canonical project composition.

AUTH-10 uses independent submitter and reviewer grants. The retired both role and replacement-event migration states are not accepted by the v0.1 baseline. Recreate pre-v0.1 development databases. Production remediation requires a separately approved evidence-preserving data decision; never automatically convert or delete authority evidence.

Migration 0014_project_role_scope narrows the current project-role and audit contracts to submitter and reviewer. It preserves supported grants and qualification/audit history. If retained grants, qualification snapshots, or authority audit facts contain the adjudicator role, the migration refuses the upgrade atomically. Investigate and obtain an evidence-preserving data decision before retrying; do not delete, relabel, or bypass those rows to force migration success. Downgrade restores the prior database vocabulary without changing retained data; it does not enable adjudicator support in the current API.

Project-role revocation is routed by exact role. Submitter invalidation may reach task assignment; reviewer invalidation reaches only REV. Verify grant ID, actor, project, role, and cause event before a consumer changes product state. Revoking one role must leave the other project roles and all AdminRoleGrants unchanged.

The closed registry now has seventeen fixed-service identities: sixteen action-bearing identities with twenty-five matrix memberships, plus the target-only workstream.compensation.adapter identity. The action-bearing set comprises seven ART identities, project setup, six exact REV identities, the active shared outbox dispatcher, and the task assignment reconciler. Missing provisioned rows deny without stopping the application. The target-only identity has no matrix membership, and the REV actions remain unavailable. Dispatcher authority grants no feature permission. Do not create a shared review service or a database service-grant table.

Historically, AUTH-12B extended the registry to an eighth identity, workstream.project.setup, now with exactly six static memberships: project.guide_sufficiency.run, project.guide_compilation.request_automatic, project.guide_compilation.execute, project.submission_artifact_policy.derive, project.post_submit_checker_policy.derive, and project.setup_run.update. AUTH-12E activates project.guide_sufficiency.run, AUTH-12F3 activates project.submission_artifact_policy.derive, and AUTH-12I activates project.guide_compilation.execute. AUTH-12B2 activates project.setup_run.update only for the exact finalization resource. AUTH-12G activates post-submit derivation for this fixed service, binding complete finalized lineage and policy commitments through the same request-local PREP and root transaction. Exact-project managers separately authorize post-policy read, approval and correction; diagnostic grants do not permit proposal access. POL-06B exposes those manager operations and delivers deterministic derivation through the fixed setup service. Every delivery resolves current service authority and starts a fresh root transaction. The setup service is not admitted through a human HTTP route, and it never receives a fabricated human grant. The baseline seeds no profile, link, AdminRoleGrant, or ProjectRoleGrant. An Access Administrator may use the existing controlled service-actor provisioning route only when the deployment supplies the exact issuer and opaque subject. Provisioning alone grants no executable setup action; each action becomes executable only after its own activation chunk merges.

AUTH-12J adds request-local adapters for the two deterministic projections created from an already persisted unified compilation result. Each adapter uses a distinct closed resource context, binds the exact project, compilation attempt, service actor/link, output identity, and complete server-owned fact digest, and consumes the existing opaque PREP capability in the caller's root transaction. Exact replay freshly validates the stored allowed decision but does not consume authority or create another event. These adapters are not wired into the live setup flow by AUTH-12J.

Fixed-service admission is request-local. Resolve only the verified issuer and opaque subject through the exact stored link and active service profile; never accept a service identity, action, permission, or matrix row from request or token claims. An unknown or absent provisioned row returns bounded service_actor_not_provisioned and does not block startup or Access Administrator provisioning. Static catalogue/matrix mismatch is instead a code invariant and may fail startup.

For an admitted service, AUTH selects its exact static ActionId row before availability. Cross-service actions deny without human grant lookup, including actions sharing a PermissionId; own rows remain unavailable while planned. Revoked links and suspended or deactivated profiles deny from current database state. Failed admission creates no first-access row, invokes no human rate control, and advances no timestamp. If exact active resolution staged observation timestamps before a later denial, cancellation, or evidence failure, the request transaction rolls them back before secret-free denial evidence is restaged from a clean transaction.

Diagnose fixed-service denials only through request/correlation ID, local actor reference, exact ActionId, and bounded denial facts. Never log or export issuer, opaque subject, bearer material, claims, scopes, provider payloads, mapping-file contents, or service credentials. Lifecycle or immutable-identity drift during the profile-then-link lock/revalidation step is a denial, not a fallback to human grants.

Actor Self Decision Operations

GET /api/v1/actors/me declares actor.profile.read_self; it permits an active identity link with an active human actor. Suspended actors are denied on both self routes. Both self routes lock the exact actor profile first and its exact identity link second and recheck current state before deciding. GET then advances verification timestamps and commits bounded read-decision evidence. PATCH /api/v1/actors/me declares actor.profile.update_self; it additionally mutates only display_name or contact_email and commits mutation plus allow evidence once. The authorization kernel never commits or rolls back.

Self routes return explicit 403 errors because the caller owns the target: identity_link_revoked, then actor_deactivated, then actor_suspended for both self-read and self-update. A correction to lifecycle state takes effect on the next request; no decision cache survives a request. Token role changes do not affect either self action. Unknown and planned actions appear publicly only as permission_not_granted.

For diagnosis, query authority-domain authorization_decision rows by bounded request/correlation ID and exact ActionId. Confirm the mapped PermissionId, actor-profile resource reference, allowed fact, and denial code. Do not log or export issuer subjects, bearer tokens, display names, contact emails, or token roles. If a denied PATCH occurs, the route transaction is rolled back and the same frozen denial is committed from a clean transaction; a changed decision ID or concurrent display-field mutation is an incident signal.

Administrative Authority Operations

AUTH-08 activates permission and administrative-role definition reads, scoped administrative-grant collection and actor-history reads, and administrative grant issue/revoke. Access Administrator is the only role that can issue or revoke. Audit Authority is read-only and sees only the system or exact-project scope covered by its current grant; filtering occurs before totals and cursors. Requested target role/scope is mutation data, never caller authority.

AUTH-09C adds GET /api/v1/actors/{actor_profile_id} and GET /api/v1/actors/{actor_profile_id}/identity-links. Both require an effective system-scoped Access Administrator or Audit Authority grant; a project-scoped Audit Authority grant never covers the global actor registry. The link route returns the one v0.1 link object, not a collection. Suspended/deactivated target actors and revoked target links remain readable for lifecycle diagnosis.

The profile response includes only canonical lifecycle state, timestamps, display name, provisioning method, and the closed local service_identity for a service actor (null for a human). The link response includes only its local IDs, subject kind, lifecycle state, and timestamps. Neither response includes issuer, subject, contact email, reason, lifecycle actor, token/claim, grant, assignment, or service-action-matrix data.

Controlled provisioning may create the target-only workstream.compensation.adapter profile and service identity link. Operators must not add a service-action matrix row for it: it is a binding target, not an action-bearing service principal. CP03A left all adapter-binding actions unavailable; CP03B is the separate completed Finance Authority activation boundary.

The kernel locks and revalidates the human caller profile, exact link, and matched system grant before target lookup and holds those locks through disclosure and commit. It does not acquire AuthorityControl or lock a distinct target. Unauthorized callers are denied before lookup. Missing actor and link targets both roll back the staged allow and return the same actor_resource_not_found 404; they do not advance caller timestamps or leave allow evidence. SQL/evidence/touch/commit failure rolls back and returns the retryable service_unavailable 503.

Each protected route owns one caller-session transaction. A successful read, exact replay, issue, or revoke commits its decision evidence and advances the caller's ActorProfile.last_seen_at and ActorIdentityLink.last_verified_at using database time. Issue/revoke additionally commit business state, idempotency completion, success evidence, and linked invalidation together. Success, invalidation, mismatch, and post-allow conflict evidence derive their request/correlation IDs from the exact authorization decision; feature callers cannot override them. The decision resource-context digest binds role, scope, target, and existing idempotency-record disposition. Issue/revoke recomputes the reason digest before any state or evidence write. The shared authorization dependency never commits an open feature transaction; it rolls back anything the route forgot to commit.

Controlled Service Provisioning

POST /api/v1/service-actors accepts only a fixed service_identity, opaque subject with no leading or trailing whitespace, bounded reason, and UUID Idempotency-Key. Accepted subject bytes are preserved without normalization. The issuer comes from the configured provider-neutral verifier; operators cannot submit or override it. Only an effective system Access Administrator may call the route. A successful request creates one active service ActorProfile and exact identity link plus the allowed decision, ServiceActorProvisioned, linked invalidation, and committed idempotency result in one transaction. It creates no role, grant, assignment, or service admission.

Treat service_identity_already_provisioned and identity_subject_already_linked as final 409 occupancy conflicts. Treat idempotency_mismatch as client request drift. Retry service_unavailable with the same key and exact body. Do not inspect or export issuer, subject, bearer token, email, or raw reason when diagnosing a failure; use bounded request/correlation IDs and ActionId actor.service.provision.

Provisioning is not token verification. The new service profile's last_seen_at and link's last_verified_at stay null, including on replay. Only the human caller timestamps advance on a committed create or replay. Provisioned service tokens enter only the central AUTH typed-service path; legacy dependencies continue to reject them. Unprovisioned service tokens deny without actor first-access, timestamp observation, or rate-control activity.

If route-owned persistence or decision evidence fails, roll back the entire unit and return the bounded retryable 503 service_unavailable envelope. Do not report a mutation as successful, retain a pending idempotency result, or advance verification timestamps. A retry uses the same idempotency key. Exact replays reauthorize current caller authority and canonical resource state before returning the stored response. A deactivated service profile or revoked service link makes replay unavailable; mismatches commit only bounded denial evidence from a clean transaction.

Rollback

Rollback stops rather than bypasses authorization. A deployment may roll back only to the preceding reviewed chunk state and compatible schema revision.

Stop rollout when:

  • issuer behavior would require trusting a token role/unverified claim;
  • classification requires guessing subject kind;
  • a second canonical actor/verifier/authorization path appears necessary;
  • authority state and evidence cannot commit atomically;
  • final-administrator safety depends on an unlocked count;
  • an intermediate release cannot execute the established intake lifecycle;
  • tests, CI, privacy, or auth defaults would need weakening.

Do not restore deleted authority through direct SQL or re-enable any obsolete token-role path.

Project identity and self authorization-context reads are active under AUTH-11B. Both use a canonical project target and revalidate the current human profile and exact identity link. project.read accepts either an effective covered administrative grant or an active exact-project contributor grant and records which grant class authorized the decision. The context response is a derived read model, not an authority token: it contains no grant ids or identity-link fields and never advertises planned or unrelated actions.

The five AUTH-11C1 diagnostic GET routes use the same rate-first human-read admission and concealed authorization response. They lock the exact project, guide/version, selected child or collection, source snapshot, current actor and identity link, and matched administrative grant through projection/commit. Only a covered Project Manager, scoped Audit Authority, or system Operator may read them. Finance Authority, Access Administrator, contributor, non-human, revoked, wrong-scope, and cross-guide/cross-project requests do not disclose whether the target exists. Authentication and rate-control failures retain their canonical 401/503 and 429/503 behavior before private lookup.

Recovery Permission Inventory

Operation Authority Required controls
Normal covered task/setup repair Covered Project Manager project.task.manage Exact project, lifecycle guard, reason/evidence where mutation is corrective.
Start override Operator operations.task.start_override Recovery-only path, exact task/project, reason, matched grant/permission, audit.
Submission gate repair (planned; unavailable) Operator operations.submission_gate.repair No submission/review rewrite; reason, matched authority, immutable checker evidence.
Checker retry (planned; unavailable) Operator operations.checker.retry New attempt/supersession evidence; no prior result deletion.
Review lease force release Operator review.lease.force_release under WS-REV-001 Review-owned lease guards and evidence; no review decision.

Conceptual historical “admin override” statements are not operations. No recovery permission may erase checker evidence, create a review decision, alter an immutable submission, create/alter a contribution record, or bypass contribution policy.

Monitoring And Alerts

Required bounded-cardinality metrics cover:

  • workstream_auth_verification_total{result};
  • workstream_auth_jwks_cache_total{result};
  • workstream_auth_jwks_refresh_total{result};
  • workstream_auth_introspection_total{mode,result};
  • actor first access/conflict and actor/link state;
  • authorization allow/deny code and registered permission;
  • administrative/project grant state;
  • invalidation backlog and reconciliation retry;
  • bootstrap attempt/result.

Alerts require an owner, diagnosis steps, safe recovery, escalation path, and evidence-retention period. Alert on sustained verification failure, unusable JWKS cache, repeated bootstrap/final-administrator denial, unusual grant mutation rate, invalidation backlog, and abnormal first-access conflicts.

Platform security/on-call alerts when verification or refresh failures exceed 5% for five minutes, when all JWKS refreshes fail for two consecutive cache windows, or when required introspection is unavailable for two minutes. Diagnosis checks the approved issuer configuration, HTTPS reachability, key rotation window, cache age, and introspection health without printing response bodies or credentials. Recovery restores the approved issuer endpoint/policy; it never enables HMAC, development auth, redirects, or an unpinned algorithm. Escalate to the release owner and security lead and retain redacted incident metrics/configuration evidence for the normal security incident period.

Never use token, subject, email, jti, raw URL, key material, or unbounded resource IDs as metric labels.

Authority Mutation Idempotency

AUTH-09D-A and AUTH-09D-B expose:

POST /api/v1/actors/{actor_profile_id}/suspend
POST /api/v1/actors/{actor_profile_id}/reactivate
POST /api/v1/actors/{actor_profile_id}/deactivate
POST /api/v1/actor-identity-links/{identity_link_id}/revoke
POST /api/v1/actor-identity-links/{identity_link_id}/reactivate

Each route requires an effective system Access Administrator, the administrative mutation limiter, a UUID Idempotency-Key, and exactly one normalized bounded reason. Conflicts do not consume the key. Deactivation is terminal, and a profile reactivation does not restore a revoked identity link, grant, or fixed service admission. Link revoke/reactivate preserves the immutable issuer and subject binding, permits repair while its owner is suspended, refuses terminal owners, and never restores a grant or fixed-service admission. An administrator cannot revoke their own identity link.

Service-actor creation, administrative/project grant issue or revocation, actor suspension/reactivation/deactivation, and identity-link revocation/reactivation require a canonical UUID idempotency key. The namespace is actor-kind, opaque actor reference, closed operation, and key. Reusing that namespace with a different canonical request produces idempotency_mismatch without exposing the stored digest, record, or response.

Reservation must be the first database write. Business state, one concrete success event, one linked invalidation event, and the typed replay reference commit in the same caller-owned transaction. The authorization repository and service never commit, roll back, open a second session, expire a pending row, or steal a claim. On mismatch the caller rolls back the reservation transaction, starts a clean transaction on the same injected session, commits exactly one privacy-bounded denial event, and then translates the conflict.

A replay reference is internal only. Active administrative routes load the canonical resource and evaluate current authority again before responding; later route owners must preserve the same rule. ARCH-03C2 registers production assignment invalidation. ARCH-03B9 supplies the hidden exact-assignment handler; ARCH-03C1 supplies its sole fixed service workstream.task.assignment_reconciler and permission task.assignment.authority_reconcile. No human or dispatcher inherits it. ARCH-03C2 atomically publishes assignment-specific events from supported originating AUTH mutations and registers the handler with enforced prefork routing. Provisioning the service alone does not dispatch events. Release receipts retain the real decision and resource digest; later service revocation does not invalidate historical receipts. An audit invalidation row alone is not a dispatched reconciliation.

Project Role Read Operations

AUTH-10B2 exposes exactly three human-only, durable-rate-controlled reads:

GET /api/v1/projects/{project_id}/contributor-candidates
GET /api/v1/projects/{project_id}/role-grants
GET /api/v1/projects/{project_id}/role-grants/{grant_id}

Contributor candidates require a covered Project Manager and are available only for draft, active, or paused projects. Each item contains only actor_profile_id and nullable display_name. Grant list/detail require a covered Project Manager or Audit Authority and remain readable for every project state. List responses contain exactly items and next_cursor; no count or total is computed or returned. Candidate pages accept limit 1..100 (default 50) and a cursor of at most 512 characters. Grant pages add only optional status=active|revoked and role=submitter|reviewer filters.

Each grant contains exactly id, project_id, actor_profile_id, role, status, version, grant_method, qualification_snapshot, granted_by_actor_profile_id, granted_by_admin_role_grant_id, granted_at, grant_reason, and nullable revoked_by_actor_profile_id, revoked_at, and revoked_reason. Its qualification snapshot contains exactly id, requested_role, skills_snapshot, reputation_snapshot, prior_project_work_refs, external_expertise_refs, captured_by_actor_profile_id, captured_by_admin_role_grant_id, and captured_at. Skills and reputation objects contain only availability, reference_ids, and nullable unavailable_reason.

Permission/scope denial, an ineligible candidate project, missing project or grant, and project/grant mismatch share the same project_authorization_resource_not_found 404.

Provision WORKSTREAM_PAGINATION_CURSOR_HMAC_SECRET as canonical Base64 for exactly 32 random bytes. For example, generate it with openssl rand -base64 32. Missing or malformed values stop application startup. The key is independent from authentication and rate-control secrets. Rotation must be coordinated across all instances; replacing it invalidates every outstanding cursor, so drain or accept bounded client pagination restarts. Never log the key, a cursor, or distinctions hidden by the shared 404. Authorization read exhaustion returns 429 with Retry-After, and unavailable rate/evidence persistence returns retryable 503 before private row lookup.

AUTH-10C adds project-role issue evidence. It performs no product-row rewrite: it replaces only the three frozen authority evidence function bodies, adds qualification_snapshot to the existing privacy resource registry, and leaves the existing fact constraint and trigger identities in place. Its project-role mutations use the admin-mutation rate control, exact-project PREP, UUID idempotency keys, stable replay/conflict responses, and fail-closed retryable 503 handling for persistence failures. Operators may retry the same key and body after a 503; they must not invent a new key until the committed state is known. A revoked or suspended target may still have an active grant revoked. Issue writes snapshot-captured then grant-issued evidence without invalidation; revoke writes grant-revoked then a linked authority invalidation bound to the affected actor, exact grant, role, project, and closed future-obligation token.

Authority Audit Custody

Authority decisions and invalidation requests use the shared audit_events ledger. Database triggers reject normal UPDATE, DELETE, and TRUNCATE for both lifecycle and authority rows. There is no runtime flag, session setting, or application-user bypass. Authority timestamps come from the database, and the application writer joins the caller's transaction so evidence cannot commit separately from the authority mutation it explains.

Production must run Workstream with a dedicated non-owner database role that has no DDL, trigger-management, table-owner, superuser, or bypass privileges. Release verification must fail if the application credential owns audit_events or can disable its triggers. Schema migration credentials are separate and unavailable to the running service.

Owner-level maintenance is exceptional and requires an approved change record, an outage or writer drain, and an explicit list of rows and purpose. The database owner must:

  1. begin one transaction and take ACCESS EXCLUSIVE lock on audit_events;
  2. record the pre-change row count and trigger state without exporting private data;
  3. disable only the named mutation trigger needed for the approved operation;
  4. perform only the listed maintenance statements and verify affected IDs/counts;
  5. re-enable the trigger before commit and prove all three audit triggers enabled;
  6. retain redacted change evidence and return credentials to controlled storage.

Do not use owner maintenance to revise authority history, erase a denial, or fabricate evidence. Destructive cleanup requires a separately reviewed retention or legal procedure and is not an application operation.

Incident Response

For suspected authority misuse:

  1. Preserve request/correlation IDs and append-only authority evidence.
  2. Suspend/revoke through supported operations when current authority permits.
  3. Confirm same-token denial on the next request.
  4. Inspect exact matched grant, permission, project, and resource guards.
  5. Reconcile affected assignments without rewriting submitted/review history.
  6. Escalate final-administrator risk before any state mutation.
  7. Record corrective action and retained evidence without secrets or private artifact content.

Live Proof Responsibility

The final release owner coordinates a supported API/command drill proving:

  • first human access;
  • one-time bootstrap and concurrent conflict;
  • scoped administrative grants;
  • exact-project submitter/reviewer grants;
  • admin/contributor separation and self-action denial;
  • same-unexpired-token revocation;
  • suspension/reactivation and link revocation;
  • service subject handling;
  • cross-project concealment;
  • final-administrator concurrency safety;
  • authorized audit export and absence of direct database authority edits.

Committed proof uses approved redacted placeholders and never production tokens, private keys, raw claims, private actor/source IDs, or local paths.

Project creation authorization

Project creation is a system-scoped administrative mutation. Operators should verify that the caller has an active local human profile, active identity link, and active system-scoped project_manager grant; a token role is observation only and grants no authority. POST /api/v1/projects also requires a UUID Idempotency-Key. Exact retries return the original project, while reuse with changed request facts returns idempotency_mismatch and creates nothing. An exact committed retry is response recovery: it returns the database-bound original response without a second authorization event even if the original grant was later revoked. Revocation still denies every new key or changed request.

The protected transaction writes one draft project shell, its project-owned replay record, and an allowed authorization event that binds the distinct operation UUID to the future project UUID. If authorization, evidence, or the project write fails, the reservation rolls back with the transaction. Do not repair this path by inserting a project without the complete creation provenance columns or by granting project-scoped authority; project-scoped Project Manager grants cannot create projects.

Draft guide and source-metadata authorization

POST /api/v1/projects/{project_id}/guides and its draft-guide PATCH require a UUID Idempotency-Key and an active system or exact-project Project Manager grant. A 403 for an existing project is expected when that local grant is absent, revoked, stale, or scoped to another project; do not restore access from token roles or issuer claims. Use request/correlation IDs to inspect the bounded denial event.

Guide creation commits guide metadata, the complete declared document set and one awaiting_documents setup together. Its transaction consumes distinct internal guide-create and source-consent decisions and commits their paired replay records using the same external key. There is no public source-snapshot creation operation. Exact create replay rechecks current authority for both decisions and returns the original document IDs and initial setup response.

Upload each declared document through POST /api/v1/projects/{project_id}/guides/{guide_id}/documents/{document_id}/content with its declared content type and a UUID replay key. Exact membership and current ingest authority are checked before reading bytes. Only committed readiness of every declared document can dispatch setup. Celery receives identifiers after commit; prepared authorization handles must never appear in task arguments, logs or serialized state. The existing bounded continuation and dispatch recovery paths handle post-commit failures without another upload or compilation attempt.

The ordered task-example list and document declarations are immutable guide metadata in PostgreSQL; changes require a new guide version. Original document bytes live in ArtifactStore/S3. Inline Markdown and URL/repository ingestion are unavailable. Bounded draft metadata such as change_summary may still be updated. Embedded review, revision, retired payout/economic, and contribution-record configuration fields correctly return 422; do not reintroduce a compatibility payload or direct product-service authorization path.

The v0.1 guide-metadata schema does not invent or backfill historical custody. Every new covered mutation must commit its complete replay, decision, and row provenance atomically. Operators must preserve authority evidence and recover forward.

The v0.1 schema leaves historical sufficiency reports readable with null authorization provenance. New 12E mutations record complete creation or acknowledgement provenance and use the append-only guide_sufficiency_mutation_idempotency_records replay ledger. Do not delete replay, product, or authority evidence; recover forward.

The v0.1 baseline installs submission-policy PREP, replay, nullable provenance custody, and the fixed-service derivation execution claim. Human replay custody permits only pending -> committed. Fixed-service derivation commits reserved before material or agent I/O, then uses fresh final PREP and atomically advances reserved -> pending -> committed with the protected product mutation. A reserved or pending row is durable custody. Any audit event using the submission-policy mutation resource type, including denied evidence, must be preserved. 12F2 activates only manual human create/update. Each update appends a separately authorized successor and supersedes its exact hash-selected predecessor atomically. 12F3 activates derive only for the fixed workstream.project.setup service; approve remains planned. Operators must not treat the shared schema as wider activation.

The v0.1 baseline admits the guide-compilation request action, permission, and resource while preserving the execute vocabulary. The baseline cannot be downgraded. Recreate a development database instead of deleting authority evidence or attempting revision-specific rollback.

Draft review and revision policy authorization

The guide-bound review-policy and revision-policy PUT routes require a UUID Idempotency-Key, an active covered Project Manager grant carrying project.review_policy.manage, and a quoted If-Match value. The first version uses "no-current-policy"; replacements use the opaque selector composed from the current policy ID, generation, and canonical digest. Omitted, wildcard, unquoted, stale, cross-guide, or cross-project preconditions fail without advancing a selector.

Each success appends one immutable policy version, records the exact actor, identity link, matched grant, action and authorization decision, and advances only the corresponding draft-guide selector in the same transaction. The two policies may be attached in either order. Never repair an active guide by changing these selectors: active and superseded guide selections remain frozen.

human_review_required accepts only JSON booleans. Creation defaults true; omitted replacements preserve the exact predecessor's value. Every new version uses semantics_format=v2 and hashes the explicit setting. Existing v1 rows retain their hashes and mean true; incomplete history remains incomplete. False may be saved in draft, but the current guide activation service explicitly rejects it until automated acceptance and contribution execution is available. An exact committed retry recovers the original response under the adopted WS-XINT-003-02B actor/request contract; it does not reselect today's policy or perform another mutation. An omitted setting differs from an explicit true in request identity, preventing a changed retry from resetting false.

The v0.1 baseline includes nullable historical provenance columns and the policy_mutation_idempotency_records custody ledger. Historical legacy_incomplete rows remain grandfathered and are not attributed. Downgrade is refused after any 02B mutation/replay custody exists; do not delete policy or authorization evidence to force rollback. A populated rollback requires an explicit reviewed data-retention and migration plan.

POL-04B1 adds the hidden project.guide_compilation.request_automatic action under the existing project.guide_compilation.execute permission, restricted to workstream.project.setup. It binds the exact committed source mutation and its authorization event to one setup generation. Both human and automatic request replays recheck current authority inside the receipt transaction. POL-04B composes this authority with execution, projections and finalization in the live Celery worker. The automatic operation stops at findings or draft proposals; POL-05A owns manager review, correction and pre-submit approval. AUTH-12F4 supplies exact-project Project Manager authority; POL-05B supplies public composition and manual dispatch. Complete proposal content requires current exact-project manager authority; Operator and Audit diagnostic permissions do not grant it. Proposal services require explicit authority injection; there is no unconfigured construction path.

Complete-guide activation authority

AUTH-12H activates only project.guide.activate with project.guide.manage through the explicit guide_activation_authorization adapter. It authorizes the existing CP07 operation; AUTH-18 exposes it through the public guide activation POST and extends the authorized draft post-policy read with exact selectors. Only a current human Project Manager grant scoped to the exact project qualifies. System scope, other administrative roles and fixed services do not qualify.

Shared PREP locks authority control, actor/link and the manager grant before CP07 locks project and policy resources. A nominal one-use handle binds the operation, request, identity, session and root transaction. The complete CP07 facts digest is the exact digest saved in the allow event, mutation ledger and activation receipt. CP07 still owns complete-chain readiness, separate approvals, ContributionPolicy validation and atomic activation/supersession. human_review_required=false remains activation-blocked under the current capability guard.

Exact replay acquires fresh live authority and validates the retained decision; it returns the original receipt without a second allow or activation. Supersession or later ContributionPolicy retirement does not rewrite that evidence. Revoked actor/link/grant authority denies replay. Composition without the explicit adapter continues to deny. CP08 delivers Task, Assignment and hidden Submission policy lineage. Public manager activation is delivered; approved-guide intake integration remains next.

Shared outbox dispatcher

workstream.outbox.dispatcher has the active outbox.dispatch permission only. Provision it through the existing administrative service operation; Celery workers do not create identities. Missing or inactive provisioning denies each new phase. No human role receives dispatch authority, and no TASK, checker, artifact or compensation permission is inherited.

Celery registers workstream.outbox.deliver_event and a 60-second workstream.outbox.scan_pending sweep. The sweep reads bounded UUID pages and closes SQL before publishing event/project selectors. Failed publication is rediscovered; expired claims are recovered even if their handler was removed. Each delivery phase uses fresh AUTH/PREP and retains its exact decision reference. Unknown invoked effects remain terminal for reconciliation. The production registry contains only TaskAssignmentAuthorityInvalidationRequested version 1, with its separate exact feature authority. Unregistered event types stay unclaimed. Celery worker retries cover infrastructure failure with at most three retries and a 30-second exponential delay; they never authorize repeating an invocation.

Delivery requires Celery's prefork process pool. deliver_event has a 300-second hard execution limit, independent of its 240-second handler timeout and covering async shutdown as well. The prefork parent acknowledges a hard timeout instead of requeuing that timed-out invocation. A committed UNKNOWN remains terminal; if termination interrupts finalization, the existing expired-invocation recovery records UNKNOWN without calling the handler again. Ordinary Celery worker-loss redelivery remains fenced by the same durable invocation custody.

Eager execution and solo/thread/greenlet pools do not provide this process containment. Delivery is routed to workstream.outbox; startup rejects a consumer of that queue unless it uses prefork and disables eager execution. Delivery entry also rejects direct, eager or unvalidated consumers, including a queue added to an unvalidated Celery process after startup. Guide-only solo processes must select their other queues explicitly.

Run the dedicated consumer with:

celery -A app.workers.celery_app worker --pool=prefork -Q workstream.outbox

Keep a Celery process consuming celery for the recovery scan and run the existing Celery beat schedule. Provision both dispatcher and assignment-reconciler service identities through their authorized workflow. Missing/revoked feature authority leaves TASK unchanged; a dispatcher grant never supplies feature authority.

Supported Submitter grant revoke, actor suspend/deactivate and identity-link revoke append every affected pre-submission assignment in the same transaction as the authority state, audit pair and replay receipt. Projection/append failure rolls everything back and returns a sanitized retryable 503. Actor-wide projection reads pages of 100 without TASK locks; all pages commit together, so total work and held AUTH lock time grow with affected assignments. There is no truncation or historical invalidation backfill. Timed contributor expiry and voluntary skip remain deferred; this handler releases work for supported authority loss only.

Canonical submission and checker history

The TASK history contract defines eight exact read actions and distinct contributor/manager projections. AUTH stages a fresh matched-grant decision; the caller commits it only with a validated response. Authentication has no token-role compatibility projection or identity-observation writer. Retained actor classification data remains evidence, never an authority source. No manual checker or finalize-repair route survives.