ultra-builder-pro-cli 0.23.0 → 0.24.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 (91) hide show
  1. package/.ultra-template/docs/research/README.md +4 -4
  2. package/CHANGELOG.md +45 -0
  3. package/README.md +21 -18
  4. package/adapters/_shared/codex-assets.cjs +121 -65
  5. package/adapters/_shared/interaction-contract.cjs +7 -1
  6. package/adapters/_shared/provenance.cjs +7 -2
  7. package/adapters/_shared/runtime-assets.cjs +3 -2
  8. package/adapters/_shared/runtime-native.cjs +132 -0
  9. package/adapters/claude.js +60 -30
  10. package/adapters/codex.js +178 -81
  11. package/adapters/grok.js +372 -0
  12. package/adapters/kimi.js +7 -3
  13. package/adapters/opencode.js +210 -32
  14. package/agents/code-reviewer.md +4 -2
  15. package/agents/debugger.md +4 -1
  16. package/agents/review-code.md +7 -3
  17. package/agents/review-comments.md +7 -4
  18. package/agents/review-coordinator.md +11 -7
  19. package/agents/review-design.md +8 -4
  20. package/agents/review-errors.md +8 -4
  21. package/agents/review-spec.md +8 -5
  22. package/agents/review-tests.md +7 -4
  23. package/agents/tdd-runner.md +5 -2
  24. package/bin/install.js +9 -4
  25. package/bin/orchestrator.js +4 -13
  26. package/docs/AGENT-CONTEXT.md +141 -229
  27. package/docs/ARCHITECTURE.md +203 -494
  28. package/docs/ARTIFACT-AUTHORITY.md +26 -22
  29. package/docs/PLUGIN-ISOLATION-CONTRACT.md +12 -9
  30. package/docs/ROADMAP.md +85 -110
  31. package/docs/RUNTIME-COMPAT-MATRIX.md +139 -175
  32. package/docs/SKILL-AUTHORING.md +3 -3
  33. package/docs/STATE-DB-ACCESS-POLICY.md +13 -8
  34. package/docs/WORKFLOW-LIFECYCLE.md +174 -448
  35. package/hooks/README.md +11 -8
  36. package/hooks/active_task_context.py +16 -16
  37. package/hooks/adapters/grok.py +134 -0
  38. package/hooks/{context_spine.py → context_envelope.py} +26 -22
  39. package/hooks/health_check.py +19 -29
  40. package/hooks/pre_stop_check.py +22 -12
  41. package/hooks/subagent_tracker.py +1 -1
  42. package/hooks/workflow_checkpoint.py +14 -13
  43. package/hooks/workflow_context.py +11 -12
  44. package/hooks/workflow_resume.py +14 -13
  45. package/mcp-server/{breadcrumb.cjs → hook-context.cjs} +7 -9
  46. package/mcp-server/lib/baseline-workflow.cjs +36 -38
  47. package/mcp-server/lib/canonical-json.cjs +19 -0
  48. package/mcp-server/lib/change-workflow.cjs +596 -44
  49. package/mcp-server/lib/context-envelope.cjs +508 -0
  50. package/mcp-server/lib/decision-records.cjs +337 -0
  51. package/mcp-server/lib/doctor.cjs +91 -33
  52. package/mcp-server/lib/init-project.cjs +78 -39
  53. package/mcp-server/lib/managed-file-write.cjs +116 -0
  54. package/mcp-server/lib/plan-checkpoint.cjs +177 -0
  55. package/mcp-server/lib/project-context.cjs +178 -0
  56. package/mcp-server/lib/stage-checkpoints.cjs +309 -0
  57. package/mcp-server/lib/state-db.cjs +155 -24
  58. package/mcp-server/lib/task-ledger.cjs +522 -13
  59. package/mcp-server/lib/ultra-facade.cjs +630 -442
  60. package/mcp-server/lib/worker-packet.cjs +358 -0
  61. package/mcp-server/server.cjs +200 -1103
  62. package/orchestrator/daemon.cjs +27 -9
  63. package/orchestrator/parallel-orchestrator.cjs +111 -76
  64. package/orchestrator/session-runner.cjs +135 -34
  65. package/package.json +10 -3
  66. package/skills/ultra-change/SKILL.md +9 -8
  67. package/skills/ultra-deliver/SKILL.md +3 -3
  68. package/skills/ultra-dev/SKILL.md +18 -11
  69. package/skills/ultra-doctor/SKILL.md +2 -2
  70. package/skills/ultra-init/SKILL.md +6 -5
  71. package/skills/ultra-init/references/brownfield-adoption.md +11 -8
  72. package/skills/ultra-plan/SKILL.md +10 -8
  73. package/skills/ultra-research/SKILL.md +12 -7
  74. package/skills/ultra-review/SKILL.md +9 -6
  75. package/skills/ultra-review/references/unified-schema.md +2 -0
  76. package/skills/ultra-review/scripts/review_wait.py +8 -0
  77. package/skills/ultra-status/SKILL.md +2 -2
  78. package/skills/ultra-test/SKILL.md +4 -2
  79. package/skills/ultra-think/SKILL.md +7 -7
  80. package/skills/ultra-think/references/interaction-boundary.md +56 -0
  81. package/spec/cli-protocol.md +80 -199
  82. package/spec/mcp-tools.yaml +37 -2804
  83. package/spec/schemas/state-db.sql +107 -4
  84. package/spec/schemas/{task-ledger.v1.schema.json → task-ledger.v2.schema.json} +70 -6
  85. package/ultra-tools/commands/status.cjs +369 -243
  86. package/mcp-server/lib/context-spine.cjs +0 -1208
  87. package/mcp-server/lib/decision-dialogue.cjs +0 -1128
  88. package/mcp-server/lib/project-breadcrumb.cjs +0 -173
  89. package/mcp-server/lib/spec-learning.cjs +0 -284
  90. package/mcp-server/lib/workflow-state.cjs +0 -3129
  91. package/skills/ultra-think/references/decision-dialogue.md +0 -155
