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.
| 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. |
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 --checkUse 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.
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.
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.
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.
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.
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:
- Quiesce every protected write for at least the largest effective pre-rotation window configured on any replica.
- Rotate every replica while writes remain quiesced; mixed-secret replicas must not serve protected writes.
- Delete only rows expired by PostgreSQL time:
DELETE FROM api_rate_control_counters
WHERE window_expires_at <= statement_timestamp();- 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.
Rotation procedure:
- Confirm the new key is published by the configured issuer over trusted HTTPS.
- Verify algorithm and key-use constraints.
- Exercise unknown-key refresh once; do not create refresh loops.
- Verify both old and new unexpired tokens only during the issuer's approved overlap.
- Confirm cache, refresh-success, and refresh-failure metrics use bounded labels.
- 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.
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 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>' --executeDry-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.
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.
For each chunk:
- Confirm allowed files and stop conditions.
- Run focused tests plus the full backend suite/API drill required by the contract.
- Run the current migration's forward and refusal tests where applicable.
- Confirm the obsolete-path allowlist only shrinks and no compatibility path was added or restored.
- Run required internal reviewers and repair valid findings.
- 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.
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.
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.
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.
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 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.
| 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.
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.
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.
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 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:
- begin one transaction and take
ACCESS EXCLUSIVElock onaudit_events; - record the pre-change row count and trigger state without exporting private data;
- disable only the named mutation trigger needed for the approved operation;
- perform only the listed maintenance statements and verify affected IDs/counts;
- re-enable the trigger before commit and prove all three audit triggers enabled;
- 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.
For suspected authority misuse:
- Preserve request/correlation IDs and append-only authority evidence.
- Suspend/revoke through supported operations when current authority permits.
- Confirm same-token denial on the next request.
- Inspect exact matched grant, permission, project, and resource guards.
- Reconcile affected assignments without rewriting submitted/review history.
- Escalate final-administrator risk before any state mutation.
- Record corrective action and retained evidence without secrets or private artifact content.
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 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.
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.
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.
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.
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.outboxKeep 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.
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.