sneakoscope 8.3.2 → 8.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +1 -1
  2. package/config/architecture-map-policy.v1.json +168 -0
  3. package/crates/sks-core/Cargo.lock +1 -1
  4. package/crates/sks-core/Cargo.toml +1 -1
  5. package/dist/commands/bridge.js +19 -1
  6. package/dist/commands/doctor-profile.js +1 -1
  7. package/dist/commands/doctor.js +97 -16
  8. package/dist/config/skills-manifest.json +1 -1
  9. package/dist/core/align/align-route.js +8 -2
  10. package/dist/core/align/code-navigation-align.js +88 -32
  11. package/dist/core/architecture-map-pipeline.js +173 -0
  12. package/dist/core/architecture-map-review.js +180 -0
  13. package/dist/core/codex/agent-config-file-repair.js +17 -3
  14. package/dist/core/codex/codex-config-guard.js +3 -1
  15. package/dist/core/codex/codex-feature-flags.js +10 -0
  16. package/dist/core/codex/codex-project-config-policy.js +54 -30
  17. package/dist/core/codex/codex-startup-config-postcheck.js +5 -0
  18. package/dist/core/codex-app/codex-app-fast-ui-repair.js +2 -1
  19. package/dist/core/codex-app/menubar/constants.js +1 -0
  20. package/dist/core/codex-hooks/codex-hook-state-writer.js +2 -0
  21. package/dist/core/codex-lb/codex-lb-env.js +25 -3
  22. package/dist/core/codex-lb/combined-catalog/builder.js +7 -2
  23. package/dist/core/codex-lb/combined-catalog/model-selection.js +71 -0
  24. package/dist/core/codex-lb/combined-catalog/normalize.js +20 -3
  25. package/dist/core/codex-lb/desktop-bridge/security.js +11 -8
  26. package/dist/core/codex-lb/desktop-controller-v3/catalog.js +75 -4
  27. package/dist/core/codex-lb/desktop-controller-v3.js +5 -1
  28. package/dist/core/codex-lb/request-route-resolver.js +21 -18
  29. package/dist/core/commands/triwiki-atlas-command.js +372 -0
  30. package/dist/core/commands/triwiki-command.js +12 -1
  31. package/dist/core/doctor/doctor-dirty-planner.js +16 -1
  32. package/dist/core/doctor/doctor-idempotence.js +11 -0
  33. package/dist/core/doctor/doctor-repair-postcheck.js +49 -0
  34. package/dist/core/doctor/doctor-transaction.js +47 -2
  35. package/dist/core/doctor/legacy-global-hook-cleanup.js +1 -1
  36. package/dist/core/fsx.js +14 -0
  37. package/dist/core/git-hygiene/git-policy.js +4 -0
  38. package/dist/core/git-hygiene/gitignore-writer.js +2 -0
  39. package/dist/core/gx-renderer.js +2 -1
  40. package/dist/core/init.js +40 -17
  41. package/dist/core/managed-paths.js +1 -0
  42. package/dist/core/perf/release-latency-slo.js +57 -11
  43. package/dist/core/pipeline-internals/pipeline-stage-builder.js +181 -0
  44. package/dist/core/pipeline-internals/runtime-core.js +18 -172
  45. package/dist/core/pipeline-internals/runtime-gates.js +12 -1
  46. package/dist/core/release/content-digest-cache.js +70 -0
  47. package/dist/core/release/gate-manifest.js +9 -0
  48. package/dist/core/release/main-push-guard.js +4 -3
  49. package/dist/core/release/package-dist-snapshot.js +18 -2
  50. package/dist/core/release/physical-release-gates.js +26 -3
  51. package/dist/core/release/release-authorization-snapshot.js +4 -0
  52. package/dist/core/release/release-gate-cache-v2.js +27 -3
  53. package/dist/core/release/release-gate-contract.js +2 -0
  54. package/dist/core/release/release-gate-dag.js +3 -0
  55. package/dist/core/release/release-inspection-memo.js +69 -0
  56. package/dist/core/release/release-pack-content-scanner.js +5 -0
  57. package/dist/core/release/release-pack-receipt.js +28 -18
  58. package/dist/core/release/release-pack-tarball.js +10 -0
  59. package/dist/core/release/release-upgrade-baseline.js +4 -0
  60. package/dist/core/routes.js +1 -1
  61. package/dist/core/safety/ssot-authority-inventory.js +114 -0
  62. package/dist/core/safety/ssot-guard.js +2 -44
  63. package/dist/core/subagents/agent-catalog.js +4 -2
  64. package/dist/core/subagents/official-subagent-config.js +92 -15
  65. package/dist/core/subagents/official-subagent-preparation.js +1 -0
  66. package/dist/core/triwiki/context-graph/architecture/baseline.js +81 -0
  67. package/dist/core/triwiki/context-graph/architecture/capsule.js +34 -0
  68. package/dist/core/triwiki/context-graph/architecture/contracts.js +67 -0
  69. package/dist/core/triwiki/context-graph/architecture/delta.js +149 -0
  70. package/dist/core/triwiki/context-graph/architecture/finding-factory.js +28 -0
  71. package/dist/core/triwiki/context-graph/architecture/findings.js +173 -0
  72. package/dist/core/triwiki/context-graph/architecture/fingerprint.js +75 -0
  73. package/dist/core/triwiki/context-graph/architecture/index.js +15 -0
  74. package/dist/core/triwiki/context-graph/architecture/input-bundle.js +66 -0
  75. package/dist/core/triwiki/context-graph/architecture/metrics.js +137 -0
  76. package/dist/core/triwiki/context-graph/architecture/policy.js +321 -0
  77. package/dist/core/triwiki/context-graph/architecture/slice.js +100 -0
  78. package/dist/core/triwiki/context-graph/architecture/ssot-analysis.js +59 -0
  79. package/dist/core/triwiki/context-graph/architecture/topology-overlay.js +106 -0
  80. package/dist/core/triwiki/context-graph/architecture/validation.js +145 -0
  81. package/dist/core/triwiki/context-graph/architecture/voxel-context.js +39 -0
  82. package/dist/core/triwiki/context-graph/extractors/index.js +4 -0
  83. package/dist/core/triwiki/context-graph/projections/index.js +2 -0
  84. package/dist/core/triwiki/context-graph/projections/mermaid/architecture-delta.js +68 -0
  85. package/dist/core/triwiki/context-graph/projections/mermaid/ast.js +49 -0
  86. package/dist/core/triwiki/context-graph/projections/mermaid/change-impact.js +43 -0
  87. package/dist/core/triwiki/context-graph/projections/mermaid/contracts.js +5 -0
  88. package/dist/core/triwiki/context-graph/projections/mermaid/escape.js +45 -0
  89. package/dist/core/triwiki/context-graph/projections/mermaid/ids.js +73 -0
  90. package/dist/core/triwiki/context-graph/projections/mermaid/index.js +113 -0
  91. package/dist/core/triwiki/context-graph/projections/mermaid/manifest.js +37 -0
  92. package/dist/core/triwiki/context-graph/projections/mermaid/module-dependency.js +21 -0
  93. package/dist/core/triwiki/context-graph/projections/mermaid/ownership-workstream.js +21 -0
  94. package/dist/core/triwiki/context-graph/projections/mermaid/project-topology.js +13 -0
  95. package/dist/core/triwiki/context-graph/projections/mermaid/public-surface.js +17 -0
  96. package/dist/core/triwiki/context-graph/projections/mermaid/reduce.js +44 -0
  97. package/dist/core/triwiki/context-graph/projections/mermaid/risk-domains.js +23 -0
  98. package/dist/core/triwiki/context-graph/projections/mermaid/runtime-control.js +20 -0
  99. package/dist/core/triwiki/context-graph/projections/mermaid/selection-ledger.js +94 -0
  100. package/dist/core/triwiki/context-graph/projections/mermaid/serializer.js +81 -0
  101. package/dist/core/triwiki/context-graph/projections/mermaid/ssot-provenance.js +17 -0
  102. package/dist/core/triwiki/context-graph/projections/mermaid/verification-coverage.js +17 -0
  103. package/dist/core/triwiki/context-graph/projections/mermaid/view-builder-common.js +1 -0
  104. package/dist/core/triwiki/context-graph/projections/mermaid/view-builder.js +173 -0
  105. package/dist/core/triwiki/context-graph/projections/mermaid/view-specs.js +33 -0
  106. package/dist/core/triwiki/context-graph/store/architecture-map-store.js +71 -0
  107. package/dist/core/triwiki/triwiki-proof-bank-index.js +26 -1
  108. package/dist/core/triwiki/triwiki-proof-bank.js +82 -2
  109. package/dist/core/version.js +1 -1
  110. package/dist/native/sks-menubar/Sources/OverviewViewController.swift +2 -2
  111. package/dist/native/sks-menubar/Sources/ProvidersModelExposure.swift +178 -0
  112. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +10 -1
  113. package/dist/scripts/architecture-map-check.js +299 -0
  114. package/dist/scripts/lib/ensure-dist-fresh.js +48 -1
  115. package/dist/scripts/release-metadata-check.js +2 -0
  116. package/package.json +6 -3
  117. package/release-gates.v2.json +204 -0
  118. package/schemas/architecture-baseline.v1.schema.json +47 -0
  119. package/schemas/architecture-map-manifest.v1.schema.json +40 -0
  120. package/schemas/architecture-map-policy.v1.schema.json +147 -0
  121. package/schemas/architecture-review.v1.schema.json +46 -0
  122. package/schemas/mermaid-projection.v1.schema.json +47 -0
