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.
- package/README.md +13 -10
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/bin/sks.js +1 -1
- package/dist/cli/command-registry.js +1 -1
- package/dist/core/auto-review.js +1 -1
- package/dist/core/codex-control/codex-app-server-v2-client.js +86 -2
- package/dist/core/codex-control/codex-reliability-shield.js +26 -5
- package/dist/core/codex-control/codex-task-runner.js +7 -1
- package/dist/core/codex-control/model-call-concurrency.js +1 -1
- package/dist/core/commands/mad-db-command.js +146 -51
- package/dist/core/commands/mad-sks-command.js +15 -31
- package/dist/core/commands/qa-loop-command.js +23 -7
- package/dist/core/db-safety.js +35 -37
- package/dist/core/doctor/supabase-mcp-repair.js +2 -2
- package/dist/core/feature-registry.js +1 -1
- package/dist/core/fsx.js +1 -1
- package/dist/core/hooks-runtime.js +1 -1
- package/dist/core/init.js +5 -4
- package/dist/core/mad-db/mad-db-capability.js +203 -74
- package/dist/core/mad-db/mad-db-coordinator.js +287 -0
- package/dist/core/mad-db/mad-db-executor.js +156 -0
- package/dist/core/mad-db/mad-db-ledger.js +1 -1
- package/dist/core/mad-db/mad-db-lock.js +40 -0
- package/dist/core/mad-db/mad-db-operation-store.js +140 -0
- package/dist/core/mad-db/mad-db-policy-resolver.js +42 -22
- package/dist/core/mad-db/mad-db-policy.js +195 -0
- package/dist/core/mad-db/mad-db-postconditions.js +30 -0
- package/dist/core/mad-db/mad-db-recovery.js +27 -0
- package/dist/core/mad-db/mad-db-result-lifecycle.js +31 -102
- package/dist/core/mad-db/mad-db-runtime-profile.js +121 -0
- package/dist/core/mad-db/mad-db-target.js +64 -0
- package/dist/core/managed-assets/managed-assets-manifest.js +1 -1
- package/dist/core/pipeline-internals/runtime-core.js +40 -0
- package/dist/core/providers/glm/bench/glm-benchmark-types.js +1 -1
- package/dist/core/qa-loop/qa-app-server-driver.js +134 -0
- package/dist/core/qa-loop/qa-contract-v2.js +231 -0
- package/dist/core/qa-loop/qa-gate-v2.js +132 -0
- package/dist/core/qa-loop/qa-runtime-artifacts.js +53 -0
- package/dist/core/qa-loop/qa-surface-router.js +114 -0
- package/dist/core/qa-loop/qa-types.js +18 -0
- package/dist/core/qa-loop.js +83 -26
- package/dist/core/release/gate-manifest.js +1 -0
- package/dist/core/release/release-gate-dag.js +6 -5
- package/dist/core/release/sla-scheduler.js +1 -1
- package/dist/core/routes.js +42 -12
- package/dist/core/triwiki/triwiki-affected-graph.js +3 -2
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-slot-column-anchor.js +5 -1
- package/dist/scripts/check-dist-runtime.js +3 -2
- package/dist/scripts/codex-0142-manifest-check.js +2 -1
- package/dist/scripts/codex-control-all-pipelines-check.js +1 -0
- package/dist/scripts/codex-control-model-capacity-fallback-check.js +53 -0
- package/dist/scripts/config-managed-merge-callsite-coverage-check.js +7 -1
- package/dist/scripts/loop-directive-check-lib.js +78 -1
- package/dist/scripts/mad-db-capability-check.js +13 -2
- package/dist/scripts/mad-db-command-check.js +7 -5
- package/dist/scripts/mad-db-hook-idempotency-check.js +21 -0
- package/dist/scripts/mad-db-ledger-check.js +2 -1
- package/dist/scripts/mad-db-lifecycle-hook-decision-check.js +5 -4
- package/dist/scripts/mad-db-mad-command-check.js +29 -16
- package/dist/scripts/mad-db-mcp-result-lifecycle-check.js +11 -10
- package/dist/scripts/mad-db-one-cycle-bounded-check.js +15 -18
- package/dist/scripts/mad-db-one-cycle-consumption-check.js +3 -3
- package/dist/scripts/mad-db-operation-lifecycle-blackbox.js +9 -9
- package/dist/scripts/mad-db-operation-lifecycle-ledger-check.js +6 -6
- package/dist/scripts/mad-db-parallel-lifecycle-check.js +24 -0
- package/dist/scripts/mad-db-policy-v2-check.js +20 -0
- package/dist/scripts/mad-db-priority-resolver-check.js +5 -5
- package/dist/scripts/mad-db-real-supabase-e2e.js +166 -0
- package/dist/scripts/mad-db-route-identity-check.js +28 -0
- package/dist/scripts/mad-db-runtime-profile-lifecycle-check.js +24 -0
- package/dist/scripts/mad-db-safety-conflict-matrix-check.js +3 -3
- package/dist/scripts/mad-db-skill-policy-snapshot-check.js +15 -0
- package/dist/scripts/qa-loop-app-server-driver-check.js +74 -0
- package/dist/scripts/qa-loop-surface-router-check.js +49 -0
- package/dist/scripts/release-check-dynamic-execute.js +1 -1
- package/dist/scripts/release-dag-full-coverage-check.js +6 -0
- package/dist/scripts/release-triwiki-first-runner-blackbox.js +5 -1
- package/dist/scripts/runtime-ts-rust-boundary-check.js +1 -1
- package/dist/scripts/triwiki-affected-graph-check.js +2 -2
- package/package.json +18 -5
- 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
|
-
|
|
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
|
|
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 ||
|
|
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
|
-
|
|
18
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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'), {
|
|
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
|
|
41
|
-
|
|
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.
|
|
55
|
-
&& capability.
|
|
56
|
-
&& capability.
|
|
57
|
-
&&
|
|
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 (!
|
|
64
|
-
return
|
|
65
|
-
|
|
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.
|
|
157
|
+
type: 'db_operation.legacy_recorded',
|
|
77
158
|
mission_id: missionId,
|
|
78
|
-
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
|
-
|
|
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
|
-
|
|
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
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|