@plazmodium/odin 0.3.2-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/README.md +306 -0
  2. package/dist/adapters/archive/supabase.d.ts +19 -0
  3. package/dist/adapters/archive/supabase.d.ts.map +1 -0
  4. package/dist/adapters/archive/supabase.js +121 -0
  5. package/dist/adapters/archive/supabase.js.map +1 -0
  6. package/dist/adapters/archive/types.d.ts +26 -0
  7. package/dist/adapters/archive/types.d.ts.map +1 -0
  8. package/dist/adapters/archive/types.js +6 -0
  9. package/dist/adapters/archive/types.js.map +1 -0
  10. package/dist/adapters/formal-verification/tla-precheck.d.ts +22 -0
  11. package/dist/adapters/formal-verification/tla-precheck.d.ts.map +1 -0
  12. package/dist/adapters/formal-verification/tla-precheck.js +270 -0
  13. package/dist/adapters/formal-verification/tla-precheck.js.map +1 -0
  14. package/dist/adapters/formal-verification/types.d.ts +37 -0
  15. package/dist/adapters/formal-verification/types.d.ts.map +1 -0
  16. package/dist/adapters/formal-verification/types.js +6 -0
  17. package/dist/adapters/formal-verification/types.js.map +1 -0
  18. package/dist/adapters/review/semgrep.d.ts +12 -0
  19. package/dist/adapters/review/semgrep.d.ts.map +1 -0
  20. package/dist/adapters/review/semgrep.js +175 -0
  21. package/dist/adapters/review/semgrep.js.map +1 -0
  22. package/dist/adapters/review/types.d.ts +14 -0
  23. package/dist/adapters/review/types.d.ts.map +1 -0
  24. package/dist/adapters/review/types.js +6 -0
  25. package/dist/adapters/review/types.js.map +1 -0
  26. package/dist/adapters/skills/filesystem.d.ts +18 -0
  27. package/dist/adapters/skills/filesystem.d.ts.map +1 -0
  28. package/dist/adapters/skills/filesystem.js +398 -0
  29. package/dist/adapters/skills/filesystem.js.map +1 -0
  30. package/dist/adapters/skills/types.d.ts +19 -0
  31. package/dist/adapters/skills/types.d.ts.map +1 -0
  32. package/dist/adapters/skills/types.js +6 -0
  33. package/dist/adapters/skills/types.js.map +1 -0
  34. package/dist/adapters/sql-executor/direct-postgres.d.ts +15 -0
  35. package/dist/adapters/sql-executor/direct-postgres.d.ts.map +1 -0
  36. package/dist/adapters/sql-executor/direct-postgres.js +33 -0
  37. package/dist/adapters/sql-executor/direct-postgres.js.map +1 -0
  38. package/dist/adapters/sql-executor/supabase-management-api.d.ts +17 -0
  39. package/dist/adapters/sql-executor/supabase-management-api.d.ts.map +1 -0
  40. package/dist/adapters/sql-executor/supabase-management-api.js +40 -0
  41. package/dist/adapters/sql-executor/supabase-management-api.js.map +1 -0
  42. package/dist/adapters/sql-executor/types.d.ts +15 -0
  43. package/dist/adapters/sql-executor/types.d.ts.map +1 -0
  44. package/dist/adapters/sql-executor/types.js +6 -0
  45. package/dist/adapters/sql-executor/types.js.map +1 -0
  46. package/dist/adapters/workflow-state/in-memory.d.ts +69 -0
  47. package/dist/adapters/workflow-state/in-memory.d.ts.map +1 -0
  48. package/dist/adapters/workflow-state/in-memory.js +444 -0
  49. package/dist/adapters/workflow-state/in-memory.js.map +1 -0
  50. package/dist/adapters/workflow-state/supabase.d.ts +55 -0
  51. package/dist/adapters/workflow-state/supabase.d.ts.map +1 -0
  52. package/dist/adapters/workflow-state/supabase.js +823 -0
  53. package/dist/adapters/workflow-state/supabase.js.map +1 -0
  54. package/dist/adapters/workflow-state/types.d.ts +55 -0
  55. package/dist/adapters/workflow-state/types.d.ts.map +1 -0
  56. package/dist/adapters/workflow-state/types.js +6 -0
  57. package/dist/adapters/workflow-state/types.js.map +1 -0
  58. package/dist/cli.d.ts +3 -0
  59. package/dist/cli.d.ts.map +1 -0
  60. package/dist/cli.js +52 -0
  61. package/dist/cli.js.map +1 -0
  62. package/dist/config.d.ts +44 -0
  63. package/dist/config.d.ts.map +1 -0
  64. package/dist/config.js +115 -0
  65. package/dist/config.js.map +1 -0
  66. package/dist/domain/actors.d.ts +10 -0
  67. package/dist/domain/actors.d.ts.map +1 -0
  68. package/dist/domain/actors.js +60 -0
  69. package/dist/domain/actors.js.map +1 -0
  70. package/dist/domain/development-evals.d.ts +9 -0
  71. package/dist/domain/development-evals.d.ts.map +1 -0
  72. package/dist/domain/development-evals.js +164 -0
  73. package/dist/domain/development-evals.js.map +1 -0
  74. package/dist/domain/matching.d.ts +8 -0
  75. package/dist/domain/matching.d.ts.map +1 -0
  76. package/dist/domain/matching.js +24 -0
  77. package/dist/domain/matching.js.map +1 -0
  78. package/dist/domain/phases.d.ts +10 -0
  79. package/dist/domain/phases.d.ts.map +1 -0
  80. package/dist/domain/phases.js +165 -0
  81. package/dist/domain/phases.js.map +1 -0
  82. package/dist/domain/quality-gates.d.ts +7 -0
  83. package/dist/domain/quality-gates.d.ts.map +1 -0
  84. package/dist/domain/quality-gates.js +8 -0
  85. package/dist/domain/quality-gates.js.map +1 -0
  86. package/dist/domain/resonance.d.ts +33 -0
  87. package/dist/domain/resonance.d.ts.map +1 -0
  88. package/dist/domain/resonance.js +100 -0
  89. package/dist/domain/resonance.js.map +1 -0
  90. package/dist/domain/tasks.d.ts +9 -0
  91. package/dist/domain/tasks.d.ts.map +1 -0
  92. package/dist/domain/tasks.js +57 -0
  93. package/dist/domain/tasks.js.map +1 -0
  94. package/dist/init.d.ts +7 -0
  95. package/dist/init.d.ts.map +1 -0
  96. package/dist/init.js +387 -0
  97. package/dist/init.js.map +1 -0
  98. package/dist/schemas.d.ts +366 -0
  99. package/dist/schemas.d.ts.map +1 -0
  100. package/dist/schemas.js +184 -0
  101. package/dist/schemas.js.map +1 -0
  102. package/dist/server.d.ts +7 -0
  103. package/dist/server.d.ts.map +1 -0
  104. package/dist/server.js +243 -0
  105. package/dist/server.js.map +1 -0
  106. package/dist/tools/apply-migrations.d.ts +21 -0
  107. package/dist/tools/apply-migrations.d.ts.map +1 -0
  108. package/dist/tools/apply-migrations.js +286 -0
  109. package/dist/tools/apply-migrations.js.map +1 -0
  110. package/dist/tools/archive-feature-release.d.ts +13 -0
  111. package/dist/tools/archive-feature-release.d.ts.map +1 -0
  112. package/dist/tools/archive-feature-release.js +182 -0
  113. package/dist/tools/archive-feature-release.js.map +1 -0
  114. package/dist/tools/capture-learning.d.ts +9 -0
  115. package/dist/tools/capture-learning.d.ts.map +1 -0
  116. package/dist/tools/capture-learning.js +53 -0
  117. package/dist/tools/capture-learning.js.map +1 -0
  118. package/dist/tools/explore-knowledge.d.ts +9 -0
  119. package/dist/tools/explore-knowledge.d.ts.map +1 -0
  120. package/dist/tools/explore-knowledge.js +142 -0
  121. package/dist/tools/explore-knowledge.js.map +1 -0
  122. package/dist/tools/get-claims-needing-review.d.ts +8 -0
  123. package/dist/tools/get-claims-needing-review.d.ts.map +1 -0
  124. package/dist/tools/get-claims-needing-review.js +21 -0
  125. package/dist/tools/get-claims-needing-review.js.map +1 -0
  126. package/dist/tools/get-development-eval-status.d.ts +8 -0
  127. package/dist/tools/get-development-eval-status.d.ts.map +1 -0
  128. package/dist/tools/get-development-eval-status.js +49 -0
  129. package/dist/tools/get-development-eval-status.js.map +1 -0
  130. package/dist/tools/get-feature-status.d.ts +8 -0
  131. package/dist/tools/get-feature-status.d.ts.map +1 -0
  132. package/dist/tools/get-feature-status.js +68 -0
  133. package/dist/tools/get-feature-status.js.map +1 -0
  134. package/dist/tools/get-next-phase.d.ts +8 -0
  135. package/dist/tools/get-next-phase.d.ts.map +1 -0
  136. package/dist/tools/get-next-phase.js +26 -0
  137. package/dist/tools/get-next-phase.js.map +1 -0
  138. package/dist/tools/prepare-phase-context.d.ts +9 -0
  139. package/dist/tools/prepare-phase-context.d.ts.map +1 -0
  140. package/dist/tools/prepare-phase-context.js +151 -0
  141. package/dist/tools/prepare-phase-context.js.map +1 -0
  142. package/dist/tools/record-commit.d.ts +8 -0
  143. package/dist/tools/record-commit.d.ts.map +1 -0
  144. package/dist/tools/record-commit.js +28 -0
  145. package/dist/tools/record-commit.js.map +1 -0
  146. package/dist/tools/record-eval-plan.d.ts +8 -0
  147. package/dist/tools/record-eval-plan.d.ts.map +1 -0
  148. package/dist/tools/record-eval-plan.js +40 -0
  149. package/dist/tools/record-eval-plan.js.map +1 -0
  150. package/dist/tools/record-eval-run.d.ts +8 -0
  151. package/dist/tools/record-eval-run.d.ts.map +1 -0
  152. package/dist/tools/record-eval-run.js +42 -0
  153. package/dist/tools/record-eval-run.js.map +1 -0
  154. package/dist/tools/record-merge.d.ts +8 -0
  155. package/dist/tools/record-merge.d.ts.map +1 -0
  156. package/dist/tools/record-merge.js +16 -0
  157. package/dist/tools/record-merge.js.map +1 -0
  158. package/dist/tools/record-phase-artifact.d.ts +8 -0
  159. package/dist/tools/record-phase-artifact.d.ts.map +1 -0
  160. package/dist/tools/record-phase-artifact.js +26 -0
  161. package/dist/tools/record-phase-artifact.js.map +1 -0
  162. package/dist/tools/record-phase-result.d.ts +9 -0
  163. package/dist/tools/record-phase-result.d.ts.map +1 -0
  164. package/dist/tools/record-phase-result.js +122 -0
  165. package/dist/tools/record-phase-result.js.map +1 -0
  166. package/dist/tools/record-pull-request.d.ts +8 -0
  167. package/dist/tools/record-pull-request.d.ts.map +1 -0
  168. package/dist/tools/record-pull-request.js +16 -0
  169. package/dist/tools/record-pull-request.js.map +1 -0
  170. package/dist/tools/record-quality-gate.d.ts +8 -0
  171. package/dist/tools/record-quality-gate.d.ts.map +1 -0
  172. package/dist/tools/record-quality-gate.js +26 -0
  173. package/dist/tools/record-quality-gate.js.map +1 -0
  174. package/dist/tools/record-watcher-review.d.ts +8 -0
  175. package/dist/tools/record-watcher-review.d.ts.map +1 -0
  176. package/dist/tools/record-watcher-review.js +18 -0
  177. package/dist/tools/record-watcher-review.js.map +1 -0
  178. package/dist/tools/run-policy-checks.d.ts +8 -0
  179. package/dist/tools/run-policy-checks.d.ts.map +1 -0
  180. package/dist/tools/run-policy-checks.js +38 -0
  181. package/dist/tools/run-policy-checks.js.map +1 -0
  182. package/dist/tools/run-review-checks.d.ts +9 -0
  183. package/dist/tools/run-review-checks.d.ts.map +1 -0
  184. package/dist/tools/run-review-checks.js +45 -0
  185. package/dist/tools/run-review-checks.js.map +1 -0
  186. package/dist/tools/start-feature.d.ts +8 -0
  187. package/dist/tools/start-feature.d.ts.map +1 -0
  188. package/dist/tools/start-feature.js +33 -0
  189. package/dist/tools/start-feature.js.map +1 -0
  190. package/dist/tools/submit-claim.d.ts +8 -0
  191. package/dist/tools/submit-claim.d.ts.map +1 -0
  192. package/dist/tools/submit-claim.js +45 -0
  193. package/dist/tools/submit-claim.js.map +1 -0
  194. package/dist/tools/verify-claims.d.ts +8 -0
  195. package/dist/tools/verify-claims.d.ts.map +1 -0
  196. package/dist/tools/verify-claims.js +39 -0
  197. package/dist/tools/verify-claims.js.map +1 -0
  198. package/dist/tools/verify-design.d.ts +8 -0
  199. package/dist/tools/verify-design.d.ts.map +1 -0
  200. package/dist/tools/verify-design.js +31 -0
  201. package/dist/tools/verify-design.js.map +1 -0
  202. package/dist/types.d.ts +333 -0
  203. package/dist/types.d.ts.map +1 -0
  204. package/dist/types.js +52 -0
  205. package/dist/types.js.map +1 -0
  206. package/dist/utils.d.ts +24 -0
  207. package/dist/utils.d.ts.map +1 -0
  208. package/dist/utils.js +50 -0
  209. package/dist/utils.js.map +1 -0
  210. package/migrations/001_schema.sql +795 -0
  211. package/migrations/002_functions.sql +2126 -0
  212. package/migrations/003_views.sql +599 -0
  213. package/migrations/004_seed.sql +106 -0
  214. package/migrations/005_odin_v2_schema.sql +217 -0
  215. package/migrations/006_odin_v2_functions.sql +671 -0
  216. package/migrations/007_odin_v2_phase_alignment.sql +554 -0
  217. package/migrations/008_related_learnings.sql +80 -0
  218. package/migrations/README.md +23 -0
  219. package/package.json +63 -0
