76 lines
4.1 KiB
Markdown
76 lines
4.1 KiB
Markdown
# Claude ownership claim — 2026-08-11
|
|
|
|
Read `CLAUDE_HANDOFF_2026-08-10.md` first. Two items in it have since moved
|
|
on (checked against the code and against live production on 2026-08-11):
|
|
|
|
1. The structured-claims refactor it describes as in progress is finished and
|
|
shipped (`dfdbf52`, then `9c3acd0`). `pytest -q --ignore=tests/test_api.py
|
|
--ignore=tests/test_live_datastores.py` = 219 passed at the start of this
|
|
session.
|
|
2. Entailment majority vote (2-of-3) is no longer in the code. `df55af4`
|
|
introduced it; `9c3acd0` replaced it with a single pass
|
|
(`_ENTAILMENT_MAX_ATTEMPTS = 1`), with the reasoning in
|
|
`_verify_entailment`'s docstring: repeating an identical temperature-0
|
|
prompt is a correlated retry rather than an independent vote.
|
|
|
|
## What this session is changing, and why
|
|
|
|
All five items come from driving production (`https://realvuxbaro.me`) by
|
|
hand plus direct `/api/chat` probes — measured, not inferred from docs.
|
|
|
|
- **`rag/answer.py`** — availability failures during the entailment pass are
|
|
currently recorded and shown as `unsupported_claim`, so a timing or outage
|
|
problem reaches the user as a content failure. The failure taxonomy in
|
|
`docs/current-rag-pipeline-audit.md` §4 keeps these separate. Reusing
|
|
the reason codes that already exist and are already mapped in
|
|
`apps/web/app/api/chat/route.ts` (`request_budget_exhausted`,
|
|
`provider_unavailable`, `malformed_output`) — **no new reason code**, so
|
|
the frontend mapping needs no change. Fail-closed behaviour is unchanged;
|
|
only the label changes.
|
|
- **`rag/answer.py`** — `_verify_entailment`'s `for _ in
|
|
range(_ENTAILMENT_MAX_ATTEMPTS)` loop always returns on its first
|
|
iteration, so raising that constant silently does nothing, and the
|
|
unreachable `return False` after it returns a `bool` where every caller
|
|
reads `.supported`. Making the single-pass intent explicit.
|
|
- **`rag/agent.py`** — the pediatric dosing gate asks "Bé bao nhiêu tuổi và
|
|
cân nặng bao nhiêu kg?" even when the user just gave one of the two.
|
|
Reproduced 5/5 live ("18 ký", "18 cân", explicit "18 kg", "Trẻ 5 tuổi").
|
|
**The gate itself is NOT being loosened** — both fields stay required,
|
|
which is clinically right here (the correct answer uses both an age band
|
|
and a mg/kg rule). Only the question text becomes specific to what is
|
|
actually missing.
|
|
- **`apps/web/app/_components/ChatPanel.tsx`** — a hard 25s client abort
|
|
against a backend whose own budget is 40s (`config.py:60`). Measured
|
|
n=8 sequential: 2/8 exceeded 25s, and one of those was a **correct**
|
|
`answerable`/grounded/2-citation reply at 25.1s that the user never saw.
|
|
Caddy (`reverse_proxy web:3000`, no timeout) and the BFF (`signal:
|
|
request.signal`, no own timeout) do not cap this, so the client constant
|
|
is the only binding limit.
|
|
- **`packages/ui/src/ChatBubble.tsx`** — chips dedupe by `chunkId` but the
|
|
label is only drug+section+page, so several distinct chunks render as
|
|
identical-looking chips. **Not** collapsing them by label: the click
|
|
handler maps to a specific citation index, so collapsing would make real
|
|
evidence blocks unreachable from the prose, and provenance is a hard
|
|
guardrail.
|
|
|
|
## Files claimed
|
|
|
|
`apps/ai-service/rag/answer.py`, `apps/ai-service/rag/agent.py`,
|
|
`apps/ai-service/tests/test_grounded_generation.py`,
|
|
`apps/ai-service/tests/test_agent.py`,
|
|
`apps/web/app/_components/ChatPanel.tsx`,
|
|
`packages/ui/src/ChatBubble.tsx`, and this file.
|
|
|
|
Not touching `ingestion/`, retrieval adapters, `rag/service.py`,
|
|
`rag/understanding.py`, or anything sparse/BM25 related — task #4 (real
|
|
BM25 via Qdrant native sparse vectors) is still **not started**.
|
|
|
|
## Test-coverage context for review
|
|
|
|
These areas start with little automated cover: no tests currently touch
|
|
`missing_pediatric_age_or_weight` / `missing_population`, and the repo has no
|
|
frontend test setup (no `test` script in `apps/web/package.json`, no
|
|
ChatPanel/ChatBubble tests). A passing `pytest` run therefore is not on its
|
|
own sufficient evidence here. Backend tests are being added alongside the
|
|
changes, and the two frontend changes are verified by driving the real site.
|