diff --git a/database/migrations/026_continuity_attention_response_outcomes.sql b/database/migrations/026_continuity_attention_response_outcomes.sql new file mode 100644 index 0000000..55650c7 --- /dev/null +++ b/database/migrations/026_continuity_attention_response_outcomes.sql @@ -0,0 +1,22 @@ +BEGIN; + +SET ROLE continuity_role; + +ALTER TABLE continuity.attention_items + DROP CONSTRAINT IF EXISTS attention_items_response_projection_check; + +ALTER TABLE continuity.attention_items + ADD CONSTRAINT attention_items_response_projection_check + CHECK ( + state <> 'RESOLVED' + OR ( + response_id <> '' + AND response_utterance_id <> '' + AND response_operation IN ('ACKNOWLEDGE','COMPLETE','SNOOZE','CANCEL','DISMISS','CONTINUE','REJECT') + AND response_outcome IN ('USER_REPORTED_COMPLETE','SNOOZED','CANCELLED','DISMISSED','CLARIFICATION_NEEDED','CONTINUED','REJECTED','NOOP') + AND responded_at_unix_millis > 0 + ) + ); + +RESET ROLE; +COMMIT; diff --git a/tests/delegated_continuity/attention_response_projection_test.go b/tests/delegated_continuity/attention_response_projection_test.go new file mode 100644 index 0000000..2792d8c --- /dev/null +++ b/tests/delegated_continuity/attention_response_projection_test.go @@ -0,0 +1,27 @@ +package delegatedcontinuity + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func TestAttentionResponseProjectionAllowsDelegationContinuationOutcomes(t *testing.T) { + path := filepath.Join("..", "..", "database", "migrations", "026_continuity_attention_response_outcomes.sql") + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read migration: %v", err) + } + sql := string(content) + for _, want := range []string{ + "attention_items_response_projection_check", + "'CONTINUED'", + "'REJECTED'", + "'CLARIFICATION_NEEDED'", + } { + if !strings.Contains(sql, want) { + t.Fatalf("migration %s must contain %s", path, want) + } + } +}