@@ -151,29 +151,30 @@ a user says something like "yes but make it 3pm".
151151Slot extraction runs ** only** for ` SLOT_COMMITTING_TURN_TYPES ` :
152152` planning_request ` , ` edit_request ` , ` clarification_answer ` .
153153
154- Before calling the LLM, ` derivePendingSlots ()` computes which required slots
155- are still missing from the current ` WriteContract ` :
154+ Before calling the LLM, ` requiredSlotsForOperation ()` computes which schedule
155+ fields are still missing given the current ` operationKind ` :
156156
157- - ** ` DEFAULT_WRITE_CONTRACT ` ** (plan intent): requires ` ["day", "time"] `
158- - ** ` EDIT_CONTRACT ` ** (edit intent): requires ` ["time"] `
157+ - ** ` plan ` ** : requires ` ["day", "time"] `
158+ - ** ` edit ` / ` reschedule ` ** : requires ` ["time"] `
159+ - ** ` complete ` / ` archive ` ** : requires ` [] `
159160
160- ` resolveWriteContract ()` picks the active contract :
161- - ` planning_request ` → always ` DEFAULT_WRITE_CONTRACT `
162- - ` edit_request ` → always ` EDIT_CONTRACT `
163- - everything else → inherits ` priorContract ` from discourse state
161+ ` resolveOperationKind ()` ( ` packages/core ` ) derives the active operation :
162+ - ` planning_request ` → ` plan `
163+ - ` edit_request ` → ` edit `
164+ - everything else → inherits ` priorOperationKind ` from ` pending_write_operation `
164165
165- ** Slot types** (` ResolvedSlots ` ):
166+ ** Schedule slot types** (grouped under ` scheduleFields ` in ` ResolvedFields ` ):
166167``` ts
167168{
168- day ?: string ; // e.g. "monday", "tomorrow"
169- time ?: TimeSpec ; // absolute {hour,minute}, relative {minutes}, or window {morning|afternoon|evening}
170- duration ?: number ; // minutes
171- target ?: string ; // entity ID of the task/block being referenced
169+ day ?: string ; // e.g. "monday", "tomorrow"
170+ time ?: TimeSpec ; // absolute {hour,minute}, relative {minutes}, or window {morning|afternoon|evening}
171+ duration ?: number ; // minutes
172172}
173173```
174174
175- The slot normalizer (` packages/core/src/slot-normalizer.ts ` ) validates ranges
176- and converts raw LLM output into typed ` ResolvedSlots ` .
175+ Target entity resolution happens via ` classification.resolvedEntityIds ` , not
176+ slot extraction. The slot normalizer (` packages/core/src/slot-normalizer.ts ` )
177+ validates ranges and converts raw LLM output into typed schedule values.
177178
178179** Output:** ` { extractedValues, confidence, unresolvable } `
179180- ` confidence ` is a per-slot score (0–1)
@@ -184,29 +185,36 @@ and converts raw LLM output into typed `ResolvedSlots`.
184185** File:** ` packages/core/src/commit-policy.ts ` → ` applyCommitPolicy() `
185186
186187The commit policy is the gate between "LLM extracted something" and "the
187- system will act on it". Each extracted slot is individually evaluated:
188+ system will act on it". Each extracted schedule field is individually evaluated:
188189
189190| Condition | Result |
190191| -----------| --------|
191- | Slot is in ` unresolvable ` | → ` needsClarification ` |
192- | ` confidence[slot ] < 0.75 ` | → ` needsClarification ` |
193- | Slot corrects a prior value AND ` confidence < 0.90 ` | → ` needsClarification ` |
194- | Otherwise | → ` committedSlots ` |
192+ | Field is in ` unresolvable ` | → ` needsClarification ` |
193+ | ` confidence[field ] < 0.75 ` | → ` needsClarification ` |
194+ | Field corrects a prior value AND ` confidence < 0.90 ` | → ` needsClarification ` |
195+ | Otherwise | → ` resolvedFields.scheduleFields ` |
195196
196- The correction threshold (0.90 vs 0.75) is higher because overwriting a slot
197+ The correction threshold (0.90 vs 0.75) is higher because overwriting a field
197198the user previously confirmed carries more risk.
198199
199- ** Contract change detection:** if the new ` activeContract.intentKind ` differs
200- from ` priorContract.intentKind ` (e.g., the user switches from scheduling to
201- editing), all prior resolved slots are discarded so stale plan-slots don't
202- bleed into an edit.
200+ ** Workflow change detection:** if ` operationKind ` changed from the prior
201+ operation, or if ` currentTargetEntityId ` differs from the prior
202+ ` targetRef.entityId ` , all prior resolved schedule fields are discarded so stale
203+ fields don't bleed into a new workflow. ` workflowChanged: true ` is surfaced in
204+ the output so ` buildResolvedOperation ` can reset ` originatingText ` /` startedAt ` .
205+
206+ ** Target resolution:** ` resolvedTargetRef ` is the canonical next target —
207+ ` currentTargetEntityId ` when the classifier resolved one, otherwise carried
208+ forward from ` priorPendingWriteOperation.targetRef ` .
203209
204210** Output:** ` CommitPolicyOutput `
205211``` ts
206212{
207- committedSlots : ResolvedSlots ; // slots safe to act on
208- needsClarification : SlotKey []; // slots extracted but not confident enough
209- missingSlots : SlotKey []; // required by contract, not yet resolved
213+ resolvedFields : ResolvedFields ; // schedule fields safe to act on
214+ resolvedTargetRef : TargetRef ; // canonical target for this workflow step
215+ needsClarification : string []; // dot-path fields not confident enough (e.g. "scheduleFields.time")
216+ missingFields : string []; // required by operationKind, not yet resolved
217+ workflowChanged : boolean ; // true when operation or target switched
210218}
211219```
212220
@@ -251,9 +259,8 @@ relative to a prior proposal.
251259 targetEntityId ?: string ;
252260 targetProposalId ?: string ;
253261 mutationInputSource ?: " direct_user_turn" | " recovered_proposal" ;
254- clarificationSlots ?: string [];
255- committedSlots : ResolvedSlots ;
256- resolvedContract : WriteContract ;
262+ clarificationSlots ?: string []; // dot-path fields (e.g. "scheduleFields.time")
263+ resolvedOperation ?: PendingWriteOperation ; // set for non-reply_only turns
257264}
258265```
259266
@@ -431,7 +438,7 @@ After any branch completes, the conversation state is updated:
431438 - New pending clarification (for ` ask_clarification ` )
432439 - New proposal entity (for ` present_proposal ` )
433440 - Conversation mode update (planning → clarifying / confirming)
434- - Committed slots in ` pending_write_contract ` and ` resolved_slots `
441+ - ` pending_write_operation ` updated from ` policy.resolvedOperation ` (non- ` reply_only ` turns only)
435442
436443** Mutation branch:**
437444` deriveMutationState() ` (` apps/web/src/lib/server/conversation-state.ts ` )
@@ -480,8 +487,8 @@ computed, not stored directly — it is derived from whether there are pending
480487clarifications or presented proposals in the entity registry.
481488
482489** ` editing ` mode** is entered when an ` edit_request ` turn arrives and an
483- editable entity is present. It is structurally similar to ` planning ` but uses
484- ` EDIT_CONTRACT ` which requires only ` time ` .
490+ editable entity is present. It is structurally similar to ` planning ` but the
491+ ` edit ` operationKind requires only ` time ` .
485492
486493---
487494
@@ -502,7 +509,7 @@ slots.
502509** From:** ` applyCommitPolicy() ` → ` CommitPolicyOutput `
503510** To:** ` decideTurnPolicy() ` → ` TurnPolicyDecision `
504511
505- The policy decision reads ` missingSlots ` and ` needsClarification ` from the
512+ The policy decision reads ` missingFields ` and ` needsClarification ` from the
506513commit output to determine whether the system can proceed or must ask. It also
507514reads the entity registry to check for consent requirements.
508515
@@ -590,12 +597,14 @@ User-facing reply renderer for mutation outcomes. Converts
590597` ProcessedInboxResult ` to a human-readable message in the user's timezone.
591598
592599### ` packages/core/src/commit-policy.ts `
593- Slot gating logic. Thresholds: 0.75 (normal), 0.90 (correction). Contract
594- change detection resets prior slots. Pure function, no LLM calls.
600+ Schedule field gating logic. Thresholds: 0.75 (normal), 0.90 (correction).
601+ Operation/target change detection clears prior schedule fields and sets
602+ ` workflowChanged ` . Outputs ` resolvedTargetRef ` as the canonical next target.
603+ Pure function, no LLM calls.
595604
596605### ` packages/core/src/write-contract.ts `
597- Contract definitions and resolver. ` DEFAULT_WRITE_CONTRACT ` requires
598- ` [day, time] ` . ` EDIT_CONTRACT ` requires ` [time] ` .
606+ ` resolveOperationKind() ` — derives the active ` OperationKind ` from turn type
607+ and prior operation. Required fields per operation are owned by commit-policy .
599608
600609### ` packages/core/src/discourse-state.ts `
601610All discourse state schema types, helpers, and mode derivation. Contains
0 commit comments