Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

fix(drafter): make the post-meeting notification fire, and reach the fleet

merged#2667CedarCopilot

CedarCopilot wants to merge 2 commits into staging from fix/drafter-post-meeting-notify

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Sep 2, 2026, 4:07 PM
  2. Sep 2, 2026, 5:06 PM
  3. Live on staging
    Sep 2, 2026, 5:16 PM
  4. Pipelines steady after this deploy
    Sep 2, 2026, 5:16 PM
  5. Merged
    Sep 2, 2026, 5:16 PM
  6. Live on prod
    Sep 2, 2026, 5:16 PM
  7. Observed 19 hours
    Sep 2, 2026, 5:16 PM
  8. Unobserved

    Live on prod, no production signal yet

    Sep 2, 2026, 5:16 PM
  9. Pipelines steady after this deploy
    Sep 2, 2026, 5:16 PM

Behaviors Libra is checking

After saving a post-meeting draft, the drafter must finish with exactly one notify-user call before its execution summary so the user knows the draft is ready.Degradedhigh confidence

Since deploy, telemetry shows 84 runs with notify-user logging: 75 runs had exactly one call, but 9 runs had duplicates (6 runs with 2 calls, 2 with 3, and 1 with 4), totaling 97 calls. This violates the exactly-one requirement; duplicate calls are tied to concrete execution.

staging, checked Sep 5, 2026, 4:47 PM
When the drafter decides not to create a draft, it must state that outcome and send no notification, task, or field-update substitute.Degradedlow confidence

Unable to complete verification because the available telemetry query returned no drafter spans and the runtime identifier mapping was not finished.

staging, checked Sep 5, 2026, 4:49 PM
Post-meeting email notifications must omit the draft body while Slack notifications must include the full draft under a Draft heading with ampersands, angle brackets, and greater-than signs escaped.Inconclusivelow confidence

Verification reached its budget before a verdict.

staging, checked Sep 3, 2026, 6:43 PM
Operators can run the notify backfill to add or update the post-meeting notification and corrected skip-notice regions in already-created drafter documents without requiring the document-creation rollout to run again.Inconclusivehigh confidence

No production execution evidence for `pnpm tsx scripts/backfill-drafter.ts notify` was found in staging after 2026-09-03T00:16:57Z. CloudWatch returned 0 matches for `drafterNotifyPatch`, `backfill-drafter`, `drafter-notify`, post-meeting notification terms, and exact report.

staging, checked Sep 3, 2026, 6:45 PM
A fleet-wide notify apply is refused unless the operator explicitly supplies the fleet-wide acknowledgement, preventing the post-meeting message from being re-enabled for every account accidentally.Inconclusivehigh confidence

In staging, since 2026-09-03T00:16:57Z, CloudWatch returned 0 rows for backfill-drafter, drafterNotifyPatch, acknowledgeFleetWideActivation, and fleet-wide signals, and OTEL returned 0 matching spans for drafter routes/operations/attributes. There is therefore no positive.

staging, checked Sep 3, 2026, 7:43 PM
Applying a notification patch writes through the guarded authorSubagentDoc patch path, preserves existing frontmatter and agent_id references, and refuses success if the operation creates a new document.Inconclusivelow confidence

Verification reached its 120s wall-clock budget before a tied verdict. Libra is keeping this intent verifying until the next check.

staging, checked Sep 3, 2026, 7:45 PM

Failures attributed to this change

No prod customers are affected while this is only in staging. If promoted, prod impact is unknown because Libra still needs a concrete exception, route, and failed user action before assigning severity. 1 hit · no retained affected-user count · no retained trace sample.Introducedmedium confidence

internal_only

staging, first seen Sep 2, 2026, 7:41 PM
No prod customers are affected while this is only in staging. If promoted, prod impact is unknown because Libra still needs a concrete exception, route, and failed user action before assigning severity. 1 hit · no retained affected-user count · no retained trace sample.Introducedmedium confidence

internal_only

staging, first seen Sep 2, 2026, 7:55 PM
No prod customers are affected while this is only in staging. If promoted, prod impact is unknown because Libra still needs a concrete exception, route, and failed user action before assigning severity. 1 hit · no retained affected-user count · no retained trace sample.Introducedmedium confidence

internal_only

staging, first seen Sep 2, 2026, 11:26 PM
No prod customers are affected while this is only in staging. If promoted, prod impact is unknown because Libra still needs a concrete exception, route, and failed user action before assigning severity. 1 hit · no retained affected-user count · no retained trace sample.Introducedmedium confidence

internal_only

staging, first seen Sep 3, 2026, 3:55 AM
No prod customers are affected while this is only in staging. If promoted, prod impact is unknown because Libra still needs a concrete exception, route, and failed user action before assigning severity. 1 hit · no retained affected-user count · no retained trace sample.Introducedmedium confidence

internal_only

