@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.
- package/README.md +306 -0
- package/dist/adapters/archive/supabase.d.ts +19 -0
- package/dist/adapters/archive/supabase.d.ts.map +1 -0
- package/dist/adapters/archive/supabase.js +121 -0
- package/dist/adapters/archive/supabase.js.map +1 -0
- package/dist/adapters/archive/types.d.ts +26 -0
- package/dist/adapters/archive/types.d.ts.map +1 -0
- package/dist/adapters/archive/types.js +6 -0
- package/dist/adapters/archive/types.js.map +1 -0
- package/dist/adapters/formal-verification/tla-precheck.d.ts +22 -0
- package/dist/adapters/formal-verification/tla-precheck.d.ts.map +1 -0
- package/dist/adapters/formal-verification/tla-precheck.js +270 -0
- package/dist/adapters/formal-verification/tla-precheck.js.map +1 -0
- package/dist/adapters/formal-verification/types.d.ts +37 -0
- package/dist/adapters/formal-verification/types.d.ts.map +1 -0
- package/dist/adapters/formal-verification/types.js +6 -0
- package/dist/adapters/formal-verification/types.js.map +1 -0
- package/dist/adapters/review/semgrep.d.ts +12 -0
- package/dist/adapters/review/semgrep.d.ts.map +1 -0
- package/dist/adapters/review/semgrep.js +175 -0
- package/dist/adapters/review/semgrep.js.map +1 -0
- package/dist/adapters/review/types.d.ts +14 -0
- package/dist/adapters/review/types.d.ts.map +1 -0
- package/dist/adapters/review/types.js +6 -0
- package/dist/adapters/review/types.js.map +1 -0
- package/dist/adapters/skills/filesystem.d.ts +18 -0
- package/dist/adapters/skills/filesystem.d.ts.map +1 -0
- package/dist/adapters/skills/filesystem.js +398 -0
- package/dist/adapters/skills/filesystem.js.map +1 -0
- package/dist/adapters/skills/types.d.ts +19 -0
- package/dist/adapters/skills/types.d.ts.map +1 -0
- package/dist/adapters/skills/types.js +6 -0
- package/dist/adapters/skills/types.js.map +1 -0
- package/dist/adapters/sql-executor/direct-postgres.d.ts +15 -0
- package/dist/adapters/sql-executor/direct-postgres.d.ts.map +1 -0
- package/dist/adapters/sql-executor/direct-postgres.js +33 -0
- package/dist/adapters/sql-executor/direct-postgres.js.map +1 -0
- package/dist/adapters/sql-executor/supabase-management-api.d.ts +17 -0
- package/dist/adapters/sql-executor/supabase-management-api.d.ts.map +1 -0
- package/dist/adapters/sql-executor/supabase-management-api.js +40 -0
- package/dist/adapters/sql-executor/supabase-management-api.js.map +1 -0
- package/dist/adapters/sql-executor/types.d.ts +15 -0
- package/dist/adapters/sql-executor/types.d.ts.map +1 -0
- package/dist/adapters/sql-executor/types.js +6 -0
- package/dist/adapters/sql-executor/types.js.map +1 -0
- package/dist/adapters/workflow-state/in-memory.d.ts +69 -0
- package/dist/adapters/workflow-state/in-memory.d.ts.map +1 -0
- package/dist/adapters/workflow-state/in-memory.js +444 -0
- package/dist/adapters/workflow-state/in-memory.js.map +1 -0
- package/dist/adapters/workflow-state/supabase.d.ts +55 -0
- package/dist/adapters/workflow-state/supabase.d.ts.map +1 -0
- package/dist/adapters/workflow-state/supabase.js +823 -0
- package/dist/adapters/workflow-state/supabase.js.map +1 -0
- package/dist/adapters/workflow-state/types.d.ts +55 -0
- package/dist/adapters/workflow-state/types.d.ts.map +1 -0
- package/dist/adapters/workflow-state/types.js +6 -0
- package/dist/adapters/workflow-state/types.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +52 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +115 -0
- package/dist/config.js.map +1 -0
- package/dist/domain/actors.d.ts +10 -0
- package/dist/domain/actors.d.ts.map +1 -0
- package/dist/domain/actors.js +60 -0
- package/dist/domain/actors.js.map +1 -0
- package/dist/domain/development-evals.d.ts +9 -0
- package/dist/domain/development-evals.d.ts.map +1 -0
- package/dist/domain/development-evals.js +164 -0
- package/dist/domain/development-evals.js.map +1 -0
- package/dist/domain/matching.d.ts +8 -0
- package/dist/domain/matching.d.ts.map +1 -0
- package/dist/domain/matching.js +24 -0
- package/dist/domain/matching.js.map +1 -0
- package/dist/domain/phases.d.ts +10 -0
- package/dist/domain/phases.d.ts.map +1 -0
- package/dist/domain/phases.js +165 -0
- package/dist/domain/phases.js.map +1 -0
- package/dist/domain/quality-gates.d.ts +7 -0
- package/dist/domain/quality-gates.d.ts.map +1 -0
- package/dist/domain/quality-gates.js +8 -0
- package/dist/domain/quality-gates.js.map +1 -0
- package/dist/domain/resonance.d.ts +33 -0
- package/dist/domain/resonance.d.ts.map +1 -0
- package/dist/domain/resonance.js +100 -0
- package/dist/domain/resonance.js.map +1 -0
- package/dist/domain/tasks.d.ts +9 -0
- package/dist/domain/tasks.d.ts.map +1 -0
- package/dist/domain/tasks.js +57 -0
- package/dist/domain/tasks.js.map +1 -0
- package/dist/init.d.ts +7 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +387 -0
- package/dist/init.js.map +1 -0
- package/dist/schemas.d.ts +366 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +184 -0
- package/dist/schemas.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +243 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/apply-migrations.d.ts +21 -0
- package/dist/tools/apply-migrations.d.ts.map +1 -0
- package/dist/tools/apply-migrations.js +286 -0
- package/dist/tools/apply-migrations.js.map +1 -0
- package/dist/tools/archive-feature-release.d.ts +13 -0
- package/dist/tools/archive-feature-release.d.ts.map +1 -0
- package/dist/tools/archive-feature-release.js +182 -0
- package/dist/tools/archive-feature-release.js.map +1 -0
- package/dist/tools/capture-learning.d.ts +9 -0
- package/dist/tools/capture-learning.d.ts.map +1 -0
- package/dist/tools/capture-learning.js +53 -0
- package/dist/tools/capture-learning.js.map +1 -0
- package/dist/tools/explore-knowledge.d.ts +9 -0
- package/dist/tools/explore-knowledge.d.ts.map +1 -0
- package/dist/tools/explore-knowledge.js +142 -0
- package/dist/tools/explore-knowledge.js.map +1 -0
- package/dist/tools/get-claims-needing-review.d.ts +8 -0
- package/dist/tools/get-claims-needing-review.d.ts.map +1 -0
- package/dist/tools/get-claims-needing-review.js +21 -0
- package/dist/tools/get-claims-needing-review.js.map +1 -0
- package/dist/tools/get-development-eval-status.d.ts +8 -0
- package/dist/tools/get-development-eval-status.d.ts.map +1 -0
- package/dist/tools/get-development-eval-status.js +49 -0
- package/dist/tools/get-development-eval-status.js.map +1 -0
- package/dist/tools/get-feature-status.d.ts +8 -0
- package/dist/tools/get-feature-status.d.ts.map +1 -0
- package/dist/tools/get-feature-status.js +68 -0
- package/dist/tools/get-feature-status.js.map +1 -0
- package/dist/tools/get-next-phase.d.ts +8 -0
- package/dist/tools/get-next-phase.d.ts.map +1 -0
- package/dist/tools/get-next-phase.js +26 -0
- package/dist/tools/get-next-phase.js.map +1 -0
- package/dist/tools/prepare-phase-context.d.ts +9 -0
- package/dist/tools/prepare-phase-context.d.ts.map +1 -0
- package/dist/tools/prepare-phase-context.js +151 -0
- package/dist/tools/prepare-phase-context.js.map +1 -0
- package/dist/tools/record-commit.d.ts +8 -0
- package/dist/tools/record-commit.d.ts.map +1 -0
- package/dist/tools/record-commit.js +28 -0
- package/dist/tools/record-commit.js.map +1 -0
- package/dist/tools/record-eval-plan.d.ts +8 -0
- package/dist/tools/record-eval-plan.d.ts.map +1 -0
- package/dist/tools/record-eval-plan.js +40 -0
- package/dist/tools/record-eval-plan.js.map +1 -0
- package/dist/tools/record-eval-run.d.ts +8 -0
- package/dist/tools/record-eval-run.d.ts.map +1 -0
- package/dist/tools/record-eval-run.js +42 -0
- package/dist/tools/record-eval-run.js.map +1 -0
- package/dist/tools/record-merge.d.ts +8 -0
- package/dist/tools/record-merge.d.ts.map +1 -0
- package/dist/tools/record-merge.js +16 -0
- package/dist/tools/record-merge.js.map +1 -0
- package/dist/tools/record-phase-artifact.d.ts +8 -0
- package/dist/tools/record-phase-artifact.d.ts.map +1 -0
- package/dist/tools/record-phase-artifact.js +26 -0
- package/dist/tools/record-phase-artifact.js.map +1 -0
- package/dist/tools/record-phase-result.d.ts +9 -0
- package/dist/tools/record-phase-result.d.ts.map +1 -0
- package/dist/tools/record-phase-result.js +122 -0
- package/dist/tools/record-phase-result.js.map +1 -0
- package/dist/tools/record-pull-request.d.ts +8 -0
- package/dist/tools/record-pull-request.d.ts.map +1 -0
- package/dist/tools/record-pull-request.js +16 -0
- package/dist/tools/record-pull-request.js.map +1 -0
- package/dist/tools/record-quality-gate.d.ts +8 -0
- package/dist/tools/record-quality-gate.d.ts.map +1 -0
- package/dist/tools/record-quality-gate.js +26 -0
- package/dist/tools/record-quality-gate.js.map +1 -0
- package/dist/tools/record-watcher-review.d.ts +8 -0
- package/dist/tools/record-watcher-review.d.ts.map +1 -0
- package/dist/tools/record-watcher-review.js +18 -0
- package/dist/tools/record-watcher-review.js.map +1 -0
- package/dist/tools/run-policy-checks.d.ts +8 -0
- package/dist/tools/run-policy-checks.d.ts.map +1 -0
- package/dist/tools/run-policy-checks.js +38 -0
- package/dist/tools/run-policy-checks.js.map +1 -0
- package/dist/tools/run-review-checks.d.ts +9 -0
- package/dist/tools/run-review-checks.d.ts.map +1 -0
- package/dist/tools/run-review-checks.js +45 -0
- package/dist/tools/run-review-checks.js.map +1 -0
- package/dist/tools/start-feature.d.ts +8 -0
- package/dist/tools/start-feature.d.ts.map +1 -0
- package/dist/tools/start-feature.js +33 -0
- package/dist/tools/start-feature.js.map +1 -0
- package/dist/tools/submit-claim.d.ts +8 -0
- package/dist/tools/submit-claim.d.ts.map +1 -0
- package/dist/tools/submit-claim.js +45 -0
- package/dist/tools/submit-claim.js.map +1 -0
- package/dist/tools/verify-claims.d.ts +8 -0
- package/dist/tools/verify-claims.d.ts.map +1 -0
- package/dist/tools/verify-claims.js +39 -0
- package/dist/tools/verify-claims.js.map +1 -0
- package/dist/tools/verify-design.d.ts +8 -0
- package/dist/tools/verify-design.d.ts.map +1 -0
- package/dist/tools/verify-design.js +31 -0
- package/dist/tools/verify-design.js.map +1 -0
- package/dist/types.d.ts +333 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +52 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +24 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +50 -0
- package/dist/utils.js.map +1 -0
- package/migrations/001_schema.sql +795 -0
- package/migrations/002_functions.sql +2126 -0
- package/migrations/003_views.sql +599 -0
- package/migrations/004_seed.sql +106 -0
- package/migrations/005_odin_v2_schema.sql +217 -0
- package/migrations/006_odin_v2_functions.sql +671 -0
- package/migrations/007_odin_v2_phase_alignment.sql +554 -0
- package/migrations/008_related_learnings.sql +80 -0
- package/migrations/README.md +23 -0
- 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.
|