ADR 0021 — Re-author mosaic-pages as tessera.yaml
The mosaic-pages app (pages.tessera) is written in the legacy .tessera
text format, which the CLI no longer loads (ADR 0008: YAML is canonical;
mosaic-cli rejects the legacy format). This ADR re-authors the app as
tessera.yaml, using the features P5–P7 just landed so the port doubles as
their first real-world consumer.
Context
pages.tessera(Sep 26) predates the YAML migration and the knowledge RAG work: itsvectordb docsis inline-docs-only (three seeded texts), its chat is a workflow search node, and its deploy story doesn't exist (nodeploys— the tessera has no deploy specs at all).- The README documents three known workarounds from that era: a disabled
@envapi-key binding (codegen bug, since fixed), a post-render patch adding missing web-crate deps (fixed), and the note that published docs don't reach the RAG index (still true — there is no upsert-to-vectordb DSL; documented, not solved). - P5 (ADR 0018) gave
vector_dbs[]retrieval/chunk config + source-scoped search; P6 (ADR 0019) made re-indexing delta per source; P7 (ADR 0020) gave deploy specshost/ingress_class/proxy_bufferingand the appcontent_root.
Decision
Rewrite mosaic-pages as tessera.yaml (dropping pages.tessera), keeping
the same app shape — the Doc aggregate, the RBAC policy, the SSO identity,
the ask-docs workflow, the operator guide — and adding what the legacy
tessera lacked:
- Knowledge sources, the ee-pages way.
vectordb docsgets real sources alongside the inline docs:- a
books/folder (kindauto— epub/docx get the chapter model, pdfs the page model), - a git source (K8: a committed git bundle, CI-hermetic),
- a data-URI source (ADR 0015:
memory://docs-remote, proving the OpenDAL seam — empty on a fresh boot, fail-soft), retrieval: {mode: hybrid, top_k: 5}andchunk: {chars: 2000, overlap: 200}(P5 — the ee-pages defaults),strategy: {books: true}explicit. Source-scoped search is e2e-proven: a search restricted to the git source's label finds that source's text and nothing else (and an unknown label returns empty).
- a
content_root: true(P7): the portal root belongs to the content — the web lens emits no root route; the UI keeps its other pages as a hidden entry point.- A deploy spec (ADR 0010 + P7):
deploys: [{name: prod, target: k8s, host: pages.example.com, ingress_class: nginx, proxy_buffering: off}]— the chart gains the ingress with the SSE annotation (the workflow run endpoint streams over?stream=true). - e2e: the legacy four scenarios (health/publish/list/get) plus token-scoped authz (viewer 403 / owner 200 on publish — the permission gate the README showcases) and the source-scoped search scenarios.
The api_key part-config env binding is restored (the codegen bug the
README worked around is gone) and the README is rewritten for the YAML
format (no more post-render patch).
Consequences
mosaic-pagesbecomes loadable and e2e-green again;out/stays git-ignored and regenerable.- The knowledge corpus (
books/, the git bundle) is committed to the app repo — the same posture asexamples/full-stack/knowledge/. - The upsert-to-vectordb gap (published docs don't reach the RAG index at runtime) remains; it is a DSL feature request, tracked separately.
- The legacy
pages.tesserais deleted, not kept (the CLI cannot read it; keeping it would be dead weight that drifts).