Appearance
AI Generation Replay Cache Contract Proof
Scope
P6-048 reduces latency and avoids a repeated provider request for an identical, already-settled AI generation preview. It applies only when AI_GENERATION_USAGE_WALLET_ENABLED=true; default deployments keep that flag off and preserve the existing preview behavior.
ai-classifier-service owns the replay record. It is not a Question Bank write, a wallet ledger, a usage counter, or a Gateway default-route promotion.
Replay Contract
- The service normalizes the generation request and derives the existing deterministic SHA-256 idempotency key from the actor, organization, mode, prompt, scope, count, document references, and reference question IDs.
- Cache lookup is isolated by
(organizationId, actorId, idempotencyKey)and only returns a non-expiredai_generation_preview_replaysrecord. - On a hit, the stored no-write preview is returned with a warning that the provider, usage-service, and wallet-service were not called.
- On a miss, the normal sequence remains
preflight -> provider -> settle -> provider usage event. Only that completed sequence saves a 24-hour replay. - Provider failures, settlement failures, and usage-event persistence failures are not cached. A cache persistence failure does not hide an already settled response; the owner-service idempotency keys remain the fallback on retry.
singleflightjoins concurrent identical requests in one Go process. It is deliberately not presented as cross-pod mutual exclusion; the durable cache serves completed retries after a restart or on another pod.
Boundary And Rollback
- The replay is an
ai-classifier-serviceprojection of an existing preview. It never creates a canonical question. A teacher still submits a reviewed candidate through Question Bank's separate owner API. - The default Gateway routes remain legacy-proxied. This is not browser or production-provider proof, and no paid provider request is made by these regressions.
- To disable the behavior, leave or set
AI_GENERATION_USAGE_WALLET_ENABLED=false; migration rollback drops only the AI-service replay table.
Hermetic Evidence
bash
GOTOOLCHAIN=go1.25.11 go test ./services/ai-classifier-service/internal/usecase \
-run 'TestClassifierServiceChargedGeneration(ReplaySkipsProviderAndSettlement|DoesNotCacheSettlementFailure)' -count=1 -v
GOTOOLCHAIN=go1.25.11 go test ./services/ai-classifier-service/internal/repository \
-run TestScanGenerationPreviewReplayDecodesSettledResult -count=1 -vThe first regression proves a second identical charged preview invokes exactly one preflight, provider, and settlement sequence, produces one usage event, and returns the stored preview. The second proves a settlement failure is not cached and a retry re-enters the provider path. The repository regression verifies durable JSON replay decoding.