KB public reader tier, scoped reconcile

Task 5164 · Done · Coder · created · updated

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.

Pull request

Artifacts

Activity

  • Draft
  • Ready
  • Runner started
  • Runner ended (done)