summaryrefslogtreecommitdiff
path: root/internal/executor/channel_test.go
diff options
context:
space:
mode:
authorClaudomator Agent <agent@claudomator>2026-07-08 09:11:14 +0000
committerClaudomator Agent <agent@claudomator>2026-07-08 09:11:14 +0000
commit09066e1e4e928487bea0658492fd8573607c77c3 (patch)
tree76f3456fbf4eb3c71d90598297919dad97d43ddb /internal/executor/channel_test.go
parent2d311c129b6233ae7279587a82c95ffec3d6eeb5 (diff)
feat(agentchannel,executor): add ReportVerdict for structured approve/reject signals
Diffstat (limited to 'internal/executor/channel_test.go')
-rw-r--r--internal/executor/channel_test.go62
1 files changed, 62 insertions, 0 deletions
diff --git a/internal/executor/channel_test.go b/internal/executor/channel_test.go
index 84cad89..23f0661 100644
--- a/internal/executor/channel_test.go
+++ b/internal/executor/channel_test.go
@@ -607,3 +607,65 @@ func TestStoreChannel_ProposeRoleConfig_EmitsRoleConfigProposedEvent(t *testing.
t.Errorf("payload mismatch: %+v (want role=evaluator_quality version=%d)", payload, version)
}
}
+
+// TestStoreChannel_ReportVerdict_EmitsVerdictReportedEvent proves calling
+// ReportVerdict records a KindVerdictReported event attached to the
+// *calling task's* own ID, payload {approved, reasoning} —
+// internal/scheduler.StoryOrchestrator's finalizeArbitration later reads an
+// arbitration task's own event stream for this to decide REVIEW_READY vs
+// NEEDS_FIX. Mirrors TestStoreChannel_ProposeRoleConfig_EmitsRoleConfigProposedEvent.
+func TestStoreChannel_ReportVerdict_EmitsVerdictReportedEvent(t *testing.T) {
+ store := &fakeChannelStore{}
+ ch := newStoreChannel(store, "arbitration-task-1")
+
+ if err := ch.ReportVerdict(context.Background(), false, "the CSS change breaks the running-log panel"); err != nil {
+ t.Fatalf("ReportVerdict: %v", err)
+ }
+
+ if len(store.createdEvents) != 1 {
+ t.Fatalf("expected 1 event, got %d", len(store.createdEvents))
+ }
+ ev := store.createdEvents[0]
+ if ev.Kind != event.KindVerdictReported {
+ t.Errorf("expected KindVerdictReported, got %q", ev.Kind)
+ }
+ if ev.Actor != event.ActorAgent {
+ t.Errorf("expected ActorAgent, got %q", ev.Actor)
+ }
+ if ev.TaskID != "arbitration-task-1" {
+ t.Errorf("expected event attached to calling task ID, got %q", ev.TaskID)
+ }
+
+ var payload struct {
+ Approved bool `json:"approved"`
+ Reasoning string `json:"reasoning"`
+ }
+ if err := json.Unmarshal(ev.Payload, &payload); err != nil {
+ t.Fatalf("unmarshal payload: %v", err)
+ }
+ if payload.Approved != false || payload.Reasoning != "the CSS change breaks the running-log panel" {
+ t.Errorf("unexpected payload: %+v", payload)
+ }
+}
+
+// TestStoreChannel_ReportVerdict_Approved proves the approved=true case
+// round-trips correctly too — not just the rejection path exercised above.
+func TestStoreChannel_ReportVerdict_Approved(t *testing.T) {
+ store := &fakeChannelStore{}
+ ch := newStoreChannel(store, "arbitration-task-2")
+
+ if err := ch.ReportVerdict(context.Background(), true, "meets all acceptance criteria"); err != nil {
+ t.Fatalf("ReportVerdict: %v", err)
+ }
+
+ var payload struct {
+ Approved bool `json:"approved"`
+ Reasoning string `json:"reasoning"`
+ }
+ if err := json.Unmarshal(store.createdEvents[0].Payload, &payload); err != nil {
+ t.Fatalf("unmarshal payload: %v", err)
+ }
+ if !payload.Approved {
+ t.Error("expected approved=true to round-trip as true")
+ }
+}