Driven by siwen.ink (~13k articles): the sidebar's category view used
to download every entry on every navigation and filter client-side.
This release adds two surgical hooks on /api/articles/lite — the fast
index.json-backed slim path added in v0.6.4 — that let large-KB
deployments cut payload AND skip the round-trip per nav.
Surface:
- ?tag=<slug> server-side filter on /api/articles/lite. Filters in-memory
against index.json's tags field (no frontmatter parse), case-sensitive
exact match. Empty match returns 200 + empty list, same as
/api/articles?tag=nonexistent — lite deliberately doesn't load taxonomy
to validate tag existence (would defeat the "1 file read" promise).
Reuses the existing _normalize_tags helper so a frontmatter tag stored
as a single string (rather than a list) still matches.
- LLMBASE_LITE_CACHE_MAX_AGE env var. When set to a positive integer,
/api/articles/lite (and its 304s) emit Cache-Control: public, max-age=N
instead of the default no-cache. ETag still present so freshness past
the TTL is correct. Default 0 / unset / non-numeric → no-cache,
unchanged. Caveat: during the max-age window, sidebars lag behind a
fresh compile by up to N seconds.
Why a downstream knob, not a hardcoded 600s default change: the
existing no-cache default is shared by every KB endpoint (taxonomy,
articles, lite). A blanket switch to public+max-age would silently
change the caching contract for all callers. Env-gated keeps the safe
default for everyone except deployments that opt in.
ETag isolation: /api/articles/lite ETag now mixes the tag param via
the existing _kb_etag(extra=...) hook, so distinct slices get distinct
validators — a 304 will never serve a stale partial slice to the wrong
caller. (Same pattern /api/articles already uses for its tag/q/cursor
slices.)
Tests: +11 (lite filter narrows, unknown tag → empty 200, no-tag
preserves backwards compat, ETag distinct per tag, 304 respects tag,
default Cache-Control no-cache, env opts in to max-age, max-age
applies to 304s, invalid env falls back, zero env means no-cache,
string-tag normalizes). 175 total green. tsc clean. Python imports OK.
Codex LGTM first pass — no changes needed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>