From 1454e1be90b2042432b0c8f4a03f645241b6c963 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Nov 2026 13:00:57 +0900 Subject: [PATCH 1/3] test(interactive): reproduce R04 pre-await start input snapshot race --- tests/interactive/coordinator.test.mjs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/interactive/coordinator.test.mjs b/tests/interactive/coordinator.test.mjs index c02a291..5ccb0fb 100644 --- a/tests/interactive/coordinator.test.mjs +++ b/tests/interactive/coordinator.test.mjs @@ -402,3 +402,28 @@ test('M4 a successful receipt CAS followed by a lost response is recovered by du assert.equal(recovered.state.answer,'once'); assert.equal(store.load(waiting.runId).receipts.length,1); }); + + +test('R04 regression: start snapshots caller State and startIntent before its first await',async t=>{ + const {api,source,state,store}=await runAgentFixture(t); + const originalState={...state}; + const originalIntent={request:'before-await'}; + const intent={...originalIntent}; + const starting=api.start({ + ...source,startKey:'r04-first-await-snapshot',state,startIntent:intent, + }); + // This mutation happens after the caller hands the object to the SDK, + // but before the first awaited Program import has completed. + state.existing='modified-after-start'; + intent.request='modified-after-start'; + const frame=await starting; + const saved=store.load(frame.runId); + assert.deepEqual(saved.state,originalState, + 'checkpoint must reflect State at call entry, not external post-call writes'); + // Same original intent and state must retain the startKey's original identity. + const replay=await api.start({ + ...source,startKey:'r04-first-await-snapshot', + state:originalState,startIntent:originalIntent, + }); + assert.equal(replay.runId,frame.runId); +}); From f08efc1379c2b3153cba6a9be6632abdae5e6f52 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Nov 2026 13:01:48 +0900 Subject: [PATCH 2/3] test(interactive): isolate R04 State and startIntent races in separate regressions --- tests/interactive/coordinator.test.mjs | 35 ++++++++++++++------------ 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/tests/interactive/coordinator.test.mjs b/tests/interactive/coordinator.test.mjs index 5ccb0fb..da50187 100644 --- a/tests/interactive/coordinator.test.mjs +++ b/tests/interactive/coordinator.test.mjs @@ -404,26 +404,29 @@ test('M4 a successful receipt CAS followed by a lost response is recovered by du }); -test('R04 regression: start snapshots caller State and startIntent before its first await',async t=>{ +test('R04 regression: start snapshots caller-owned State before first await',async t=>{ const {api,source,state,store}=await runAgentFixture(t); const originalState={...state}; - const originalIntent={request:'before-await'}; - const intent={...originalIntent}; + const starting=api.start({...source,startKey:'r04-state-snapshot',state}); + // A later write by the caller must never become the Run's initial State. + state.existing='modified-after-start'; + const frame=await starting; + assert.deepEqual(store.load(frame.runId).state,originalState, + 'persisted State must be an entry-time snapshot'); +}); + +test('R04 regression: start snapshots caller-owned startIntent before first await',async t=>{ + const {api,source,state}=await runAgentFixture(t); + const intent={request:'before-await'}; const starting=api.start({ - ...source,startKey:'r04-first-await-snapshot',state,startIntent:intent, + ...source,startKey:'r04-intent-snapshot',state,startIntent:intent, }); - // This mutation happens after the caller hands the object to the SDK, - // but before the first awaited Program import has completed. - state.existing='modified-after-start'; + // The idempotency identity must not depend on post-call mutation. intent.request='modified-after-start'; - const frame=await starting; - const saved=store.load(frame.runId); - assert.deepEqual(saved.state,originalState, - 'checkpoint must reflect State at call entry, not external post-call writes'); - // Same original intent and state must retain the startKey's original identity. - const replay=await api.start({ - ...source,startKey:'r04-first-await-snapshot', - state:originalState,startIntent:originalIntent, + const first=await starting; + const originalReplay=await api.start({ + ...source,startKey:'r04-intent-snapshot',state, + startIntent:{request:'before-await'}, }); - assert.equal(replay.runId,frame.runId); + assert.equal(originalReplay.runId,first.runId); }); From ada01c933553206948ffcf2f944dfc5604e44da2 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Nov 2026 13:36:52 +0900 Subject: [PATCH 3/3] test(interactive): verify nested R04 pre-await State snapshot and retrigger CI --- tests/interactive/coordinator.test.mjs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/interactive/coordinator.test.mjs b/tests/interactive/coordinator.test.mjs index da50187..86a1292 100644 --- a/tests/interactive/coordinator.test.mjs +++ b/tests/interactive/coordinator.test.mjs @@ -406,13 +406,16 @@ test('M4 a successful receipt CAS followed by a lost response is recovered by du test('R04 regression: start snapshots caller-owned State before first await',async t=>{ const {api,source,state,store}=await runAgentFixture(t); - const originalState={...state}; + // Exercise both an existing top-level key and a nested caller-owned reference. + state.context={request:'before-await'}; + const originalState=structuredClone(state); const starting=api.start({...source,startKey:'r04-state-snapshot',state}); - // A later write by the caller must never become the Run's initial State. + // These writes occur synchronously after invoking start(), before its await resolves. state.existing='modified-after-start'; + state.context.request='modified-after-start'; const frame=await starting; assert.deepEqual(store.load(frame.runId).state,originalState, - 'persisted State must be an entry-time snapshot'); + 'persisted State must be a deep entry-time snapshot'); }); test('R04 regression: start snapshots caller-owned startIntent before first await',async t=>{