Provenance/claims carried created_by/verified_by as {type,id} principal
refs from the service, but the types said string|null and ProvenancePanel
rendered them raw → React #31 crash on every object view. Widen to
string|PrincipalRef|null and add formatPrincipal() (barrel-exported).
Badges: mode-aware semantic tones (mix toward --foreground) so success/
warning/info/danger text clears WCAG AA on the subtle tint in BOTH light
and dark; Active badge 2.81→5.25/5.67:1. SensitivityBadge renders nothing
for an unset level (objects inherit from their collection) instead of a
misleading "—" pill. TierBadge tolerates an unknown tier.
Accessibility: Badge gains ariaLabel (screen readers announce the meaning,
not just the terse label); Field links label↔control via htmlFor + useId
and wires aria-describedby to the hint; OwnerToggle gets aria-pressed;
icons aria-hidden.
First-run: CollectionForm leads with Name and auto-derives the Identifier
(was slug-first); placeholder text uses --muted-foreground. Drop the
Sparkles "AI-magic" icons from the review empty state and the agent tier
badge (Inbox / Bot instead), per the no-magic-framing principle.
Verified live on dev-knowledge.sky-ai.com.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The curation base for a per-person gated `memory` collection of FREE-TEXT notes
(kind: note), distinct from ClaimsReviewQueue's subject·predicate·value triples.
Groups proposed (specialist-noted, awaiting confirmation) vs remembered (active),
with confirm/forget callbacks, source attribution, and tags — matching the KB UI
house style. Collection-agnostic (props in, callbacks out): the same base powers
the KB `memory` collection and a consumer's /memory page.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A kb.list row can arrive without a sensitivity (a claim/note, or older data);
SENSITIVITY[level] was then undefined and reading .tone crashed the whole
object list. Fall back to a neutral badge — never defaulting an unknown value
to "Open", which would misstate exposure. (Surfaced building the standalone
webapp against a real corpus.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both consumers (embedded + the coming standalone) need the same search UI and
paginated lists; keep them from diverging by owning both here.
- KnowledgeSearch (components-search.tsx): the search input + paginated results
panel, over an injected onSearch. Owns query/results/loading/error/clear and a
"Load more" for search results; renders the caller's `browse` content when
there is no active search. Replaces each app hand-rolling hit rendering.
- CollectionList: onLoadMore/hasMore/loadingMore (mirrors ObjectList), so a
paginated corpus list gets a load-more affordance.
Stacked on fix/kb-ui-p0 (ObjectList already gained load-more there). tsc clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- TextReader: monotonic request guard (stale slice can't clobber current) +
catch with a retry surface instead of a blank panel / unhandled rejection;
Read-more guarded and shows loading.
- OutlineNav: an explicit section selection now wins over the initial citation
highlight, so clicking sections works on ?start=&end= views (was inert).
- ObjectViewer: reset section + image on object switch (no bleed across
citation navigation); catch the blob resolve.
- ObjectList: optional onLoadMore/hasMore/loadingMore (paginated corpuses).
- ClaimsReviewQueue: catch-all "Awaiting review" bucket so a claim the queue
returned is never silently dropped (e.g. an open-conflict singleton whose
counterpart is not in the payload).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>