ultra-builder-pro-cli 0.14.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 (154) 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 +44 -1
  8. package/README.md +34 -19
  9. package/adapters/_shared/codex-assets.cjs +6 -2
  10. package/adapters/_shared/file-ops.cjs +6 -2
  11. package/adapters/claude.js +3 -2
  12. package/adapters/codex.js +1 -0
  13. package/adapters/kimi.js +3 -2
  14. package/adapters/opencode.js +3 -2
  15. package/agents/review-coordinator.md +9 -6
  16. package/docs/AGENT-CONTEXT.md +15 -8
  17. package/docs/ARCHITECTURE.md +33 -12
  18. package/docs/PLAN.zh-CN.md +3 -2
  19. package/docs/ROADMAP.md +8 -4
  20. package/docs/RUNTIME-COMPAT-MATRIX.md +4 -4
  21. package/docs/STATE-DB-ACCESS-POLICY.md +27 -25
  22. package/docs/WORKFLOW-LIFECYCLE.md +266 -0
  23. package/hooks/README.md +6 -1
  24. package/hooks/health_check.py +12 -3
  25. package/hooks/subagent_tracker.py +52 -77
  26. package/mcp-server/hook-event.cjs +34 -0
  27. package/mcp-server/lib/archive-journal.cjs +17 -5
  28. package/mcp-server/lib/baseline-workflow.cjs +158 -18
  29. package/mcp-server/lib/change-workflow.cjs +550 -85
  30. package/mcp-server/lib/context-spine.cjs +242 -24
  31. package/mcp-server/lib/doctor.cjs +33 -3
  32. package/mcp-server/lib/init-project.cjs +210 -16
  33. package/mcp-server/lib/plan-store.cjs +4 -1
  34. package/mcp-server/lib/pricing.cjs +7 -10
  35. package/mcp-server/lib/project-breadcrumb.cjs +6 -0
  36. package/mcp-server/lib/projector.cjs +57 -3
  37. package/mcp-server/lib/spec-learning.cjs +79 -2
  38. package/mcp-server/lib/state-db.cjs +145 -8
  39. package/mcp-server/lib/state-ops.cjs +160 -9
  40. package/mcp-server/lib/workflow-state.cjs +2292 -0
  41. package/mcp-server/server.cjs +161 -15
  42. package/orchestrator/daemon.cjs +1 -2
  43. package/orchestrator/dispatch-rules.cjs +5 -31
  44. package/orchestrator/planner/plan-builder.cjs +21 -12
  45. package/package.json +13 -3
  46. package/skills/ultra-change/SKILL.md +53 -68
  47. package/skills/ultra-change/references/change-contract.md +36 -0
  48. package/skills/ultra-deliver/SKILL.md +69 -79
  49. package/skills/ultra-deliver/references/baseline-reconciliation.md +20 -0
  50. package/skills/ultra-dev/SKILL.md +54 -59
  51. package/skills/ultra-doctor/SKILL.md +40 -71
  52. package/skills/ultra-init/SKILL.md +96 -103
  53. package/skills/ultra-init/references/brownfield-adoption.md +2 -2
  54. package/skills/ultra-plan/SKILL.md +79 -85
  55. package/skills/ultra-plan/references/semantic-preflight.md +18 -0
  56. package/skills/ultra-research/SKILL.md +87 -60
  57. package/skills/ultra-research/references/00-problem-validation.md +36 -0
  58. package/skills/ultra-research/references/01-opportunity-discovery.md +33 -0
  59. package/skills/ultra-research/references/02-market-assessment.md +30 -0
  60. package/skills/ultra-research/references/03-competitive-landscape.md +31 -0
  61. package/skills/ultra-research/references/04-product-strategy.md +32 -0
  62. package/skills/ultra-research/references/05-assumptions-validation.md +31 -0
  63. package/skills/ultra-research/references/10-user-personas.md +29 -0
  64. package/skills/ultra-research/references/11-user-scenarios.md +28 -0
  65. package/skills/ultra-research/references/20-user-stories.md +30 -0
  66. package/skills/ultra-research/references/21-features-scope.md +29 -0
  67. package/skills/ultra-research/references/22-success-metrics.md +28 -0
  68. package/skills/ultra-research/references/30-architecture-context.md +30 -0
  69. package/skills/ultra-research/references/31-solution-strategy.md +28 -0
  70. package/skills/ultra-research/references/32-building-blocks.md +28 -0
  71. package/skills/ultra-research/references/40-deployment.md +29 -0
  72. package/skills/ultra-research/references/41-quality-risks.md +28 -0
  73. package/skills/ultra-research/references/99-synthesis.md +35 -0
  74. package/skills/ultra-review/SKILL.md +57 -73
  75. package/skills/ultra-review/references/review-modes.md +27 -0
  76. package/skills/ultra-review/references/unified-schema.md +25 -0
  77. package/skills/ultra-review/scripts/review_wait.py +40 -3
  78. package/skills/ultra-status/SKILL.md +41 -45
  79. package/skills/ultra-test/SKILL.md +48 -55
  80. package/skills/ultra-verify/SKILL.md +1 -1
  81. package/skills/ultra-verify/references/{confidence-system.md → evidence-status.md} +3 -3
  82. package/spec/cli-protocol.md +7 -2
  83. package/spec/mcp-tools.yaml +384 -63
  84. package/spec/schemas/baseline-reconciliation.v1.schema.json +73 -0
  85. package/spec/schemas/delivery-report.v1.schema.json +111 -0
  86. package/spec/schemas/mcp-tools.schema.json +1 -1
  87. package/spec/schemas/state-db.sql +82 -1
  88. package/spec/schemas/tasks.v4.5.schema.json +8 -1
  89. package/spec/schemas/test-report.v1.schema.json +194 -0
  90. package/ultra-tools/cli.cjs +1 -1
  91. package/ultra-tools/commands/migrate.cjs +3 -3
  92. package/ultra-tools/commands/status.cjs +213 -12
  93. package/.ultra-template/delivery-report.json +0 -9
  94. package/.ultra-template/test-report.json +0 -8
  95. package/adapters/_shared/tests/file-ops.test.cjs +0 -54
  96. package/adapters/_shared/tests/frontmatter.test.cjs +0 -47
  97. package/adapters/_shared/tests/handbook.test.cjs +0 -101
  98. package/adapters/_shared/tests/path-rewrite.test.cjs +0 -60
  99. package/adapters/_shared/tests/provenance.test.cjs +0 -133
  100. package/adapters/_shared/tests/resolve-target.test.cjs +0 -75
  101. package/adapters/_shared/tests/runtime-assets.test.cjs +0 -149
  102. package/adapters/_shared/tests/settings-merge.test.cjs +0 -85
  103. package/adapters/_shared/tests/validate.test.cjs +0 -30
  104. package/adapters/tests/claude.test.cjs +0 -138
  105. package/adapters/tests/codex-hook.test.cjs +0 -142
  106. package/adapters/tests/codex.test.cjs +0 -430
  107. package/adapters/tests/kimi-hook.test.cjs +0 -149
  108. package/adapters/tests/kimi.test.cjs +0 -259
  109. package/adapters/tests/opencode.test.cjs +0 -357
  110. package/mcp-server/lib/archive-journal.test.cjs +0 -35
  111. package/mcp-server/lib/baseline-workflow.test.cjs +0 -477
  112. package/mcp-server/lib/change-workflow.test.cjs +0 -971
  113. package/mcp-server/lib/context-spine.test.cjs +0 -93
  114. package/mcp-server/lib/doctor.test.cjs +0 -148
  115. package/mcp-server/lib/plan-store.test.cjs +0 -132
  116. package/mcp-server/lib/prd-parser.test.cjs +0 -82
  117. package/mcp-server/lib/project-breadcrumb.test.cjs +0 -112
  118. package/mcp-server/lib/runtime-state.test.cjs +0 -92
  119. package/mcp-server/lib/spec-learning.test.cjs +0 -67
  120. package/mcp-server/lib/state-db.test.cjs +0 -314
  121. package/mcp-server/lib/task-expander.test.cjs +0 -169
  122. package/mcp-server/lib/topo.test.cjs +0 -158
  123. package/mcp-server/tests/circuit-breaker.test.cjs +0 -125
  124. package/mcp-server/tests/commit-hash-flow.test.cjs +0 -117
  125. package/mcp-server/tests/concurrency-update.test.cjs +0 -96
  126. package/mcp-server/tests/concurrency.test.cjs +0 -112
  127. package/mcp-server/tests/db-ops.test.cjs +0 -121
  128. package/mcp-server/tests/init-project.test.cjs +0 -393
  129. package/mcp-server/tests/migrate.test.cjs +0 -232
  130. package/mcp-server/tests/projector.test.cjs +0 -162
  131. package/mcp-server/tests/server-contract.test.cjs +0 -1467
  132. package/mcp-server/tests/staleness.test.cjs +0 -190
  133. package/mcp-server/tests/state-db.test.cjs +0 -106
  134. package/mcp-server/tests/state-ops.test.cjs +0 -449
  135. package/mcp-server/tests/tagged-tasks.test.cjs +0 -163
  136. package/mcp-server/tests/telemetry.test.cjs +0 -219
  137. package/orchestrator/planner/plan-builder.test.cjs +0 -165
  138. package/orchestrator/tests/auto-merge.test.cjs +0 -216
  139. package/orchestrator/tests/daemon.test.cjs +0 -311
  140. package/orchestrator/tests/dispatch-rules.test.cjs +0 -124
  141. package/orchestrator/tests/parallel-orchestrator.test.cjs +0 -233
  142. package/orchestrator/tests/phase-8b-gate.test.cjs +0 -183
  143. package/orchestrator/tests/recovery.test.cjs +0 -190
  144. package/orchestrator/tests/session-runner.test.cjs +0 -314
  145. package/orchestrator/tests/skill-miner.test.cjs +0 -147
  146. package/orchestrator/tests/worktree-manager.test.cjs +0 -148
  147. package/skills/ultra-research/references/architecture.md +0 -38
  148. package/skills/ultra-research/references/problem-product.md +0 -39
  149. package/skills/ultra-research/references/quality-delivery.md +0 -34
  150. package/skills/ultra-research/references/synthesis.md +0 -38
  151. package/skills/ultra-research/references/users-scope.md +0 -40
  152. package/ultra-tools/legacy-memory.test.cjs +0 -80
  153. package/ultra-tools/status-command.test.cjs +0 -181
  154. 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
- });