package agenttask import ( "context" "errors" "reflect" "testing" "time" ) func TestStateMachineLegalAndIllegalTransitions(t *testing.T) { record := WorkRecord{State: WorkStateObserved} for _, next := range []WorkState{ WorkStateReady, WorkStatePreparing, WorkStateDispatching, WorkStateSubmitted, WorkStateReviewing, WorkStatePendingIntegration, WorkStateIntegrating, WorkStateCompleted, } { if err := transitionWork(&record, next); err != nil { t.Fatalf("transition to %s: %v", next, err) } } if err := transitionWork(&record, WorkStateReady); err == nil { t.Fatal("completed -> ready unexpectedly allowed") } } func TestStateMachineDuplicateCommandIdempotency(t *testing.T) { harness := newHarness(t, map[ProjectID]ProjectWorkflowSnapshot{}, 1) request := StartRequest{ CommandID: "command", ProjectID: "project", WorkspaceID: "workspace", MilestoneID: "milestone", WorkflowRevision: "workflow-r1", ConfigRevision: "config-r1", GrantRevision: "grant-r1", } if err := harness.manager.StartProject(context.Background(), request); err != nil { t.Fatalf("first StartProject: %v", err) } if err := harness.manager.StartProject(context.Background(), request); err != nil { t.Fatalf("idempotent StartProject: %v", err) } request.ConfigRevision = "config-r2" if err := harness.manager.StartProject(context.Background(), request); err == nil { t.Fatal("same command with different immutable input accepted") } } func TestStateMachineCorruptIdentityBlocker(t *testing.T) { unit := testUnit("same", WriteSetUnknown) snapshot := testSnapshot("project", "workspace", unit, unit) harness := newHarness(t, map[ProjectID]ProjectWorkflowSnapshot{"project": snapshot}, 1) harness.start("project", "workspace", nil) if err := harness.manager.Reconcile(context.Background()); err != nil { t.Fatalf("Reconcile: %v", err) } project := harness.store.snapshot().Projects["project"] if project.Status != ProjectStatusBlocked || project.Blocker == nil || project.Blocker.Code != BlockerInvalidIdentity { t.Fatalf("project = %#v, want corrupt identity blocker", project) } if harness.invoker.callCount() != 0 { t.Fatalf("corrupt workflow invoked provider %d times", harness.invoker.callCount()) } } func TestNewManagerRequiresStrictExecutionPorts(t *testing.T) { _, err := NewManager( ManagerConfig{OwnerID: "manager"}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, ) if err == nil { t.Fatal("NewManager accepted missing strict ports") } var identityErr *IdentityError if _, err = NewManager( ManagerConfig{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, ); !errors.As(err, &identityErr) { t.Fatalf("empty owner error = %v, want IdentityError", err) } } func TestDurableIdentityEncodingIsInjective(t *testing.T) { id1 := durableIdentity("dispatch-v1", "p1/w", "2", "1") id2 := durableIdentity("dispatch-v1", "p1", "w/2", "1") if id1 == id2 { t.Fatalf("durable identity collision: %q == %q", id1, id2) } dk1 := dispatchKey("p1/w", "2", 1) dk2 := dispatchKey("p1", "w/2", 1) if dk1 == dk2 { t.Fatalf("dispatchKey collision: %q == %q", dk1, dk2) } rk1 := reviewKey("p1", "w", 1, "art#1") rk2 := reviewKey("p1", "w#1", 1, "art") if rk1 == rk2 { t.Fatalf("reviewKey collision: %q == %q", rk1, rk2) } } func TestEventDeliveryCheckpointCloneValidation(t *testing.T) { now := time.Date(2026, 7, 30, 17, 0, 0, 0, time.UTC) unit := testUnit("work-delivery", WriteSetDisjoint) work := WorkRecord{ Unit: unit, State: WorkStateReady, Attempt: 1, AttemptID: attemptID(unit.ID, 1), DispatchOrdinal: 7, Locators: make(map[LocatorKind]LocatorRecord), FailureBudgets: make(map[FailureStage]FailureBudgetRecord), UpdatedAt: now, } project := ProjectRecord{ ProjectID: "project-delivery", WorkspaceID: "workspace-delivery", Status: ProjectStatusRunning, Works: map[WorkUnitID]WorkRecord{ unit.ID: work, }, UpdatedAt: now, } event := normalizeEventIdentity(Event{ Type: EventDependencyReady, ProjectID: project.ProjectID, WorkspaceID: project.WorkspaceID, WorkUnitID: unit.ID, AttemptID: work.AttemptID, Ordinal: work.DispatchOrdinal, State: work.State, Detail: "dependency committed", Timestamp: now, }) state := cloneState(ManagerState{ SchemaVersion: currentSchemaVersion, Projects: map[ProjectID]ProjectRecord{ project.ProjectID: project, }, PendingEvents: map[string]EventDelivery{ event.EventID: { Event: event, EvidenceRevision: "revision-7", Project: &project, Work: &work, }, }, }) if err := validateManagerState(state); err != nil { t.Fatalf("valid pending delivery rejected: %v", err) } cloned := cloneState(state) clonedDelivery := cloned.PendingEvents[event.EventID] clonedDelivery.Work.Unit.Metadata = map[string]string{"mutated": "true"} clonedProjectWork := clonedDelivery.Project.Works[unit.ID] clonedProjectWork.Unit.Metadata = map[string]string{"project-mutated": "true"} clonedDelivery.Project.Works[unit.ID] = clonedProjectWork cloned.PendingEvents[event.EventID] = clonedDelivery original := state.PendingEvents[event.EventID] if original.Work.Unit.Metadata != nil || original.Project.Works[unit.ID].Unit.Metadata != nil { t.Fatal("pending delivery clone aliases original evidence") } tests := []struct { name string mutate func(*ManagerState) }{ { name: "map key drift", mutate: func(candidate *ManagerState) { delivery := candidate.PendingEvents[event.EventID] delete(candidate.PendingEvents, event.EventID) candidate.PendingEvents["other-event"] = delivery }, }, { name: "project identity drift", mutate: func(candidate *ManagerState) { delivery := candidate.PendingEvents[event.EventID] delivery.Project.ProjectID = "other-project" candidate.PendingEvents[event.EventID] = delivery }, }, { name: "work snapshot drift", mutate: func(candidate *ManagerState) { delivery := candidate.PendingEvents[event.EventID] delivery.Work.State = WorkStateBlocked candidate.PendingEvents[event.EventID] = delivery }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { candidate := cloneState(state) test.mutate(&candidate) if err := validateManagerState(candidate); err == nil { t.Fatal("drifted pending delivery passed validation") } }) } } func TestEventDeliveryEnqueueReplayKeepsTimestampAndRejectsConflict(t *testing.T) { store := newMemoryStore() now := time.Date(2026, 7, 30, 18, 0, 0, 0, time.UTC) clock := &advancingClock{now: now} unit := testUnit("work-event", WriteSetUnknown) work := WorkRecord{ Unit: unit, State: WorkStateReady, Attempt: 1, AttemptID: attemptID(unit.ID, 1), DispatchOrdinal: 1, Locators: make(map[LocatorKind]LocatorRecord), FailureBudgets: make(map[FailureStage]FailureBudgetRecord), } project := ProjectRecord{ ProjectID: "project-event", WorkspaceID: "workspace-event", Status: ProjectStatusRunning, Works: map[WorkUnitID]WorkRecord{unit.ID: work}, } store.edit(func(state *ManagerState) { state.Projects[project.ProjectID] = project }) manager := &Manager{ config: ManagerConfig{StateWriteAttempts: 4}, clock: clock, store: store, events: &recordingEvents{}, } event := Event{ Type: EventDependencyReady, ProjectID: project.ProjectID, WorkspaceID: project.WorkspaceID, WorkUnitID: unit.ID, AttemptID: work.AttemptID, Ordinal: work.DispatchOrdinal, State: work.State, Detail: "ready", } first, err := manager.enqueueEvent(context.Background(), event) if err != nil { t.Fatalf("first enqueue: %v", err) } clock.Advance(time.Hour) replayed, err := manager.enqueueEvent(context.Background(), event) if err != nil { t.Fatalf("replayed enqueue: %v", err) } if first.Event.EventID != replayed.Event.EventID || !first.Event.Timestamp.Equal(replayed.Event.Timestamp) || first.EvidenceRevision != replayed.EvidenceRevision || !reflect.DeepEqual(first, replayed) { t.Fatalf("pending replay changed delivery:\nfirst=%+v\nreplay=%+v", first, replayed) } conflicting := event conflicting.EventID = first.Event.EventID conflicting.Detail = "different logical content" if _, err := manager.enqueueEvent(context.Background(), conflicting); err == nil { t.Fatal("conflicting pending EventID reuse was accepted") } } func TestEventIdentityDistinguishesCommandsAndReplays(t *testing.T) { e1 := Event{ Type: EventManualStart, ProjectID: "p1", WorkspaceID: "w1", CommandID: "cmd-1", WorkflowRevision: "rev-1", } e2 := Event{ Type: EventManualStart, ProjectID: "p1", WorkspaceID: "w1", CommandID: "cmd-2", WorkflowRevision: "rev-1", } m := &Manager{clock: systemClock{}, events: &recordingEvents{}} m.emit(context.Background(), e1) m.emit(context.Background(), e2) var id1, id2, id1Replay string m.events = &testSink{onEmit: func(e Event) { id1 = e.EventID }} m.emit(context.Background(), e1) m.events = &testSink{onEmit: func(e Event) { id2 = e.EventID }} m.emit(context.Background(), e2) m.events = &testSink{onEmit: func(e Event) { id1Replay = e.EventID }} m.emit(context.Background(), e1) if id1 == id2 { t.Fatalf("different commands produced identical EventID: %q", id1) } if id1 != id1Replay { t.Fatalf("exact replay produced different EventID: %q vs %q", id1, id1Replay) } } type testSink struct { onEmit func(Event) } func (s *testSink) Emit(_ context.Context, e Event) error { if s.onEmit != nil { s.onEmit(e) } return nil } func TestInterruptedResumeEmitsStableEvent(t *testing.T) { snapshot := testSnapshot("project", "workspace", testUnit("work", WriteSetUnknown)) harness := newHarness(t, map[ProjectID]ProjectWorkflowSnapshot{"project": snapshot}, 1) harness.start("project", "workspace", nil) harness.store.edit(func(state *ManagerState) { project := state.Projects["project"] project.Status = ProjectStatusRunning state.Projects["project"] = project }) if err := harness.manager.Reconcile(context.Background()); err != nil { t.Fatalf("Reconcile: %v", err) } eventsEmitted := harness.events.snapshot() var hasAutoResume bool for _, e := range eventsEmitted { if e.Type == EventAutoResume { hasAutoResume = true if e.CommandID == "" || e.WorkflowRevision == "" { t.Fatalf("EventAutoResume missing logical discriminator: %#v", e) } } } if !hasAutoResume { t.Fatalf("auto resume did not emit EventAutoResume event") } }