sneakoscope 0.6.69 → 0.6.70

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
@@ -83,6 +83,7 @@ If the CLI is not on `PATH`, SKS also checks the app bundle path:
83
83
  - Installs or upgrades the latest cmux cask through Homebrew when cmux is missing or not launchable.
84
84
  - Re-probes the real cmux binary after install instead of trusting Homebrew's success text alone.
85
85
  - Wakes cmux and retries the socket probe; if the socket is broken, SKS attempts a cmux app restart during that explicit launch.
86
+ - Reuses the named SKS MAD cmux workspace when it already exists and closes duplicate SKS-named MAD workspaces instead of increasing the workspace count on every launch.
86
87
 
87
88
  ## Installation
88
89
 
@@ -174,7 +175,9 @@ sks --mad
174
175
  sks --mad --yes
175
176
  ```
176
177
 
177
- This creates/uses the `sks-mad-high` Codex profile for a one-shot full-access, high-reasoning cmux workspace with `approval_policy = "on-request"` and `approvals_reviewer = "auto_review"`. It is scoped to that explicit command and does not change normal SKS/DB safety defaults.
178
+ This creates/uses the `sks-mad-high` Codex profile for a one-shot full-access, high-reasoning cmux workspace with `approval_policy = "on-request"` and `approvals_reviewer = "auto_review"`. It is scoped to that explicit command and does not change normal SKS/DB safety defaults. Repeat launches select the existing named SKS MAD workspace and clean duplicate SKS-named MAD workspaces instead of creating an endless workspace list.
179
+
180
+ MAD does not disable the pipeline contract: stages, executors, reviewers, and auto-review policy still must not invent unrequested fallback implementation code. If the requested path cannot be implemented, SKS should block with evidence rather than add substitute behavior.
178
181
 
179
182
  Before launching, SKS checks whether a newer `sneakoscope` exists on npm. In an interactive terminal it prompts:
180
183
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "ㅅㅋㅅ",
4
- "version": "0.6.69",
4
+ "version": "0.6.70",
5
5
  "description": "Sneakoscope Codex: database-safe Codex CLI/App harness with Team, Ralph, 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
@@ -25,12 +25,12 @@ import { DEFAULT_EVAL_THRESHOLDS, compareEvaluationReports, defaultEvaluationSce
25
25
  import { buildResearchPrompt, evaluateResearchGate, writeMockResearchResult, writeResearchPlan } from '../core/research.mjs';
26
26
  import { contextCapsule } from '../core/triwiki-attention.mjs';
27
27
  import { rgbaKey, rgbaToWikiCoord, validateWikiCoordinateIndex } from '../core/wiki-coordinate.mjs';
28
- import { COMMAND_CATALOG, DOLLAR_COMMAND_ALIASES, DOLLAR_COMMANDS, 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_SKILLS, ROUTES, USAGE_TOPICS, context7ConfigToml, hasContext7ConfigText, hasFromChatImgSignal, looksLikeAnswerOnlyRequest, reflectionRequiredForRoute, reasoningInstruction, routePrompt, routeReasoning, routeRequiresSubagents, stackCurrentDocsPolicy, triwikiContextTracking } from '../core/routes.mjs';
28
+ import { COMMAND_CATALOG, DOLLAR_COMMAND_ALIASES, DOLLAR_COMMANDS, 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_SKILLS, ROUTES, USAGE_TOPICS, context7ConfigToml, hasContext7ConfigText, hasFromChatImgSignal, looksLikeAnswerOnlyRequest, noUnrequestedFallbackCodePolicyText, reflectionRequiredForRoute, reasoningInstruction, routePrompt, routeReasoning, routeRequiresSubagents, stackCurrentDocsPolicy, triwikiContextTracking } from '../core/routes.mjs';
29
29
  import { context7Evidence, evaluateStop, recordContext7Evidence, recordSubagentEvidence } from '../core/pipeline.mjs';
30
30
  import { TEAM_DECOMPOSITION_ARTIFACT, TEAM_GRAPH_ARTIFACT, TEAM_INBOX_DIR, TEAM_RUNTIME_TASKS_ARTIFACT, teamRuntimePlanMetadata, teamRuntimeRequiredArtifacts, validateTeamRuntimeArtifacts, writeTeamRuntimeArtifacts } from '../core/team-dag.mjs';
31
31
  import { appendTeamEvent, formatRoleCounts, initTeamLive, normalizeTeamSpec, parseTeamSpecArgs, parseTeamSpecText, readTeamDashboard, readTeamLive, readTeamTranscriptTail, renderTeamAgentLane } from '../core/team-live.mjs';
32
32
  import { CODEX_APP_DOCS_URL, codexAppIntegrationStatus, formatCodexAppStatus } from '../core/codex-app.mjs';
33
- import { CMUX_BREW_COMMAND, CMUX_BREW_UPGRADE_COMMAND, buildCmuxLaunchPlan, defaultCmuxWorkspaceName, ensureCmuxInstalled, formatCmuxBanner, launchCmuxTeamView, launchCmuxUi, platformCmuxInstallHint, runCmuxStatus, sanitizeCmuxWorkspaceName, cmuxAvailable } from '../core/cmux-ui.mjs';
33
+ import { CMUX_BREW_COMMAND, CMUX_BREW_UPGRADE_COMMAND, buildCmuxLaunchPlan, buildCmuxNewWorkspaceArgs, cmuxWorkspaceRef, defaultCmuxWorkspaceName, ensureCmuxInstalled, formatCmuxBanner, launchCmuxTeamView, launchCmuxUi, matchingCmuxWorkspaces, parseCmuxWorkspaceList, platformCmuxInstallHint, runCmuxStatus, sanitizeCmuxWorkspaceName, cmuxAvailable } from '../core/cmux-ui.mjs';
34
34
  import { autoReviewProfileName, autoReviewStatus, autoReviewSummary, enableAutoReview, disableAutoReview, enableMadHighProfile, madHighProfileName } from '../core/auto-review.mjs';
35
35
 
36
36
  const flag = (args, name) => args.includes(name);
@@ -492,7 +492,7 @@ async function updateCheck(args = []) {
492
492
  if (result.update_available) console.log('Run: npm i -g sneakoscope');
493
493
  }
494
494
 
495
- const DOLLAR_DEFAULT_PIPELINE_TEXT = 'Default pipeline: questions -> $Answer, small design/content -> $DFix, code -> $Team. Use $From-Chat-IMG only for chat screenshot plus original attachments. Use $MAD-SKS only as an explicit scoped DB authorization modifier that can be combined with another $ route.';
495
+ const DOLLAR_DEFAULT_PIPELINE_TEXT = 'Default pipeline: questions -> $Answer, small design/content -> $DFix, code -> $Team. Use $From-Chat-IMG only for chat screenshot plus original attachments. Use $MAD-SKS only as an explicit scoped DB authorization modifier that can be combined with another $ route. No route may invent unrequested fallback implementation code.';
496
496
 
497
497
  function commands(args = []) {
498
498
  if (flag(args, '--json')) return console.log(JSON.stringify({ aliases: ['sks', 'sneakoscope'], dollar_commands: DOLLAR_COMMANDS, app_skill_aliases: DOLLAR_COMMAND_ALIASES, commands: COMMAND_CATALOG }, null, 2));
@@ -2367,8 +2367,17 @@ async function selftest() {
2367
2367
  const madProfilePath = path.join(tmp, 'mad-codex-config.toml');
2368
2368
  const madProfile = await enableMadHighProfile({ configPath: madProfilePath });
2369
2369
  const madProfileText = await safeReadText(madProfilePath);
2370
- if (madProfile.profile_name !== 'sks-mad-high' || !madProfileText.includes('sandbox_mode = "danger-full-access"') || !madProfileText.includes('approval_policy = "on-request"') || !madProfileText.includes('approvals_reviewer = "auto_review"') || !madProfileText.includes('model_reasoning_effort = "high"')) throw new Error('selftest failed: MAD high profile is not full-access auto-review high');
2370
+ if (madProfile.profile_name !== 'sks-mad-high' || !madProfileText.includes('sandbox_mode = "danger-full-access"') || !madProfileText.includes('approval_policy = "on-request"') || !madProfileText.includes('approvals_reviewer = "auto_review"') || !madProfileText.includes('model_reasoning_effort = "high"') || !madProfileText.includes('unrequested fallback implementation code')) throw new Error('selftest failed: MAD high profile is not full-access auto-review high with fallback-code guard');
2371
2371
  if (!isMadHighLaunch(['--mad', '--high']) || isMadHighLaunch(['db', '--mad'])) throw new Error('selftest failed: MAD high launch flag parsing is not top-level only');
2372
+ const workspacePlan = { workspace: 'sks-mad-selftest', root: tmp, codexArgs: ['--profile', 'sks-mad-high'] };
2373
+ const workspaceArgs = buildCmuxNewWorkspaceArgs(workspacePlan, 'codex');
2374
+ if (!workspaceArgs.includes('--name') || !workspaceArgs.includes('sks-mad-selftest') || !workspaceArgs.includes('--description')) throw new Error('selftest failed: MAD cmux workspace is not named for reuse');
2375
+ const workspaceList = parseCmuxWorkspaceList(JSON.stringify({ workspaces: [
2376
+ { id: 'keep-id', ref: 'workspace:1', name: 'sks-mad-selftest', cwd: tmp },
2377
+ { id: 'other-id', ref: 'workspace:2', name: 'other', cwd: tmp }
2378
+ ] }));
2379
+ const workspaceMatches = matchingCmuxWorkspaces(workspaceList, workspacePlan);
2380
+ if (workspaceMatches.length !== 1 || cmuxWorkspaceRef(workspaceMatches[0]) !== 'workspace:1') throw new Error('selftest failed: MAD cmux workspace reuse matching did not select the stable workspace');
2372
2381
  const guardBlocked = await checkHarnessModification(tmp, { tool_name: 'apply_patch', command: '*** Update File: .agents/skills/team/SKILL.md\n+tamper\n' });
2373
2382
  if (guardBlocked.action !== 'block') throw new Error('selftest failed: harness guard allowed skill tampering');
2374
2383
  const setupBlocked = await checkHarnessModification(tmp, { command: 'sks setup --force' });
@@ -180,9 +180,10 @@ function upsertProfile(text, profile, effort, reviewer = AUTO_REVIEW_REVIEWER) {
180
180
  function upsertAutoReviewPolicy(text) {
181
181
  const policy = [
182
182
  '[auto_review]',
183
- 'policy = "Deny destructive database operations, credential exfiltration, persistent security weakening, broad file deletion, and writes outside the workspace unless explicitly authorized by the user."'
183
+ 'policy = "Deny destructive database operations, credential exfiltration, persistent security weakening, broad file deletion, writes outside the workspace, and unrequested fallback implementation code unless explicitly authorized by the user or sealed decision contract."'
184
184
  ].join('\n');
185
- if (readTableString(text, 'auto_review', 'policy')) return text;
185
+ const existing = readTableString(text, 'auto_review', 'policy');
186
+ if (existing && /unrequested fallback implementation code/i.test(existing)) return text;
186
187
  return upsertTable(text, 'auto_review', policy);
187
188
  }
188
189
 
@@ -28,6 +28,52 @@ export function defaultCmuxWorkspaceName(root) {
28
28
  return sanitizeCmuxWorkspaceName(`sks-${base}-${hash}`);
29
29
  }
30
30
 
31
+ export function cmuxWorkspaceDescription(plan = {}) {
32
+ const profile = codexProfileFromArgs(plan.codexArgs);
33
+ return [
34
+ 'managed-by=sneakoscope',
35
+ `workspace=${sanitizeCmuxWorkspaceName(plan.workspace || defaultCmuxWorkspaceName(plan.root))}`,
36
+ `root=${path.resolve(plan.root || process.cwd())}`,
37
+ `profile=${profile || 'default'}`
38
+ ].join('; ');
39
+ }
40
+
41
+ export function buildCmuxNewWorkspaceArgs(plan = {}, command = '') {
42
+ return [
43
+ 'new-workspace',
44
+ '--name', sanitizeCmuxWorkspaceName(plan.workspace || defaultCmuxWorkspaceName(plan.root)),
45
+ '--description', cmuxWorkspaceDescription(plan),
46
+ '--cwd', path.resolve(plan.root || process.cwd()),
47
+ '--command', command
48
+ ];
49
+ }
50
+
51
+ export function parseCmuxWorkspaceList(text) {
52
+ const raw = String(text || '').trim();
53
+ if (!raw) return [];
54
+ try {
55
+ return normalizeWorkspacePayload(JSON.parse(raw));
56
+ } catch {}
57
+ return raw.split('\n').map(parseWorkspaceLine).filter(Boolean);
58
+ }
59
+
60
+ export function matchingCmuxWorkspaces(workspaces = [], plan = {}) {
61
+ const targetName = sanitizeCmuxWorkspaceName(plan.workspace || defaultCmuxWorkspaceName(plan.root));
62
+ const root = path.resolve(plan.root || process.cwd());
63
+ return workspaces.filter((workspace) => {
64
+ const name = workspaceName(workspace);
65
+ const description = workspaceDescription(workspace);
66
+ const cwd = workspaceCwd(workspace);
67
+ if (name !== targetName && !description.includes(`workspace=${targetName}`)) return false;
68
+ if (!cwd && !description.includes(`root=${root}`)) return true;
69
+ return path.resolve(cwd || root) === root || description.includes(`root=${root}`);
70
+ });
71
+ }
72
+
73
+ export function cmuxWorkspaceRef(workspace = {}) {
74
+ return String(workspace.ref || workspace.workspace_ref || workspace.handle || workspace.id || workspace.workspace_id || workspace.uuid || '').trim();
75
+ }
76
+
31
77
  export function shellEscape(value) {
32
78
  return `'${String(value).replace(/'/g, `'\\''`)}'`;