staging, first seen Sep 3, 2026, 3:56 AM
No prod customers are affected while this is only in staging. If promoted, prod impact is unknown because Libra still needs a concrete exception, route, and failed user action before assigning severity. 2 hits · no retained affected-user count · no retained trace sample.Introducedmedium confidence

internal_only

staging, first seen Sep 3, 2026, 7:11 AM
No prod customers are affected while this is only in staging. If promoted, prod impact is unknown because Libra still needs a concrete exception, route, and failed user action before assigning severity. 0 hits · no retained affected-user count · no retained trace sample.Introducedmedium confidence

internal_only

staging, first seen Sep 3, 2026, 9:41 AM
No prod customers are affected while this is only in staging. If promoted, prod impact is unknown because Libra still needs a concrete exception, route, and failed user action before assigning severity. 2 hits · no retained affected-user count · no retained trace sample.Introducedmedium confidence

internal_only

staging, first seen Sep 3, 2026, 9:41 AM

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

PR #2664 moved the post-meeting draft notification off a hardcoded programmatic DM onto a notify-user call driven by prose in each user's subagents/drafter.md. Two defects followed it, and neither fix reaches anyone without the third change here.

Rebased onto staging after #2648 (drafter Stage 5) and #2645 landed. What that changed is at the bottom, under Rebase notes , including a live dry run that caught a real defect in this branch.

1. The notification fired ~36% of the time

The deleted code fired on inputData.taskType === 'post-meeting' , 100% deterministically. The shipped prose notified on 2/8 and 3/6 post-meeting runs across two runs of the eval harness at apps/server/.claude/skills/playbook-instruction-eval/, while drafting on 8/8. Two structural causes:

The document contradicted itself. The mandatory preamble ended with a bullet telling the model not to compensate for a skip by "notifying the user that you decided not to write", while the closing section told it to send exactly one notification. A model reading both resolves it the cheap way and sends nothing. That single paragraph is the whole of the first fix, and on its own it moved the measured rate 2/8 → 5/8, negatives unchanged (scheduled-task 0/8, inbound-email 0/8), drafting still 8/8.

The notification read as an afterthought. ## Telling the user the recap is waiting, placed after "What is not yours", says what to send but never that the run is unfinished without it. agent-defaults/daily-agenda.ts gets reliable delivery from the opposite framing , it names the notification "Stage E , Tell the user" and says "Finish with one notify-user call". The section is now ## Last step , tell the user and opens by saying a post-meeting run has two outputs.

A stronger "MANDATORY + ordered tool sequence" variant was measured and rejected: it raised the rate but produced duplicate notifications and runs that never drafted at all. That approach is not reintroduced here, and the constant's docblock records why so the next person does not try it again.

2. The Slack notification lost the draft body

formatPostMeetingDraftMessage, deleted by #2664, was asymmetric on purpose , its own comment: // Slack draft notification , include commentary and full draft body so the user can read it verbatim in the DM. It rendered *Draft:*\n${escapedDraft} with &, <, > escaped and linked to CedarRoute.PipelineConversation (the deal, not a thread); the email variant deliberately omitted the body. The migration flattened that to "Not the draft itself" for both channels, which removed the one case where the notification IS the product: a Slack message short enough to approve on sight without opening anything.

The section is channel-specific again , email says do NOT include the body, Slack says DO, verbatim, under a *Draft:* heading, with &/</> escaped, linking to the deal and the destination channel.

3. The fix could not reach the fleet , a patch mode for the backfill

Verified read-only against production, dry run, on the current branch: every drafter.md in the active cohort already exists (57 playbooks / 57 users) and NOT ONE contains a notification section. Post-meeting notifications are off fleet-wide. backfill-drafter.ts document cannot turn them on: seedFile short-circuits on an existing document, which is exactly what preserves user edits.

A --force flag would fix that by overwriting the body. That is the wrong trade twice over , these are documents people have edited, not identical seed copies; and an overwrite leaves nothing afterwards that can say what was there.

So: a third subcommand, backfill-drafter.ts notify, which patches two named regions in place and leaves every other byte alone.

pnpm tsx scripts/backfill-drafter.ts notify --all                       # survey
pnpm tsx scripts/backfill-drafter.ts notify --email <email> --apply # write

Same scoping as the other two subco

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/scripts/backfill-drafter.tsno production surface mapped
  • apps/server/src/services/playbook/agent-defaults/drafter.tsno production surface mapped
  • apps/server/src/services/playbook/agent-defaults/index.tsno production surface mapped
  • apps/server/src/services/playbook/backfill/__tests__/drafter-migration.test.tsno production surface mapped
  • apps/server/src/services/playbook/backfill/__tests__/drafter-notify-patch.test.tsno production surface mapped
  • apps/server/src/services/playbook/backfill/drafter-migration.tsno production surface mapped
  • apps/server/src/services/playbook/backfill/drafter-notify-patch.tsno production surface mapped
  • apps/server/src/services/playbook/backfill/drafter-notify-prior.tsno production surface mapped
  • apps/server/src/services/playbook/backfill/prose-compare.tsno production surface mapped