feat(api): wire extractCommitments into the live digest (#475)#500
Merged
Conversation
Surface the user's OWN stated commitments ("I'll send the draft tomorrow")
from authored content (sent mail, calendar descriptions, voice notes) as
first-class to-dos in the daily digest.
`extractCommitments` was built + tested in
packages/decision-engine/src/commitment-extractor.ts under #484 but never
consumed in the live path. buildLiveDigest now runs it over every decision
whose underlying signal the user authored (SignalText.authoredByUser) and
turns each distinct commitment into a to-do DigestItem.
Each commitment to-do:
- carries ActionProvenance = user_originated (highest trust)
- gets an ExplanationRecord citing the user's verbatim sentence (rawSpan)
(safety invariant #2)
- forwards the raw deadlineHint when present
- uses a synthetic unique ref (<decisionId>#commit-N) so it never collides
with the decision's own digest item
Security boundary holds (safety invariant #8): extractCommitments gates on
authoredByUser AND the capability x source matrix, so inbound "you agreed to
X" content is never read for commitments. Restated commitments collapse to
one to-do. Extraction is on by default, pure-when-off behind the rollback
flag COMMITMENT_EXTRACTION=off, and any extractor throw is caught so it can
never break the digest.
Tests: 4 new live-digest integration cases — happy path (two commitments ->
two from-you to-dos with citation + deadline hint), gating fallback
(identical phrasing on inbound content -> no to-do), same-body restatement
dedup, and the rollback flag. All 12 live-digest tests pass; the file
type-checks clean against the @Skytwin source chain.
Closes #475
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR wires the existing extractCommitments rule extractor into the API’s live-digest generation so that commitments explicitly stated by the user in authored content (e.g., sent email / authored calendar descriptions / voice notes) appear as first-class digest to-dos, with “from you” provenance and source-sentence citation.
Changes:
- Invoke
extractCommitments(signalText)duringbuildLiveDigestfor user-authored signals and emit one digest to-do per distinct commitment, with synthetic refs (<decisionId>#commit-N) and power-view detail. - Add a rollback flag (
COMMITMENT_EXTRACTION=off) that disables commitment extraction and prevents extractor invocation. - Add four integration tests covering: happy path, inbound gating, same-body dedup, and rollback behavior; update changelog entry.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| CHANGELOG.md | Documents commitment to-dos being wired into the live digest path and lists behavior guarantees/rollback flag. |
| apps/api/src/services/live-digest.ts | Generates commitment-based to-dos from authored SignalText and attaches power-view detail; adds env-flag gate. |
| apps/api/src/tests/live-digest.test.ts | Adds integration coverage for commitment to-dos, authored-only gating, dedup behavior, and rollback flag. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
417
to
419
| }); | ||
|
|
||
| // Coverage for the power-view panel, from the user's connected accounts. |
This was referenced Jun 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Wires the previously-unconsumed
extractCommitmentsrule extractor (built + tested inpackages/decision-engine/src/commitment-extractor.tsunder #484) into the live digest path, so the user's OWN stated commitments surface as to-dos.apps/api/src/services/live-digest.ts(buildLiveDigest) now, for every decision whose underlying signal the user authored (SignalText.authoredByUser), runsextractCommitments(signalText)and turns each distinct commitment into a to-doDigestItem. A phrasing like "I'll send over the draft tomorrow" in a sent email becomes a first-class to-do.Each commitment to-do:
ActionProvenance = user_originated(highest trust) in its power-view detailrawSpan) — safety invariant Make SkyTwin usable by a non-technical person end-to-end #2deadlineHintwhen present (nullotherwise)<decisionId>#commit-Nso it never collides with the decision's own digest itemSecurity boundary holds (safety invariant #8):
extractCommitmentsitself gates onauthoredByUserAND the capability×source matrix, so inbound "you agreed to X" content (a poisoning vector) is never read for commitments. Provenance is never weakened to a default. Restated commitments collapse to one to-do. Extraction is on by default and pure-when-off behind the issue's rollback flagCOMMITMENT_EXTRACTION=off; any extractor throw is caught so it can never break the digest.Acceptance criteria
Commitmentobjects with non-emptyrawSpan) — covered by the extractor's own tests + the new happy-path integration test (two commitment to-dos, each with a body/citation).[]) — new integration test: identical phrasing oninbox_personalcontent yields no to-do.user_originated+ExplanationRecordciting the source sentence) — asserted in the happy-path test (provenanceLabelfrom-you, explanation cites the user's words).extractCommitmentsruns the rule path by default; no LLM is involved.deadlineHintcarries the raw temporal phrase /null) — asserted (deadline === 'tomorrow').Tests added
Four new integration cases in
apps/api/src/__tests__/live-digest.test.ts:COMMITMENT_EXTRACTION=off→ no commitment to-dos (rollback flag)Verification
Run in an isolated worktree (no install/build permitted) using a source-alias vitest config and source-path
tsc:live-digest.test.ts: 12/12 pass (8 prior + 4 new)commitment-extractor.test.ts(decision-engine): 10/10 passtsc --noEmitonlive-digest.tsagainst the@skytwin/*source chain: 0 type errorsCloses #475
🤖 Generated with Claude Code