33
79
  }
@@ -216,9 +262,25 @@ export async function launchCmuxUi(args = [], opts = {}) {
216
262
  process.exitCode = 1;
217
263
  return { plan: blocked };
218
264
  }
265
+ if (args.includes('--status-only')) return { plan };
219
266
  if (!args.includes('--no-open')) await openCmuxApp().catch(() => null);
220
267
  const command = codexLaunchCommand(plan.root, plan.codex.bin, plan.codexArgs);
221
- const created = spawnSync(plan.cmux.bin, ['new-workspace', '--cwd', plan.root, '--command', command], { encoding: 'utf8', stdio: args.includes('--quiet') ? 'pipe' : 'inherit' });
268
+ if (!args.includes('--status-only')) {
269
+ const reuse = await reuseExistingCmuxWorkspace(plan, { cleanup: opts.cleanupWorkspaces !== false });
270
+ if (reuse.reused) {
271
+ if (!args.includes('--quiet')) {
272
+ const suffix = reuse.closed_duplicates ? `; closed duplicate workspace(s): ${reuse.closed_duplicates}` : '';
273
+ console.log(`SKS cmux workspace reused: ${plan.workspace}${suffix}`);
274
+ }
275
+ return { plan, created: false, reused: true, workspace: reuse.workspace, cleanup: reuse };
276
+ }
277
+ if (!reuse.ok) {
278
+ process.exitCode = 1;
279
+ console.error(`SKS cmux workspace check failed: ${reuse.error}`);
280
+ return { plan, workspace_reuse: reuse };
281
+ }
282
+ }
283
+ const created = spawnSync(plan.cmux.bin, buildCmuxNewWorkspaceArgs(plan, command), { encoding: 'utf8', stdio: args.includes('--quiet') ? 'pipe' : 'inherit' });
222
284
  if (created.status !== 0) {
223
285
  process.exitCode = created.status || 1;
224
286
  if (created.stderr) process.stderr.write(created.stderr);
@@ -230,6 +292,35 @@ export async function launchCmuxUi(args = [], opts = {}) {
230
292
  return { plan, created: true };
231
293
  }
232
294
 
295
+ async function reuseExistingCmuxWorkspace(plan = {}, opts = {}) {
296
+ const listed = await listCmuxWorkspaces(plan.cmux?.bin);
297
+ if (!listed.ok) return listed;
298
+ const matches = matchingCmuxWorkspaces(listed.workspaces, plan);
299
+ if (!matches.length) return { ok: true, reused: false, closed_duplicates: 0 };
300
+ const [keep, ...duplicates] = matches;
301
+ const ref = cmuxWorkspaceRef(keep);
302
+ if (!ref) return { ok: false, error: 'matching cmux workspace has no usable id/ref' };
303
+ const selected = await runProcess(plan.cmux.bin, ['select-workspace', '--workspace', ref], { timeoutMs: 5000, maxOutputBytes: 16 * 1024 }).catch((err) => ({ code: 1, stdout: '', stderr: err.message }));
304
+ if (selected.code !== 0) return { ok: false, error: `${selected.stderr || selected.stdout || 'cmux select-workspace failed'}`.trim() };
305
+ let closed = 0;
306
+ if (opts.cleanup !== false) {
307
+ for (const duplicate of duplicates) {
308
+ const duplicateRef = cmuxWorkspaceRef(duplicate);
309
+ if (!duplicateRef || duplicateRef === ref) continue;
310
+ const close = await runProcess(plan.cmux.bin, ['close-workspace', '--workspace', duplicateRef], { timeoutMs: 5000, maxOutputBytes: 16 * 1024 }).catch((err) => ({ code: 1, stdout: '', stderr: err.message }));
311
+ if (close.code === 0) closed += 1;
312
+ }
313
+ }
314
+ return { ok: true, reused: true, workspace: keep, workspace_ref: ref, closed_duplicates: closed, total_matches: matches.length };
315
+ }
316
+
317
+ async function listCmuxWorkspaces(bin) {
318
+ if (!bin) return { ok: false, error: 'cmux CLI not found' };
319
+ const run = await runProcess(bin, ['list-workspaces', '--json'], { timeoutMs: 5000, maxOutputBytes: 128 * 1024 }).catch((err) => ({ code: 1, stdout: '', stderr: err.message }));
320
+ if (run.code !== 0) return { ok: false, error: `${run.stderr || run.stdout || 'cmux list-workspaces failed'}`.trim() };
321
+ return { ok: true, workspaces: parseCmuxWorkspaceList(run.stdout || run.stderr || '') };
322
+ }
323
+
233
324
  function printCmuxLaunchBlocked(plan, opts = {}) {
234
325
  if (opts.concise) {
235
326
  console.error('SKS cmux launch blocked.');
@@ -367,3 +458,37 @@ function readOption(args, name, fallback = null) {
367
458
  const i = args.indexOf(name);
368
459
  return i >= 0 && args[i + 1] ? args[i + 1] : fallback;
369
460
  }
461
+
462
+ function codexProfileFromArgs(args = []) {
463
+ const i = Array.isArray(args) ? args.indexOf('--profile') : -1;
464
+ return i >= 0 && args[i + 1] ? String(args[i + 1]) : '';
465
+ }
466
+
467
+ function normalizeWorkspacePayload(payload) {
468
+ if (Array.isArray(payload)) return payload.filter((item) => item && typeof item === 'object');
469
+ if (!payload || typeof payload !== 'object') return [];
470
+ for (const key of ['workspaces', 'workspace', 'items', 'data']) {
471
+ if (Array.isArray(payload[key])) return normalizeWorkspacePayload(payload[key]);
472
+ }
473
+ if (payload.result) return normalizeWorkspacePayload(payload.result);
474
+ return [];
475
+ }
476
+
477
+ function parseWorkspaceLine(line) {
478
+ const text = String(line || '').trim();
479
+ if (!text) return null;
480
+ const ref = text.match(/\bworkspace:\d+\b/i)?.[0] || text.match(/[0-9a-f]{8}-[0-9a-f-]{27,}/i)?.[0] || '';
481
+ return ref ? { ref, title: text.replace(ref, '').trim(), raw: text } : null;
482
+ }
483
+
484
+ function workspaceName(workspace = {}) {
485
+ return String(workspace.name || workspace.title || workspace.label || workspace.workspace_name || workspace.raw_name || '').trim();
486
+ }
487
+
488
+ function workspaceDescription(workspace = {}) {
489
+ return String(workspace.description || workspace.desc || workspace.subtitle || workspace.raw || '').trim();
490
+ }
491
+
492
+ function workspaceCwd(workspace = {}) {
493
+ return String(workspace.cwd || workspace.path || workspace.root || workspace.working_directory || workspace.workspace_cwd || '').trim();
494
+ }
@@ -45,6 +45,7 @@ export function buildDecisionContract({ mission, schema, answers }) {
45
45
  if_test_command_unknown: 'infer_from_repo_scripts_and_run_most_local_relevant_test',
46
46
  if_e2e_unavailable: 'run_unit_or_integration_and_record_e2e_not_executed',
47
47
  if_dependency_needed: 'avoid_new_dependency_unless_allowed_by_contract',
48
+ if_fallback_implementation_is_tempting: 'do_not_create_unrequested_substitute_code_block_with_evidence_instead',
48
49
  if_existing_behavior_conflict: 'preserve_existing_public_behavior',
49
50
  if_visual_cartridge_conflict: 'vgraph_json_wins_over_rendered_gx_artifact',
50
51
  if_wiki_conflict: 'current_code_wins_over_wiki',
@@ -82,6 +83,7 @@ export function buildDecisionContract({ mission, schema, answers }) {
82
83
  qa_loop_mutation_policy: answers.QA_MUTATION_POLICY || null,
83
84
  qa_loop_credentials_saved: false,
84
85
  qa_loop_ui_requires_official_browser_or_computer_use: Boolean(answers.QA_SCOPE && answers.QA_SCOPE !== 'api_e2e_only'),
86
+ unrequested_fallback_code_allowed: false,
85
87
  mad_sks_mode: madSks ? 'explicit_invocation_only' : false,
86
88
  production_database_writes_allowed: madSks ? 'mad_sks_scoped' : false,
87
89
  mcp_direct_execute_sql_writes_allowed: madSks ? 'mad_sks_scoped' : false,
@@ -113,6 +115,7 @@ export function buildDecisionContract({ mission, schema, answers }) {
113
115
  'explicit_user_answer',
114
116
  'approved_defaults',
115
117
  'database_safety_policy',
118
+ 'no_unrequested_fallback_implementation_code',
116
119
  'AGENTS.md',
117
120
  'vgraph.json',
118
121
  'current_code_and_tests',
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.69';
8
+ export const PACKAGE_VERSION = '0.6.70';
9
9
  export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
10
10
  export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
11
11
 
@@ -154,7 +154,7 @@ async function hookPostTool(root, state, payload, noQuestion) {
154
154
  if (toolFailed(payload)) {
155
155
  return {
156
156
  additionalContext: [
157
- 'SKS no-question mode is active. Do not ask the user about this tool failure. Apply the active plan fallback ladder, create a fix task, and continue.',
157
+ 'SKS no-question mode is active. Do not ask the user about this tool failure. Apply the active decision ladder, create a fix task only inside the sealed contract, and continue. Do not create unrequested fallback implementation code; block with evidence if the requested path is impossible.',
158
158
  teamDigest?.context
159
159
  ].filter(Boolean).join('\n\n'),
160
160
  systemMessage: joinSystemMessages(visibleHookMessage('post-tool'), teamDigest?.system)
package/src/core/init.mjs CHANGED
@@ -88,7 +88,7 @@ function isSksManagedHook(hook) {
88
88
  return hook.type === 'command' && /\bhook\s+(?:user-prompt-submit|pre-tool|post-tool|permission-request|stop)\b/.test(command) && /\b(?:sks|sneakoscope|sks\.mjs)\b/.test(command);
89
89
  }
90
90
 
91
- const AGENTS_BLOCK = "\n# Sneakoscope Codex Managed Rules\n\nThis repository uses Sneakoscope Codex.\n\n## Core Rules\n\n- Ralph asks only during prepare. After `decision-contract.json` is sealed, do not ask the user; resolve with the decision ladder.\n- Keep runtime state bounded: raw logs go to files, prompts get tails/summaries, and `sks gc` may prune stale artifacts.\n- Before substantive work, SKS checks npm for a newer package. If newer, ask update-now vs skip-for-this-conversation.\n- Versioning is managed by the SKS pre-commit hook; check `sks versioning status`. Bypass only with `SKS_DISABLE_VERSIONING=1`.\n- Installed harness files are immutable to LLM edits: `.codex/*`, `.agents/skills/`, `.codex/agents/`, `.sneakoscope/*policy*.json`, `AGENTS.md`, and `node_modules/sneakoscope`. The Sneakoscope engine source repo is the only automatic exception.\n- OMX/DCodex conflicts block setup/doctor. Show `sks conflicts prompt`; cleanup requires explicit human approval.\n- Do not stop at a plan when implementation was requested. Finish, verify, or report the hard blocker.\n\n## Routes\n\n- General execution/code-changing prompts default to `$Team`: analysis scouts, TriWiki refresh/validate, read-only debate, consensus, concrete runtime task graph/inboxes, fresh executor team, review, integration, Honest Mode.\n- `$DFix` is only for tiny design/content edits and bypasses the main pipeline. `$Answer`, `$Help`, and `$Wiki` stay lightweight.\n- For code work, surface route/guard/write scopes first, split independent worker scopes when available, and keep parent-owned integration and verification.\n- Design work reads `design.md`; if missing, use `design-system-builder`. Image/logo/raster assets use `imagegen`.\n- Research, AutoResearch, performance, token, accuracy, SEO/GEO, or workflow-improvement claims need experiment/eval evidence. Do not claim live model accuracy without a scored dataset.\n\n## Evidence And Context\n\n- Context7 is required for external libraries, APIs, MCPs, package managers, SDKs, and generated docs: resolve-library-id then query-docs.\n- When tech stack, framework, package, runtime, or deployment-platform versions change, use Context7 or official vendor web docs, record current syntax/security/limit guidance as high-priority TriWiki claims, then refresh and validate before coding.\n- TriWiki is the context-tracking SSOT for long-running missions, Team handoffs, and context-pressure recovery. Read `.sneakoscope/wiki/context-pack.json` before each stage, use `attention.use_first` for compact high-trust recall, hydrate `attention.hydrate_first` from source before risky or lower-trust decisions, refresh after findings or artifact changes, and validate before handoffs/final claims.\n- Source priority: current code/tests/config, decision contract, vgraph, beta, GX render/snapshot metadata, LLM Wiki coordinate index, then model knowledge only if allowed.\n- Final response before stop: summarize what was done, what changed for the user/repo, what was verified, and what remains unverified or blocked; then run Honest Mode. Say what passed and what was not verified.\n\n## Safety\n\n- Database access is high risk. Use read-only inspection by default; live data mutation is out of scope unless a sealed contract allows local or branch-only migration files.\n- Task completion requires relevant tests or justification, zero unsupported critical claims, accepted visual/wiki drift, and final evidence.\n\n## Codex App\n\nUse `.codex/SNEAKOSCOPE.md`, generated `.agents/skills`, `.codex/hooks.json`, and SKS dollar commands (`$sks`, `$team`, `$dfix`, `$qa-loop`, etc.) as the app control surface.\n";
91
+ const AGENTS_BLOCK = "\n# Sneakoscope Codex Managed Rules\n\nThis repository uses Sneakoscope Codex.\n\n## Core Rules\n\n- Ralph asks only during prepare. After `decision-contract.json` is sealed, do not ask the user; resolve with the decision ladder.\n- Keep runtime state bounded: raw logs go to files, prompts get tails/summaries, and `sks gc` may prune stale artifacts.\n- Before substantive work, SKS checks npm for a newer package. If newer, ask update-now vs skip-for-this-conversation.\n- Versioning is managed by the SKS pre-commit hook; check `sks versioning status`. Bypass only with `SKS_DISABLE_VERSIONING=1`.\n- Installed harness files are immutable to LLM edits: `.codex/*`, `.agents/skills/`, `.codex/agents/`, `.sneakoscope/*policy*.json`, `AGENTS.md`, and `node_modules/sneakoscope`. The Sneakoscope engine source repo is the only automatic exception.\n- OMX/DCodex conflicts block setup/doctor. Show `sks conflicts prompt`; cleanup requires explicit human approval.\n- Do not stop at a plan when implementation was requested. Finish, verify, or report the hard blocker.\n- Do not create unrequested fallback implementation code. If the requested path is impossible, block with evidence instead of inventing substitute behavior.\n\n## Routes\n\n- General execution/code-changing prompts default to `$Team`: analysis scouts, TriWiki refresh/validate, read-only debate, consensus, concrete runtime task graph/inboxes, fresh executor team, review, integration, Honest Mode.\n- `$DFix` is only for tiny design/content edits and bypasses the main pipeline. `$Answer`, `$Help`, and `$Wiki` stay lightweight.\n- For code work, surface route/guard/write scopes first, split independent worker scopes when available, and keep parent-owned integration and verification.\n- Design work reads `design.md`; if missing, use `design-system-builder`. Image/logo/raster assets use `imagegen`.\n- Research, AutoResearch, performance, token, accuracy, SEO/GEO, or workflow-improvement claims need experiment/eval evidence. Do not claim live model accuracy without a scored dataset.\n\n## Evidence And Context\n\n- Context7 is required for external libraries, APIs, MCPs, package managers, SDKs, and generated docs: resolve-library-id then query-docs.\n- When tech stack, framework, package, runtime, or deployment-platform versions change, use Context7 or official vendor web docs, record current syntax/security/limit guidance as high-priority TriWiki claims, then refresh and validate before coding.\n- TriWiki is the context-tracking SSOT for long-running missions, Team handoffs, and context-pressure recovery. Read `.sneakoscope/wiki/context-pack.json` before each stage, use `attention.use_first` for compact high-trust recall, hydrate `attention.hydrate_first` from source before risky or lower-trust decisions, refresh after findings or artifact changes, and validate before handoffs/final claims.\n- Source priority: current code/tests/config, decision contract, vgraph, beta, GX render/snapshot metadata, LLM Wiki coordinate index, then model knowledge only if allowed.\n- Final response before stop: summarize what was done, what changed for the user/repo, what was verified, and what remains unverified or blocked; then run Honest Mode. Say what passed and what was not verified.\n\n## Safety\n\n- Database access is high risk. Use read-only inspection by default; live data mutation is out of scope unless a sealed contract allows local or branch-only migration files.\n- MAD and MAD-SKS widen only explicit scoped permissions; they still do not authorize unrequested fallback implementation code.\n- Task completion requires relevant tests or justification, zero unsupported critical claims, accepted visual/wiki drift, and final evidence.\n\n## Codex App\n\nUse `.codex/SNEAKOSCOPE.md`, generated `.agents/skills`, `.codex/hooks.json`, and SKS dollar commands (`$sks`, `$team`, `$dfix`, `$qa-loop`, etc.) as the app control surface.\n";
92
92
 
93
93
  export async function initProject(root, opts = {}) {
94
94
  const created = [];
@@ -410,7 +410,7 @@ sandbox_mode = "danger-full-access"
410
410
  model_reasoning_effort = "high"
411
411
 
412
412
  [auto_review]
413
- policy = "Deny destructive database operations, credential exfiltration, persistent security weakening, broad file deletion, and writes outside the workspace unless explicitly authorized by the user."
413
+ policy = "Deny destructive database operations, credential exfiltration, persistent security weakening, broad file deletion, writes outside the workspace, and unrequested fallback implementation code unless explicitly authorized by the user or sealed decision contract."
414
414
 
415
415
  [profiles.sks-default]\nmodel = "gpt-5.5"\napproval_policy = "on-request"\nsandbox_mode = "workspace-write"\nmodel_reasoning_effort = "medium"\n`);
416
416
  created.push('.codex/config.toml');
@@ -623,9 +623,9 @@ async function installCodexAgents(root) {
623
623
  const agents = {
624
624
  'analysis-scout.toml': `name = "analysis_scout"\ndescription = "Read-only Team analysis scout. Maps one independent repo/docs/tests/API/risk/user-friction slice and returns TriWiki-ready source-backed findings before debate starts."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "read-only"\ndeveloper_instructions = """\nYou are an SKS Team analysis scout.\nDo not edit files.\nOwn exactly one investigation slice assigned by the parent orchestrator.\nMap relevant source files, docs, tests, APIs, DB or safety risks, UX friction, and likely implementation boundaries.\nReturn concise source-backed claims suitable for team-analysis.md and TriWiki ingestion: claim, source path, evidence hash or quoted anchor, risk, confidence, and recommended implementation slice.\nDo not debate the final plan and do not implement code.\nAlso return a concise LIVE_EVENT line that the parent can record with sks team event.\n"""\n`,
625
625
  'team-consensus.toml': `name = "team_consensus"\ndescription = "Planning and debate specialist for SKS Team mode. Maps options, constraints, role-persona risks, and proposes the agreed objective before implementation starts."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "read-only"\ndeveloper_instructions = """\nYou are the SKS Team consensus specialist.\nDo not edit files.\nMap the affected code paths, viable approaches, constraints, risks, and acceptance criteria.\nRun the debate as role-persona synthesis: final users are low-context, self-interested, stubborn, and inconvenience-averse; executors are capable developers; reviewers are strict.\nArgue for the smallest coherent objective that can be handed to a fresh executor_N development team.\nReturn: recommended objective, rejected alternatives, implementation slices, required reviewers, user-friction risks, and unresolved risks.\nAlso return a concise LIVE_EVENT line that the parent can record with sks team event.\n"""\n`,
626
- 'implementation-worker.toml': `name = "implementation_worker"\ndescription = "Implementation specialist for SKS Team mode. Owns one bounded write set and coordinates with other executor_N workers."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "workspace-write"\ndeveloper_instructions = """\nYou are an SKS Team executor/developer in the fresh development bundle.\nYou are not alone in the codebase. Other executor_N workers may be editing disjoint files.\nOnly edit the files or module slice assigned to you.\nDo not revert or overwrite edits made by others.\nRead local patterns first, make the smallest correct change, avoid adding user friction, run focused verification for your slice, and report changed paths plus evidence.\nRespect all SKS hooks, DB safety rules, no-question Ralph rules, and H-Proof completion gates.\nAlso return concise LIVE_EVENT lines for started, blocked, changed files, verification, and final result so the parent can record them.\n"""\n`,
626
+ 'implementation-worker.toml': `name = "implementation_worker"\ndescription = "Implementation specialist for SKS Team mode. Owns one bounded write set and coordinates with other executor_N workers."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "workspace-write"\ndeveloper_instructions = """\nYou are an SKS Team executor/developer in the fresh development bundle.\nYou are not alone in the codebase. Other executor_N workers may be editing disjoint files.\nOnly edit the files or module slice assigned to you.\nDo not revert or overwrite edits made by others.\nRead local patterns first, make the smallest correct change, avoid adding user friction, run focused verification for your slice, and report changed paths plus evidence.\nDo not create fallback implementation code, substitute behavior, mock behavior, or compatibility shims unless the user or sealed decision contract explicitly requested them.\nRespect all SKS hooks, DB safety rules, no-question Ralph rules, and H-Proof completion gates.\nAlso return concise LIVE_EVENT lines for started, blocked, changed files, verification, and final result so the parent can record them.\n"""\n`,
627
627
  'db-safety-reviewer.toml': `name = "db_safety_reviewer"\ndescription = "Read-only database safety reviewer for SQL, migrations, Supabase, RLS, destructive-operation risk, and rollback safety."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "read-only"\ndeveloper_instructions = """\nYou are a database safety reviewer.\nNever modify files or execute destructive commands.\nReview migrations, SQL, Supabase RLS, transaction boundaries, rollback safety, and MCP database tool usage.\nBlock DROP, TRUNCATE, mass DELETE/UPDATE, db reset, db push, project deletion, branch reset/merge/delete, RLS disabling, and live execute_sql writes.\nReturn concrete risks, exact file references, and required fixes.\nAlso return a concise LIVE_EVENT line that the parent can record with sks team event.\n"""\n`,
628
- 'qa-reviewer.toml': `name = "qa_reviewer"\ndescription = "Strict read-only verification reviewer for correctness, regressions, missing tests, user friction, and final evidence."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "read-only"\ndeveloper_instructions = """\nYou are an SKS Team strict reviewer.\nDo not edit files.\nReview correctness, edge cases, regression risk, missing tests, unsupported claims, and whether the final evidence proves the claimed outcome.\nAlso evaluate practical friction from the viewpoint of a stubborn, low-context final user who dislikes inconvenience.\nPrioritize concrete findings with file references and focused verification suggestions.\nReturn no findings if the implementation is sound, and clearly list residual test gaps.\nAlso return a concise LIVE_EVENT line that the parent can record with sks team event.\n"""\n`
628
+ 'qa-reviewer.toml': `name = "qa_reviewer"\ndescription = "Strict read-only verification reviewer for correctness, regressions, missing tests, user friction, and final evidence."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "read-only"\ndeveloper_instructions = """\nYou are an SKS Team strict reviewer.\nDo not edit files.\nReview correctness, edge cases, regression risk, missing tests, unsupported claims, and whether the final evidence proves the claimed outcome.\nAlso evaluate practical friction from the viewpoint of a stubborn, low-context final user who dislikes inconvenience.\nPrioritize concrete findings with file references and focused verification suggestions.\nFlag any unrequested fallback implementation code, substitute behavior, mock behavior, or compatibility shim as a blocking finding unless the user or sealed decision contract explicitly requested it.\nReturn no findings if the implementation is sound, and clearly list residual test gaps.\nAlso return a concise LIVE_EVENT line that the parent can record with sks team event.\n"""\n`
629
629
  };
630
630
  const dir = path.join(root, '.codex', 'agents');
631
631
  await ensureDir(dir);
@@ -7,7 +7,7 @@ import { buildQuestionSchemaForRoute, writeQuestions } from './questions.mjs';
7
7
  import { sealContract } from './decision-contract.mjs';
8
8
  import { scanDbSafety } from './db-safety.mjs';
9
9
  import { writeResearchPlan } from './research.mjs';
10
- import { 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, chatCaptureIntakeText, context7RequirementText, dollarCommand, hasFromChatImgSignal, hasMadSksSignal, reflectionRequiredForRoute, reasoningInstruction, routeNeedsContext7, routePrompt, routeReasoning, routeRequiresSubagents, stripDollarCommand, stripMadSksSignal, subagentExecutionPolicyText, stackCurrentDocsPolicyText, triwikiContextTracking, triwikiContextTrackingText, triwikiStagePolicyText } from './routes.mjs';
10
+ import { 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, chatCaptureIntakeText, context7RequirementText, dollarCommand, hasFromChatImgSignal, hasMadSksSignal, noUnrequestedFallbackCodePolicyText, reflectionRequiredForRoute, reasoningInstruction, routeNeedsContext7, routePrompt, routeReasoning, routeRequiresSubagents, stripDollarCommand, stripMadSksSignal, subagentExecutionPolicyText, stackCurrentDocsPolicyText, triwikiContextTracking, triwikiContextTrackingText, triwikiStagePolicyText } from './routes.mjs';
11
11
  import { TEAM_DECOMPOSITION_ARTIFACT, TEAM_GRAPH_ARTIFACT, TEAM_INBOX_DIR, TEAM_RUNTIME_TASKS_ARTIFACT, teamRuntimePlanMetadata, teamRuntimeRequiredArtifacts, validateTeamRuntimeArtifacts, writeTeamRuntimeArtifacts } from './team-dag.mjs';
12
12
  import { formatRoleCounts, initTeamLive, parseTeamSpecText } from './team-live.mjs';
13
13
 
@@ -45,6 +45,7 @@ export function promptPipelineContext(prompt, route = routePrompt(prompt)) {
45
45
  'Default execution routing: general implementation/code-changing prompts promote to Team so the normal path is parallel analysis, TriWiki refresh, debate/consensus, then fresh parallel executors. Answer, DFix, Help, Wiki maintenance, and safety-specific routes are intentional exceptions.',
46
46
  'Stance: infer the user intent aggressively from rough wording and local context, but ask short ambiguity-removal questions before work when a missing answer can change the target, scope, safety boundary, or acceptance criteria.',
47
47
  subagentExecutionPolicyText(route, prompt),
48
+ noUnrequestedFallbackCodePolicyText(),
48
49
  'Design routing: UI/UX reads design.md first; if missing, use design-system-builder from docs/Design-Sys-Prompt.md with plan-tool clarification and a default font recommendation. Existing designs use design-ui-editor plus design-artifact-expert. Image/logo/raster assets use imagegen.',
49
50
  triwikiContextTrackingText(),
50
51
  triwikiStagePolicyText(),
@@ -312,7 +313,7 @@ async function prepareTeam(root, route, task, required) {
312
313
  await writeJsonAtomic(path.join(dir, 'team-plan.json'), plan);
313
314
  await writeJsonAtomic(path.join(dir, 'team-roster.json'), { schema_version: 1, mission_id: id, role_counts: roleCounts, agent_sessions: agentSessions, bundle_size: roster.bundle_size, roster, confirmed: true, source: 'default_or_prompt_team_spec' });
314
315
  const contextTracking = triwikiContextTracking();
315
- await writeTextAtomic(path.join(dir, 'team-workflow.md'), `# SKS Team Workflow\n\nTask: ${cleanTask}\n\nAgent session budget: ${agentSessions}\nBundle size: ${roster.bundle_size}\nRole counts: ${formatRoleCounts(roleCounts)}\nReasoning: high for team logic, temporary for this route only.\nContext tracking: ${contextTracking.ssot} SSOT, ${contextTracking.default_pack}; use relevant TriWiki context before every work stage, refresh/validate after findings, and preserve hydratable source anchors.\n\n1. Run exactly ${roster.bundle_size} read-only analysis_scout_N agents and write team-analysis.md.\n2. Refresh/validate TriWiki before debate.\n3. Run exactly ${roster.bundle_size} debate participants, then write consensus and implementation slices.\n4. Compile ${TEAM_GRAPH_ARTIFACT}, ${TEAM_RUNTIME_TASKS_ARTIFACT}, ${TEAM_DECOMPOSITION_ARTIFACT}, and ${TEAM_INBOX_DIR} so worker handoff uses concrete runtime task ids.\n5. Close debate agents before starting a fresh ${roster.bundle_size}-person executor team.\n6. Review, integrate, verify, and record evidence.\n7. Close/clean remaining Team sessions, finalize live transcript state, and write ${TEAM_SESSION_CLEANUP_ARTIFACT} before reflection/final.\n\nLive visibility:\n- sks team log ${id}\n- sks team tail ${id}\n- sks team watch ${id}\n- sks team lane ${id} --agent analysis_scout_1 --follow\n- sks team event ${id} --agent <name> --phase <phase> --message \"...\"\n`);
316
+ await writeTextAtomic(path.join(dir, 'team-workflow.md'), `# SKS Team Workflow\n\nTask: ${cleanTask}\n\nAgent session budget: ${agentSessions}\nBundle size: ${roster.bundle_size}\nRole counts: ${formatRoleCounts(roleCounts)}\nReasoning: high for team logic, temporary for this route only.\nContext tracking: ${contextTracking.ssot} SSOT, ${contextTracking.default_pack}; use relevant TriWiki context before every work stage, refresh/validate after findings, and preserve hydratable source anchors.\n\n1. Run exactly ${roster.bundle_size} read-only analysis_scout_N agents and write team-analysis.md.\n2. Refresh/validate TriWiki before debate.\n3. Run exactly ${roster.bundle_size} debate participants, then write consensus and implementation slices.\n4. Compile ${TEAM_GRAPH_ARTIFACT}, ${TEAM_RUNTIME_TASKS_ARTIFACT}, ${TEAM_DECOMPOSITION_ARTIFACT}, and ${TEAM_INBOX_DIR} so worker handoff uses concrete runtime task ids.\n5. Close debate agents before starting a fresh ${roster.bundle_size}-person executor team.\n6. Review, integrate, verify, and record evidence.\n7. Close/clean remaining Team sessions, finalize live transcript state, and write ${TEAM_SESSION_CLEANUP_ARTIFACT} before reflection/final.\n\nNo unrequested fallback implementation code is allowed in any stage, executor lane, review lane, MAD route, or MAD-SKS route. If the requested path cannot be implemented inside the sealed contract, block with evidence instead of adding substitute behavior.\n\nLive visibility:\n- sks team log ${id}\n- sks team tail ${id}\n- sks team watch ${id}\n- sks team lane ${id} --agent analysis_scout_1 --follow\n- sks team event ${id} --agent <name> --phase <phase> --message \"...\"\n`);
316
317
  await initTeamLive(id, dir, cleanTask, { agentSessions, roleCounts, roster });
317
318
  const runtime = await writeTeamRuntimeArtifacts(dir, plan, {});
318
319
  await writeJsonAtomic(path.join(dir, 'team-gate.json'), { passed: false, team_roster_confirmed: true, analysis_artifact: false, triwiki_refreshed: false, triwiki_validated: false, consensus_artifact: false, ...runtime.gate_fields, implementation_team_fresh: false, review_artifact: false, integration_evidence: false, session_cleanup: false, context7_evidence: false, ...(fromChatImgRequired ? { from_chat_img_required: true, from_chat_img_request_coverage: false } : {}) });
@@ -50,7 +50,7 @@ export function buildQaLoopQuestionSchema(prompt) {
50
50
  { id: 'ACCEPTANCE_CRITERIA', question: 'List the QA completion criteria.', required: true, type: 'array_or_string' },
51
51
  { id: 'NON_GOALS', question: 'List anything QA-LOOP must not test.', required: true, type: 'array_or_string', allow_empty: true },
52
52
  { id: 'RISK_BOUNDARY', question: 'List hard safety boundaries for data, auth, permissions, money, messages, and third-party systems.', required: true, type: 'array_or_string' },
53
- { id: 'MID_RALPH_UNKNOWN_POLICY', question: 'If ambiguity appears during no-question QA, choose the fallback order.', required: true, type: 'array', options: ['preserve_existing_behavior', 'smallest_reversible_change', 'defer_optional_scope', 'block_only_if_no_safe_path'] }
53
+ { id: 'MID_RALPH_UNKNOWN_POLICY', question: 'If ambiguity appears during no-question QA, choose the resolution order. This does not authorize unrequested fallback implementation code.', required: true, type: 'array', options: ['preserve_existing_behavior', 'smallest_reversible_change', 'defer_optional_scope', 'block_only_if_no_safe_path'] }
54
54
  ]
55
55
  };
56
56
  }
@@ -138,7 +138,8 @@ export function inferAnswersForPrompt(prompt, explicitAnswers = {}) {
138
138
  addInferred(inferred, notes, 'RISK_BOUNDARY', [
139
139
  'no npm publish unless explicitly requested',
140
140
  'do not revert unrelated changes',
141
- 'no destructive commands or live data writes'
141
+ 'no destructive commands or live data writes',
142
+ 'no unrequested fallback implementation code'
142
143
  ], 'safety');
143
144
  }
144
145
  return { answers: inferred, notes };
@@ -159,7 +160,7 @@ export function buildQuestionSchema(prompt) {
159
160
  { id: 'DB_SCHEMA_CHANGE_ALLOWED', question: 'DB schema 또는 migration 변경을 허용하나요?', required: true, type: 'enum', options: ['no', 'yes_if_needed', 'yes_with_migration'] },
160
161
  { id: 'DEPENDENCY_CHANGE_ALLOWED', question: '새 dependency 추가를 허용하나요?', required: true, type: 'enum', options: ['no', 'yes_if_already_approved', 'yes'] },
161
162
  { id: 'TEST_SCOPE', question: 'Ralph가 완료 전 실행 또는 정당화해야 할 테스트 범위를 지정해주세요.', required: true, type: 'array_or_string', examples: ['unit', 'integration', 'e2e', 'lint', 'typecheck'] },
162
- { id: 'MID_RALPH_UNKNOWN_POLICY', question: 'Ralph 중 새 모호성이 생기면 사용자에게 묻지 않고 어떤 fallback 순서로 해결할까요?', required: true, type: 'array', options: ['preserve_existing_behavior', 'smallest_reversible_change', 'defer_optional_scope', 'block_only_if_no_safe_path'] },
163
+ { id: 'MID_RALPH_UNKNOWN_POLICY', question: 'Ralph 중 새 모호성이 생기면 사용자에게 묻지 않고 어떤 해결 순서로 판단할까요? 이 항목은 대체 구현 또는 fallback 코드를 새로 만드는 허가가 아닙니다.', required: true, type: 'array', options: ['preserve_existing_behavior', 'smallest_reversible_change', 'defer_optional_scope', 'block_only_if_no_safe_path'] },
163
164
  { id: 'RISK_BOUNDARY', question: '보안, 결제, 데이터 손상, 권한, 인증 등 절대 넘으면 안 되는 위험 경계를 적어주세요.', required: true, type: 'array_or_string' },
164
165
 
165
166
  { id: 'DATABASE_TARGET_ENVIRONMENT', question: 'DB 관련 작업의 대상 환경을 지정해주세요. production write는 Sneakoscope Codex가 허용하지 않습니다.', required: true, type: 'enum', options: ['no_database', 'local_dev', 'preview_branch', 'supabase_branch', 'production_read_only'] },
@@ -110,6 +110,10 @@ export function chatCaptureIntakeText() {
110
110
  return `From-Chat-IMG intake: explicit signal only. Treat uploads as chat screenshot plus originals, use Computer Use/browser visual inspection when available, list requirements first in source order, match regions to attachments with confidence, and write ${FROM_CHAT_IMG_COVERAGE_ARTIFACT}, ${FROM_CHAT_IMG_CHECKLIST_ARTIFACT}, ${FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT}, and ${FROM_CHAT_IMG_QA_LOOP_ARTIFACT}. Preserve each visible customer request as source-bound text, account for every screenshot image region and separate attachment, map each item to work-order actions, perform the customer-request work, then run a scoped QA-LOOP over that exact work-order range before Team completion. Update checklist checkboxes as work proceeds until all boxes are checked, unresolved_items is empty, scoped_qa_loop_completed=true, and QA unresolved findings are zero. ${FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT} is temporary TriWiki-backed session context with expires_after_sessions=${FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS}, so it can be forgotten by retention after enough later sessions. Do not assume ordinary image prompts are chat captures.`;
111
111
  }
112
112
 
113
+ export function noUnrequestedFallbackCodePolicyText() {
114
+ return 'No unrequested fallback implementation code: every pipeline stage, executor, reviewer, auto-review profile, and MAD/MAD-SKS invocation must implement only the requested contract. Do not invent alternate code paths, substitute features, compatibility shims, mock behavior, or hidden fallbacks unless the user explicitly requested them or the sealed decision contract names them; if the requested path is impossible, block with evidence instead.';
115
+ }
116
+
113
117
  export function hasFromChatImgSignal(prompt = '') {
114
118
  return /(?:^|\s)\$?from-chat-img(?:\s|:|$)/i.test(String(prompt || ''));
115
119
  }
@@ -521,7 +525,8 @@ export function subagentExecutionPolicyText(route, prompt = '') {
521
525
  'Subagent policy: REQUIRED for code-changing or execution work in this route.',
522
526
  'Before editing, the parent orchestrator must visibly state the SKS route, split independent write scopes, and spawn worker/reviewer subagents whenever the tools are available.',
523
527
  'Run workers in parallel only with disjoint ownership. The parent owns integration, verification, and final evidence.',
524
- 'If subagent tools are unavailable or the work cannot be safely split, record that as explicit subagent evidence before editing.'
528
+ 'If subagent tools are unavailable or the work cannot be safely split, record that as explicit subagent evidence before editing.',
529
+ noUnrequestedFallbackCodePolicyText()
525
530
  ].join(' ');
526
531
  }
527
532
 
@@ -373,6 +373,7 @@ function inboxMarkdown(worker, tasks, compiled) {
373
373
  '',
374
374
  'Use concrete task ids for readiness and handoff. Dependencies below are runtime task ids, not plan-only symbolic ids.',
375
375
  'Before task work, read `.sneakoscope/wiki/context-pack.json`: use `attention.use_first` for compact high-trust context and hydrate `attention.hydrate_first` from source before risky or lower-trust decisions.',
376
+ 'Do not create fallback implementation code, substitute behavior, mock behavior, or compatibility shims unless the user or sealed decision contract explicitly requested them.',
376
377
  ''
377
378
  ];
378
379
  for (const task of tasks) {