sneakoscope 0.6.85 → 0.6.89

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 CHANGED
@@ -90,6 +90,8 @@ sks bootstrap
90
90
 
91
91
  `sks` commands work even when no project root is present. Project-aware commands use the nearest `.sneakoscope`, `.dcodex`, or `.git` root; if none exists, SKS uses a per-user global runtime root. `sks bootstrap` still initializes the current project when you want project-local hooks, skills, and TriWiki state.
92
92
 
93
+ Project setup writes shared `.gitignore` entries for generated SKS files: `.sneakoscope/`, `.codex/`, `.agents/`, and managed `AGENTS.md`. Use `sks setup --local-only` when you want those excludes kept only in `.git/info/exclude`.
94
+
93
95
  ### One-Shot Install
94
96
 
95
97
  Use this when you do not want to keep a global install:
@@ -215,6 +217,8 @@ sks gx init homepage
215
217
  sks gx render homepage --format html
216
218
  sks validate-artifacts latest --json
217
219
  sks perf run --json
220
+ sks perf workflow --json --intent "small CLI change" --changed src/cli/main.mjs,src/core/routes.mjs
221
+ sks proof-field scan --json --intent "small CLI change"
218
222
  sks code-structure scan --json
219
223
  ```
220
224
 
@@ -254,6 +258,8 @@ Generated app files include:
254
258
  | `.codex/config.toml` | Codex profiles, agents, and MCP configuration. |
255
259
  | `.sneakoscope/` | Runtime state, missions, wiki packs, policies, and artifacts. |
256
260
 
261
+ Default setup adds these generated SKS paths to the project `.gitignore`; `--local-only` uses `.git/info/exclude` instead.
262
+
257
263
  Use `sks dollar-commands` to confirm that terminal discovery and Codex App prompt commands agree.
258
264
 
259
265
  TriWiki is intentionally sparse: `sks wiki sweep` records demote, soft-forget, archive, delete, promote-to-skill, and promote-to-rule candidates instead of injecting every old claim into future prompts. `sks harness fixture` validates the broader Harness Growth Factory contract: deliberate forgetting fixtures, skill card metadata, experiment schema, tool-error taxonomy, permission profiles, MultiAgentV2 defaults, and Warp cockpit view coverage. `sks code-structure scan` flags handwritten files above 1000/2000/3000-line thresholds so new logic can be extracted before command files become harder to maintain.
@@ -274,7 +280,7 @@ Use these inside Codex App or another agent prompt. They are prompt commands, no
274
280
  | `$Research` | You need frontier-style research with hypotheses and falsification. |
275
281
  | `$AutoResearch` | You want iterative improve/test/keep-or-discard optimization. |
276
282
  | `$DB` | You need database, Supabase, migration, SQL, or MCP safety checks. |
277
- | `$MAD-SKS` | You explicitly authorize a scoped high-risk DB permission modifier for the active invocation only. |
283
+ | `$MAD-SKS` | You explicitly authorize scoped Supabase MCP DB cleanup/write permissions for the active invocation only, while keeping catastrophic wipe safeguards. |
278
284
  | `$GX` | You need deterministic visual context cartridges. |
279
285
  | `$Wiki` | You want TriWiki refresh, pack, prune, validate, or maintenance. |
280
286
  | `$Help` | You want installed command and workflow explanation. |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "ㅅㅋㅅ",
4
- "version": "0.6.85",
4
+ "version": "0.6.89",
5
5
  "description": "Sneakoscope Codex: database-safe Codex CLI/App harness with Team, Goal, AutoResearch, TriWiki, and Honest Mode.",
6
6
  "type": "module",
7
7
  "homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
package/src/cli/main.mjs CHANGED
@@ -14,7 +14,7 @@ import { containsUserQuestion, noQuestionContinuationReason } from '../core/no-q
14
14
  import { evaluateDoneGate, defaultDoneGate } from '../core/hproof.mjs';
15
15
  import { emitHook } from '../core/hooks-runtime.mjs';
16
16
  import { storageReport, enforceRetention, pruneWikiArtifacts } from '../core/retention.mjs';
17
- import { classifySql, classifyCommand, loadDbSafetyPolicy, safeSupabaseMcpConfig, checkSqlFile, checkDbOperation, scanDbSafety, handleMadSksUserConfirmation } from '../core/db-safety.mjs';
17
+ import { classifySql, classifyCommand, checkDbOperation, handleMadSksUserConfirmation } from '../core/db-safety.mjs';
18
18
  import { checkHarnessModification, harnessGuardStatus, isHarnessSourceProject } from '../core/harness-guard.mjs';
19
19
  import { formatHarnessConflictReport, llmHarnessCleanupPrompt, scanHarnessConflicts } from '../core/harness-conflicts.mjs';
20
20
  import { context7Docs, context7Resolve, context7Text, context7Tools } from '../core/context7-client.mjs';
@@ -36,6 +36,8 @@ import { buildFromChatImgVisualMap } from '../core/from-chat-img-forensics.mjs';
36
36
  import { classifyDogfoodFinding, createDogfoodReport, writeDogfoodReport } from '../core/dogfood-loop.mjs';
37
37
  import { createSkillCandidate, decideSkillInjection, writeSkillCandidate, writeSkillForgeReport, writeSkillInjectionDecision } from '../core/skill-forge.mjs';
38
38
  import { classifyToolError, harnessGrowthReport } from '../core/evaluation.mjs';
39
+ import { runWorkflowPerfBench, validateWorkflowPerfReport } from '../core/perf-bench.mjs';
40
+ import { proofFieldFixture, validateProofFieldReport } from '../core/proof-field.mjs';
39
41
  import { recordMistake, writeMistakeMemoryReport } from '../core/mistake-memory.mjs';
40
42
  import { buildPromptContext } from '../core/prompt-context-builder.mjs';
41
43
  import { renderTeamDashboardState, writeTeamDashboardState } from '../core/team-dashboard-renderer.mjs';
@@ -43,11 +45,10 @@ import { GOAL_WORKFLOW_ARTIFACT } from '../core/goal-workflow.mjs';
43
45
  import { CODEX_APP_DOCS_URL, codexAppIntegrationStatus, formatCodexAppStatus } from '../core/codex-app.mjs';
44
46
  import { buildWarpLaunchConfigYaml, buildWarpLaunchPlan, buildWarpOpenArgs, runWarpLaunchConfigSyntaxCheck, warpReadiness, warpStatusKind, defaultWarpWorkspaceName, formatWarpBanner, launchWarpTeamView, launchWarpUi, platformWarpInstallHint, runWarpStatus, sanitizeWarpWorkspaceName, teamLaneStyle, writeWarpLaunchConfig } from '../core/warp-ui.mjs';
45
47
  import { autoReviewProfileName, autoReviewStatus, autoReviewSummary, enableAutoReview, disableAutoReview, enableMadHighProfile, madHighProfileName } from '../core/auto-review.mjs';
46
- import { buildTeamPlan, codeStructureCommand, defaultBeta, defaultVGraph, evalCommand, gcCommand, goalCommand, gxCommand, harnessCommand, hproofCommand, memoryCommand, migrateWikiContextPack, parseTeamCreateArgs, perfCommand, profileCommand, projectWikiClaims, qaLoopCommand, researchCommand, statsCommand, team, teamWorkflowMarkdown, validateArtifactsCommand, wikiCommand, wikiVoxelRowCount, writeWikiContextPack } from './maintenance-commands.mjs';
48
+ import { buildTeamPlan, codeStructureCommand, dbCommand, defaultBeta, defaultVGraph, evalCommand, gcCommand, goalCommand, gxCommand, harnessCommand, hproofCommand, memoryCommand, migrateWikiContextPack, parseTeamCreateArgs, perfCommand, profileCommand, projectWikiClaims, proofFieldCommand, qaLoopCommand, quickstartCommand, researchCommand, statsCommand, team, teamWorkflowMarkdown, validateArtifactsCommand, wikiCommand, wikiVoxelRowCount, writeWikiContextPack } from './maintenance-commands.mjs';
47
49
 
48
50
  const flag = (args, name) => args.includes(name);
49
51
  const promptOf = (args) => args.filter((x) => !String(x).startsWith('--')).join(' ').trim();
50
- const REPOSITORY_URL = 'https://github.com/mandarange/Sneakoscope-Codex.git';
51
52
  const REFLECTION_ARTIFACT = 'reflection.md';
52
53
  const REFLECTION_GATE = 'reflection-gate.json';
53
54
  const TEAM_SESSION_CLEANUP_ARTIFACT = 'team-session-cleanup.json';
@@ -76,7 +77,7 @@ export async function main(args) {
76
77
  if (cmd === 'commands') return commands(tail);
77
78
  if (cmd === 'usage') return usage(tail);
78
79
  if (cmd === 'root') return rootCommand(tail);
79
- if (cmd === 'quickstart') return quickstart();
80
+ if (cmd === 'quickstart') return quickstartCommand();
80
81
  if (cmd === 'codex-app') return codexAppHelp(tail);
81
82
  if (cmd === 'bootstrap') return bootstrap(tail);
82
83
  if (cmd === 'deps') return deps(sub, rest);
@@ -102,11 +103,12 @@ export async function main(args) {
102
103
  if (cmd === 'hproof') return hproofCommand(sub, rest);
103
104
  if (cmd === 'validate-artifacts') return validateArtifactsCommand(tail);
104
105
  if (cmd === 'perf') return perfCommand(sub, rest);
106
+ if (cmd === 'proof-field') return proofFieldCommand(sub, rest);
105
107
  if (cmd === 'code-structure') return codeStructureCommand(sub, rest);
106
108
  if (cmd === 'memory') return memoryCommand(sub, rest);
107
109
  if (cmd === 'gx') return gxCommand(sub, rest);
108
110
  if (cmd === 'team') return team(tail);
109
- if (cmd === 'db') return db(sub, rest);
111
+ if (cmd === 'db') return dbCommand(sub, rest);
110
112
  if (cmd === 'eval') return evalCommand(sub, rest);
111
113
  if (cmd === 'harness') return harnessCommand(sub, rest);
112
114
  if (cmd === 'wiki') return wikiCommand(sub, rest);
@@ -178,7 +180,8 @@ Usage:
178
180
  sks validate-artifacts [mission-id|latest] [--json]
179
181
  sks eval run [--json] [--out report.json]
180
182
  sks eval compare --baseline old.json --candidate new.json [--json]
181
- sks perf run [--json]
183
+ sks perf run|workflow [--json] [--intent "task"] [--changed file1,file2]
184
+ sks proof-field scan [--json] [--intent "task"]
182
185
  sks harness fixture [--json]
183
186
  sks code-structure scan [--json]
184
187
  sks wiki coords --rgba 12,34,56,255
@@ -812,15 +815,16 @@ async function materializeAfterPipelineAnswer(root, id, dir, mission, route, rou
812
815
  passed: false,
813
816
  mad_sks_permission_active: true,
814
817
  permissions_deactivated: false,
815
- table_delete_confirmation_required: true,
816
- table_delete_confirmation_timeout_ms: 30000,
818
+ supabase_mcp_schema_cleanup_allowed: true,
819
+ direct_execute_sql_allowed: true,
820
+ catastrophic_safety_guard_active: true,
817
821
  contract_hash: contract.sealed_hash || null
818
822
  });
819
823
  await appendJsonlBounded(path.join(dir, 'events.jsonl'), {
820
824
  ts: nowIso(),
821
825
  type: 'mad_sks.scoped_permission_opened',
822
826
  route: route.id,
823
- table_delete_confirmation_timeout_ms: 30000
827
+ catastrophic_safety_guard_active: true
824
828
  });
825
829
  return {
826
830
  phase: 'MADSKS_SCOPED_PERMISSION_ACTIVE',
@@ -830,7 +834,9 @@ async function materializeAfterPipelineAnswer(root, id, dir, mission, route, rou
830
834
  mad_sks_modifier: true,
831
835
  mad_sks_gate_file: 'mad-sks-gate.json',
832
836
  mad_sks_gate_ready: true,
833
- table_delete_confirmation_timeout_ms: 30000
837
+ supabase_mcp_schema_cleanup_allowed: true,
838
+ direct_execute_sql_allowed: true,
839
+ catastrophic_safety_guard_active: true
834
840
  }
835
841
  };
836
842
  }
@@ -901,8 +907,9 @@ async function materializeMadSksAuthorization(dir, id, route, routeContext = {},
901
907
  status: 'active',
902
908
  active_only_for_current_route: true,
903
909
  deactivates_when_gate_passed: gateFile,
904
- table_delete_confirmation_required: true,
905
- table_delete_confirmation_timeout_ms: 30000,
910
+ supabase_mcp_schema_cleanup_allowed: true,
911
+ direct_execute_sql_allowed: true,
912
+ catastrophic_safety_guard_active: true,
906
913
  contract_hash: contract.sealed_hash || null
907
914
  };
908
915
  await writeJsonAtomic(path.join(dir, 'mad-sks-authorization.json'), artifact);
@@ -911,13 +918,15 @@ async function materializeMadSksAuthorization(dir, id, route, routeContext = {},
911
918
  type: 'mad_sks.modifier_authorization_opened',
912
919
  route: route?.id || null,
913
920
  gate: gateFile,
914
- table_delete_confirmation_timeout_ms: 30000
921
+ catastrophic_safety_guard_active: true
915
922
  });
916
923
  return {
917
924
  mad_sks_active: true,
918
925
  mad_sks_modifier: true,
919
926
  mad_sks_gate_file: gateFile,
920
- table_delete_confirmation_timeout_ms: 30000
927
+ supabase_mcp_schema_cleanup_allowed: true,
928
+ direct_execute_sql_allowed: true,
929
+ catastrophic_safety_guard_active: true
921
930
  };
922
931
  }
923
932
 
@@ -1346,60 +1355,6 @@ async function autoReviewCommand(sub = 'status', args = []) {
1346
1355
  process.exitCode = 1;
1347
1356
  }
1348
1357
 
1349
- function quickstart() {
1350
- console.log(`ㅅㅋㅅ Quickstart
1351
-
1352
- First install and bootstrap this project:
1353
- npm i -g sneakoscope
1354
- sks root
1355
- sks bootstrap
1356
- sks
1357
-
1358
- Use outside a project:
1359
- sks root
1360
- sks deps check
1361
- sks team "global mission"
1362
-
1363
- If warp is missing:
1364
- sks deps install warp
1365
-
1366
- Initialize this project for CLI and Codex App:
1367
- sks setup --bootstrap
1368
-
1369
- Open from terminal:
1370
- sks
1371
- sks --auto-review --high
1372
- sks auto-review start --high
1373
-
1374
- Verify:
1375
- sks deps check
1376
- sks codex-app check
1377
- sks warp check
1378
- sks auto-review status
1379
- sks doctor --fix
1380
- sks context7 check
1381
- sks selftest --mock
1382
- sks commands
1383
- sks dollar-commands
1384
-
1385
- If hooks cannot find the command:
1386
- sks fix-path
1387
-
1388
- Project-only install:
1389
- npm i -D sneakoscope
1390
- npx sks setup --install-scope project
1391
-
1392
- Local-only install artifacts:
1393
- sks setup --local-only
1394
- # writes generated SKS files but excludes .sneakoscope/, .codex/, .agents/, AGENTS.md through .git/info/exclude
1395
- # user-owned AGENTS.md is preserved; an existing SKS managed block is refreshed
1396
-
1397
- GitHub install for unreleased commits:
1398
- npm i -g git+${REPOSITORY_URL}
1399
- sks bootstrap
1400
- `);
1401
- }
1402
-
1403
1358
  async function codexAppHelp(args = []) {
1404
1359
  const action = args[0] || 'help';
1405
1360
  if (action === 'check' || action === 'status') {
@@ -1430,6 +1385,7 @@ async function codexAppHelp(args = []) {
1430
1385
  `Skills: project=${skills.project.ok ? 'ok' : `missing ${skills.project.missing.length}`} global=${skills.global.ok ? 'ok' : `missing ${skills.global.missing.length}`}`, '',
1431
1386
  'Setup:', ' sks bootstrap', ' sks deps check', ' sks codex-app check', ' sks warp check', '',
1432
1387
  'Generated files:', ' .codex/config.toml', ' .codex/hooks.json', ' .agents/skills/', ' .codex/agents/', ' .codex/SNEAKOSCOPE.md', ' AGENTS.md', '',
1388
+ 'Git ignore:', ' default setup writes .gitignore entries for .sneakoscope/, .codex/, .agents/, AGENTS.md', ' --local-only writes those patterns to .git/info/exclude instead', '',
1433
1389
  'Prompt routes:', formatDollarCommandsCompact(' ')
1434
1390
  ].join('\n'));
1435
1391
  }
@@ -1609,6 +1565,7 @@ async function setup(args) {
1609
1565
  console.log(`Hooks: ${path.relative(root, hooksPath)}`);
1610
1566
  console.log(`Version: ${versioningInfo.enabled ? (versioningInfo.hook_installed ? 'auto-bump enabled' : 'auto-bump hook missing') : 'not enabled'}${versioningInfo.package_version ? ` (${versioningInfo.package_version})` : ''}`);
1611
1567
  if (localOnly) console.log('Git: local-only (.git/info/exclude; user AGENTS preserved, SKS managed block refreshed)');
1568
+ else console.log('Git: .gitignore ignores SKS generated files');
1612
1569
  console.log(`Codex App: .codex/config.toml, .codex/hooks.json, .agents/skills, .codex/agents, .codex/SNEAKOSCOPE.md`);
1613
1570
  console.log(`Global $: ${globalSkills.status === 'installed' ? 'ok' : globalSkills.status} ${globalSkills.root || ''}`.trimEnd());
1614
1571
  console.log(`App tools: ${appRuntime.ok ? 'ok' : 'needs setup'} Codex App=${appRuntime.app.installed ? 'ok' : 'missing'} Browser Use=${appRuntime.mcp.has_browser_use ? 'ok' : 'missing'} Computer Use=${appRuntime.mcp.has_computer_use ? 'ok' : 'missing'}`);
@@ -1804,6 +1761,7 @@ async function init(args) {
1804
1761
  console.log(`Initialized ㅅㅋㅅ in ${root}`);
1805
1762
  console.log(`Install scope: ${installScope} (${sksCommandPrefix(installScope, { globalCommand })})`);
1806
1763
  if (localOnly) console.log('Git mode: local-only (.git/info/exclude)');
1764
+ else console.log('Git mode: shared .gitignore');
1807
1765
  for (const x of res.created) console.log(`- ${x}`);
1808
1766
  }
1809
1767
 
@@ -2012,9 +1970,11 @@ async function selftest() {
2012
1970
  await writeJsonAtomic(path.join(postinstallBootstrapTmp, 'package.json'), { name: 'postinstall-bootstrap-smoke', version: '0.0.0' });
2013
1971
  const postinstallBootstrap = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'postinstall'], { cwd: postinstallBootstrapTmp, input: 'y\n', env: { INIT_CWD: postinstallBootstrapTmp, HOME: path.join(postinstallBootstrapTmp, 'home'), SKS_SKIP_POSTINSTALL_SHIM: '1', SKS_SKIP_POSTINSTALL_CONTEXT7: '1', SKS_SKIP_POSTINSTALL_GLOBAL_SKILLS: '1', SKS_SKIP_CLI_TOOLS: '1', SKS_POSTINSTALL_PROMPT: '1' }, timeoutMs: 30000, maxOutputBytes: 256 * 1024 });
2014
1972
  if (postinstallBootstrap.code !== 0 || !String(postinstallBootstrap.stdout || '').includes('SKS Ready')) throw new Error(`selftest failed: approved postinstall bootstrap did not run: ${postinstallBootstrap.stderr}`);
2015
- for (const rel of ['.agents/skills/team/SKILL.md', '.codex/config.toml', '.codex/hooks.json', '.sneakoscope/harness-guard.json', '.codex/SNEAKOSCOPE.md', 'AGENTS.md']) {
1973
+ for (const rel of ['.agents/skills/team/SKILL.md', '.codex/config.toml', '.codex/hooks.json', '.sneakoscope/harness-guard.json', '.codex/SNEAKOSCOPE.md', 'AGENTS.md', '.gitignore']) {
2016
1974
  if (!(await exists(path.join(postinstallBootstrapTmp, rel)))) throw new Error(`selftest failed: bootstrap did not create ${rel}`);
2017
1975
  }
1976
+ const postinstallBootstrapGitignore = await safeReadText(path.join(postinstallBootstrapTmp, '.gitignore'));
1977
+ if (!postinstallBootstrapGitignore.includes('.sneakoscope/') || !postinstallBootstrapGitignore.includes('.codex/') || !postinstallBootstrapGitignore.includes('.agents/') || !postinstallBootstrapGitignore.includes('AGENTS.md')) throw new Error('selftest failed: bootstrap did not ignore SKS generated files');
2018
1978
  const bootstrapJsonTmp = tmpdir();
2019
1979
  await writeJsonAtomic(path.join(bootstrapJsonTmp, 'package.json'), { name: 'bootstrap-json-smoke', version: '0.0.0' });
2020
1980
  const bootstrapJson = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'bootstrap', '--json'], { cwd: bootstrapJsonTmp, env: { HOME: path.join(bootstrapJsonTmp, 'home'), SKS_SKIP_POSTINSTALL_GLOBAL_SKILLS: '1', SKS_SKIP_CLI_TOOLS: '1' }, timeoutMs: 30000, maxOutputBytes: 256 * 1024 });
@@ -2135,10 +2095,19 @@ async function selftest() {
2135
2095
  await initProject(localOnlyTmp, { localOnly: true });
2136
2096
  const localExclude = await safeReadText(path.join(localOnlyTmp, '.git', 'info', 'exclude'));
2137
2097
  if (!localExclude.includes('.codex/') || !localExclude.includes('AGENTS.md')) throw new Error('selftest failed: local-only git excludes missing');
2098
+ if (await exists(path.join(localOnlyTmp, '.gitignore'))) throw new Error('selftest failed: local-only wrote shared .gitignore');
2138
2099
  const localAgents = await safeReadText(path.join(localOnlyTmp, 'AGENTS.md'));
2139
2100
  if (localAgents.trim() !== 'existing local rules') throw new Error('selftest failed: local-only modified existing AGENTS.md');
2140
2101
  const localManifest = await readJson(path.join(localOnlyTmp, '.sneakoscope', 'manifest.json'));
2141
2102
  if (!localManifest.git?.local_only) throw new Error('selftest failed: local-only manifest missing');
2103
+ const gitignoreTmp = tmpdir();
2104
+ await writeTextAtomic(path.join(gitignoreTmp, '.gitignore'), 'node_modules/\n.sneakoscope/\n');
2105
+ await initProject(gitignoreTmp, {});
2106
+ const gitignoreText = await safeReadText(path.join(gitignoreTmp, '.gitignore'));
2107
+ if (!gitignoreText.includes('node_modules/') || !gitignoreText.includes('# BEGIN Sneakoscope Codex generated files') || !gitignoreText.includes('.codex/') || !gitignoreText.includes('.agents/') || !gitignoreText.includes('AGENTS.md')) throw new Error('selftest failed: shared .gitignore did not preserve existing entries and add SKS patterns');
2108
+ await initProject(gitignoreTmp, {});
2109
+ const gitignoreTextSecond = await safeReadText(path.join(gitignoreTmp, '.gitignore'));
2110
+ if ((gitignoreTextSecond.match(/BEGIN Sneakoscope Codex generated files/g) || []).length !== 1) throw new Error('selftest failed: shared .gitignore managed block duplicated');
2142
2111
  const managedAgentsTmp = tmpdir();
2143
2112
  await ensureDir(path.join(managedAgentsTmp, '.git'));
2144
2113
  await writeTextAtomic(path.join(managedAgentsTmp, 'AGENTS.md'), '<!-- BEGIN Sneakoscope Codex GX MANAGED BLOCK -->\nold managed rules\n<!-- END Sneakoscope Codex GX MANAGED BLOCK -->\n');
@@ -2904,17 +2873,17 @@ async function selftest() {
2904
2873
  const madMission = await createMission(tmp, { mode: 'mad-sks', prompt: '$MAD-SKS selftest scoped DB override' });
2905
2874
  await writeJsonAtomic(path.join(madMission.dir, 'team-gate.json'), { schema_version: 1, passed: false, team_roster_confirmed: true });
2906
2875
  const madState = { mission_id: madMission.id, mode: 'TEAM', route_command: '$Team', stop_gate: 'team-gate.json', mad_sks_active: true, mad_sks_modifier: true, mad_sks_gate_file: 'team-gate.json' };
2876
+ const columnCleanupSql = 'alter table users ' + 'dr' + 'op column legacy_name;';
2877
+ const madColumnCleanupDecision = await checkDbOperation(tmp, madState, { tool_name: 'mcp__supabase__execute_sql', sql: columnCleanupSql }, { duringNoQuestion: false });
2878
+ if (madColumnCleanupDecision.action !== 'allow') throw new Error('selftest failed: MAD-SKS column cleanup was not allowed');
2907
2879
  const tableRemovalSql = 'dr' + 'op table users;';
2908
- const madNeedsConfirmation = await checkDbOperation(tmp, madState, { tool_name: 'mcp__supabase__execute_sql', sql: tableRemovalSql }, { duringNoQuestion: false });
2909
- if (madNeedsConfirmation.action !== 'confirm') throw new Error('selftest failed: MAD-SKS table deletion did not require confirmation');
2910
- await setCurrent(tmp, madState);
2911
- const madConfirmation = await handleMadSksUserConfirmation(tmp, madState, 'yes');
2912
- if (!madConfirmation?.handled) throw new Error('selftest failed: MAD-SKS confirmation was not accepted');
2913
- const madConfirmedState = await readJson(stateFile(tmp), {});
2914
- const madConfirmedDecision = await checkDbOperation(tmp, madConfirmedState, { tool_name: 'mcp__supabase__execute_sql', sql: tableRemovalSql }, { duringNoQuestion: false });
2915
- if (madConfirmedDecision.action !== 'allow') throw new Error('selftest failed: MAD-SKS confirmed table deletion was not allowed in the short confirmation window');
2880
+ const madTableRemovalDecision = await checkDbOperation(tmp, madState, { tool_name: 'mcp__supabase__execute_sql', sql: tableRemovalSql }, { duringNoQuestion: false });
2881
+ if (madTableRemovalDecision.action !== 'block') throw new Error('selftest failed: MAD-SKS catastrophic table removal was not blocked');
2882
+ const allRowsSql = 'de' + 'lete from users;';
2883
+ const madAllRowsDecision = await checkDbOperation(tmp, madState, { tool_name: 'mcp__supabase__execute_sql', sql: allRowsSql }, { duringNoQuestion: false });
2884
+ if (madAllRowsDecision.action !== 'block') throw new Error('selftest failed: MAD-SKS all-row DML was not blocked');
2916
2885
  await writeJsonAtomic(path.join(madMission.dir, 'team-gate.json'), { schema_version: 1, passed: true, team_roster_confirmed: true, permissions_deactivated: true });
2917
- const madClosedDecision = await checkDbOperation(tmp, madConfirmedState, { tool_name: 'mcp__supabase__execute_sql', sql: tableRemovalSql }, { duringNoQuestion: false });
2886
+ const madClosedDecision = await checkDbOperation(tmp, madState, { tool_name: 'mcp__supabase__execute_sql', sql: columnCleanupSql }, { duringNoQuestion: false });
2918
2887
  if (madClosedDecision.action !== 'block') throw new Error('selftest failed: MAD-SKS permission persisted after gate close');
2919
2888
  const nonDbDecision = await checkDbOperation(tmp, {}, { command: 'npm test' }, { duringNoQuestion: true });
2920
2889
  if (nonDbDecision.action !== 'allow') throw new Error('selftest failed: non-DB command blocked by DB guard');
@@ -2924,6 +2893,15 @@ async function selftest() {
2924
2893
  if (evalReport.candidate.wiki?.voxel_schema !== 'sks.wiki-voxel.v1' || evalReport.candidate.wiki?.voxel_rows < 1) throw new Error('selftest failed: eval did not include voxel overlay metrics');
2925
2894
  const harnessReport = harnessGrowthReport({});
2926
2895
  if (!harnessReport.forgetting.fixture.passed || !harnessReport.warp.views.includes('Harness Experiments View') || !harnessReport.reliability.tool_error_taxonomy.includes('Unknown')) throw new Error('selftest failed: harness growth fixture incomplete');
2896
+ const proofField = await proofFieldFixture();
2897
+ if (!proofField.validation.ok || !validateProofFieldReport(proofField.report).ok) throw new Error('selftest failed: proof field report invalid');
2898
+ if (!proofField.checks.route_cone_selected || !proofField.checks.cli_cone_selected || !proofField.checks.catastrophic_guard_present || !proofField.checks.negative_release_work_recorded) throw new Error('selftest failed: proof field fixture checks incomplete');
2899
+ const workflowPerf = await runWorkflowPerfBench(tmp, {
2900
+ iterations: 2,
2901
+ intent: 'small CLI help surface update',
2902
+ changedFiles: ['src/cli/maintenance-commands.mjs', 'src/core/routes.mjs']
2903
+ });
2904
+ if (!validateWorkflowPerfReport(workflowPerf).ok || workflowPerf.metrics.decision_mode !== 'fast_lane' || !workflowPerf.metrics.fast_lane_eligible) throw new Error('selftest failed: workflow perf proof field did not produce a valid fast lane report');
2927
2905
  if (classifyToolError({ message: 'operation timed out' }) !== 'Timeout' || classifyToolError({ message: 'unclassified weirdness' }) !== 'Unknown') throw new Error('selftest failed: tool error taxonomy classification');
2928
2906
  const coord = rgbaToWikiCoord({ r: 12, g: 34, b: 56, a: 255 });
2929
2907
  if (coord.schema !== 'sks.wiki-coordinate.v1' || coord.xyzw.length !== 4) throw new Error('selftest failed: RGBA wiki coordinate conversion');
@@ -2995,49 +2973,3 @@ async function selftest() {
2995
2973
  console.log('ㅅㅋㅅ selftest passed.');
2996
2974
  console.log(`temp: ${tmp}`);
2997
2975
  }
2998
-
2999
- async function db(sub, args) {
3000
- const root = await sksRoot();
3001
- if (sub === 'policy') {
3002
- console.log(JSON.stringify(await loadDbSafetyPolicy(root), null, 2));
3003
- return;
3004
- }
3005
- if (sub === 'scan') {
3006
- const report = await scanDbSafety(root, { includeMigrations: flag(args, '--migrations') });
3007
- console.log(JSON.stringify(report, null, 2));
3008
- process.exitCode = report.ok ? 0 : 2;
3009
- return;
3010
- }
3011
- if (sub === 'mcp-config') {
3012
- const projectIdx = args.indexOf('--project-ref');
3013
- const featuresIdx = args.indexOf('--features');
3014
- const projectRef = projectIdx >= 0 ? args[projectIdx + 1] : '<project_ref>';
3015
- const features = featuresIdx >= 0 ? args[featuresIdx + 1] : 'database,docs';
3016
- console.log(JSON.stringify(safeSupabaseMcpConfig({ projectRef, readOnly: true, features }), null, 2));
3017
- return;
3018
- }
3019
- if (sub === 'classify' || sub === 'check') {
3020
- const sqlIdx = args.indexOf('--sql');
3021
- const commandIdx = args.indexOf('--command');
3022
- const fileIdx = args.indexOf('--file');
3023
- let result;
3024
- if (fileIdx >= 0 && args[fileIdx + 1]) result = await checkSqlFile(path.resolve(args[fileIdx + 1]));
3025
- else if (commandIdx >= 0 && args[commandIdx + 1]) result = classifyCommand(args[commandIdx + 1]);
3026
- else if (sqlIdx >= 0 && args[sqlIdx + 1]) result = classifySql(args[sqlIdx + 1]);
3027
- else if (sub === 'check' && args[0]) result = await checkSqlFile(path.resolve(args[0]));
3028
- else result = classifySql(args.join(' ').trim());
3029
- console.log(JSON.stringify(result, null, 2));
3030
- process.exitCode = ['destructive', 'write', 'possible_db'].includes(result.level) ? 2 : 0;
3031
- return;
3032
- }
3033
- if (sub === 'scan-payload') {
3034
- const raw = await fsp.readFile(0, 'utf8');
3035
- const payload = raw.trim() ? JSON.parse(raw) : {};
3036
- const decision = await checkDbOperation(root, {}, payload, { duringNoQuestion: false });
3037
- console.log(JSON.stringify(decision, null, 2));
3038
- process.exitCode = decision.action === 'block' ? 2 : 0;
3039
- return;
3040
- }
3041
- console.error('Usage: sks db policy | db scan [--migrations] | db mcp-config --project-ref <id> | db check --sql "..." | db check --command "..." | db check --file file.sql');
3042
- process.exitCode = 1;
3043
- }
@@ -23,22 +23,80 @@ import { writeEffortDecision } from '../core/effort-orchestrator.mjs';
23
23
  import { createWorkOrderLedger, writeWorkOrderLedger } from '../core/work-order-ledger.mjs';
24
24
  import { writeFromChatImgArtifacts } from '../core/from-chat-img-forensics.mjs';
25
25
  import { renderTeamDashboardState, writeTeamDashboardState } from '../core/team-dashboard-renderer.mjs';
26
- import { runPerfBench } from '../core/perf-bench.mjs';
26
+ import { runPerfBench, runWorkflowPerfBench } from '../core/perf-bench.mjs';
27
+ import { writeProofFieldReport } from '../core/proof-field.mjs';
27
28
  import { GOAL_BRIDGE_ARTIFACT, GOAL_WORKFLOW_ARTIFACT, updateGoalWorkflow, writeGoalWorkflow } from '../core/goal-workflow.mjs';
28
29
  import { scanCodeStructure, writeCodeStructureReport } from '../core/code-structure.mjs';
29
30
  import { writeMemorySweepReport } from '../core/memory-governor.mjs';
30
31
  import { cleanupWarpTeamView, launchWarpTeamView } from '../core/warp-ui.mjs';
31
32
  import { writeSkillForgeReport } from '../core/skill-forge.mjs';
32
33
  import { writeMistakeMemoryReport } from '../core/mistake-memory.mjs';
33
- import { scanDbSafety } from '../core/db-safety.mjs';
34
+ import { checkDbOperation, checkSqlFile, classifyCommand, classifySql, loadDbSafetyPolicy, safeSupabaseMcpConfig, scanDbSafety } from '../core/db-safety.mjs';
34
35
  import { harnessGrowthReport, writeHarnessGrowthReport } from '../core/evaluation.mjs';
35
36
 
36
37
  const flag = (args, name) => args.includes(name);
37
38
  const promptOf = (args) => args.filter((x) => !String(x).startsWith('--')).join(' ').trim();
38
39
  const TEAM_SESSION_CLEANUP_ARTIFACT = 'team-session-cleanup.json';
40
+ const REPOSITORY_URL = 'https://github.com/mandarange/Sneakoscope-Codex.git';
39
41
 
40
42
  async function resolveMissionId(root, arg) { return (!arg || arg === 'latest') ? findLatestMission(root) : arg; }
41
43
 
44
+ export function quickstartCommand() {
45
+ console.log(`ㅅㅋㅅ Quickstart
46
+
47
+ First install and bootstrap this project:
48
+ npm i -g sneakoscope
49
+ sks root
50
+ sks bootstrap
51
+ sks
52
+
53
+ Use outside a project:
54
+ sks root
55
+ sks deps check
56
+ sks team "global mission"
57
+
58
+ If warp is missing:
59
+ sks deps install warp
60
+
61
+ Initialize this project for CLI and Codex App:
62
+ sks setup --bootstrap
63
+
64
+ Open from terminal:
65
+ sks
66
+ sks --auto-review --high
67
+ sks auto-review start --high
68
+
69
+ Verify:
70
+ sks deps check
71
+ sks codex-app check
72
+ sks warp check
73
+ sks auto-review status
74
+ sks doctor --fix
75
+ sks context7 check
76
+ sks selftest --mock
77
+ sks commands
78
+ sks dollar-commands
79
+
80
+ If hooks cannot find the command:
81
+ sks fix-path
82
+
83
+ Project-only install:
84
+ npm i -D sneakoscope
85
+ npx sks setup --install-scope project
86
+
87
+ Local-only install artifacts:
88
+ sks setup --local-only
89
+ # writes generated SKS files but excludes .sneakoscope/, .codex/, .agents/, AGENTS.md through .git/info/exclude
90
+ # user-owned AGENTS.md is preserved; an existing SKS managed block is refreshed
91
+
92
+ Default project setup writes the same SKS generated-file patterns into the project .gitignore.
93
+
94
+ GitHub install for unreleased commits:
95
+ npm i -g git+${REPOSITORY_URL}
96
+ sks bootstrap
97
+ `);
98
+ }
99
+
42
100
  export async function researchCommand(sub, args) {
43
101
  if (sub === 'prepare') return researchPrepare(args);
44
102
  if (sub === 'run') return researchRun(args);
@@ -385,6 +443,52 @@ export async function hproofCommand(sub, args) {
385
443
  console.log(JSON.stringify(await evaluateDoneGate(root, id), null, 2));
386
444
  }
387
445
 
446
+ export async function dbCommand(sub, args = []) {
447
+ const root = await sksRoot();
448
+ if (sub === 'policy') {
449
+ console.log(JSON.stringify(await loadDbSafetyPolicy(root), null, 2));
450
+ return;
451
+ }
452
+ if (sub === 'scan') {
453
+ const report = await scanDbSafety(root, { includeMigrations: flag(args, '--migrations') });
454
+ console.log(JSON.stringify(report, null, 2));
455
+ process.exitCode = report.ok ? 0 : 2;
456
+ return;
457
+ }
458
+ if (sub === 'mcp-config') {
459
+ const projectIdx = args.indexOf('--project-ref');
460
+ const featuresIdx = args.indexOf('--features');
461
+ const projectRef = projectIdx >= 0 ? args[projectIdx + 1] : '<project_ref>';
462
+ const features = featuresIdx >= 0 ? args[featuresIdx + 1] : 'database,docs';
463
+ console.log(JSON.stringify(safeSupabaseMcpConfig({ projectRef, readOnly: true, features }), null, 2));
464
+ return;
465
+ }
466
+ if (sub === 'classify' || sub === 'check') {
467
+ const sqlIdx = args.indexOf('--sql');
468
+ const commandIdx = args.indexOf('--command');
469
+ const fileIdx = args.indexOf('--file');
470
+ let result;
471
+ if (fileIdx >= 0 && args[fileIdx + 1]) result = await checkSqlFile(path.resolve(args[fileIdx + 1]));
472
+ else if (commandIdx >= 0 && args[commandIdx + 1]) result = classifyCommand(args[commandIdx + 1]);
473
+ else if (sqlIdx >= 0 && args[sqlIdx + 1]) result = classifySql(args[sqlIdx + 1]);
474
+ else if (sub === 'check' && args[0]) result = await checkSqlFile(path.resolve(args[0]));
475
+ else result = classifySql(args.join(' ').trim());
476
+ console.log(JSON.stringify(result, null, 2));
477
+ process.exitCode = ['destructive', 'write', 'possible_db'].includes(result.level) ? 2 : 0;
478
+ return;
479
+ }
480
+ if (sub === 'scan-payload') {
481
+ const raw = await fsp.readFile(0, 'utf8');
482
+ const payload = raw.trim() ? JSON.parse(raw) : {};
483
+ const decision = await checkDbOperation(root, {}, payload, { duringNoQuestion: false });
484
+ console.log(JSON.stringify(decision, null, 2));
485
+ process.exitCode = decision.action === 'block' ? 2 : 0;
486
+ return;
487
+ }
488
+ console.error('Usage: sks db policy | db scan [--migrations] | db mcp-config --project-ref <id> | db check --sql "..." | db check --command "..." | db check --file file.sql');
489
+ process.exitCode = 1;
490
+ }
491
+
388
492
  export async function validateArtifactsCommand(args = []) {
389
493
  const root = await sksRoot();
390
494
  const missionArg = args[0] && !String(args[0]).startsWith('--') ? args[0] : 'latest';
@@ -404,12 +508,32 @@ export async function validateArtifactsCommand(args = []) {
404
508
  }
405
509
 
406
510
  export async function perfCommand(sub, args = []) {
407
- if (sub !== 'run') {
408
- console.error('Usage: sks perf run [--json] [--iterations N]');
511
+ if (!['run', 'workflow'].includes(sub)) {
512
+ console.error('Usage: sks perf run|workflow [--json] [--iterations N] [--intent "task"] [--changed file1,file2]');
409
513
  process.exitCode = 1;
410
514
  return;
411
515
  }
412
516
  const root = await sksRoot();
517
+ if (sub === 'workflow') {
518
+ const changedRaw = readFlagValue(args, '--changed', null);
519
+ const report = await runWorkflowPerfBench(root, {
520
+ iterations: readFlagValue(args, '--iterations', 3),
521
+ intent: readFlagValue(args, '--intent', positionalArgs(args).join(' ')),
522
+ changedFiles: changedRaw ? changedRaw.split(',').filter(Boolean) : undefined
523
+ });
524
+ const outPath = path.join(root, '.sneakoscope', 'reports', `workflow-perf-${Date.now()}.json`);
525
+ await writeJsonAtomic(outPath, report);
526
+ if (flag(args, '--json')) return console.log(JSON.stringify({ ...report, report_path: outPath }, null, 2));
527
+ console.log('SKS Workflow Performance');
528
+ console.log(`Mode: ${report.metrics.decision_mode}`);
529
+ console.log(`Fast lane: ${report.metrics.fast_lane_eligible ? 'yes' : 'no'}`);
530
+ console.log(`Proof Field p95: ${report.metrics.proof_field_build_ms_p95}ms`);
531
+ console.log(`Proof cones: ${report.metrics.proof_cone_count}`);
532
+ console.log(`Negative work skipped: ${report.metrics.negative_work_skipped_count}`);
533
+ console.log(`Next: ${report.recommendation.next.join('; ')}`);
534
+ console.log(`Report: ${path.relative(root, outPath)}`);
535
+ return;
536
+ }
413
537
  const report = await runPerfBench(root, { iterations: readFlagValue(args, '--iterations', 3) });
414
538
  const outPath = path.join(root, '.sneakoscope', 'reports', `perf-${Date.now()}.json`);
415
539
  await writeJsonAtomic(outPath, report);
@@ -421,6 +545,34 @@ export async function perfCommand(sub, args = []) {
421
545
  console.log(`Report: ${path.relative(root, outPath)}`);
422
546
  }
423
547
 
548
+ export async function proofFieldCommand(sub, args = []) {
549
+ const action = sub || 'scan';
550
+ if (!['scan', 'help', '--help'].includes(action)) {
551
+ console.error('Usage: sks proof-field scan [--json] [--intent "task"] [--changed file1,file2]');
552
+ process.exitCode = 1;
553
+ return;
554
+ }
555
+ if (action === 'help' || action === '--help') {
556
+ console.log('Usage: sks proof-field scan [--json] [--intent "task"] [--changed file1,file2]');
557
+ console.log('Build a Potential Proof Field report: proof cones, negative-work cache, and fast-lane eligibility for the current change set.');
558
+ return;
559
+ }
560
+ const root = await sksRoot();
561
+ const changedRaw = readFlagValue(args, '--changed', null);
562
+ const report = await writeProofFieldReport(root, {
563
+ intent: readFlagValue(args, '--intent', positionalArgs(args).join(' ')),
564
+ changedFiles: changedRaw ? changedRaw.split(',').filter(Boolean) : undefined
565
+ });
566
+ if (flag(args, '--json')) return console.log(JSON.stringify(report, null, 2));
567
+ console.log('SKS Proof Field');
568
+ console.log(`Mode: ${report.fast_lane_decision.mode}`);
569
+ console.log(`Eligible: ${report.fast_lane_decision.eligible ? 'yes' : 'no'}`);
570
+ if (report.fast_lane_decision.blockers.length) console.log(`Blockers: ${report.fast_lane_decision.blockers.join(', ')}`);
571
+ console.log(`Proof cones: ${report.proof_cones.map((cone) => cone.id).join(', ')}`);
572
+ console.log(`Verification: ${report.fast_lane_decision.verification.join('; ')}`);
573
+ console.log(`Report: ${path.relative(root, report.report_path)}`);
574
+ }
575
+
424
576
  export async function harnessCommand(sub, args = []) {
425
577
  const action = sub || 'fixture';
426
578
  if (!['fixture', 'review'].includes(action)) {
@@ -1084,7 +1236,7 @@ export async function statsCommand(args) {
1084
1236
 
1085
1237
  function positionalArgs(args = []) {
1086
1238
  const out = [];
1087
- const valueFlags = new Set(['--format', '--iterations', '--out', '--baseline', '--candidate', '--install-scope', '--max-cycles', '--depth', '--scope', '--transport', '--query', '--topic', '--tokens', '--timeout-ms', '--sql', '--command', '--project-ref', '--agent', '--phase', '--message', '--role', '--max-anchors', '--lines']);
1239
+ const valueFlags = new Set(['--format', '--iterations', '--out', '--baseline', '--candidate', '--install-scope', '--max-cycles', '--depth', '--scope', '--transport', '--query', '--topic', '--tokens', '--timeout-ms', '--sql', '--command', '--project-ref', '--agent', '--phase', '--message', '--role', '--max-anchors', '--lines', '--intent', '--changed']);
1088
1240
  for (let i = 0; i < args.length; i++) {
1089
1241
  const arg = String(args[i]);
1090
1242
  if (valueFlags.has(arg)) {
@@ -226,7 +226,27 @@ function hasTableRemovalRisk(cls = {}) {
226
226
  ...(cls.sql?.reasons || []),
227
227
  ...(cls.command?.reasons || [])
228
228
  ]);
229
- return ['drop_table', 'alter_table_drop', 'truncate'].some((reason) => reasons.has(reason));
229
+ return ['drop_table', 'truncate'].some((reason) => reasons.has(reason));
230
+ }
231
+
232
+ function hasMadSksCatastrophicDbRisk(cls = {}) {
233
+ const reasons = new Set([
234
+ ...(cls.reasons || []),
235
+ ...(cls.sql?.reasons || []),
236
+ ...(cls.command?.reasons || [])
237
+ ]);
238
+ return [
239
+ 'drop_database',
240
+ 'drop_schema',
241
+ 'drop_table',
242
+ 'truncate',
243
+ 'delete_without_where',
244
+ 'update_without_where',
245
+ 'supabase_db_reset',
246
+ 'prisma_migrate_reset',
247
+ 'postgres_database_admin_command'
248
+ ].some((reason) => reasons.has(reason))
249
+ || cls.toolReasons?.includes?.('dangerous_supabase_management_tool');
230
250
  }
231
251
 
232
252
  function isMadSksRouteState(state = {}) {
@@ -259,23 +279,32 @@ export function evaluateDbSafety({ classification, policy = DEFAULT_DB_SAFETY_PO
259
279
  if (cls.level === 'safe') return { allowed: true, action: 'allow', reasons: ['read_only_operation'], classification: cls };
260
280
  if (cls.level === 'possible_db') return { allowed: !noQuestion, action: noQuestion ? 'block' : 'warn', reasons: noQuestion ? ['unknown_database_operation_blocked_during_no_question_run'] : ['unknown_database_operation'], classification: cls };
261
281
  if (madSks?.active && (cls.level === 'write' || cls.level === 'destructive')) {
262
- if (hasTableRemovalRisk(cls) && !madSks.tableDeleteConfirmed) {
282
+ if (hasMadSksCatastrophicDbRisk(cls)) {
263
283
  return {
264
284
  allowed: false,
265
- action: 'confirm',
266
- reasons: ['mad_sks_table_delete_requires_user_confirmation_30s'],
285
+ action: 'block',
286
+ reasons: ['mad_sks_catastrophic_db_operation_blocked'],
267
287
  classification: cls,
268
288
  effective,
269
- mad_sks: { active: true, table_delete_confirmation_required: true, timeout_ms: MAD_SKS_TABLE_DELETE_TIMEOUT_MS }
289
+ mad_sks: {
290
+ active: true,
291
+ catastrophic_safety_guard_active: true,
292
+ blocked_categories: ['whole_database_or_table_removal', 'all_rows_delete_or_update', 'dangerous_project_management']
293
+ }
270
294
  };
271
295
  }
272
296
  return {
273
297
  allowed: true,
274
298
  action: 'allow',
275
- reasons: hasTableRemovalRisk(cls) ? ['mad_sks_table_delete_confirmed'] : ['mad_sks_scoped_override_active'],
299
+ reasons: ['mad_sks_scoped_override_active'],
276
300
  classification: cls,
277
301
  effective,
278
- mad_sks: { active: true, table_delete_confirmed_until: madSks.tableDeleteConfirmedUntil || null }
302
+ mad_sks: {
303
+ active: true,
304
+ sks_db_constraints_removed: true,
305
+ catastrophic_safety_guard_active: true,
306
+ supabase_mcp_schema_cleanup_allowed: true
307
+ }
279
308
  };
280
309
  }
281
310
  if (cls.level === 'destructive') reasons.push('destructive_database_operation_blocked_always');
@@ -384,6 +413,13 @@ export async function checkSqlFile(file) {
384
413
  }
385
414
 
386
415
  export function dbBlockReason(decision) {
416
+ if ((decision.reasons || []).includes('mad_sks_catastrophic_db_operation_blocked')) {
417
+ return [
418
+ 'Sneakoscope Codex MAD-SKS catastrophic database safeguard blocked this operation.',
419
+ 'MAD-SKS opens Supabase MCP column/schema cleanup, direct execute SQL, and normal DB writes only while the mission gate is active.',
420
+ 'Whole database/table removal, all-row value wipes, database reset, and dangerous project or branch management remain blocked.'
421
+ ].join(' ');
422
+ }
387
423
  if ((decision.reasons || []).includes('mad_sks_table_delete_requires_user_confirmation_30s')) {
388
424
  return [
389
425
  'Sneakoscope Codex MAD-SKS gate paused a table deletion operation.',
@@ -87,21 +87,23 @@ export function buildDecisionContract({ mission, schema, answers }) {
87
87
  mad_sks_mode: madSks ? 'explicit_invocation_only' : false,
88
88
  production_database_writes_allowed: madSks ? 'mad_sks_scoped' : false,
89
89
  mcp_direct_execute_sql_writes_allowed: madSks ? 'mad_sks_scoped' : false,
90
- db_reset_allowed: madSks ? 'mad_sks_scoped' : false,
91
- db_drop_allowed: madSks ? 'requires_table_delete_confirmation_when_table_removal' : false,
92
- db_truncate_allowed: madSks ? 'requires_table_delete_confirmation_when_table_removal' : false,
90
+ db_reset_allowed: false,
91
+ db_drop_allowed: madSks ? 'column_and_non_catastrophic_schema_cleanup_only' : false,
92
+ db_truncate_allowed: false,
93
93
  db_mass_delete_update_allowed: madSks ? 'mad_sks_scoped' : false
94
94
  },
95
95
  database_safety: {
96
- policy: madSks ? 'mad_sks_scoped_override_table_delete_confirmation_required' : 'destructive_denied_always',
96
+ policy: madSks ? 'mad_sks_scoped_override_with_catastrophic_db_guard' : 'destructive_denied_always',
97
97
  supabase_mcp_recommended_url: 'https://mcp.supabase.com/mcp?project_ref=<project_ref>&read_only=true&features=database,docs',
98
98
  allowed_targets_for_write: madSks ? ['main_branch', 'production', 'local_dev', 'preview_branch', 'supabase_branch'] : ['local_dev', 'preview_branch', 'supabase_branch'],
99
- forbidden_operations: madSks ? ['TABLE_REMOVAL_WITHOUT_RUNTIME_CONFIRMATION'] : ['DROP', 'TRUNCATE', 'DELETE_WITHOUT_WHERE', 'UPDATE_WITHOUT_WHERE', 'DB_RESET', 'DB_PUSH', 'PROJECT_DELETE', 'BRANCH_RESET_OR_MERGE_OR_DELETE', 'DISABLE_RLS', 'BROAD_GRANT_REVOKE'],
99
+ forbidden_operations: madSks ? ['DROP_DATABASE', 'DROP_SCHEMA', 'DROP_TABLE', 'TRUNCATE', 'DELETE_WITHOUT_WHERE', 'UPDATE_WITHOUT_WHERE', 'DB_RESET', 'PROJECT_DELETE', 'BRANCH_RESET_OR_MERGE_OR_DELETE'] : ['DROP', 'TRUNCATE', 'DELETE_WITHOUT_WHERE', 'UPDATE_WITHOUT_WHERE', 'DB_RESET', 'DB_PUSH', 'PROJECT_DELETE', 'BRANCH_RESET_OR_MERGE_OR_DELETE', 'DISABLE_RLS', 'BROAD_GRANT_REVOKE'],
100
100
  mad_sks_scope: madSks ? {
101
101
  active_only_when_prompt_contains: '$MAD-SKS',
102
102
  may_combine_with_primary_route: true,
103
103
  deactivates_when_active_mission_gate_passes: true,
104
- table_delete_confirmation_timeout_ms: 30000
104
+ supabase_mcp_schema_cleanup_allowed: true,
105
+ direct_execute_sql_allowed: true,
106
+ catastrophic_safety_guard_active: true
105
107
  } : null,
106
108
  migration_apply_allowed: answers.DB_MIGRATION_APPLY_ALLOWED || 'no',
107
109
  read_only_query_limit: answers.DB_READ_ONLY_QUERY_LIMIT || '1000'
package/src/core/fsx.mjs CHANGED
@@ -5,7 +5,7 @@ import os from 'node:os';
5
5
  import crypto from 'node:crypto';
6
6
  import { spawn } from 'node:child_process';
7
7
 
8
- export const PACKAGE_VERSION = '0.6.85';
8
+ export const PACKAGE_VERSION = '0.6.89';
9
9
  export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
10
10
  export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
11
11
 
package/src/core/init.mjs CHANGED
@@ -9,6 +9,8 @@ import { installVersionGitHook } from './version-manager.mjs';
9
9
  import { CODEX_COMPUTER_USE_ONLY_POLICY, DOLLAR_COMMANDS, DOLLAR_COMMAND_ALIASES, DOLLAR_SKILL_NAMES, FROM_CHAT_IMG_CHECKLIST_ARTIFACT, FROM_CHAT_IMG_COVERAGE_ARTIFACT, FROM_CHAT_IMG_QA_LOOP_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS, RECOMMENDED_MCP_SERVERS, RECOMMENDED_SKILLS, chatCaptureIntakeText, context7ConfigToml, stackCurrentDocsPolicyText, triwikiContextTracking, triwikiContextTrackingText, triwikiStagePolicyText } from './routes.mjs';
10
10
 
11
11
  const REFLECTION_MEMORY_PATH = '.sneakoscope/memory/q2_facts/post-route-reflection.md';
12
+ const SKS_GENERATED_GIT_PATTERNS = ['.sneakoscope/', '.codex/', '.agents/', 'AGENTS.md'];
13
+
12
14
  function reflectionInstructionText(commandPrefix = 'sks') {
13
15
  return `Post-route reflection: full routes load \`reflection\` after work/tests and before final; DFix/Answer/Help/Wiki/SKS discovery are exempt. Write reflection.md; record only real misses/gaps, or no_issue_acknowledged. For lessons, append TriWiki claim rows to ${REFLECTION_MEMORY_PATH}. Run "${commandPrefix} wiki refresh" or pack, validate, then pass reflection-gate.json.`;
