← Console Planning · FF Batch 4 Readiness Partial shell · Batch 10 bridge Ops Doc Groups Mgmt Status

Feature Flags · Batch 4 · Infra-backed Readiness Planning · JWT/JWKS readiness · persistence schema · Redis wiring notes · parity/cutover matrix · non-implementation

Planning · readiness pass · NOT FF 2c
Batch 4 is a readiness-documentation pass. No endpoints are added. No JWKS fetch is wired. No Postgres connection is opened. No Redis client runs. No cutover happens. What Batch 4 ships is conformable targets — JSON contracts and checklists — that let a human say honestly: "we know exactly what Phase 2c must build, and we know exactly what would block a db-backed cutover if attempted today." Batch 5 / FF 2c will take these artefacts as its acceptance gate.

Deliverable sets A–D Batch 4 scope

Set A

JWT / JWKS readiness

Fetch semantics · kid resolution · caching · rotation · algorithm allowlist · claim expectation examples · mode matrix consolidated. All documented · none wired in runtime.
Set B

Persistence backend readiness

Canonical DDL · indexes · FK cascade rules · migration ordering · file-backed pointer · alembic target. Applies to ff.flag_registry / ff.tenant_override / ff.user_override / ff.audit. Cutover parity matrix field-by-field.
Set C

Redis / cache invalidation readiness

Runtime wiring notes beyond the 2b+ contract. Client lifecycle · subscriber loop · single-flight locks · graceful degradation · metrics. Pub/sub channel payload examples (6 kinds).
Set D

Parity / cutover readiness

Test vectors for file vs db parity (17 vectors covering all 4 auth modes × 3 override scopes × 5 sensitive paths × 6 TTL states). 42-item cutover checklist across 10 concern groups.

Current state vs Phase 2c target

Concern
Current (2b+)
2c target
Batch-4 artefact
Verified JWT
decode-only · no JWKS fetch · no signature verify
verified mode default · decode-only fallback disabled in prod
Docs only jwks_integration_notes.json
Persistence
file-backed JSON · in-process dict · dev writes to same file
PostgreSQL · 4 tables · alembic-managed · dual-write parity window · db-authoritative after cutover
Docs only persistence_schema.json + cutover_parity_matrix.json
Cache
no cache · every evaluate re-reads file
Redis cluster · 6-namespace key prefix · pub/sub invalidation · single-flight locks · stampede protection
Docs only cache_runtime_notes.json + redis_channel_examples.json
Cutover gate
no harness · no blocker list
42-item green checklist · 17 parity vectors 100% pass · 48h staging observation · signed-off by platform lead + security lead
Docs only cutover_readiness_checklist.json + parity_test_matrix.json
Admin cross-service
sensitive.check.2b call modeled · not wired from FF
FF → Admin call active · 1s timeout · circuit breaker · fail-safe deny on admin_unreachable
Docs only see group F in cutover_readiness_checklist.json

Use cases modeled in Batch 4

