sneakoscope 4.1.1 → 4.2.1

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 (84) hide show
  1. package/README.md +13 -10
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/bin/sks.js +1 -1
  6. package/dist/cli/command-registry.js +1 -1
  7. package/dist/core/auto-review.js +1 -1
  8. package/dist/core/codex-control/codex-app-server-v2-client.js +86 -2
  9. package/dist/core/codex-control/codex-reliability-shield.js +26 -5
  10. package/dist/core/codex-control/codex-task-runner.js +7 -1
  11. package/dist/core/codex-control/model-call-concurrency.js +1 -1
  12. package/dist/core/commands/mad-db-command.js +146 -51
  13. package/dist/core/commands/mad-sks-command.js +15 -31
  14. package/dist/core/commands/qa-loop-command.js +23 -7
  15. package/dist/core/db-safety.js +35 -37
  16. package/dist/core/doctor/supabase-mcp-repair.js +2 -2
  17. package/dist/core/feature-registry.js +1 -1
  18. package/dist/core/fsx.js +1 -1
  19. package/dist/core/hooks-runtime.js +1 -1
  20. package/dist/core/init.js +5 -4
  21. package/dist/core/mad-db/mad-db-capability.js +203 -74
  22. package/dist/core/mad-db/mad-db-coordinator.js +287 -0
  23. package/dist/core/mad-db/mad-db-executor.js +156 -0
  24. package/dist/core/mad-db/mad-db-ledger.js +1 -1
  25. package/dist/core/mad-db/mad-db-lock.js +40 -0
  26. package/dist/core/mad-db/mad-db-operation-store.js +140 -0
  27. package/dist/core/mad-db/mad-db-policy-resolver.js +42 -22
  28. package/dist/core/mad-db/mad-db-policy.js +195 -0
  29. package/dist/core/mad-db/mad-db-postconditions.js +30 -0
  30. package/dist/core/mad-db/mad-db-recovery.js +27 -0
  31. package/dist/core/mad-db/mad-db-result-lifecycle.js +31 -102
  32. package/dist/core/mad-db/mad-db-runtime-profile.js +121 -0
  33. package/dist/core/mad-db/mad-db-target.js +64 -0
  34. package/dist/core/managed-assets/managed-assets-manifest.js +1 -1
  35. package/dist/core/pipeline-internals/runtime-core.js +40 -0
  36. package/dist/core/providers/glm/bench/glm-benchmark-types.js +1 -1
  37. package/dist/core/qa-loop/qa-app-server-driver.js +134 -0
  38. package/dist/core/qa-loop/qa-contract-v2.js +231 -0
  39. package/dist/core/qa-loop/qa-gate-v2.js +132 -0
  40. package/dist/core/qa-loop/qa-runtime-artifacts.js +53 -0
  41. package/dist/core/qa-loop/qa-surface-router.js +114 -0
  42. package/dist/core/qa-loop/qa-types.js +18 -0
  43. package/dist/core/qa-loop.js +83 -26
  44. package/dist/core/release/gate-manifest.js +1 -0
  45. package/dist/core/release/release-gate-dag.js +6 -5
  46. package/dist/core/release/sla-scheduler.js +1 -1
  47. package/dist/core/routes.js +42 -12
  48. package/dist/core/triwiki/triwiki-affected-graph.js +3 -2
  49. package/dist/core/version.js +1 -1
  50. package/dist/core/zellij/zellij-slot-column-anchor.js +5 -1
  51. package/dist/scripts/check-dist-runtime.js +3 -2
  52. package/dist/scripts/codex-0142-manifest-check.js +2 -1
  53. package/dist/scripts/codex-control-all-pipelines-check.js +1 -0
  54. package/dist/scripts/codex-control-model-capacity-fallback-check.js +53 -0
  55. package/dist/scripts/config-managed-merge-callsite-coverage-check.js +7 -1
  56. package/dist/scripts/loop-directive-check-lib.js +78 -1
  57. package/dist/scripts/mad-db-capability-check.js +13 -2
  58. package/dist/scripts/mad-db-command-check.js +7 -5
  59. package/dist/scripts/mad-db-hook-idempotency-check.js +21 -0
  60. package/dist/scripts/mad-db-ledger-check.js +2 -1
  61. package/dist/scripts/mad-db-lifecycle-hook-decision-check.js +5 -4
  62. package/dist/scripts/mad-db-mad-command-check.js +29 -16
  63. package/dist/scripts/mad-db-mcp-result-lifecycle-check.js +11 -10
  64. package/dist/scripts/mad-db-one-cycle-bounded-check.js +15 -18
  65. package/dist/scripts/mad-db-one-cycle-consumption-check.js +3 -3
  66. package/dist/scripts/mad-db-operation-lifecycle-blackbox.js +9 -9
  67. package/dist/scripts/mad-db-operation-lifecycle-ledger-check.js +6 -6
  68. package/dist/scripts/mad-db-parallel-lifecycle-check.js +24 -0
  69. package/dist/scripts/mad-db-policy-v2-check.js +20 -0
  70. package/dist/scripts/mad-db-priority-resolver-check.js +5 -5
  71. package/dist/scripts/mad-db-real-supabase-e2e.js +166 -0
  72. package/dist/scripts/mad-db-route-identity-check.js +28 -0
  73. package/dist/scripts/mad-db-runtime-profile-lifecycle-check.js +24 -0
  74. package/dist/scripts/mad-db-safety-conflict-matrix-check.js +3 -3
  75. package/dist/scripts/mad-db-skill-policy-snapshot-check.js +15 -0
  76. package/dist/scripts/qa-loop-app-server-driver-check.js +74 -0
  77. package/dist/scripts/qa-loop-surface-router-check.js +49 -0
  78. package/dist/scripts/release-check-dynamic-execute.js +1 -1
  79. package/dist/scripts/release-dag-full-coverage-check.js +6 -0
  80. package/dist/scripts/release-triwiki-first-runner-blackbox.js +5 -1
  81. package/dist/scripts/runtime-ts-rust-boundary-check.js +1 -1
  82. package/dist/scripts/triwiki-affected-graph-check.js +2 -2
  83. package/package.json +18 -5
  84. package/schemas/mad-db/mad-db-capability.schema.json +92 -19
