summaryrefslogtreecommitdiff
path: root/internal/storage/epic.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/storage/epic.go')
-rw-r--r--internal/storage/epic.go11
1 files changed, 11 insertions, 0 deletions
diff --git a/internal/storage/epic.go b/internal/storage/epic.go
index 9f3863c..6d2b4d6 100644
--- a/internal/storage/epic.go
+++ b/internal/storage/epic.go
@@ -28,6 +28,17 @@ func (s *DB) GetEpic(id string) (*story.Epic, error) {
return scanEpic(row)
}
+// GetEpicByName retrieves an epic by exact name match (the earliest-created
+// one, if more than one somehow shares a name), or sql.ErrNoRows if none
+// exists. Used by internal/executor's ProposeEpic (Phase 7c) to decide
+// whether a discovery/planner agent's proposed epic name refers to an
+// existing epic or needs a new one — simplest reasonable matching, no fuzzy
+// dedup.
+func (s *DB) GetEpicByName(name string) (*story.Epic, error) {
+ row := s.db.QueryRow(`SELECT id, name, description, status, discovery_source, created_at, updated_at FROM epics WHERE name = ? ORDER BY created_at ASC LIMIT 1`, name)
+ return scanEpic(row)
+}
+
// ListEpics returns epics, optionally filtered by status. Pass an empty
// string to list all epics.
func (s *DB) ListEpics(status string) ([]*story.Epic, error) {