Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

feat(playbook): flag-gated Jev AOP selection for isabelle+jesse

merged#2851CedarCopilot

CedarCopilot wants to merge 0 commits into staging from feat/jev-aop-selection

Live on prod, watching, 2 days leftTimeline and evidence
  1. Opened
    Sep 20, 2026, 4:12 PM
  2. Merged
    Sep 20, 2026, 5:54 PM
  3. Live on prod
    Sep 20, 2026, 5:54 PM
  4. Observed 0 hours
    Sep 20, 2026, 5:54 PM
  5. Watching

    Live on prod, watching, 2 days left

    Sep 20, 2026, 5:54 PM
  6. Pipelines steady after this deploy
    Sep 20, 2026, 5:54 PM

Behaviors Libra is checking

An account-only CRM association, missing integration metadata, unsupported CRM provider, or a linked deal without a resolvable Deal/Opportunity AOP does not force Deal classification and continues through normal Jev/GPT-4o selection.Not checked
prod
Deterministic CRM-deal routing prefers an explicitly object-bound Deal/Opportunity AOP and only falls back to the legacy `Deals`-named AOP when no explicit binding exists.Not checked
prod
A conversation with a real linked HubSpot, Attio, Salesforce, or Copper deal is deterministically routed to the user's Deal/Opportunity-bound AOP, overriding Jev and GPT-4o classification.Not checked
prod
The linked-deal pre-check runs before conversation-context construction and skips both Jev and GPT-4o calls when it can resolve a Deal/Opportunity AOP.Not checked
prod
Valid Jev choice keys are resolved back to real AOP IDs and names, considered AOPs are sorted by probability, unknown keys are discarded, and the selected AOP is included even when Jev omits it from its probability map.Not checked
prod
Flagged conversations are classified by Jev using the same full conversation context, user identity, candidate AOPs, and user-defined selection procedures that the existing classifier uses.Not checked
prod

Libra has verdicts on 0 of 15 tracked behaviors on prod; 15 are still being checked. Libra checks hourly for 3 days after each deploy.

What changed

Adds a second selectAopForConversation path (apps/server/src/services/aop/jev-aop-selection.ts) that routes AOP classification through TypeSafe AI's Jev "Choice" model instead of GPT-4o/Sol, gated by a new PostHog flag. Both paths return the exact same AopSelectionOutput shape, so every downstream consumer , confidence bands, the ambiguity-ping decision, logToolCall , works unchanged regardless of which model produced the result.

aop-selection.ts now tries Jev first (only when the flag is on for that user); if Jev returns a result, the GPT-4o Agent is never constructed. If Jev is off, or on but fails/times out/returns something unusable, it falls straight through to the existing GPT-4o/Sol path , unchanged from before this PR.

Why: model/quality evidence

A 60-row sample of real production MEDIUM-band classifications, replayed with the exact same full conversation context GPT-4o's own prompt is built from (formatHydratedConversationForAgent): 47.4% raw agreement between Jev and GPT-4o (n=57 reconstructable).

A rigorous 15-case manual audit of the disagreements , checked against each org's own selectionProcedure text and the real conversation content, not assumptions carried over from other orgs:

  • 11/15 favored Jev
  • 0/15 favored GPT-4o
  • 0/15 genuinely ambiguous either way
  • 4/15 unusable due to contaminated sample data (synthetic seed data in one sub-account, one Cedar-generated digest email mistaken for a real external conversation) , not a model failure
  • Zero genuine Jev errors found in the audited sample

GPT-4o showed multiple distinct real failure modes in that sample:

  • Its own reasoning field argued for one category while selectedAop named a different one (a reasoning/output self-contradiction bug)
  • Never considered the category its own criteria said should apply (a support ticket from an active customer , its own Deals definition explicitly says "prospective or active customer")
  • Factual misreads of the actual email content
  • Wrong-direction-of-sale errors

Cost

GPT-4o costs ~$214.91/month for this call site today (Understudy billing, aop-selection workload, 30-day window: 14,283 requests, ~92.6M input + 3.6M output tokens). Projected Jev cost at the same volume, using the measured real average of 3,515 input tokens/call from the full-context test, is ~$2.01/month. Not the primary motivation , accuracy is , but real.

Jev's Choice primitive has no native "abstain"

type: 'choice' forces a pick among the given options. A customer-support-ticket conversation with no good category match got a confidently-wrong pick in testing for exactly this reason. Rather than invent a synthetic "none of the above" option (which would need a real no-op AOP to route to , not every org has one), a low top-choice confidence is treated the same way GPT-4o's own LOW band already is: as the abstain signal, mapped into the SAME AOP_CONFIDENCE_BANDS thresholds already used for GPT-4o.

Fail-open semantics

AOP selection is a required step , every conversation needs one. Unlike jev-action-gate.ts (where fail-open means "skip the check, run the orchestrator as normal" is safe), a Jev failure here falls all the way back to running the existing GPT-4o/Sol agent for that call, never to "no AOP." selectAopWithJev never throws; every failure mode (HTTP error, timeout via AbortSignal.timeout(8000), malformed response, unresolvable choice, missing API key, zero candidates) returns null, and the caller treats null as "run GPT-4o."

Telemetry

Every Jev evaluation is logged via createStructuredLog under jev-aop-selection.evaluated (reaches Axiom), with outcome of selected | fallback_error | fallback_malformed_response | not_configured | no_candidates, carrying user/conversation ids and (when present) the caller's tracingContext for correlation.

Exactly how the flag is scoped

New PostHog flag cedar-aop-selection-jev (

Show production surfaces and changed-file mapping

Production surfaces

Libra has not measured any production surfaces for this change yet.

Changed files → surfaces

  • apps/server/src/mastra/utils/__tests__/aop-selection-jev-branch.test.tsno production surface mapped
  • apps/server/src/mastra/utils/aop-selection.tsno production surface mapped
  • apps/server/src/services/aop/__tests__/jev-aop-selection.test.tsno production surface mapped
  • apps/server/src/services/aop/bound-object-resolution.tsno production surface mapped
  • apps/server/src/services/aop/jev-aop-selection.tsno production surface mapped