sneakoscope 4.4.0 → 4.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +28 -2
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/bin/sks.js +1 -1
  6. package/dist/cli/command-registry.js +1 -0
  7. package/dist/core/agents/agent-runner-ollama.js +2 -0
  8. package/dist/core/agents/native-worker-backend-router.js +3 -0
  9. package/dist/core/bench.js +115 -0
  10. package/dist/core/code-structure.js +399 -11
  11. package/dist/core/codex-control/codex-fake-sdk-adapter.js +67 -9
  12. package/dist/core/codex-control/gpt-final-arbiter.js +4 -1
  13. package/dist/core/codex-control/gpt-final-review-schema.js +58 -0
  14. package/dist/core/codex-native/core-skill-manifest.js +23 -0
  15. package/dist/core/commands/bench-command.js +11 -2
  16. package/dist/core/commands/code-structure-command.js +34 -2
  17. package/dist/core/commands/run-command.js +92 -2
  18. package/dist/core/commands/seo-command.js +130 -0
  19. package/dist/core/db-safety.js +8 -6
  20. package/dist/core/feature-fixtures.js +6 -0
  21. package/dist/core/feature-registry.js +3 -1
  22. package/dist/core/fsx.js +1 -1
  23. package/dist/core/hooks-runtime.js +8 -0
  24. package/dist/core/init.js +8 -6
  25. package/dist/core/lean-engineering-policy.js +159 -0
  26. package/dist/core/mad-db/mad-db-policy-resolver.js +23 -2
  27. package/dist/core/pipeline-internals/runtime-core.js +15 -5
  28. package/dist/core/proof/auto-finalize.js +3 -2
  29. package/dist/core/proof/proof-schema.js +2 -1
  30. package/dist/core/proof/proof-writer.js +1 -0
  31. package/dist/core/proof/route-adapter.js +4 -2
  32. package/dist/core/proof/route-finalizer.js +35 -3
  33. package/dist/core/routes.js +75 -9
  34. package/dist/core/search-visibility/adapter-registry.js +26 -0
  35. package/dist/core/search-visibility/adapters/next-app.js +6 -0
  36. package/dist/core/search-visibility/adapters/next-pages.js +6 -0
  37. package/dist/core/search-visibility/adapters/static-site.js +6 -0
  38. package/dist/core/search-visibility/analyzers.js +377 -0
  39. package/dist/core/search-visibility/artifacts.js +183 -0
  40. package/dist/core/search-visibility/discovery.js +347 -0
  41. package/dist/core/search-visibility/index.js +199 -0
  42. package/dist/core/search-visibility/mission.js +67 -0
  43. package/dist/core/search-visibility/mutation.js +314 -0
  44. package/dist/core/search-visibility/types.js +2 -0
  45. package/dist/core/search-visibility/verifier.js +60 -0
  46. package/dist/core/version.js +1 -1
  47. package/dist/scripts/check-architecture.js +40 -7
  48. package/dist/scripts/check-command-module-budget.js +43 -5
  49. package/dist/scripts/check-pipeline-budget.js +17 -30
  50. package/dist/scripts/check-publish-tag.js +33 -6
  51. package/dist/scripts/check-route-modularity.js +25 -33
  52. package/dist/scripts/check-runtime-schemas.js +22 -0
  53. package/dist/scripts/config-managed-merge-callsite-coverage-check.js +2 -2
  54. package/dist/scripts/core-skill-immutable-sync-check.js +3 -2
  55. package/dist/scripts/core-skill-integrity-blackbox.js +3 -2
  56. package/dist/scripts/core-skill-manifest-check.js +7 -2
  57. package/dist/scripts/geo-claim-evidence-check.js +18 -0
  58. package/dist/scripts/geo-cli-blackbox-check.js +18 -0
  59. package/dist/scripts/geo-crawler-policy-check.js +16 -0
  60. package/dist/scripts/geo-llms-txt-optional-check.js +19 -0
  61. package/dist/scripts/gpt-final-arbiter-check.js +4 -1
  62. package/dist/scripts/mad-db-direct-apply-migration-hook-check.js +50 -0
  63. package/dist/scripts/release-dag-full-coverage-check.js +1 -0
  64. package/dist/scripts/release-parallel-check.js +15 -0
  65. package/dist/scripts/release-registry-check.js +33 -14
  66. package/dist/scripts/search-visibility-gate-lib.js +124 -0
  67. package/dist/scripts/seo-audit-fixture-check.js +16 -0
  68. package/dist/scripts/seo-canonical-locale-check.js +19 -0
  69. package/dist/scripts/seo-cli-blackbox-check.js +18 -0
  70. package/dist/scripts/seo-geo-feature-fixture-quality-check.js +18 -0
  71. package/dist/scripts/seo-geo-geo-disambiguation-check.js +12 -0
  72. package/dist/scripts/seo-geo-no-unsupported-ranking-claims-check.js +18 -0
  73. package/dist/scripts/seo-geo-route-identity-check.js +12 -0
  74. package/dist/scripts/seo-geo-skill-rich-content-check.js +22 -0
  75. package/dist/scripts/seo-mutation-rollback-check.js +23 -0
  76. package/dist/scripts/seo-no-mutation-by-default-check.js +17 -0
  77. package/dist/scripts/seo-structured-data-visible-content-check.js +19 -0
  78. package/dist/scripts/sks-3-1-5-directive-check-lib.js +10 -1
  79. package/package.json +21 -2
  80. package/schemas/search-visibility/finding-ledger.schema.json +36 -0
  81. package/schemas/search-visibility/gate.schema.json +22 -0
  82. package/schemas/search-visibility/mutation-plan.schema.json +27 -0
  83. package/schemas/search-visibility/site-inventory.schema.json +21 -0
  84. package/schemas/search-visibility/verification-report.schema.json +23 -0
package/dist/core/init.js CHANGED
@@ -7,7 +7,7 @@ import { isHarnessSourceProject, writeHarnessGuardPolicy } from './harness-guard
7
7
  import { repairSksGeneratedArtifacts } from './harness-conflicts.js';
8
8
  import { disableVersionGitHook } from './version-manager.js';
9
9
  import { MIN_TEAM_REVIEWER_LANES, MIN_TEAM_REVIEW_POLICY_TEXT } from './team-review-policy.js';
10
- import { AWESOME_DESIGN_MD_REFERENCE, CODEX_APP_IMAGE_GENERATION_DOC_URL, CODEX_COMPUTER_USE_ONLY_POLICY, CODEX_IMAGEGEN_REQUIRED_POLICY, CODEX_WEB_VERIFICATION_POLICY, DEFAULT_CODEX_APP_PLUGINS, DESIGN_SYSTEM_SSOT, 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, GETDESIGN_REFERENCE, IMAGEGEN_SOCIAL_SOURCE_POLICY, OPENAI_CHATGPT_IMAGES_2_DOC_URL, OPENAI_GPT_IMAGE_2_MODEL_DOC_URL, OPENAI_IMAGE_GENERATION_DOC_URL, PPT_CONDITIONAL_SKILL_ALLOWLIST, PPT_PIPELINE_MCP_ALLOWLIST, PPT_PIPELINE_SKILL_ALLOWLIST, RECOMMENDED_DESIGN_REFERENCES, RECOMMENDED_MCP_SERVERS, RECOMMENDED_SKILLS, RESERVED_CODEX_PLUGIN_SKILL_NAMES, SOLUTION_SCOUT_SKILL_NAME, chatCaptureIntakeText, context7ConfigToml, getdesignReferencePolicyText, imageUxReviewPipelinePolicyText, outcomeRubricPolicyText, pptPipelineAllowlistPolicyText, productDesignPluginPolicyText, solutionScoutPolicyText, speedLanePolicyText, stackCurrentDocsPolicyText, triwikiContextTracking, triwikiContextTrackingText, triwikiStagePolicyText } from './routes.js';
10
+ import { AWESOME_DESIGN_MD_REFERENCE, CODEX_APP_IMAGE_GENERATION_DOC_URL, CODEX_COMPUTER_USE_ONLY_POLICY, CODEX_IMAGEGEN_REQUIRED_POLICY, CODEX_WEB_VERIFICATION_POLICY, DEFAULT_CODEX_APP_PLUGINS, DESIGN_SYSTEM_SSOT, 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, GETDESIGN_REFERENCE, IMAGEGEN_SOCIAL_SOURCE_POLICY, OPENAI_CHATGPT_IMAGES_2_DOC_URL, OPENAI_GPT_IMAGE_2_MODEL_DOC_URL, OPENAI_IMAGE_GENERATION_DOC_URL, PPT_CONDITIONAL_SKILL_ALLOWLIST, PPT_PIPELINE_MCP_ALLOWLIST, PPT_PIPELINE_SKILL_ALLOWLIST, RECOMMENDED_DESIGN_REFERENCES, RECOMMENDED_MCP_SERVERS, RECOMMENDED_SKILLS, RESERVED_CODEX_PLUGIN_SKILL_NAMES, SOLUTION_SCOUT_SKILL_NAME, chatCaptureIntakeText, context7ConfigToml, getdesignReferencePolicyText, imageUxReviewPipelinePolicyText, leanEngineeringCompactText, outcomeRubricPolicyText, pptPipelineAllowlistPolicyText, productDesignPluginPolicyText, solutionScoutPolicyText, speedLanePolicyText, stackCurrentDocsPolicyText, triwikiContextTracking, triwikiContextTrackingText, triwikiStagePolicyText } from './routes.js';
11
11
  import { SKILL_DREAM_POLICY, skillDreamPolicyText } from './skill-forge.js';
