docs(claude): record plan 002 phase 2 in the project status
Why:
- The status section described plan 002 as Phase 1 only. The /v1/points read
routes, the query service, and the points scopes had shipped but were listed
under "not built yet", so a fresh session would start from a wrong map of the
codebase.
Changes:
- Record the five read routes, the points:read gating, and the 404-not-403
mapping.
- Call out the three route-level rules that fail quietly when broken: /count and
/search must precede /{point_id}, file_id is required on the listing, and the
search query is Persian-folded before matching.
- Point at tests/support/point_contract.py as the place new repository behaviour
belongs, since it runs against both the fake and real Qdrant.
- Narrow the "not built yet" list to Phases 3-6.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
34
CLAUDE.md
34
CLAUDE.md
@@ -37,9 +37,9 @@ driving `tests/e2e/test_compose_smoke.py` against a real uvicorn process, which
|
|||||||
skips itself unless `SMOKE_BASE_URL` is set. That maps to plan 001 Phases 1-6
|
skips itself unless `SMOKE_BASE_URL` is set. That maps to plan 001 Phases 1-6
|
||||||
done.
|
done.
|
||||||
|
|
||||||
Plan 002 (`/v1/points` CRUD and keyword search) is **Phase 1 done**. Landed: the
|
Plan 002 (`/v1/points` CRUD and keyword search) is **Phases 1-2 done**. Phase 1
|
||||||
`PointRepository` port (`src/application/ports/point_repository.py`) with its
|
landed the `PointRepository` port (`src/application/ports/point_repository.py`)
|
||||||
`Point` read model (`src/application/points/point.py`), the Qdrant adapter
|
with its `Point` read model (`src/application/points/point.py`), the Qdrant adapter
|
||||||
(`src/infrastructure/qdrant/point_repository.py`), request/response schemas
|
(`src/infrastructure/qdrant/point_repository.py`), request/response schemas
|
||||||
(`src/api/schemas/points.py`), and lifespan wiring. This port is **separate from
|
(`src/api/schemas/points.py`), and lifespan wiring. This port is **separate from
|
||||||
`PointStorage`**, which stays exactly the two bulk operations ingestion
|
`PointStorage`**, which stays exactly the two bulk operations ingestion
|
||||||
@@ -59,9 +59,31 @@ and ordered listing paginates by `order_id` value rather than offset (Qdrant
|
|||||||
returns no page offset under `order_by`, and an offset cursor skips or repeats
|
returns no page offset under `order_by`, and an offset cursor skips or repeats
|
||||||
rows under a concurrent insert).
|
rows under a concurrent insert).
|
||||||
|
|
||||||
Not built yet: plan 002 Phases 2-6 — the `/v1/points` routes themselves, soft
|
Phase 2 added the **read routes**: `GET /v1/points/{point_id}`,
|
||||||
delete with neighbour relinking, create/replace/patch, reorder and batch, and
|
`GET /v1/points?file_id=...`, `GET /v1/points/count`, `GET /v1/points/search`,
|
||||||
the `api_request_logs`/`point_audit_events` tables — and `src/agent/`.
|
and `GET /v1/files/{file_id}/points`, over `src/application/points/queries.py`
|
||||||
|
(`src/api/routers/points.py`). All are gated on `points:read`, which — with
|
||||||
|
`points:write` — is now in `DEFAULT_SCOPES`; `GET /v1/files/{file_id}/points`
|
||||||
|
uses `points:read` rather than `files:write`, so the scope follows the data
|
||||||
|
rather than the URL prefix. `PointNotFoundError` maps to `404` in
|
||||||
|
`src/api/errors.py`, never `403`. Three route-level rules are load-bearing:
|
||||||
|
`/count` and `/search` are declared **before** `/{point_id}` (FastAPI matches in
|
||||||
|
declaration order, so reordering them makes `/v1/points/count` a `422`),
|
||||||
|
`file_id` is **required** on the listing (the cursor is an `order_id` value and
|
||||||
|
`order_id` is unique only within one file), and `search_points` folds the query
|
||||||
|
with `normalize_persian_text` before matching, because ingestion letter-folds
|
||||||
|
content and an unfolded Arabic-keyboard query would return an empty result set
|
||||||
|
silently rather than erroring (ADR-0002).
|
||||||
|
|
||||||
|
Also worth knowing before touching the points tests: `tests/support/point_contract.py`
|
||||||
|
holds **one** scenario suite run against both `FakePointRepository` (unit) and
|
||||||
|
`QdrantPointRepository` (integration), so new repository behaviour belongs there
|
||||||
|
rather than in one of the two runners — that is what keeps the fake from drifting
|
||||||
|
more permissive than the real store.
|
||||||
|
|
||||||
|
Not built yet: plan 002 Phases 3-6 — soft delete with neighbour relinking,
|
||||||
|
create/replace/patch, reorder and batch, and the
|
||||||
|
`api_request_logs`/`point_audit_events` tables — and `src/agent/`.
|
||||||
|
|
||||||
Architecture decisions live in `docs/adr/` (18 ADRs plus the 0000 template;
|
Architecture decisions live in `docs/adr/` (18 ADRs plus the 0000 template;
|
||||||
0001–0004 are `Accepted` — 0004 amended by 0018; 0014 is `Superseded by 0017`;
|
0001–0004 are `Accepted` — 0004 amended by 0018; 0014 is `Superseded by 0017`;
|
||||||
|
|||||||
Reference in New Issue
Block a user