sneakoscope 4.1.1 → 4.2.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.
- package/README.md +12 -9
- 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/commands/mad-db-command.js +146 -51
- package/dist/core/commands/mad-sks-command.js +15 -31
- 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/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/release/release-gate-dag.js +6 -5
- package/dist/core/routes.js +23 -8
- 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/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/release-dag-full-coverage-check.js +6 -0
- package/dist/scripts/release-triwiki-first-runner-blackbox.js +5 -1
- package/package.json +13 -3
- package/schemas/mad-db/mad-db-capability.schema.json +92 -19
|
@@ -6,21 +6,21 @@ import path from 'node:path';
|
|
|
6
6
|
import { checkDbOperation, madDbLifecycleHookFromDecision } from '../core/db-safety.js';
|
|
7
7
|
import { createMadDbCapability, MAD_DB_ACK } from '../core/mad-db/mad-db-capability.js';
|
|
8
8
|
import { recordMadDbToolResult } from '../core/mad-db/mad-db-result-lifecycle.js';
|
|
9
|
-
import { missionDir } from '../core/mission.js';
|
|
9
|
+
import { createMission, missionDir } from '../core/mission.js';
|
|
10
10
|
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
11
11
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-mad-db-lifecycle-blackbox-'));
|
|
12
|
-
const
|
|
13
|
-
await createMadDbCapability(root, { missionId, ack: MAD_DB_ACK, ttlMs: 60000 });
|
|
14
|
-
const success = await checkDbOperation(root, { mission_id:
|
|
12
|
+
const mission = await createMission(root, { mode: 'mad-db', prompt: 'lifecycle blackbox fixture' });
|
|
13
|
+
await createMadDbCapability(root, { missionId: mission.id, ack: MAD_DB_ACK, ttlMs: 60000, projectRef: 'fixture-project-ref', status: 'active' });
|
|
14
|
+
const success = await checkDbOperation(root, { mission_id: mission.id }, { tool_name: 'supabase.execute_sql', tool_call_id: 'blackbox-success-call', sql: 'insert into audit_log(id) values (1)' });
|
|
15
15
|
const successHook = madDbLifecycleHookFromDecision(success);
|
|
16
16
|
assertGate(Boolean(successHook), 'success hook missing', success);
|
|
17
|
-
await recordMadDbToolResult({ root, missionId, hook: successHook, ok: true, rowCount: 1 });
|
|
18
|
-
const failure = await checkDbOperation(root, { mission_id:
|
|
17
|
+
await recordMadDbToolResult({ root, missionId: mission.id, hook: successHook, ok: true, rowCount: 1 });
|
|
18
|
+
const failure = await checkDbOperation(root, { mission_id: mission.id }, { tool_name: 'supabase.execute_sql', tool_call_id: 'blackbox-failure-call', sql: 'update users set flag = true where id = 1' });
|
|
19
19
|
const failureHook = madDbLifecycleHookFromDecision(failure);
|
|
20
20
|
assertGate(Boolean(failureHook), 'failure hook missing', failure);
|
|
21
|
-
await recordMadDbToolResult({ root, missionId, hook: failureHook, ok: false, error: 'fixture failure' });
|
|
22
|
-
const ledger = await fs.readFile(path.join(missionDir(root,
|
|
23
|
-
for (const token of ['db_operation.started', '
|
|
21
|
+
await recordMadDbToolResult({ root, missionId: mission.id, hook: failureHook, ok: false, error: 'fixture failure' });
|
|
22
|
+
const ledger = await fs.readFile(path.join(missionDir(root, mission.id), 'mad-db-ledger.jsonl'), 'utf8');
|
|
23
|
+
for (const token of ['db_operation.started', 'db_mutation.allowed', 'db_operation.succeeded', 'db_operation.failed']) {
|
|
24
24
|
assertGate(ledger.includes(token), `Mad-DB ledger missing ${token}`, { ledger });
|
|
25
25
|
}
|
|
26
26
|
assertGate((ledger.match(/db_operation\.succeeded/g) || []).length === 1, 'success terminal event must be recorded exactly once', { ledger });
|
|
@@ -5,13 +5,13 @@ import os from 'node:os';
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { createMadDbCapability, MAD_DB_ACK } from '../core/mad-db/mad-db-capability.js';
|
|
7
7
|
import { checkDbOperation } from '../core/db-safety.js';
|
|
8
|
-
import { missionDir } from '../core/mission.js';
|
|
8
|
+
import { createMission, missionDir } from '../core/mission.js';
|
|
9
9
|
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
10
10
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-mad-db-ledger-'));
|
|
11
|
-
const
|
|
12
|
-
await createMadDbCapability(root, { missionId, ack: MAD_DB_ACK, ttlMs: 60000 });
|
|
13
|
-
await checkDbOperation(root, { mission_id:
|
|
14
|
-
const ledger = await fs.readFile(path.join(missionDir(root,
|
|
15
|
-
assertGate(ledger.includes('db_operation.
|
|
11
|
+
const mission = await createMission(root, { mode: 'mad-db', prompt: 'ledger fixture' });
|
|
12
|
+
await createMadDbCapability(root, { missionId: mission.id, ack: MAD_DB_ACK, ttlMs: 60000, projectRef: 'fixture-project-ref', status: 'active' });
|
|
13
|
+
await checkDbOperation(root, { mission_id: mission.id }, { tool_name: 'supabase.execute_sql', tool_call_id: 'ledger-call-1', sql: 'insert into audit_log(id) values (1)' });
|
|
14
|
+
const ledger = await fs.readFile(path.join(missionDir(root, mission.id), 'mad-db-ledger.jsonl'), 'utf8');
|
|
15
|
+
assertGate(ledger.includes('db_operation.reserved') && ledger.includes('db_operation.started') && ledger.includes('db_mutation.allowed') && !ledger.includes('unknown_pending_tool_result'), 'Mad-DB lifecycle ledger events missing or pending-latest fallback still present', { ledger });
|
|
16
16
|
emitGate('mad-db:operation-lifecycle-ledger');
|
|
17
17
|
//# sourceMappingURL=mad-db-operation-lifecycle-ledger-check.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { createMission } from '../core/mission.js';
|
|
6
|
+
import { createMadDbCapability, MAD_DB_ACK, readMadDbCapability } from '../core/mad-db/mad-db-capability.js';
|
|
7
|
+
import { reserveMadDbOperation, transitionMadDbOperation } from '../core/mad-db/mad-db-operation-store.js';
|
|
8
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
9
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-mad-db-parallel-lifecycle-'));
|
|
10
|
+
const mission = await createMission(root, { mode: 'mad-db', prompt: 'parallel lifecycle fixture' });
|
|
11
|
+
const cap = await createMadDbCapability(root, { missionId: mission.id, ack: MAD_DB_ACK, cwd: root, projectRef: 'fixture-project-ref', status: 'active' });
|
|
12
|
+
const [first, second] = await Promise.all([
|
|
13
|
+
reserveMadDbOperation({ root, missionId: mission.id, capability: cap, toolCallId: 'parallel-call-a', toolName: 'supabase.execute_sql', sql: 'insert into fixture values (1)', operationClasses: ['insert'] }),
|
|
14
|
+
reserveMadDbOperation({ root, missionId: mission.id, capability: cap, toolCallId: 'parallel-call-b', toolName: 'supabase.execute_sql', sql: 'update fixture set id = 2', operationClasses: ['all_row_update'] })
|
|
15
|
+
]);
|
|
16
|
+
await Promise.all([
|
|
17
|
+
transitionMadDbOperation({ root, missionId: mission.id, toolCallId: 'parallel-call-b', state: 'failed', errorCode: 'fixture_parallel_failure' }),
|
|
18
|
+
transitionMadDbOperation({ root, missionId: mission.id, toolCallId: 'parallel-call-a', state: 'succeeded', result: { ok: true } })
|
|
19
|
+
]);
|
|
20
|
+
const capAfter = await readMadDbCapability(root, mission.id);
|
|
21
|
+
assertGate(first.operation.operation_id !== second.operation.operation_id, 'parallel calls must not collide by tool name', { first, second });
|
|
22
|
+
assertGate(Boolean(capAfter) && capAfter.counters.reserved === 2 && capAfter.counters.succeeded === 1 && capAfter.counters.failed === 1, 'parallel lifecycle counters must track exact call ids', capAfter || {});
|
|
23
|
+
emitGate('mad-db:parallel-lifecycle', { first: first.operation.operation_id, second: second.operation.operation_id, counters: capAfter.counters });
|
|
24
|
+
//# sourceMappingURL=mad-db-parallel-lifecycle-check.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { MAD_DB_POLICY, isMadDbControlPlaneDeniedTool, isMadDbSqlPlaneToolName, madDbOperationClassesFromClassification } from '../core/mad-db/mad-db-policy.js';
|
|
3
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
4
|
+
for (const operation of ['drop', 'all_row_delete', 'truncate', 'migration_apply', 'direct_execute_sql']) {
|
|
5
|
+
assertGate(MAD_DB_POLICY.sql_plane_allowed.includes(operation), `policy missing ${operation}`, MAD_DB_POLICY);
|
|
6
|
+
}
|
|
7
|
+
assertGate(isMadDbSqlPlaneToolName('mcp__supabase_mad_db__execute_sql') === true, 'execute_sql variants must be SQL-plane tools');
|
|
8
|
+
assertGate(isMadDbSqlPlaneToolName('supabase.apply_migration') === true, 'apply_migration variants must be SQL-plane tools');
|
|
9
|
+
assertGate(isMadDbControlPlaneDeniedTool('supabase.delete_project') === true, 'project control-plane delete must remain denied');
|
|
10
|
+
assertGate(isMadDbControlPlaneDeniedTool('supabase.billing_update') === true, 'billing control-plane updates must remain denied');
|
|
11
|
+
const classes = madDbOperationClassesFromClassification({
|
|
12
|
+
toolName: 'supabase.execute_sql',
|
|
13
|
+
level: 'destructive',
|
|
14
|
+
sql: { reasons: ['truncate', 'delete_without_where', 'alter_table_drop'], statements: ['truncate public.fixture;', 'delete from public.fixture;', 'alter table public.fixture drop column old_col;'] }
|
|
15
|
+
});
|
|
16
|
+
for (const operation of ['direct_execute_sql', 'truncate', 'all_row_delete', 'drop']) {
|
|
17
|
+
assertGate(classes.includes(operation), `classification must map ${operation}`, { classes });
|
|
18
|
+
}
|
|
19
|
+
emitGate('mad-db:policy-v2', { classes });
|
|
20
|
+
//# sourceMappingURL=mad-db-policy-v2-check.js.map
|
|
@@ -11,10 +11,10 @@ const mission = await missionMod.createMission(root, { mode: 'mad-db', prompt: '
|
|
|
11
11
|
const state = { mission_id: mission.id };
|
|
12
12
|
const denied = await db.checkDbOperation(root, state, { tool_name: 'supabase.execute_sql', sql: 'drop table users;' });
|
|
13
13
|
assertGate(denied.allowed === false, 'without Mad-DB capability destructive DB must be blocked', denied);
|
|
14
|
-
await capMod.createMadDbCapability(root, { missionId: mission.id, ack: capMod.MAD_DB_ACK, cwd: root });
|
|
15
|
-
const allowed = await db.checkDbOperation(root, state, { tool_name: 'supabase.execute_sql', sql: 'drop table users;' });
|
|
14
|
+
await capMod.createMadDbCapability(root, { missionId: mission.id, ack: capMod.MAD_DB_ACK, cwd: root, projectRef: 'fixture-project-ref', status: 'active' });
|
|
15
|
+
const allowed = await db.checkDbOperation(root, state, { tool_name: 'supabase.execute_sql', tool_call_id: 'priority-drop-table', sql: 'drop table users;' });
|
|
16
16
|
assertGate(allowed.allowed === true && allowed.mad_db?.active === true, 'Mad-DB capability must allow destructive DB mutation with highest priority', allowed);
|
|
17
|
-
const
|
|
18
|
-
assertGate(
|
|
19
|
-
emitGate('mad-db:priority-resolver', { cycle_id:
|
|
17
|
+
const after = await capMod.readMadDbCapability(root, mission.id);
|
|
18
|
+
assertGate(after.status === 'active' && after.counters.reserved === 1, 'Mad-DB capability must remain active and reserve exactly one operation', after);
|
|
19
|
+
emitGate('mad-db:priority-resolver', { cycle_id: after.cycle_id, reserved: after.counters.reserved });
|
|
20
20
|
//# sourceMappingURL=mad-db-priority-resolver-check.js.map
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { createMission } from '../core/mission.js';
|
|
6
|
+
import { MAD_DB_ACK, closeMadDbCycle, createMadDbCapability } from '../core/mad-db/mad-db-capability.js';
|
|
7
|
+
import { MadDbMcpExecutor } from '../core/mad-db/mad-db-executor.js';
|
|
8
|
+
import { createMadDbRuntimeProfile, closeMadDbRuntimeProfile } from '../core/mad-db/mad-db-runtime-profile.js';
|
|
9
|
+
import { emitGate } from './sks-1-18-gate-lib.js';
|
|
10
|
+
const requireReal = process.argv.includes('--require-real');
|
|
11
|
+
const projectRef = process.env.SKS_MAD_DB_E2E_PROJECT_REF || process.env.SKS_MAD_DB_PROJECT_REF || '';
|
|
12
|
+
const hasAuth = Boolean(process.env.SUPABASE_ACCESS_TOKEN || process.env.SKS_MAD_DB_SUPABASE_ACCESS_TOKEN);
|
|
13
|
+
if (!projectRef || !hasAuth) {
|
|
14
|
+
const detail = {
|
|
15
|
+
status: 'unverified',
|
|
16
|
+
require_real: requireReal,
|
|
17
|
+
missing_project_ref: !projectRef,
|
|
18
|
+
missing_supabase_access_token: !hasAuth,
|
|
19
|
+
required_env: ['SKS_MAD_DB_E2E_PROJECT_REF', 'SUPABASE_ACCESS_TOKEN or SKS_MAD_DB_SUPABASE_ACCESS_TOKEN']
|
|
20
|
+
};
|
|
21
|
+
console.error(JSON.stringify({ schema: 'sks.mad-db-real-e2e.v1', ok: false, ...detail }, null, 2));
|
|
22
|
+
process.exit(requireReal ? 2 : 0);
|
|
23
|
+
}
|
|
24
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-mad-db-real-e2e-'));
|
|
25
|
+
await fs.mkdir(path.join(root, '.codex'), { recursive: true });
|
|
26
|
+
await fs.writeFile(path.join(root, '.codex', 'config.toml'), `[mcp_servers.supabase]\nurl = "https://mcp.supabase.com/mcp?project_ref=${projectRef}&read_only=true"\n`);
|
|
27
|
+
const mission = await createMission(root, { mode: 'mad-db', prompt: 'real disposable Supabase MadDB E2E' });
|
|
28
|
+
const cycleId = `real-e2e-${Date.now().toString(36)}`;
|
|
29
|
+
const profile = await createMadDbRuntimeProfile({ root, missionId: mission.id, cycleId, projectRef, runtimeSessionId: 'real-e2e-session' });
|
|
30
|
+
await createMadDbCapability(root, {
|
|
31
|
+
missionId: mission.id,
|
|
32
|
+
ack: MAD_DB_ACK,
|
|
33
|
+
cwd: root,
|
|
34
|
+
cycleId,
|
|
35
|
+
projectRef,
|
|
36
|
+
runtimeSessionId: 'real-e2e-session',
|
|
37
|
+
profilePath: profile.profile_path,
|
|
38
|
+
profileSha256: profile.profile_sha256,
|
|
39
|
+
serverUrlRedacted: profile.server_url_redacted,
|
|
40
|
+
status: 'active'
|
|
41
|
+
});
|
|
42
|
+
const executor = new MadDbMcpExecutor(profile, { timeoutMs: Number(process.env.SKS_MAD_DB_E2E_TIMEOUT_MS || 120000) });
|
|
43
|
+
const suffix = Date.now().toString(36).replace(/[^a-z0-9]/g, '');
|
|
44
|
+
const table = `sks_mad_db_e2e_${suffix}`;
|
|
45
|
+
const migrationName = `sks_mad_db_e2e_migration_${suffix}`;
|
|
46
|
+
const steps = [
|
|
47
|
+
{
|
|
48
|
+
name: 'create_table',
|
|
49
|
+
tool: 'execute_sql',
|
|
50
|
+
sql: `create table public.${table} (id integer primary key, label text not null);`,
|
|
51
|
+
verify: `select case when to_regclass('public.${table}') is not null then 1 else 1/0 end as ok;`
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'add_column',
|
|
55
|
+
tool: 'execute_sql',
|
|
56
|
+
sql: `alter table public.${table} add column note text;`,
|
|
57
|
+
verify: `select case when exists (select 1 from information_schema.columns where table_schema='public' and table_name='${table}' and column_name='note') then 1 else 1/0 end as ok;`
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'insert',
|
|
61
|
+
tool: 'execute_sql',
|
|
62
|
+
sql: `insert into public.${table} (id, label, note) values (1, 'alpha', 'inserted');`,
|
|
63
|
+
verify: `select case when (select count(*) from public.${table}) = 1 then 1 else 1/0 end as ok;`
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'update',
|
|
67
|
+
tool: 'execute_sql',
|
|
68
|
+
sql: `update public.${table} set label = 'beta' where id = 1;`,
|
|
69
|
+
verify: `select case when exists (select 1 from public.${table} where id=1 and label='beta') then 1 else 1/0 end as ok;`
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'targeted_delete',
|
|
73
|
+
tool: 'execute_sql',
|
|
74
|
+
sql: `delete from public.${table} where id = 1;`,
|
|
75
|
+
verify: `select case when (select count(*) from public.${table}) = 0 then 1 else 1/0 end as ok;`
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'all_row_delete',
|
|
79
|
+
tool: 'execute_sql',
|
|
80
|
+
sql: `insert into public.${table} (id, label) values (2, 'two'), (3, 'three'); delete from public.${table};`,
|
|
81
|
+
verify: `select case when (select count(*) from public.${table}) = 0 then 1 else 1/0 end as ok;`
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'truncate',
|
|
85
|
+
tool: 'execute_sql',
|
|
86
|
+
sql: `insert into public.${table} (id, label) values (4, 'four'), (5, 'five'); truncate table public.${table};`,
|
|
87
|
+
verify: `select case when (select count(*) from public.${table}) = 0 then 1 else 1/0 end as ok;`
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'drop_column',
|
|
91
|
+
tool: 'execute_sql',
|
|
92
|
+
sql: `alter table public.${table} add column drop_me text; alter table public.${table} drop column drop_me;`,
|
|
93
|
+
verify: `select case when not exists (select 1 from information_schema.columns where table_schema='public' and table_name='${table}' and column_name='drop_me') then 1 else 1/0 end as ok;`
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: 'migration_apply',
|
|
97
|
+
tool: 'apply_migration',
|
|
98
|
+
sql: `alter table public.${table} add column migrated_flag boolean default false;`,
|
|
99
|
+
verify: `select case when exists (select 1 from information_schema.columns where table_schema='public' and table_name='${table}' and column_name='migrated_flag') then 1 else 1/0 end as ok;`
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: 'drop_table',
|
|
103
|
+
tool: 'execute_sql',
|
|
104
|
+
sql: `drop table public.${table};`,
|
|
105
|
+
verify: `select case when to_regclass('public.${table}') is null then 1 else 1/0 end as ok;`
|
|
106
|
+
}
|
|
107
|
+
];
|
|
108
|
+
const timings = [];
|
|
109
|
+
const matrix = [];
|
|
110
|
+
let inventory = null;
|
|
111
|
+
let restoration = null;
|
|
112
|
+
let failure = null;
|
|
113
|
+
try {
|
|
114
|
+
inventory = await executor.inventory();
|
|
115
|
+
if (inventory.ok !== true)
|
|
116
|
+
throw failureDetail('real Supabase MCP inventory must expose execute_sql and apply_migration', inventory);
|
|
117
|
+
for (const step of steps) {
|
|
118
|
+
const started = Date.now();
|
|
119
|
+
const result = step.tool === 'apply_migration'
|
|
120
|
+
? await executor.applyMigration(`${migrationName}_${step.name}`, step.sql)
|
|
121
|
+
: await executor.executeSql(step.sql);
|
|
122
|
+
const verify = await executor.executeSql(step.verify);
|
|
123
|
+
const elapsed = Date.now() - started;
|
|
124
|
+
timings.push(elapsed);
|
|
125
|
+
matrix.push({ name: step.name, tool: step.tool, execute_ok: result.ok, verify_ok: verify.ok, duration_ms: elapsed, result_digest: result.result_digest, verify_digest: verify.result_digest });
|
|
126
|
+
if (result.ok !== true || verify.ok !== true)
|
|
127
|
+
throw failureDetail(`real MadDB E2E step failed: ${step.name}`, matrix[matrix.length - 1]);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
failure = err?.detail || { message: err?.message || String(err) };
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
await executor.close();
|
|
135
|
+
restoration = await closeMadDbRuntimeProfile({ root, missionId: mission.id, profile, reason: 'real_e2e_finally' });
|
|
136
|
+
await closeMadDbCycle(root, mission.id, cycleId, 'real_e2e_finally');
|
|
137
|
+
}
|
|
138
|
+
if (failure) {
|
|
139
|
+
console.error(JSON.stringify({
|
|
140
|
+
schema: 'sks.mad-db-real-e2e.v1',
|
|
141
|
+
ok: false,
|
|
142
|
+
status: 'failed_real_supabase',
|
|
143
|
+
project_ref_hash: profile.project_ref_hash,
|
|
144
|
+
failure,
|
|
145
|
+
destructive_operation_matrix: matrix,
|
|
146
|
+
read_only_restoration: restoration
|
|
147
|
+
}, null, 2));
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
timings.sort((a, b) => a - b);
|
|
151
|
+
const percentile = (p) => timings.length ? timings[Math.min(timings.length - 1, Math.floor((timings.length - 1) * p))] : 0;
|
|
152
|
+
emitGate('mad-db:real-e2e', {
|
|
153
|
+
status: 'passed_real_supabase',
|
|
154
|
+
project_ref_hash: profile.project_ref_hash,
|
|
155
|
+
table_hash: table.slice(-10),
|
|
156
|
+
inventory: { execute_sql_available: inventory?.execute_sql_available === true, apply_migration_available: inventory?.apply_migration_available === true, tool_count: inventory?.tool_names?.length || 0 },
|
|
157
|
+
destructive_operation_matrix: matrix,
|
|
158
|
+
timings_ms: { p50: percentile(0.5), p95: percentile(0.95), max: timings[timings.length - 1] || 0 },
|
|
159
|
+
read_only_restoration: restoration
|
|
160
|
+
});
|
|
161
|
+
function failureDetail(message, detail) {
|
|
162
|
+
const err = new Error(message);
|
|
163
|
+
err.detail = { message, detail };
|
|
164
|
+
return err;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=mad-db-real-supabase-e2e.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { routeByDollarCommand } from '../core/routes.js';
|
|
6
|
+
import { closeMadDbCycle, isMadDbCapabilityActive } from '../core/mad-db/mad-db-capability.js';
|
|
7
|
+
import { closeMadDbRuntimeProfile } from '../core/mad-db/mad-db-runtime-profile.js';
|
|
8
|
+
import { madDbRouteIdentityProof, prepareMadDbMission } from '../core/mad-db/mad-db-coordinator.js';
|
|
9
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
10
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-mad-db-route-identity-'));
|
|
11
|
+
const prepared = await prepareMadDbMission({
|
|
12
|
+
root,
|
|
13
|
+
task: '$MAD-DB truncate public.fixture',
|
|
14
|
+
args: ['--project-ref', 'fixture-project-ref', '--target', 'preview'],
|
|
15
|
+
verifyTools: false,
|
|
16
|
+
runtimeSessionId: 'route-identity-session'
|
|
17
|
+
});
|
|
18
|
+
const proof = await madDbRouteIdentityProof(root, prepared.mission_id);
|
|
19
|
+
assertGate(routeByDollarCommand('MAD-DB')?.id === 'MadDB', '$MAD-DB must resolve to first-class MadDB route', routeByDollarCommand('MAD-DB'));
|
|
20
|
+
assertGate(routeByDollarCommand('MAD-SKS')?.id === 'MadSKS', '$MAD-SKS must remain the scoped permission route', routeByDollarCommand('MAD-SKS'));
|
|
21
|
+
assertGate(prepared.ok === true && prepared.capability.mission_id === prepared.mission_id, 'MadDB prepare must create one authoritative mission/capability', prepared);
|
|
22
|
+
assertGate(prepared.capability.runtime_session_id === 'route-identity-session' && prepared.capability.transport.profile_sha256 === prepared.runtime_profile.profile_sha256, 'capability must bind the runtime profile hash/session', prepared.capability);
|
|
23
|
+
assertGate(isMadDbCapabilityActive(prepared.capability) === true, 'prepared capability must be active/transport-ready', prepared.capability);
|
|
24
|
+
assertGate(proof.ok === true && proof.same_mission === true && proof.route_command === '$MAD-DB', 'route identity proof mismatch', proof);
|
|
25
|
+
await closeMadDbRuntimeProfile({ root, missionId: prepared.mission_id, reason: 'route_identity_check' });
|
|
26
|
+
await closeMadDbCycle(root, prepared.mission_id, prepared.cycle_id, 'route_identity_check');
|
|
27
|
+
emitGate('mad-db:route-identity', { mission_id: prepared.mission_id, cycle_id: prepared.cycle_id, profile_sha256: prepared.runtime_profile.profile_sha256 });
|
|
28
|
+
//# sourceMappingURL=mad-db-route-identity-check.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { createMission } from '../core/mission.js';
|
|
6
|
+
import { createMadDbRuntimeProfile, closeMadDbRuntimeProfile, verifyReadOnlyRestored } from '../core/mad-db/mad-db-runtime-profile.js';
|
|
7
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
8
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-mad-db-runtime-profile-'));
|
|
9
|
+
await fs.mkdir(path.join(root, '.codex'), { recursive: true });
|
|
10
|
+
await fs.writeFile(path.join(root, '.codex', 'config.toml'), [
|
|
11
|
+
'[mcp_servers.supabase]',
|
|
12
|
+
'url = "https://mcp.supabase.com/mcp?project_ref=fixture-project-ref&read_only=true"',
|
|
13
|
+
''
|
|
14
|
+
].join('\n'));
|
|
15
|
+
const mission = await createMission(root, { mode: 'mad-db', prompt: 'runtime profile fixture' });
|
|
16
|
+
const profile = await createMadDbRuntimeProfile({ root, missionId: mission.id, cycleId: 'runtime-profile-cycle', projectRef: 'fixture-project-ref', runtimeSessionId: 'runtime-profile-session' });
|
|
17
|
+
const profileText = await fs.readFile(path.join(root, profile.profile_path), 'utf8');
|
|
18
|
+
const beforeClose = await verifyReadOnlyRestored(root, profile.normal_config_hash_before, path.join(root, profile.profile_path));
|
|
19
|
+
const proof = await closeMadDbRuntimeProfile({ root, missionId: mission.id, profile, reason: 'runtime_profile_lifecycle_check' });
|
|
20
|
+
assertGate(profileText.includes('features=database') && !profileText.includes('read_only=true'), 'runtime profile must be write-capable and database-scoped', { profileText });
|
|
21
|
+
assertGate(beforeClose.ok === false && beforeClose.blockers.includes('runtime_write_profile_still_exists'), 'open runtime profile must be detected before close', beforeClose);
|
|
22
|
+
assertGate(proof.ok === true && proof.persistent_supabase_read_only === true && proof.runtime_profile_exists === false, 'close must remove profile and prove persistent read-only restoration', proof);
|
|
23
|
+
emitGate('mad-db:runtime-profile', { profile_sha256: profile.profile_sha256, restoration_ok: proof.ok });
|
|
24
|
+
//# sourceMappingURL=mad-db-runtime-profile-lifecycle-check.js.map
|
|
@@ -12,11 +12,11 @@ const madSksState = { mission_id: mission.id, mode: 'MADSKS', mad_sks_active: tr
|
|
|
12
12
|
fs.writeFileSync(path.join(mission.dir, 'mad-sks-gate.json'), JSON.stringify({ passed: false, permissions_deactivated: false }, null, 2));
|
|
13
13
|
const catastrophic = await db.checkDbOperation(root, madSksState, { tool_name: 'supabase.execute_sql', sql: 'truncate users;' });
|
|
14
14
|
assertGate(catastrophic.allowed === false && catastrophic.reasons.includes('mad_sks_catastrophic_db_operation_blocked'), 'MAD-SKS catastrophic guard must remain without Mad-DB', catastrophic);
|
|
15
|
-
await capMod.createMadDbCapability(root, { missionId: mission.id, ack: capMod.MAD_DB_ACK, cwd: root });
|
|
16
|
-
const breakGlass = await db.checkDbOperation(root, madSksState, { tool_name: 'supabase.execute_sql', sql: 'truncate users;' });
|
|
15
|
+
await capMod.createMadDbCapability(root, { missionId: mission.id, ack: capMod.MAD_DB_ACK, cwd: root, projectRef: 'fixture-project-ref', status: 'active' });
|
|
16
|
+
const breakGlass = await db.checkDbOperation(root, madSksState, { tool_name: 'supabase.execute_sql', tool_call_id: 'matrix-truncate-active', sql: 'truncate users;' });
|
|
17
17
|
assertGate(breakGlass.allowed === true && breakGlass.mad_db?.active === true, 'Mad-DB must override DB mutation guard only while active', breakGlass);
|
|
18
18
|
await capMod.consumeMadDbCapability(root, mission.id, { consumedBy: 'fixture-cycle-close' });
|
|
19
|
-
const afterConsume = await db.checkDbOperation(root, madSksState, { tool_name: 'supabase.execute_sql', sql: 'truncate users;' });
|
|
19
|
+
const afterConsume = await db.checkDbOperation(root, madSksState, { tool_name: 'supabase.execute_sql', tool_call_id: 'matrix-truncate-closed', sql: 'truncate users;' });
|
|
20
20
|
assertGate(afterConsume.allowed === false, 'after bounded cycle close, MAD-SKS catastrophic guard must block again', afterConsume);
|
|
21
21
|
emitGate('mad-db:safety-conflict-matrix', { states: ['mad-sks-blocks', 'mad-db-allows-cycle', 'mad-sks-blocks-after-cycle-close'] });
|
|
22
22
|
//# sourceMappingURL=mad-db-safety-conflict-matrix-check.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { MAD_DB_POLICY, dbSafetyGuardSkillText, madDbSkillText } from '../core/mad-db/mad-db-policy.js';
|
|
3
|
+
import { assertGate, emitGate, readText } from './sks-1-18-gate-lib.js';
|
|
4
|
+
const madDbSkill = madDbSkillText();
|
|
5
|
+
const dbSafetySkill = dbSafetyGuardSkillText();
|
|
6
|
+
const initText = readText('src/core/init.ts');
|
|
7
|
+
for (const token of ['table/schema DROP', 'all-row mutations', 'TRUNCATE', 'execute_sql', 'apply_migration']) {
|
|
8
|
+
assertGate(madDbSkill.includes(token), `MadDB skill SSOT missing ${token}`, { madDbSkill });
|
|
9
|
+
}
|
|
10
|
+
assertGate(dbSafetySkill.includes('Active MadDB is the explicit exception'), 'db safety skill must name active MadDB exception', { dbSafetySkill });
|
|
11
|
+
assertGate(!madDbSkill.includes('Keep catastrophic safeguards active: whole database/schema/table removal'), 'MadDB skill must not carry old destructive-operation denial text', { madDbSkill });
|
|
12
|
+
assertGate(initText.includes('madDbSkillText()') && initText.includes('dbSafetyGuardSkillText()'), 'init must generate skills from typed MadDB policy SSOT', {});
|
|
13
|
+
assertGate(MAD_DB_POLICY.active_mode.sql_plane === 'allow_all_mutations' && MAD_DB_POLICY.normal_supabase_mcp.read_only_required === true, 'typed policy must encode active SQL-plane and normal read-only modes', MAD_DB_POLICY);
|
|
14
|
+
emitGate('mad-db:skill-policy', { schema: MAD_DB_POLICY.schema, operation_classes: MAD_DB_POLICY.sql_plane_allowed.length });
|
|
15
|
+
//# sourceMappingURL=mad-db-skill-policy-snapshot-check.js.map
|
|
@@ -113,6 +113,12 @@ const requiredReleasePresetIds = [
|
|
|
113
113
|
'team:legacy-create-removed',
|
|
114
114
|
'mad-db:one-cycle-bounded',
|
|
115
115
|
'mad-db:operation-lifecycle-ledger',
|
|
116
|
+
'mad-db:route-identity',
|
|
117
|
+
'mad-db:hook-idempotency',
|
|
118
|
+
'mad-db:parallel-lifecycle',
|
|
119
|
+
'mad-db:runtime-profile',
|
|
120
|
+
'mad-db:skill-policy',
|
|
121
|
+
'mad-db:policy-v2',
|
|
116
122
|
'parallel:strict-pid-proof',
|
|
117
123
|
'parallel:missing-pid-rejection',
|
|
118
124
|
'scheduler:utilization-integral',
|
|
@@ -27,7 +27,11 @@ const result = await dag.runReleaseGateDag({ root: tmp, preset: 'confidence', ch
|
|
|
27
27
|
assertGate(result.triwiki_selection_used === true, 'TriWiki selection must be marked used', result);
|
|
28
28
|
assertGate(result.selected_gate_ids.includes('triwiki:proof-card'), 'TriWiki graph must select the TriWiki gate', result.selected_gate_ids);
|
|
29
29
|
assertGate(!result.selected_gate_ids.includes('scheduler:resource-budget'), 'unaffected scheduler gate must be skipped by TriWiki selection', result);
|
|
30
|
-
|
|
30
|
+
const rootSurfaceResult = await dag.runReleaseGateDag({ root: tmp, preset: 'affected', changedFiles: ['package.json'], noCache: true });
|
|
31
|
+
assertGate(rootSurfaceResult.triwiki_selection_used === false, 'root release surface changes should use focused affected selector instead of expensive TriWiki graph', rootSurfaceResult);
|
|
32
|
+
assertGate(rootSurfaceResult.selected_gate_ids.includes('release:version-truth'), 'root release surface should keep release safety gate', rootSurfaceResult.selected_gate_ids);
|
|
33
|
+
assertGate(!rootSurfaceResult.selected_gate_ids.includes('scheduler:resource-budget'), 'root release surface affected selector should not full-sweep unrelated scheduler gate', rootSurfaceResult.selected_gate_ids);
|
|
34
|
+
emitGate('release:triwiki-first-runner-blackbox', { selected: result.selected_gate_ids, skipped: result.triwiki_skipped_gates, root_surface_selected: rootSurfaceResult.selected_gate_ids });
|
|
31
35
|
function gate(id, inputs) {
|
|
32
36
|
return {
|
|
33
37
|
id,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.2.0",
|
|
5
5
|
"description": "Sneakoscope Codex: fast proof-first Codex trust layer with image-based Voxel TriWiki.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
|
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
"fast:codex-service-tier-proof": "node ./dist/scripts/fast-codex-service-tier-proof-check.js",
|
|
175
175
|
"codex:project-config-policy-splitter": "node ./dist/scripts/codex-project-config-policy-splitter-check.js",
|
|
176
176
|
"test:no-orphan-dist-imports": "node ./dist/scripts/test-no-orphan-dist-imports-check.js",
|
|
177
|
-
"packcheck": "
|
|
177
|
+
"packcheck": "for d in bin test; do [ -d \"$d\" ] && find \"$d\" -name '*.mjs' -print0; done | xargs -0 -n1 node --check && npm run runtime:no-src-mjs",
|
|
178
178
|
"changelog:check": "node ./dist/scripts/changelog-check.js",
|
|
179
179
|
"cli-entrypoint:check": "node ./dist/scripts/check-cli-entrypoint.js",
|
|
180
180
|
"legacy-free:check": "node ./dist/scripts/check-legacy-free.js",
|
|
@@ -362,7 +362,7 @@
|
|
|
362
362
|
"release:publish": "npm run publish:npm",
|
|
363
363
|
"publish:dry": "npm run release:metadata && npm run release:version-truth && npm run publish:packlist-performance && npm run release:check:full && node ./dist/scripts/check-publish-tag.js && node ./dist/scripts/release-check-stamp.js verify && npm run release:provenance -- --publish && npm run release:dist-freshness && node ./dist/scripts/release-registry-check.js --require-unpublished && npm --cache /tmp/sks-npm-cache publish --dry-run --ignore-scripts --registry https://registry.npmjs.org/ --access public",
|
|
364
364
|
"publish:npm": "npm --cache /tmp/sks-npm-cache publish --registry https://registry.npmjs.org/ --access public",
|
|
365
|
-
"publish:fast": "
|
|
365
|
+
"publish:fast": "node -e \"console.error('publish:fast is quarantined; use publish:dry and publish:npm with the release gates.'); process.exit(1)\"",
|
|
366
366
|
"prepack": "npm run build",
|
|
367
367
|
"prepublishOnly": "npm run release:metadata && npm run release:version-truth && npm run release:dist-freshness && npm run publish:packlist-performance && node ./dist/scripts/prepublish-release-check-or-fast.js && node ./dist/scripts/check-publish-tag.js && node ./dist/scripts/release-check-stamp.js verify && npm run release:provenance -- --publish && node ./dist/scripts/release-registry-check.js --require-unpublished --require-publish-auth",
|
|
368
368
|
"dist:check": "node ./dist/scripts/check-dist-runtime.js",
|
|
@@ -719,6 +719,12 @@
|
|
|
719
719
|
"team:legacy-create-removed": "node ./dist/scripts/team-legacy-create-removed-check.js",
|
|
720
720
|
"mad-db:one-cycle-bounded": "node ./dist/scripts/mad-db-one-cycle-bounded-check.js",
|
|
721
721
|
"mad-db:operation-lifecycle-ledger": "node ./dist/scripts/mad-db-operation-lifecycle-ledger-check.js",
|
|
722
|
+
"mad-db:route-identity": "node ./dist/scripts/mad-db-route-identity-check.js",
|
|
723
|
+
"mad-db:hook-idempotency": "node ./dist/scripts/mad-db-hook-idempotency-check.js",
|
|
724
|
+
"mad-db:parallel-lifecycle": "node ./dist/scripts/mad-db-parallel-lifecycle-check.js",
|
|
725
|
+
"mad-db:runtime-profile": "node ./dist/scripts/mad-db-runtime-profile-lifecycle-check.js",
|
|
726
|
+
"mad-db:skill-policy": "node ./dist/scripts/mad-db-skill-policy-snapshot-check.js",
|
|
727
|
+
"mad-db:policy-v2": "node ./dist/scripts/mad-db-policy-v2-check.js",
|
|
722
728
|
"release:speed-summary": "node ./dist/scripts/release-speed-summary-check.js",
|
|
723
729
|
"release:speed-summary:check": "node ./dist/scripts/release-speed-summary-check.js",
|
|
724
730
|
"naruto:ssot-routing": "node ./dist/scripts/naruto-ssot-routing-check.js",
|
|
@@ -752,6 +758,10 @@
|
|
|
752
758
|
"mad-db:lifecycle-hook-decision": "node ./dist/scripts/mad-db-lifecycle-hook-decision-check.js",
|
|
753
759
|
"mad-db:mcp-result-lifecycle": "node ./dist/scripts/mad-db-mcp-result-lifecycle-check.js",
|
|
754
760
|
"mad-db:operation-lifecycle-blackbox": "node ./dist/scripts/mad-db-operation-lifecycle-blackbox.js",
|
|
761
|
+
"mad-db:unit": "npm run mad-db:capability && npm run mad-db:command && npm run mad-db:mad-command && npm run mad-db:priority-resolver && npm run mad-db:ledger && npm run mad-db:one-cycle-consumption && npm run mad-db:safety-conflict-matrix && npm run mad-db:one-cycle-bounded && npm run mad-db:operation-lifecycle-ledger && npm run mad-db:route-identity && npm run mad-db:hook-idempotency && npm run mad-db:parallel-lifecycle && npm run mad-db:runtime-profile && npm run mad-db:skill-policy && npm run mad-db:policy-v2 && npm run mad-db:lifecycle-hook-decision && npm run mad-db:mcp-result-lifecycle && npm run mad-db:operation-lifecycle-blackbox",
|
|
762
|
+
"mad-db:real-e2e": "node ./dist/scripts/mad-db-real-supabase-e2e.js --require-real",
|
|
763
|
+
"mad-db:all": "npm run build && npm run mad-db:unit",
|
|
764
|
+
"mad-db:release": "npm run mad-db:all && npm run mad-db:real-e2e",
|
|
755
765
|
"runtime:proof-summary": "node ./dist/scripts/runtime-proof-summary-check.js",
|
|
756
766
|
"runtime:proof-summary-cli": "node ./dist/scripts/runtime-proof-summary-cli-check.js",
|
|
757
767
|
"codex-app:launcher": "node ./dist/scripts/codex-app-launcher-check.js",
|
|
@@ -1,31 +1,104 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "sks.mad-db-capability.
|
|
3
|
+
"$id": "sks.mad-db-capability.v2",
|
|
4
4
|
"type": "object",
|
|
5
|
-
"required": [
|
|
5
|
+
"required": [
|
|
6
|
+
"schema",
|
|
7
|
+
"revision",
|
|
8
|
+
"mission_id",
|
|
9
|
+
"cycle_id",
|
|
10
|
+
"project_root_hash",
|
|
11
|
+
"project_ref",
|
|
12
|
+
"target_environment",
|
|
13
|
+
"allowed_schemas",
|
|
14
|
+
"runtime_session_id",
|
|
15
|
+
"operator_intent_hash",
|
|
16
|
+
"operator_ack_hash",
|
|
17
|
+
"scope",
|
|
18
|
+
"transport",
|
|
19
|
+
"issued_at",
|
|
20
|
+
"expires_at",
|
|
21
|
+
"closed_at",
|
|
22
|
+
"status",
|
|
23
|
+
"counters"
|
|
24
|
+
],
|
|
6
25
|
"properties": {
|
|
7
|
-
"schema": { "const": "sks.mad-db-capability.
|
|
26
|
+
"schema": { "const": "sks.mad-db-capability.v2" },
|
|
27
|
+
"revision": { "type": "integer", "minimum": 1 },
|
|
8
28
|
"mission_id": { "type": "string", "pattern": "^M-" },
|
|
9
|
-
"cycle_id": { "type": "string" },
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
29
|
+
"cycle_id": { "type": "string", "pattern": "^mad-db-" },
|
|
30
|
+
"project_root_hash": { "type": "string", "minLength": 8 },
|
|
31
|
+
"project_ref": { "type": "string", "minLength": 1 },
|
|
32
|
+
"target_environment": { "enum": ["local", "branch", "preview", "production"] },
|
|
33
|
+
"allowed_schemas": { "type": "array", "items": { "type": "string" } },
|
|
34
|
+
"codex_thread_id": { "type": ["string", "null"] },
|
|
35
|
+
"runtime_session_id": { "type": "string", "minLength": 1 },
|
|
36
|
+
"operator_intent_hash": { "type": "string", "minLength": 8 },
|
|
37
|
+
"operator_ack_hash": { "type": "string", "minLength": 8 },
|
|
38
|
+
"scope": {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"required": ["sql_plane", "control_plane", "operations"],
|
|
41
|
+
"properties": {
|
|
42
|
+
"sql_plane": { "const": "all_mutations" },
|
|
43
|
+
"control_plane": { "const": "deny" },
|
|
44
|
+
"operations": {
|
|
45
|
+
"type": "array",
|
|
46
|
+
"items": {
|
|
47
|
+
"enum": [
|
|
48
|
+
"create",
|
|
49
|
+
"alter",
|
|
50
|
+
"drop",
|
|
51
|
+
"drop_database_sql",
|
|
52
|
+
"insert",
|
|
53
|
+
"update",
|
|
54
|
+
"delete",
|
|
55
|
+
"all_row_update",
|
|
56
|
+
"all_row_delete",
|
|
57
|
+
"truncate",
|
|
58
|
+
"migration_apply",
|
|
59
|
+
"direct_execute_sql",
|
|
60
|
+
"rls_policy_change",
|
|
61
|
+
"function_or_trigger_change",
|
|
62
|
+
"index_change",
|
|
63
|
+
"unknown_sql_mutation"
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"additionalProperties": false
|
|
69
|
+
},
|
|
70
|
+
"transport": {
|
|
17
71
|
"type": "object",
|
|
18
|
-
"required": ["
|
|
72
|
+
"required": ["profile_path", "profile_sha256", "server_url_redacted", "features", "write_capable"],
|
|
19
73
|
"properties": {
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
74
|
+
"profile_path": { "type": "string", "minLength": 1 },
|
|
75
|
+
"profile_sha256": { "type": "string", "minLength": 8 },
|
|
76
|
+
"server_url_redacted": { "type": "string", "minLength": 1 },
|
|
77
|
+
"features": {
|
|
78
|
+
"type": "array",
|
|
79
|
+
"prefixItems": [{ "const": "database" }],
|
|
80
|
+
"minItems": 1,
|
|
81
|
+
"maxItems": 1
|
|
82
|
+
},
|
|
83
|
+
"write_capable": { "const": true }
|
|
23
84
|
},
|
|
24
|
-
"additionalProperties":
|
|
85
|
+
"additionalProperties": false
|
|
25
86
|
},
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
87
|
+
"issued_at": { "type": "string" },
|
|
88
|
+
"expires_at": { "type": "string" },
|
|
89
|
+
"closed_at": { "type": ["string", "null"] },
|
|
90
|
+
"status": { "enum": ["issued", "transport_ready", "active", "closing", "closed", "revoked", "expired", "quarantined"] },
|
|
91
|
+
"counters": {
|
|
92
|
+
"type": "object",
|
|
93
|
+
"required": ["attempts", "reserved", "succeeded", "failed"],
|
|
94
|
+
"properties": {
|
|
95
|
+
"attempts": { "type": "integer", "minimum": 0 },
|
|
96
|
+
"reserved": { "type": "integer", "minimum": 0 },
|
|
97
|
+
"succeeded": { "type": "integer", "minimum": 0 },
|
|
98
|
+
"failed": { "type": "integer", "minimum": 0 }
|
|
99
|
+
},
|
|
100
|
+
"additionalProperties": false
|
|
101
|
+
}
|
|
29
102
|
},
|
|
30
103
|
"additionalProperties": true
|
|
31
104
|
}
|