@@ -0,0 +1,309 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+
5
+ const ops = require('./state-ops.cjs');
6
+ const canonical = require('./canonical-json.cjs');
7
+
8
+ const STAGES = new Set(['init', 'research', 'change', 'plan', 'dev', 'test', 'review', 'deliver']);
9
+ const SCOPE_KEYS = Object.freeze([
10
+ ['task_id', 'task'],
11
+ ['change_id', 'change'],
12
+ ['baseline_id', 'baseline'],
13
+ ['project_id', 'project'],
14
+ ]);
15
+
16
+ class StageCheckpointError extends Error {
17
+ constructor(code, message, details) {
18
+ super(message);
19
+ this.name = 'StageCheckpointError';
20
+ this.code = code;
21
+ if (details) this.details = details;
22
+ }
23
+ }
24
+
25
+ function parseJson(value, fallback) {
26
+ try { return value == null ? fallback : JSON.parse(value); }
27
+ catch { return fallback; }
28
+ }
29
+
30
+ function normalizeScope(scope = {}) {
31
+ const matches = SCOPE_KEYS.filter(([key]) => (
32
+ typeof scope[key] === 'string' && scope[key].trim()
33
+ ));
34
+ if (matches.length !== 1) {
35
+ throw new StageCheckpointError(
36
+ 'VALIDATION_ERROR',
37
+ 'checkpoint scope must contain exactly one of project_id, baseline_id, change_id, or task_id',
38
+ );
39
+ }
40
+ const [key, type] = matches[0];
41
+ return { type, id: scope[key].trim() };
42
+ }
43
+
44
+ function validateStage(stage) {
45
+ if (!STAGES.has(stage)) {
46
+ throw new StageCheckpointError('VALIDATION_ERROR', `unsupported checkpoint stage: ${stage}`);
47
+ }
48
+ }
49
+
50
+ function normalizeDiagnostics(value) {
51
+ if (!Array.isArray(value)) {
52
+ throw new StageCheckpointError('VALIDATION_ERROR', 'diagnostics must be an array');
53
+ }
54
+ return value.map((item, index) => {
55
+ if (!item || typeof item !== 'object' || Array.isArray(item)) {
56
+ throw new StageCheckpointError('VALIDATION_ERROR', `diagnostics[${index}] must be an object`);
57
+ }
58
+ const code = String(item.code || '').trim();
59
+ if (!code) {
60
+ throw new StageCheckpointError('VALIDATION_ERROR', `diagnostics[${index}].code is required`);
61
+ }
62
+ const severity = item.severity || 'needs_attention';
63
+ if (!['warning', 'needs_attention', 'hard_conflict'].includes(severity)) {
64
+ throw new StageCheckpointError(
65
+ 'VALIDATION_ERROR',
66
+ `diagnostics[${index}].severity is invalid`,
67
+ );
68
+ }
69
+ return {
70
+ code,
71
+ severity,
72
+ ...(item.message ? { message: String(item.message) } : {}),
73
+ ...(item.details === undefined ? {} : { details: item.details }),
74
+ };
75
+ });
76
+ }
77
+
78
+ function checkpointDigest(value) {
79
+ return canonical.digest({
80
+ stage: value.stage,
81
+ scope_type: value.scope_type,
82
+ scope_id: value.scope_id,
83
+ revision: value.revision,
84
+ payload: value.payload,
85
+ evidence: value.evidence,
86
+ diagnostics: value.diagnostics,
87
+ context_envelope_id: value.context_envelope_id || null,
88
+ supersedes_id: value.supersedes_id || null,
89
+ });
90
+ }
91
+
92
+ function rowToCheckpoint(row) {
93
+ if (!row) return null;
94
+ const checkpoint = {
95
+ id: row.id,
96
+ stage: row.stage,
97
+ scope: { [`${row.scope_type}_id`]: row.scope_id },
98
+ scope_type: row.scope_type,
99
+ scope_id: row.scope_id,
100
+ revision: row.revision,
101
+ status: row.status,
102
+ payload: parseJson(row.payload_json, {}),
103
+ evidence: parseJson(row.evidence_json, []),
104
+ diagnostics: parseJson(row.diagnostics_json, []),
105
+ context_envelope_id: row.context_envelope_id,
106
+ digest: row.digest,
107
+ supersedes_id: row.supersedes_id,
108
+ idempotency_key: row.idempotency_key,
109
+ created_at: row.created_at,
110
+ updated_at: row.updated_at,
111
+ accepted_at: row.accepted_at,
112
+ };
113
+ const actual = checkpointDigest(checkpoint);
114
+ if (actual !== checkpoint.digest) {
115
+ throw new StageCheckpointError(
116
+ 'CHECKPOINT_DIGEST_MISMATCH',
117
+ `Stage Checkpoint database authority is corrupt: ${checkpoint.id}`,
118
+ { expected: checkpoint.digest, actual },
119
+ );
120
+ }
121
+ return checkpoint;
122
+ }
123
+
124
+ function readCheckpoint(db, id) {
125
+ return rowToCheckpoint(db.prepare('SELECT * FROM stage_checkpoints WHERE id = ?').get(id));
126
+ }
127
+
128
+ function listCheckpoints(db, { stage, scope, status, limit = 100 } = {}) {
129
+ const clauses = [];
130
+ const params = [];
131
+ if (stage) { validateStage(stage); clauses.push('stage = ?'); params.push(stage); }
132
+ if (scope) {
133
+ const normalized = normalizeScope(scope);
134
+ clauses.push('scope_type = ?', 'scope_id = ?');
135
+ params.push(normalized.type, normalized.id);
136
+ }
137
+ if (status) { clauses.push('status = ?'); params.push(status); }
138
+ const bounded = Math.min(Math.max(Number(limit) || 100, 1), 500);
139
+ return db.prepare(
140
+ `SELECT * FROM stage_checkpoints
141
+ ${clauses.length ? `WHERE ${clauses.join(' AND ')}` : ''}
142
+ ORDER BY stage, scope_type, scope_id, revision DESC
143
+ LIMIT ?`,
144
+ ).all(...params, bounded).map(rowToCheckpoint);
145
+ }
146
+
147
+ function existingByIdempotency(db, idempotencyKey) {
148
+ if (!idempotencyKey) return null;
149
+ return rowToCheckpoint(
150
+ db.prepare('SELECT * FROM stage_checkpoints WHERE idempotency_key = ?').get(idempotencyKey),
151
+ );
152
+ }
153
+
154
+ function saveDraft(db, input = {}) {
155
+ validateStage(input.stage);
156
+ const scope = normalizeScope(input.scope);
157
+ const idempotencyKey = String(input.idempotency_key || '').trim();
158
+ if (!idempotencyKey) {
159
+ throw new StageCheckpointError('VALIDATION_ERROR', 'idempotency_key is required');
160
+ }
161
+ const existingRetry = existingByIdempotency(db, idempotencyKey);
162
+ if (existingRetry) return existingRetry;
163
+ const payload = input.payload && typeof input.payload === 'object' && !Array.isArray(input.payload)
164
+ ? input.payload : {};
165
+ const evidence = Array.isArray(input.evidence) ? input.evidence : [];
166
+ const diagnostics = normalizeDiagnostics(input.diagnostics || []);
167
+ return ops.tx(db, () => {
168
+ const draft = db.prepare(
169
+ `SELECT * FROM stage_checkpoints
170
+ WHERE stage = ? AND scope_type = ? AND scope_id = ? AND status = 'draft'
171
+ ORDER BY revision DESC LIMIT 1`,
172
+ ).get(input.stage, scope.type, scope.id);
173
+ if (draft) {
174
+ const value = {
175
+ stage: input.stage,
176
+ scope_type: scope.type,
177
+ scope_id: scope.id,
178
+ revision: draft.revision,
179
+ payload,
180
+ evidence,
181
+ diagnostics,
182
+ context_envelope_id: input.context_envelope_id || null,
183
+ supersedes_id: draft.supersedes_id,
184
+ };
185
+ const digest = checkpointDigest(value);
186
+ db.prepare(
187
+ `UPDATE stage_checkpoints
188
+ SET payload_json = ?, evidence_json = ?, diagnostics_json = ?,
189
+ context_envelope_id = ?, digest = ?, idempotency_key = ?,
190
+ updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
191
+ WHERE id = ?`,
192
+ ).run(
193
+ JSON.stringify(payload),
194
+ JSON.stringify(evidence),
195
+ JSON.stringify(diagnostics),
196
+ input.context_envelope_id || null,
197
+ digest,
198
+ idempotencyKey,
199
+ draft.id,
200
+ );
201
+ return readCheckpoint(db, draft.id);
202
+ }
203
+ const accepted = db.prepare(
204
+ `SELECT id, revision FROM stage_checkpoints
205
+ WHERE stage = ? AND scope_type = ? AND scope_id = ? AND status = 'accepted'
206
+ ORDER BY revision DESC LIMIT 1`,
207
+ ).get(input.stage, scope.type, scope.id);
208
+ const revision = (accepted?.revision || 0) + 1;
209
+ const id = `checkpoint-${crypto.randomUUID()}`;
210
+ const value = {
211
+ stage: input.stage,
212
+ scope_type: scope.type,
213
+ scope_id: scope.id,
214
+ revision,
215
+ payload,
216
+ evidence,
217
+ diagnostics,
218
+ context_envelope_id: input.context_envelope_id || null,
219
+ supersedes_id: accepted?.id || null,
220
+ };
221
+ db.prepare(
222
+ `INSERT INTO stage_checkpoints
223
+ (id, stage, scope_type, scope_id, revision, payload_json, evidence_json,
224
+ diagnostics_json, context_envelope_id, digest, supersedes_id, idempotency_key)
225
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
226
+ ).run(
227
+ id,
228
+ input.stage,
229
+ scope.type,
230
+ scope.id,
231
+ revision,
232
+ JSON.stringify(payload),
233
+ JSON.stringify(evidence),
234
+ JSON.stringify(diagnostics),
235
+ input.context_envelope_id || null,
236
+ checkpointDigest(value),
237
+ accepted?.id || null,
238
+ idempotencyKey,
239
+ );
240
+ return readCheckpoint(db, id);
241
+ });
242
+ }
243
+
244
+ function acceptDraft(db, input = {}) {
245
+ const idempotencyKey = String(input.idempotency_key || '').trim();
246
+ if (!idempotencyKey) {
247
+ throw new StageCheckpointError('VALIDATION_ERROR', 'idempotency_key is required');
248
+ }
249
+ return ops.tx(db, () => {
250
+ const row = db.prepare('SELECT * FROM stage_checkpoints WHERE id = ?').get(input.id);
251
+ if (!row) throw new StageCheckpointError('CHECKPOINT_NOT_FOUND', `checkpoint not found: ${input.id}`);
252
+ if (row.status === 'accepted') return rowToCheckpoint(row);
253
+ if (row.status !== 'draft') {
254
+ throw new StageCheckpointError(
255
+ 'CHECKPOINT_NOT_MUTABLE',
256
+ `checkpoint ${input.id} is ${row.status}`,
257
+ );
258
+ }
259
+ if (row.supersedes_id) {
260
+ db.prepare(
261
+ `UPDATE stage_checkpoints SET status = 'superseded',
262
+ updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
263
+ WHERE id = ? AND status = 'accepted'`,
264
+ ).run(row.supersedes_id);
265
+ }
266
+ db.prepare(
267
+ `UPDATE stage_checkpoints
268
+ SET status = 'accepted', accepted_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now'),
269
+ updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
270
+ WHERE id = ?`,
271
+ ).run(row.id);
272
+ const accepted = readCheckpoint(db, row.id);
273
+ ops.appendEventInTx(db, {
274
+ type: 'ultra_checkpoint_accepted',
275
+ change_id: accepted.scope_type === 'change' ? accepted.scope_id : null,
276
+ task_id: accepted.scope_type === 'task' ? accepted.scope_id : null,
277
+ payload: {
278
+ checkpoint_id: accepted.id,
279
+ stage: accepted.stage,
280
+ revision: accepted.revision,
281
+ digest: accepted.digest,
282
+ },
283
+ });
284
+ return accepted;
285
+ });
286
+ }
287
+
288
+ function currentCheckpoint(db, stage, scope, { includeDraft = true } = {}) {
289
+ validateStage(stage);
290
+ const normalized = normalizeScope(scope);
291
+ const statuses = includeDraft ? "('draft','accepted')" : "('accepted')";
292
+ return rowToCheckpoint(db.prepare(
293
+ `SELECT * FROM stage_checkpoints
294
+ WHERE stage = ? AND scope_type = ? AND scope_id = ? AND status IN ${statuses}
295
+ ORDER BY CASE status WHEN 'draft' THEN 0 ELSE 1 END, revision DESC LIMIT 1`,
296
+ ).get(stage, normalized.type, normalized.id));
297
+ }
298
+
299
+ module.exports = {
300
+ StageCheckpointError,
301
+ STAGES,
302
+ normalizeScope,
303
+ readCheckpoint,
304
+ listCheckpoints,
305
+ saveDraft,
306
+ acceptDraft,
307
+ currentCheckpoint,
308
+ checkpointDigest,
309
+ };
@@ -9,7 +9,7 @@ const REPO_ROOT = process.env.UBP_RUNTIME_ROOT
9
9
  ? path.resolve(process.env.UBP_RUNTIME_ROOT)
10
10
  : path.resolve(__dirname, '..', '..');
11
11
  const SCHEMA_FILE = path.join(REPO_ROOT, 'spec', 'schemas', 'state-db.sql');
12
- const EXPECTED_VERSION = '20.0';
12
+ const EXPECTED_VERSION = '22.0';
13
13
  const KIMI_SCHEMA_VERSION = '9.1';
14
14
  const CONTEXT_SCHEMA_VERSION = '10.0';
15
15
  const BASELINE_SCHEMA_VERSION = '11.0';
@@ -22,6 +22,8 @@ const GIT_AUTHORITY_SCHEMA_VERSION = '17.0';
22
22
  const ADAPTIVE_SCHEMA_VERSION = '18.0';
23
23
  const DECISION_COMPLETION_SCHEMA_VERSION = '19.0';
24
24
  const ARTIFACT_REGISTRY_SCHEMA_VERSION = '20.0';
25
+ const KERNEL_SCHEMA_VERSION = '21.0';
26
+ const CHECKPOINT_NATIVE_SCHEMA_VERSION = '22.0';
25
27
 
26
28
  const MIGRATED_GAPS = Object.freeze([{
27
29
  id: 'legacy-rebaseline-required',
@@ -56,6 +58,10 @@ const REQUIRED_TABLES = Object.freeze([
56
58
  'workflow_steps',
57
59
  'decision_threads',
58
60
  'decision_items',
61
+ 'stage_checkpoints',
62
+ 'decision_records',
63
+ 'context_envelopes',
64
+ 'worker_packets',
59
65
  ]);
60
66
 
61
67
  class ActiveSessionLeaseConflictError extends Error {
@@ -173,6 +179,7 @@ function applyBaselineUpgrade(db, { legacyState = false } = {}) {
173
179
  classification_json TEXT NOT NULL DEFAULT '{}',
174
180
  provider_refs_json TEXT NOT NULL DEFAULT '{}',
175
181
  research_run_id TEXT,
182
+ research_checkpoint_id TEXT,
176
183
  approved_by TEXT,
177
184
  approval_note TEXT,
178
185
  started_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
@@ -226,6 +233,62 @@ function applyBaselineColumns(db) {
226
233
  db, 'baselines', columns, 'classification_json', "TEXT NOT NULL DEFAULT '{}'",
227
234
  ) || changed;
228
235
  changed = addColumnIfMissing(db, 'baselines', columns, 'research_run_id', 'TEXT') || changed;
236
+ changed = addColumnIfMissing(
237
+ db,
238
+ 'baselines',
239
+ columns,
240
+ 'research_checkpoint_id',
241
+ 'TEXT',
242
+ ) || changed;
243
+ if (columns.has('research_checkpoint_id')
244
+ && tableNames(db).includes('stage_checkpoints')) {
245
+ const result = db.prepare(
246
+ `UPDATE baselines
247
+ SET research_checkpoint_id = research_run_id
248
+ WHERE research_checkpoint_id IS NULL
249
+ AND research_run_id IS NOT NULL
250
+ AND EXISTS (
251
+ SELECT 1 FROM stage_checkpoints
252
+ WHERE stage_checkpoints.id = baselines.research_run_id
253
+ AND stage_checkpoints.stage = 'research'
254
+ )`,
255
+ ).run();
256
+ changed = result.changes > 0 || changed;
257
+ }
258
+ return changed;
259
+ }
260
+
261
+ function applyKernelIntegrityColumns(db) {
262
+ const tables = new Set(tableNames(db));
263
+ let changed = false;
264
+ if (tables.has('context_envelopes')) {
265
+ const columns = columnNames(db, 'context_envelopes');
266
+ changed = addColumnIfMissing(
267
+ db,
268
+ 'context_envelopes',
269
+ columns,
270
+ 'file_digest',
271
+ 'TEXT',
272
+ ) || changed;
273
+ }
274
+ if (tables.has('worker_packets')) {
275
+ const columns = columnNames(db, 'worker_packets');
276
+ for (const [name, definition] of [
277
+ ['file_digest', 'TEXT'],
278
+ ['status', "TEXT NOT NULL DEFAULT 'assigned' CHECK (status IN ('pending', 'assigned', 'abandoned'))"],
279
+ ['assigned_at', 'TEXT'],
280
+ ['abandoned_at', 'TEXT'],
281
+ ['abandon_reason', 'TEXT'],
282
+ ]) {
283
+ changed = addColumnIfMissing(
284
+ db,
285
+ 'worker_packets',
286
+ columns,
287
+ name,
288
+ definition,
289
+ ) || changed;
290
+ }
291
+ }
229
292
  return changed;
230
293
  }
231
294
 
@@ -422,7 +485,8 @@ function migrateAdaptiveWorkflowRuns(db, fromVersion = latestSchemaVersion(db))
422
485
  ).get();
423
486
  if ([
424
487
  ADAPTIVE_SCHEMA_VERSION, DECISION_COMPLETION_SCHEMA_VERSION,
425
- ARTIFACT_REGISTRY_SCHEMA_VERSION,
488
+ ARTIFACT_REGISTRY_SCHEMA_VERSION, KERNEL_SCHEMA_VERSION,
489
+ CHECKPOINT_NATIVE_SCHEMA_VERSION,
426
490
  ].includes(fromVersion) || existing) {
427
491
  return false;
428
492
  }
@@ -538,11 +602,11 @@ function migrateAdaptiveWorkflowRuns(db, fromVersion = latestSchemaVersion(db))
538
602
  return true;
539
603
  }
540
604
 
541
- function tableSupportsKimi(db, table) {
605
+ function tableSupportsRuntime(db, table, runtime) {
542
606
  const row = db.prepare(
543
607
  "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?",
544
608
  ).get(table);
545
- return typeof row?.sql === 'string' && row.sql.includes("'kimi'");
609
+ return typeof row?.sql === 'string' && row.sql.includes(`'${runtime}'`);
546
610
  }
547
611
 
548
612
  function baselineSupportsUnbornGit(db) {
@@ -676,6 +740,7 @@ function upgradeBaselineWorktreeConstraint(db, fromVersion = latestSchemaVersion
676
740
  classification_json TEXT NOT NULL DEFAULT '{}',
677
741
  provider_refs_json TEXT NOT NULL DEFAULT '{}',
678
742
  research_run_id TEXT,
743
+ research_checkpoint_id TEXT,
679
744
  approved_by TEXT,
680
745
  approval_note TEXT,
681
746
  started_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
@@ -687,7 +752,8 @@ function upgradeBaselineWorktreeConstraint(db, fromVersion = latestSchemaVersion
687
752
  repository_revision, repository_branch, worktree_state, worktree_digest,
688
753
  worktree_files_json, worktree_accepted, known_red_accepted, spec_refs_json,
689
754
  evidence_json, verification_json, unknowns_json, gaps_json, classification_json,
690
- provider_refs_json, research_run_id, approved_by, approval_note, started_at,
755
+ provider_refs_json, research_run_id, research_checkpoint_id,
756
+ approved_by, approval_note, started_at,
691
757
  updated_at, converged_at
692
758
  )
693
759
  SELECT
@@ -695,7 +761,8 @@ function upgradeBaselineWorktreeConstraint(db, fromVersion = latestSchemaVersion
695
761
  repository_revision, repository_branch, worktree_state, worktree_digest,
696
762
  worktree_files_json, worktree_accepted, known_red_accepted, spec_refs_json,
697
763
  evidence_json, verification_json, unknowns_json, gaps_json, classification_json,
698
- provider_refs_json, research_run_id, approved_by, approval_note, started_at,
764
+ provider_refs_json, research_run_id, research_checkpoint_id,
765
+ approved_by, approval_note, started_at,
699
766
  updated_at, converged_at
700
767
  FROM baselines;
701
768
  DROP TABLE baselines;
@@ -717,7 +784,11 @@ function upgradeBaselineWorktreeConstraint(db, fromVersion = latestSchemaVersion
717
784
 
718
785
  function upgradeRuntimeConstraints(db, fromVersion = latestSchemaVersion(db)) {
719
786
  assertNoDuplicateActiveSessionLeases(db);
720
- if (tableSupportsKimi(db, 'events') && tableSupportsKimi(db, 'sessions')) return false;
787
+ const missingKimi = !tableSupportsRuntime(db, 'events', 'kimi')
788
+ || !tableSupportsRuntime(db, 'sessions', 'kimi');
789
+ const missingGrok = !tableSupportsRuntime(db, 'events', 'grok')
790
+ || !tableSupportsRuntime(db, 'sessions', 'grok');
791
+ if (!missingKimi && !missingGrok) return false;
721
792
  const previousVersion = fromVersion || 'unknown';
722
793
  const foreignKeys = db.pragma('foreign_keys', { simple: true });
723
794
  db.pragma('foreign_keys = OFF');
@@ -732,7 +803,7 @@ function upgradeRuntimeConstraints(db, fromVersion = latestSchemaVersion(db)) {
732
803
  task_id TEXT,
733
804
  change_id TEXT,
734
805
  session_id TEXT,
735
- runtime TEXT CHECK (runtime IS NULL OR runtime IN ('claude', 'opencode', 'codex', 'kimi')),
806
+ runtime TEXT CHECK (runtime IS NULL OR runtime IN ('claude', 'opencode', 'codex', 'kimi', 'grok')),
736
807
  payload_json TEXT
737
808
  );
738
809
  INSERT INTO events_runtime_upgrade
@@ -749,7 +820,7 @@ function upgradeRuntimeConstraints(db, fromVersion = latestSchemaVersion(db)) {
749
820
  CREATE TABLE sessions_runtime_upgrade (
750
821
  sid TEXT PRIMARY KEY,
751
822
  task_id TEXT NOT NULL REFERENCES tasks(id),
752
- runtime TEXT NOT NULL CHECK (runtime IN ('claude', 'opencode', 'codex', 'kimi')),
823
+ runtime TEXT NOT NULL CHECK (runtime IN ('claude', 'opencode', 'codex', 'kimi', 'grok')),
753
824
  pid INTEGER,
754
825
  worktree_path TEXT NOT NULL,
755
826
  artifact_dir TEXT NOT NULL,
@@ -771,15 +842,28 @@ function upgradeRuntimeConstraints(db, fromVersion = latestSchemaVersion(db)) {
771
842
  CREATE UNIQUE INDEX sessions_one_active_task
772
843
  ON sessions(task_id) WHERE status = 'running';
773
844
  `);
774
- db.prepare(
775
- `INSERT INTO migration_history
776
- (from_version, to_version, direction, status, notes)
777
- VALUES (?, ?, 'forward', 'success', ?)`,
778
- ).run(
779
- previousVersion,
780
- KIMI_SCHEMA_VERSION,
781
- 'Add Kimi to durable event and session runtime constraints',
782
- );
845
+ if (missingKimi) {
846
+ db.prepare(
847
+ `INSERT INTO migration_history
848
+ (from_version, to_version, direction, status, notes)
849
+ VALUES (?, ?, 'forward', 'success', ?)`,
850
+ ).run(
851
+ previousVersion,
852
+ KIMI_SCHEMA_VERSION,
853
+ 'Add Kimi to durable event and session runtime constraints',
854
+ );
855
+ }
856
+ if (missingGrok) {
857
+ db.prepare(
858
+ `INSERT INTO migration_history
859
+ (from_version, to_version, direction, status, notes)
860
+ VALUES (?, ?, 'forward', 'success', ?)`,
861
+ ).run(
862
+ missingKimi ? KIMI_SCHEMA_VERSION : previousVersion,
863
+ KERNEL_SCHEMA_VERSION,
864
+ 'Add Grok to durable event and session runtime constraints',
865
+ );
866
+ }
783
867
  const violations = db.pragma('foreign_key_check');
784
868
  if (violations.length > 0) {
785
869
  throw new Error(`runtime constraint migration produced ${violations.length} foreign key violation(s)`);
@@ -935,6 +1019,7 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
935
1019
  WORKFLOW_SCHEMA_VERSION, AUTHORITY_SCHEMA_VERSION, SEMANTIC_SCHEMA_VERSION,
936
1020
  DIALOGUE_SCHEMA_VERSION, GIT_AUTHORITY_SCHEMA_VERSION, ADAPTIVE_SCHEMA_VERSION,
937
1021
  DECISION_COMPLETION_SCHEMA_VERSION, ARTIFACT_REGISTRY_SCHEMA_VERSION,
1022
+ KERNEL_SCHEMA_VERSION, CHECKPOINT_NATIVE_SCHEMA_VERSION,
938
1023
  ].includes(fromVersion)
939
1024
  && !contextMigration,
940
1025
  );
@@ -953,6 +1038,7 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
953
1038
  applyBaselineColumns(db);
954
1039
  applyChangeColumns(db);
955
1040
  applySemanticAuthorityColumns(db);
1041
+ applyKernelIntegrityColumns(db);
956
1042
  const artifactRegistryChanged = applyArtifactRegistryUpgrade(db);
957
1043
  const baselineMigration = db.prepare(
958
1044
  "SELECT 1 FROM migration_history WHERE to_version = '11.0' AND status = 'success' LIMIT 1",
@@ -962,6 +1048,7 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
962
1048
  AUTHORITY_SCHEMA_VERSION, SEMANTIC_SCHEMA_VERSION, DIALOGUE_SCHEMA_VERSION,
963
1049
  GIT_AUTHORITY_SCHEMA_VERSION, ADAPTIVE_SCHEMA_VERSION,
964
1050
  DECISION_COMPLETION_SCHEMA_VERSION, ARTIFACT_REGISTRY_SCHEMA_VERSION,
1051
+ KERNEL_SCHEMA_VERSION, CHECKPOINT_NATIVE_SCHEMA_VERSION,
965
1052
  ].includes(fromVersion)
966
1053
  && !baselineMigration) {
967
1054
  db.prepare(
@@ -993,7 +1080,8 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
993
1080
  db.prepare(
994
1081
  `UPDATE baselines SET mode = 'migrated', status = 'adopting',
995
1082
  classification_json = ?, gaps_json = ?, approved_by = NULL, approval_note = ?,
996
- converged_at = NULL, research_run_id = NULL, updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
1083
+ converged_at = NULL, research_run_id = NULL, research_checkpoint_id = NULL,
1084
+ updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
997
1085
  WHERE id = ?`,
998
1086
  ).run(
999
1087
  JSON.stringify(classification), JSON.stringify(gaps),
@@ -1034,6 +1122,7 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
1034
1122
  WORKFLOW_SCHEMA_VERSION, AUTHORITY_SCHEMA_VERSION, SEMANTIC_SCHEMA_VERSION,
1035
1123
  DIALOGUE_SCHEMA_VERSION, GIT_AUTHORITY_SCHEMA_VERSION, ADAPTIVE_SCHEMA_VERSION,
1036
1124
  DECISION_COMPLETION_SCHEMA_VERSION, ARTIFACT_REGISTRY_SCHEMA_VERSION,
1125
+ KERNEL_SCHEMA_VERSION, CHECKPOINT_NATIVE_SCHEMA_VERSION,
1037
1126
  ].includes(fromVersion) && !workflowMigration) {
1038
1127
  db.prepare(
1039
1128
  `INSERT INTO migration_history
@@ -1051,7 +1140,8 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
1051
1140
  if (fromVersion && ![
1052
1141
  AUTHORITY_SCHEMA_VERSION, SEMANTIC_SCHEMA_VERSION, DIALOGUE_SCHEMA_VERSION,
1053
1142
  GIT_AUTHORITY_SCHEMA_VERSION, ADAPTIVE_SCHEMA_VERSION, DECISION_COMPLETION_SCHEMA_VERSION,
1054
- ARTIFACT_REGISTRY_SCHEMA_VERSION,
1143
+ ARTIFACT_REGISTRY_SCHEMA_VERSION, KERNEL_SCHEMA_VERSION,
1144
+ CHECKPOINT_NATIVE_SCHEMA_VERSION,
1055
1145
  ].includes(fromVersion) && !authorityMigration) {
1056
1146
  db.prepare(
1057
1147
  `INSERT INTO migration_history
@@ -1069,7 +1159,8 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
1069
1159
  if (fromVersion && ![
1070
1160
  SEMANTIC_SCHEMA_VERSION, DIALOGUE_SCHEMA_VERSION, GIT_AUTHORITY_SCHEMA_VERSION,
1071
1161
  ADAPTIVE_SCHEMA_VERSION, DECISION_COMPLETION_SCHEMA_VERSION,
1072
- ARTIFACT_REGISTRY_SCHEMA_VERSION,
1162
+ ARTIFACT_REGISTRY_SCHEMA_VERSION, KERNEL_SCHEMA_VERSION,
1163
+ CHECKPOINT_NATIVE_SCHEMA_VERSION,
1073
1164
  ].includes(fromVersion) && !semanticMigration) {
1074
1165
  db.prepare(
1075
1166
  `INSERT INTO migration_history
@@ -1087,6 +1178,7 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
1087
1178
  if (fromVersion && ![
1088
1179
  DIALOGUE_SCHEMA_VERSION, GIT_AUTHORITY_SCHEMA_VERSION, ADAPTIVE_SCHEMA_VERSION,
1089
1180
  DECISION_COMPLETION_SCHEMA_VERSION, ARTIFACT_REGISTRY_SCHEMA_VERSION,
1181
+ KERNEL_SCHEMA_VERSION, CHECKPOINT_NATIVE_SCHEMA_VERSION,
1090
1182
  ].includes(fromVersion)
1091
1183
  && !dialogueMigration) {
1092
1184
  db.prepare(
@@ -1104,7 +1196,8 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
1104
1196
  ).get();
1105
1197
  if (fromVersion && ![
1106
1198
  GIT_AUTHORITY_SCHEMA_VERSION, ADAPTIVE_SCHEMA_VERSION, DECISION_COMPLETION_SCHEMA_VERSION,
1107
- ARTIFACT_REGISTRY_SCHEMA_VERSION,
1199
+ ARTIFACT_REGISTRY_SCHEMA_VERSION, KERNEL_SCHEMA_VERSION,
1200
+ CHECKPOINT_NATIVE_SCHEMA_VERSION,
1108
1201
  ].includes(fromVersion)
1109
1202
  && !gitStateMigration) {
1110
1203
  db.prepare(
@@ -1123,7 +1216,8 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
1123
1216
  ).get();
1124
1217
  if (fromVersion && ![
1125
1218
  ADAPTIVE_SCHEMA_VERSION, DECISION_COMPLETION_SCHEMA_VERSION,
1126
- ARTIFACT_REGISTRY_SCHEMA_VERSION,
1219
+ ARTIFACT_REGISTRY_SCHEMA_VERSION, KERNEL_SCHEMA_VERSION,
1220
+ CHECKPOINT_NATIVE_SCHEMA_VERSION,
1127
1221
  ].includes(fromVersion) && !adaptiveMigration) {
1128
1222
  db.prepare(
1129
1223
  `INSERT INTO migration_history
@@ -1142,6 +1236,7 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
1142
1236
  ).get();
1143
1237
  if (fromVersion && ![
1144
1238
  DECISION_COMPLETION_SCHEMA_VERSION, ARTIFACT_REGISTRY_SCHEMA_VERSION,
1239
+ KERNEL_SCHEMA_VERSION, CHECKPOINT_NATIVE_SCHEMA_VERSION,
1145
1240
  ].includes(fromVersion) && !completionMigration) {
1146
1241
  db.prepare(
1147
1242
  `INSERT INTO migration_history
@@ -1159,6 +1254,8 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
1159
1254
  "SELECT 1 FROM migration_history WHERE to_version = '20.0' AND status = 'success' LIMIT 1",
1160
1255
  ).get();
1161
1256
  if (fromVersion && fromVersion !== ARTIFACT_REGISTRY_SCHEMA_VERSION
1257
+ && fromVersion !== KERNEL_SCHEMA_VERSION
1258
+ && fromVersion !== CHECKPOINT_NATIVE_SCHEMA_VERSION
1162
1259
  && !artifactRegistryMigration) {
1163
1260
  db.prepare(
1164
1261
  `INSERT INTO migration_history
@@ -1172,6 +1269,39 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
1172
1269
  : 'Add the typed artifact registry, dependency graph, and orphan diagnostics',
1173
1270
  );
1174
1271
  }
1272
+ const kernelMigration = db.prepare(
1273
+ "SELECT 1 FROM migration_history WHERE to_version = '21.0' AND status = 'success' LIMIT 1",
1274
+ ).get();
1275
+ if (fromVersion
1276
+ && fromVersion !== KERNEL_SCHEMA_VERSION
1277
+ && fromVersion !== CHECKPOINT_NATIVE_SCHEMA_VERSION
1278
+ && !kernelMigration) {
1279
+ db.prepare(
1280
+ `INSERT INTO migration_history
1281
+ (from_version, to_version, direction, status, notes)
1282
+ VALUES (?, ?, 'forward', 'success', ?)`,
1283
+ ).run(
1284
+ ARTIFACT_REGISTRY_SCHEMA_VERSION,
1285
+ KERNEL_SCHEMA_VERSION,
1286
+ 'Add the seven-tool persistence kernel, reversible stage checkpoints, canonical context envelopes, normalized decisions, worker packets, and Grok runtime authority',
1287
+ );
1288
+ }
1289
+ const checkpointNativeMigration = db.prepare(
1290
+ "SELECT 1 FROM migration_history WHERE to_version = '22.0' AND status = 'success' LIMIT 1",
1291
+ ).get();
1292
+ if (fromVersion
1293
+ && fromVersion !== CHECKPOINT_NATIVE_SCHEMA_VERSION
1294
+ && !checkpointNativeMigration) {
1295
+ db.prepare(
1296
+ `INSERT INTO migration_history
1297
+ (from_version, to_version, direction, status, notes)
1298
+ VALUES (?, ?, 'forward', 'success', ?)`,
1299
+ ).run(
1300
+ KERNEL_SCHEMA_VERSION,
1301
+ CHECKPOINT_NATIVE_SCHEMA_VERSION,
1302
+ 'Bind Baseline research to Stage Checkpoints and add byte digests for Context Envelopes and Worker Packets',
1303
+ );
1304
+ }
1175
1305
  db.exec('CREATE INDEX IF NOT EXISTS tasks_change ON tasks(change_id) WHERE change_id IS NOT NULL');
1176
1306
  db.exec('CREATE INDEX IF NOT EXISTS events_change ON events(change_id, id)');
1177
1307
  ensureActiveSessionLeaseIndex(db);
@@ -1179,7 +1309,7 @@ function applyCompatibleUpgrades(db, fromVersion = latestSchemaVersion(db), { le
1179
1309
  'INSERT OR IGNORE INTO schema_version (version, description) VALUES (?, ?)',
1180
1310
  ).run(
1181
1311
  EXPECTED_VERSION,
1182
- 'Typed artifact registry, normalized dependency edges, and orphan diagnostics',
1312
+ 'Checkpoint-native baseline authority plus byte-bound Context Envelopes and Worker Packets',
1183
1313
  );
1184
1314
  })();
1185
1315
  }
@@ -1212,6 +1342,7 @@ function initStateDb(dbPath) {
1212
1342
  WORKFLOW_SCHEMA_VERSION, AUTHORITY_SCHEMA_VERSION, SEMANTIC_SCHEMA_VERSION,
1213
1343
  DIALOGUE_SCHEMA_VERSION, GIT_AUTHORITY_SCHEMA_VERSION, ADAPTIVE_SCHEMA_VERSION,
1214
1344
  DECISION_COMPLETION_SCHEMA_VERSION, ARTIFACT_REGISTRY_SCHEMA_VERSION,
1345
+ KERNEL_SCHEMA_VERSION, CHECKPOINT_NATIVE_SCHEMA_VERSION,
1215
1346
  ].includes(fromVersion);
1216
1347
  backupPath = migrationBackup(db, dbPath, fromVersion, existing);
1217
1348
  // This must precede every ALTER, table rebuild, or index creation. Runtime