CedarCopilot wants to merge 2 commits into staging from fix/preserve-email-links
Live on prod since Wed, 1 of 4 behaviors working
The deployed search-semantic path produced 33 concrete post-deploy search-turbopuffer executions with successful result logs (Found 8–30 results), but every observed input explicitly used searchType=\"vector\" and there were 0 fts calls. Thus the required exact-token/URL FTS.
Post-deploy production telemetry shows positive runtime evidence for the conversation-read behavior: 33 successful search-turbopuffer executions (23 on Aug 27, 10 on Aug 28) with no exact [search-turbopuffer] Error logs, plus 747 get invocations carrying an explicit.
Verifier did not provide positive runtime evidence tied to this intent, so Libra is keeping it inconclusive. Original assessment: In staging since 2026-08-27T02:25:22Z, telemetry shows 33 search-turbopuffer invocations and 33 corresponding completions, with 0 errors. All 33.
Unable to complete the production verification because the telemetry query found no matching OTEL spans, and the required follow-up telemetry query could not be executed in this loop.
Verification reached its 120s wall-clock budget before a tied verdict. Libra is keeping this intent verifying until the next check.
Verification reached its 120s wall-clock budget before a tied verdict. Libra is keeping this intent verifying until the next check.
internal_only
internal_only
internal_only
internal_only
Libra has verdicts on 1 of 4 tracked behaviors on prod; 3 are still being checked. Libra checks hourly for 3 days after each deploy.
Three retrieval fixes from one customer's reports. All are cases where the agent looked bad at finding things, and the cause was upstream of retrieval.
"the chat cannot retrieve basic things from previous emails e.g. links embedded in text"
htmlToAgentMarkdown maps headings, lists, tables and breaks to Markdown, then runs a catch-all <[^>]+> strip. <a href> had no case above that line, so every anchor lost its URL , before the model read the mail, and before the text was embedded for search.
That was collateral, not a decision. The catch-all exists so <img> payloads (base64 and /api/inline-image) can never reach the model , mail-sync-memory-fix Ph4. The existing test asserted the resulting behaviour rather than a requirement, so it's updated with a comment saying why.
Anchors now render [text](url), with the Ph4 guarantees intact:
data: is refused outright, since a data: href would reintroduce exactly the base64 Ph4 removed/api/inline-image stays suppressed, including as an href rather than an img srctext === href, which Gmail produces constantly) emitted once, not [url](url)Reaches every surface reading mail through this converter: message bodies, draft bodies, activity bodies, taxonomy extraction.
"Don't look verbatim, but just look at the transcript and see"
The agent searched a 90-minute call and returned quoted fragments. Search gives a top-k slice , 10-15 chunks of a ~10,000-word transcript. "What did they mean" and "what did we decide" can't be answered from a sample.
Both halves already sat one line apart in conversation-read's description: action (1) get with expandEventId is the family's wrapper over fetch-full-event-content and reads the event whole. Nothing pointed at it. Action (3) now does.
Edited on the family surface, not the granular tools , buildMasterFamilyToolset() hands the chat agents the shared FAMILY_TOOLS facade, so the granular descriptions never reach the model. Scoped to one named event deliberately: these transcripts run 19k,60k chars, so a general "prefer whole reads" rule would put hundreds of KB in a turn.
hybrid search was a silent no-opif (searchType === 'vector' || searchType === 'hybrid') { // vector leg
if (searchType === 'fts') { // BM25 leg
// TODO: Implement hybrid search (vector + FTS with fusion) if needed in the future
hybrid ran vector and nothing else , while the enum offered it and its description promised "combines both." An agent reaching for keyword matching silently got pure semantic search.
Removed from the tool enum (no caller passes it). The service type and branch stay, so the seam remains for whoever implements the fusion. The two real modes now say when each is right rather than just what they are: vectors for meaning, fts for a string that must appear verbatim , an order number, a URL, a name , because vectors blur exactly those.
pnpm --filter @zero/server run types cleanpnpm deps:check clean (1572 modules)html-to-agent-markdown 21 tests (was 14), covering every new rule: data-URI refusal, inline-image suppression as an href, the 400-char cap, autolink dedup, image-in-link, links inside list itemshybrid enum or the old descriptionRe-embedding existing mail. Fix 1 only helps new content until a backfill runs; backfill-workflow.ts exists if you want it.
🤖 Generated with Claude Code
Libra has not measured any production surfaces for this change yet.