@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,554 @@
1
+ -- ============================================================================
2
+ -- Odin v2 Phase Alignment
3
+ -- Version: 2.0.0
4
+ -- Created: 2026-03-09
5
+ -- Description: Aligns persisted phase numbers with the Odin v2 workflow by:
6
+ -- - remapping historical phase values from the 9-phase model to the 11-phase model
7
+ -- - updating core workflow functions to use Product/Reviewer numbering
8
+ -- - moving Complete from phase 8 to phase 10
9
+ --
10
+ -- Dependencies: Requires 005_odin_v2_schema.sql and 006_odin_v2_functions.sql
11
+ --
12
+ -- IMPORTANT: DO NOT RUN ON SUPABASE UNTIL READY FOR DEPLOYMENT
13
+ -- ============================================================================
14
+
15
+ -- ============================================================================
16
+ -- PRECHECK
17
+ -- ============================================================================
18
+
19
+ DO $$
20
+ BEGIN
21
+ IF EXISTS (
22
+ SELECT 1
23
+ FROM audit_log
24
+ WHERE operation = 'MIGRATION_007_PHASE_ALIGNMENT_APPLIED'
25
+ ) THEN
26
+ RAISE EXCEPTION '007_odin_v2_phase_alignment.sql has already been applied';
27
+ END IF;
28
+
29
+ IF NOT EXISTS (
30
+ SELECT 1
31
+ FROM pg_enum e
32
+ JOIN pg_type t ON t.oid = e.enumtypid
33
+ WHERE t.typname = 'phase' AND e.enumlabel = '10'
34
+ ) THEN
35
+ RAISE EXCEPTION 'phase enum is not v2-ready. Run 005_odin_v2_schema.sql before 007_odin_v2_phase_alignment.sql';
36
+ END IF;
37
+
38
+ IF to_regclass('public.agent_claims') IS NULL OR to_regclass('public.security_findings') IS NULL THEN
39
+ RAISE EXCEPTION 'v2 tables are missing. Run 005_odin_v2_schema.sql before 007_odin_v2_phase_alignment.sql';
40
+ END IF;
41
+
42
+ IF EXISTS (SELECT 1 FROM agent_claims)
43
+ OR EXISTS (SELECT 1 FROM policy_verdicts)
44
+ OR EXISTS (SELECT 1 FROM watcher_reviews)
45
+ OR EXISTS (SELECT 1 FROM security_findings) THEN
46
+ RAISE EXCEPTION '007_odin_v2_phase_alignment.sql must run before any v2 claim/watcher/security data is created';
47
+ END IF;
48
+ END;
49
+ $$;
50
+
51
+ -- ============================================================================
52
+ -- PHASE REMAP
53
+ -- Old numbering: 0=Planning, 1=Discovery, 2=Architect, 3=Guardian, 4=Builder,
54
+ -- 5=Integrator, 6=Documenter, 7=Release, 8=Complete
55
+ -- New numbering: 0=Planning, 1=Product, 2=Discovery, 3=Architect, 4=Guardian,
56
+ -- 5=Builder, 6=Reviewer, 7=Integrator, 8=Documenter,
57
+ -- 9=Release, 10=Complete
58
+ --
59
+ -- Mapping: 0->0, 1->2, 2->3, 3->4, 4->5, 5->7, 6->8, 7->9, 8->10
60
+ -- ============================================================================
61
+
62
+ UPDATE features
63
+ SET current_phase = CASE current_phase
64
+ WHEN '0' THEN '0'::phase
65
+ WHEN '1' THEN '2'::phase
66
+ WHEN '2' THEN '3'::phase
67
+ WHEN '3' THEN '4'::phase
68
+ WHEN '4' THEN '5'::phase
69
+ WHEN '5' THEN '7'::phase
70
+ WHEN '6' THEN '8'::phase
71
+ WHEN '7' THEN '9'::phase
72
+ WHEN '8' THEN '10'::phase
73
+ END
74
+ WHERE current_phase IN ('0', '1', '2', '3', '4', '5', '6', '7', '8');
75
+
76
+ UPDATE phase_transitions
77
+ SET from_phase = CASE from_phase
78
+ WHEN '0' THEN '0'::phase
79
+ WHEN '1' THEN '2'::phase
80
+ WHEN '2' THEN '3'::phase
81
+ WHEN '3' THEN '4'::phase
82
+ WHEN '4' THEN '5'::phase
83
+ WHEN '5' THEN '7'::phase
84
+ WHEN '6' THEN '8'::phase
85
+ WHEN '7' THEN '9'::phase
86
+ WHEN '8' THEN '10'::phase
87
+ END
88
+ WHERE from_phase IN ('0', '1', '2', '3', '4', '5', '6', '7', '8');
89
+
90
+ UPDATE phase_transitions
91
+ SET to_phase = CASE to_phase
92
+ WHEN '0' THEN '0'::phase
93
+ WHEN '1' THEN '2'::phase
94
+ WHEN '2' THEN '3'::phase
95
+ WHEN '3' THEN '4'::phase
96
+ WHEN '4' THEN '5'::phase
97
+ WHEN '5' THEN '7'::phase
98
+ WHEN '6' THEN '8'::phase
99
+ WHEN '7' THEN '9'::phase
100
+ WHEN '8' THEN '10'::phase
101
+ END
102
+ WHERE to_phase IN ('0', '1', '2', '3', '4', '5', '6', '7', '8');
103
+
104
+ UPDATE quality_gates
105
+ SET phase = CASE phase
106
+ WHEN '0' THEN '0'::phase
107
+ WHEN '1' THEN '2'::phase
108
+ WHEN '2' THEN '3'::phase
109
+ WHEN '3' THEN '4'::phase
110
+ WHEN '4' THEN '5'::phase
111
+ WHEN '5' THEN '7'::phase
112
+ WHEN '6' THEN '8'::phase
113
+ WHEN '7' THEN '9'::phase
114
+ WHEN '8' THEN '10'::phase
115
+ END
116
+ WHERE phase IN ('0', '1', '2', '3', '4', '5', '6', '7', '8');
117
+
118
+ UPDATE blockers
119
+ SET phase = CASE phase
120
+ WHEN '0' THEN '0'::phase
121
+ WHEN '1' THEN '2'::phase
122
+ WHEN '2' THEN '3'::phase
123
+ WHEN '3' THEN '4'::phase
124
+ WHEN '4' THEN '5'::phase
125
+ WHEN '5' THEN '7'::phase
126
+ WHEN '6' THEN '8'::phase
127
+ WHEN '7' THEN '9'::phase
128
+ WHEN '8' THEN '10'::phase
129
+ END
130
+ WHERE phase IN ('0', '1', '2', '3', '4', '5', '6', '7', '8');
131
+
132
+ UPDATE conflict_detection
133
+ SET detected_phase = CASE detected_phase
134
+ WHEN '0' THEN '0'::phase
135
+ WHEN '1' THEN '2'::phase
136
+ WHEN '2' THEN '3'::phase
137
+ WHEN '3' THEN '4'::phase
138
+ WHEN '4' THEN '5'::phase
139
+ WHEN '5' THEN '7'::phase
140
+ WHEN '6' THEN '8'::phase
141
+ WHEN '7' THEN '9'::phase
142
+ WHEN '8' THEN '10'::phase
143
+ END
144
+ WHERE detected_phase IN ('0', '1', '2', '3', '4', '5', '6', '7', '8');
145
+
146
+ UPDATE agent_invocations
147
+ SET phase = CASE phase
148
+ WHEN '0' THEN '0'::phase
149
+ WHEN '1' THEN '2'::phase
150
+ WHEN '2' THEN '3'::phase
151
+ WHEN '3' THEN '4'::phase
152
+ WHEN '4' THEN '5'::phase
153
+ WHEN '5' THEN '7'::phase
154
+ WHEN '6' THEN '8'::phase
155
+ WHEN '7' THEN '9'::phase
156
+ WHEN '8' THEN '10'::phase
157
+ END
158
+ WHERE phase IN ('0', '1', '2', '3', '4', '5', '6', '7', '8');
159
+
160
+ UPDATE feature_commits
161
+ SET phase = CASE phase
162
+ WHEN '0' THEN '0'::phase
163
+ WHEN '1' THEN '2'::phase
164
+ WHEN '2' THEN '3'::phase
165
+ WHEN '3' THEN '4'::phase
166
+ WHEN '4' THEN '5'::phase
167
+ WHEN '5' THEN '7'::phase
168
+ WHEN '6' THEN '8'::phase
169
+ WHEN '7' THEN '9'::phase
170
+ WHEN '8' THEN '10'::phase
171
+ END
172
+ WHERE phase IN ('0', '1', '2', '3', '4', '5', '6', '7', '8');
173
+
174
+ UPDATE phase_outputs
175
+ SET phase = CASE phase
176
+ WHEN '0' THEN '0'::phase
177
+ WHEN '1' THEN '2'::phase
178
+ WHEN '2' THEN '3'::phase
179
+ WHEN '3' THEN '4'::phase
180
+ WHEN '4' THEN '5'::phase
181
+ WHEN '5' THEN '7'::phase
182
+ WHEN '6' THEN '8'::phase
183
+ WHEN '7' THEN '9'::phase
184
+ WHEN '8' THEN '10'::phase
185
+ END
186
+ WHERE phase IN ('0', '1', '2', '3', '4', '5', '6', '7', '8');
187
+
188
+ UPDATE memories
189
+ SET phase = CASE phase
190
+ WHEN '0' THEN '0'::phase
191
+ WHEN '1' THEN '2'::phase
192
+ WHEN '2' THEN '3'::phase
193
+ WHEN '3' THEN '4'::phase
194
+ WHEN '4' THEN '5'::phase
195
+ WHEN '5' THEN '7'::phase
196
+ WHEN '6' THEN '8'::phase
197
+ WHEN '7' THEN '9'::phase
198
+ WHEN '8' THEN '10'::phase
199
+ ELSE NULL
200
+ END
201
+ WHERE phase IS NOT NULL;
202
+
203
+ UPDATE learnings
204
+ SET phase = CASE phase
205
+ WHEN '0' THEN '0'::phase
206
+ WHEN '1' THEN '2'::phase
207
+ WHEN '2' THEN '3'::phase
208
+ WHEN '3' THEN '4'::phase
209
+ WHEN '4' THEN '5'::phase
210
+ WHEN '5' THEN '7'::phase
211
+ WHEN '6' THEN '8'::phase
212
+ WHEN '7' THEN '9'::phase
213
+ WHEN '8' THEN '10'::phase
214
+ ELSE NULL
215
+ END
216
+ WHERE phase IS NOT NULL;
217
+
218
+ UPDATE agent_claims
219
+ SET phase = CASE phase
220
+ WHEN '0' THEN '0'::phase
221
+ WHEN '1' THEN '2'::phase
222
+ WHEN '2' THEN '3'::phase
223
+ WHEN '3' THEN '4'::phase
224
+ WHEN '4' THEN '5'::phase
225
+ WHEN '5' THEN '7'::phase
226
+ WHEN '6' THEN '8'::phase
227
+ WHEN '7' THEN '9'::phase
228
+ WHEN '8' THEN '10'::phase
229
+ END
230
+ WHERE phase IN ('0', '1', '2', '3', '4', '5', '6', '7', '8');
231
+
232
+ UPDATE security_findings
233
+ SET phase = CASE phase
234
+ WHEN '0' THEN '0'::phase
235
+ WHEN '1' THEN '2'::phase
236
+ WHEN '2' THEN '3'::phase
237
+ WHEN '3' THEN '4'::phase
238
+ WHEN '4' THEN '5'::phase
239
+ WHEN '5' THEN '7'::phase
240
+ WHEN '6' THEN '8'::phase
241
+ WHEN '7' THEN '9'::phase
242
+ WHEN '8' THEN '10'::phase
243
+ END
244
+ WHERE phase IN ('0', '1', '2', '3', '4', '5', '6', '7', '8');
245
+
246
+ -- ============================================================================
247
+ -- CORE FUNCTION OVERRIDES FOR V2 PHASE NUMBERING
248
+ -- ============================================================================
249
+
250
+ CREATE OR REPLACE FUNCTION transition_phase(
251
+ p_feature_id TEXT,
252
+ p_to_phase phase,
253
+ p_transitioned_by TEXT,
254
+ p_notes TEXT DEFAULT NULL
255
+ ) RETURNS phase_transitions AS $$
256
+ DECLARE
257
+ v_current_phase phase;
258
+ v_current_int INTEGER;
259
+ v_to_int INTEGER;
260
+ v_transition_type transition_type;
261
+ v_transition phase_transitions;
262
+ BEGIN
263
+ SELECT current_phase INTO v_current_phase FROM features WHERE id = p_feature_id;
264
+ IF NOT FOUND THEN
265
+ RAISE EXCEPTION 'Feature % not found', p_feature_id;
266
+ END IF;
267
+
268
+ v_current_int := v_current_phase::TEXT::INTEGER;
269
+ v_to_int := p_to_phase::TEXT::INTEGER;
270
+
271
+ IF v_to_int = v_current_int THEN
272
+ v_transition_type := 'FORWARD';
273
+ ELSIF v_to_int = v_current_int + 1 THEN
274
+ v_transition_type := 'FORWARD';
275
+ ELSIF v_to_int > v_current_int + 1 THEN
276
+ RAISE EXCEPTION 'Phase skip not allowed: cannot jump from phase % to phase %. '
277
+ 'Phases must advance sequentially (one at a time). '
278
+ 'Current: % (%), Target: % (%). '
279
+ 'All 11 phases must be executed - complexity level affects depth within each phase, not which phases run.',
280
+ v_current_int, v_to_int,
281
+ v_current_int,
282
+ CASE v_current_int
283
+ WHEN 0 THEN 'Planning'
284
+ WHEN 1 THEN 'Product'
285
+ WHEN 2 THEN 'Discovery'
286
+ WHEN 3 THEN 'Architect'
287
+ WHEN 4 THEN 'Guardian'
288
+ WHEN 5 THEN 'Builder'
289
+ WHEN 6 THEN 'Reviewer'
290
+ WHEN 7 THEN 'Integrator'
291
+ WHEN 8 THEN 'Documenter'
292
+ WHEN 9 THEN 'Release'
293
+ ELSE 'Complete'
294
+ END,
295
+ v_to_int,
296
+ CASE v_to_int
297
+ WHEN 0 THEN 'Planning'
298
+ WHEN 1 THEN 'Product'
299
+ WHEN 2 THEN 'Discovery'
300
+ WHEN 3 THEN 'Architect'
301
+ WHEN 4 THEN 'Guardian'
302
+ WHEN 5 THEN 'Builder'
303
+ WHEN 6 THEN 'Reviewer'
304
+ WHEN 7 THEN 'Integrator'
305
+ WHEN 8 THEN 'Documenter'
306
+ WHEN 9 THEN 'Release'
307
+ ELSE 'Complete'
308
+ END;
309
+ ELSIF v_to_int < v_current_int THEN
310
+ v_transition_type := 'BACKWARD';
311
+ END IF;
312
+
313
+ UPDATE features
314
+ SET current_phase = p_to_phase, updated_at = now()
315
+ WHERE id = p_feature_id;
316
+
317
+ INSERT INTO phase_transitions (feature_id, from_phase, to_phase, transitioned_by, transition_type, notes)
318
+ VALUES (p_feature_id, v_current_phase, p_to_phase, p_transitioned_by, v_transition_type, p_notes)
319
+ RETURNING * INTO v_transition;
320
+
321
+ INSERT INTO audit_log (feature_id, operation, agent_name, details) VALUES (
322
+ p_feature_id, 'PHASE_TRANSITION', p_transitioned_by,
323
+ jsonb_build_object(
324
+ 'from_phase', v_current_phase::TEXT,
325
+ 'to_phase', p_to_phase::TEXT,
326
+ 'transition_type', v_transition_type::TEXT
327
+ )
328
+ );
329
+
330
+ RETURN v_transition;
331
+ END;
332
+ $$ LANGUAGE plpgsql SET search_path = public;
333
+
334
+ COMMENT ON FUNCTION transition_phase IS 'Transition feature to a new phase with sequential enforcement for the v2 11-phase workflow. Forward transitions must advance exactly one phase at a time. Back transitions (rework) can go to any earlier phase.';
335
+
336
+ CREATE OR REPLACE FUNCTION complete_feature(p_feature_id TEXT, p_completed_by TEXT)
337
+ RETURNS BOOLEAN AS $$
338
+ DECLARE
339
+ v_missing_pairs TEXT;
340
+ BEGIN
341
+ WITH expected AS (
342
+ SELECT *
343
+ FROM (VALUES
344
+ ('1'::phase, 'product-agent'::text),
345
+ ('2'::phase, 'discovery-agent'::text),
346
+ ('3'::phase, 'architect-agent'::text),
347
+ ('4'::phase, 'guardian-agent'::text),
348
+ ('5'::phase, 'builder-agent'::text),
349
+ ('6'::phase, 'reviewer-agent'::text),
350
+ ('7'::phase, 'integrator-agent'::text),
351
+ ('8'::phase, 'documenter-agent'::text),
352
+ ('9'::phase, 'release-agent'::text)
353
+ ) AS t(phase, agent_name)
354
+ ),
355
+ actual AS (
356
+ SELECT DISTINCT phase, agent_name
357
+ FROM agent_invocations
358
+ WHERE feature_id = p_feature_id
359
+ AND ended_at IS NOT NULL
360
+ AND duration_ms IS NOT NULL
361
+ ),
362
+ missing AS (
363
+ SELECT e.phase, e.agent_name
364
+ FROM expected e
365
+ LEFT JOIN actual a
366
+ ON a.phase = e.phase
367
+ AND a.agent_name = e.agent_name
368
+ WHERE a.phase IS NULL
369
+ )
370
+ SELECT string_agg(
371
+ format('phase %s -> %s', m.phase::TEXT, m.agent_name),
372
+ ', '
373
+ ORDER BY m.phase::TEXT, m.agent_name
374
+ )
375
+ INTO v_missing_pairs
376
+ FROM missing m;
377
+
378
+ IF v_missing_pairs IS NOT NULL THEN
379
+ INSERT INTO quality_gates (
380
+ feature_id, gate_name, phase, status, approver, approval_notes, decision_log
381
+ ) VALUES (
382
+ p_feature_id,
383
+ 'agent_invocation_coverage',
384
+ '9',
385
+ 'REJECTED',
386
+ p_completed_by,
387
+ 'Missing completed agent invocation telemetry: ' || v_missing_pairs,
388
+ 'Completion blocked by telemetry coverage guardrail'
389
+ )
390
+ ON CONFLICT (feature_id, gate_name, phase)
391
+ DO UPDATE SET
392
+ status = EXCLUDED.status,
393
+ approver = EXCLUDED.approver,
394
+ approved_at = now(),
395
+ approval_notes = EXCLUDED.approval_notes,
396
+ decision_log = EXCLUDED.decision_log;
397
+
398
+ IF NOT EXISTS (
399
+ SELECT 1
400
+ FROM blockers
401
+ WHERE feature_id = p_feature_id
402
+ AND phase = '9'
403
+ AND blocker_type = 'VALIDATION_FAILED'
404
+ AND title = 'Agent invocation telemetry coverage failed'
405
+ AND status IN ('OPEN', 'IN_PROGRESS')
406
+ ) THEN
407
+ INSERT INTO blockers (
408
+ feature_id, blocker_type, phase, status, severity, title, description, created_by
409
+ ) VALUES (
410
+ p_feature_id,
411
+ 'VALIDATION_FAILED',
412
+ '9',
413
+ 'OPEN',
414
+ 'HIGH',
415
+ 'Agent invocation telemetry coverage failed',
416
+ 'Missing completed agent invocation telemetry: ' || v_missing_pairs,
417
+ p_completed_by
418
+ );
419
+ ELSE
420
+ UPDATE blockers
421
+ SET status = 'OPEN',
422
+ severity = 'HIGH',
423
+ description = 'Missing completed agent invocation telemetry: ' || v_missing_pairs,
424
+ escalation_notes = 'Coverage guardrail re-checked and still failing'
425
+ WHERE feature_id = p_feature_id
426
+ AND phase = '9'
427
+ AND blocker_type = 'VALIDATION_FAILED'
428
+ AND title = 'Agent invocation telemetry coverage failed'
429
+ AND status IN ('OPEN', 'IN_PROGRESS');
430
+ END IF;
431
+
432
+ UPDATE features
433
+ SET status = 'BLOCKED',
434
+ updated_at = now()
435
+ WHERE id = p_feature_id
436
+ AND status <> 'COMPLETED';
437
+
438
+ INSERT INTO audit_log (feature_id, operation, agent_name, details) VALUES (
439
+ p_feature_id,
440
+ 'AGENT_INVOCATION_COVERAGE_FAILED',
441
+ p_completed_by,
442
+ jsonb_build_object(
443
+ 'missing_pairs', v_missing_pairs,
444
+ 'checkpoint', 'complete_feature'
445
+ )
446
+ );
447
+
448
+ RAISE NOTICE 'Cannot complete feature % - missing telemetry coverage: %', p_feature_id, v_missing_pairs;
449
+ RETURN FALSE;
450
+ END IF;
451
+
452
+ IF EXISTS (SELECT 1 FROM blockers WHERE feature_id = p_feature_id AND status = 'OPEN') THEN
453
+ RAISE EXCEPTION 'Cannot complete feature % - has open blockers', p_feature_id;
454
+ END IF;
455
+
456
+ UPDATE features
457
+ SET status = 'COMPLETED',
458
+ current_phase = '10',
459
+ completed_at = now(),
460
+ updated_at = now()
461
+ WHERE id = p_feature_id;
462
+
463
+ IF NOT FOUND THEN
464
+ RAISE EXCEPTION 'Feature % not found', p_feature_id;
465
+ END IF;
466
+
467
+ INSERT INTO phase_transitions (feature_id, from_phase, to_phase, transitioned_by, notes, transition_type)
468
+ VALUES (p_feature_id, '9', '10', p_completed_by, 'Feature completed', 'FORWARD');
469
+
470
+ PERFORM compute_feature_eval(p_feature_id);
471
+
472
+ INSERT INTO audit_log (feature_id, operation, agent_name, details) VALUES (
473
+ p_feature_id, 'FEATURE_COMPLETED', p_completed_by,
474
+ jsonb_build_object('completed_at', now())
475
+ );
476
+
477
+ RETURN TRUE;
478
+ END;
479
+ $$ LANGUAGE plpgsql SET search_path = public;
480
+
481
+ COMMENT ON FUNCTION complete_feature IS 'Mark feature as completed, transition to phase 10, compute eval, and enforce v2 telemetry coverage for phases 1-9. Returns FALSE if telemetry coverage guardrail fails.';
482
+
483
+ CREATE OR REPLACE FUNCTION get_phase_durations(p_feature_id TEXT)
484
+ RETURNS TABLE (
485
+ phase phase,
486
+ phase_name TEXT,
487
+ started_at TIMESTAMPTZ,
488
+ ended_at TIMESTAMPTZ,
489
+ duration_minutes NUMERIC,
490
+ agent_invocation_count BIGINT,
491
+ total_agent_duration_ms BIGINT
492
+ ) AS $$
493
+ BEGIN
494
+ RETURN QUERY
495
+ WITH phase_windows AS (
496
+ SELECT
497
+ pt.id,
498
+ pt.to_phase,
499
+ pt.transitioned_at AS phase_started,
500
+ LEAD(pt.transitioned_at) OVER (ORDER BY pt.transitioned_at, pt.id) AS phase_ended
501
+ FROM phase_transitions pt
502
+ WHERE pt.feature_id = p_feature_id
503
+ ORDER BY pt.transitioned_at, pt.id
504
+ )
505
+ SELECT
506
+ pw.to_phase,
507
+ CASE pw.to_phase
508
+ WHEN '0' THEN 'Planning'
509
+ WHEN '1' THEN 'Product'
510
+ WHEN '2' THEN 'Discovery'
511
+ WHEN '3' THEN 'Architect'
512
+ WHEN '4' THEN 'Guardian'
513
+ WHEN '5' THEN 'Builder'
514
+ WHEN '6' THEN 'Reviewer'
515
+ WHEN '7' THEN 'Integrator'
516
+ WHEN '8' THEN 'Documenter'
517
+ WHEN '9' THEN 'Release'
518
+ WHEN '10' THEN 'Complete'
519
+ ELSE 'Unknown'
520
+ END,
521
+ pw.phase_started,
522
+ CASE WHEN pw.to_phase = '10' THEN pw.phase_started ELSE pw.phase_ended END,
523
+ ROUND(EXTRACT(EPOCH FROM (
524
+ COALESCE(CASE WHEN pw.to_phase = '10' THEN pw.phase_started ELSE pw.phase_ended END, now()) - pw.phase_started
525
+ )) / 60, 1),
526
+ COALESCE((
527
+ SELECT COUNT(*) FROM agent_invocations ai
528
+ WHERE ai.feature_id = p_feature_id AND ai.phase = pw.to_phase
529
+ ), 0),
530
+ COALESCE((
531
+ SELECT SUM(ai.duration_ms) FROM agent_invocations ai
532
+ WHERE ai.feature_id = p_feature_id AND ai.phase = pw.to_phase AND ai.ended_at IS NOT NULL
533
+ ), 0)::BIGINT
534
+ FROM phase_windows pw
535
+ ORDER BY pw.phase_started, pw.id;
536
+ END;
537
+ $$ LANGUAGE plpgsql SET search_path = public;
538
+
539
+ COMMENT ON FUNCTION get_phase_durations IS 'Get phase timing for a feature using the v2 11-phase names and numbering.';
540
+
541
+ INSERT INTO audit_log (feature_id, operation, agent_name, details)
542
+ VALUES (
543
+ NULL,
544
+ 'MIGRATION_007_PHASE_ALIGNMENT_APPLIED',
545
+ 'migration-007',
546
+ jsonb_build_object(
547
+ 'applied_at', now(),
548
+ 'mapping', '0->0, 1->2, 2->3, 3->4, 4->5, 5->7, 6->8, 7->9, 8->10'
549
+ )
550
+ );
551
+
552
+ -- ============================================================================
553
+ -- END OF PHASE ALIGNMENT
554
+ -- ============================================================================
@@ -0,0 +1,80 @@
1
+ -- Migration: 008_related_learnings
2
+ -- Created: 2026-03-17
3
+ -- Description: Add get_related_learnings() function for cross-feature knowledge retrieval.
4
+ -- Finds learnings from other features that share propagation targets with the given feature's learnings.
5
+ -- Falls back to tag intersection (>= 2 shared tags) when the feature has no propagation targets.
6
+ --
7
+ -- Rollback:
8
+ -- DROP FUNCTION IF EXISTS get_related_learnings(TEXT, INT);
9
+
10
+ CREATE OR REPLACE FUNCTION get_related_learnings(p_feature_id TEXT, p_limit INT DEFAULT 5)
11
+ RETURNS TABLE(
12
+ id UUID,
13
+ title TEXT,
14
+ category TEXT,
15
+ content TEXT,
16
+ confidence_score NUMERIC,
17
+ source_feature_id TEXT,
18
+ shared_domains TEXT[],
19
+ shared_domain_count INT
20
+ )
21
+ AS $$
22
+ WITH feature_targets AS (
23
+ SELECT DISTINCT lpt.target_type, lpt.target_path
24
+ FROM learning_propagation_targets lpt
25
+ JOIN learnings l ON l.id = lpt.learning_id
26
+ WHERE l.feature_id = p_feature_id
27
+ ),
28
+ target_count AS (
29
+ SELECT count(*) AS cnt FROM feature_targets
30
+ ),
31
+ -- Primary path: shared propagation targets
32
+ target_candidates AS (
33
+ SELECT
34
+ l.id, l.title, l.category::TEXT, l.content, l.confidence_score,
35
+ l.feature_id AS source_feature_id,
36
+ array_agg(DISTINCT lpt.target_type || ':' || COALESCE(lpt.target_path, '')
37
+ ORDER BY lpt.target_type || ':' || COALESCE(lpt.target_path, '')) AS shared_domains,
38
+ count(DISTINCT (lpt.target_type, lpt.target_path))::INT AS shared_domain_count
39
+ FROM learnings l
40
+ JOIN learning_propagation_targets lpt ON lpt.learning_id = l.id
41
+ JOIN feature_targets ft ON ft.target_type = lpt.target_type
42
+ AND (ft.target_path = lpt.target_path OR (ft.target_path IS NULL AND lpt.target_path IS NULL))
43
+ WHERE l.feature_id != p_feature_id
44
+ AND l.is_superseded = false
45
+ AND l.confidence_score >= 0.70
46
+ GROUP BY l.id, l.title, l.category, l.content, l.confidence_score, l.feature_id
47
+ ),
48
+ -- Fallback path: tag intersection (>= 2 shared tags) when no propagation targets exist
49
+ feature_tags AS (
50
+ SELECT DISTINCT unnest(l.tags) AS tag
51
+ FROM learnings l
52
+ WHERE l.feature_id = p_feature_id
53
+ AND l.tags IS NOT NULL
54
+ AND array_length(l.tags, 1) > 0
55
+ ),
56
+ tag_candidates AS (
57
+ SELECT
58
+ l.id, l.title, l.category::TEXT, l.content, l.confidence_score,
59
+ l.feature_id AS source_feature_id,
60
+ array_agg(DISTINCT ft.tag ORDER BY ft.tag) AS shared_domains,
61
+ count(DISTINCT ft.tag)::INT AS shared_domain_count
62
+ FROM learnings l,
63
+ LATERAL unnest(l.tags) AS lt(tag)
64
+ JOIN feature_tags ft ON ft.tag = lt.tag
65
+ WHERE l.feature_id != p_feature_id
66
+ AND l.is_superseded = false
67
+ AND l.confidence_score >= 0.70
68
+ AND (SELECT cnt FROM target_count) = 0
69
+ GROUP BY l.id, l.title, l.category, l.content, l.confidence_score, l.feature_id
70
+ HAVING count(DISTINCT ft.tag) >= 2
71
+ ),
72
+ combined AS (
73
+ SELECT * FROM target_candidates
74
+ UNION ALL
75
+ SELECT * FROM tag_candidates
76
+ )
77
+ SELECT * FROM combined
78
+ ORDER BY shared_domain_count DESC, confidence_score DESC
79
+ LIMIT p_limit;
80
+ $$ LANGUAGE sql STABLE SET search_path = public;
@@ -0,0 +1,23 @@
1
+ # Odin Schema Migrations
2
+
3
+ These SQL migration files define the Odin database schema. They are applied sequentially by the `odin.apply_migrations` tool using either direct PostgreSQL (`DATABASE_URL`) or the Supabase Management API (`SUPABASE_URL` + `SUPABASE_ACCESS_TOKEN`).
4
+
5
+ ## Usage
6
+
7
+ The `odin.apply_migrations` tool will:
8
+ 1. Create an `odin_migrations` tracking table (if it doesn't exist)
9
+ 2. Check which migrations have already been applied
10
+ 3. Apply pending migrations in filename order
11
+ 4. Record each successful migration in the tracking table
12
+
13
+ ## Requirements
14
+
15
+ Choose one connection path:
16
+
17
+ - `DATABASE_URL` — direct PostgreSQL connection string; recommended for local PostgreSQL or local Supabase Postgres
18
+ - `SUPABASE_URL` — your hosted Supabase project base URL (`https://<ref>.supabase.co`)
19
+ - `SUPABASE_ACCESS_TOKEN` — Supabase Management API personal access token (from https://supabase.com/dashboard/account/tokens)
20
+
21
+ ## File naming
22
+
23
+ Files are named `NNN_description.sql` and applied in lexicographic order.