14
16
  }
@@ -107,7 +109,9 @@ export async function initProject(root, opts = {}) {
107
109
  ];
108
110
  for (const d of dirs) await ensureDir(path.join(root, d));
109
111
  const localExclude = localOnly ? await ensureLocalOnlyGitExclude(root) : null;
112
+ const sharedIgnore = localOnly ? null : await ensureSharedGitIgnore(root);
110
113
  if (localExclude?.path) created.push(`${path.relative(root, localExclude.path)} local-only excludes`);
114
+ if (sharedIgnore?.changed) created.push(`${path.relative(root, sharedIgnore.path)} SKS generated files ignore`);
111
115
 
112
116
  await writeJsonAtomic(path.join(sine, 'manifest.json'), {
113
117
  package: 'sneakoscope',
@@ -165,6 +169,8 @@ export async function initProject(root, opts = {}) {
165
169
  },
166
170
  git: {
167
171
  local_only: localOnly,
172
+ ignore_path: sharedIgnore?.path ? path.relative(root, sharedIgnore.path) : null,
173
+ ignored_patterns: sharedIgnore?.patterns || [],
168
174
  exclude_path: localExclude?.path ? path.relative(root, localExclude.path) : null,
169
175
  excluded_patterns: localExclude?.patterns || [],
170
176
  versioning: {
@@ -198,6 +204,8 @@ export async function initProject(root, opts = {}) {
198
204
  git: {
199
205
  ...(policy.git || {}),
200
206
  local_only: localOnly || Boolean(policy.git?.local_only),
207
+ ignore_path: sharedIgnore?.path ? path.relative(root, sharedIgnore.path) : policy.git?.ignore_path || null,
208
+ ignored_patterns: sharedIgnore?.patterns || policy.git?.ignored_patterns || [],
201
209
  exclude_path: localExclude?.path ? path.relative(root, localExclude.path) : policy.git?.exclude_path || null,
202
210
  excluded_patterns: localExclude?.patterns || policy.git?.excluded_patterns || [],
203
211
  versioning: {
@@ -267,6 +275,8 @@ export async function initProject(root, opts = {}) {
267
275
  installation: installPolicy(scope, commandPrefix),
268
276
  git: {
269
277
  local_only: localOnly,
278
+ ignore_path: sharedIgnore?.path ? path.relative(root, sharedIgnore.path) : null,
279
+ ignored_patterns: sharedIgnore?.patterns || [],
270
280
  exclude_path: localExclude?.path ? path.relative(root, localExclude.path) : null,
271
281
  excluded_patterns: localExclude?.patterns || [],
272
282
  versioning: {
@@ -445,10 +455,33 @@ policy = "Deny destructive database operations, credential exfiltration, persist
445
455
  return { created };
446
456
  }
447
457
 
458
+ async function ensureSharedGitIgnore(root) {
459
+ const patterns = SKS_GENERATED_GIT_PATTERNS;
460
+ const ignorePath = path.join(root, '.gitignore');
461
+ const markerStart = '# BEGIN Sneakoscope Codex generated files';
462
+ const markerEnd = '# END Sneakoscope Codex generated files';
463
+ const managedBlock = `${markerStart}\n${patterns.join('\n')}\n${markerEnd}\n`;
464
+ const current = await readText(ignorePath, '');
465
+ if (current.includes(markerStart)) {
466
+ const re = new RegExp(`${escapeRegExp(markerStart)}[\\s\\S]*?${escapeRegExp(markerEnd)}\\n?`);
467
+ const next = current.replace(re, managedBlock);
468
+ if (next !== current) await writeTextAtomic(ignorePath, next.endsWith('\n') ? next : `${next}\n`);
469
+ return { path: ignorePath, patterns, changed: next !== current };
470
+ }
471
+ const existing = new Set(current.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
472
+ const missing = patterns.filter((pattern) => !existing.has(pattern));
473
+ if (!missing.length) return { path: ignorePath, patterns, changed: false };
474
+ const block = missing.length === patterns.length
475
+ ? managedBlock
476
+ : `${markerStart}\n${missing.join('\n')}\n${markerEnd}\n`;
477
+ await writeTextAtomic(ignorePath, `${current.trimEnd()}${current.trim() ? '\n\n' : ''}${block}`);
478
+ return { path: ignorePath, patterns, changed: true };
479
+ }
480
+
448
481
  async function ensureLocalOnlyGitExclude(root) {
449
482
  const gitDir = await resolveGitDir(root);
450
483
  if (!gitDir) return { path: null, patterns: [] };
451
- const patterns = ['.sneakoscope/', '.codex/', '.agents/', 'AGENTS.md'];
484
+ const patterns = SKS_GENERATED_GIT_PATTERNS;
452
485
  const excludePath = path.join(gitDir, 'info', 'exclude');
453
486
  await ensureDir(path.dirname(excludePath));
454
487
  const markerStart = '# Sneakoscope Codex local-only generated files';
@@ -505,7 +538,7 @@ export async function installSkills(root) {
505
538
  'research': `---\nname: research\ndescription: Dollar-command route for $Research or $research frontier discovery workflows.\n---\n\nUse when the user invokes $Research/$research or asks for research, hypotheses, new mechanisms, falsification, or testable predictions. Prefer sks research prepare and sks research run. Do not use for ordinary code edits.\n`,
506
539
  'autoresearch': `---\nname: autoresearch\ndescription: Dollar-command route for $AutoResearch or $autoresearch iterative experiment loops.\n---\n\nUse for $AutoResearch, iterative improvement, SEO/GEO, ranking, workflow, benchmark, or experiments. Define program, hypothesis, experiment, metric, keep/discard, falsification, next step, and Honest Mode. Load seo-geo-optimizer for README/npm/GitHub/schema/AI-search work.\n`,
507
540
  'db': `---\nname: db\ndescription: Dollar-command route for $DB or $db database and Supabase safety checks.\n---\n\nUse when the user invokes $DB/$db or the task touches SQL, Supabase, Postgres, migrations, Prisma, Drizzle, Knex, MCP database tools, or production data. Run or follow sks db policy, sks db scan, sks db classify, and sks db check. Destructive database operations remain forbidden.\n`,
508
- 'mad-sks': `---\nname: mad-sks\ndescription: Explicit high-risk authorization modifier for $MAD-SKS scoped Supabase MCP DB permission widening.\n---\n\nUse only when the user explicitly invokes $MAD-SKS. It can be combined with another route, such as $MAD-SKS $Team or $DB ... $MAD-SKS; in that case the other command remains the primary workflow and MAD-SKS is only the temporary permission grant. The widened DB permission applies only while the active mission gate is open, and must be deactivated when the task ends. Table deletion remains special: pause, ask the user for explicit confirmation, and abort that operation if no confirmation arrives within about 30 seconds. Do not carry MAD-SKS permission into later prompts or routes.\n`,
541
+ 'mad-sks': `---\nname: mad-sks\ndescription: Explicit high-risk authorization modifier for $MAD-SKS scoped Supabase MCP DB permission widening.\n---\n\nUse only when the user explicitly invokes $MAD-SKS. It can be combined with another route, such as $MAD-SKS $Team or $DB ... $MAD-SKS; in that case the other command remains the primary workflow and MAD-SKS is only the temporary permission grant. The widened DB permission applies only while the active mission gate is open, must be deactivated when the task ends, and opens Supabase MCP column/schema cleanup, direct execute SQL, and normal DB write permissions. Keep only catastrophic database-wipe safeguards: whole database/table removal, all-row delete/update, reset, and dangerous project/branch management remain blocked. Do not carry MAD-SKS permission into later prompts or routes.\n`,
509
542
  'gx': `---\nname: gx\ndescription: Dollar-command route for $GX or $gx deterministic GX visual context cartridges.\n---\n\nUse when the user invokes $GX/$gx or asks for architecture/context visualization through SKS. Prefer sks gx init, render, validate, drift, and snapshot. vgraph.json remains the source of truth.\n`,
510
543
  'help': `---\nname: help\ndescription: Dollar-command route for $Help or $help explaining installed SKS commands and workflows.\n---\n\nUse when the user invokes $Help/$help or asks what commands exist. Prefer concise output from sks commands, sks usage <topic>, sks quickstart, sks aliases, and sks codex-app.\n`,
511
544
  'prompt-pipeline': `---\nname: prompt-pipeline\ndescription: Default SKS prompt optimization pipeline for execution prompts; Answer and DFix bypass it.\n---\n\nClassify intent: Answer only for real questions; question-shaped implicit instructions, complaints, and mandatory-policy statements route to Team. DFix handles tiny design/content; code defaults to Team unless safety/research/GX route fits. Infer goal, target, constraints, acceptance, risk, and smallest safe route. Ask only scope/safety/behavior/acceptance-changing questions; otherwise seal inferred answers. Code work surfaces route/guard/scopes, materializes team-roster.json from default or explicit counts before implementation, compiles concrete Team runtime graph/inbox artifacts after consensus, and parent owns integration/tests/Context7/Honest Mode.\n\n${chatCaptureIntakeText()}\n\nDesign: read design.md; if missing use design-system-builder; use imagegen for image/logo/raster. TriWiki context-tracking SSOT: .sneakoscope/wiki/context-pack.json; read only the latest coordinate+voxel overlay pack before every route stage, run sks wiki refresh/pack after changes, validate before handoffs/final.\n`,
@@ -1,6 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { performance } from 'node:perf_hooks';
3
3
  import { dirSize, fileSize, nowIso, packageRoot, runProcess, writeJsonAtomic } from './fsx.mjs';
4
+ import { buildProofField, validateProofFieldReport } from './proof-field.mjs';
4
5
 
5
6
  export const DEFAULT_PERF_BUDGETS = {
6
7
  cli_startup_ms_p95: 250,
@@ -8,6 +9,8 @@ export const DEFAULT_PERF_BUDGETS = {
8
9
  context_build_ms_p95: 500,
9
10
  artifact_validation_ms_p95: 150,
10
11
  dashboard_render_ms_p95: 100,
12
+ proof_field_build_ms_p95: 150,
13
+ workflow_scan_ms_p95: 1000,
11
14
  fast_selftest_ms_p95: 5000,
12
15
  package_size_kb_max: 1024,
13
16
  notes: 'Package payload budget is 1024KB because the current low-dependency CLI payload is already above 512KB; reduce only with measured justification.'
@@ -52,6 +55,90 @@ export async function runPerfBench(root, opts = {}) {
52
55
  };
53
56
  }
54
57
 
58
+ export async function runWorkflowPerfBench(root, opts = {}) {
59
+ const iterations = Math.max(1, Math.min(20, Number(opts.iterations || 3)));
60
+ const intent = String(opts.intent || '').trim();
61
+ const changedFiles = normalizeChangedFiles(opts.changedFiles);
62
+ const proofFieldBuild = [];
63
+ let proofField = null;
64
+ for (let i = 0; i < iterations; i++) {
65
+ const t0 = performance.now();
66
+ proofField = await buildProofField(root, {
67
+ intent,
68
+ changedFiles: changedFiles.length ? changedFiles : undefined
69
+ });
70
+ proofFieldBuild.push(performance.now() - t0);
71
+ }
72
+ const proofValidation = validateProofFieldReport(proofField);
73
+ const verification = proofField?.fast_lane_decision?.verification || [];
74
+ const negativeWork = proofField?.negative_work_cache || [];
75
+ const estimatedSavedWork = negativeWork.filter((item) => item.disposition === 'skip_with_evidence').length;
76
+ const proofFieldMsP95 = Math.round(percentile(proofFieldBuild, 95));
77
+ const workflowScanMsP95 = proofFieldMsP95;
78
+ return {
79
+ schema_version: 1,
80
+ measured_at: nowIso(),
81
+ theory: 'Potential Proof Field',
82
+ iterations,
83
+ intent: intent || null,
84
+ budgets: DEFAULT_PERF_BUDGETS,
85
+ metrics: {
86
+ proof_field_build_ms_p95: proofFieldMsP95,
87
+ workflow_scan_ms_p95: workflowScanMsP95,
88
+ decision_mode: proofField?.fast_lane_decision?.mode || null,
89
+ fast_lane_eligible: Boolean(proofField?.fast_lane_decision?.eligible),
90
+ proof_cone_count: proofField?.proof_cones?.length || 0,
91
+ verification_count: verification.length,
92
+ negative_work_skipped_count: estimatedSavedWork,
93
+ proof_field_valid: proofValidation.ok
94
+ },
95
+ proof_field: proofField,
96
+ recommendation: workflowRecommendation(proofField, proofValidation),
97
+ raw: {
98
+ proof_field_build_ms: proofFieldBuild.map((value) => Math.round(value))
99
+ }
100
+ };
101
+ }
102
+
103
+ export function validateWorkflowPerfReport(report = {}) {
104
+ const issues = [];
105
+ if (report.schema_version !== 1) issues.push('schema_version');
106
+ if (report.theory !== 'Potential Proof Field') issues.push('theory');
107
+ if (!report.metrics || !Number.isFinite(Number(report.metrics.proof_field_build_ms_p95))) issues.push('proof_field_build_ms_p95');
108
+ if (!report.metrics?.decision_mode) issues.push('decision_mode');
109
+ if (!report.proof_field || !validateProofFieldReport(report.proof_field).ok) issues.push('proof_field');
110
+ if (!report.recommendation?.mode) issues.push('recommendation');
111
+ return { ok: issues.length === 0, issues };
112
+ }
113
+
114
+ function normalizeChangedFiles(files) {
115
+ return [...new Set((files || []).flatMap((value) => String(value || '').split(',')).map((file) => file.trim()).filter(Boolean))]
116
+ .sort();
117
+ }
118
+
119
+ function workflowRecommendation(proofField, validation) {
120
+ if (!validation.ok) {
121
+ return {
122
+ mode: 'full_proof',
123
+ reason: `proof field invalid: ${validation.issues.join(', ')}`,
124
+ next: ['repair proof-field report generation', 'rerun sks perf workflow --json']
125
+ };
126
+ }
127
+ const decision = proofField.fast_lane_decision;
128
+ if (decision.eligible) {
129
+ return {
130
+ mode: 'fast_lane',
131
+ reason: 'selected proof cones are narrow and all unrelated work is safely cached as negative work',
132
+ next: decision.verification
133
+ };
134
+ }
135
+ return {
136
+ mode: decision.mode,
137
+ reason: decision.blockers.length ? `blocked by ${decision.blockers.join(', ')}` : 'balanced proof required',
138
+ next: decision.verification
139
+ };
140
+ }
141
+
55
142
  async function packagePayloadSize(root) {
56
143
  let total = 0;
57
144
  for (const rel of ['bin', 'src']) total += await dirSize(path.join(root, rel));
@@ -258,16 +258,16 @@ function applyMadSksAuthorizationToSchema(schema = {}) {
258
258
  DATABASE_TARGET_ENVIRONMENT: 'main_branch',
259
259
  DATABASE_WRITE_MODE: 'mad_sks_full_mcp_write_for_invocation',
260
260
  SUPABASE_MCP_POLICY: 'mad_sks_project_scoped_write_for_invocation',
261
- DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'mad_sks_scoped_with_table_delete_confirmation',
261
+ DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'mad_sks_scoped_except_catastrophic_db_wipe',
262
262
  DB_BACKUP_OR_BRANCH_REQUIRED: 'recommended_but_not_required_in_mad_sks',
263
- DB_MAX_BLAST_RADIUS: 'mad_sks_active_invocation_only_table_delete_confirmation_required',
263
+ DB_MAX_BLAST_RADIUS: 'mad_sks_active_invocation_only_catastrophic_wipe_blocked',
264
264
  DB_MIGRATION_APPLY_ALLOWED: 'mad_sks_active_invocation_only',
265
265
  DB_READ_ONLY_QUERY_LIMIT: '100'
266
266
  };
267
267
  schema.inference_notes = {
268
268
  ...(schema.inference_notes || {}),
269
269
  MAD_SKS_MODE: 'explicit dollar command modifier is the permission boundary',
270
- DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'MAD-SKS scoped override with table deletion confirmation'
270
+ DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'MAD-SKS opens Supabase MCP DB cleanup while blocking only catastrophic database wipe operations'
271
271
  };
272
272
  schema.slots = (schema.slots || []).filter((slot) => !/^(DB_|DATABASE_|DESTRUCTIVE_DB_|SUPABASE_MCP_POLICY$)/.test(slot.id));
273
273
  return schema;
@@ -0,0 +1,219 @@
1
+ import path from 'node:path';
2
+ import { nowIso, readText, rel, runProcess, sha256, writeJsonAtomic } from './fsx.mjs';
3
+
4
+ export const PROOF_FIELD_SCHEMA_VERSION = 1;
5
+
6
+ export const INVARIANT_LEDGER = Object.freeze([
7
+ { id: 'db-catastrophic-guard', severity: 'critical', description: 'Database/table wipe, all-row DML, reset, and dangerous project/branch operations remain blocked.' },
8
+ { id: 'honest-evidence', severity: 'critical', description: 'Final claims must be backed by current code, tests, artifacts, or explicitly marked unverified.' },
9
+ { id: 'route-surface-consistency', severity: 'high', description: 'User-visible route surfaces must agree across CLI help, command catalog, generated skills, and docs.' },
10
+ { id: 'triwiki-hydratable-context', severity: 'high', description: 'TriWiki context must remain coordinate+voxel backed and hydratable by source/hash/anchor.' },
11
+ { id: 'no-unrequested-fallback-code', severity: 'high', description: 'Do not add substitute paths, mocks, shims, or fallback behavior unless explicitly requested.' }
12
+ ]);
13
+
14
+ export const PROOF_CONE_DEFINITIONS = Object.freeze([
15
+ {
16
+ id: 'db_safety',
17
+ surfaces: ['database', 'supabase', 'mad-sks'],
18
+ match: [/db-safety|supabase|migration|rls|schema|sql/i],
19
+ verification: ['npm run packcheck', 'npm run selftest -- --mock', 'sks db scan --json'],
20
+ negative_work: ['browser_ui_e2e', 'visual_snapshot']
21
+ },
22
+ {
23
+ id: 'route_surface',
24
+ surfaces: ['routes', 'skills', 'cli-help', 'docs'],
25
+ match: [/routes\.mjs|init\.mjs|codex-app|README|AGENTS|skills/i],
26
+ verification: ['npm run packcheck', 'npm run selftest -- --mock', 'sks commands --json'],
27
+ negative_work: ['database_migration', 'from_chat_img_forensics']
28
+ },
29
+ {
30
+ id: 'cli_runtime',
31
+ surfaces: ['cli', 'commands', 'runtime'],
32
+ match: [/src\/cli|bin\/sks|maintenance-commands|fsx|codex-adapter/i],
33
+ verification: ['npm run packcheck', 'node ./bin/sks.mjs commands --json', 'node ./bin/sks.mjs proof-field scan --json'],
34
+ negative_work: ['browser_ui_e2e']
35
+ },
36
+ {
37
+ id: 'context_memory',
38
+ surfaces: ['triwiki', 'memory', 'evaluation'],
39
+ match: [/triwiki|wiki|memory|evaluation|perf-bench|proof-field/i],
40
+ verification: ['npm run packcheck', 'node ./bin/sks.mjs eval run --json', 'node ./bin/sks.mjs wiki validate .sneakoscope/wiki/context-pack.json'],
41
+ negative_work: ['database_migration', 'browser_ui_e2e']
42
+ },
43
+ {
44
+ id: 'release_surface',
45
+ surfaces: ['package', 'changelog', 'release'],
46
+ match: [/package\.json|package-lock\.json|CHANGELOG|README/i],
47
+ verification: ['npm run release:check'],
48
+ negative_work: []
49
+ },
50
+ {
51
+ id: 'visual_forensic',
52
+ surfaces: ['from-chat-img', 'visual', 'qa-loop'],
53
+ match: [/from-chat-img|visual|screenshot|qa-loop|dogfood/i],
54
+ verification: ['npm run packcheck', 'npm run selftest -- --mock'],
55
+ negative_work: ['database_migration']
56
+ }
57
+ ]);
58
+
59
+ export async function buildProofField(root, opts = {}) {
60
+ const changedFiles = normalizeChangedFiles(opts.changedFiles || await gitChangedFiles(root));
61
+ const intent = String(opts.intent || '').trim();
62
+ const selectedCones = selectProofCones(changedFiles, intent);
63
+ const risk = riskSummary(changedFiles, selectedCones, intent);
64
+ const negativeWork = buildNegativeWorkCache(selectedCones, risk);
65
+ const fastLane = fastLaneDecision({ changedFiles, selectedCones, risk, negativeWork });
66
+ const sourceHash = await sourceDigest(root, changedFiles);
67
+ return {
68
+ schema_version: PROOF_FIELD_SCHEMA_VERSION,
69
+ generated_at: nowIso(),
70
+ theory: 'Potential Proof Field',
71
+ intent: intent || null,
72
+ source_hash: sourceHash,
73
+ changed_files: changedFiles,
74
+ invariant_ledger: INVARIANT_LEDGER,
75
+ proof_cones: selectedCones,
76
+ negative_work_cache: negativeWork,
77
+ fast_lane_decision: fastLane,
78
+ next_action: nextAction(fastLane)
79
+ };
80
+ }
81
+
82
+ export async function writeProofFieldReport(root, opts = {}) {
83
+ const report = await buildProofField(root, opts);
84
+ const file = path.join(root, '.sneakoscope', 'reports', `proof-field-${Date.now()}.json`);
85
+ await writeJsonAtomic(file, report);
86
+ return { ...report, report_path: file };
87
+ }
88
+
89
+ export function validateProofFieldReport(report = {}) {
90
+ const issues = [];
91
+ if (report.schema_version !== PROOF_FIELD_SCHEMA_VERSION) issues.push('schema_version');
92
+ if (!Array.isArray(report.invariant_ledger) || !report.invariant_ledger.length) issues.push('invariant_ledger');
93
+ if (!Array.isArray(report.proof_cones)) issues.push('proof_cones');
94
+ if (!Array.isArray(report.negative_work_cache)) issues.push('negative_work_cache');
95
+ if (!report.fast_lane_decision?.mode) issues.push('fast_lane_decision');
96
+ if (report.fast_lane_decision?.mode === 'fast_lane' && report.fast_lane_decision?.escalate_on?.length < 1) issues.push('fast_lane_escalation');
97
+ return { ok: issues.length === 0, issues };
98
+ }
99
+
100
+ export async function proofFieldFixture() {
101
+ const report = await buildProofField(process.cwd(), {
102
+ intent: 'small CLI help surface update',
103
+ changedFiles: ['src/cli/maintenance-commands.mjs', 'src/core/routes.mjs']
104
+ });
105
+ return {
106
+ report,
107
+ validation: validateProofFieldReport(report),
108
+ checks: {
109
+ route_cone_selected: report.proof_cones.some((cone) => cone.id === 'route_surface'),
110
+ cli_cone_selected: report.proof_cones.some((cone) => cone.id === 'cli_runtime'),
111
+ catastrophic_guard_present: report.invariant_ledger.some((item) => item.id === 'db-catastrophic-guard'),
112
+ negative_release_work_recorded: report.negative_work_cache.some((item) => item.id === 'full_release_gate' && item.disposition === 'skip_with_evidence')
113
+ }
114
+ };
115
+ }
116
+
117
+ async function gitChangedFiles(root) {
118
+ const result = await runProcess('git', ['diff', '--name-only', 'HEAD', '--'], { cwd: root, timeoutMs: 10000, maxOutputBytes: 128 * 1024 });
119
+ if (result.code !== 0) return [];
120
+ return result.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
121
+ }
122
+
123
+ function normalizeChangedFiles(files = []) {
124
+ return [...new Set((files || []).flatMap((value) => String(value || '').split(',')).map((file) => file.trim()).filter(Boolean))]
125
+ .sort();
126
+ }
127
+
128
+ function selectProofCones(files, intent) {
129
+ const haystack = `${files.join('\n')}\n${intent || ''}`;
130
+ const selected = PROOF_CONE_DEFINITIONS
131
+ .filter((cone) => cone.match.some((re) => re.test(haystack)))
132
+ .map((cone) => ({
133
+ id: cone.id,
134
+ surfaces: cone.surfaces,
135
+ verification: cone.verification,
136
+ matched_files: files.filter((file) => cone.match.some((re) => re.test(file)))
137
+ }));
138
+ if (!selected.length) {
139
+ selected.push({
140
+ id: 'generic_local_change',
141
+ surfaces: ['unknown'],
142
+ verification: ['npm run packcheck', 'focused relevant tests or documented justification'],
143
+ matched_files: files
144
+ });
145
+ }
146
+ return selected;
147
+ }
148
+
149
+ function riskSummary(files, cones, intent) {
150
+ const text = `${files.join('\n')}\n${intent || ''}`;
151
+ const flags = {
152
+ database: /\b(db|database|supabase|sql|migration|rls|schema)\b/i.test(text),
153
+ security: /\b(auth|permission|token|secret|security|권한|보안)\b/i.test(text),
154
+ visual_forensic: /from-chat-img|screenshot|visual|이미지|스크린샷/i.test(text),
155
+ release: /package\.json|package-lock\.json|CHANGELOG|release|publish/i.test(text),
156
+ broad_change: files.length > 3,
157
+ unknown_surface: cones.some((cone) => cone.id === 'generic_local_change')
158
+ };
159
+ const score = Object.values(flags).filter(Boolean).length;
160
+ const level = score >= 3 ? 'high' : score === 2 ? 'medium' : score === 1 ? 'low' : 'minimal';
161
+ return { level, score, flags };
162
+ }
163
+
164
+ function buildNegativeWorkCache(cones, risk) {
165
+ const required = new Set(cones.flatMap((cone) => cone.verification));
166
+ const candidates = new Set(cones.flatMap((cone) => cone.negative_work || []));
167
+ const out = [];
168
+ for (const id of candidates) {
169
+ const blockedByRisk = (id === 'database_migration' && risk.flags.database)
170
+ || (id === 'browser_ui_e2e' && risk.flags.visual_forensic);
171
+ out.push({
172
+ id,
173
+ disposition: blockedByRisk ? 'not_skipped_risk_present' : 'skip_with_evidence',
174
+ reason: blockedByRisk ? 'risk flag requires explicit verification' : 'selected proof cones do not touch this surface'
175
+ });
176
+ }
177
+ if (!required.has('npm run release:check') && !risk.flags.release) {
178
+ out.push({ id: 'full_release_gate', disposition: 'skip_with_evidence', reason: 'no package/release surface in selected cones' });
179
+ }
180
+ return out.sort((a, b) => a.id.localeCompare(b.id));
181
+ }
182
+
183
+ function fastLaneDecision({ changedFiles, selectedCones, risk, negativeWork }) {
184
+ const verification = [...new Set(selectedCones.flatMap((cone) => cone.verification))];
185
+ const safeSkips = negativeWork.filter((item) => item.disposition === 'skip_with_evidence').map((item) => item.id);
186
+ const blockers = [];
187
+ if (!changedFiles.length) blockers.push('no_changed_files');
188
+ if (changedFiles.length > 3) blockers.push('broad_change_set');
189
+ if (risk.flags.database) blockers.push('database_surface');
190
+ if (risk.flags.security) blockers.push('security_surface');
191
+ if (risk.flags.visual_forensic) blockers.push('visual_forensic_surface');
192
+ if (risk.flags.unknown_surface) blockers.push('unknown_surface');
193
+ const mode = blockers.length ? (risk.level === 'high' ? 'full_proof' : 'balanced') : 'fast_lane';
194
+ return {
195
+ mode,
196
+ eligible: mode === 'fast_lane',
197
+ blockers,
198
+ verification,
199
+ negative_work: safeSkips,
200
+ escalate_on: ['verification_failed', 'proof_cone_unknown', 'source_hash_changed', 'unsupported_claim', 'user_scope_expanded']
201
+ };
202
+ }
203
+
204
+ function nextAction(decision) {
205
+ if (decision.mode === 'fast_lane') return 'apply minimal patch, run listed verification, then Honest Mode against the proof field report';
206
+ if (decision.mode === 'balanced') return 'narrow the change set or run parent-led implementation with listed verification and reviewer escalation if checks fail';
207
+ return 'use full Team/Honest proof path; fast lane is intentionally blocked for this risk state';
208
+ }
209
+
210
+ async function sourceDigest(root, files) {
211
+ const rows = [];
212
+ for (const file of files) {
213
+ const abs = path.resolve(root, file);
214
+ if (!abs.startsWith(path.resolve(root))) continue;
215
+ const text = await readText(abs, null);
216
+ rows.push([rel(root, abs), text == null ? null : sha256(text).slice(0, 16)]);
217
+ }
218
+ return sha256(JSON.stringify(rows)).slice(0, 24);
219
+ }
@@ -13,16 +13,16 @@ function buildMadSksQuestionSchema(prompt) {
13
13
  const task = String(prompt || '').trim() || 'MAD-SKS scoped database override';
14
14
  return {
15
15
  schema_version: 1,
16
- description: 'MAD-SKS is explicit-invocation-only. It auto-seals because the dollar command itself is the permission boundary; table deletion still requires runtime user confirmation with an approximately 30 second timeout.',
16
+ description: 'MAD-SKS is explicit-invocation-only. It auto-seals because the dollar command itself is the permission boundary; while active, SKS opens Supabase MCP schema cleanup and direct DB write permissions, leaving only catastrophic database-wipe safeguards.',
17
17
  prompt,
18
18
  domain_hints: ['db', 'mad-sks'],
19
19
  inferred_answers: {
20
20
  GOAL_PRECISE: `명시적인 MAD-SKS 호출 범위에서만 DB 권한 조건을 넓혀 작업한다: ${task}`,
21
21
  ACCEPTANCE_CRITERIA: [
22
22
  '$MAD-SKS is listed in dollar commands and routes to MADSKS mode',
23
- 'broad Supabase MCP DB manipulation is allowed only while the active MAD-SKS mission gate remains open',
23
+ 'Supabase MCP column cleanup, schema cleanup, direct execute SQL, and normal DB writes are allowed only while the active MAD-SKS mission gate remains open',
24
24
  'the widened permission is inactive after the MAD-SKS gate is passed or permissions_deactivated is true',
25
- 'table deletion requires explicit user confirmation and expires after about 30 seconds without confirmation'
25
+ 'whole database/table removal and all-row delete/update operations remain blocked as non-sensible catastrophic operations'
26
26
  ],
27
27
  NON_GOALS: [],
28
28
  PUBLIC_API_CHANGE_ALLOWED: 'yes_if_needed',
@@ -33,21 +33,21 @@ function buildMadSksQuestionSchema(prompt) {
33
33
  RISK_BOUNDARY: [
34
34
  'MAD-SKS permission widening is explicit-invocation-only',
35
35
  'MAD-SKS permission widening does not persist after the active task gate closes',
36
- 'table deletion must pause for explicit user confirmation and timeout-abort after about 30 seconds'
36
+ 'catastrophic database wipe operations remain blocked even in MAD-SKS'
37
37
  ],
38
38
  MAD_SKS_MODE: 'explicit_invocation_only',
39
39
  DATABASE_TARGET_ENVIRONMENT: 'main_branch',
40
40
  DATABASE_WRITE_MODE: 'mad_sks_full_mcp_write_for_invocation',
41
41
  SUPABASE_MCP_POLICY: 'mad_sks_project_scoped_write_for_invocation',
42
- DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'mad_sks_scoped_with_table_delete_confirmation',
42
+ DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'mad_sks_scoped_except_catastrophic_db_wipe',
43
43
  DB_BACKUP_OR_BRANCH_REQUIRED: 'recommended_but_not_required_in_mad_sks',
44
- DB_MAX_BLAST_RADIUS: 'mad_sks_active_invocation_only_table_delete_confirmation_required',
44
+ DB_MAX_BLAST_RADIUS: 'mad_sks_active_invocation_only_catastrophic_wipe_blocked',
45
45
  DB_MIGRATION_APPLY_ALLOWED: 'mad_sks_active_invocation_only',
46
46
  DB_READ_ONLY_QUERY_LIMIT: '100'
47
47
  },
48
48
  inference_notes: {
49
49
  MAD_SKS_MODE: 'explicit dollar command is the permission boundary',
50
- DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'MAD-SKS scoped override with table deletion confirmation'
50
+ DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'MAD-SKS opens Supabase MCP DB cleanup while blocking only catastrophic database wipe operations'
51
51
  },
52
52
  slots: []
53
53
  };
@@ -7,7 +7,7 @@ export const FROM_CHAT_IMG_CHECKLIST_ARTIFACT = 'from-chat-img-checklist.md';
7
7
  export const FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT = 'from-chat-img-temp-triwiki.json';
8
8
  export const FROM_CHAT_IMG_QA_LOOP_ARTIFACT = 'from-chat-img-qa-loop.json';
9
9
  export const FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS = 5;
10
- export const USAGE_TOPICS = 'install|setup|bootstrap|root|deps|warp|auto-review|team|qa-loop|goal|research|db|codex-app|dfix|design|imagegen|dollar|context7|pipeline|reasoning|guard|conflicts|versioning|eval|harness|hproof|gx|wiki|code-structure';
10
+ export const USAGE_TOPICS = 'install|setup|bootstrap|root|deps|warp|auto-review|team|qa-loop|goal|research|db|codex-app|dfix|design|imagegen|dollar|context7|pipeline|reasoning|guard|conflicts|versioning|eval|harness|hproof|gx|wiki|code-structure|proof-field';
11
11
  export const CODEX_COMPUTER_USE_EVIDENCE_SOURCE = 'codex_computer_use';
12
12
  export const CODEX_COMPUTER_USE_ONLY_POLICY = 'Pipeline UI/browser verification and visual inspection must use Codex Computer Use only. Do not use Playwright, Chrome MCP, Browser Use, Selenium, Puppeteer, or any other browser automation substitute; if Codex Computer Use is unavailable, mark the UI/browser evidence unverified instead of substituting another tool.';
13
13
  export const FORBIDDEN_BROWSER_AUTOMATION_RE = /\b(playwright|chrome\s+mcp|browser\s+use|selenium|puppeteer)\b/i;
@@ -276,14 +276,14 @@ export const ROUTES = [
276
276
  command: '$MAD-SKS',
277
277
  mode: 'MADSKS',
278
278
  route: 'explicit scoped database authorization modifier',
279
- description: 'Explicit high-risk authorization modifier that can be combined with other $ commands to temporarily widen Supabase MCP DB permissions for that active invocation only; table deletion still requires user confirmation with an approximately 30 second timeout.',
279
+ description: 'Explicit high-risk authorization modifier that can be combined with other $ commands to temporarily open Supabase MCP column/schema cleanup, direct execute SQL, and normal DB write permissions for the active invocation, while blocking only catastrophic database-wipe operations.',
280
280
  requiredSkills: ['mad-sks', 'db-safety-guard', 'pipeline-runner', 'context7-docs', REFLECTION_SKILL_NAME, 'honest-mode'],
281
- lifecycle: ['explicit_invocation', 'auto_sealed_permission_scope', 'scoped_db_override', 'table_delete_confirmation_gate', 'permission_deactivation', 'post_route_reflection', 'honest_mode'],
281
+ lifecycle: ['explicit_invocation', 'auto_sealed_permission_scope', 'scoped_db_cleanup_override', 'catastrophic_db_guard', 'permission_deactivation', 'post_route_reflection', 'honest_mode'],
282
282
  context7Policy: 'required',
283
283
  reasoningPolicy: 'high',
284
284
  stopGate: 'mad-sks-gate.json',
285
285
  cliEntrypoint: 'Codex App prompt route only: $MAD-SKS <task>',
286
- examples: ['$MAD-SKS $Team Supabase MCP로 main 대상 DB 작업을 수행하되 테이블 삭제는 확인받아', '$DB Supabase 점검 $MAD-SKS']
286
+ examples: ['$MAD-SKS $Team Supabase MCP로 main 대상 DB 컬럼 정리를 수행해', '$DB Supabase 점검 $MAD-SKS']
287
287
  },
288
288
  {
289
289
  id: 'GX',
@@ -376,7 +376,8 @@ export const COMMAND_CATALOG = [
376
376
  { name: 'db', usage: 'sks db policy|scan|mcp-config|classify|check ...', description: 'Inspect and enforce database/Supabase safety policy.' },
377
377
  { name: 'eval', usage: 'sks eval run|compare|thresholds ...', description: 'Run deterministic context-quality and performance evidence checks.' },
378
378
  { name: 'harness', usage: 'sks harness fixture|review [--json]', description: 'Run Harness Growth Factory fixtures for forgetting, skills, experiments, tool taxonomy, permissions, MultiAgentV2, and Warp views.' },
379
- { name: 'perf', usage: 'sks perf run [--json] [--iterations N]', description: 'Measure structured GPT-5.5/SKS performance budgets such as CLI startup and package size.' },
379
+ { name: 'perf', usage: 'sks perf run|workflow [--json] [--iterations N] [--intent "task"] [--changed file1,file2]', description: 'Measure structured GPT-5.5/SKS performance budgets, including Proof Field workflow decisions and fast-lane evidence.' },
380
+ { name: 'proof-field', usage: 'sks proof-field scan [--json] [--intent "task"] [--changed file1,file2]', description: 'Analyze Potential Proof Field cones, negative-work cache, and fast-lane eligibility for a change set.' },
380
381
  { name: 'code-structure', usage: 'sks code-structure scan [--json]', description: 'Scan handwritten source files for 1000/2000/3000-line structure gates and split-review exceptions.' },
381
382
  { name: 'validate-artifacts', usage: 'sks validate-artifacts [mission-id|latest] [--json]', description: 'Validate schema-backed mission artifacts for work orders, effort decisions, visual maps, dogfood reports, skills, mistake memory, Team dashboard state, and Honest Mode.' },
382
383
  { name: 'wiki', usage: 'sks wiki coords|pack|refresh|prune|validate ...', description: 'Build, refresh, prune, and validate RGBA/trig LLM Wiki context packs with attention.use_first and attention.hydrate_first for compact recall plus source hydration.' },