ultra-builder-pro-cli 0.13.0 → 0.15.0

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 (172) hide show
  1. package/.ultra-template/docs/research/README.md +11 -7
  2. package/.ultra-template/specs/architecture.md +36 -36
  3. package/.ultra-template/specs/discovery.md +46 -33
  4. package/.ultra-template/specs/product.md +38 -29
  5. package/.ultra-template/specs/research-distillate.md +48 -0
  6. package/.ultra-template/tasks/contexts/TEMPLATE.md +11 -28
  7. package/CHANGELOG.md +86 -1
  8. package/README.md +40 -26
  9. package/adapters/_shared/codex-assets.cjs +29 -165
  10. package/adapters/_shared/file-ops.cjs +6 -2
  11. package/adapters/_shared/runtime-assets.cjs +1 -0
  12. package/adapters/claude.js +3 -2
  13. package/adapters/codex.js +1 -0
  14. package/adapters/kimi.js +3 -2
  15. package/adapters/opencode.js +33 -122
  16. package/agents/review-coordinator.md +9 -6
  17. package/docs/AGENT-CONTEXT.md +21 -11
  18. package/docs/ARCHITECTURE.md +41 -13
  19. package/docs/PLAN.zh-CN.md +3 -2
  20. package/docs/ROADMAP.md +9 -5
  21. package/docs/RUNTIME-COMPAT-MATRIX.md +6 -6
  22. package/docs/STATE-DB-ACCESS-POLICY.md +27 -25
  23. package/docs/WORKFLOW-LIFECYCLE.md +266 -0
  24. package/hooks/README.md +6 -1
  25. package/hooks/active_task_context.py +22 -50
  26. package/hooks/context_spine.py +61 -332
  27. package/hooks/health_check.py +29 -18
  28. package/hooks/pre_stop_check.py +28 -33
  29. package/hooks/subagent_tracker.py +54 -85
  30. package/hooks/workflow_checkpoint.py +39 -47
  31. package/hooks/workflow_context.py +4 -9
  32. package/hooks/workflow_resume.py +48 -128
  33. package/mcp-server/breadcrumb.cjs +22 -0
  34. package/mcp-server/hook-event.cjs +34 -0
  35. package/mcp-server/lib/archive-journal.cjs +17 -5
  36. package/mcp-server/lib/baseline-workflow.cjs +158 -18
  37. package/mcp-server/lib/change-workflow.cjs +550 -85
  38. package/mcp-server/lib/context-spine.cjs +242 -24
  39. package/mcp-server/lib/doctor.cjs +33 -3
  40. package/mcp-server/lib/init-project.cjs +210 -16
  41. package/mcp-server/lib/plan-store.cjs +4 -1
  42. package/mcp-server/lib/prd-parser.cjs +14 -41
  43. package/mcp-server/lib/pricing.cjs +7 -10
  44. package/mcp-server/lib/project-breadcrumb.cjs +145 -0
  45. package/mcp-server/lib/projector.cjs +57 -3
  46. package/mcp-server/lib/spec-learning.cjs +79 -2
  47. package/mcp-server/lib/state-db.cjs +145 -8
  48. package/mcp-server/lib/state-ops.cjs +160 -9
  49. package/mcp-server/lib/task-expander.cjs +9 -38
  50. package/mcp-server/lib/workflow-state.cjs +2292 -0
  51. package/mcp-server/server.cjs +182 -50
  52. package/orchestrator/daemon.cjs +1 -2
  53. package/orchestrator/dispatch-rules.cjs +5 -31
  54. package/orchestrator/planner/plan-builder.cjs +21 -12
  55. package/package.json +14 -6
  56. package/skills/cc-collab/SKILL.md +2 -2
  57. package/skills/codex-collab/SKILL.md +2 -3
  58. package/skills/ultra-change/SKILL.md +53 -68
  59. package/skills/ultra-change/references/change-contract.md +36 -0
  60. package/skills/ultra-deliver/SKILL.md +69 -79
  61. package/skills/ultra-deliver/references/baseline-reconciliation.md +20 -0
  62. package/skills/ultra-dev/SKILL.md +54 -59
  63. package/skills/ultra-doctor/SKILL.md +40 -71
  64. package/skills/ultra-init/SKILL.md +96 -103
  65. package/skills/ultra-init/references/brownfield-adoption.md +2 -2
  66. package/skills/ultra-plan/SKILL.md +79 -75
  67. package/skills/ultra-plan/references/semantic-preflight.md +18 -0
  68. package/skills/ultra-research/SKILL.md +87 -60
  69. package/skills/ultra-research/references/00-problem-validation.md +36 -0
  70. package/skills/ultra-research/references/01-opportunity-discovery.md +33 -0
  71. package/skills/ultra-research/references/02-market-assessment.md +30 -0
  72. package/skills/ultra-research/references/03-competitive-landscape.md +31 -0
  73. package/skills/ultra-research/references/04-product-strategy.md +32 -0
  74. package/skills/ultra-research/references/05-assumptions-validation.md +31 -0
  75. package/skills/ultra-research/references/10-user-personas.md +29 -0
  76. package/skills/ultra-research/references/11-user-scenarios.md +28 -0
  77. package/skills/ultra-research/references/20-user-stories.md +30 -0
  78. package/skills/ultra-research/references/21-features-scope.md +29 -0
  79. package/skills/ultra-research/references/22-success-metrics.md +28 -0
  80. package/skills/ultra-research/references/30-architecture-context.md +30 -0
  81. package/skills/ultra-research/references/31-solution-strategy.md +28 -0
  82. package/skills/ultra-research/references/32-building-blocks.md +28 -0
  83. package/skills/ultra-research/references/40-deployment.md +29 -0
  84. package/skills/ultra-research/references/41-quality-risks.md +28 -0
  85. package/skills/ultra-research/references/99-synthesis.md +35 -0
  86. package/skills/ultra-review/SKILL.md +57 -73
  87. package/skills/ultra-review/references/review-modes.md +27 -0
  88. package/skills/ultra-review/references/unified-schema.md +25 -0
  89. package/skills/ultra-review/scripts/review_wait.py +40 -3
  90. package/skills/ultra-status/SKILL.md +41 -45
  91. package/skills/ultra-test/SKILL.md +48 -55
  92. package/skills/ultra-verify/SKILL.md +22 -31
  93. package/skills/ultra-verify/references/{confidence-system.md → evidence-status.md} +3 -3
  94. package/skills/ultra-verify/scripts/verify_wait.py +54 -54
  95. package/spec/cli-protocol.md +7 -2
  96. package/spec/mcp-tools.yaml +422 -73
  97. package/spec/schemas/baseline-reconciliation.v1.schema.json +73 -0
  98. package/spec/schemas/delivery-report.v1.schema.json +111 -0
  99. package/spec/schemas/mcp-tools.schema.json +1 -1
  100. package/spec/schemas/state-db.sql +82 -1
  101. package/spec/schemas/tasks.v4.5.schema.json +8 -1
  102. package/spec/schemas/test-report.v1.schema.json +194 -0
  103. package/ultra-tools/cli.cjs +1 -1
  104. package/ultra-tools/commands/migrate.cjs +3 -3
  105. package/ultra-tools/commands/status.cjs +213 -12
  106. package/.ultra-template/delivery-report.json +0 -9
  107. package/.ultra-template/test-report.json +0 -8
  108. package/adapters/_shared/tests/file-ops.test.cjs +0 -54
  109. package/adapters/_shared/tests/frontmatter.test.cjs +0 -47
  110. package/adapters/_shared/tests/handbook.test.cjs +0 -101
  111. package/adapters/_shared/tests/path-rewrite.test.cjs +0 -60
  112. package/adapters/_shared/tests/provenance.test.cjs +0 -133
  113. package/adapters/_shared/tests/resolve-target.test.cjs +0 -75
  114. package/adapters/_shared/tests/runtime-assets.test.cjs +0 -131
  115. package/adapters/_shared/tests/settings-merge.test.cjs +0 -85
  116. package/adapters/_shared/tests/validate.test.cjs +0 -30
  117. package/adapters/tests/claude.test.cjs +0 -137
  118. package/adapters/tests/codex-hook.test.cjs +0 -115
  119. package/adapters/tests/codex.test.cjs +0 -423
  120. package/adapters/tests/kimi-hook.test.cjs +0 -122
  121. package/adapters/tests/kimi.test.cjs +0 -259
  122. package/adapters/tests/opencode.test.cjs +0 -371
  123. package/mcp-server/lib/archive-journal.test.cjs +0 -35
  124. package/mcp-server/lib/baseline-workflow.test.cjs +0 -477
  125. package/mcp-server/lib/change-workflow.test.cjs +0 -971
  126. package/mcp-server/lib/context-spine.test.cjs +0 -93
  127. package/mcp-server/lib/doctor.test.cjs +0 -148
  128. package/mcp-server/lib/llm-client.cjs +0 -157
  129. package/mcp-server/lib/llm-client.test.cjs +0 -156
  130. package/mcp-server/lib/plan-store.test.cjs +0 -132
  131. package/mcp-server/lib/prd-parser.test.cjs +0 -171
  132. package/mcp-server/lib/runtime-state.test.cjs +0 -92
  133. package/mcp-server/lib/spec-learning.test.cjs +0 -67
  134. package/mcp-server/lib/state-db.test.cjs +0 -314
  135. package/mcp-server/lib/task-expander.test.cjs +0 -324
  136. package/mcp-server/lib/topo.test.cjs +0 -158
  137. package/mcp-server/tests/circuit-breaker.test.cjs +0 -125
  138. package/mcp-server/tests/commit-hash-flow.test.cjs +0 -117
  139. package/mcp-server/tests/concurrency-update.test.cjs +0 -96
  140. package/mcp-server/tests/concurrency.test.cjs +0 -112
  141. package/mcp-server/tests/db-ops.test.cjs +0 -121
  142. package/mcp-server/tests/init-project.test.cjs +0 -393
  143. package/mcp-server/tests/migrate.test.cjs +0 -232
  144. package/mcp-server/tests/projector.test.cjs +0 -162
  145. package/mcp-server/tests/server-contract.test.cjs +0 -1471
  146. package/mcp-server/tests/staleness.test.cjs +0 -190
  147. package/mcp-server/tests/state-db.test.cjs +0 -106
  148. package/mcp-server/tests/state-ops.test.cjs +0 -449
  149. package/mcp-server/tests/tagged-tasks.test.cjs +0 -163
  150. package/mcp-server/tests/telemetry.test.cjs +0 -219
  151. package/orchestrator/planner/expand-prompt.cjs +0 -62
  152. package/orchestrator/planner/expand-prompt.test.cjs +0 -52
  153. package/orchestrator/planner/plan-builder.test.cjs +0 -165
  154. package/orchestrator/planner/prd-prompt.cjs +0 -44
  155. package/orchestrator/planner/prd-prompt.test.cjs +0 -30
  156. package/orchestrator/tests/auto-merge.test.cjs +0 -216
  157. package/orchestrator/tests/daemon.test.cjs +0 -311
  158. package/orchestrator/tests/dispatch-rules.test.cjs +0 -124
  159. package/orchestrator/tests/parallel-orchestrator.test.cjs +0 -233
  160. package/orchestrator/tests/phase-8b-gate.test.cjs +0 -183
  161. package/orchestrator/tests/recovery.test.cjs +0 -190
  162. package/orchestrator/tests/session-runner.test.cjs +0 -314
  163. package/orchestrator/tests/skill-miner.test.cjs +0 -147
  164. package/orchestrator/tests/worktree-manager.test.cjs +0 -148
  165. package/skills/ultra-research/references/architecture.md +0 -38
  166. package/skills/ultra-research/references/problem-product.md +0 -39
  167. package/skills/ultra-research/references/quality-delivery.md +0 -34
  168. package/skills/ultra-research/references/synthesis.md +0 -38
  169. package/skills/ultra-research/references/users-scope.md +0 -40
  170. package/ultra-tools/legacy-memory.test.cjs +0 -80
  171. package/ultra-tools/status-command.test.cjs +0 -181
  172. package/ultra-tools/system-command.test.cjs +0 -309
