1- import type { ConversationStateSnapshot , TimeSpec } from "@atlas/core" ;
1+ import type {
2+ ConversationStateSnapshot ,
3+ PendingWriteOperation ,
4+ TimeSpec ,
5+ } from "@atlas/core" ;
26import type { ProcessedInboxResult } from "@atlas/db" ;
37import { describe , expect , it } from "vitest" ;
48
59function t ( hour : number , minute : number ) : TimeSpec {
610 return { kind : "absolute" , hour, minute } ;
711}
812
13+ function buildPendingWriteOperation (
14+ overrides ?: Partial < PendingWriteOperation > ,
15+ ) : PendingWriteOperation {
16+ return {
17+ operationKind : "plan" ,
18+ targetRef : null ,
19+ resolvedFields : { } ,
20+ missingFields : [ ] ,
21+ originatingText : "schedule gym tomorrow" ,
22+ startedAt : "2026-03-22T16:00:00.000Z" ,
23+ ...overrides ,
24+ } ;
25+ }
26+
927import {
1028 deriveConversationReplyState ,
1129 deriveMutationState ,
@@ -41,15 +59,14 @@ describe("deriveConversationReplyState", () => {
4159 snapshot : buildSnapshot ( ) ,
4260 policy : {
4361 action : "ask_clarification" ,
44- clarificationSlots : [ "time" ] ,
45- committedSlots : { } ,
62+ clarificationSlots : [ "scheduleFields.time" ] ,
4663 } ,
4764 interpretation : {
4865 turnType : "planning_request" ,
4966 confidence : 0.58 ,
5067 resolvedEntityIds : [ ] ,
5168 ambiguity : "high" ,
52- missingSlots : [ "time" ] ,
69+ missingFields : [ "scheduleFields. time" ] ,
5370 } ,
5471 reply : "What time should I schedule the Malaysia trip planning?" ,
5572 userTurnText : "schedule malaysia trip planning tomorrow" ,
@@ -62,12 +79,12 @@ describe("deriveConversationReplyState", () => {
6279 kind : "clarification" ,
6380 status : "active" ,
6481 data : {
65- reason : "time" ,
82+ reason : "scheduleFields. time" ,
6683 } ,
6784 } ) ;
6885 expect ( result . discourseState ?. pending_clarifications ) . toEqual ( [
6986 expect . objectContaining ( {
70- slot : "time" ,
87+ slot : "scheduleFields. time" ,
7188 status : "pending" ,
7289 } ) ,
7390 ] ) ;
@@ -80,7 +97,6 @@ describe("deriveConversationReplyState", () => {
8097 policy : {
8198 action : "ask_clarification" ,
8299 clarificationSlots : [ "proposal" ] ,
83- committedSlots : { } ,
84100 } ,
85101 interpretation : {
86102 turnType : "confirmation" ,
@@ -104,14 +120,13 @@ describe("deriveConversationReplyState", () => {
104120 snapshot : buildSnapshot ( ) ,
105121 policy : {
106122 action : "ask_clarification" ,
107- committedSlots : { } ,
108123 } ,
109124 interpretation : {
110125 turnType : "unknown" ,
111126 confidence : 0.42 ,
112127 resolvedEntityIds : [ ] ,
113128 ambiguity : "high" ,
114- missingSlots : [ "unknown" ] ,
129+ missingFields : [ "unknown" ] ,
115130 } ,
116131 reply : "Can you clarify what you want me to change?" ,
117132 userTurnText : "do it" ,
@@ -165,7 +180,6 @@ describe("deriveConversationReplyState", () => {
165180 snapshot,
166181 policy : {
167182 action : "present_proposal" ,
168- committedSlots : { } ,
169183 } ,
170184 interpretation : {
171185 turnType : "clarification_answer" ,
@@ -197,47 +211,40 @@ describe("deriveConversationReplyState", () => {
197211 expect ( result . discourseState ?. mode ) . toBe ( "confirming" ) ;
198212 } ) ;
199213
200- it ( "persists pending_write_contract when resolvedContract is provided" , ( ) => {
201- const contract = {
202- requiredSlots : [ "day" , "time" ] as (
203- | "day"
204- | "time"
205- | "duration"
206- | "target"
207- ) [ ] ,
208- intentKind : "plan" as const ,
209- } ;
214+ it ( "persists pending_write_operation when resolvedOperation is provided" , ( ) => {
215+ const op = buildPendingWriteOperation ( {
216+ resolvedFields : { scheduleFields : { day : "tomorrow" } } ,
217+ missingFields : [ "scheduleFields.time" ] ,
218+ } ) ;
210219
211220 const result = deriveConversationReplyState ( {
212221 snapshot : buildSnapshot ( ) ,
213222 policy : {
214223 action : "ask_clarification" ,
215- clarificationSlots : [ "time" ] ,
216- committedSlots : { day : "tomorrow" } ,
217- resolvedContract : contract ,
224+ clarificationSlots : [ "scheduleFields.time" ] ,
225+ resolvedOperation : op ,
218226 } ,
219227 interpretation : {
220228 turnType : "planning_request" ,
221229 confidence : 0.58 ,
222230 resolvedEntityIds : [ ] ,
223231 ambiguity : "high" ,
224- missingSlots : [ "time" ] ,
232+ missingFields : [ "scheduleFields. time" ] ,
225233 } ,
226234 reply : "What time should I schedule it?" ,
227235 userTurnText : "schedule gym tomorrow" ,
228236 summaryText : null ,
229237 occurredAt : "2026-03-22T16:05:00.000Z" ,
230238 } ) ;
231239
232- expect ( result . discourseState ?. pending_write_contract ) . toEqual ( contract ) ;
240+ expect ( result . discourseState ?. pending_write_operation ) . toEqual ( op ) ;
233241 } ) ;
234242
235- it ( "does not set pending_write_contract when resolvedContract is absent" , ( ) => {
243+ it ( "does not set pending_write_operation when resolvedOperation is absent" , ( ) => {
236244 const result = deriveConversationReplyState ( {
237245 snapshot : buildSnapshot ( ) ,
238246 policy : {
239247 action : "reply_only" ,
240- committedSlots : { } ,
241248 } ,
242249 interpretation : {
243250 turnType : "informational" ,
@@ -251,7 +258,7 @@ describe("deriveConversationReplyState", () => {
251258 occurredAt : "2026-03-22T16:05:00.000Z" ,
252259 } ) ;
253260
254- expect ( result . discourseState ?. pending_write_contract ) . toBeUndefined ( ) ;
261+ expect ( result . discourseState ?. pending_write_operation ) . toBeUndefined ( ) ;
255262 } ) ;
256263
257264 it ( "clears active clarifications when a clarification_answer resolves all slots" , ( ) => {
@@ -294,7 +301,12 @@ describe("deriveConversationReplyState", () => {
294301 snapshot,
295302 policy : {
296303 action : "present_proposal" ,
297- committedSlots : { day : "tomorrow" , time : t ( 17 , 0 ) } ,
304+ resolvedOperation : buildPendingWriteOperation ( {
305+ resolvedFields : {
306+ scheduleFields : { day : "tomorrow" , time : t ( 17 , 0 ) } ,
307+ } ,
308+ missingFields : [ ] ,
309+ } ) ,
298310 } ,
299311 interpretation : {
300312 turnType : "clarification_answer" ,
@@ -428,15 +440,13 @@ describe("deriveMutationState", () => {
428440 expect ( result . discourseState . mode ) . toBe ( "editing" ) ;
429441 } ) ;
430442
431- it ( "clears resolved_slots and pending_write_contract on successful mutation" , ( ) => {
443+ it ( "clears pending_write_operation on successful mutation" , ( ) => {
432444 const snapshot = buildSnapshot ( ) ;
433445 snapshot . discourseState = {
434446 ...snapshot . discourseState ! ,
435- resolved_slots : { day : "tomorrow" , time : t ( 17 , 0 ) } ,
436- pending_write_contract : {
437- requiredSlots : [ "day" , "time" ] ,
438- intentKind : "plan" ,
439- } ,
447+ pending_write_operation : buildPendingWriteOperation ( {
448+ resolvedFields : { scheduleFields : { day : "tomorrow" , time : t ( 17 , 0 ) } } ,
449+ } ) ,
440450 } ;
441451
442452 const processing : ProcessedInboxResult = {
@@ -504,19 +514,18 @@ describe("deriveMutationState", () => {
504514 occurredAt : "2026-03-22T16:10:00.000Z" ,
505515 } ) ;
506516
507- expect ( result . discourseState . resolved_slots ) . toEqual ( { } ) ;
508- expect ( result . discourseState . pending_write_contract ) . toBeUndefined ( ) ;
517+ expect ( result . discourseState . pending_write_operation ) . toBeUndefined ( ) ;
509518 } ) ;
510519
511- it ( "preserves resolved_slots and pending_write_contract on needs_clarification" , ( ) => {
520+ it ( "preserves pending_write_operation on needs_clarification" , ( ) => {
521+ const op = buildPendingWriteOperation ( {
522+ resolvedFields : { scheduleFields : { day : "tomorrow" } } ,
523+ missingFields : [ "scheduleFields.time" ] ,
524+ } ) ;
512525 const snapshot = buildSnapshot ( ) ;
513526 snapshot . discourseState = {
514527 ...snapshot . discourseState ! ,
515- resolved_slots : { day : "tomorrow" } ,
516- pending_write_contract : {
517- requiredSlots : [ "day" , "time" ] ,
518- intentKind : "plan" ,
519- } ,
528+ pending_write_operation : op ,
520529 } ;
521530
522531 const processing : ProcessedInboxResult = {
@@ -549,10 +558,6 @@ describe("deriveMutationState", () => {
549558 occurredAt : "2026-03-22T16:10:00.000Z" ,
550559 } ) ;
551560
552- expect ( result . discourseState . resolved_slots ) . toEqual ( { day : "tomorrow" } ) ;
553- expect ( result . discourseState . pending_write_contract ) . toEqual ( {
554- requiredSlots : [ "day" , "time" ] ,
555- intentKind : "plan" ,
556- } ) ;
561+ expect ( result . discourseState . pending_write_operation ) . toEqual ( op ) ;
557562 } ) ;
558563} ) ;
0 commit comments