@@ -0,0 +1,599 @@
1
+ -- ============================================================================
2
+ -- Odin SDD Framework - Consolidated Views
3
+ -- Version: 1.1.0
4
+ -- Created: 2026-02-16
5
+ -- Updated: 2026-02-16 (reconciled with live Supabase DB)
6
+ -- Description: All database views for Odin. Run after 002_functions.sql.
7
+ -- All views use security_invoker = true to prevent SECURITY DEFINER bypasses.
8
+ -- ============================================================================
9
+
10
+ -- ============================================================================
11
+ -- FEATURE VIEWS
12
+ -- ============================================================================
13
+
14
+ -- Active features with duration tracking
15
+ CREATE OR REPLACE VIEW v_active_features WITH (security_invoker = true) AS
16
+ SELECT
17
+ f.id,
18
+ f.name,
19
+ f.complexity_level,
20
+ f.severity,
21
+ f.current_phase,
22
+ f.status,
23
+ f.epic_id,
24
+ f.parent_feature_id,
25
+ f.created_at,
26
+ f.updated_at,
27
+ f.completed_at,
28
+ f.requirements_path,
29
+ f.spec_path,
30
+ f.assigned_agent,
31
+ COUNT(DISTINCT pt.id) AS phase_transition_count,
32
+ COUNT(DISTINCT b.id) FILTER (WHERE b.status = 'OPEN') AS open_blockers,
33
+ COALESCE(SUM(ai.duration_ms) FILTER (WHERE ai.ended_at IS NOT NULL), 0) AS total_duration_ms,
34
+ COUNT(DISTINCT ai.id) AS invocation_count,
35
+ MAX(COALESCE(ai.ended_at, ai.started_at)) AS last_activity
36
+ FROM features f
37
+ LEFT JOIN phase_transitions pt ON f.id = pt.feature_id
38
+ LEFT JOIN blockers b ON f.id = b.feature_id
39
+ LEFT JOIN agent_invocations ai ON f.id = ai.feature_id
40
+ WHERE f.status = 'IN_PROGRESS'
41
+ GROUP BY f.id;
42
+
43
+ COMMENT ON VIEW v_active_features IS 'Active features with aggregated metrics';
44
+
45
+ -- All features summary with health scores (matches live DB column names)
46
+ CREATE OR REPLACE VIEW all_features_summary WITH (security_invoker = true) AS
47
+ SELECT
48
+ f.id AS feature_id,
49
+ f.name AS feature_name,
50
+ f.status AS feature_status,
51
+ f.current_phase,
52
+ f.complexity_level,
53
+ f.severity,
54
+ f.created_at,
55
+ f.completed_at,
56
+ f.branch_name,
57
+ f.pr_url,
58
+ f.pr_number,
59
+ f.merged_at,
60
+ f.author,
61
+ e.computed_at AS last_eval_at,
62
+ e.overall_score,
63
+ e.health_status,
64
+ e.efficiency_score,
65
+ e.quality_score,
66
+ COALESCE(
67
+ (SELECT sum(ai.duration_ms) FROM agent_invocations ai WHERE ai.feature_id = f.id AND ai.ended_at IS NOT NULL),
68
+ 0
69
+ )::BIGINT AS total_duration_ms,
70
+ (SELECT count(*) FROM eval_alerts a WHERE a.feature_id = f.id AND a.resolved_at IS NULL) AS active_alerts
71
+ FROM features f
72
+ LEFT JOIN LATERAL (
73
+ SELECT fe.computed_at, fe.overall_score, fe.health_status, fe.efficiency_score, fe.quality_score
74
+ FROM feature_evals fe
75
+ WHERE fe.feature_id = f.id
76
+ ORDER BY fe.computed_at DESC
77
+ LIMIT 1
78
+ ) e ON true
79
+ ORDER BY
80
+ CASE f.status
81
+ WHEN 'IN_PROGRESS' THEN 0
82
+ WHEN 'BLOCKED' THEN 1
83
+ WHEN 'COMPLETED' THEN 2
84
+ WHEN 'CANCELLED' THEN 3
85
+ END,
86
+ f.created_at DESC;
87
+
88
+ COMMENT ON VIEW all_features_summary IS 'Summary of all features with latest health scores';
89
+
90
+ -- Feature health overview (for dashboard)
91
+ CREATE OR REPLACE VIEW feature_health_overview WITH (security_invoker = true) AS
92
+ SELECT
93
+ f.id AS feature_id,
94
+ f.name AS feature_name,
95
+ f.status AS feature_status,
96
+ f.current_phase,
97
+ f.complexity_level,
98
+ e.computed_at AS last_eval_at,
99
+ e.overall_score,
100
+ e.health_status,
101
+ e.efficiency_score,
102
+ e.quality_score,
103
+ COALESCE((SELECT SUM(ai.duration_ms) FROM agent_invocations ai WHERE ai.feature_id = f.id AND ai.ended_at IS NOT NULL), 0) AS total_duration_ms,
104
+ (SELECT COUNT(*) FROM eval_alerts a WHERE a.feature_id = f.id AND a.resolved_at IS NULL) AS active_alerts
105
+ FROM features f
106
+ LEFT JOIN LATERAL (
107
+ SELECT fe.* FROM feature_evals fe
108
+ WHERE fe.feature_id = f.id
109
+ ORDER BY fe.computed_at DESC LIMIT 1
110
+ ) e ON true
111
+ WHERE f.status IN ('IN_PROGRESS', 'BLOCKED')
112
+ ORDER BY
113
+ CASE
114
+ WHEN e.health_status = 'CRITICAL' THEN 0
115
+ WHEN e.health_status = 'CONCERNING' THEN 1
116
+ ELSE 2
117
+ END,
118
+ f.updated_at DESC;
119
+
120
+ COMMENT ON VIEW feature_health_overview IS 'Feature health overview prioritized by health status';
121
+
122
+ -- Pending quality gates
123
+ CREATE OR REPLACE VIEW v_pending_gates WITH (security_invoker = true) AS
124
+ SELECT
125
+ qg.id,
126
+ qg.feature_id,
127
+ qg.gate_name,
128
+ qg.phase,
129
+ qg.status,
130
+ qg.approver,
131
+ qg.approved_at,
132
+ qg.approval_notes,
133
+ qg.decision_log,
134
+ f.name AS feature_name,
135
+ f.complexity_level,
136
+ f.assigned_agent
137
+ FROM quality_gates qg
138
+ JOIN features f ON qg.feature_id = f.id
139
+ WHERE qg.status = 'PENDING';
140
+
141
+ COMMENT ON VIEW v_pending_gates IS 'Quality gates awaiting approval';
142
+
143
+ -- ============================================================================
144
+ -- LEARNING VIEWS
145
+ -- ============================================================================
146
+
147
+ -- Active learnings with propagation status (derived from relational tables)
148
+ CREATE OR REPLACE VIEW active_learnings WITH (security_invoker = true) AS
149
+ SELECT
150
+ l.id,
151
+ l.predecessor_id,
152
+ l.iteration_number,
153
+ l.feature_id,
154
+ f.name AS feature_name,
155
+ l.task_id,
156
+ l.category,
157
+ l.title,
158
+ l.content,
159
+ l.delta_summary,
160
+ l.confidence_score,
161
+ l.validation_count,
162
+ l.last_validated_at,
163
+ l.importance,
164
+ l.tags,
165
+ l.phase,
166
+ l.agent,
167
+ l.created_at,
168
+ l.updated_at,
169
+ l.created_by,
170
+ -- Derive is_propagated from relational tables
171
+ CASE
172
+ WHEN prop_stats.total_targets > 0 AND prop_stats.propagated_count = prop_stats.total_targets THEN true
173
+ ELSE false
174
+ END AS is_propagated,
175
+ -- Keep propagated_to for backward compat
176
+ l.propagated_to,
177
+ l.propagated_at,
178
+ -- Derive ready_for_propagation from relational tables
179
+ CASE
180
+ WHEN l.confidence_score >= 0.80
181
+ AND prop_stats.total_targets > 0
182
+ AND prop_stats.propagated_count < prop_stats.total_targets THEN true
183
+ ELSE false
184
+ END AS ready_for_propagation,
185
+ (EXISTS (
186
+ SELECT 1 FROM learnings s WHERE s.predecessor_id = l.id
187
+ )) AS has_successors,
188
+ -- Propagation status for badges
189
+ COALESCE(prop_stats.propagation_status, 'no_targets') AS propagation_status,
190
+ COALESCE(prop_stats.total_targets, 0) AS total_targets,
191
+ COALESCE(prop_stats.propagated_count, 0) AS propagated_count
192
+ FROM learnings l
193
+ LEFT JOIN features f ON l.feature_id = f.id
194
+ LEFT JOIN LATERAL (
195
+ SELECT
196
+ count(lpt.id)::integer AS total_targets,
197
+ count(lp.id)::integer AS propagated_count,
198
+ CASE
199
+ WHEN count(lpt.id) = 0 THEN 'no_targets'
200
+ WHEN count(lp.id) = count(lpt.id) THEN 'complete'
201
+ WHEN count(lp.id) > 0 THEN 'partial'
202
+ ELSE 'pending'
203
+ END AS propagation_status
204
+ FROM learning_propagation_targets lpt
205
+ LEFT JOIN learning_propagations lp
206
+ ON lpt.learning_id = lp.learning_id
207
+ AND lpt.target_type = lp.target_type
208
+ AND NOT lpt.target_path IS DISTINCT FROM lp.target_path
209
+ WHERE lpt.learning_id = l.id
210
+ ) prop_stats ON true
211
+ WHERE NOT l.is_superseded;
212
+
213
+ COMMENT ON VIEW active_learnings IS 'Active (non-superseded) learnings with propagation status';
214
+
215
+ -- Propagation queue (learnings ready for propagation — matches live DB)
216
+ CREATE OR REPLACE VIEW propagation_queue WITH (security_invoker = true) AS
217
+ SELECT
218
+ l.id,
219
+ l.category,
220
+ l.title,
221
+ l.content,
222
+ l.confidence_score,
223
+ l.validation_count,
224
+ l.importance,
225
+ l.feature_id,
226
+ f.name AS feature_name,
227
+ l.tags,
228
+ l.created_at,
229
+ l.created_by,
230
+ CASE
231
+ WHEN l.propagation_summary IS NOT NULL THEN l.propagation_summary
232
+ ELSE left(l.content, 200) ||
233
+ CASE WHEN length(l.content) > 200 THEN '...' ELSE '' END
234
+ END AS suggested_summary
235
+ FROM learnings l
236
+ LEFT JOIN features f ON l.feature_id = f.id
237
+ WHERE l.confidence_score >= 0.80
238
+ AND array_length(l.propagated_to, 1) IS NULL
239
+ AND NOT l.is_superseded
240
+ ORDER BY l.confidence_score DESC, l.importance DESC;
241
+
242
+ COMMENT ON VIEW propagation_queue IS 'Learnings eligible for propagation (confidence >= 0.80)';
243
+
244
+ -- Skill propagation queue
245
+ CREATE OR REPLACE VIEW skill_propagation_queue WITH (security_invoker = true) AS
246
+ SELECT
247
+ l.id AS learning_id,
248
+ l.title,
249
+ l.category,
250
+ l.content,
251
+ l.confidence_score,
252
+ l.feature_id,
253
+ lpt.target_type,
254
+ lpt.target_path,
255
+ lpt.relevance_score
256
+ FROM learnings l
257
+ JOIN learning_propagation_targets lpt ON l.id = lpt.learning_id
258
+ LEFT JOIN learning_propagations lp
259
+ ON lpt.learning_id = lp.learning_id
260
+ AND lpt.target_type = lp.target_type
261
+ AND lpt.target_path IS NOT DISTINCT FROM lp.target_path
262
+ WHERE l.confidence_score >= 0.80
263
+ AND NOT l.is_superseded
264
+ AND lpt.relevance_score >= 0.60
265
+ AND lp.id IS NULL
266
+ AND NOT EXISTS (
267
+ SELECT 1 FROM learning_conflicts lc
268
+ WHERE (lc.learning_a_id = l.id OR lc.learning_b_id = l.id)
269
+ AND lc.status = 'OPEN'
270
+ );
271
+
272
+ COMMENT ON VIEW skill_propagation_queue IS 'Learnings with unpropagated skill targets';
273
+
274
+ -- Learning propagation overview
275
+ CREATE OR REPLACE VIEW learning_propagation_overview WITH (security_invoker = true) AS
276
+ SELECT
277
+ l.id AS learning_id,
278
+ l.title,
279
+ l.category,
280
+ l.confidence_score,
281
+ l.feature_id,
282
+ COUNT(lpt.id)::INTEGER AS total_targets,
283
+ COUNT(lp.id)::INTEGER AS propagated_count,
284
+ (COUNT(lpt.id) - COUNT(lp.id))::INTEGER AS pending_count,
285
+ CASE
286
+ WHEN COUNT(lpt.id) = 0 THEN 'no_targets'
287
+ WHEN COUNT(lp.id) = COUNT(lpt.id) THEN 'complete'
288
+ WHEN COUNT(lp.id) > 0 THEN 'partial'
289
+ ELSE 'pending'
290
+ END AS propagation_status
291
+ FROM learnings l
292
+ LEFT JOIN learning_propagation_targets lpt ON l.id = lpt.learning_id
293
+ LEFT JOIN learning_propagations lp
294
+ ON lpt.learning_id = lp.learning_id
295
+ AND lpt.target_type = lp.target_type
296
+ AND lpt.target_path IS NOT DISTINCT FROM lp.target_path
297
+ WHERE NOT l.is_superseded
298
+ GROUP BY l.id, l.title, l.category, l.confidence_score, l.feature_id;
299
+
300
+ COMMENT ON VIEW learning_propagation_overview IS 'Propagation status summary per learning';
301
+
302
+ -- Open learning conflicts (matches live DB with extra columns)
303
+ CREATE OR REPLACE VIEW open_learning_conflicts WITH (security_invoker = true) AS
304
+ SELECT
305
+ c.id,
306
+ c.conflict_type,
307
+ c.description,
308
+ c.status,
309
+ c.detected_at,
310
+ c.detected_by,
311
+ c.learning_a_id,
312
+ la.title AS learning_a_title,
313
+ la.category AS learning_a_category,
314
+ la.confidence_score AS learning_a_confidence,
315
+ la.feature_id AS learning_a_feature_id,
316
+ c.learning_b_id,
317
+ lb.title AS learning_b_title,
318
+ lb.category AS learning_b_category,
319
+ lb.confidence_score AS learning_b_confidence,
320
+ lb.feature_id AS learning_b_feature_id,
321
+ EXTRACT(EPOCH FROM (now() - c.detected_at)) / 3600 AS hours_open
322
+ FROM learning_conflicts c
323
+ JOIN learnings la ON c.learning_a_id = la.id
324
+ JOIN learnings lb ON c.learning_b_id = lb.id
325
+ WHERE c.status IN ('OPEN', 'INVESTIGATING')
326
+ ORDER BY c.detected_at;
327
+
328
+ COMMENT ON VIEW open_learning_conflicts IS 'Open learning conflicts requiring resolution';
329
+
330
+ -- Feature learning summary (matches live DB with extra columns)
331
+ CREATE OR REPLACE VIEW feature_learning_summary WITH (security_invoker = true) AS
332
+ SELECT
333
+ f.id AS feature_id,
334
+ f.name AS feature_name,
335
+ f.status AS feature_status,
336
+ COUNT(l.id) AS total_learnings,
337
+ COUNT(l.id) FILTER (WHERE NOT l.is_superseded) AS active_learnings,
338
+ COUNT(l.id) FILTER (WHERE l.confidence_score >= 0.80) AS high_confidence_learnings,
339
+ COUNT(l.id) FILTER (WHERE array_length(l.propagated_to, 1) > 0) AS propagated_learnings,
340
+ AVG(l.confidence_score) FILTER (WHERE NOT l.is_superseded) AS avg_confidence,
341
+ MAX(l.created_at) AS last_learning_at,
342
+ array_agg(DISTINCT l.category) FILTER (WHERE NOT l.is_superseded) AS categories_covered
343
+ FROM features f
344
+ LEFT JOIN learnings l ON l.feature_id = f.id
345
+ GROUP BY f.id, f.name, f.status;
346
+
347
+ COMMENT ON VIEW feature_learning_summary IS 'Learning statistics per feature';
348
+
349
+ -- Learning chain summary (evolution chains)
350
+ CREATE OR REPLACE VIEW learning_chain_summary WITH (security_invoker = true) AS
351
+ WITH chain_stats AS (
352
+ SELECT
353
+ (WITH RECURSIVE find_root AS (
354
+ SELECT l.id, l.predecessor_id, l.id AS current
355
+ FROM learnings l WHERE l.id = outer_l.id
356
+ UNION ALL
357
+ SELECT fr.id, p.predecessor_id, p.id
358
+ FROM find_root fr JOIN learnings p ON fr.predecessor_id = p.id
359
+ )
360
+ SELECT find_root.current FROM find_root WHERE find_root.predecessor_id IS NULL LIMIT 1
361
+ ) AS chain_root_id,
362
+ outer_l.id,
363
+ outer_l.iteration_number,
364
+ outer_l.is_superseded,
365
+ outer_l.confidence_score,
366
+ outer_l.title,
367
+ outer_l.created_at
368
+ FROM learnings outer_l
369
+ )
370
+ SELECT
371
+ chain_root_id,
372
+ count(*) AS chain_length,
373
+ max(iteration_number) AS latest_iteration,
374
+ max(confidence_score) FILTER (WHERE NOT is_superseded) AS current_confidence,
375
+ (SELECT learnings.title FROM learnings WHERE learnings.id = chain_stats.chain_root_id) AS original_title,
376
+ (SELECT cs2.id FROM chain_stats cs2
377
+ WHERE cs2.chain_root_id = chain_stats.chain_root_id AND NOT cs2.is_superseded
378
+ ORDER BY cs2.iteration_number DESC LIMIT 1) AS current_learning_id,
379
+ min(created_at) AS chain_started_at,
380
+ max(created_at) AS last_evolved_at
381
+ FROM chain_stats
382
+ WHERE chain_root_id IS NOT NULL
383
+ GROUP BY chain_root_id;
384
+
385
+ COMMENT ON VIEW learning_chain_summary IS 'Summary of learning evolution chains';
386
+
387
+ -- ============================================================================
388
+ -- EVALS VIEWS
389
+ -- ============================================================================
390
+
391
+ -- Active eval alerts (matches live DB with extra columns)
392
+ CREATE OR REPLACE VIEW active_eval_alerts WITH (security_invoker = true) AS
393
+ SELECT
394
+ a.id,
395
+ a.severity,
396
+ a.dimension,
397
+ a.message,
398
+ a.current_value,
399
+ a.threshold,
400
+ a.source_type,
401
+ a.feature_id,
402
+ f.name AS feature_name,
403
+ a.created_at,
404
+ EXTRACT(EPOCH FROM (now() - a.created_at)) / 3600 AS hours_active,
405
+ (a.acknowledged_at IS NOT NULL) AS is_acknowledged,
406
+ a.acknowledged_by
407
+ FROM eval_alerts a
408
+ LEFT JOIN features f ON a.feature_id = f.id
409
+ WHERE a.resolved_at IS NULL
410
+ ORDER BY
411
+ CASE a.severity WHEN 'CRITICAL' THEN 0 ELSE 1 END,
412
+ a.created_at DESC;
413
+
414
+ COMMENT ON VIEW active_eval_alerts IS 'Unresolved evaluation alerts';
415
+
416
+ -- Latest system health per period
417
+ CREATE OR REPLACE VIEW latest_system_health WITH (security_invoker = true) AS
418
+ SELECT DISTINCT ON (period_days)
419
+ id,
420
+ computed_at,
421
+ period_days,
422
+ overall_health_score,
423
+ health_status,
424
+ workflow_metrics,
425
+ quality_metrics,
426
+ learning_metrics,
427
+ alerts
428
+ FROM system_health_evals
429
+ ORDER BY period_days, computed_at DESC;
430
+
431
+ COMMENT ON VIEW latest_system_health IS 'Most recent system health eval per time period';
432
+
433
+ -- ============================================================================
434
+ -- BATCH EXECUTION VIEWS
435
+ -- ============================================================================
436
+
437
+ -- Batch execution stats (last 30 days)
438
+ CREATE OR REPLACE VIEW batch_execution_stats WITH (security_invoker = true) AS
439
+ SELECT
440
+ COALESCE(template_used, 'custom') AS template,
441
+ COUNT(*) AS total_executions,
442
+ COUNT(*) FILTER (WHERE success) AS successful,
443
+ COUNT(*) FILTER (WHERE NOT success) AS failed,
444
+ ROUND(AVG(duration_ms), 0) AS avg_duration_ms,
445
+ MAX(executed_at) AS last_execution
446
+ FROM batch_executions
447
+ WHERE executed_at >= now() - INTERVAL '30 days'
448
+ GROUP BY COALESCE(template_used, 'custom')
449
+ ORDER BY COUNT(*) DESC;
450
+
451
+ COMMENT ON VIEW batch_execution_stats IS 'Batch execution statistics by template (30 day window)';
452
+
453
+ -- ============================================================================
454
+ -- MEMORY VIEWS
455
+ -- ============================================================================
456
+
457
+ -- Recent memories (last 30 days)
458
+ CREATE OR REPLACE VIEW v_recent_memories WITH (security_invoker = true) AS
459
+ SELECT id, feature_id, category, importance, title, content, rationale, tags, phase, agent, created_at, created_by
460
+ FROM memories
461
+ WHERE is_archived = false AND created_at > now() - INTERVAL '30 days'
462
+ ORDER BY created_at DESC;
463
+
464
+ COMMENT ON VIEW v_recent_memories IS 'Memories created in the last 30 days';
465
+
466
+ -- Critical memories (HIGH importance)
467
+ CREATE OR REPLACE VIEW v_critical_memories WITH (security_invoker = true) AS
468
+ SELECT id, feature_id, category, importance, title, content, rationale, tags, phase, agent, created_at, created_by
469
+ FROM memories
470
+ WHERE is_archived = false AND importance = 'HIGH'
471
+ ORDER BY created_at DESC;
472
+
473
+ COMMENT ON VIEW v_critical_memories IS 'High-importance memories';
474
+
475
+ -- Global memories (not tied to a feature)
476
+ CREATE OR REPLACE VIEW v_global_memories WITH (security_invoker = true) AS
477
+ SELECT id, category, importance, title, content, rationale, tags, phase, agent, created_at, created_by
478
+ FROM memories
479
+ WHERE is_archived = false AND feature_id IS NULL
480
+ ORDER BY importance DESC, created_at DESC;
481
+
482
+ COMMENT ON VIEW v_global_memories IS 'Global memories not tied to any feature';
483
+
484
+ -- Gotchas
485
+ CREATE OR REPLACE VIEW v_gotchas WITH (security_invoker = true) AS
486
+ SELECT id, feature_id, importance, title, content, rationale, tags, created_at
487
+ FROM memories
488
+ WHERE is_archived = false AND category = 'GOTCHA'
489
+ ORDER BY importance DESC, created_at DESC;
490
+
491
+ COMMENT ON VIEW v_gotchas IS 'All gotcha memories';
492
+
493
+ -- Architecture timeline
494
+ CREATE OR REPLACE VIEW v_architecture_timeline WITH (security_invoker = true) AS
495
+ SELECT id, feature_id, category, importance, title, content, rationale, tags, created_at, created_by
496
+ FROM memories
497
+ WHERE is_archived = false AND category IN ('ARCHITECTURE', 'DECISION')
498
+ ORDER BY created_at DESC;
499
+
500
+ COMMENT ON VIEW v_architecture_timeline IS 'Architecture decisions and patterns timeline';
501
+
502
+ -- Feature memory stats
503
+ CREATE OR REPLACE VIEW v_feature_memory_stats WITH (security_invoker = true) AS
504
+ SELECT
505
+ feature_id,
506
+ count(*) AS total_memories,
507
+ count(*) FILTER (WHERE importance = 'HIGH') AS high_importance,
508
+ count(*) FILTER (WHERE category = 'DECISION') AS decisions,
509
+ count(*) FILTER (WHERE category = 'GOTCHA') AS gotchas,
510
+ count(*) FILTER (WHERE category = 'PATTERN') AS patterns,
511
+ count(*) FILTER (WHERE category = 'ARCHITECTURE') AS architecture,
512
+ count(*) FILTER (WHERE category = 'BLOCKER') AS blockers,
513
+ max(created_at) AS last_memory_at
514
+ FROM memories
515
+ WHERE is_archived = false AND feature_id IS NOT NULL
516
+ GROUP BY feature_id;
517
+
518
+ COMMENT ON VIEW v_feature_memory_stats IS 'Memory statistics per feature';
519
+
520
+ -- ============================================================================
521
+ -- ARCHIVE VIEWS
522
+ -- ============================================================================
523
+
524
+ -- Recent archives
525
+ CREATE OR REPLACE VIEW v_recent_archives WITH (security_invoker = true) AS
526
+ SELECT
527
+ fa.id,
528
+ fa.feature_id,
529
+ f.name AS feature_name,
530
+ fa.summary,
531
+ fa.files_archived,
532
+ fa.total_size_bytes,
533
+ fa.release_version,
534
+ fa.archived_at,
535
+ fa.spec_snapshot->>'complexity_level' AS complexity_level,
536
+ array_length(fa.files_archived, 1) AS file_count
537
+ FROM feature_archives fa
538
+ JOIN features f ON f.id = fa.feature_id::text
539
+ ORDER BY fa.archived_at DESC
540
+ LIMIT 50;
541
+
542
+ COMMENT ON VIEW v_recent_archives IS 'Most recent 50 feature archives';
543
+
544
+ -- Archive stats
545
+ CREATE OR REPLACE VIEW v_archive_stats WITH (security_invoker = true) AS
546
+ SELECT
547
+ count(*) AS total_archives,
548
+ sum(total_size_bytes) AS total_storage_bytes,
549
+ sum(array_length(files_archived, 1)) AS total_files,
550
+ count(DISTINCT release_version) AS release_count,
551
+ min(archived_at) AS oldest_archive,
552
+ max(archived_at) AS newest_archive
553
+ FROM feature_archives;
554
+
555
+ COMMENT ON VIEW v_archive_stats IS 'Aggregate archive statistics';
556
+
557
+ -- Archives by release
558
+ CREATE OR REPLACE VIEW v_archives_by_release WITH (security_invoker = true) AS
559
+ SELECT
560
+ release_version,
561
+ count(*) AS feature_count,
562
+ sum(total_size_bytes) AS total_bytes,
563
+ array_agg(feature_id ORDER BY archived_at) AS features,
564
+ min(archived_at) AS release_date
565
+ FROM feature_archives
566
+ WHERE release_version IS NOT NULL
567
+ GROUP BY release_version
568
+ ORDER BY min(archived_at) DESC;
569
+
570
+ COMMENT ON VIEW v_archives_by_release IS 'Archives grouped by release version';
571
+
572
+ -- ============================================================================
573
+ -- CONFLICT VIEWS
574
+ -- ============================================================================
575
+
576
+ -- High risk conflicts
577
+ CREATE OR REPLACE VIEW v_high_risk_conflicts WITH (security_invoker = true) AS
578
+ SELECT
579
+ cd.id,
580
+ cd.feature_a_id,
581
+ cd.feature_b_id,
582
+ cd.file_path,
583
+ cd.conflict_risk,
584
+ cd.detected_at,
585
+ cd.detected_phase,
586
+ cd.status,
587
+ cd.strategy,
588
+ cd.notes,
589
+ fa.name AS feature_a_name,
590
+ fb.name AS feature_b_name,
591
+ fa.assigned_agent AS agent_a,
592
+ fb.assigned_agent AS agent_b
593
+ FROM conflict_detection cd
594
+ JOIN features fa ON cd.feature_a_id = fa.id
595
+ JOIN features fb ON cd.feature_b_id = fb.id
596
+ WHERE cd.conflict_risk IN ('HIGH', 'MEDIUM')
597
+ AND cd.status = 'DETECTED';
598
+
599
+ COMMENT ON VIEW v_high_risk_conflicts IS 'Unresolved high/medium risk conflicts between features';
@@ -0,0 +1,106 @@
1
+ -- ============================================================================
2
+ -- Odin SDD Framework - Seed Data
3
+ -- Version: 1.0.0
4
+ -- Created: 2026-02-16
5
+ -- Description: Initial seed data for Odin. Run after 003_views.sql.
6
+ -- Contains batch templates for common operations.
7
+ -- ============================================================================
8
+
9
+ -- ============================================================================
10
+ -- BATCH TEMPLATES
11
+ -- ============================================================================
12
+
13
+ -- Clear existing templates (idempotent)
14
+ DELETE FROM batch_templates WHERE created_by = 'system';
15
+
16
+ -- Template: Full Feature Status
17
+ INSERT INTO batch_templates (name, description, params, steps, output_config, created_by)
18
+ VALUES (
19
+ 'feature_full_status',
20
+ 'Get complete feature status including durations, gates, blockers, transitions',
21
+ '[{"name": "feature_id", "type": "string", "required": true}]',
22
+ '[
23
+ {"step_id": 0, "tool": "get_feature", "args": {"feature_id": "$params.feature_id"}, "on_error": "fail"},
24
+ {"step_id": 1, "tool": "get_phase_durations", "args": {"feature_id": "$params.feature_id"}, "on_error": "continue"},
25
+ {"step_id": 2, "tool": "get_quality_gates", "args": {"feature_id": "$params.feature_id"}, "on_error": "continue"},
26
+ {"step_id": 3, "tool": "get_blockers", "args": {"feature_id": "$params.feature_id"}, "on_error": "continue"},
27
+ {"step_id": 4, "tool": "get_phase_transitions", "args": {"feature_id": "$params.feature_id"}, "on_error": "continue"}
28
+ ]',
29
+ '{"include_steps": [0,1,2,3,4], "format": "full"}',
30
+ 'system'
31
+ );
32
+
33
+ -- Template: Feature with Learnings
34
+ INSERT INTO batch_templates (name, description, params, steps, output_config, created_by)
35
+ VALUES (
36
+ 'feature_with_learnings',
37
+ 'Get feature status plus all associated learnings',
38
+ '[{"name": "feature_id", "type": "string", "required": true}]',
39
+ '[
40
+ {"step_id": 0, "tool": "get_feature", "args": {"feature_id": "$params.feature_id"}, "on_error": "fail"},
41
+ {"step_id": 1, "tool": "get_learnings_for_feature", "args": {"feature_id": "$params.feature_id"}, "on_error": "continue"},
42
+ {"step_id": 2, "tool": "compute_feature_eval", "args": {"feature_id": "$params.feature_id"}, "on_error": "skip"}
43
+ ]',
44
+ '{"include_steps": [0,1,2], "format": "full"}',
45
+ 'system'
46
+ );
47
+
48
+ -- Template: System Health Check
49
+ INSERT INTO batch_templates (name, description, params, steps, output_config, created_by)
50
+ VALUES (
51
+ 'system_health_check',
52
+ 'Get system health, active alerts, and blocked features',
53
+ '[]',
54
+ '[
55
+ {"step_id": 0, "tool": "get_system_health", "args": {}, "on_error": "continue"},
56
+ {"step_id": 1, "tool": "get_active_alerts", "args": {}, "on_error": "continue"},
57
+ {"step_id": 2, "tool": "list_features", "args": {"status": "BLOCKED"}, "on_error": "continue"}
58
+ ]',
59
+ '{"include_steps": [0,1,2], "format": "full"}',
60
+ 'system'
61
+ );
62
+
63
+ -- Template: Learning Evolution
64
+ INSERT INTO batch_templates (name, description, params, steps, output_config, created_by)
65
+ VALUES (
66
+ 'learning_evolution',
67
+ 'Get full evolution chain for a learning',
68
+ '[{"name": "learning_id", "type": "uuid", "required": true}]',
69
+ '[
70
+ {"step_id": 0, "tool": "get_learning", "args": {"learning_id": "$params.learning_id"}, "on_error": "fail"},
71
+ {"step_id": 1, "tool": "get_learning_chain", "args": {"learning_id": "$params.learning_id"}, "on_error": "continue"},
72
+ {"step_id": 2, "tool": "detect_conflicts", "args": {"learning_id": "$params.learning_id"}, "on_error": "skip"}
73
+ ]',
74
+ '{"include_steps": [0,1,2], "format": "full"}',
75
+ 'system'
76
+ );
77
+
78
+ -- Template: Propagation Review
79
+ INSERT INTO batch_templates (name, description, params, steps, output_config, created_by)
80
+ VALUES (
81
+ 'propagation_review',
82
+ 'Get learnings ready for propagation and any open conflicts',
83
+ '[]',
84
+ '[
85
+ {"step_id": 0, "tool": "get_propagation_queue", "args": {}, "on_error": "continue"},
86
+ {"step_id": 1, "tool": "get_open_conflicts", "args": {}, "on_error": "continue"}
87
+ ]',
88
+ '{"include_steps": [0,1], "format": "full"}',
89
+ 'system'
90
+ );
91
+
92
+ -- ============================================================================
93
+ -- VERIFICATION
94
+ -- ============================================================================
95
+
96
+ -- Verify all templates were inserted
97
+ DO $$
98
+ DECLARE
99
+ template_count INTEGER;
100
+ BEGIN
101
+ SELECT COUNT(*) INTO template_count FROM batch_templates WHERE created_by = 'system';
102
+ IF template_count != 5 THEN
103
+ RAISE EXCEPTION 'Expected 5 system templates, found %', template_count;
104
+ END IF;
105
+ RAISE NOTICE 'Seed data verified: % batch templates created', template_count;
106
+ END $$;