UC-B4-01 · verified token happy path
Bearer JWT with valid RS256 signature + aud=pty-feature-flags + iss match + exp future · matrix row M-01 · auth_source=jwt · warnings=[] · JWT-EX-01 fixture.
UC-B4-02 · decode-only fallback (JWKS unreachable)
JWKS endpoint unreachable · FF_ALLOW_DEV_HEADERS=true · matrix row M-02 · warnings=['auth_not_verified','jwks_unreachable'] · JWT-EX-02 fixture.
UC-B4-03 · invalid signature must deny
Signature does not verify against cached kid · matrix row M-04 · code=signature_invalid · http=401 · no fall-through regardless of env · JWT-EX-04 fixture.
UC-B4-04 · token expired
exp claim in the past · matrix row M-07 · code=token_expired · http=401 · JWT-EX-03 fixture.
UC-B4-05 · kid miss with refresh fail → decode-only fallback
Token kid not in cache · one refresh attempt fails · matrix row M-03 · warnings=['auth_not_verified','kid_not_found'] · JWT-EX-07 fixture.
UC-B4-06 · file-backed vs db-backed parity (PV-01..PV-08)
17 test vectors span all override scopes · all MUST_MATCH fields identical except meta.backing_state. Harness passes → cutover allowed. Any divergence → blocker.
UC-B4-07 · cutover blocker example
Hypothetical divergence on reason_chain field between file and db paths → cutover BLOCKED. Rollback steps documented in cutover_readiness_checklist.json group I.
UC-B4-08 · tenant override invalidation
PUT /v1/flags/override/tenant/T-pty-pilot-01/ff.x → publish PUB-01 → subscriber DELs both override and eval keys for that tenant+flag. 2b+ reality: no cache to invalidate · trigger is documented only.
UC-B4-09 · user override invalidation
PUT /v1/flags/override/user/U1001/ff.y → publish PUB-02 → subscriber DELs per-user eval entries only (SCAN+DEL scoped to user_id).
UC-B4-10 · global invalidate with guardrails
Operator command → publish PUB-04 kind=global · scoped to ptt:ff:* prefix · rate-limited 1/minute/operator · audit.boundary emitted.
UC-B4-11 · stale cache late propagation
Subscriber disconnected during invalidation publish · local cache serves stale up to TTL · bounded staleness · documented limitation.
UC-B4-12 · sensitive flag · valid approval under verified mode
approval_ref=APP-100001-abcd · ttl_state=valid · auth_source=jwt · PT-04 vector · expected allow with meta.approval_ref and meta.ttl_state=valid.
UC-B4-13 · sensitive flag · expired approval denied
approval_ref=APP-100004-expired · ttl_state=expired · PT-05 vector · reason=approval_expired · regardless of otherwise-valid JWT.
UC-B4-14 · sensitive + auth_not_verified denies
approval_ref valid but auth_mode=decode-only · sensitive_overlay rule forces deny with reason=auth_not_verified · PT-07 vector · verified mode is mandatory for sensitive paths.
UC-B4-15 · audit boundary emitted on readiness path
Any mutation path (when wired in 2c) emits an admin.audit envelope with sink_status='pending'. Downstream worker ships to Kafka ptt.audit.trail. Batch 4 state: envelope shape documented · delivery deferred.

Deferred matrix what Batch 4 does NOT do

Item
Current state
Why deferred
Next phase
Public IdP / production JWKS rotation
no endpoint · no fetcher
requires IdP stand-up · platform decision
FF 2c
Fallback dev headers retirement
FF_ALLOW_DEV_HEADERS=true default
would break local dev without verified replacement
FF 2c post-JWKS wiring
Full DB persistence cutover
file-backed authoritative
no alembic · no parity harness executed
Batch 5 / FF 2c
Redis live invalidation wiring
contract only · no client
no Redis client in app.py · subscriber not implemented
FF 2c
Audit sink delivery
sink_status='deferred' returned
requires Kafka producer + WORM S3 mirror
Admin 2c · parallel with FF 2c
Approval issuance flow
read-only in 2b · file-backed store
requires signer UI + auth verified mode
Admin 2c / 2d
Signer workflow UI
not built
out of scope · Admin 2d
Admin 2d
FF transition API / flip / rollback writes
no endpoint
depends on audit sink delivery
FF 2c post-audit
Background expiry sweep
passive read-time expiry
acceptable under prec-8 fail-safe · no perf issue yet
later
Rate limiting
none in FF
upstream gateway responsibility · platform-level
FF 2c / platform
Production deployment hardening
run.sh local dev
requires containerisation + secret management
platform
Cross-service live gating calls
modeled · not wired
FF does not call Admin HTTP yet
FF 2c

Honest runtime limits after Batch 4

Next
FF 2c will: (1) introduce auth.py with JWKS fetch + verify · (2) create alembic migration 0001 for ff schema · (3) wire asyncpg pool + FF_BACKING env switch · (4) stand up Redis client + subscriber · (5) build parity_runner.py to execute parity_test_matrix.json · (6) enable FF → Admin sensitive.check.2b HTTP call with circuit breaker · (7) run 48h staging observation · (8) coordinate lock-step cutover with Admin Batch 4 checklist.