12
12
  import { CODEX_HOOK_EVENT_STATE_KEYS } from './codex-compat/codex-hook-events.js';
13
13
  import { codexCommandHookCurrentHash } from './codex-hooks/codex-hook-hash.js';
@@ -1043,7 +1043,7 @@ export async function installSkills(root) {
1043
1043
  'with-local-llm-on': `---\nname: with-local-llm-on\ndescription: Dollar-command route for $with-local-llm-on local Ollama worker enablement.\n---\n\nUse when the user invokes $with-local-llm-on or asks to enable the optional local Ollama worker backend. Prefer \`sks with-local-llm on --json\`. The command writes the machine-local config at \`~/.sneakoscope/local-model.json\`. Default off means SKS stays GPT-only until this command enables local workers. Enabled mode only lets policy-eligible simple code patch-envelope or read-only collection worker slices use Ollama; GPT/Codex still owns strategy, planning, design, review, verification, safety, and integration. \`--no-ollama\` and \`SKS_OLLAMA_WORKERS=0\` still force local workers off for a run. Finish with a short status and Honest Mode; do not start Team for a toggle-only request.\n`,
1044
1044
  'with-local-llm-off': `---\nname: with-local-llm-off\ndescription: Dollar-command route for $with-local-llm-off local Ollama worker disablement.\n---\n\nUse when the user invokes $with-local-llm-off or asks to disable the optional local Ollama worker backend. Prefer \`sks with-local-llm off --json\`. The command writes the machine-local config at \`~/.sneakoscope/local-model.json\`. Disabled mode keeps SKS GPT-only by default. Strategy, planning, design, review, verification, safety, and integration remain GPT/Codex-owned regardless of this toggle. Finish with a short status and Honest Mode; do not start Team for a toggle-only request.\n`,
1045
1045
  'wiki': `---\nname: wiki\ndescription: Dollar-command route for $Wiki TriWiki refresh, pack, validate, and prune commands.\n---\n\nUse for $Wiki or Korean wiki-refresh requests. Refresh/update/갱신: run sks wiki refresh, then validate .sneakoscope/wiki/context-pack.json. Pack: run sks wiki pack, then validate. Prune/clean/정리: use sks wiki refresh --prune, or sks wiki prune --dry-run for inspection. Report claims, anchors, trust, attention.use_first/hydrate_first, validation, and blockers. Do not start ambiguity-gated implementation, subagents, or unrelated work.\n`,
1046
- 'team': `---\nname: team\ndescription: SKS Team orchestration for $Team/code work; $From-Chat-IMG is the explicit chat-image alias.\n---\n\nUse for $Team/code work. Auto-seal the route contract from prompt, TriWiki/current-code defaults, and conservative policy; do not surface a prequestion sheet. Read pipeline-plan.json or run sks pipeline plan to see the runtime lane, kept/skipped stages, and verification before implementation. Write team-roster.json; team-gate.json needs team_roster_confirmed=true. executor:N means N native analysis agents, N debate voices, then fresh N executors. ${MIN_TEAM_REVIEW_POLICY_TEXT} After consensus, compile team-graph.json, team-runtime-tasks.json, team-decomposition-report.json, and team-inbox/ so worker handoff uses concrete runtime task ids with role/path/domain/lane hints. Refresh/validate TriWiki before debate, implementation, review, and final; consume attention.use_first and hydrate attention.hydrate_first before risky decisions. ${outcomeRubricPolicyText()} ${speedLanePolicyText()} ${solutionScoutPolicyText('fix this broken behavior')} ${skillDreamPolicyText()} Log events and use sks team message for bounded inter-agent communication in transcript/lane panes. Color-coded Zellij lanes distinguish overview/native-analysis/planning/execution/review/safety sessions in one Zellij window using split panes when Zellij is available. $Team/$team plus sks --mad uses the MAD-SKS permission gate module: user-authorized target-project scopes such as files, shell, packages, services, network, browser/Computer Use, generated assets, file permissions, migrations, normal DB writes, Supabase MCP writes, direct SQL, and schema cleanup are open only for the active invocation; catastrophic wipe/all-row/project-management, credential exfiltration, persistent security weakening, and unrequested fallback guards remain. End with cleanup-zellij or a cleanup event so follow panes show cleanup and stop; pass team-session-cleanup.json, then reflection and Honest Mode. Parent integrates/verifies.\n\n${chatCaptureIntakeText()}\n`,
1046
+ 'team': `---\nname: team\ndescription: SKS Team orchestration for $Team/code work; $From-Chat-IMG is the explicit chat-image alias.\n---\n\nUse for $Team/code work. Auto-seal the route contract from prompt, TriWiki/current-code defaults, and conservative policy; do not surface a prequestion sheet. Read pipeline-plan.json or run sks pipeline plan to see the runtime lane, kept/skipped stages, and verification before implementation. Write team-roster.json; team-gate.json needs team_roster_confirmed=true. executor:N means N native analysis agents, N debate voices, then fresh N executors. ${MIN_TEAM_REVIEW_POLICY_TEXT} After consensus, compile team-graph.json, team-runtime-tasks.json, team-decomposition-report.json, and team-inbox/ so worker handoff uses concrete runtime task ids with role/path/domain/lane hints. Refresh/validate TriWiki before debate, implementation, review, and final; consume attention.use_first and hydrate attention.hydrate_first before risky decisions. ${leanEngineeringCompactText()} ${outcomeRubricPolicyText()} ${speedLanePolicyText()} ${solutionScoutPolicyText('fix this broken behavior')} ${skillDreamPolicyText()} Log events and use sks team message for bounded inter-agent communication in transcript/lane panes. Color-coded Zellij lanes distinguish overview/native-analysis/planning/execution/review/safety sessions in one Zellij window using split panes when Zellij is available. $Team/$team plus sks --mad uses the MAD-SKS permission gate module: user-authorized target-project scopes such as files, shell, packages, services, network, browser/Computer Use, generated assets, file permissions, migrations, normal DB writes, Supabase MCP writes, direct SQL, and schema cleanup are open only for the active invocation; catastrophic wipe/all-row/project-management, credential exfiltration, persistent security weakening, and unrequested fallback guards remain. End with cleanup-zellij or a cleanup event so follow panes show cleanup and stop; pass team-session-cleanup.json, then reflection and Honest Mode. Parent integrates/verifies.\n\n${chatCaptureIntakeText()}\n`,
1047
1047
  'from-chat-img': `---\nname: from-chat-img\ndescription: Explicit $From-Chat-IMG Team alias for chat screenshot plus attachment analysis.\n---\n\nUse only for From-Chat-IMG/$From-Chat-IMG. It enters the normal Team pipeline. Treat uploads as chat screenshot plus originals. For web/browser/webapp targets use Codex Chrome Extension first; for native Mac/non-web app surfaces use Codex Computer Use visual inspection when available. List requirements first, match regions to attachments with confidence, write ${FROM_CHAT_IMG_COVERAGE_ARTIFACT}, ${FROM_CHAT_IMG_CHECKLIST_ARTIFACT}, ${FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT}, and ${FROM_CHAT_IMG_QA_LOOP_ARTIFACT}, then continue Team gates, review, reflection, and Honest Mode. ${CODEX_WEB_VERIFICATION_POLICY} ${CODEX_COMPUTER_USE_ONLY_POLICY} The ledger must account for every visible customer request, screenshot image region, and separate attachment; ${FROM_CHAT_IMG_CHECKLIST_ARTIFACT} must have a checked item for each request, image-region/attachment match, work item, scoped QA-LOOP, and verification step; ${FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT} stores temporary TriWiki-backed session context with expires_after_sessions=${FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS}. ${FROM_CHAT_IMG_QA_LOOP_ARTIFACT} must prove QA-LOOP ran over the exact customer-request work-order range after implementation, with every work item covered, post-fix verification complete, and zero unresolved findings. team-gate.json cannot pass From-Chat-IMG completion until unresolved_items is empty, every checklist box is checked, and scoped_qa_loop_completed=true.\n`,
1048
1048
  'naruto': `---\nname: naruto\ndescription: $Naruto Shadow Clone Swarm (影分身 / Kage Bunshin no Jutsu) fans out up to 100 parallel clone sessions on the native agent kernel for high-throughput work.\n---\n\nUse when the user invokes $Naruto, $ShadowClone, or $Kagebunshin, or asks to fan out many parallel agent clones for high-throughput sweeps. Naruto runs on the native agent kernel and layers on the Team route: it loads the team, pipeline-runner, prompt-pipeline, and honest-mode skills. Prefer \`sks naruto run "<task>" [--clones N] [--backend codex-exec|fake] [--work-items N] [--real] [--readonly] [--json]\` and \`sks naruto status [--mission <id>] [--json]\`. Clones default to the native kernel and are throttled to host capacity (cores/free memory); the requested clone count is the ceiling, not a guarantee, and the scheduler backfills slots as clones complete. Shadow clones always run in fast service tier; \`--no-fast\`/standard requests are not honored for clones. Writes are lease-based and non-overlapping: each clone takes a path lease before writing so parallel clones never edit the same file, and every clone emits its own proof. Keep agent-central-ledger.json, agent-task-board.json, agent-effort-policy.json, agent-scheduler-state.json, agent-proof-evidence.json, and agent-session-cleanup.json; the parent session owns integration, verification, and final claims. Use \`--backend fake\` only for fixtures/selftests; remove it when real clone evidence is intended. Lifecycle: clone roster build, work partition, parallel clone scheduling, lease-based write swarm, per-clone proof, session cleanup, then reflection and Honest Mode. Refresh/validate TriWiki before risky decisions and consume attention.use_first/hydrate_first. Catastrophic safeguards remain active for every clone. Finish with a concise completion summary and Honest Mode covering verified clones, unverified work, and any blockers.\n`,
1049
1049
  'shadow-clone': `---\nname: shadow-clone\ndescription: $ShadowClone alias for the $Naruto Shadow Clone Swarm high-scale parallel agent route.\n---\n\nUse the same rules as the naruto skill: this is the English alias for $Naruto / Kage Bunshin no Jutsu. Fan out up to 100 lease-safe parallel clone sessions on the native agent kernel via \`sks naruto run "<task>" [--clones N] [--backend codex-exec|fake] [--work-items N] [--json]\`. Clones run in fast service tier, are throttled to host capacity, take path leases for non-overlapping writes, and each emit per-clone proof; the parent integrates and verifies. Keep the same agent ledgers and finish with reflection and Honest Mode.\n`,
@@ -1057,18 +1057,20 @@ export async function installSkills(root) {
1057
1057
  'commit': `---\nname: commit\ndescription: Simple git-only route for $Commit requests that stage current changes and create one commit without the full SKS pipeline.\n---\n\nUse only when the user invokes $Commit or explicitly asks to commit the current repository changes without pushing. Keep this route lightweight: inspect git status and the relevant diff summary, avoid Team/pipeline/TriWiki route work unless separately requested, stage the intended current changes, and create one git commit. The commit message must summarize the actual work and include exactly one trailer: Co-authored-by: Codex <noreply@openai.com>. Do not push. If there are no changes, report that no commit was created. Finish with a concise result and a one-line Honest Mode covering the commit hash and any unverified items.\n`,
1058
1058
  'commit-and-push': `---\nname: commit-and-push\ndescription: Simple git-only route for $Commit-And-Push requests that stage current changes, create one commit, and push without the full SKS pipeline.\n---\n\nUse only when the user invokes $Commit-And-Push or explicitly asks to commit and push the current repository changes. Keep this route lightweight: inspect git status and the relevant diff summary, avoid Team/pipeline/TriWiki route work unless separately requested, stage the intended current changes, create one git commit, then push the current branch. The commit message must summarize the actual work and include exactly one trailer: Co-authored-by: Codex <noreply@openai.com>. If there are no changes, do not create an empty commit unless the user explicitly asks for one. Finish with a concise result and a one-line Honest Mode covering the commit hash, pushed branch, and any unverified items.\n`,
1059
1059
  '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. Research is not an implementation route: do not edit repository source, docs, package metadata, generated skills, or harness files; write only route-local mission artifacts under .sneakoscope/missions/<mission-id>/. Run the genius-lens agent council with named persona-inspired cognitive roles: Einstein Agent, Feynman Agent, Turing Agent, von Neumann Agent, and Skeptic Agent. These are lenses only; do not impersonate the historical people. Every Research agent ledger row must include display_name, persona, persona_boundary, effort=xhigh, reasoning_effort=xhigh, service_tier when available, one literal "Eureka!" idea, falsifiers, cheap_probes, and challenge_or_response before synthesis. This is not a fixed three-cycle route: repeat source gathering, Eureka ideas, evidence-bound debate, falsification, and synthesis pressure until every agent records final agreement, or until the explicit max-cycle safety cap pauses with an unpassed gate. Create research-source-skill.md as a route-local Skill Creator artifact, then maximize layered public web/source search across latest papers, official/government or leading-institution data, standards/primary docs, current news, public discourse, developer/practitioner sources, traditional background sources, and counterevidence before synthesis. Record research-source-skill.md, source-ledger.json, agent-ledger.json, debate-ledger.json, novelty-ledger.json, falsification-ledger.json, research-report.md, research-paper.md, genius-opinion-summary.md, and research-gate.json. debate-ledger.json must include consensus_iterations, unanimous_consensus, and per-agent agreements; research-gate.json cannot pass until unanimous_consensus=true with every agent agreement recorded. Context7 is optional and only needed when the research topic depends on external package/API/framework docs; do not use it as the default research evidence layer. Normal Research may take one or two hours when needed; favor real source collection, cross-layer comparison, falsification, and a concise paper manuscript over speed. Do not use --mock except for selftests or dry harness checks; if live source execution is unavailable, record a blocker and keep the gate unpassed. Do not use for ordinary code edits.\n`,
1060
- '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`,
1060
+ 'autoresearch': `---\nname: autoresearch\ndescription: Dollar-command route for $AutoResearch or $autoresearch iterative experiment loops.\n---\n\nUse for $AutoResearch, iterative improvement, ranking, workflow, benchmark, or experiments. Define program, hypothesis, experiment, metric, keep/discard, falsification, next step, and Honest Mode. Do not become the parent identity for SEO/GEO; $SEO-GEO-OPTIMIZER may call research as a child stage for query, market, or competitor discovery while keeping the parent mission, gate, and Completion Proof on $SEO-GEO-OPTIMIZER.\n`,
1061
1061
  '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`,
1062
1062
  'mad-db': `${madDbSkillText()}\n`,
1063
1063
  'mad-sks': `---\nname: mad-sks\ndescription: Explicit high-risk authorization modifier for $MAD-SKS scoped permission widening across approved target-project surfaces.\n---\n\nUse only when the user explicitly invokes $MAD-SKS or top-level sks --mad. 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 permission applies only while the active mission gate is open, must be deactivated when the task ends, and can open approved scopes such as target-project file writes, shell commands, package installs, local service control, network operations, browser/Computer Use workflows, generated assets, file permissions, migrations, Supabase MCP database writes, column/schema cleanup, direct execute SQL, and normal targeted DB writes. Keep catastrophic safeguards active: whole database/schema/table removal, truncate, all-row delete/update, reset, dangerous project/branch management, credential exfiltration, persistent security weakening, destructive delete without explicit confirmation, and unrequested fallback implementation remain blocked. Do not carry MAD-SKS permission into later prompts or routes. The permission profile source is centralized in src/core/permission-gates.ts and emitted as dist/core/permission-gates.js so skill/hook/MCP-style gates share one decision function.\n`,
1064
1064
  '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`,
1065
1065
  '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`,
1066
- '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 Direct Fix work: tiny copy/config/docs/labels/spacing/translation/simple mechanical edits; code and broad implementation default to Team unless safety/research/GX route fits. Infer goal, target, constraints, acceptance, risk, and smallest safe route from prompt, TriWiki/current-code defaults, and conservative SKS policy. Do not surface a prequestion sheet. Materialize pipeline-plan.json for the runtime lane, kept/skipped stages, no-fallback invariant, and verification; inspect with sks pipeline plan, adding --proof-field when changed files are known. 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. ${outcomeRubricPolicyText()} ${speedLanePolicyText()} ${solutionScoutPolicyText('fix this broken behavior')} ${skillDreamPolicyText()}\n\n${chatCaptureIntakeText()}\n\nDesign: non-PPT UI/UX uses Product Design plugin first; legacy design.md/design-system-builder/design-ui-editor/design-artifact-expert/getdesign-reference are fallback only when the plugin is unavailable or an existing project design.md must be respected. Use imagegen for image/logo/raster, and imagegen must prefer Codex App built-in image generation (${CODEX_APP_IMAGE_GENERATION_DOC_URL}) before API generation. ${productDesignPluginPolicyText()} ${CODEX_IMAGEGEN_REQUIRED_POLICY} For UI/UX review/audit requests that mention image generation, gpt-image-2, callouts, or annotated review images, route to $Image-UX-Review/$UX-Review and require generated annotated review image evidence before issue extraction; do not satisfy that route with text-only critique. For $PPT, ${pptPipelineAllowlistPolicyText()} ${getdesignReferencePolicyText()} 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`,
1066
+ '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 Direct Fix work: tiny copy/config/docs/labels/spacing/translation/simple mechanical edits; code and broad implementation default to Team unless safety/research/GX route fits. Infer goal, target, constraints, acceptance, risk, and smallest safe route from prompt, TriWiki/current-code defaults, and conservative SKS policy. Do not surface a prequestion sheet. Materialize pipeline-plan.json for the runtime lane, kept/skipped stages, no-fallback invariant, lean_decision, and verification; inspect with sks pipeline plan, adding --proof-field when changed files are known. 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. ${leanEngineeringCompactText()} ${outcomeRubricPolicyText()} ${speedLanePolicyText()} ${solutionScoutPolicyText('fix this broken behavior')} ${skillDreamPolicyText()}\n\n${chatCaptureIntakeText()}\n\nDesign: non-PPT UI/UX uses Product Design plugin first; legacy design.md/design-system-builder/design-ui-editor/design-artifact-expert/getdesign-reference are fallback only when the plugin is unavailable or an existing project design.md must be respected. Use imagegen for image/logo/raster, and imagegen must prefer Codex App built-in image generation (${CODEX_APP_IMAGE_GENERATION_DOC_URL}) before API generation. ${productDesignPluginPolicyText()} ${CODEX_IMAGEGEN_REQUIRED_POLICY} For UI/UX review/audit requests that mention image generation, gpt-image-2, callouts, or annotated review images, route to $Image-UX-Review/$UX-Review and require generated annotated review image evidence before issue extraction; do not satisfy that route with text-only critique. For $PPT, ${pptPipelineAllowlistPolicyText()} ${getdesignReferencePolicyText()} 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`,
1067
1067
  [SOLUTION_SCOUT_SKILL_NAME]: `---\nname: ${SOLUTION_SCOUT_SKILL_NAME}\ndescription: Web-similarity scout hook for SKS problem-solving and repair requests.\n---\n\n${solutionScoutPolicyText('fix this broken behavior')}\n\nUse this as a pipeline hook, not as a standalone route: when a user asks to solve, fix, repair, troubleshoot, or investigate broken behavior, search first for similar resolution cases, summarize the useful patterns with sources, then combine them with current repo evidence before editing. If browsing is unavailable, mark the external scout unverified and continue with local evidence only.\n`,
1068
1068
  'reasoning-router': `---\nname: reasoning-router\ndescription: Temporary SKS reasoning-effort routing for every command and pipeline route.\n---\n\nmedium: simple copy/color/discovery/setup/mechanical edits. high: logic, safety, architecture, DB, orchestration, refactor, multi-file work. xhigh: research, AutoResearch, falsification, benchmarks, SEO/GEO, open-ended discovery, and From-Chat-IMG image work-order analysis. Routing is temporary; return to default after the gate. Inspect with sks reasoning and sks pipeline status.\n`,
1069
- 'pipeline-runner': `---\nname: pipeline-runner\ndescription: Execute SKS dollar-command routes as stateful pipelines with mission artifacts, route gates, Context7 evidence, temporary reasoning routing, reflection, and Honest Mode.\n---\n\nEvery $ command is a route. Use current.json, mission artifacts, and pipeline-plan.json as the execution plan: it records the lane, skipped stages, kept stages, verification, and no-unrequested-fallback invariant. Use temporary reasoning, TriWiki before stages, source hydration, Context7 when required, Team cleanup before reflection, reflection for full routes, and completion summary plus Honest Mode before final. Surface guard/scopes, record evidence, refresh/pack/validate TriWiki, and check sks pipeline status/resume/plan. ${speedLanePolicyText()} ${skillDreamPolicyText()}\n`,
1069
+ 'pipeline-runner': `---\nname: pipeline-runner\ndescription: Execute SKS dollar-command routes as stateful pipelines with mission artifacts, route gates, Context7 evidence, temporary reasoning routing, reflection, and Honest Mode.\n---\n\nEvery $ command is a route. Use current.json, mission artifacts, and pipeline-plan.json as the execution plan: it records the lane, skipped stages, kept stages, verification, lean_decision, and no-unrequested-fallback invariant. Use temporary reasoning, TriWiki before stages, source hydration, Context7 when required, Team cleanup before reflection, reflection for full routes, and completion summary plus Honest Mode before final. Surface guard/scopes, record evidence, refresh/pack/validate TriWiki, and check sks pipeline status/resume/plan. ${leanEngineeringCompactText()} ${speedLanePolicyText()} ${skillDreamPolicyText()}\n`,
1070
1070
  'context7-docs': `---\nname: context7-docs\ndescription: Enforce Context7 MCP documentation evidence for SKS routes that depend on external libraries, frameworks, APIs, MCPs, package managers, DB SDKs, or generated docs.\n---\n\nWhen required, resolve-library-id, then query-docs for the resolved id. Legacy get-library-docs evidence is accepted. Prefer sks context7 tools/resolve/docs/evidence and finish only after both evidence stages exist. Check setup with sks context7 check.\n`,
1071
- 'seo-geo-optimizer': `---\nname: seo-geo-optimizer\ndescription: SEO/GEO support for README, npm, GitHub, keywords, snippets, schema, and AI-search visibility.\n---\n\nUse for SEO/GEO, package metadata, README ranking, snippets, schema, and AI search. Optimize README, package.json, docs, badges, topics, quickstart, examples, command discovery, exact names, keywords, and AI Answer Snapshot. Do not invent metrics; use $AutoResearch unless it is a tiny copy edit.\n`,
1071
+ 'ultra-search': `---\nname: ultra-search\ndescription: Dollar-command route for $Ultra-Search/$UltraSearch provider-independent source intelligence.\n---\n\nUse when the user invokes $Ultra-Search, $UltraSearch, or asks for UltraSearch source intelligence, source acquisition, X-search-style collection, URL acquisition, source normalization, claim ledgers, or citation proof. Prefer \`sks ultra-search doctor --json\` for readiness and \`sks ultra-search run "<query>" --mode balanced --json\` for provider-independent source proof; use \`sks ultra-search x "<query>" --json\` for X-search intent and \`sks ultra-search fetch "<url>" --json\` for URL acquisition. Context7 is required only when the query depends on current package/API/framework/MCP/generated documentation behavior. xAI/Grok credentials are optional and must not be required for route readiness. Evidence/artifacts live under \`.sneakoscope/missions/<ultra-* or route mission>/ultra-search/\`: intent.json, axes.json, query-variants.json, provider-plan.json, source-ledger.json, lead-ledger.json, claim-ledger.json, synthesis.md, ultra-search-proof.json, ultra-search-gate.json, and ultra-search-result.json. Do not turn weak discovery into supported claims; finish with an Honest Mode summary of verified sources, blockers, and unverified external coverage.\n`,
1072
+ 'search-visibility-core': `---\nname: search-visibility-core\ndescription: Shared kernel for seo-geo-optimizer audit, plan, explicit apply, rollback, verification, gates, and Completion Proof.\n---\n\nPurpose: keep Search Engine Optimization and Generative Engine Optimization on one typed search-visibility kernel instead of duplicate implementations. Use when $SEO-GEO-OPTIMIZER or \`sks seo-geo-optimizer\` is selected. Workflow: doctor detects package/static/Next evidence; audit writes source-backed inventory and findings; plan compiles safe mutation operations; apply requires explicit \`--apply\`; verify separates source, build, HTTP, browser, production, and measured outcome; rollback only reverses mission-owned operations. Safety: default read-only, never overwrite unmanaged robots.txt, sitemap, llms.txt, metadata, or structured data; do not hard-code customer routes; do not invent prices, reviews, availability, rankings, traffic, or AI citation outcomes. Evidence/artifacts: search-visibility/intake.json, adapter-detection.json, site-inventory.json, route-graph.json, robots-policy.json, structured-data-ledger.json, mutation-plan.json, mutation-journal.jsonl, rollback-manifest.json, verification-report.json, route gate, and completion-proof.json. Failure/recovery: unsupported frameworks stay audit/plan-only; missing production/browser/Search Console evidence remains unverified, not fabricated. CLI entrypoint: \`sks seo-geo-optimizer ... --mode seo|geo\`.\n`,
1073
+ 'seo-geo-optimizer': `---\nname: seo-geo-optimizer\ndescription: Unified $SEO-GEO-OPTIMIZER route for Search Engine Optimization and Generative Engine Optimization.\n---\n\nPurpose: use one route name for SEO and GEO work while keeping the internal search-visibility mode explicit. Use when: the user asks for SEO audit/fix/verification, package/npm/GitHub search visibility, canonical, sitemap, robots.txt, hreflang, metadata, structured data, AI answer visibility, LLM citation readiness, answerability, entity/claim provenance, crawler policy, OAI-SearchBot/GPTBot/ChatGPT-User, Claude-SearchBot/ClaudeBot/Claude-User, or optional llms.txt planning. GEO means Generative Engine Optimization, not geolocation, GeoIP, maps, CDN geography, location permission, or regional redirect bugs. Workflow: run \`sks seo-geo-optimizer doctor --mode seo|geo\`, then audit, plan, explicit apply, verify, status, and rollback. Use \`--mode seo\` for technical/package search optimization and \`--mode geo\` for entity facts, claim evidence, answerability, crawler policy, and optional llms.txt. Safety: audit and plan must not mutate source; apply checks base hashes, ownership, scope, protected paths, rollback manifest, and post-verify. AI crawler policy must split search, training, user-directed retrieval, and ads/other; never use one allow_ai toggle and never auto-allow training crawlers. Evidence/artifacts: site-inventory.json, route-graph.json, seo-findings.json or geo-findings.json, entity-facts.json, claim-evidence-ledger.json, answerability-report.json, ai-crawler-policy.json, llms-txt-plan.json, mutation-plan.json, verification-report.json, seo-gate.json or geo-gate.json, completion-proof.json. Failure/recovery: unsupported frameworks stay plan-only; browser/production/Search Console/analytics outcomes are marked unverified when not actually run. Forbidden claims: no ranking, indexing, traffic lift, rich-result, answer inclusion, or AI citation guarantee; no keyword stuffing, doorway pages, fake reviews, fake prices, fake availability, fake shipping, fake awards, hidden AI-only text, or scaled spam. CLI entrypoint: \`sks seo-geo-optimizer doctor|audit|plan|apply|verify|status|rollback|fixture --mode seo|geo\`.\n`,
1072
1074
  'reflection': `---\nname: reflection\ndescription: Post-route self-review for full SKS routes that records real misses, gaps, and corrective lessons into TriWiki memory.\n---\n\nUse after full route work/tests and before final. DFix, Answer, Help, Wiki, SKS discovery are exempt. Do not invent faults. Write reflection.md; append real lessons to ${REFLECTION_MEMORY_PATH}; refresh/pack, validate context-pack.json, pass reflection-gate.json.\n\n${reflectionInstructionText()}\n`,
1073
1075
  'honest-mode': `---\nname: honest-mode\ndescription: Required final SKS verification pass before claiming a task is complete.\n---\n\nBefore final: include a completion summary explaining what was done, what changed for the user/repo, what was verified, and what remains unverified or blocked. Then restate the goal, compare result to evidence, list tests/commands/inspections, state uncertainty or blockers plainly, and do not claim completion beyond evidence. Full routes must pass reflection-gate.json first. Include concise SKS Honest Mode or 솔직모드 when required.\n`,
1074
1076
  'autoresearch-loop': `---\nname: autoresearch-loop\ndescription: Iterative AutoResearch-style loop for open-ended improvement, discovery, prompt, ranking, SEO/GEO, and workflow-quality tasks.\n---\n\nUse for research, ranking, prompt/workflow improvement, benchmark gains, or repeated refinement. Loop: program, hypothesis, smallest falsifying experiment, metric, keep/discard, falsify, next step. Keep a ledger and do not claim improvement without evidence.\n`,
@@ -0,0 +1,159 @@
1
+ import { createHash } from 'node:crypto';
2
+ export const LEAN_ENGINEERING_POLICY_ID = 'sks.lean-engineering-policy.v1';
3
+ export const LEAN_DECISION_SCHEMA = 'sks.lean-decision.v1';
4
+ export const LEAN_CHANGE_EVIDENCE_SCHEMA = 'sks.lean-change-evidence.v1';
5
+ export const LEAN_SOLUTION_RUNGS = Object.freeze([
6
+ 'skip',
7
+ 'reuse-existing',
8
+ 'stdlib',
9
+ 'native-platform',
10
+ 'installed-dependency',
11
+ 'single-expression',
12
+ 'minimal-custom'
13
+ ]);
14
+ const LEAN_ENGINEERING_POLICY_CANONICAL = [
15
+ 'Understand the real flow before changing code.',
16
+ 'Stop at the highest sufficient rung: skip, reuse existing code, stdlib, native platform, installed dependency, safe single expression, minimal custom code.',
17
+ 'Do not add unrequested routes, commands, daemons, dependencies, abstractions, config flags, shims, or hidden fallbacks.',
18
+ 'Fix shared root causes instead of duplicating caller-specific symptom guards.',
19
+ 'Capability and compatibility fallbacks require one authority, proof, bounded scope, and honest verification level.',
20
+ 'Never remove trust-boundary validation, data-loss protection, security, permissions, rollback, accessibility, or explicit user requirements to shrink a diff.',
21
+ 'Non-trivial logic needs one smallest runnable check.'
22
+ ].join('\n');
23
+ export const LEAN_ENGINEERING_POLICY_HASH = createHash('sha256')
24
+ .update(LEAN_ENGINEERING_POLICY_CANONICAL)
25
+ .digest('hex')
26
+ .slice(0, 16);
27
+ export function leanPolicyReference() {
28
+ return {
29
+ policy_id: LEAN_ENGINEERING_POLICY_ID,
30
+ policy_hash: LEAN_ENGINEERING_POLICY_HASH
31
+ };
32
+ }
33
+ export function leanEngineeringCompactText() {
34
+ return [
35
+ `Lean Engineering Policy (${LEAN_ENGINEERING_POLICY_ID}/${LEAN_ENGINEERING_POLICY_HASH}):`,
36
+ 'Read the touched flow first, then stop at the highest sufficient rung: skip, reuse existing, stdlib, native platform, installed dependency, safe single expression, minimal custom.',
37
+ 'No unrequested route/command/daemon/dependency/abstraction/config flag/shim/hidden fallback; required capability/compatibility fallback needs one authority, proof, and bounded scope.',
38
+ 'Fix root cause once, preserve trust-boundary validation/security/rollback/accessibility/user requirements, and leave one runnable check for non-trivial logic.'
39
+ ].join('\n');
40
+ }
41
+ export function leanEngineeringLongText() {
42
+ return [
43
+ leanEngineeringCompactText(),
44
+ 'Forbidden fallback: silent mock/fixture success, provider contract switching without authority, catch-all empty success, unused future shims, duplicate legacy/new SSOTs, or production proof from test fakes.',
45
+ 'Allowed fallback: same contract or explicit narrower contract, capability detection, one selection authority, recorded provider/proof level, honest downgrade when used, and a bounded chain.',
46
+ 'Compatibility bridge: one canonical implementation; legacy entry only converts arguments, emits deprecation context, and has a sunset trigger.',
47
+ 'Intentional simplification marker: `sks-lean: ceiling=<known limit>; revisit_when=<measurable trigger>; upgrade=<specific path>`.'
48
+ ].join('\n');
49
+ }
50
+ export function normalizeLeanDecision(input = {}, defaults = {}) {
51
+ const value = record(input);
52
+ const defaultFallback = defaults.fallback_plan || { kind: 'none', authority: null, justification: null };
53
+ return {
54
+ schema: LEAN_DECISION_SCHEMA,
55
+ policy_id: LEAN_ENGINEERING_POLICY_ID,
56
+ policy_hash: LEAN_ENGINEERING_POLICY_HASH,
57
+ selected_rung: normalizeRung(value.selected_rung, defaults.selected_rung || 'minimal-custom'),
58
+ task_requires_change: booleanValue(value.task_requires_change, defaults.task_requires_change ?? true),
59
+ root_cause_target: nullableString(value.root_cause_target, defaults.root_cause_target ?? null),
60
+ reused_paths: stringArray(value.reused_paths, defaults.reused_paths),
61
+ stdlib_or_native_choice: nullableString(value.stdlib_or_native_choice, defaults.stdlib_or_native_choice ?? null),
62
+ new_dependency_requested: booleanValue(value.new_dependency_requested, defaults.new_dependency_requested ?? false),
63
+ new_dependency_justification: nullableString(value.new_dependency_justification, defaults.new_dependency_justification ?? null),
64
+ new_abstraction_requested: booleanValue(value.new_abstraction_requested, defaults.new_abstraction_requested ?? false),
65
+ new_abstraction_justification: nullableString(value.new_abstraction_justification, defaults.new_abstraction_justification ?? null),
66
+ fallback_plan: normalizeFallbackPlan(value.fallback_plan, defaultFallback),
67
+ expected_changed_paths: stringArray(value.expected_changed_paths, defaults.expected_changed_paths),
68
+ verification_minimum: stringArray(value.verification_minimum, defaults.verification_minimum)
69
+ };
70
+ }
71
+ export function validateLeanDecision(input) {
72
+ const value = record(input);
73
+ const issues = [];
74
+ if (value.schema !== LEAN_DECISION_SCHEMA)
75
+ issues.push('schema');
76
+ if (value.policy_id !== LEAN_ENGINEERING_POLICY_ID)
77
+ issues.push('policy_id');
78
+ if (value.policy_hash !== LEAN_ENGINEERING_POLICY_HASH)
79
+ issues.push('policy_hash');
80
+ if (!isLeanSolutionRung(value.selected_rung))
81
+ issues.push('selected_rung');
82
+ if (typeof value.task_requires_change !== 'boolean')
83
+ issues.push('task_requires_change');
84
+ if (!Array.isArray(value.reused_paths))
85
+ issues.push('reused_paths');
86
+ if (!Array.isArray(value.expected_changed_paths))
87
+ issues.push('expected_changed_paths');
88
+ if (!Array.isArray(value.verification_minimum))
89
+ issues.push('verification_minimum');
90
+ const fallback = record(value.fallback_plan);
91
+ if (!isFallbackKind(fallback.kind))
92
+ issues.push('fallback_plan.kind');
93
+ if (fallback.kind !== 'none' && (!fallback.authority || !fallback.justification))
94
+ issues.push('fallback_plan.evidence');
95
+ if (value.new_dependency_requested === true && !value.new_dependency_justification)
96
+ issues.push('new_dependency_justification');
97
+ if (value.new_abstraction_requested === true && !value.new_abstraction_justification)
98
+ issues.push('new_abstraction_justification');
99
+ if (value.selected_rung === 'skip' && value.task_requires_change === true)
100
+ issues.push('skip_requires_no_change');
101
+ if (value.task_requires_change === true && !value.verification_minimum?.length)
102
+ issues.push('verification_minimum_required');
103
+ return { ok: issues.length === 0, issues };
104
+ }
105
+ export function parseLeanSimplificationMarkerLine(text, file = '', line = 0) {
106
+ const match = /^\s*(?:(?:\/\/|#)\s*)sks-lean:\s*(.+)$/i.exec(text);
107
+ if (!match)
108
+ return null;
109
+ const fields = Object.fromEntries((match[1] || '').split(';').map((part) => {
110
+ const [key, ...rest] = part.split('=');
111
+ return [String(key || '').trim(), rest.join('=').trim()];
112
+ }));
113
+ const ceiling = fields.ceiling || null;
114
+ const revisit = fields.revisit_when || null;
115
+ const upgrade = fields.upgrade || null;
116
+ return {
117
+ file,
118
+ line,
119
+ ceiling,
120
+ revisit_when: revisit,
121
+ upgrade,
122
+ status: !revisit ? 'missing-trigger' : !upgrade ? 'missing-upgrade' : 'complete'
123
+ };
124
+ }
125
+ function normalizeFallbackPlan(input, defaults) {
126
+ const value = record(input);
127
+ const kind = isFallbackKind(value.kind) ? value.kind : defaults.kind;
128
+ return {
129
+ kind,
130
+ authority: nullableString(value.authority, defaults.authority),
131
+ justification: nullableString(value.justification, defaults.justification)
132
+ };
133
+ }
134
+ function normalizeRung(value, fallback) {
135
+ return isLeanSolutionRung(value) ? value : fallback;
136
+ }
137
+ function isLeanSolutionRung(value) {
138
+ return typeof value === 'string' && LEAN_SOLUTION_RUNGS.includes(value);
139
+ }
140
+ function isFallbackKind(value) {
141
+ return value === 'none' || value === 'capability' || value === 'compatibility' || value === 'fail-closed';
142
+ }
143
+ function stringArray(value, fallback = []) {
144
+ const source = Array.isArray(value) ? value : Array.isArray(fallback) ? fallback : [];
145
+ return source.map((item) => String(item || '').trim()).filter(Boolean);
146
+ }
147
+ function nullableString(value, fallback = null) {
148
+ const text = String(value ?? '').trim();
149
+ if (text)
150
+ return text;
151
+ return fallback;
152
+ }
153
+ function booleanValue(value, fallback) {
154
+ return typeof value === 'boolean' ? value : fallback;
155
+ }
156
+ function record(value) {
157
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
158
+ }
159
+ //# sourceMappingURL=lean-engineering-policy.js.map
@@ -1,8 +1,26 @@
1
1
  import { isMadDbCapabilityActive, readMadDbCapability } from './mad-db-capability.js';
2
2
  import { activeMadDbAllowsSqlPlane, isMadDbControlPlaneDeniedTool, madDbOperationClassesFromClassification } from './mad-db-policy.js';
3
- import { sha256 } from '../fsx.js';
3
+ import { readJson, sha256 } from '../fsx.js';
4
+ import { stateFile } from '../mission.js';
4
5
  export const MAD_DB_POLICY_DECISION_SCHEMA = 'sks.mad-db-policy-decision.v2';
5
6
  export async function resolveMadDbMutationPolicy(root, state = {}, classification = {}, explicitCapability) {
7
+ const primary = await resolveMadDbMutationPolicyForState(root, state, classification, explicitCapability);
8
+ if (primary.allowed === true || explicitCapability)
9
+ return primary;
10
+ const persistedState = await readJson(stateFile(root), null).catch(() => null);
11
+ if (persistedState && persistedState !== state) {
12
+ const fallback = await resolveMadDbMutationPolicyForState(root, persistedState, classification, null);
13
+ if (fallback.allowed === true) {
14
+ return {
15
+ ...fallback,
16
+ state_source: 'persisted_sks_state',
17
+ reasons: [...fallback.reasons, 'mad_db_persisted_state_binding_used']
18
+ };
19
+ }
20
+ }
21
+ return primary;
22
+ }
23
+ async function resolveMadDbMutationPolicyForState(root, state = {}, classification = {}, explicitCapability) {
6
24
  const missionId = explicitCapability?.mission_id || state?.mad_db_capability_mission_id || state?.mission_id;
7
25
  if (!missionId)
8
26
  return inactive('mission_id_missing');
@@ -39,7 +57,10 @@ export function validateCapabilityBinding(capability, state = {}, classification
39
57
  return { ok: false, reason: `mad_db_capability_${capability.status || 'inactive'}` };
40
58
  if (!capability.project_ref)
41
59
  return { ok: false, reason: 'mad_db_project_ref_missing' };
42
- if (state?.mission_id && String(state.mission_id) !== capability.mission_id)
60
+ const boundMadDbMissionId = state?.mad_db_capability_mission_id ? String(state.mad_db_capability_mission_id) : null;
61
+ if (boundMadDbMissionId === capability.mission_id && state?.mad_db_active === false)
62
+ return { ok: false, reason: 'mad_db_state_inactive' };
63
+ if (state?.mission_id && String(state.mission_id) !== capability.mission_id && boundMadDbMissionId !== capability.mission_id)
43
64
  return { ok: false, reason: 'mad_db_mission_binding_mismatch' };
44
65
  if (state?.mad_db_cycle_id && String(state.mad_db_cycle_id) !== capability.cycle_id)
45
66
  return { ok: false, reason: 'mad_db_cycle_binding_mismatch' };
@@ -26,7 +26,8 @@ import { prepareMadDbMission } from '../mad-db/mad-db-coordinator.js';
26
26
  import { AGENT_INTAKE_STAGE_ID, AGENT_COUNT } from '../agents/agent-schema.js';
27
27
  import { normalizeAgentPolicy, routeRequiresAgentIntake, agentPipelineStage } from '../agents/agent-plan.js';
28
28
  import { readAgentGateStatus } from '../agents/agent-gate.js';
29
- import { CODEX_APP_IMAGE_GENERATION_DOC_URL, CODEX_COMPUTER_USE_EVIDENCE_SOURCE, CODEX_COMPUTER_USE_ONLY_POLICY, CODEX_IMAGEGEN_REQUIRED_POLICY, CODEX_WEB_VERIFICATION_POLICY, 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, SOLUTION_SCOUT_STAGE_ID, chatCaptureIntakeText, context7RequirementText, dollarCommand, evidenceMentionsForbiddenBrowserAutomation, getdesignReferencePolicyText, hasFromChatImgSignal, hasMadSksSignal, imageUxReviewPipelinePolicyText, looksLikeProblemSolvingRequest, noUnrequestedFallbackCodePolicyText, outcomeRubricPolicyText, pptPipelineAllowlistPolicyText, reflectionRequiredForRoute, reasoningInstruction, routeNeedsContext7, routePrompt, routeReasoning, routeRequiresSubagents, solutionScoutPolicyText, speedLanePolicyText, stripDollarCommand, stripMadSksSignal, stripVisibleDecisionAnswerBlocks, subagentExecutionPolicyText, stackCurrentDocsPolicyText, triwikiContextTracking, triwikiContextTrackingText, triwikiStagePolicyText } from '../routes.js';
29
+ import { CODEX_APP_IMAGE_GENERATION_DOC_URL, CODEX_COMPUTER_USE_EVIDENCE_SOURCE, CODEX_COMPUTER_USE_ONLY_POLICY, CODEX_IMAGEGEN_REQUIRED_POLICY, CODEX_WEB_VERIFICATION_POLICY, 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, SOLUTION_SCOUT_STAGE_ID, chatCaptureIntakeText, context7RequirementText, dollarCommand, evidenceMentionsForbiddenBrowserAutomation, getdesignReferencePolicyText, hasFromChatImgSignal, hasMadSksSignal, imageUxReviewPipelinePolicyText, leanEngineeringCompactText, looksLikeProblemSolvingRequest, pptPipelineAllowlistPolicyText, reflectionRequiredForRoute, reasoningInstruction, routeNeedsContext7, routePrompt, routeReasoning, routeRequiresSubagents, solutionScoutPolicyText, stripDollarCommand, stripMadSksSignal, stripVisibleDecisionAnswerBlocks, subagentExecutionPolicyText, stackCurrentDocsPolicyText, triwikiContextTracking, triwikiContextTrackingText, triwikiStagePolicyText } from '../routes.js';
30
+ import { normalizeLeanDecision, validateLeanDecision } from '../lean-engineering-policy.js';
30
31
  import { TEAM_DECOMPOSITION_ARTIFACT, TEAM_GRAPH_ARTIFACT, TEAM_INBOX_DIR, TEAM_RUNTIME_TASKS_ARTIFACT, teamRuntimePlanMetadata, teamRuntimeRequiredArtifacts, validateTeamRuntimeArtifacts, writeTeamRuntimeArtifacts } from '../team-dag.js';
31
32
  import { formatAgentReasoning, formatRoleCounts, initTeamLive, parseTeamSpecText, teamReasoningPolicy } from '../team-live.js';
32
33
  import { evaluateTeamReviewPolicyGate, MIN_TEAM_REVIEWER_LANES, MIN_TEAM_REVIEW_POLICY_TEXT, teamReviewPolicy } from '../team-review-policy.js';
@@ -93,6 +94,13 @@ export function buildPipelinePlan(input = {}) {
93
94
  const skipped = stages.filter((stage) => stage.status === 'skipped').map((stage) => stage.id);
94
95
  const kept = stages.filter((stage) => stage.status !== 'skipped' && stage.status !== 'not_applicable').map((stage) => stage.id);
95
96
  const routeEconomy = routeEconomyPlan(proof);
97
+ const leanDecision = normalizeLeanDecision(input.leanDecision, {
98
+ selected_rung: ['Answer', 'Help', 'Wiki'].includes(route?.id) ? 'skip' : 'minimal-custom',
99
+ task_requires_change: !['Answer', 'Help', 'Wiki'].includes(route?.id),
100
+ root_cause_target: route?.id ? `${route.id} route selected implementation surface` : null,
101
+ expected_changed_paths: input.expectedChangedPaths || input.touchedFiles || [],
102
+ verification_minimum: verification.slice(0, 3).map((item) => String(item || '').trim()).filter(Boolean)
103
+ });
96
104
  return {
97
105
  schema_version: PIPELINE_PLAN_SCHEMA_VERSION,
98
106
  generated_at: nowIso(),
@@ -135,6 +143,7 @@ export function buildPipelinePlan(input = {}) {
135
143
  verification,
136
144
  invariants: ['no_unrequested_fallback_code', 'ssot_guard', 'listed_verification', 'triwiki_validate_before_final', 'honest_mode'],
137
145
  proof_field: proof,
146
+ lean_decision: leanDecision,
138
147
  ssot_guard: buildSsotGuard({ route: route?.id || 'SKS', mode: route?.mode || 'SKS', task }),
139
148
  route_economy: routeEconomy,
140
149
  agent_intake: agentPolicy,
@@ -193,6 +202,9 @@ export function validatePipelinePlan(plan = {}) {
193
202
  const routeEconomyLatticeIssues = validateRouteEconomyDecisionLattice(plan.route_economy, plan.proof_field);
194
203
  if (routeEconomyLatticeIssues.length)
195
204
  issues.push(...routeEconomyLatticeIssues.map((issue) => `route_economy.decision_lattice:${issue}`));
205
+ const leanDecision = validateLeanDecision(plan.lean_decision);
206
+ if (!leanDecision.ok)
207
+ issues.push(...leanDecision.issues.map((issue) => `lean_decision:${issue}`));
196
208
  if (plan.no_unrequested_fallback_code !== true || !plan.invariants?.includes('no_unrequested_fallback_code'))
197
209
  issues.push('fallback_guard');
198
210
  if (!plan.ssot_guard?.required || !plan.invariants?.includes('ssot_guard'))
@@ -427,10 +439,8 @@ export function promptPipelineContext(prompt, route = null) {
427
439
  'Stance: infer the user intent aggressively from rough wording, local context, TriWiki, and conservative defaults; do not surface prequestion sheets before work.',
428
440
  subagentExecutionPolicyText(route, cleanPrompt),
429
441
  solutionScoutPolicyText(cleanPrompt),
430
- noUnrequestedFallbackCodePolicyText(),
442
+ leanEngineeringCompactText(),
431
443
  ssotGuardPolicyText(),
432
- outcomeRubricPolicyText(),
433
- speedLanePolicyText(),
434
444
  skillDreamPolicyText(),
435
445
  route?.id === 'PPT'
436
446
  ? `${pptPipelineAllowlistPolicyText()} ${getdesignReferencePolicyText()}`
@@ -456,7 +466,7 @@ export function promptPipelineContext(prompt, route = null) {
456
466
  if (route?.id === 'ImageUXReview')
457
467
  lines.push(`Image UX Review route: ${imageUxReviewPipelinePolicyText()} Use ${IMAGE_UX_REVIEW_POLICY_ARTIFACT}, ${IMAGE_UX_REVIEW_SCREEN_INVENTORY_ARTIFACT}, ${IMAGE_UX_REVIEW_GENERATED_REVIEW_LEDGER_ARTIFACT}, ${IMAGE_UX_REVIEW_ISSUE_LEDGER_ARTIFACT}, ${IMAGE_UX_REVIEW_ITERATION_REPORT_ARTIFACT}, and ${IMAGE_UX_REVIEW_GATE_ARTIFACT} as the route evidence set. The route may suggest safe fixes only when the user requested fixing; otherwise report findings and blockers.`);
458
468
  if (route?.id === 'AutoResearch')
459
- lines.push('AutoResearch route: load autoresearch-loop plus seo-geo-optimizer when SEO/GEO, discoverability, README, npm, GitHub stars, ranking, or AI-search visibility is relevant.');
469
+ lines.push('AutoResearch route: load autoresearch-loop for experiments and benchmarking. SEO/GEO, discoverability, README, npm, GitHub search visibility, and AI-search visibility should use the first-class $SEO-GEO-OPTIMIZER parent route unless the selected route explicitly needs a child experiment.');
460
470
  if (route?.id === 'DB')
461
471
  lines.push('DB route: scan/check database risk first; destructive DB operations remain forbidden.');
462
472
  if (route?.id === 'MadDB')
@@ -13,7 +13,7 @@ const AGENT_ARTIFACTS = [
13
13
  'agents/agent-task-board.json',
14
14
  'agents/agent-concurrency-policy.json'
15
15
  ];
16
- export async function maybeFinalizeRoute(root, { missionId, route, gateFile = null, gate = null, artifacts = [], claims = [], visualEvidence = null, visual = false, fixClaim = false, requireRelation = false, mock = false, statusHint = null, reason = null, command = null, dbEvidence = null, testEvidence = null, blockers = [], unverified = [], agents = undefined, allowActiveWrongnessPartial = false, failureAnalysis = null } = {}) {
16
+ export async function maybeFinalizeRoute(root, { missionId, route, gateFile = null, gate = null, artifacts = [], claims = [], visualEvidence = null, visual = false, fixClaim = false, requireRelation = false, mock = false, statusHint = null, reason = null, command = null, dbEvidence = null, testEvidence = null, blockers = [], unverified = [], agents = undefined, allowActiveWrongnessPartial = false, failureAnalysis = null, lightweightEvidence = false } = {}) {
17
17
  if (!missionId || !route) {
18
18
  return { ok: false, skipped: true, reason: 'mission_id_or_route_missing' };
19
19
  }
@@ -62,7 +62,8 @@ export async function maybeFinalizeRoute(root, { missionId, route, gateFile = nu
62
62
  visualClaim: visual,
63
63
  agents,
64
64
  allowActiveWrongnessPartial,
65
- failureAnalysis
65
+ failureAnalysis,
66
+ lightweightEvidence
66
67
  });
67
68
  return { ...proof, auto_finalized: true, gate_passed: passed, status_hint: finalStatus };
68
69
  }
@@ -33,7 +33,8 @@ export function emptyCompletionProof(overrides = {}) {
33
33
  triwiki: null,
34
34
  wrongness: null,
35
35
  source_intelligence: null,
36
- goal_mode: null
36
+ goal_mode: null,
37
+ lean_engineering: null
37
38
  },
38
39
  claims: [],
39
40
  unverified: [],
@@ -74,6 +74,7 @@ export function renderProofMarkdown(proof = {}, validation = validateCompletionP
74
74
  `- Agents: ${proof.evidence?.agents?.agent_count ?? 0} (${proof.evidence?.agents?.status || 'not_recorded'})`,
75
75
  `- TriWiki: ${proof.evidence?.triwiki?.status || 'not_recorded'}`,
76
76
  `- Wrongness: ${proof.evidence?.wrongness?.active_count ?? 0} active (${proof.evidence?.wrongness?.high_severity_active ?? 0} high)`,
77
+ `- Lean engineering: ${proof.evidence?.lean_engineering?.semantic_review?.status || proof.evidence?.lean_engineering?.status || 'not_recorded'}`,
77
78
  `- Evidence router: ${proof.evidence?.evidence_router?.records ?? 0} record(s)`,
78
79
  `- Trust report: ${proof.evidence?.trust_report || 'not_recorded'}`,
79
80
  ''
@@ -5,8 +5,8 @@ import { normalizeProofRoute, routeRequiresImageVoxelAnchors } from './route-pro
5
5
  import { linkProofClaimsToEvidence, proofEvidenceSummary } from '../evidence/evidence-proof-linker.js';
6
6
  import { writeTrustArtifactsForProof } from '../trust-kernel/trust-report.js';
7
7
  import { enforceRetention } from '../retention.js';
8
- export async function writeRouteCompletionProof(root, { missionId = null, route = null, status = 'verified_partial', gate = null, summary = {}, artifacts = [], evidence = {}, claims = [], unverified = [], blockers = [], failureAnalysis = null, nextHumanActions = [] } = {}) {
9
- const collected = await collectProofEvidence(root);
8
+ export async function writeRouteCompletionProof(root, { missionId = null, route = null, status = 'verified_partial', gate = null, summary = {}, artifacts = [], evidence = {}, claims = [], unverified = [], blockers = [], failureAnalysis = null, nextHumanActions = [], lightweightEvidence = false } = {}) {
9
+ const collected = lightweightEvidence ? { files: [] } : await collectProofEvidence(root);
10
10
  const normalizedRoute = normalizeProofRoute(route);
11
11
  const mergedEvidence = {
12
12
  ...collected,
@@ -45,6 +45,8 @@ export async function writeRouteCompletionProof(root, { missionId = null, route
45
45
  status: normalizedStatus
46
46
  }
47
47
  });
48
+ if (lightweightEvidence)
49
+ return { ...written, trust: null, retention: null };
48
50
  if (!missionId)
49
51
  return written;
50
52
  const firstTrust = await writeTrustArtifactsForProof(root, written.proof);
@@ -6,7 +6,8 @@ import { readAgentProofEvidence } from '../agents/agent-proof-evidence.js';
6
6
  import { wrongnessProofEvidence } from '../triwiki-wrongness/wrongness-proof-linker.js';
7
7
  import { computerUseStatusReport } from '../computer-use-status.js';
8
8
  import { readComputerUseLiveEvidence } from '../computer-use-live-evidence.js';
9
- export async function finalizeRouteWithProof(root, { missionId, route, gateFile = null, gate = null, artifacts = [], visualEvidence = null, dbEvidence = null, madSksEvidence = null, testEvidence = null, commandEvidence = null, claims = [], unverified = [], blockers = [], statusHint = 'verified_partial', strict = false, mock = false, fixClaim = false, requireRelation = false, visualClaim = undefined, agents = undefined, allowActiveWrongnessPartial = false, failureAnalysis = null } = {}) {
9
+ import { leanChangeEvidenceFromReport, scanCodeStructure } from '../code-structure.js';
10
+ export async function finalizeRouteWithProof(root, { missionId, route, gateFile = null, gate = null, artifacts = [], visualEvidence = null, dbEvidence = null, madSksEvidence = null, testEvidence = null, commandEvidence = null, claims = [], unverified = [], blockers = [], statusHint = 'verified_partial', strict = false, mock = false, fixClaim = false, requireRelation = false, visualClaim = undefined, agents = undefined, allowActiveWrongnessPartial = false, failureAnalysis = null, lightweightEvidence = false } = {}) {
10
11
  const policy = routeFinalizerPolicy(route, { strict, fixClaim, requireRelation, visualClaim });
11
12
  const localBlockers = [...blockers];
12
13
  const providedVisualEvidence = visualEvidence;
@@ -23,9 +24,14 @@ export async function finalizeRouteWithProof(root, { missionId, route, gateFile
23
24
  localBlockers.push(...(imageEvidence.issues?.length ? imageEvidence.issues : ['image_voxel_anchors_missing']));
24
25
  }
25
26
  }
26
- const collected = await collectProofEvidence(root);
27
+ const collected = lightweightEvidence ? { files: [] } : await collectProofEvidence(root);
28
+ const leanEngineeringEvidence = await collectLeanEngineeringEvidence(root, lightweightEvidence).catch((err) => ({
29
+ schema: 'sks.lean-change-evidence.v1',
30
+ status: 'not_collected',
31
+ reason: err?.message || String(err || 'unknown_error')
32
+ }));
27
33
  const agentEvidence = agents === false ? null : await readAgentProofEvidence(root, missionId).catch(() => null);
28
- const wrongnessEvidence = await wrongnessProofEvidence(root, missionId, { route: policy.route }).catch(() => null);
34
+ const wrongnessEvidence = lightweightEvidence ? null : await wrongnessProofEvidence(root, missionId, { route: policy.route }).catch(() => null);
29
35
  const requiresNativeComputerUseLiveEvidence = ['$Computer-Use', '$CU'].includes(String(policy.route || ''));
30
36
  const computerUse = requiresNativeComputerUseLiveEvidence
31
37
  ? await computerUseStatusReport().catch((err) => ({ schema: 'sks.computer-use-status.v1', status: 'unknown', ok: false, guidance: [err.message], evidence: { status: 'unknown' } }))
@@ -117,6 +123,7 @@ export async function finalizeRouteWithProof(root, { missionId, route, gateFile
117
123
  evidence: computerUse.evidence || null,
118
124
  live_evidence: computerUseLive?.evidence || null
119
125
  } } : {}),
126
+ lean_engineering: leanEngineeringEvidence,
120
127
  route_gate: gate || (gateFile ? { source: gateFile } : null)
121
128
  };
122
129
  return writeRouteCompletionProof(root, {
@@ -130,6 +137,7 @@ export async function finalizeRouteWithProof(root, { missionId, route, gateFile
130
137
  unverified: finalUnverified,
131
138
  blockers: localBlockers,
132
139
  failureAnalysis: resolvedFailureAnalysis,
140
+ lightweightEvidence,
133
141
  summary: {
134
142
  files_changed: collected.files?.length || 0,
135
143
  commands_run: evidence.commands?.length || 0,
@@ -139,6 +147,30 @@ export async function finalizeRouteWithProof(root, { missionId, route, gateFile
139
147
  }
140
148
  });
141
149
  }
150
+ async function collectLeanEngineeringEvidence(root, lightweightEvidence) {
151
+ if (lightweightEvidence) {
152
+ return leanChangeEvidenceFromReport({
153
+ changed_scope: {
154
+ mode: 'lightweight',
155
+ base: 'HEAD',
156
+ changed_files: [],
157
+ files_added: 0,
158
+ files_deleted: 0,
159
+ lines_added: 0,
160
+ lines_deleted: 0,
161
+ net_lines: 0,
162
+ source_files: [],
163
+ entries: []
164
+ },
165
+ semantic_review: {
166
+ status: 'needs-review',
167
+ findings: [{ tag: 'verify', severity: 'review', summary: 'lightweight proof skipped changed-scope code-structure scan' }]
168
+ }
169
+ });
170
+ }
171
+ const report = await scanCodeStructure(root, { changed: true });
172
+ return leanChangeEvidenceFromReport(report);
173
+ }
142
174
  function inferRouteFailureAnalysis({ missionId, route, status, blockers, unverified, wrongnessEvidence, imageEvidence, agentEvidence, computerUse, computerUseLive, visualComputerUseDowngrade } = {}) {
143
175
  if (status === 'verified' && !blockers?.length && !unverified?.length)
144
176
  return null;