Verify exact production traces and record rollout

This commit is contained in:
2026-08-11 11:29:59 +07:00
parent 6b8f7584ed
commit 59e6ad2d0d
46 changed files with 2795 additions and 290 deletions
+38
View File
@@ -53,6 +53,44 @@ hand plus direct `/api/chat` probes — measured, not inferred from docs.
evidence blocks unreachable from the prose, and provenance is a hard
guardrail.
## Second batch — guardrail gaps (same day)
A guardrail review against `docs/architecture.md` found two things the design
specifies that were not in the code. Both were implemented around the files
currently carrying uncommitted changes, so nothing in that set was touched.
- **Rate limiting — new `apps/web/middleware.ts`.** `/api/chat` is public,
takes no credentials and spends Bedrock credit per call against a small
personal AWS budget; the architecture assigns this to `api-gateway`, which
is not built. 12/min and 120/hour for `/api/chat`, 120/min for
`/api/suggest` (a local catalog lookup, no model call), keyed on the
left-most `X-Forwarded-For` entry that Caddy sets, returning 429 with
`Retry-After`. Counters are per process and in memory: correct for the
single `web` container in production today, and the point at which that
scales past one replica is the point this has to move to Redis or to the
gateway. It is a cost/abuse guard, not authentication.
- **Disclaimer — `rag/answer.py` only, wire-up still pending.**
`GroundedAnswer` now carries `disclaimer: str = DISCLAIMER` as a dataclass
default, so no response path can be constructed without it, including
abstains and clarifications. Deliberately a module constant and never sent
through the generator: a model-written disclaimer can be reworded or
dropped, and would then need verifying like any other generated claim.
### Wire-up left for whoever next owns `routers/rag.py`
`routers/rag.py` has uncommitted changes in this worktree, so the last step is
left undone rather than edited around someone else's work. Two small changes
complete it:
1. Add `disclaimer: str` to `RagQueryResponse` and pass
`grounded.disclaimer` through when the response is built.
2. `packages/shared-types/src/dto/chat.ts` already declares
`disclaimer?: string`, so the BFF only needs to copy it onto the message it
returns — no type change required.
Until step 1 lands, the guarantee exists in the domain object but is not yet
visible to an API consumer.
## Files claimed
`apps/ai-service/rag/answer.py`, `apps/ai-service/rag/agent.py`,