Dev-mode context is read from
X-PTT-* headers or query params · bind to 127.0.0.1 only · not safe for public exposure.
Phase 2a+ HTTP boundary · FastAPI scaffold · wraps evaluator.py (parity-locked with evaluator.js)
FF_PORT)bash docs/runtime/feature-flags-service/run.sh.venv → install FastAPI + uvicorn → run verify_parity.py (must be 19/19) → start uvicorn on 127.0.0.1:8080.Point the URL bar at your running service and hit a flag. Nothing in this page stores state — context stays in the form.
No JWT in this phase. Context comes from headers or query params. Headers win on conflict.
| Header | Query fallback | Meaning |
|---|---|---|
X-PTT-User-Id | ?user= | Stable id · required · used for bucketing |
X-PTT-Tenant-Id | ?tenant= | Tenant scope · optional for platform flags |
X-PTT-Tier | ?tier= | RBAC tier · default anonymous |
X-PTT-Env | ?env= | prod / staging / dev · default dev |
X-PTT-Role-Key | ?role_key= | Platform vs tenant role · optional |
X-Request-Id | — | Correlation id · echoed in response |
The service returns HTTP 400 invalid_request with a hint field when no user id is supplied. This is deliberate — bucketing determinism breaks without a stable id.
Authorization: Bearer <jwt> · RS256 signed via IdP · JWKS rotation supported.sub (user_id) · tenant_id · tier · role_key · exp.Assumes the service is at http://127.0.0.1:8080. Replace host / port as needed.
curl -s http://127.0.0.1:8080/api/flags/health | jq .
curl -s 'http://127.0.0.1:8080/api/flags/eval?key=flags.registry_v1&user=U-1&tier=staff&env=prod' | jq .data
curl -s 'http://127.0.0.1:8080/api/flags/eval?key=cases.runtime_v1&user=U-2&tier=admin&env=prod&tenant=pty-zeroth' | jq .data
curl -s 'http://127.0.0.1:8080/api/flags/eval?key=flags.registry_v1' \ -H 'X-PTT-User-Id: hdr-user' \ -H 'X-PTT-Tier: admin' \ -H 'X-PTT-Env: prod' | jq .data
curl -s -X POST 'http://127.0.0.1:8080/api/flags/eval/batch' \ -H 'Content-Type: application/json' \ -d '{ "context": {"user_id":"U-batch","tier":"staff","env":"prod","tenant_id":"pty-zeroth"}, "flags": [ "flags.registry_v1", "cases.runtime_v1", {"flag_key":"wizard.runtime_v1","tier":"platinum"} ] }' | jq .data
curl -s 'http://127.0.0.1:8080/api/flags/registry?summary=true' | jq '.data | {count, flags: .flags[0:3]}'
curl -s -w 'HTTP=%{http_code}\n' 'http://127.0.0.1:8080/api/flags/eval?key=flags.registry_v1' | jq
Source: docs/runtime/feature-flags-service/http_contract.json · Parity reference: ../feature-flags/evaluator_contract.json
loading…