Planning · readiness pass · NOT Admin 2c
Batch 4 on the Admin side mirrors Batch 4 on the FF side. Target: make it honest and concrete what Phase 2c must build for Admin Control Plane. No endpoints added · no alembic · no DB pool · no audit sink delivery wiring. What Batch 4 ships: target schema (admin.approval / admin.signature / admin.approval_ttl_state view / admin.audit) · extended approval-store example fixtures · 28-item cutover readiness checklist that lock-steps with FF Batch 4.
Current state vs 2c target
Concern
Current (2b)
2c target
Batch-4 artefact
approval store
file-backed JSON · approval_examples.json
admin.approval + admin.signature in PG · alembic migrated
Docs only persistence_schema.json
TTL computation
computed in-memory · policy_engine.sensitive_check_2b
admin.approval_ttl_state view · db-native computation · passive expiry preserved
Docs only view DDL in persistence_schema.json
audit sink delivery
sink_status='deferred' · stdout NDJSON mirror only
admin.audit → worker → Kafka ptt.audit.trail → WORM S3 (7yr retention)
Docs only group D in cutover_readiness_notes.json
cross-service with FF
Admin exposes sensitive.check.2b · FF does NOT call it
FF calls Admin 1s-timeout with circuit breaker · Admin publishes approval_ttl_refresh on Redis
Docs only group E in cutover_readiness_notes.json
signer workflow
read-only endpoints in 2b
POST /api/policy/approvals/{id}/sign · state transitions · withdrawal path
Docs only group F in cutover_readiness_notes.json — Admin 2d
Use cases modeled in Batch 4 (Admin side)
UC-ADM-B4-01 · ASE-01 single-signer valid
APP-100001-abcd · state=signed_full · required_signer_count=1 · product_owner signed · FF consume returns valid · ttl_state=valid. Fixture for smoke test.
UC-ADM-B4-02 · ASE-02 dual-signer signed_full
APP-100002-dual · finance_gate + legal_gate both signed · state=signed_full · FF consume returns valid · verifies count-of-approvals == required_signer_count arithmetic.
UC-ADM-B4-03 · ASE-03 dual-signer signed_partial denied
APP-100003-partial · only finance_gate signed · state=signed_partial · FF consume returns deny reason=dual_signers_required. Verifies state machine never allows signed_partial to produce valid.
UC-ADM-B4-04 · ASE-04 expired approval
APP-100004-expired · sla_deadline past · view returns ttl_state=expired · FF returns reason=approval_expired.
UC-ADM-B4-05 · ASE-05 withdrawn
APP-100005-withdrawn · closed_at set · state=withdrawn · FF returns reason=approval_withdrawn · ttl_state=not-applicable. Verifies withdrawn never re-activates.
UC-ADM-B4-06 · ASE-06 stale approval with operator alert
APP-100006-stale · past deadline by more than 24h · ttl_state=stale · FF returns deny + meta.operator_alert=true.
UC-ADM-B4-07 · audit envelope deferred
Any preview request returns envelope with sink_status='deferred'. No row written to admin.audit (table does not exist yet). Shape contract preserved for 2c wiring.
Deferred matrix (Admin side)
Item
Current state
Why deferred
Next phase
admin schema in Postgres
not created
needs alembic · no migration harness
Admin 2c
alembic migration history
directory doesn't exist
first migration is a Batch-5 task
Admin 2c
asyncpg pool in app.py
not wired
awaits schema creation
Admin 2c
admin.audit row writes
no writes
awaits schema · sink worker · Kafka
Admin 2c
Kafka producer for audit shipment
not wired
needs ptt.audit.trail topic and schema-registry
Admin 2c
WORM S3 mirror for 7yr retention
not configured
platform-level
platform
signer workflow mutations
read-only endpoints in 2b
out-of-scope Batch 4
Admin 2d
verified JWT on Admin
decode-only (same as FF 2b+)
platform-wide IdP stand-up required
Admin 2c (lock-step with FF)
background expiry sweep
passive read-time expiry
prec-8 fail-safe documented · no need yet
later
approval issuance flow (writes)
no create endpoint
depends on signer workflow
Admin 2d
Redis publisher for approval_ttl_refresh
not wired
Redis not stood up on Admin side
Admin 2c
admin.audit.ingest endpoint
not created
depends on FF audit shipment
Admin 2c
Next
Admin 2c will: (1) stand up admin schema via alembic using persistence_schema.json as spec · (2) wire asyncpg pool · (3) implement admin.audit.ingest endpoint for FF → Admin event shipment · (4) start Kafka producer worker to drain admin.audit pending rows · (5) publish approval_ttl_refresh on state transitions · (6) run harness against ASE-01..ASE-06 fixtures proving file-backed and db-backed return identical sensitive.check.2b responses · (7) coordinate cutover with FF Batch 4 checklist (lock-step).