@@ -1,190 +0,0 @@
1
- 'use strict';
2
-
3
- // Phase 5.3 — Task staleness consumer:
4
- // • markTasksStaleBySpecSections: UPDATE pending tasks whose trace_to
5
- // matches a changed spec section → stale=1 + task_stale_marked event.
6
- // • consumeSpecChangedEvents: pulls unprocessed spec_changed events from
7
- // the event stream and applies the rule above, advancing a cursor.
8
-
9
- const test = require('node:test');
10
- const assert = require('node:assert/strict');
11
- const fs = require('node:fs');
12
- const os = require('node:os');
13
- const path = require('node:path');
14
-
15
- const { initStateDb, closeStateDb } = require('../lib/state-db.cjs');
16
- const ops = require('../lib/state-ops.cjs');
17
- const projector = require('../lib/projector.cjs');
18
-
19
- function freshDb() {
20
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ubp-stale-'));
21
- const file = path.join(dir, 'state.db');
22
- const init = initStateDb(file);
23
- return { dir, db: init.db };
24
- }
25
-
26
- function teardown(dir, db) {
27
- try { closeStateDb(db); } catch (_) { /* ignore */ }
28
- try { fs.rmSync(dir, { recursive: true, force: true }); } catch (_) { /* ignore */ }
29
- }
30
-
31
- function seed(db, id, { trace_to, status = 'pending' } = {}) {
32
- ops.createTask(db, { id, title: `task ${id}`, type: 'feature', priority: 'P2', trace_to });
33
- if (status !== 'pending') ops.patchTask(db, id, { status });
34
- }
35
-
36
- test('markTasksStaleBySpecSections: marks pending tasks with matching trace_to', () => {
37
- const { dir, db } = freshDb();
38
- try {
39
- seed(db, 't-prod', { trace_to: 'product' });
40
- seed(db, 't-arch', { trace_to: 'arch' });
41
- seed(db, 't-exec', { trace_to: 'exec' });
42
-
43
- const result = ops.markTasksStaleBySpecSections(db, ['product']);
44
- assert.equal(result.marked_count, 1);
45
- assert.deepEqual(result.marked_ids, ['t-prod']);
46
-
47
- assert.equal(ops.readTask(db, 't-prod').stale, true);
48
- assert.equal(ops.readTask(db, 't-arch').stale, false);
49
- assert.equal(ops.readTask(db, 't-exec').stale, false);
50
- } finally { teardown(dir, db); }
51
- });
52
-
53
- test('markTasksStaleBySpecSections: multi-section update', () => {
54
- const { dir, db } = freshDb();
55
- try {
56
- seed(db, 't-a', { trace_to: 'product' });
57
- seed(db, 't-b', { trace_to: 'arch' });
58
- seed(db, 't-c', { trace_to: 'exec' });
59
-
60
- const result = ops.markTasksStaleBySpecSections(db, ['product', 'arch']);
61
- assert.equal(result.marked_count, 2);
62
- assert.ok(result.marked_ids.includes('t-a'));
63
- assert.ok(result.marked_ids.includes('t-b'));
64
- assert.equal(ops.readTask(db, 't-c').stale, false);
65
- } finally { teardown(dir, db); }
66
- });
67
-
68
- test('markTasksStaleBySpecSections: skips non-pending tasks', () => {
69
- const { dir, db } = freshDb();
70
- try {
71
- seed(db, 't-running', { trace_to: 'product' });
72
- ops.patchTask(db, 't-running', { status: 'in_progress' });
73
-
74
- seed(db, 't-done', { trace_to: 'product' });
75
- ops.patchTask(db, 't-done', { status: 'in_progress' });
76
- ops.patchTask(db, 't-done', { status: 'completed' });
77
-
78
- seed(db, 't-pending', { trace_to: 'product' });
79
-
80
- const result = ops.markTasksStaleBySpecSections(db, ['product']);
81
- assert.equal(result.marked_count, 1);
82
- assert.deepEqual(result.marked_ids, ['t-pending']);
83
- } finally { teardown(dir, db); }
84
- });
85
-
86
- test('markTasksStaleBySpecSections: emits task_stale_marked event per task', () => {
87
- const { dir, db } = freshDb();
88
- try {
89
- seed(db, 't-e1', { trace_to: 'product' });
90
- seed(db, 't-e2', { trace_to: 'product' });
91
-
92
- const { events: before } = ops.subscribeEventsSince(db, { since_id: 0, limit: 500 });
93
- ops.markTasksStaleBySpecSections(db, ['product']);
94
- const { events: after } = ops.subscribeEventsSince(db, { since_id: 0, limit: 500 });
95
-
96
- const marked = after.slice(before.length).filter((e) => e.type === 'task_stale_marked');
97
- assert.equal(marked.length, 2);
98
- const taskIds = marked.map((e) => e.task_id).sort();
99
- assert.deepEqual(taskIds, ['t-e1', 't-e2']);
100
- } finally { teardown(dir, db); }
101
- });
102
-
103
- test('markTasksStaleBySpecSections: idempotent — re-mark already-stale task does not double-emit', () => {
104
- const { dir, db } = freshDb();
105
- try {
106
- seed(db, 't-idem', { trace_to: 'product' });
107
- ops.markTasksStaleBySpecSections(db, ['product']);
108
-
109
- const { events: before } = ops.subscribeEventsSince(db, { since_id: 0, limit: 500 });
110
- ops.markTasksStaleBySpecSections(db, ['product']);
111
- const { events: after } = ops.subscribeEventsSince(db, { since_id: 0, limit: 500 });
112
-
113
- const newEvents = after.slice(before.length);
114
- const marked = newEvents.filter((e) => e.type === 'task_stale_marked');
115
- assert.equal(marked.length, 0, 'should not re-emit for already-stale task');
116
- } finally { teardown(dir, db); }
117
- });
118
-
119
- test('consumeSpecChangedEvents: processes queued events and advances cursor', () => {
120
- const { dir, db } = freshDb();
121
- try {
122
- seed(db, 't-c1', { trace_to: 'product' });
123
- seed(db, 't-c2', { trace_to: 'arch' });
124
-
125
- ops.appendEvent(db, { type: 'spec_changed', payload: { sections: ['product'] } });
126
- ops.appendEvent(db, { type: 'spec_changed', payload: { sections: ['arch'] } });
127
-
128
- const result = ops.consumeSpecChangedEvents(db, { since_id: 0 });
129
- assert.equal(result.processed, 2);
130
- assert.ok(result.next_since_id > 0);
131
- assert.equal(ops.readTask(db, 't-c1').stale, true);
132
- assert.equal(ops.readTask(db, 't-c2').stale, true);
133
- } finally { teardown(dir, db); }
134
- });
135
-
136
- test('consumeSpecChangedEvents: cursor prevents reprocessing', () => {
137
- const { dir, db } = freshDb();
138
- try {
139
- seed(db, 't-cur', { trace_to: 'product' });
140
- ops.appendEvent(db, { type: 'spec_changed', payload: { sections: ['product'] } });
141
-
142
- const first = ops.consumeSpecChangedEvents(db, { since_id: 0 });
143
- assert.equal(first.processed, 1);
144
-
145
- // second call from the new cursor — no new spec_changed events.
146
- const second = ops.consumeSpecChangedEvents(db, { since_id: first.next_since_id });
147
- assert.equal(second.processed, 0);
148
- assert.equal(second.next_since_id, first.next_since_id);
149
- } finally { teardown(dir, db); }
150
- });
151
-
152
- test('consumeSpecChangedEvents: ignores non-spec_changed events', () => {
153
- const { dir, db } = freshDb();
154
- try {
155
- seed(db, 't-other', { trace_to: 'product' });
156
- ops.appendEvent(db, { type: 'task_failure', task_id: 't-other', payload: { reason: 'noise' } });
157
-
158
- const result = ops.consumeSpecChangedEvents(db, { since_id: 0 });
159
- assert.equal(result.processed, 0);
160
- assert.equal(ops.readTask(db, 't-other').stale, false);
161
- } finally { teardown(dir, db); }
162
- });
163
-
164
- test('projector: stale task context md carries STALE banner before body', () => {
165
- const { dir, db } = freshDb();
166
- const rootDir = dir;
167
- try {
168
- seed(db, 't-proj', { trace_to: 'product' });
169
- ops.markTasksStaleBySpecSections(db, ['product']);
170
-
171
- const result = projector.projectContext(db, 't-proj', {}, { rootDir });
172
- const text = fs.readFileSync(result.path, 'utf8');
173
- // Banner goes after YAML frontmatter end + blank line.
174
- const frontmatterEnd = text.indexOf('\n---', 3);
175
- assert.ok(frontmatterEnd > 0, 'frontmatter should exist');
176
- const body = text.slice(frontmatterEnd + 4);
177
- assert.match(body, /⚠️\s*STALE/, 'stale banner should render');
178
- assert.match(body, /spec/i, 'banner should mention spec');
179
- } finally { teardown(dir, db); }
180
- });
181
-
182
- test('projector: non-stale task context md has no STALE banner', () => {
183
- const { dir, db } = freshDb();
184
- try {
185
- seed(db, 't-fresh', { trace_to: 'product' });
186
- const result = projector.projectContext(db, 't-fresh', {}, { rootDir: dir });
187
- const text = fs.readFileSync(result.path, 'utf8');
188
- assert.doesNotMatch(text, /STALE/);
189
- } finally { teardown(dir, db); }
190
- });
@@ -1,106 +0,0 @@
1
- 'use strict';
2
-
3
- const test = require('node:test');
4
- const assert = require('node:assert/strict');
5
- const fs = require('node:fs');
6
- const os = require('node:os');
7
- const path = require('node:path');
8
-
9
- const stateDb = require('../lib/state-db.cjs');
10
-
11
- test('initStateDb upgrades a pre-10.0 database through Context Spine into baseline authority', () => {
12
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ubp-db-upgrade-'));
13
- const file = path.join(dir, 'state.db');
14
- try {
15
- const db = stateDb.openStateDb(file);
16
- db.exec(`
17
- CREATE TABLE tasks (
18
- id TEXT PRIMARY KEY,
19
- title TEXT NOT NULL,
20
- type TEXT NOT NULL,
21
- priority TEXT NOT NULL,
22
- complexity INTEGER,
23
- status TEXT NOT NULL DEFAULT 'pending',
24
- deps TEXT,
25
- files_modified TEXT,
26
- session_id TEXT,
27
- stale INTEGER NOT NULL DEFAULT 0,
28
- complexity_hint TEXT,
29
- tag TEXT,
30
- trace_to TEXT,
31
- context_file TEXT,
32
- completion_commit TEXT,
33
- parent_id TEXT,
34
- created_at TEXT NOT NULL,
35
- updated_at TEXT NOT NULL
36
- );
37
- CREATE TABLE events (
38
- id INTEGER PRIMARY KEY AUTOINCREMENT,
39
- ts TEXT NOT NULL,
40
- type TEXT NOT NULL,
41
- task_id TEXT,
42
- session_id TEXT,
43
- runtime TEXT,
44
- payload_json TEXT
45
- );
46
- CREATE TABLE schema_version (
47
- version TEXT PRIMARY KEY,
48
- applied_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
49
- description TEXT
50
- );
51
- INSERT INTO schema_version (version, applied_at, description)
52
- VALUES ('8A.1', '2026-01-01T00:00:00.000Z', 'legacy fixture');
53
- `);
54
- stateDb.closeStateDb(db);
55
-
56
- const upgraded = stateDb.initStateDb(file);
57
- const columns = upgraded.db.prepare('PRAGMA table_info(tasks)').all().map((row) => row.name);
58
- assert.ok(columns.includes('estimated_days'));
59
- assert.ok(columns.includes('change_id'));
60
- const eventColumns = upgraded.db.prepare('PRAGMA table_info(events)').all().map((row) => row.name);
61
- assert.ok(eventColumns.includes('change_id'));
62
- assert.equal(upgraded.schema_version, '12.0');
63
- assert.ok(upgraded.backup_path);
64
- assert.ok(fs.existsSync(upgraded.backup_path));
65
- assert.ok(upgraded.db.prepare("SELECT 1 FROM schema_version WHERE version = '10.0'").get());
66
- const contextColumns = upgraded.db.prepare('PRAGMA table_info(context_snapshots)').all()
67
- .map((row) => row.name);
68
- for (const column of ['role', 'gate', 'next_action', 'readiness', 'context_json', 'token_budget']) {
69
- assert.ok(contextColumns.includes(column), column);
70
- }
71
- assert.ok(upgraded.db.prepare(
72
- "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'spec_learning_candidates'",
73
- ).get());
74
- const baseline = upgraded.db.prepare(
75
- "SELECT mode, status FROM baselines WHERE id = 'migrated-baseline'",
76
- ).get();
77
- assert.deepEqual(baseline, { mode: 'migrated', status: 'adopting' });
78
- const contextMigration = upgraded.db.prepare(
79
- "SELECT from_version, to_version, notes FROM migration_history WHERE to_version = '10.0' ORDER BY id DESC LIMIT 1",
80
- ).get();
81
- assert.equal(contextMigration.from_version, '9.1');
82
- assert.equal(contextMigration.to_version, '10.0');
83
- assert.match(contextMigration.notes, /Context Spine/);
84
- const baselineMigration = upgraded.db.prepare(
85
- "SELECT from_version, to_version, notes FROM migration_history WHERE to_version = '11.0' ORDER BY id DESC LIMIT 1",
86
- ).get();
87
- assert.equal(baselineMigration.from_version, '10.0');
88
- assert.match(baselineMigration.notes, /baseline adoption/i);
89
- const adoptionMigration = upgraded.db.prepare(
90
- "SELECT from_version, to_version, notes FROM migration_history WHERE to_version = '12.0' ORDER BY id DESC LIMIT 1",
91
- ).get();
92
- assert.equal(adoptionMigration.from_version, '11.0');
93
- assert.match(adoptionMigration.notes, /gap ledger|re-adoption/i);
94
- const migrated = upgraded.db.prepare(
95
- "SELECT gaps_json, worktree_state FROM baselines WHERE id = 'migrated-baseline'",
96
- ).get();
97
- assert.equal(migrated.worktree_state, 'unavailable');
98
- assert.equal(JSON.parse(migrated.gaps_json)[0].category, 'baseline_blocker');
99
- assert.ok(upgraded.db.prepare(
100
- "SELECT 1 FROM migration_history WHERE from_version = '8A.1' AND to_version = '9.1' AND notes LIKE '%Kimi%'",
101
- ).get());
102
- stateDb.closeStateDb(upgraded.db);
103
- } finally {
104
- fs.rmSync(dir, { recursive: true, force: true });
105
- }
106
- });