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.
- package/README.md +1 -1
- package/config/architecture-map-policy.v1.json +168 -0
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/commands/bridge.js +19 -1
- package/dist/commands/doctor-profile.js +1 -1
- package/dist/commands/doctor.js +97 -16
- package/dist/config/skills-manifest.json +1 -1
- package/dist/core/align/align-route.js +8 -2
- package/dist/core/align/code-navigation-align.js +88 -32
- package/dist/core/architecture-map-pipeline.js +173 -0
- package/dist/core/architecture-map-review.js +180 -0
- package/dist/core/codex/agent-config-file-repair.js +17 -3
- package/dist/core/codex/codex-config-guard.js +3 -1
- package/dist/core/codex/codex-feature-flags.js +10 -0
- package/dist/core/codex/codex-project-config-policy.js +54 -30
- package/dist/core/codex/codex-startup-config-postcheck.js +5 -0
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +2 -1
- package/dist/core/codex-app/menubar/constants.js +1 -0
- package/dist/core/codex-hooks/codex-hook-state-writer.js +2 -0
- package/dist/core/codex-lb/codex-lb-env.js +25 -3
- package/dist/core/codex-lb/combined-catalog/builder.js +7 -2
- package/dist/core/codex-lb/combined-catalog/model-selection.js +71 -0
- package/dist/core/codex-lb/combined-catalog/normalize.js +20 -3
- package/dist/core/codex-lb/desktop-bridge/security.js +11 -8
- package/dist/core/codex-lb/desktop-controller-v3/catalog.js +75 -4
- package/dist/core/codex-lb/desktop-controller-v3.js +5 -1
- package/dist/core/codex-lb/request-route-resolver.js +21 -18
- package/dist/core/commands/triwiki-atlas-command.js +372 -0
- package/dist/core/commands/triwiki-command.js +12 -1
- package/dist/core/doctor/doctor-dirty-planner.js +16 -1
- package/dist/core/doctor/doctor-idempotence.js +11 -0
- package/dist/core/doctor/doctor-repair-postcheck.js +49 -0
- package/dist/core/doctor/doctor-transaction.js +47 -2
- package/dist/core/doctor/legacy-global-hook-cleanup.js +1 -1
- package/dist/core/fsx.js +14 -0
- package/dist/core/git-hygiene/git-policy.js +4 -0
- package/dist/core/git-hygiene/gitignore-writer.js +2 -0
- package/dist/core/gx-renderer.js +2 -1
- package/dist/core/init.js +40 -17
- package/dist/core/managed-paths.js +1 -0
- package/dist/core/perf/release-latency-slo.js +57 -11
- package/dist/core/pipeline-internals/pipeline-stage-builder.js +181 -0
- package/dist/core/pipeline-internals/runtime-core.js +18 -172
- package/dist/core/pipeline-internals/runtime-gates.js +12 -1
- package/dist/core/release/content-digest-cache.js +70 -0
- package/dist/core/release/gate-manifest.js +9 -0
- package/dist/core/release/main-push-guard.js +4 -3
- package/dist/core/release/package-dist-snapshot.js +18 -2
- package/dist/core/release/physical-release-gates.js +26 -3
- package/dist/core/release/release-authorization-snapshot.js +4 -0
- package/dist/core/release/release-gate-cache-v2.js +27 -3
- package/dist/core/release/release-gate-contract.js +2 -0
- package/dist/core/release/release-gate-dag.js +3 -0
- package/dist/core/release/release-inspection-memo.js +69 -0
- package/dist/core/release/release-pack-content-scanner.js +5 -0
- package/dist/core/release/release-pack-receipt.js +28 -18
- package/dist/core/release/release-pack-tarball.js +10 -0
- package/dist/core/release/release-upgrade-baseline.js +4 -0
- package/dist/core/routes.js +1 -1
- package/dist/core/safety/ssot-authority-inventory.js +114 -0
- package/dist/core/safety/ssot-guard.js +2 -44
- package/dist/core/subagents/agent-catalog.js +4 -2
- package/dist/core/subagents/official-subagent-config.js +92 -15
- package/dist/core/subagents/official-subagent-preparation.js +1 -0
- package/dist/core/triwiki/context-graph/architecture/baseline.js +81 -0
- package/dist/core/triwiki/context-graph/architecture/capsule.js +34 -0
- package/dist/core/triwiki/context-graph/architecture/contracts.js +67 -0
- package/dist/core/triwiki/context-graph/architecture/delta.js +149 -0
- package/dist/core/triwiki/context-graph/architecture/finding-factory.js +28 -0
- package/dist/core/triwiki/context-graph/architecture/findings.js +173 -0
- package/dist/core/triwiki/context-graph/architecture/fingerprint.js +75 -0
- package/dist/core/triwiki/context-graph/architecture/index.js +15 -0
- package/dist/core/triwiki/context-graph/architecture/input-bundle.js +66 -0
- package/dist/core/triwiki/context-graph/architecture/metrics.js +137 -0
- package/dist/core/triwiki/context-graph/architecture/policy.js +321 -0
- package/dist/core/triwiki/context-graph/architecture/slice.js +100 -0
- package/dist/core/triwiki/context-graph/architecture/ssot-analysis.js +59 -0
- package/dist/core/triwiki/context-graph/architecture/topology-overlay.js +106 -0
- package/dist/core/triwiki/context-graph/architecture/validation.js +145 -0
- package/dist/core/triwiki/context-graph/architecture/voxel-context.js +39 -0
- package/dist/core/triwiki/context-graph/extractors/index.js +4 -0
- package/dist/core/triwiki/context-graph/projections/index.js +2 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/architecture-delta.js +68 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/ast.js +49 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/change-impact.js +43 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/contracts.js +5 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/escape.js +45 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/ids.js +73 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/index.js +113 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/manifest.js +37 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/module-dependency.js +21 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/ownership-workstream.js +21 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/project-topology.js +13 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/public-surface.js +17 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/reduce.js +44 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/risk-domains.js +23 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/runtime-control.js +20 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/selection-ledger.js +94 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/serializer.js +81 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/ssot-provenance.js +17 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/verification-coverage.js +17 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/view-builder-common.js +1 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/view-builder.js +173 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/view-specs.js +33 -0
- package/dist/core/triwiki/context-graph/store/architecture-map-store.js +71 -0
- package/dist/core/triwiki/triwiki-proof-bank-index.js +26 -1
- package/dist/core/triwiki/triwiki-proof-bank.js +82 -2
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/OverviewViewController.swift +2 -2
- package/dist/native/sks-menubar/Sources/ProvidersModelExposure.swift +178 -0
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +10 -1
- package/dist/scripts/architecture-map-check.js +299 -0
- package/dist/scripts/lib/ensure-dist-fresh.js +48 -1
- package/dist/scripts/release-metadata-check.js +2 -0
- package/package.json +6 -3
- package/release-gates.v2.json +204 -0
- package/schemas/architecture-baseline.v1.schema.json +47 -0
- package/schemas/architecture-map-manifest.v1.schema.json +40 -0
- package/schemas/architecture-map-policy.v1.schema.json +147 -0
- package/schemas/architecture-review.v1.schema.json +46 -0
- 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
|
package/dist/core/gx-renderer.js
CHANGED
|
@@ -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
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
};
|
|
946
|
-
|
|
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(
|
|
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(
|
|
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
|
|
173
|
-
const
|
|
174
|
-
|
|
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:
|
|
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
|
+
}
|