@@ -1,48 +1,91 @@
1
1
  import path from 'node:path';
2
- import { appendJsonlBounded, nowIso, readJson, writeJsonAtomic } from '../fsx.js';
2
+ import { appendJsonlBounded, nowIso, readJson, sha256, writeJsonAtomic } from '../fsx.js';
3
3
  import { findLatestMission, missionDir } from '../mission.js';
4
- export const MAD_DB_CAPABILITY_SCHEMA = 'sks.mad-db-capability.v1';
4
+ import { withMadDbLock } from './mad-db-lock.js';
5
+ import { MAD_DB_POLICY } from './mad-db-policy.js';
6
+ export const MAD_DB_CAPABILITY_SCHEMA_V1 = 'sks.mad-db-capability.v1';
7
+ export const MAD_DB_CAPABILITY_SCHEMA = 'sks.mad-db-capability.v2';
5
8
  export const MAD_DB_CAPABILITY_FILE = 'mad-db-capability.json';
6
9
  export const MAD_DB_ACK = 'I AUTHORIZE ONE-CYCLE DB BREAK-GLASS';
7
- export const MAD_DB_MAX_TTL_MS = 2 * 60 * 60 * 1000;
10
+ export const MAD_DB_DEFAULT_TTL_MS = MAD_DB_POLICY.ttl.default_ms;
11
+ export const MAD_DB_MAX_TTL_MS = MAD_DB_POLICY.ttl.hard_max_ms;
8
12
  export async function createMadDbCapability(root, input) {
9
13
  if (input.ack !== MAD_DB_ACK)
10
14
  throw new Error('mad_db_ack_phrase_mismatch');
11
15
  const createdAt = nowIso();
12
- const ttlMs = Math.min(MAD_DB_MAX_TTL_MS, Math.max(1, Math.floor(Number(input.ttlMs || MAD_DB_MAX_TTL_MS))));
16
+ const ttlMs = Math.min(MAD_DB_MAX_TTL_MS, Math.max(1, Math.floor(Number(input.ttlMs || MAD_DB_DEFAULT_TTL_MS))));
17
+ const projectRef = String(input.projectRef || process.env.SKS_MAD_DB_PROJECT_REF || process.env.SKS_MAD_DB_E2E_PROJECT_REF || 'fixture-project-ref').trim();
18
+ const profilePath = input.profilePath || '.sneakoscope/missions/<mission>/mad-db/runtime/codex-mad-db.config.toml';
19
+ const profileSha256 = input.profileSha256 || sha256(`${input.missionId}:${projectRef}:placeholder-profile`);
13
20
  const capability = {
14
21
  schema: MAD_DB_CAPABILITY_SCHEMA,
22
+ revision: 1,
15
23
  mission_id: input.missionId,
16
24
  cycle_id: input.cycleId || `mad-db-${Date.now().toString(36)}`,
17
- enabled: true,
18
- created_at: createdAt,
25
+ project_root_hash: sha256(path.resolve(input.cwd || root)).slice(0, 24),
26
+ project_ref: projectRef,
27
+ target_environment: input.targetEnvironment || 'production',
28
+ allowed_schemas: input.allowedSchemas?.length ? input.allowedSchemas : ['public'],
29
+ codex_thread_id: input.codexThreadId ?? null,
30
+ runtime_session_id: input.runtimeSessionId || `mad-db-session-${Date.now().toString(36)}`,
31
+ operator_intent_hash: sha256(input.operatorIntent || input.ack || 'mad-db').slice(0, 32),
32
+ operator_ack_hash: sha256(input.ack).slice(0, 32),
33
+ scope: {
34
+ sql_plane: 'all_mutations',
35
+ control_plane: 'deny',
36
+ operations: input.operations?.length ? input.operations : [...MAD_DB_POLICY.sql_plane_allowed]
37
+ },
38
+ transport: {
39
+ profile_path: profilePath,
40
+ profile_sha256: profileSha256,
41
+ server_url_redacted: input.serverUrlRedacted || 'https://mcp.supabase.com/mcp?project_ref=<redacted>&features=database',
42
+ features: ['database'],
43
+ write_capable: true
44
+ },
45
+ issued_at: createdAt,
19
46
  expires_at: new Date(Date.now() + ttlMs).toISOString(),
20
- one_cycle_only: true,
21
- priority: 'highest',
22
- scope: 'all_database_mutations',
23
- operator_ack: {
24
- phrase: MAD_DB_ACK,
25
- accepted_at: createdAt,
26
- cwd: path.resolve(input.cwd || process.cwd())
47
+ closed_at: null,
48
+ status: input.status || 'issued',
49
+ counters: {
50
+ attempts: 0,
51
+ reserved: 0,
52
+ succeeded: 0,
53
+ failed: 0
27
54
  },
28
- consumed: false,
29
- consumed_at: null,
30
- consumed_by: null,
31
- max_operations: Math.max(1, Math.floor(Number(process.env.SKS_MAD_DB_MAX_OPERATIONS || 20))),
32
- operation_count: 0
55
+ legacy_compat: {
56
+ one_cycle_only: true,
57
+ priority: 'highest',
58
+ scope: 'all_database_mutations'
59
+ }
33
60
  };
34
61
  const dir = missionDir(root, input.missionId);
35
62
  await writeJsonAtomic(path.join(dir, MAD_DB_CAPABILITY_FILE), capability);
36
- await appendJsonlBounded(path.join(dir, 'mad-db-ledger.jsonl'), { ts: nowIso(), type: 'capability.created', mission_id: capability.mission_id, cycle_id: capability.cycle_id, expires_at: capability.expires_at });
63
+ await appendJsonlBounded(path.join(dir, 'mad-db-ledger.jsonl'), {
64
+ ts: nowIso(),
65
+ type: 'capability.created',
66
+ schema: capability.schema,
67
+ mission_id: capability.mission_id,
68
+ cycle_id: capability.cycle_id,
69
+ project_ref_hash: sha256(capability.project_ref).slice(0, 16),
70
+ runtime_session_id: capability.runtime_session_id,
71
+ expires_at: capability.expires_at,
72
+ status: capability.status
73
+ });
37
74
  return capability;
38
75
  }
39
76
  export async function readMadDbCapability(root, missionId) {
40
- const capability = await readJson(path.join(missionDir(root, missionId), MAD_DB_CAPABILITY_FILE), null);
41
- return capability?.schema === MAD_DB_CAPABILITY_SCHEMA ? capability : null;
77
+ const value = await readJson(path.join(missionDir(root, missionId), MAD_DB_CAPABILITY_FILE), null);
78
+ if (value?.schema === MAD_DB_CAPABILITY_SCHEMA)
79
+ return value;
80
+ if (value?.schema === MAD_DB_CAPABILITY_SCHEMA_V1)
81
+ return migrateV1Capability(value, missionId);
82
+ return null;
42
83
  }
43
84
  export async function resolveMadDbMissionId(root, state = {}, explicitMissionId = null) {
44
85
  if (explicitMissionId && explicitMissionId !== 'latest')
45
86
  return explicitMissionId;
87
+ if (state?.mad_db_capability_mission_id)
88
+ return String(state.mad_db_capability_mission_id);
46
89
  if (state?.mission_id)
47
90
  return String(state.mission_id);
48
91
  return findLatestMission(root);
@@ -51,74 +94,160 @@ export function isMadDbCapabilityActive(capability, nowMs = Date.now()) {
51
94
  if (!capability)
52
95
  return false;
53
96
  const expires = Date.parse(capability.expires_at || '');
54
- return capability.enabled === true
55
- && capability.consumed !== true
56
- && capability.one_cycle_only === true
57
- && Number(capability.operation_count || 0) < Number(capability.max_operations || 20)
97
+ return capability.schema === MAD_DB_CAPABILITY_SCHEMA
98
+ && ['transport_ready', 'active'].includes(capability.status)
99
+ && Boolean(capability.project_ref)
100
+ && capability.transport?.write_capable === true
101
+ && capability.transport?.features?.[0] === 'database'
58
102
  && Number.isFinite(expires)
59
103
  && expires > nowMs;
60
104
  }
105
+ export async function activateMadDbCapability(root, missionId) {
106
+ return updateMadDbCapability(root, missionId, (capability) => ({
107
+ ...capability,
108
+ status: capability.status === 'issued' ? 'active' : capability.status
109
+ }));
110
+ }
111
+ export async function markMadDbTransportReady(root, missionId) {
112
+ return updateMadDbCapability(root, missionId, (capability) => ({
113
+ ...capability,
114
+ status: capability.status === 'issued' ? 'transport_ready' : capability.status
115
+ }));
116
+ }
117
+ export async function updateMadDbCapabilityCounters(root, missionId, delta) {
118
+ return updateMadDbCapability(root, missionId, (capability) => ({
119
+ ...capability,
120
+ counters: {
121
+ attempts: capability.counters.attempts + Number(delta.attemptsDelta || 0),
122
+ reserved: capability.counters.reserved + Number(delta.reservedDelta || 0),
123
+ succeeded: capability.counters.succeeded + Number(delta.succeededDelta || 0),
124
+ failed: capability.counters.failed + Number(delta.failedDelta || 0)
125
+ }
126
+ }));
127
+ }
128
+ export async function updateMadDbCapability(root, missionId, mutator) {
129
+ return withMadDbLock(root, missionId, 'capability', async () => {
130
+ const current = await readMadDbCapability(root, missionId);
131
+ if (!current)
132
+ return null;
133
+ const next = mutator(current);
134
+ const updated = {
135
+ ...next,
136
+ revision: Number(current.revision || 0) + 1
137
+ };
138
+ await writeJsonAtomic(path.join(missionDir(root, missionId), MAD_DB_CAPABILITY_FILE), updated);
139
+ await appendJsonlBounded(path.join(missionDir(root, missionId), 'mad-db-ledger.jsonl'), {
140
+ ts: nowIso(),
141
+ type: 'capability.updated',
142
+ mission_id: missionId,
143
+ cycle_id: updated.cycle_id,
144
+ revision: updated.revision,
145
+ status: updated.status,
146
+ counters: updated.counters
147
+ });
148
+ return updated;
149
+ });
150
+ }
61
151
  export async function recordMadDbOperation(root, missionId, input = {}) {
62
152
  const capability = await readMadDbCapability(root, missionId);
63
- if (!isMadDbCapabilityActive(capability))
64
- return capability;
65
- const operationCount = Number(capability.operation_count || 0) + 1;
66
- const maxOperations = Math.max(1, Number(capability.max_operations || 20));
67
- const updated = {
68
- ...capability,
69
- operation_count: operationCount,
70
- max_operations: maxOperations
71
- };
72
- const dir = missionDir(root, missionId);
73
- await writeJsonAtomic(path.join(dir, MAD_DB_CAPABILITY_FILE), updated);
74
- await appendJsonlBounded(path.join(dir, 'mad-db-ledger.jsonl'), {
153
+ if (!capability)
154
+ return null;
155
+ await appendJsonlBounded(path.join(missionDir(root, missionId), 'mad-db-ledger.jsonl'), {
75
156
  ts: nowIso(),
76
- type: 'db_operation.counted',
157
+ type: 'db_operation.legacy_recorded',
77
158
  mission_id: missionId,
78
- cycle_id: updated.cycle_id,
159
+ cycle_id: capability.cycle_id,
79
160
  operation_id: input.operationId || null,
80
161
  tool_name: input.toolName || null,
81
- sql_hash: input.sqlHash || null,
82
- operation_count: operationCount,
83
- max_operations: maxOperations
162
+ sql_hash: input.sqlHash || null
84
163
  });
85
- if (operationCount >= maxOperations) {
86
- return consumeMadDbCapability(root, missionId, { consumedBy: 'db-safety-checkDbOperation', reason: 'mad_db_max_operations_reached' });
87
- }
88
- return updated;
164
+ return capability;
89
165
  }
90
166
  export async function consumeMadDbCapability(root, missionId, input = {}) {
91
- const capability = await readMadDbCapability(root, missionId);
92
- if (!capability || capability.consumed === true)
93
- return capability;
94
- const consumed = {
95
- ...capability,
96
- consumed: true,
97
- consumed_at: nowIso(),
98
- consumed_by: input.consumedBy || input.reason || 'db-safety-policy-resolver'
99
- };
100
- const dir = missionDir(root, missionId);
101
- await writeJsonAtomic(path.join(dir, MAD_DB_CAPABILITY_FILE), consumed);
102
- await writeJsonAtomic(path.join(dir, 'mad-db-capability.consumed.json'), consumed);
103
- await appendJsonlBounded(path.join(dir, 'mad-db-ledger.jsonl'), { ts: nowIso(), type: 'capability.consumed', mission_id: missionId, cycle_id: consumed.cycle_id, consumed_by: consumed.consumed_by });
104
- return consumed;
167
+ return closeMadDbCycle(root, missionId, '', input.consumedBy || input.reason || 'mad_db_cycle_closed');
105
168
  }
106
- export async function closeMadDbCycle(root, missionId, cycleId) {
107
- const capability = await readMadDbCapability(root, missionId);
108
- if (!capability || capability.cycle_id !== cycleId)
109
- return capability;
110
- if (capability.consumed === true)
111
- return capability;
112
- return consumeMadDbCapability(root, missionId, { consumedBy: 'mad-db-cycle-close', reason: 'mad_db_cycle_closed' });
169
+ export async function closeMadDbCycle(root, missionId, cycleId = '', reason = 'mad_db_cycle_closed') {
170
+ const closed = await updateMadDbCapability(root, missionId, (capability) => {
171
+ if (cycleId && capability.cycle_id !== cycleId)
172
+ return capability;
173
+ return {
174
+ ...capability,
175
+ status: capability.status === 'revoked' ? 'revoked' : 'closed',
176
+ closed_at: nowIso()
177
+ };
178
+ });
179
+ if (closed) {
180
+ await writeJsonAtomic(path.join(missionDir(root, missionId), 'mad-db-capability.closed.json'), {
181
+ schema: closed.schema,
182
+ mission_id: closed.mission_id,
183
+ cycle_id: closed.cycle_id,
184
+ closed_at: closed.closed_at,
185
+ close_reason: reason,
186
+ counters: closed.counters,
187
+ project_ref_hash: sha256(closed.project_ref).slice(0, 16)
188
+ });
189
+ }
190
+ return closed;
113
191
  }
114
192
  export async function revokeMadDbCapability(root, missionId, reason = 'operator_revoked') {
115
- const capability = await readMadDbCapability(root, missionId);
116
- if (!capability)
117
- return null;
118
- const revoked = { ...capability, enabled: false, revoked_at: nowIso(), revoke_reason: reason };
119
- const dir = missionDir(root, missionId);
120
- await writeJsonAtomic(path.join(dir, MAD_DB_CAPABILITY_FILE), revoked);
121
- await appendJsonlBounded(path.join(dir, 'mad-db-ledger.jsonl'), { ts: nowIso(), type: 'capability.revoked', mission_id: missionId, cycle_id: capability.cycle_id, reason });
193
+ const revoked = await updateMadDbCapability(root, missionId, (capability) => ({
194
+ ...capability,
195
+ status: 'revoked',
196
+ closed_at: nowIso()
197
+ }));
198
+ if (revoked) {
199
+ await appendJsonlBounded(path.join(missionDir(root, missionId), 'mad-db-ledger.jsonl'), {
200
+ ts: nowIso(),
201
+ type: 'capability.revoked',
202
+ mission_id: missionId,
203
+ cycle_id: revoked.cycle_id,
204
+ reason
205
+ });
206
+ }
122
207
  return revoked;
123
208
  }
209
+ function migrateV1Capability(value, missionId) {
210
+ const projectRef = process.env.SKS_MAD_DB_PROJECT_REF || process.env.SKS_MAD_DB_E2E_PROJECT_REF || 'legacy-v1-missing-project-ref';
211
+ return {
212
+ schema: MAD_DB_CAPABILITY_SCHEMA,
213
+ revision: 0,
214
+ mission_id: String(value.mission_id || missionId),
215
+ cycle_id: String(value.cycle_id || `mad-db-${Date.now().toString(36)}`),
216
+ project_root_hash: sha256(String(value.operator_ack?.cwd || process.cwd())).slice(0, 24),
217
+ project_ref: projectRef,
218
+ target_environment: 'production',
219
+ allowed_schemas: ['public'],
220
+ codex_thread_id: null,
221
+ runtime_session_id: `legacy-v1-${Date.now().toString(36)}`,
222
+ operator_intent_hash: sha256('legacy-v1-migrated').slice(0, 32),
223
+ operator_ack_hash: sha256(MAD_DB_ACK).slice(0, 32),
224
+ scope: {
225
+ sql_plane: 'all_mutations',
226
+ control_plane: 'deny',
227
+ operations: [...MAD_DB_POLICY.sql_plane_allowed]
228
+ },
229
+ transport: {
230
+ profile_path: '.sneakoscope/missions/<mission>/mad-db/runtime/codex-mad-db.config.toml',
231
+ profile_sha256: sha256('legacy-v1-missing-profile'),
232
+ server_url_redacted: 'https://mcp.supabase.com/mcp?project_ref=<legacy-redacted>&features=database',
233
+ features: ['database'],
234
+ write_capable: true
235
+ },
236
+ issued_at: String(value.created_at || nowIso()),
237
+ expires_at: String(value.expires_at || new Date(Date.now() - 1000).toISOString()),
238
+ closed_at: value.consumed ? String(value.consumed_at || nowIso()) : null,
239
+ status: value.enabled === false ? 'revoked' : value.consumed ? 'closed' : 'quarantined',
240
+ counters: {
241
+ attempts: Number(value.operation_count || 0),
242
+ reserved: Number(value.operation_count || 0),
243
+ succeeded: 0,
244
+ failed: 0
245
+ },
246
+ legacy_compat: {
247
+ one_cycle_only: true,
248
+ priority: 'highest',
249
+ scope: 'all_database_mutations'
250
+ }
251
+ };
252
+ }
124
253
  //# sourceMappingURL=mad-db-capability.js.map
@@ -0,0 +1,287 @@
1
+ import path from 'node:path';
2
+ import { createMission, missionDir, setCurrent } from '../mission.js';
3
+ import { nowIso, readJson, readText, sha256, writeJsonAtomic } from '../fsx.js';
4
+ import { createMadDbCapability, activateMadDbCapability, closeMadDbCycle, MAD_DB_ACK, markMadDbTransportReady, readMadDbCapability } from './mad-db-capability.js';
5
+ import { MadDbMcpExecutor } from './mad-db-executor.js';
6
+ import { createMadDbRuntimeProfile, closeMadDbRuntimeProfile, redactedRuntimeProfile } from './mad-db-runtime-profile.js';
7
+ import { reserveMadDbOperation, transitionMadDbOperation } from './mad-db-operation-store.js';
8
+ import { readBackCheck, runReadBackChecks } from './mad-db-postconditions.js';
9
+ import { madDbOperationClassesFromClassification } from './mad-db-policy.js';
10
+ import { projectRootHash, resolveMadDbTarget } from './mad-db-target.js';
11
+ import { classifySql } from '../db-safety.js';
12
+ export async function prepareMadDbMission(input) {
13
+ const target = await resolveMadDbTarget(input.root, { args: input.args || [] });
14
+ const { id, dir } = await createMission(input.root, { mode: 'mad-db', prompt: input.task || 'MadDB SQL-plane execution' });
15
+ const cycleId = `mad-db-${Date.now().toString(36)}`;
16
+ const runtimeSessionId = input.runtimeSessionId || `mad-db-session-${Date.now().toString(36)}`;
17
+ const blockers = [...target.blockers];
18
+ let profile;
19
+ if (!target.project_ref) {
20
+ profile = await createMadDbRuntimeProfile({ root: input.root, missionId: id, cycleId, projectRef: 'missing-project-ref', runtimeSessionId });
21
+ }
22
+ else {
23
+ profile = await createMadDbRuntimeProfile({ root: input.root, missionId: id, cycleId, projectRef: target.project_ref, runtimeSessionId });
24
+ }
25
+ const capability = await createMadDbCapability(input.root, {
26
+ missionId: id,
27
+ ack: MAD_DB_ACK,
28
+ cwd: input.root,
29
+ cycleId,
30
+ projectRef: target.project_ref || 'missing-project-ref',
31
+ targetEnvironment: target.target_environment,
32
+ allowedSchemas: target.allowed_schemas,
33
+ runtimeSessionId,
34
+ operatorIntent: input.task,
35
+ profilePath: profile.profile_path,
36
+ profileSha256: profile.profile_sha256,
37
+ serverUrlRedacted: profile.server_url_redacted,
38
+ operations: [...madDbOperationClassesFromClassification(classifySql(input.task))],
39
+ status: blockers.length ? 'quarantined' : 'transport_ready'
40
+ });
41
+ let toolInventory = null;
42
+ if (input.verifyTools && !blockers.length) {
43
+ const executor = new MadDbMcpExecutor(profile);
44
+ toolInventory = await executor.inventory();
45
+ await executor.close();
46
+ await writeJsonAtomic(path.join(dir, 'mad-db', 'runtime', 'tool-inventory.json'), toolInventory);
47
+ if (!toolInventory.ok)
48
+ blockers.push('mad_db_execute_sql_or_apply_migration_unavailable');
49
+ else
50
+ await markMadDbTransportReady(input.root, id);
51
+ }
52
+ await writeJsonAtomic(path.join(dir, 'route-context.json'), {
53
+ route: 'MadDB',
54
+ command: '$MAD-DB',
55
+ mode: 'MADDB',
56
+ task: input.task,
57
+ target: { ...target, project_ref: target.project_ref ? `<hash:${target.project_ref_hash}>` : null },
58
+ capability_file: 'mad-db-capability.json',
59
+ runtime_profile_manifest: 'mad-db/runtime/runtime-profile-manifest.json',
60
+ tool_inventory: toolInventory ? 'mad-db/runtime/tool-inventory.json' : null
61
+ });
62
+ await writeJsonAtomic(path.join(dir, 'mad-db-gate.json'), {
63
+ schema: 'sks.mad-db-gate.v1',
64
+ passed: false,
65
+ mad_db_capability_active: !blockers.length,
66
+ sql_plane_all_mutations_allowed: !blockers.length,
67
+ control_plane_denied: true,
68
+ mission_id: id,
69
+ cycle_id: cycleId,
70
+ blockers,
71
+ created_at: nowIso()
72
+ });
73
+ await setCurrent(input.root, {
74
+ mission_id: id,
75
+ mad_db_capability_mission_id: id,
76
+ route: 'MadDB',
77
+ route_command: '$MAD-DB',
78
+ mode: 'MADDB',
79
+ phase: blockers.length ? 'MADDB_BLOCKED' : 'MADDB_SQL_PLANE_CAPABILITY_ACTIVE',
80
+ questions_allowed: false,
81
+ implementation_allowed: !blockers.length,
82
+ mad_db_active: !blockers.length,
83
+ mad_db_cycle_id: cycleId,
84
+ mad_db_runtime_session_id: runtimeSessionId,
85
+ mad_db_profile_sha256: profile.profile_sha256,
86
+ mad_db_capability_file: 'mad-db-capability.json',
87
+ stop_gate: 'mad-db-gate.json',
88
+ prompt: input.task
89
+ });
90
+ return {
91
+ schema: 'sks.mad-db-prepared-mission.v1',
92
+ ok: blockers.length === 0,
93
+ mission_id: id,
94
+ cycle_id: cycleId,
95
+ target,
96
+ capability,
97
+ runtime_profile: redactedRuntimeProfile(profile),
98
+ tool_inventory: toolInventory,
99
+ blockers
100
+ };
101
+ }
102
+ export async function runMadDbCycle(input) {
103
+ const timings = {};
104
+ const start = Date.now();
105
+ const prepared = await prepareMadDbMission({ root: input.root, task: input.task, args: input.args || [], verifyTools: false });
106
+ timings.prepare_ms = Date.now() - start;
107
+ const profile = await recreateProfileFromPrepared(input.root, prepared);
108
+ const executor = new MadDbMcpExecutor(profile);
109
+ let inventory = null;
110
+ let execution = null;
111
+ let operation = null;
112
+ let readBack = null;
113
+ const blockers = [...prepared.blockers];
114
+ try {
115
+ const connectStart = Date.now();
116
+ inventory = await executor.inventory();
117
+ timings.mcp_connect_ms = Date.now() - connectStart;
118
+ await writeJsonAtomic(path.join(missionDir(input.root, prepared.mission_id), 'mad-db', 'runtime', 'tool-inventory.json'), inventory);
119
+ if (!inventory.ok) {
120
+ blockers.push('mad_db_execute_sql_or_apply_migration_unavailable');
121
+ throw new Error('mad_db_tool_inventory_failed');
122
+ }
123
+ await activateMadDbCapability(input.root, prepared.mission_id);
124
+ const sql = await resolveSqlInput(input);
125
+ if (!sql) {
126
+ blockers.push('mad_db_sql_missing_for_execution');
127
+ throw new Error('mad_db_sql_missing_for_execution');
128
+ }
129
+ const classification = classifySql(sql);
130
+ const toolName = input.action === 'apply-migration' ? 'apply_migration' : 'execute_sql';
131
+ const toolCallId = `cli-${input.action}-${sha256(`${prepared.mission_id}:${sql}:${Date.now()}`).slice(0, 16)}`;
132
+ const reservation = await reserveMadDbOperation({
133
+ root: input.root,
134
+ missionId: prepared.mission_id,
135
+ capability: prepared.capability,
136
+ toolCallId,
137
+ toolName,
138
+ sql,
139
+ migrationName: input.migrationName || null,
140
+ operationClasses: madDbOperationClassesFromClassification({ ...classification, toolName })
141
+ });
142
+ await transitionMadDbOperation({ root: input.root, missionId: prepared.mission_id, toolCallId, state: 'started' });
143
+ const execStart = Date.now();
144
+ execution = input.action === 'apply-migration'
145
+ ? await executor.applyMigration(input.migrationName || `mad_db_${Date.now()}`, sql)
146
+ : await executor.executeSql(sql);
147
+ timings.execution_ms = Date.now() - execStart;
148
+ operation = await transitionMadDbOperation({
149
+ root: input.root,
150
+ missionId: prepared.mission_id,
151
+ toolCallId,
152
+ state: execution.ok ? 'succeeded' : 'failed',
153
+ result: execution
154
+ });
155
+ if (!execution.ok)
156
+ blockers.push('mad_db_tool_execution_failed');
157
+ if (execution.ok && input.verifySql) {
158
+ const verifyStart = Date.now();
159
+ readBack = await runReadBackChecks({
160
+ root: input.root,
161
+ missionId: prepared.mission_id,
162
+ executor,
163
+ checks: [readBackCheck('operator_verify_sql', input.verifySql)]
164
+ });
165
+ timings.verification_ms = Date.now() - verifyStart;
166
+ if (!readBack.ok)
167
+ blockers.push('mad_db_read_back_verification_failed');
168
+ if (operation) {
169
+ operation = await transitionMadDbOperation({
170
+ root: input.root,
171
+ missionId: prepared.mission_id,
172
+ toolCallId,
173
+ state: readBack.ok ? 'verified' : 'verification_failed',
174
+ verificationArtifact: readBack.proof_path || null
175
+ }) || operation;
176
+ }
177
+ }
178
+ }
179
+ catch (err) {
180
+ if (!blockers.length)
181
+ blockers.push(err instanceof Error ? err.message : String(err));
182
+ }
183
+ finally {
184
+ await executor.close();
185
+ }
186
+ const closeStart = Date.now();
187
+ const restoration = await closeMadDbRuntimeProfile({ root: input.root, missionId: prepared.mission_id, profile, reason: 'mad_db_cycle_finally' });
188
+ await closeMadDbCycle(input.root, prepared.mission_id, prepared.cycle_id, 'mad_db_cycle_finally');
189
+ timings.close_ms = Date.now() - closeStart;
190
+ timings.total_ms = Date.now() - start;
191
+ const result = {
192
+ schema: 'sks.mad-db-cycle-result.v1',
193
+ ok: blockers.length === 0 && execution?.ok === true && restoration.ok,
194
+ mission_id: prepared.mission_id,
195
+ cycle_id: prepared.cycle_id,
196
+ action: input.action,
197
+ target: prepared.target,
198
+ tool_inventory: inventory,
199
+ execution,
200
+ operation,
201
+ read_back: readBack,
202
+ read_only_restoration: restoration,
203
+ capability_closed: true,
204
+ timings_ms: timings,
205
+ blockers: restoration.ok ? blockers : [...blockers, ...restoration.blockers]
206
+ };
207
+ await writeJsonAtomic(path.join(missionDir(input.root, prepared.mission_id), 'mad-db-result.json'), redactCycleResult(result));
208
+ await clearMadDbCurrentState(input.root, prepared.mission_id, result.ok, restoration);
209
+ return result;
210
+ }
211
+ async function clearMadDbCurrentState(root, missionId, ok, restoration) {
212
+ const currentPath = path.join(root, '.sneakoscope', 'state', 'current.json');
213
+ const current = await readJson(currentPath, {});
214
+ if (current.mission_id !== missionId && current.mad_db_capability_mission_id !== missionId)
215
+ return;
216
+ await setCurrent(root, {
217
+ phase: ok ? 'MADDB_CLOSED' : 'MADDB_FAILED_CLOSED',
218
+ implementation_allowed: false,
219
+ mad_db_active: false,
220
+ mad_db_runtime_session_id: null,
221
+ mad_db_profile_sha256: null,
222
+ mad_db_read_only_restored: restoration.ok,
223
+ mad_db_closed_at: nowIso(),
224
+ mad_db_last_result_file: 'mad-db-result.json'
225
+ });
226
+ }
227
+ function redactCycleResult(result) {
228
+ return {
229
+ ...result,
230
+ target: {
231
+ ...result.target,
232
+ project_ref: result.target.project_ref ? '<redacted>' : null
233
+ }
234
+ };
235
+ }
236
+ async function resolveSqlInput(input) {
237
+ if (input.sql)
238
+ return input.sql;
239
+ if (input.migrationFile)
240
+ return readText(path.resolve(input.migrationFile), '');
241
+ const trimmed = String(input.task || '').trim();
242
+ return /^(select|with|show|explain|describe|insert|update|delete|drop|truncate|alter|create|grant|revoke)\b/i.test(trimmed) ? trimmed : null;
243
+ }
244
+ async function recreateProfileFromPrepared(root, prepared) {
245
+ const projectRef = prepared.target.project_ref || 'missing-project-ref';
246
+ return {
247
+ schema: 'sks.mad-db-runtime-profile.v1',
248
+ mission_id: prepared.mission_id,
249
+ cycle_id: prepared.cycle_id,
250
+ runtime_session_id: prepared.capability.runtime_session_id,
251
+ project_ref_hash: sha256(projectRef).slice(0, 16),
252
+ profile_path: prepared.runtime_profile.profile_path,
253
+ profile_sha256: prepared.runtime_profile.profile_sha256,
254
+ server_url_redacted: prepared.runtime_profile.server_url_redacted,
255
+ server_url: `https://mcp.supabase.com/mcp?project_ref=${encodeURIComponent(projectRef)}&features=database`,
256
+ features: ['database'],
257
+ write_capable: true,
258
+ normal_config_hash_before: prepared.runtime_profile.normal_config_hash_before,
259
+ created_at: prepared.runtime_profile.created_at
260
+ };
261
+ }
262
+ export async function madDbRouteIdentityProof(root, missionId) {
263
+ const capability = await readMadDbCapability(root, missionId);
264
+ const state = await readJson(path.join(root, '.sneakoscope', 'state', 'current.json'), {});
265
+ const profile = await readJson(path.join(missionDir(root, missionId), 'mad-db', 'runtime', 'runtime-profile-manifest.json'), null);
266
+ const sameMission = Boolean(capability && capability.mission_id === missionId && state?.mission_id === missionId);
267
+ return {
268
+ schema: 'sks.mad-db-route-identity-proof.v1',
269
+ ok: sameMission && state?.route === 'MadDB' && state?.route_command === '$MAD-DB',
270
+ mission_id: missionId,
271
+ capability_mission_id: capability?.mission_id || null,
272
+ same_mission: sameMission,
273
+ route: state?.route || null,
274
+ route_command: state?.route_command || null,
275
+ cycle_id: capability?.cycle_id || null,
276
+ project_root_hash: await projectRootHash(root),
277
+ runtime_profile: profile,
278
+ blockers: [
279
+ ...(capability ? [] : ['capability_missing']),
280
+ ...(profile ? [] : ['runtime_profile_manifest_missing']),
281
+ ...(sameMission ? [] : ['mission_binding_mismatch']),
282
+ ...(state?.route === 'MadDB' ? [] : ['route_state_not_maddb']),
283
+ ...(state?.route_command === '$MAD-DB' ? [] : ['route_command_not_maddb'])
284
+ ]
285
+ };
286
+ }
287
+ //# sourceMappingURL=mad-db-coordinator.js.map