package/dist/core/fsx.js CHANGED
@@ -65,6 +65,20 @@ export async function canonicalFilesystemPath(p) {
65
65
  const resolved = path.resolve(p);
66
66
  return fsp.realpath(resolved).catch(() => resolved);
67
67
  }
68
+ export function canonicalFilesystemPathSync(value) {
69
+ const resolved = path.resolve(value);
70
+ try {
71
+ return fs.realpathSync.native(resolved);
72
+ }
73
+ catch {
74
+ if (process.platform === 'darwin' && resolved.startsWith('/var/'))
75
+ return `/private${resolved}`;
76
+ return resolved;
77
+ }
78
+ }
79
+ export function sameFilesystemPathSync(left, right) {
80
+ return Boolean(left && right && canonicalFilesystemPathSync(left) === canonicalFilesystemPathSync(right));
81
+ }
68
82
  export async function sameFilesystemPath(left, right) {
69
83
  const [leftCanonical, rightCanonical] = await Promise.all([
70
84
  canonicalFilesystemPath(left),
@@ -17,6 +17,8 @@ export const SHARED_MEMORY_TRACK = [
17
17
  export const GENERATED_INDEX_IGNORE = [
18
18
  '.sneakoscope/wiki/indexes/**/*.json',
19
19
  '.sneakoscope/wiki/context-packs/**/*.json',
20
+ '.sneakoscope/wiki/architecture-map/**',
21
+ '.sneakoscope/wiki/architecture-map/**/*.mmd',
20
22
  '.sneakoscope/wiki/tmp/**'
21
23
  ];
22
24
  export const LOCAL_RUNTIME_IGNORE = [
@@ -53,6 +55,8 @@ export const LOCAL_RUNTIME_IGNORE = [
53
55
  '.sneakoscope/wiki/image-wrongness-index.json',
54
56
  '.sneakoscope/wiki/visual-anchors.json',
55
57
  '.sneakoscope/wiki/last-sweep-report.json',
58
+ '.sneakoscope/wiki/architecture-map/**',
59
+ '.sneakoscope/wiki/architecture-map/**/*.mmd',
56
60
  '.sneakoscope/**/*.log'
57
61
  ];
58
62
  export const SHARED_MEMORY_DIRS = [
@@ -32,6 +32,8 @@ export const GITIGNORE_BLOCK = `# BEGIN ${GIT_HYGIENE_BLOCK}
32
32
  # Generated TriWiki indexes and transient context packs
33
33
  .sneakoscope/wiki/indexes/
34
34
  .sneakoscope/wiki/context-packs/
35
+ .sneakoscope/wiki/architecture-map/
36
+ .sneakoscope/wiki/architecture-map/**
35
37
  .sneakoscope/wiki/tmp/
36
38
  .sneakoscope/wiki/context-pack.json
37
39
  .sneakoscope/wiki/image-assets.json
@@ -78,7 +78,8 @@ export function normalizeVGraph(vgraph = {}) {
78
78
  edges,
79
79
  invariants: Array.isArray(vgraph.invariants) ? vgraph.invariants : [],
80
80
  tests: Array.isArray(vgraph.tests) ? vgraph.tests : [],
81
- risks: Array.isArray(vgraph.risks) ? vgraph.risks : []
81
+ risks: Array.isArray(vgraph.risks) ? vgraph.risks : [],
82
+ ...(vgraph.atlas && typeof vgraph.atlas === 'object' && !Array.isArray(vgraph.atlas) ? { atlas: vgraph.atlas } : {})
82
83
  };
83
84
  }
84
85
  export function vgraphHash(vgraph = {}) {
package/dist/core/init.js CHANGED
@@ -11,13 +11,15 @@ import { OFFICIAL_SUBAGENT_REVIEW_POLICY_TEXT } from './official-subagent-review
11
11
  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, LEGACY_DOLLAR_SKILL_NAMES, 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, prefixKnownSksDollarReferences, productDesignPluginPolicyText, sksPrefixedDollarCommand, speedLanePolicyText, stackCurrentDocsPolicyText, triwikiContextTracking, triwikiContextTrackingText, triwikiStagePolicyText } from './routes.js';
12
12
  import { SKILL_DREAM_POLICY, skillDreamPolicyText } from './skill-forge.js';
13
13
  import { CODEX_HOOK_EVENT_STATE_KEYS } from './codex-compat/codex-hook-events.js';
14
+ import { MANAGED_CODEX_FEATURE_FLAGS, REMOVED_CODEX_FEATURE_FLAGS } from './codex/codex-feature-flags.js';
15
+ import { writeCodexConfigGuarded } from './codex/codex-config-guard.js';
14
16
  import { codexCommandHookCurrentHash } from './codex-hooks/codex-hook-hash.js';
15
17
  import { buildSksCoreSkillManifest, isCoreSkillName, legacyCoreSkillNames } from './codex-native/core-skill-manifest.js';
16
18
  import { syncCoreSkillsIntegrity } from './codex-native/core-skill-integrity.js';
17
19
  import { AUTHORITATIVE_SKS_SKILL_ROOT_REFERENCE } from './codex-native/sks-skill-paths.js';
18
20
  import { currentGeneratedFileInventory, installCodexAgents, pruneStaleGeneratedFiles, REMOVED_SKS_SKILL_NAMES } from './init/skills.js';
19
21
  import { reconcileManagedSkillInstallation } from './init/managed-skill-install.js';
20
- import { backupInvalidToml, inspectOfficialSubagentToml, mergeOfficialSubagentConfig, officialSubagentConfigOwnershipProof, officialSubagentConfigWarnings, readInheritedOfficialSubagentConfigText, resolveInheritedOfficialSubagentConfigPath } from './subagents/official-subagent-config.js';
22
+ import { backupInvalidToml, inspectOfficialSubagentToml, mergeOfficialSubagentConfig, officialSubagentConfigOwnershipProof, officialSubagentConfigWarnings, readInheritedOfficialSubagentConfigText, resolveInheritedOfficialSubagentConfigPath, stampSksManagedCodexConfigMarker } from './subagents/official-subagent-config.js';
21
23
  import { escapeRegExp } from './text/regex.js';
22
24
  export { installGlobalSkills, installProjectSkills, installSkills } from './init/skills.js';
23
25
  const REFLECTION_MEMORY_PATH = '.sneakoscope/memory/q2_facts/post-route-reflection.md';
@@ -206,6 +208,8 @@ function upsertCodexTrustTomlTable(text, table, block) {
206
208
  break;
207
209
  }
208
210
  }
211
+ while (end > start + 1 && !String(lines[end - 1] || '').trim())
212
+ end -= 1;
209
213
  lines.splice(start, end - start, ...blockLines);
210
214
  return lines.join('\n').replace(/\n{3,}/g, '\n\n');
211
215
  }
@@ -631,14 +635,11 @@ export async function initProject(root, opts = {}) {
631
635
  project_install: 'npm i -D sneakoscope && npx sks setup --install-scope project'
632
636
  };
633
637
  }
634
- const MANAGED_CODEX_FEATURE_FLAGS = ['hooks', 'fast_mode', 'apps'];
635
- const REMOVED_CODEX_FEATURE_FLAGS = [
636
- 'remote_control', 'fast_mode_ui', 'codex_git_commit', 'computer_use', 'browser_use',
637
- 'browser_use_external', 'image_generation', 'in_app_browser', 'guardian_approval',
638
- 'tool_suggest', 'plugins', 'codex_hooks', 'multi_agent'
639
- ];
640
638
  function mergeManagedCodexConfigToml(existingContent = '', opts = {}) {
641
639
  let next = String(existingContent || '').trimEnd();
640
+ if (opts.sksOwned === true || opts.configWasFresh === true) {
641
+ next = stampSksManagedCodexConfigMarker(next);
642
+ }
642
643
  next = removeTomlTableKey(next, 'notice', 'fast_default_opt_out');
643
644
  next = removeTomlTableKey(next, 'features', 'codex_hooks');
644
645
  next = upsertTopLevelTomlBooleanIfAbsent(next, 'suppress_unstable_features_warning', true);
@@ -918,6 +919,7 @@ export async function initProject(root, opts = {}) {
918
919
  else {
919
920
  const managedCodexConfig = await mergeGlobalCodexConfigIfAvailable(mergeManagedCodexConfigToml(existingCodexConfig, {
920
921
  sksOwned: configPreviouslySksOwned,
922
+ configWasFresh,
921
923
  inheritedText: inheritedCodexConfig
922
924
  }), generatedCodexConfigPath, { home: opts.home, codexHome: opts.codexHome });
923
925
  const managedConfigValidation = inspectOfficialSubagentToml(managedCodexConfig);
@@ -934,16 +936,37 @@ export async function initProject(root, opts = {}) {
934
936
  created.push('.codex/config.toml merge skipped (manual repair required)');
935
937
  }
936
938
  else {
937
- await writeTextAtomic(generatedCodexConfigPath, managedCodexConfig);
938
- codexConfigInstall = {
939
- ok: true,
940
- status: managedCodexConfig === existingCodexConfig ? 'present' : 'written',
941
- config_path: generatedCodexConfigPath,
942
- backup_path: null,
943
- manual_blockers: [],
944
- warnings: officialSubagentConfigWarnings(managedCodexConfig, inheritedCodexConfig)
945
- };
946
- created.push('.codex/config.toml');
939
+ const guarded = await writeCodexConfigGuarded({
940
+ root,
941
+ configPath: generatedCodexConfigPath,
942
+ before: existingCodexConfig,
943
+ cause: 'sks-init-managed-project-config',
944
+ ownershipVerified: configWasFresh || configPreviouslySksOwned,
945
+ preserveTextFormatting: true,
946
+ mutate: () => managedCodexConfig
947
+ });
948
+ codexConfigInstall = guarded.ok
949
+ ? {
950
+ ok: true,
951
+ status: managedCodexConfig === existingCodexConfig ? 'present' : 'written',
952
+ config_path: generatedCodexConfigPath,
953
+ backup_path: guarded.backup_path,
954
+ manual_blockers: [],
955
+ warnings: officialSubagentConfigWarnings(managedCodexConfig, inheritedCodexConfig)
956
+ }
957
+ : {
958
+ ok: false,
959
+ status: guarded.status,
960
+ config_path: generatedCodexConfigPath,
961
+ backup_path: guarded.backup_path,
962
+ manual_blockers: [`manual_unmanaged_project_codex_config:${guarded.status}`],
963
+ warnings: [],
964
+ operator_actions: [
965
+ `${generatedCodexConfigPath} is not proven SKS-owned, so setup left it unchanged. `
966
+ + 'Run `sks config adopt` to bring it under management, or delete it and re-run `sks setup`.'
967
+ ]
968
+ };
969
+ created.push(guarded.ok ? '.codex/config.toml' : '.codex/config.toml preserved (user-owned)');
947
970
  }
948
971
  }
949
972
  }
@@ -29,6 +29,7 @@ export function defaultManagedPaths() {
29
29
  row('.sneakoscope/wiki/summaries', 'tracked shared markdown summaries', false, 'shared_memory', 'tracked'),
30
30
  row('.sneakoscope/wiki/indexes', 'ignored regenerated shared-memory indexes', true, 'generated_index', 'ignored'),
31
31
  row('.sneakoscope/wiki/context-packs', 'ignored regenerated context-pack snapshots', true, 'generated_index', 'ignored'),
32
+ row('.sneakoscope/wiki/architecture-map', 'ignored regenerated Architecture Map views', true, 'generated_index', 'ignored'),
32
33
  row('.sneakoscope/missions', 'local runtime mission state and proof artifacts', true, 'local_runtime', 'ignored'),
33
34
  row('.sneakoscope/reports', 'local runtime reports', true, 'local_runtime', 'ignored'),
34
35
  row('.sneakoscope/tmp', 'local temporary runtime files', true, 'local_runtime', 'ignored'),
@@ -1,4 +1,5 @@
1
1
  import { spawn } from 'node:child_process';
2
+ import { createHash } from 'node:crypto';
2
3
  import fs from 'node:fs/promises';
3
4
  import os from 'node:os';
4
5
  import path from 'node:path';
@@ -31,7 +32,7 @@ export async function runReleaseLatencySlo(root, budgets, options = {}) {
31
32
  await capture('ssh_worker_hello', budgetMap, () => measureSshHello(tmp, runs(budgetMap, 'ssh_worker_hello', 5)))
32
33
  ];
33
34
  const native = platform === 'darwin'
34
- ? await measureNativeMenuBar(tmp, budgetMap).catch((error) => nativeFailureMeasurements(budgetMap, error))
35
+ ? await measureNativeMenuBar(root, budgetMap).catch((error) => nativeFailureMeasurements(budgetMap, error))
35
36
  : ['menubar_first_state_render', 'control_center_open'].map((id) => ({
36
37
  id,
37
38
  budget_p95_ms: budgetMap.get(id)?.budget_p95_ms ?? RELEASE_LATENCY_LIMITS[id],
@@ -140,10 +141,11 @@ async function measureSshHello(tmp, count) {
140
141
  }
141
142
  return { producer: 'RemoteSshWorkerClient.connect:local_stdio_child', samples: values, evidence: { transport: 'local_process_ssh_stdio_fixture', network_included: false, process_startup_included: true } };
142
143
  }
143
- async function measureNativeMenuBar(tmp, budgets) {
144
+ async function measureNativeMenuBar(root, budgets) {
145
+ const tmp = path.join(root, '.sneakoscope', 'cache', 'menubar-latency');
144
146
  const sourceDir = path.join(tmp, 'native-sources');
145
- const executable = path.join(tmp, 'sks-menubar-latency');
146
147
  const home = path.join(tmp, 'native-home');
148
+ await fs.rm(home, { recursive: true, force: true });
147
149
  await Promise.all([sourceDir, home].map((dir) => fs.mkdir(dir, { recursive: true })));
148
150
  const cache = path.join(home, '.sneakoscope-global', 'cache', 'update-status.json');
149
151
  const cacheSnapshot = emptyUpdateStatus('6.3.0', new Date());
@@ -169,13 +171,9 @@ async function measureNativeMenuBar(tmp, budgets) {
169
171
  await fs.writeFile(path.join(sourceDir, source.name), content, { mode: 0o600 });
170
172
  }
171
173
  const files = sources.map((source) => path.join(sourceDir, source.name));
172
- const compileStarted = performance.now();
173
- const compile = await runProcess('swiftc', ['-framework', 'Cocoa', '-framework', 'UserNotifications', ...files, '-o', executable], {
174
- cwd: tmp, timeoutMs: 90_000, maxOutputBytes: 128 * 1024
175
- });
176
- const compileMs = round(performance.now() - compileStarted);
177
- if (compile.code !== 0)
178
- throw new Error(`menubar_latency_compile_failed:${compile.stderr.slice(-400)}`);
174
+ const build = await buildNativeMenuBarHarness(tmp, files);
175
+ const executable = build.executable;
176
+ const compileMs = build.compile_duration_ms;
179
177
  const nativeRuns = Math.max(runs(budgets, 'menubar_first_state_render', 5), runs(budgets, 'control_center_open', 5));
180
178
  const first = [];
181
179
  const control = [];
@@ -191,7 +189,8 @@ async function measureNativeMenuBar(tmp, budgets) {
191
189
  control.push(Number(parsed.control_center_open_ms));
192
190
  }
193
191
  const evidence = {
194
- source_count: sources.length, compile_exit_code: compile.code, compile_duration_ms: compileMs,
192
+ source_count: sources.length, compile_exit_code: 0, compile_duration_ms: compileMs,
193
+ compile_reused: build.reused, compile_source_digest: build.source_digest,
195
194
  link_frameworks: ['Cocoa', 'UserNotifications'], run_exit_codes: exitCodes,
196
195
  cache_based: true, cache_bytes: Buffer.byteLength(JSON.stringify(cacheSnapshot)), controller_prebuilt: true
197
196
  };
@@ -200,6 +199,53 @@ async function measureNativeMenuBar(tmp, budgets) {
200
199
  evaluateLatencySamples('control_center_open', budgets.get('control_center_open')?.budget_p95_ms ?? 400, 'ControlCenterWindowController.show:overview', control, evidence)
201
200
  ];
202
201
  }
202
+ async function buildNativeMenuBarHarness(buildRoot, files) {
203
+ const toolchain = await runProcess('swiftc', ['--version'], { cwd: buildRoot, timeoutMs: 30_000, maxOutputBytes: 32 * 1024 });
204
+ const digest = createHash('sha256');
205
+ digest.update(toolchain.code === 0 ? toolchain.stdout : 'swiftc_version_unavailable');
206
+ digest.update('\0');
207
+ for (const file of [...files].sort()) {
208
+ digest.update(path.basename(file));
209
+ digest.update('\0');
210
+ digest.update(await fs.readFile(file));
211
+ digest.update('\0');
212
+ }
213
+ const sourceDigest = digest.digest('hex');
214
+ const binDir = path.join(buildRoot, 'bin');
215
+ const executable = path.join(binDir, `sks-menubar-latency-${sourceDigest}`);
216
+ await fs.mkdir(binDir, { recursive: true });
217
+ if (await pathIsFile(executable)) {
218
+ return { executable, compile_duration_ms: 0, source_digest: sourceDigest, reused: true };
219
+ }
220
+ const staged = `${executable}.${process.pid}.tmp`;
221
+ const compileStarted = performance.now();
222
+ const compile = await runProcess('swiftc', ['-framework', 'Cocoa', '-framework', 'UserNotifications', ...files, '-o', staged], {
223
+ cwd: buildRoot, timeoutMs: 90_000, maxOutputBytes: 128 * 1024
224
+ });
225
+ const compileMs = round(performance.now() - compileStarted);
226
+ if (compile.code !== 0) {
227
+ await fs.rm(staged, { force: true });
228
+ throw new Error(`menubar_latency_compile_failed:${compile.stderr.slice(-400)}`);
229
+ }
230
+ await fs.rename(staged, executable);
231
+ await pruneNativeHarnessBinaries(binDir, executable);
232
+ return { executable, compile_duration_ms: compileMs, source_digest: sourceDigest, reused: false };
233
+ }
234
+ async function pruneNativeHarnessBinaries(binDir, keep) {
235
+ const entries = await fs.readdir(binDir).catch(() => []);
236
+ await Promise.all(entries
237
+ .map((name) => path.join(binDir, name))
238
+ .filter((file) => file !== keep)
239
+ .map((file) => fs.rm(file, { force: true, recursive: true }).catch(() => undefined)));
240
+ }
241
+ async function pathIsFile(file) {
242
+ try {
243
+ return (await fs.stat(file)).isFile();
244
+ }
245
+ catch {
246
+ return false;
247
+ }
248
+ }
203
249
  function nativeHarnessSource() {
204
250
  return `let application = NSApplication.shared
205
251
  application.setActivationPolicy(.accessory)
@@ -0,0 +1,181 @@
1
+ import { SPEED_LANE_POLICY } from '../proof-field.js';
2
+ import { OFFICIAL_SUBAGENT_EXECUTION_STAGE_ID } from '../agents/agent-schema.js';
3
+ import { normalizeOfficialSubagentPolicy, officialSubagentPipelineStage } from '../agents/agent-plan.js';
4
+ import { looksLikeCodeChangingWork, reflectionRequiredForRoute, routeRequiresSubagents } from '../routes.js';
5
+ import { classifyTaskProfile } from '../runtime/task-profile.js';
6
+ import {} from '../runtime/verification-budget.js';
7
+ export const LIGHTWEIGHT_ROUTES = new Set(['Answer', 'DFix', 'Help', 'Wiki', 'Goal']);
8
+ export const BLOCKING_GATE_LIMITS = Object.freeze({
9
+ passthrough: 0,
10
+ answer: 0,
11
+ 'tiny-change': 1,
12
+ 'bounded-work': 2,
13
+ 'parallel-read': 2,
14
+ 'parallel-write': 3,
15
+ 'high-risk': 4
16
+ });
17
+ function routeNeedsEngineeringSanityReview(route, task) {
18
+ const id = String(route?.id || '');
19
+ if (['DB', 'MadSKS'].includes(id))
20
+ return true;
21
+ if (['Answer', 'Help', 'Wiki', 'Goal', 'Research', 'AutoResearch', 'PPT', 'ImageUXReview', 'ComputerUse', 'GX'].includes(id))
22
+ return false;
23
+ return looksLikeCodeChangingWork(String(task || ''));
24
+ }
25
+ export const GATE_PROFILE_STAGES = Object.freeze({
26
+ none: [],
27
+ minimal: ['route_classification', 'listed_verification'],
28
+ scoped: ['route_classification', 'ownership', 'listed_verification', 'honest_summary'],
29
+ full: ['route_classification', 'ambiguity_gate', 'safety_gate', 'ownership', 'listed_verification', 'honest_summary']
30
+ });
31
+ export const STAGE_BLOCKING_GATE = Object.freeze({
32
+ ambiguity_gate: 'scope',
33
+ safety_gate: 'safety',
34
+ ssot_guard: 'safety',
35
+ context7_evidence: 'safety',
36
+ mistake_recall: 'safety',
37
+ ownership: 'ownership',
38
+ pipeline_plan: 'ownership',
39
+ focused_implementation: 'ownership',
40
+ triwiki_use_first: 'ownership',
41
+ subagent_plan: 'ownership',
42
+ official_subagent_execution: 'ownership',
43
+ parent_integration: 'ownership',
44
+ route_materialization: 'ownership',
45
+ work_order_coverage: 'ownership',
46
+ architecture_map_baseline: 'ownership',
47
+ engineering_sanity_check: 'verification',
48
+ listed_verification: 'verification',
49
+ triwiki_validate_before_final: 'verification',
50
+ architecture_map_review: 'verification',
51
+ completion_proof: 'verification',
52
+ reflection: 'verification',
53
+ honest_summary: 'verification'
54
+ });
55
+ export function selectPipelineLane(route, task, proof, taskProfile = classifyTaskProfile(task)) {
56
+ if (proof.attached && proof.lane) {
57
+ return {
58
+ lane: proof.lane,
59
+ source: 'proof_field',
60
+ fast_lane_allowed: Boolean(proof.fast_lane_allowed),
61
+ reason: proof.fast_lane_allowed ? 'Proof Field allowed the fast lane.' : `Proof Field selected ${proof.lane}.`,
62
+ blockers: proof.blockers || [],
63
+ skip_when_fast: proof.fast_lane_allowed ? SPEED_LANE_POLICY.skip_when_fast : [],
64
+ keep: proof.keep || SPEED_LANE_POLICY.always_keep
65
+ };
66
+ }
67
+ if (taskProfile === 'passthrough' || taskProfile === 'answer')
68
+ return { lane: 'no_pipeline', source: 'task_profile', fast_lane_allowed: true, reason: 'Light conversation does not create an execution pipeline.', blockers: [], skip_when_fast: [], keep: [] };
69
+ if (route?.id === 'ComputerUse')
70
+ return { lane: 'computer_use_fast_lane', source: 'route_policy', fast_lane_allowed: true, reason: 'Computer Use route is intentionally direct and defers wiki/honest checks to closeout.', blockers: [], skip_when_fast: ['planning_debate'], keep: ['focused_implementation', 'triwiki_validate_before_final', 'honest_mode'] };
71
+ if (taskProfile === 'tiny-change')
72
+ return { lane: 'minimal_change_lane', source: 'task_profile', fast_lane_allowed: true, reason: 'Tiny change uses one blocking gate and one focused check at most.', blockers: [], skip_when_fast: SPEED_LANE_POLICY.skip_when_fast, keep: ['listed_verification'] };
73
+ if (LIGHTWEIGHT_ROUTES.has(route?.id))
74
+ return { lane: `${String(route.id).toLowerCase()}_lightweight_lane`, source: 'route_policy', fast_lane_allowed: true, reason: 'Lightweight route bypasses full mission orchestration by design.', blockers: [], skip_when_fast: SPEED_LANE_POLICY.skip_when_fast, keep: ['focused_implementation', 'listed_verification', 'honest_mode'] };
75
+ if (routeRequiresSubagents(route, task, taskProfile))
76
+ return { lane: 'official_subagent_lane', source: 'task_profile', fast_lane_allowed: false, reason: 'Explicit Naruto or parallel work uses the Codex subagent workflow.', blockers: [], skip_when_fast: [], keep: ['subagent_plan', 'official_subagent_execution', 'parent_integration', 'listed_verification', 'honest_summary'] };
77
+ if (taskProfile === 'high-risk')
78
+ return { lane: SPEED_LANE_POLICY.full_lane, source: 'task_profile', fast_lane_allowed: false, reason: 'High-risk work uses the full risk gate profile.', blockers: [], skip_when_fast: [], keep: SPEED_LANE_POLICY.always_keep };
79
+ return { lane: SPEED_LANE_POLICY.balanced_lane, source: 'route_policy', fast_lane_allowed: false, reason: 'Balanced parent-owned route until Proof Field proves a narrower lane.', blockers: ['proof_field_not_attached'], skip_when_fast: [], keep: SPEED_LANE_POLICY.always_keep };
80
+ }
81
+ export function buildPipelineStages(route, task, taskProfile, gateProfile, ambiguity, lane, context7Required, officialSubagentPolicy = normalizeOfficialSubagentPolicy(route, task, {})) {
82
+ if (gateProfile === 'none')
83
+ return [];
84
+ const ids = [...GATE_PROFILE_STAGES[gateProfile]];
85
+ const specializedRoute = Boolean(route?.id && !LIGHTWEIGHT_ROUTES.has(route.id) && route.id !== 'SKS');
86
+ if (gateProfile === 'scoped' || gateProfile === 'full' || specializedRoute)
87
+ ids.push('pipeline_plan', 'focused_implementation');
88
+ if ((gateProfile === 'full' || specializedRoute) && !ids.includes('ssot_guard'))
89
+ ids.push('ssot_guard');
90
+ if (context7Required)
91
+ ids.push('context7_evidence');
92
+ if ((gateProfile === 'scoped' || gateProfile === 'full') && !LIGHTWEIGHT_ROUTES.has(route?.id)) {
93
+ ids.push('triwiki_use_first', 'triwiki_validate_before_final', 'mistake_recall', 'work_order_coverage');
94
+ }
95
+ if (routeNeedsEngineeringSanityReview(route, task))
96
+ ids.push('engineering_sanity_check');
97
+ if ((gateProfile === 'scoped' || gateProfile === 'full') && route?.id !== 'GX' && route?.id !== 'DB' && !LIGHTWEIGHT_ROUTES.has(route?.id)) {
98
+ ids.push('architecture_map_baseline', 'architecture_map_review');
99
+ }
100
+ if (routeRequiresSubagents(route, task, taskProfile))
101
+ ids.push('subagent_plan', 'official_subagent_execution', 'parent_integration');
102
+ if (specializedRoute)
103
+ ids.push('route_materialization');
104
+ if (specializedRoute)
105
+ ids.push('completion_proof');
106
+ if (reflectionRequiredForRoute(route))
107
+ ids.push('reflection');
108
+ return [...new Set(ids)].map((id) => {
109
+ const configuredGate = STAGE_BLOCKING_GATE[id] || null;
110
+ const blockingGate = configuredGate === 'safety' && gateProfile !== 'full'
111
+ ? 'ownership'
112
+ : configuredGate;
113
+ const blocking = Boolean(blockingGate);
114
+ const metadata = { blocking, blocking_gate: blocking ? blockingGate : null };
115
+ if (id === OFFICIAL_SUBAGENT_EXECUTION_STAGE_ID)
116
+ return { ...officialSubagentPipelineStage(officialSubagentPolicy), status: 'required', reason: officialSubagentPolicy.reason, ...metadata };
117
+ if (id === 'engineering_sanity_check') {
118
+ return {
119
+ id,
120
+ status: 'keep',
121
+ reason: 'required_for_code_and_database_quality',
122
+ checks: [
123
+ 'trace actual callers and preserve basic SOLID responsibility and dependency boundaries',
124
+ 'inspect loops, collections, resolvers, and serializers for N+1 or repeated I/O',
125
+ 'prove render, recursion, event, retry, and polling loops are bounded and cancellable',
126
+ 'reject disabled checks, swallowed errors, placeholder success, and verification bypasses',
127
+ 'for DB work, verify the existing canonical adapter and connection/pool lifecycle before changes',
128
+ 'for sensitive or multi-step DB work, verify transaction rollback, error propagation, idempotency, and post-commit invariants'
129
+ ],
130
+ ...metadata
131
+ };
132
+ }
133
+ if (id === 'ambiguity_gate' && ambiguity?.required === false)
134
+ return { id, status: 'not_applicable', reason: 'ambiguity_gate_not_required_for_entrypoint', ...metadata };
135
+ if (id === 'ambiguity_gate' && ambiguity?.passed)
136
+ return { id, status: 'passed', reason: 'ambiguity_contract_already_sealed', ...metadata };
137
+ return { id, status: 'keep', reason: lane.fast_lane_allowed ? 'task_profile_minimal_lane' : 'required_by_task_and_route_profile', ...metadata };
138
+ });
139
+ }
140
+ export function planVerification(route, task, proof, budget) {
141
+ if (budget === 'none')
142
+ return [];
143
+ const out = new Set(proof.verification || []);
144
+ if (budget === 'single-check')
145
+ out.add('run one focused check for the changed surface');
146
+ if (budget === 'affected')
147
+ out.add('run affected tests or checks for changed files');
148
+ if (budget === 'confidence') {
149
+ out.add('run the focused build or typecheck for the affected package');
150
+ out.add('run affected regression tests and the risk-specific safety check');
151
+ }
152
+ if (budget === 'release') {
153
+ out.add('npm run packcheck');
154
+ out.add('sks selftest --mock --json');
155
+ }
156
+ if (route?.id === 'Naruto')
157
+ out.add('validate official subagent evidence and the parent integration summary');
158
+ if (routeNeedsEngineeringSanityReview(route, task)) {
159
+ out.add('complete the engineering sanity review for SOLID boundaries, N+1/repeated I/O, bounded loops, and verification bypasses');
160
+ }
161
+ if (route?.id === 'DB' || route?.id === 'MadSKS') {
162
+ out.add('verify existing canonical DB access, pool lifecycle, and transaction integrity for sensitive or multi-step mutations');
163
+ }
164
+ if (reflectionRequiredForRoute(route))
165
+ out.add('sks wiki validate .sneakoscope/wiki/context-pack.json');
166
+ return [...out];
167
+ }
168
+ export function pipelineInvariants(input) {
169
+ const out = ['no_unrequested_fallback_code'];
170
+ if (input.stages.some((stage) => stage.id === 'engineering_sanity_check'))
171
+ out.push('engineering_sanity_check');
172
+ if (input.verificationBudget !== 'none')
173
+ out.push('listed_verification');
174
+ if (input.stages.some((stage) => stage.id === 'ssot_guard' && stage.status !== 'not_applicable'))
175
+ out.push('ssot_guard');
176
+ if (input.stages.some((stage) => stage.id === 'triwiki_validate_before_final'))
177
+ out.push('triwiki_validate_before_final');
178
+ if (input.gateProfile !== 'none')
179
+ out.push('honest_summary');
180
+ return out;
181
+ }