Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
648 lines
26 KiB
Go
648 lines
26 KiB
Go
package storesqlite
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
func TestHistoricalDuplicateProviderBindingCanStillAdvance(t *testing.T) {
|
|
t.Parallel()
|
|
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
|
ctx := context.Background()
|
|
if _, err := store.ReportSessionState(ctx, SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "source", Kind: SessionKindRoot,
|
|
Origin: "runtime", Provider: "codex", ProviderSessionID: "provider-source",
|
|
Status: "ready", CurrentPhase: "idle", OccurredAtUnixMS: 1,
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for index, turnID := range []string{"turn-1", "turn-2"} {
|
|
occurred := int64(10 + index*10)
|
|
providerTurnID := "provider-" + turnID
|
|
if _, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "source", Kind: SessionKindRoot,
|
|
Origin: "runtime", Provider: "codex", ProviderSessionID: "provider-source",
|
|
Status: "active", CurrentPhase: "working", OccurredAtUnixMS: occurred,
|
|
},
|
|
Turn: &TurnTransition{
|
|
WorkspaceID: "ws-1", AgentSessionID: "source", TurnID: turnID,
|
|
Phase: TurnPhaseRunning, OccurredAtUnixMS: occurred,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "source", RootTurnID: turnID,
|
|
ProviderTurnID: providerTurnID, Phase: RootProviderTurnPhaseRunning,
|
|
OccurredAtUnixMS: occurred,
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if turnID == "turn-1" {
|
|
reportRootProviderTurn(
|
|
t,
|
|
store,
|
|
"source",
|
|
turnID,
|
|
providerTurnID,
|
|
RootProviderTurnPhaseCompleted,
|
|
occurred+1,
|
|
)
|
|
}
|
|
}
|
|
if _, err := store.db.ExecContext(ctx, `
|
|
UPDATE workspace_agent_turns
|
|
SET root_provider_turn_id = 'provider-turn-1'
|
|
WHERE workspace_id = 'ws-1' AND agent_session_id = 'source' AND turn_id = 'turn-2'
|
|
`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
result, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "source",
|
|
OccurredAtUnixMS: 100,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "source",
|
|
RootTurnID: "turn-2", ProviderTurnID: "provider-turn-1",
|
|
Phase: RootProviderTurnPhaseCompleted, Outcome: TurnOutcomeCompleted,
|
|
OccurredAtUnixMS: 100,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("advance historical duplicate binding: %v", err)
|
|
}
|
|
if result.RootTurn.RootProviderTurnID != "provider-turn-1" ||
|
|
result.RootTurn.RootProviderTurnPhase != RootProviderTurnPhaseCompleted ||
|
|
result.RootTurn.Phase != TurnPhaseSettled {
|
|
t.Fatalf("advanced historical turn = %#v", result.RootTurn)
|
|
}
|
|
}
|
|
|
|
func TestProviderCheckpointPersistsThroughAndAfterTurnSettlement(t *testing.T) {
|
|
t.Parallel()
|
|
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
|
ctx := context.Background()
|
|
reportSessionWithTurn(t, store, SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root",
|
|
Provider: "claude-code", OccurredAtUnixMS: 10,
|
|
}, "turn-1", 10)
|
|
reportRootProviderTurn(
|
|
t,
|
|
store,
|
|
"root",
|
|
"turn-1",
|
|
"provider-user-1",
|
|
RootProviderTurnPhaseRunning,
|
|
11,
|
|
)
|
|
for _, checkpoint := range []struct {
|
|
id string
|
|
occurred int64
|
|
}{
|
|
{id: "provider-assistant-1", occurred: 12},
|
|
{id: "provider-system-1", occurred: 14},
|
|
} {
|
|
if checkpoint.occurred == 14 {
|
|
reportRootProviderTurn(
|
|
t,
|
|
store,
|
|
"root",
|
|
"turn-1",
|
|
"provider-user-1",
|
|
RootProviderTurnPhaseCompleted,
|
|
13,
|
|
)
|
|
}
|
|
if _, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root",
|
|
OccurredAtUnixMS: checkpoint.occurred,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "root",
|
|
RootTurnID: "turn-1", ProviderTurnID: "provider-user-1",
|
|
ProviderTurnBindingJSON: json.RawMessage(
|
|
`{"checkpointMessageId":"` + checkpoint.id + `"}`,
|
|
),
|
|
OccurredAtUnixMS: checkpoint.occurred,
|
|
},
|
|
}); err != nil {
|
|
t.Fatalf("persist checkpoint %q: %v", checkpoint.id, err)
|
|
}
|
|
}
|
|
if _, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root",
|
|
OccurredAtUnixMS: 12,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "root",
|
|
RootTurnID: "turn-1", ProviderTurnID: "provider-user-1",
|
|
ProviderTurnBindingJSON: json.RawMessage(
|
|
`{"checkpointMessageId":"provider-assistant-stale"}`,
|
|
),
|
|
OccurredAtUnixMS: 12,
|
|
},
|
|
}); err != nil {
|
|
t.Fatalf("persist stale checkpoint: %v", err)
|
|
}
|
|
turn, found, err := store.GetTurn(ctx, "ws-1", "root", "turn-1")
|
|
if err != nil || !found ||
|
|
string(turn.ProviderTurnBindingJSON) !=
|
|
`{"checkpointMessageId":"provider-system-1"}` ||
|
|
turn.RootProviderTurnUpdatedAtUnixMS != 14 {
|
|
t.Fatalf("persisted turn=%#v found=%v error=%v", turn, found, err)
|
|
}
|
|
}
|
|
|
|
func TestProviderTurnBindingJSONDoesNotSurviveIdentityReplacement(
|
|
t *testing.T,
|
|
) {
|
|
t.Parallel()
|
|
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
|
ctx := context.Background()
|
|
reportSessionWithTurn(t, store, SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root",
|
|
Provider: "claude-code", OccurredAtUnixMS: 10,
|
|
}, "turn-1", 10)
|
|
if _, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root",
|
|
OccurredAtUnixMS: 11,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "root",
|
|
RootTurnID: "turn-1", ProviderTurnID: "provider-observed",
|
|
ProviderTurnBindingJSON: json.RawMessage(
|
|
`{"checkpointMessageId":"checkpoint-observed"}`,
|
|
),
|
|
Phase: RootProviderTurnPhaseRunning,
|
|
OccurredAtUnixMS: 11,
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root",
|
|
OccurredAtUnixMS: 12,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "root",
|
|
RootTurnID: "turn-1", ProviderTurnID: "synthetic-replacement",
|
|
Phase: RootProviderTurnPhaseRunning, OccurredAtUnixMS: 12,
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
turn, found, err := store.GetTurn(ctx, "ws-1", "root", "turn-1")
|
|
if err != nil || !found {
|
|
t.Fatalf("GetTurn() found=%v error=%v", found, err)
|
|
}
|
|
if turn.RootProviderTurnID != "synthetic-replacement" ||
|
|
string(turn.ProviderTurnBindingJSON) != "{}" ||
|
|
HasPersistedProviderTurnBinding(turn) {
|
|
t.Fatalf("replacement inherited stale provider evidence: %#v", turn)
|
|
}
|
|
}
|
|
|
|
func TestReportActivityStateAtomicallyCreatesGoalTurnAndProviderBinding(t *testing.T) {
|
|
t.Parallel()
|
|
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
|
ctx := context.Background()
|
|
if _, err := store.ReportSessionState(ctx, SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", Kind: SessionKindRoot,
|
|
Provider: "claude-code", OccurredAtUnixMS: 20,
|
|
}); err != nil {
|
|
t.Fatalf("seed newer session snapshot: %v", err)
|
|
}
|
|
|
|
result, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", Kind: SessionKindRoot,
|
|
Provider: "claude-code", OccurredAtUnixMS: 10,
|
|
},
|
|
Turn: &TurnTransition{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", TurnID: "goal-turn",
|
|
Phase: TurnPhaseRunning, Origin: TurnOriginGoalArm,
|
|
SourceGoalOperationID: "goal-op-1", SourceGoalRevision: 1,
|
|
OccurredAtUnixMS: 10,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "root", RootTurnID: "goal-turn",
|
|
ProviderTurnID: "provider-turn", Phase: RootProviderTurnPhaseRunning,
|
|
OccurredAtUnixMS: 10,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("ReportActivityState(goal provider start): %v", err)
|
|
}
|
|
if !result.TurnAccepted || !result.RootTurnAccepted {
|
|
t.Fatalf("compound goal start result = %#v", result)
|
|
}
|
|
if result.State.StateApplied {
|
|
t.Fatalf("stale enclosing session unexpectedly applied: %#v", result.State)
|
|
}
|
|
turn, found, err := store.GetTurn(ctx, "ws-1", "root", "goal-turn")
|
|
if err != nil || !found || turn.Origin != TurnOriginGoalArm || turn.SourceGoalOperationID != "goal-op-1" ||
|
|
turn.RootProviderTurnID != "provider-turn" || turn.RootProviderTurnPhase != RootProviderTurnPhaseRunning {
|
|
t.Fatalf("persisted compound goal turn = %#v found=%v err=%v", turn, found, err)
|
|
}
|
|
messageResult, err := store.ReportSessionMessages(ctx, SessionMessageReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", Origin: "runtime",
|
|
Messages: []MessageUpdate{{
|
|
MessageID: "assistant-1", TurnID: "goal-turn", Role: "assistant",
|
|
Kind: "text", Status: "running", Payload: map[string]any{"text": "working"},
|
|
OccurredAtUnixMS: 11,
|
|
}},
|
|
})
|
|
if err != nil || messageResult.AcceptedCount != 1 {
|
|
t.Fatalf("persist first goal assistant message = %#v err=%v", messageResult, err)
|
|
}
|
|
completed, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", OccurredAtUnixMS: 30,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "root", RootTurnID: "goal-turn",
|
|
ProviderTurnID: "provider-turn", Phase: RootProviderTurnPhaseCompleted,
|
|
Outcome: TurnOutcomeCompleted, OccurredAtUnixMS: 30,
|
|
},
|
|
})
|
|
if err != nil || !completed.RootTurnAccepted || completed.RootTurn.Phase != TurnPhaseSettled {
|
|
t.Fatalf("settle compound goal turn = %#v err=%v", completed, err)
|
|
}
|
|
settledSession, found, err := store.GetSession(ctx, "ws-1", "root")
|
|
if err != nil || !found || settledSession.ActiveTurnID != "" {
|
|
t.Fatalf("settled compound goal session = %#v found=%v err=%v", settledSession, found, err)
|
|
}
|
|
}
|
|
|
|
func TestReportActivityStateRollsBackGoalTurnWhenProviderBindingFails(t *testing.T) {
|
|
t.Parallel()
|
|
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
|
ctx := context.Background()
|
|
|
|
_, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", Kind: SessionKindRoot,
|
|
Provider: "claude-code", OccurredAtUnixMS: 10,
|
|
},
|
|
Turn: &TurnTransition{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", TurnID: "goal-turn",
|
|
Phase: TurnPhaseRunning, Origin: TurnOriginGoalArm,
|
|
SourceGoalOperationID: "goal-op-1", SourceGoalRevision: 1,
|
|
OccurredAtUnixMS: 10,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "root", RootTurnID: "missing-turn",
|
|
ProviderTurnID: "provider-turn", Phase: RootProviderTurnPhaseRunning,
|
|
OccurredAtUnixMS: 10,
|
|
},
|
|
})
|
|
if err == nil {
|
|
t.Fatal("compound report with invalid provider binding unexpectedly succeeded")
|
|
}
|
|
if turn, found, getErr := store.GetTurn(ctx, "ws-1", "root", "goal-turn"); getErr != nil || found {
|
|
t.Fatalf("failed compound report leaked canonical turn = %#v found=%v err=%v", turn, found, getErr)
|
|
}
|
|
}
|
|
|
|
func TestRootProviderCompletionWaitsForEveryChildTurn(t *testing.T) {
|
|
t.Parallel()
|
|
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
|
ctx := context.Background()
|
|
reportSessionWithTurn(t, store, SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", Provider: "codex", OccurredAtUnixMS: 10,
|
|
}, "root-turn", 10)
|
|
reportSessionWithTurn(t, store, SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "child", Kind: SessionKindChild,
|
|
RootAgentSessionID: "root", RootTurnID: "root-turn",
|
|
ParentAgentSessionID: "root", ParentTurnID: "root-turn", ParentToolCallID: "call-1",
|
|
Provider: "codex", OccurredAtUnixMS: 20,
|
|
}, "child-turn", 20)
|
|
|
|
completed := reportRootProviderTurn(t, store, "root", "root-turn", "provider-turn-1", RootProviderTurnPhaseCompleted, 30)
|
|
if !completed.RootTurnAccepted || completed.RootTurn.Phase != TurnPhaseWaiting {
|
|
t.Fatalf("root provider completion result = %#v", completed)
|
|
}
|
|
persistedRoot, ok, err := store.GetTurn(ctx, "ws-1", "root", "root-turn")
|
|
if err != nil || !ok || persistedRoot.Phase != TurnPhaseWaiting ||
|
|
persistedRoot.RootProviderTurnPhase != RootProviderTurnPhaseCompleted {
|
|
t.Fatalf("persisted root after provider completion = %#v ok=%v err=%v", persistedRoot, ok, err)
|
|
}
|
|
|
|
childResult, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "child", OccurredAtUnixMS: 40,
|
|
},
|
|
Turn: &TurnTransition{
|
|
WorkspaceID: "ws-1", AgentSessionID: "child", TurnID: "child-turn",
|
|
Phase: TurnPhaseSettled, Outcome: TurnOutcomeFailed, OccurredAtUnixMS: 40,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !childResult.TurnAccepted || childResult.Turn.Outcome != TurnOutcomeFailed ||
|
|
!childResult.RootTurnAccepted || childResult.RootTurn.Phase != TurnPhaseSettled ||
|
|
childResult.RootTurn.Outcome != TurnOutcomeCompleted {
|
|
t.Fatalf("child terminal result = %#v", childResult)
|
|
}
|
|
}
|
|
|
|
func TestLateRootProviderCompletionUpdatesProjectionWithoutChangingCanceledCanonicalTurn(t *testing.T) {
|
|
t.Parallel()
|
|
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
|
ctx := context.Background()
|
|
reportSessionWithTurn(t, store, SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", Kind: SessionKindRoot,
|
|
Provider: "codex", OccurredAtUnixMS: 10,
|
|
}, "root-turn", 10)
|
|
reportRootProviderTurn(t, store, "root", "root-turn", "provider-turn-1", RootProviderTurnPhaseRunning, 20)
|
|
|
|
if _, created, err := store.PrepareRuntimeOperation(ctx, RuntimeOperationPrepare{
|
|
OperationID: "cancel-root", WorkspaceID: "ws-1", AgentSessionID: "root",
|
|
Kind: RuntimeOperationKindCancelTurn, TurnID: "root-turn", OccurredAtMS: 20,
|
|
Payload: map[string]any{"rootAgentSessionId": "root", "targets": []any{
|
|
map[string]any{"agentSessionId": "root", "turnId": "root-turn"},
|
|
}},
|
|
}); err != nil || !created {
|
|
t.Fatalf("prepare cancel created=%v err=%v", created, err)
|
|
}
|
|
claimRuntimeOperation(t, store, "cancel-root", "worker-a")
|
|
if _, changed, err := store.CompleteCancelRuntimeOperation(ctx, CompleteCancelRuntimeOperationInput{
|
|
WorkspaceID: "ws-1", OperationID: "cancel-root", LeaseOwner: "worker-a",
|
|
TargetOutcomes: []CancelRuntimeOperationTargetOutcome{{
|
|
AgentSessionID: "root", TurnID: "root-turn", Outcome: TurnOutcomeCanceled,
|
|
}},
|
|
NowUnixMS: 30,
|
|
}); err != nil || !changed {
|
|
t.Fatalf("complete cancel changed=%v err=%v", changed, err)
|
|
}
|
|
lateStarted, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", Kind: SessionKindRoot,
|
|
Provider: "codex", OccurredAtUnixMS: 35,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "root", RootTurnID: "root-turn",
|
|
ProviderTurnID: "provider-turn-2", Phase: RootProviderTurnPhaseRunning,
|
|
OccurredAtUnixMS: 35,
|
|
},
|
|
})
|
|
if err != nil || lateStarted.RootTurnAccepted || lateStarted.RootTurn.Phase != TurnPhaseSettled ||
|
|
lateStarted.RootTurn.RootProviderTurnID != "provider-turn-1" {
|
|
t.Fatalf("late provider start = %#v error=%v, want settled root unchanged", lateStarted, err)
|
|
}
|
|
if _, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", Kind: SessionKindRoot,
|
|
Provider: "codex", OccurredAtUnixMS: 40,
|
|
},
|
|
Turn: &TurnTransition{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", TurnID: "root-turn",
|
|
Phase: TurnPhaseRunning, OccurredAtUnixMS: 40,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "root", RootTurnID: "root-turn",
|
|
ProviderTurnID: "provider-turn-1", Phase: RootProviderTurnPhaseCompleted,
|
|
Outcome: TurnOutcomeCanceled, OccurredAtUnixMS: 40,
|
|
},
|
|
}); err == nil {
|
|
t.Fatal("mixed provider terminal and canonical running transition unexpectedly succeeded")
|
|
}
|
|
beforeTerminal, found, err := store.GetTurn(ctx, "ws-1", "root", "root-turn")
|
|
if err != nil || !found || beforeTerminal.RootProviderTurnPhase != RootProviderTurnPhaseRunning {
|
|
t.Fatalf("rejected mixed report changed provider projection: %#v found=%v err=%v", beforeTerminal, found, err)
|
|
}
|
|
|
|
result, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", Kind: SessionKindRoot,
|
|
Provider: "codex", OccurredAtUnixMS: 50,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "root", RootTurnID: "root-turn",
|
|
ProviderTurnID: "provider-turn-1", Phase: RootProviderTurnPhaseCompleted,
|
|
Outcome: TurnOutcomeCanceled, OccurredAtUnixMS: 50,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("report late provider completion: %v", err)
|
|
}
|
|
if result.TurnAccepted || result.RootTurnAccepted || !result.RootProviderTurnAccepted {
|
|
t.Fatalf("late provider completion changed canonical turn: %#v", result)
|
|
}
|
|
providerMutationCommitted := false
|
|
for _, mutation := range result.CommitDelta.Mutations {
|
|
if mutation.EntityKind == MutationEntityTurn && mutation.EntityID == "root-turn" {
|
|
providerMutationCommitted = true
|
|
break
|
|
}
|
|
}
|
|
if !providerMutationCommitted {
|
|
t.Fatalf("late provider completion has no root turn mutation: %#v", result.CommitDelta)
|
|
}
|
|
turn, found, err := store.GetTurn(ctx, "ws-1", "root", "root-turn")
|
|
if err != nil || !found {
|
|
t.Fatalf("get root turn found=%v err=%v", found, err)
|
|
}
|
|
if turn.Phase != TurnPhaseSettled || turn.Outcome != TurnOutcomeCanceled {
|
|
t.Fatalf("canonical root turn = %#v, want settled/canceled", turn)
|
|
}
|
|
if turn.RootProviderTurnPhase != RootProviderTurnPhaseCompleted ||
|
|
turn.RootProviderTurnOutcome != TurnOutcomeCanceled {
|
|
t.Fatalf("provider projection = %#v, want completed/canceled", turn)
|
|
}
|
|
}
|
|
|
|
func TestClaudeGoalCompleteDoesNotSettleRootWhileChildRuns(t *testing.T) {
|
|
t.Parallel()
|
|
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
|
ctx := context.Background()
|
|
reportSessionWithTurn(t, store, SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", Provider: "claude-code", OccurredAtUnixMS: 10,
|
|
RuntimeContext: map[string]any{
|
|
"goal": map[string]any{"objective": "ship it", "status": "active"},
|
|
},
|
|
}, "root-turn", 10)
|
|
reportSessionWithTurn(t, store, SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "child", Kind: SessionKindChild,
|
|
RootAgentSessionID: "root", RootTurnID: "root-turn",
|
|
ParentAgentSessionID: "root", ParentTurnID: "root-turn", ParentToolCallID: "toolu-1",
|
|
Provider: "claude-code", OccurredAtUnixMS: 20,
|
|
}, "child-turn", 20)
|
|
|
|
providerCompleted, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", OccurredAtUnixMS: 30,
|
|
RuntimeContext: map[string]any{
|
|
"goal": map[string]any{"objective": "ship it", "status": "complete"},
|
|
},
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "root", RootTurnID: "root-turn",
|
|
ProviderTurnID: "claude-turn-1", Phase: RootProviderTurnPhaseCompleted,
|
|
Outcome: TurnOutcomeCompleted, OccurredAtUnixMS: 30,
|
|
},
|
|
})
|
|
if err != nil || !providerCompleted.RootTurnAccepted || providerCompleted.RootTurn.Phase != TurnPhaseWaiting {
|
|
t.Fatalf("goal/provider completion result = %#v err=%v", providerCompleted, err)
|
|
}
|
|
persistedRootSession, ok, err := store.GetSession(ctx, "ws-1", "root")
|
|
if err != nil || !ok || persistedRootSession.ActiveTurnID != "root-turn" ||
|
|
persistedRootSession.Metadata.Goal == nil || persistedRootSession.Metadata.Goal.Status != "complete" {
|
|
t.Fatalf("persisted root session = %#v ok=%v err=%v", persistedRootSession, ok, err)
|
|
}
|
|
persistedRootTurn, ok, err := store.GetTurn(ctx, "ws-1", "root", "root-turn")
|
|
if err != nil || !ok || persistedRootTurn.Phase != TurnPhaseWaiting ||
|
|
persistedRootTurn.RootProviderTurnPhase != RootProviderTurnPhaseCompleted {
|
|
t.Fatalf("persisted root turn = %#v ok=%v err=%v", persistedRootTurn, ok, err)
|
|
}
|
|
persistedChildSession, ok, err := store.GetSession(ctx, "ws-1", "child")
|
|
if err != nil || !ok || persistedChildSession.ActiveTurnID != "child-turn" {
|
|
t.Fatalf("persisted child session = %#v ok=%v err=%v", persistedChildSession, ok, err)
|
|
}
|
|
|
|
childTerminal, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "child", OccurredAtUnixMS: 40,
|
|
},
|
|
Turn: &TurnTransition{
|
|
WorkspaceID: "ws-1", AgentSessionID: "child", TurnID: "child-turn",
|
|
Phase: TurnPhaseSettled, Outcome: TurnOutcomeCompleted, OccurredAtUnixMS: 40,
|
|
},
|
|
})
|
|
if err != nil || !childTerminal.RootTurnAccepted ||
|
|
childTerminal.RootTurn.Phase != TurnPhaseSettled ||
|
|
childTerminal.RootTurn.Outcome != TurnOutcomeCompleted {
|
|
t.Fatalf("child-only terminal result = %#v err=%v", childTerminal, err)
|
|
}
|
|
settledRootSession, ok, err := store.GetSession(ctx, "ws-1", "root")
|
|
if err != nil || !ok || settledRootSession.ActiveTurnID != "" ||
|
|
settledRootSession.Metadata.Goal == nil || settledRootSession.Metadata.Goal.Status != "complete" {
|
|
t.Fatalf("settled root session = %#v ok=%v err=%v", settledRootSession, ok, err)
|
|
}
|
|
}
|
|
|
|
func TestRootProviderCompletionIsOrderIndependentAndTracksLatestProviderTurn(t *testing.T) {
|
|
t.Parallel()
|
|
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
|
ctx := context.Background()
|
|
reportSessionWithTurn(t, store, SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", Provider: "claude-code", OccurredAtUnixMS: 10,
|
|
}, "root-turn", 10)
|
|
reportSessionWithTurn(t, store, SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "child", Kind: SessionKindChild,
|
|
RootAgentSessionID: "root", RootTurnID: "root-turn",
|
|
ParentAgentSessionID: "root", ParentTurnID: "root-turn", ParentToolCallID: "toolu-1",
|
|
Provider: "claude-code", OccurredAtUnixMS: 20,
|
|
}, "child-turn", 20)
|
|
|
|
firstCompleted := reportRootProviderTurn(t, store, "root", "root-turn", "provider-turn-1", RootProviderTurnPhaseCompleted, 30)
|
|
if firstCompleted.RootTurn.Phase != TurnPhaseWaiting {
|
|
t.Fatalf("first provider completion = %#v", firstCompleted)
|
|
}
|
|
started := reportRootProviderTurn(t, store, "root", "root-turn", "provider-turn-2", RootProviderTurnPhaseRunning, 40)
|
|
if !started.RootTurnAccepted || started.RootTurn.Phase != TurnPhaseRunning ||
|
|
started.RootTurn.RootProviderTurnID != "provider-turn-2" {
|
|
t.Fatalf("second provider start = %#v", started)
|
|
}
|
|
|
|
childResult, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{WorkspaceID: "ws-1", AgentSessionID: "child", OccurredAtUnixMS: 50},
|
|
Turn: &TurnTransition{
|
|
WorkspaceID: "ws-1", AgentSessionID: "child", TurnID: "child-turn",
|
|
Phase: TurnPhaseSettled, Outcome: TurnOutcomeCompleted, OccurredAtUnixMS: 50,
|
|
},
|
|
})
|
|
if err != nil || childResult.RootTurnAccepted {
|
|
t.Fatalf("child completion while latest provider turn runs = %#v err=%v", childResult, err)
|
|
}
|
|
root, ok, err := store.GetTurn(ctx, "ws-1", "root", "root-turn")
|
|
if err != nil || !ok || root.Phase != TurnPhaseRunning {
|
|
t.Fatalf("root before latest provider completion = %#v ok=%v err=%v", root, ok, err)
|
|
}
|
|
|
|
final := reportRootProviderTurn(t, store, "root", "root-turn", "provider-turn-2", RootProviderTurnPhaseCompleted, 60)
|
|
if !final.RootTurnAccepted || final.RootTurn.Phase != TurnPhaseSettled || final.RootTurn.Outcome != TurnOutcomeCompleted {
|
|
t.Fatalf("final provider completion = %#v", final)
|
|
}
|
|
}
|
|
|
|
func TestGuidanceContinuationFencesInterruptedProviderTerminal(t *testing.T) {
|
|
t.Parallel()
|
|
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
|
ctx := context.Background()
|
|
reportSessionWithTurn(t, store, SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", Kind: SessionKindRoot,
|
|
Provider: "codex", OccurredAtUnixMS: 10,
|
|
}, "root-turn", 10)
|
|
reportRootProviderTurn(t, store, "root", "root-turn", "provider-old", RootProviderTurnPhaseRunning, 20)
|
|
reportRootProviderTurn(t, store, "root", "root-turn", "continuation:guidance", RootProviderTurnPhaseRunning, 30)
|
|
|
|
if _, err := store.ReportActivityState(ctx, ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: "root", Kind: SessionKindRoot,
|
|
Provider: "codex", OccurredAtUnixMS: 40,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: "root", RootTurnID: "root-turn",
|
|
ProviderTurnID: "provider-old", Phase: RootProviderTurnPhaseCompleted,
|
|
Outcome: TurnOutcomeCanceled, OccurredAtUnixMS: 40,
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root, found, err := store.GetTurn(ctx, "ws-1", "root", "root-turn")
|
|
if err != nil || !found || root.Phase != TurnPhaseRunning ||
|
|
root.RootProviderTurnID != "continuation:guidance" ||
|
|
root.RootProviderTurnPhase != RootProviderTurnPhaseRunning {
|
|
t.Fatalf("interrupted response settled guidance root: %#v found=%v err=%v", root, found, err)
|
|
}
|
|
|
|
reportRootProviderTurn(t, store, "root", "root-turn", "provider-guidance", RootProviderTurnPhaseRunning, 50)
|
|
final := reportRootProviderTurn(t, store, "root", "root-turn", "provider-guidance", RootProviderTurnPhaseCompleted, 60)
|
|
if !final.RootTurnAccepted || final.RootTurn.Phase != TurnPhaseSettled ||
|
|
final.RootTurn.Outcome != TurnOutcomeCompleted {
|
|
t.Fatalf("guidance provider completion = %#v", final)
|
|
}
|
|
}
|
|
|
|
func reportRootProviderTurn(
|
|
t *testing.T,
|
|
store *Store,
|
|
rootSessionID string,
|
|
rootTurnID string,
|
|
providerTurnID string,
|
|
phase string,
|
|
occurredAtUnixMS int64,
|
|
) ActivityStateReportResult {
|
|
t.Helper()
|
|
outcome := ""
|
|
if phase == RootProviderTurnPhaseCompleted {
|
|
outcome = TurnOutcomeCompleted
|
|
}
|
|
result, err := store.ReportActivityState(context.Background(), ActivityStateReport{
|
|
Session: SessionStateReport{
|
|
WorkspaceID: "ws-1", AgentSessionID: rootSessionID, OccurredAtUnixMS: occurredAtUnixMS,
|
|
},
|
|
RootProviderTurn: &RootProviderTurnTransition{
|
|
WorkspaceID: "ws-1", RootAgentSessionID: rootSessionID, RootTurnID: rootTurnID,
|
|
ProviderTurnID: providerTurnID,
|
|
ProviderTurnBindingJSON: json.RawMessage(
|
|
`{"schemaVersion":1}`,
|
|
),
|
|
Phase: phase, Outcome: outcome,
|
|
OccurredAtUnixMS: occurredAtUnixMS,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("ReportActivityState(root provider turn) error = %v", err)
|
|
}
|
|
return result
|
|
}
|