KB public reader tier, scoped reconcile
Epic 5159 — Jarvis Website Product Assistant. Original requirement (verbatim): "Analyze viability of exposing Jarvis on our website to help with the product, present user with proposal and build it if accepted." The proposal was ACCEPTED (PRD D9). Full requirements: Task 5160's `prd` artifact. Design: Task 5161's `architecture` artifact. Read both with `task_read`/`task_read_artifact`. Its §4 contracts are pinned: build exactly to them.
## Requirement (verbatim, PRD R3)
"Public audience tier. A retrieval audience that admits only `guide` and the new marketing corpus. It MUST exclude `docs` (operator) and `web` (console comments) whatever the model asks. The filter stays single-homed with the existing audience gate."
## Build (architecture §4.1, §4.2; component K1)
- `support_kb/corpus.py`: `SOURCE_SITE = "site"`. These are crawled jaah.ai pages, audience "everyone".
- `support_kb/search.py`, the single home of the audience gate:
- `class Reader(str, Enum)` with three tiers:
- `OPERATOR`: every source except `site`;
- `TENANT`: audience == everyone AND source != site;
- `PUBLIC`: source IN (guide, site) only.
- The signature becomes `search(session, embedder, query, *, operator=False, reader=None, limit=LIMIT)`. `reader=None` derives OPERATOR or TENANT from `operator`, so every existing caller is unchanged.
- `support_kb/index.py`:
- `IMAGE_SOURCES = frozenset({"guide","docs","web"})`;
- `reconcile(session, embedder, chunks, *, sources=IMAGE_SOURCES)` reads, keeps and deletes ONLY rows whose source is in `sources`;
- a chunk whose source is outside `sources` raises `ValueError`.
- The image-build pass keeps the default.
- `support_agent/tools.py::_search_docs` stays UNTOUCHED.
- Update the single-home docstring in `support_kb/__init__.py` to name the `site` source, the three reader tiers and the scoped reconcile.
## Acceptance (verbatim, PRD AC3 retrieval half)
"KB retrieval for the public audience never returns a `docs` or `web` chunk (seeded test fixture with one chunk per corpus)."
Out of scope:
- N1 "Do NOT change signed-in, in-console Jarvis behaviour, tools, prompt, limits or UI. Existing support-agent tests must stay green unchanged."
- N3 "Do NOT widen the `everyone` audience to anonymous visitors. The `web` corpus stays console-only, and operator `docs` stays operator-only."
- Also out: no crawler, no cron, no public route or tools, no change to which files the image corpus reads.
Done means:
- Tiers. A seeded fixture with one chunk per source (guide, docs, web, site) is searched under every `Reader`:
- PUBLIC returns exactly {guide, site};
- OPERATOR returns {guide, docs, web} and never site;
- TENANT returns only everyone-audience chunks and never site.
Cite the pytest output.
- Scoped reconcile:
- `reconcile(..., sources=frozenset({"site"}))` leaves guide/docs/web rows byte-identical;
- a default reconcile leaves site rows intact;
- a chunk with a source outside `sources` raises `ValueError`.
Cite the pytest output.
- `tests/support_kb/test_index_search.py` and `tests/support_agent/` pass with NO edits. `git diff origin/develop --stat` shows neither path.
- `./dc check full` is green.
Outcome
Reader tiers (OPERATOR/TENANT/PUBLIC) + source-scoped reconcile shipped; full gate green; PR #4542 merged. Deviation: default reconcile scope = all but `site` (not a fixed IMAGE_SOURCES list) so the unedited existing tests pass.
Artifacts
Activity
- Draft
- Ready
- Runner started
- Runner ended (done)