sneakoscope 8.3.2 → 8.4.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 +33 -1
- 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 +172 -0
- package/dist/core/architecture-map-review.js +180 -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-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-controller-v3/catalog.js +75 -4
- package/dist/core/codex-lb/desktop-controller-v3.js +5 -1
- package/dist/core/commands/triwiki-atlas-command.js +372 -0
- package/dist/core/commands/triwiki-command.js +12 -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/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 +13 -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/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
|
@@ -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
|
+
}
|
|
@@ -38,7 +38,10 @@ import { NARUTO_GATE_FILENAME, NARUTO_SUMMARY_FILENAME, SUBAGENT_PLAN_FILENAME,
|
|
|
38
38
|
import { buildSubagentEvidence, readSubagentEvents, recordSubagentEvent, SUBAGENT_EVIDENCE_FILENAME, SUBAGENT_EVENT_LOG_FILENAME, SUBAGENT_PARENT_SUMMARY_FILENAME } from '../subagents/subagent-evidence.js';
|
|
39
39
|
import { effectiveSubagentTarget, normalizeLegacySubagentCountFields, subagentCountContractBlockers } from '../subagents/wave-lifecycle.js';
|
|
40
40
|
import { officialSubagentEvidenceReady } from '../subagents/terminal-subagent-state.js';
|
|
41
|
+
import { createArchitectureMapPlanBinding, maybeSeedArchitectureMapForPlan, planStagesArchitectureMap } from '../architecture-map-pipeline.js';
|
|
42
|
+
import { BLOCKING_GATE_LIMITS, LIGHTWEIGHT_ROUTES, GATE_PROFILE_STAGES, STAGE_BLOCKING_GATE, selectPipelineLane, buildPipelineStages, planVerification, pipelineInvariants } from './pipeline-stage-builder.js';
|
|
41
43
|
export { routePrompt };
|
|
44
|
+
export { LIGHTWEIGHT_ROUTES, GATE_PROFILE_STAGES, STAGE_BLOCKING_GATE, BLOCKING_GATE_LIMITS };
|
|
42
45
|
export const PIPELINE_PLAN_ARTIFACT = 'pipeline-plan.json';
|
|
43
46
|
export const PIPELINE_PLAN_SCHEMA_VERSION = 1;
|
|
44
47
|
const SKILL_DREAM_HOT_PATH_COUNTERS = new Map();
|
|
@@ -60,44 +63,6 @@ const HARD_BLOCKER_ARTIFACT = 'hard-blocker.json';
|
|
|
60
63
|
const DEFAULT_COMPLIANCE_LOOP_LIMIT = 3;
|
|
61
64
|
const CLARIFICATION_BYPASS_ROUTES = new Set(['Answer', 'DFix', 'Help', 'Wiki', 'ComputerUse', 'Goal']);
|
|
62
65
|
const QUESTION_GATE_ROUTES = new Set(['QALoop', 'PPT']);
|
|
63
|
-
const LIGHTWEIGHT_ROUTES = new Set(['Answer', 'DFix', 'Help', 'Wiki', 'Goal']);
|
|
64
|
-
const GATE_PROFILE_STAGES = Object.freeze({
|
|
65
|
-
none: [],
|
|
66
|
-
minimal: ['route_classification', 'listed_verification'],
|
|
67
|
-
scoped: ['route_classification', 'ownership', 'listed_verification', 'honest_summary'],
|
|
68
|
-
full: ['route_classification', 'ambiguity_gate', 'safety_gate', 'ownership', 'listed_verification', 'honest_summary']
|
|
69
|
-
});
|
|
70
|
-
const STAGE_BLOCKING_GATE = Object.freeze({
|
|
71
|
-
ambiguity_gate: 'scope',
|
|
72
|
-
safety_gate: 'safety',
|
|
73
|
-
ssot_guard: 'safety',
|
|
74
|
-
context7_evidence: 'safety',
|
|
75
|
-
mistake_recall: 'safety',
|
|
76
|
-
ownership: 'ownership',
|
|
77
|
-
pipeline_plan: 'ownership',
|
|
78
|
-
focused_implementation: 'ownership',
|
|
79
|
-
triwiki_use_first: 'ownership',
|
|
80
|
-
subagent_plan: 'ownership',
|
|
81
|
-
official_subagent_execution: 'ownership',
|
|
82
|
-
parent_integration: 'ownership',
|
|
83
|
-
route_materialization: 'ownership',
|
|
84
|
-
work_order_coverage: 'ownership',
|
|
85
|
-
engineering_sanity_check: 'verification',
|
|
86
|
-
listed_verification: 'verification',
|
|
87
|
-
triwiki_validate_before_final: 'verification',
|
|
88
|
-
completion_proof: 'verification',
|
|
89
|
-
reflection: 'verification',
|
|
90
|
-
honest_summary: 'verification'
|
|
91
|
-
});
|
|
92
|
-
const BLOCKING_GATE_LIMITS = Object.freeze({
|
|
93
|
-
passthrough: 0,
|
|
94
|
-
answer: 0,
|
|
95
|
-
'tiny-change': 1,
|
|
96
|
-
'bounded-work': 2,
|
|
97
|
-
'parallel-read': 2,
|
|
98
|
-
'parallel-write': 3,
|
|
99
|
-
'high-risk': 4
|
|
100
|
-
});
|
|
101
66
|
function reflectionInstructionText(commandPrefix = 'sks') {
|
|
102
67
|
return `Post-route reflection: full routes load \`reflection\` after work/tests and before final; DFix/Answer/Help/Wiki/SKS discovery are exempt. Write ${REFLECTION_ARTIFACT}; record only real misses/gaps, or no_issue_acknowledged. For lessons, append TriWiki claim rows to ${REFLECTION_MEMORY_PATH}. Run "${commandPrefix} wiki refresh" or pack, validate, then pass ${REFLECTION_GATE}.`;
|
|
103
68
|
}
|
|
@@ -182,6 +147,7 @@ export function buildPipelinePlan(input = {}) {
|
|
|
182
147
|
verification_budget: verificationBudget,
|
|
183
148
|
verification,
|
|
184
149
|
engineering_sanity_review: null,
|
|
150
|
+
architecture_map: null,
|
|
185
151
|
invariants,
|
|
186
152
|
proof_field: proof,
|
|
187
153
|
ssot_guard: buildSsotGuard({ route: route?.id || 'SKS', mode: route?.mode || 'SKS', task }),
|
|
@@ -219,6 +185,9 @@ export async function writePipelinePlan(dir, input = {}) {
|
|
|
219
185
|
changed_scope_base: resolveChangedScopeBase(root)
|
|
220
186
|
};
|
|
221
187
|
}
|
|
188
|
+
if (planStagesArchitectureMap(plan)) {
|
|
189
|
+
plan.architecture_map = createArchitectureMapPlanBinding();
|
|
190
|
+
}
|
|
222
191
|
await writeJsonAtomic(path.join(dir, PIPELINE_PLAN_ARTIFACT), plan);
|
|
223
192
|
if (plan.engineering_sanity_review) {
|
|
224
193
|
const report = await writeCodeStructureReport(root, dir, {
|
|
@@ -232,6 +201,9 @@ export async function writePipelinePlan(dir, input = {}) {
|
|
|
232
201
|
await writeJsonAtomic(reviewFile, createEngineeringSanityReviewSeed(plan.route?.command || plan.route?.id || null, report, reportText));
|
|
233
202
|
}
|
|
234
203
|
}
|
|
204
|
+
await maybeSeedArchitectureMapForPlan({
|
|
205
|
+
root, dir, plan, missionId: input.missionId, taskProfile
|
|
206
|
+
});
|
|
235
207
|
return plan;
|
|
236
208
|
}
|
|
237
209
|
function planStagesEngineeringSanityReview(plan) {
|
|
@@ -244,7 +216,8 @@ export function pipelinePlanState(plan) {
|
|
|
244
216
|
pipeline_plan_ready: validatePipelinePlan(plan).ok,
|
|
245
217
|
pipeline_plan_path: PIPELINE_PLAN_ARTIFACT,
|
|
246
218
|
engineering_sanity_required: Boolean(sanity),
|
|
247
|
-
engineering_sanity_scope_base: sanity?.changed_scope_base || null
|
|
219
|
+
engineering_sanity_scope_base: sanity?.changed_scope_base || null,
|
|
220
|
+
architecture_map_required: Boolean(plan?.architecture_map)
|
|
248
221
|
};
|
|
249
222
|
}
|
|
250
223
|
export async function writeRequestIntakeArtifact(dir, input = {}) {
|
|
@@ -488,130 +461,6 @@ function routeEconomyPlan(proof = {}) {
|
|
|
488
461
|
deletion_policy: 'do_not_delete_or_skip_pipeline_stages_until_report_only_metrics_are_calibrated'
|
|
489
462
|
};
|
|
490
463
|
}
|
|
491
|
-
function selectPipelineLane(route, task, proof, taskProfile = classifyTaskProfile(task)) {
|
|
492
|
-
if (proof.attached && proof.lane) {
|
|
493
|
-
return {
|
|
494
|
-
lane: proof.lane,
|
|
495
|
-
source: 'proof_field',
|
|
496
|
-
fast_lane_allowed: Boolean(proof.fast_lane_allowed),
|
|
497
|
-
reason: proof.fast_lane_allowed ? 'Proof Field allowed the fast lane.' : `Proof Field selected ${proof.lane}.`,
|
|
498
|
-
blockers: proof.blockers || [],
|
|
499
|
-
skip_when_fast: proof.fast_lane_allowed ? SPEED_LANE_POLICY.skip_when_fast : [],
|
|
500
|
-
keep: proof.keep || SPEED_LANE_POLICY.always_keep
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
if (taskProfile === 'passthrough' || taskProfile === 'answer')
|
|
504
|
-
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: [] };
|
|
505
|
-
if (route?.id === 'ComputerUse')
|
|
506
|
-
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'] };
|
|
507
|
-
if (taskProfile === 'tiny-change')
|
|
508
|
-
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'] };
|
|
509
|
-
if (LIGHTWEIGHT_ROUTES.has(route?.id))
|
|
510
|
-
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'] };
|
|
511
|
-
if (routeRequiresSubagents(route, task, taskProfile))
|
|
512
|
-
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'] };
|
|
513
|
-
if (taskProfile === 'high-risk')
|
|
514
|
-
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 };
|
|
515
|
-
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 };
|
|
516
|
-
}
|
|
517
|
-
function buildPipelineStages(route, task, taskProfile, gateProfile, ambiguity, lane, context7Required, officialSubagentPolicy = normalizeOfficialSubagentPolicy(route, task, {})) {
|
|
518
|
-
if (gateProfile === 'none')
|
|
519
|
-
return [];
|
|
520
|
-
const ids = [...GATE_PROFILE_STAGES[gateProfile]];
|
|
521
|
-
const specializedRoute = Boolean(route?.id && !LIGHTWEIGHT_ROUTES.has(route.id) && route.id !== 'SKS');
|
|
522
|
-
if (gateProfile === 'scoped' || gateProfile === 'full' || specializedRoute)
|
|
523
|
-
ids.push('pipeline_plan', 'focused_implementation');
|
|
524
|
-
if ((gateProfile === 'full' || specializedRoute) && !ids.includes('ssot_guard'))
|
|
525
|
-
ids.push('ssot_guard');
|
|
526
|
-
if (context7Required)
|
|
527
|
-
ids.push('context7_evidence');
|
|
528
|
-
if ((gateProfile === 'scoped' || gateProfile === 'full') && !LIGHTWEIGHT_ROUTES.has(route?.id)) {
|
|
529
|
-
ids.push('triwiki_use_first', 'triwiki_validate_before_final', 'mistake_recall', 'work_order_coverage');
|
|
530
|
-
}
|
|
531
|
-
if (routeNeedsEngineeringSanityReview(route, task))
|
|
532
|
-
ids.push('engineering_sanity_check');
|
|
533
|
-
if (routeRequiresSubagents(route, task, taskProfile))
|
|
534
|
-
ids.push('subagent_plan', 'official_subagent_execution', 'parent_integration');
|
|
535
|
-
if (specializedRoute)
|
|
536
|
-
ids.push('route_materialization');
|
|
537
|
-
if (specializedRoute)
|
|
538
|
-
ids.push('completion_proof');
|
|
539
|
-
if (reflectionRequiredForRoute(route))
|
|
540
|
-
ids.push('reflection');
|
|
541
|
-
return [...new Set(ids)].map((id) => {
|
|
542
|
-
const configuredGate = STAGE_BLOCKING_GATE[id] || null;
|
|
543
|
-
const blockingGate = configuredGate === 'safety' && gateProfile !== 'full'
|
|
544
|
-
? 'ownership'
|
|
545
|
-
: configuredGate;
|
|
546
|
-
const blocking = Boolean(blockingGate);
|
|
547
|
-
const metadata = { blocking, blocking_gate: blocking ? blockingGate : null };
|
|
548
|
-
if (id === OFFICIAL_SUBAGENT_EXECUTION_STAGE_ID)
|
|
549
|
-
return { ...officialSubagentPipelineStage(officialSubagentPolicy), status: 'required', reason: officialSubagentPolicy.reason, ...metadata };
|
|
550
|
-
if (id === 'engineering_sanity_check') {
|
|
551
|
-
return {
|
|
552
|
-
id,
|
|
553
|
-
status: 'keep',
|
|
554
|
-
reason: 'required_for_code_and_database_quality',
|
|
555
|
-
checks: [
|
|
556
|
-
'trace actual callers and preserve basic SOLID responsibility and dependency boundaries',
|
|
557
|
-
'inspect loops, collections, resolvers, and serializers for N+1 or repeated I/O',
|
|
558
|
-
'prove render, recursion, event, retry, and polling loops are bounded and cancellable',
|
|
559
|
-
'reject disabled checks, swallowed errors, placeholder success, and verification bypasses',
|
|
560
|
-
'for DB work, verify the existing canonical adapter and connection/pool lifecycle before changes',
|
|
561
|
-
'for sensitive or multi-step DB work, verify transaction rollback, error propagation, idempotency, and post-commit invariants'
|
|
562
|
-
],
|
|
563
|
-
...metadata
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
if (id === 'ambiguity_gate' && ambiguity?.required === false)
|
|
567
|
-
return { id, status: 'not_applicable', reason: 'ambiguity_gate_not_required_for_entrypoint', ...metadata };
|
|
568
|
-
if (id === 'ambiguity_gate' && ambiguity?.passed)
|
|
569
|
-
return { id, status: 'passed', reason: 'ambiguity_contract_already_sealed', ...metadata };
|
|
570
|
-
return { id, status: 'keep', reason: lane.fast_lane_allowed ? 'task_profile_minimal_lane' : 'required_by_task_and_route_profile', ...metadata };
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
function planVerification(route, task, proof, budget) {
|
|
574
|
-
if (budget === 'none')
|
|
575
|
-
return [];
|
|
576
|
-
const out = new Set(proof.verification || []);
|
|
577
|
-
if (budget === 'single-check')
|
|
578
|
-
out.add('run one focused check for the changed surface');
|
|
579
|
-
if (budget === 'affected')
|
|
580
|
-
out.add('run affected tests or checks for changed files');
|
|
581
|
-
if (budget === 'confidence') {
|
|
582
|
-
out.add('run the focused build or typecheck for the affected package');
|
|
583
|
-
out.add('run affected regression tests and the risk-specific safety check');
|
|
584
|
-
}
|
|
585
|
-
if (budget === 'release') {
|
|
586
|
-
out.add('npm run packcheck');
|
|
587
|
-
out.add('sks selftest --mock --json');
|
|
588
|
-
}
|
|
589
|
-
if (route?.id === 'Naruto')
|
|
590
|
-
out.add('validate official subagent evidence and the parent integration summary');
|
|
591
|
-
if (routeNeedsEngineeringSanityReview(route, task)) {
|
|
592
|
-
out.add('complete the engineering sanity review for SOLID boundaries, N+1/repeated I/O, bounded loops, and verification bypasses');
|
|
593
|
-
}
|
|
594
|
-
if (route?.id === 'DB' || route?.id === 'MadSKS') {
|
|
595
|
-
out.add('verify existing canonical DB access, pool lifecycle, and transaction integrity for sensitive or multi-step mutations');
|
|
596
|
-
}
|
|
597
|
-
if (reflectionRequiredForRoute(route))
|
|
598
|
-
out.add('sks wiki validate .sneakoscope/wiki/context-pack.json');
|
|
599
|
-
return [...out];
|
|
600
|
-
}
|
|
601
|
-
function pipelineInvariants(input) {
|
|
602
|
-
const out = ['no_unrequested_fallback_code'];
|
|
603
|
-
if (input.stages.some((stage) => stage.id === 'engineering_sanity_check'))
|
|
604
|
-
out.push('engineering_sanity_check');
|
|
605
|
-
if (input.verificationBudget !== 'none')
|
|
606
|
-
out.push('listed_verification');
|
|
607
|
-
if (input.stages.some((stage) => stage.id === 'ssot_guard' && stage.status !== 'not_applicable'))
|
|
608
|
-
out.push('ssot_guard');
|
|
609
|
-
if (input.stages.some((stage) => stage.id === 'triwiki_validate_before_final'))
|
|
610
|
-
out.push('triwiki_validate_before_final');
|
|
611
|
-
if (input.gateProfile !== 'none')
|
|
612
|
-
out.push('honest_summary');
|
|
613
|
-
return out;
|
|
614
|
-
}
|
|
615
464
|
function planNextActions(route, task, taskProfile, ambiguity, lane) {
|
|
616
465
|
if (taskProfile === 'passthrough' || taskProfile === 'answer')
|
|
617
466
|
return [];
|
|
@@ -1593,15 +1442,7 @@ function strictNarutoIntegerOption(text, option) {
|
|
|
1593
1442
|
function routeState(id, route, phase, context7Required, extra = {}) {
|
|
1594
1443
|
const reasoning = routeReasoning(route, extra.prompt || '');
|
|
1595
1444
|
const subagentsRequired = routeRequiresSubagents(route, extra.prompt || '');
|
|
1596
|
-
return { mission_id: id, route: route.id, route_command: route.command, mode: route.mode, phase, context7_required: context7Required, context7_verified: false, subagents_required: subagentsRequired, subagents_verified: !subagentsRequired, native_sessions_required: false, native_sessions_verified: false, reflection_required: reflectionRequiredForRoute(route), engineering_sanity_required: false, engineering_sanity_scope_base: null, visible_progress_required: true, context_tracking: 'triwiki', required_skills: route.requiredSkills, stop_gate: route.stopGate, reasoning_effort: reasoning.effort, reasoning_profile: reasoning.profile, reasoning_temporary: true, goal_continuation: ambientGoalContinuation(), ...extra };
|
|
1597
|
-
}
|
|
1598
|
-
function routeNeedsEngineeringSanityReview(route, task) {
|
|
1599
|
-
const id = String(route?.id || '');
|
|
1600
|
-
if (['DB', 'MadSKS'].includes(id))
|
|
1601
|
-
return true;
|
|
1602
|
-
if (['Answer', 'Help', 'Wiki', 'Goal', 'Research', 'AutoResearch', 'PPT', 'ImageUXReview', 'ComputerUse', 'GX'].includes(id))
|
|
1603
|
-
return false;
|
|
1604
|
-
return looksLikeCodeChangingWork(String(task || ''));
|
|
1445
|
+
return { mission_id: id, route: route.id, route_command: route.command, mode: route.mode, phase, context7_required: context7Required, context7_verified: false, subagents_required: subagentsRequired, subagents_verified: !subagentsRequired, native_sessions_required: false, native_sessions_verified: false, reflection_required: reflectionRequiredForRoute(route), engineering_sanity_required: false, engineering_sanity_scope_base: null, architecture_map_required: false, visible_progress_required: true, context_tracking: 'triwiki', required_skills: route.requiredSkills, stop_gate: route.stopGate, reasoning_effort: reasoning.effort, reasoning_profile: reasoning.profile, reasoning_temporary: true, goal_continuation: ambientGoalContinuation(), ...extra };
|
|
1605
1446
|
}
|
|
1606
1447
|
function routeContext(route, id, task, required, next) {
|
|
1607
1448
|
const visibleTask = stripVisibleDecisionAnswerBlocks(task);
|
|
@@ -17,6 +17,8 @@ import { checkStopGate } from '../stop-gate/stop-gate-check.js';
|
|
|
17
17
|
import { readWorkOrderLedger, evaluateWorkOrderCoverage } from '../work-order-ledger.js';
|
|
18
18
|
import { DB_ACCESS_REVIEW_ARTIFACT, DB_REVIEW_ARTIFACT, validateDbAccessReviewArtifact, validateDbReview, validateMadSksSqlPlaneCompletion } from '../db-review.js';
|
|
19
19
|
import { ENGINEERING_SANITY_REVIEW_ARTIFACT, validateEngineeringSanityReviewArtifact } from '../engineering-sanity-review.js';
|
|
20
|
+
import { ARCHITECTURE_MAP_REVIEW_ARTIFACT } from '../architecture-map-review.js';
|
|
21
|
+
import { architectureMapGateStatus } from '../architecture-map-pipeline.js';
|
|
20
22
|
import { clarificationStopReason, context7Evidence, hasContext7DocsEvidence, hasSubagentEvidence, subagentEvidence, PIPELINE_PLAN_ARTIFACT, } from './runtime-core.js';
|
|
21
23
|
import { projectTriwikiToAgentsMd } from '../triwiki/agents-md-projector.js';
|
|
22
24
|
import { effectiveSubagentTarget, normalizeLegacySubagentCountFields, subagentCountContractBlockers } from '../subagents/wave-lifecycle.js';
|
|
@@ -256,6 +258,7 @@ export async function evaluateStop(root, state, payload, opts = {}) {
|
|
|
256
258
|
&& !completionProofRequired
|
|
257
259
|
&& !reflectionRequired
|
|
258
260
|
&& state?.engineering_sanity_required !== true
|
|
261
|
+
&& state?.architecture_map_required !== true
|
|
259
262
|
&& state?.db_access_review_required !== true) {
|
|
260
263
|
return null;
|
|
261
264
|
}
|
|
@@ -267,12 +270,14 @@ export async function evaluateStop(root, state, payload, opts = {}) {
|
|
|
267
270
|
&& activeGatePreview?.covered_gate === 'official-subagent-evidence';
|
|
268
271
|
const dbAccessPromise = dbAccessReviewGateStatus(root, state, jsonCache);
|
|
269
272
|
const engineeringSanityPromise = engineeringSanityGateStatus(root, state, jsonCache);
|
|
273
|
+
const architectureMapPromise = architectureMapGateStatus(root, state);
|
|
270
274
|
const context7Promise = state?.context7_required ? hasContext7DocsEvidence(root, state) : Promise.resolve(true);
|
|
271
275
|
const subagentPromise = state?.subagents_required && !activeGateNotApplicable ? hasSubagentEvidence(root, state) : Promise.resolve(true);
|
|
272
276
|
const mistakeRecallPromise = mistakeRecallGateStatus(root, state);
|
|
273
|
-
const [dbAccess, engineeringSanity, context7Ok, subagentOk, mistakeRecall] = await Promise.all([
|
|
277
|
+
const [dbAccess, engineeringSanity, architectureMap, context7Ok, subagentOk, mistakeRecall] = await Promise.all([
|
|
274
278
|
dbAccessPromise,
|
|
275
279
|
engineeringSanityPromise,
|
|
280
|
+
architectureMapPromise,
|
|
276
281
|
context7Promise,
|
|
277
282
|
subagentPromise,
|
|
278
283
|
mistakeRecallPromise
|
|
@@ -280,6 +285,7 @@ export async function evaluateStop(root, state, payload, opts = {}) {
|
|
|
280
285
|
await resolveRecoveredComplianceBlocker(root, state, {
|
|
281
286
|
[DB_ACCESS_REVIEW_ARTIFACT]: dbAccess.ok,
|
|
282
287
|
[ENGINEERING_SANITY_REVIEW_ARTIFACT]: engineeringSanity.ok,
|
|
288
|
+
[ARCHITECTURE_MAP_REVIEW_ARTIFACT]: architectureMap.ok,
|
|
283
289
|
'context7-evidence': context7Ok,
|
|
284
290
|
'official-subagent-evidence': subagentOk
|
|
285
291
|
});
|
|
@@ -289,6 +295,9 @@ export async function evaluateStop(root, state, payload, opts = {}) {
|
|
|
289
295
|
if (!engineeringSanity.ok) {
|
|
290
296
|
return complianceBlock(root, state, `SKS ${state.route_command || state.mode || 'route'} must complete the engineering sanity review before completion. Static candidates are advisory only; inspect added hunks and real callers for SOLID boundaries, N+1/repeated I/O, bounded render/recursion/event/retry/polling behavior, and verification bypasses. Missing: ${(engineeringSanity.blockers || []).join(', ')}.`, { gate: ENGINEERING_SANITY_REVIEW_ARTIFACT, missing: engineeringSanity.blockers });
|
|
291
297
|
}
|
|
298
|
+
if (!architectureMap.ok) {
|
|
299
|
+
return complianceBlock(root, state, `SKS ${state.route_command || state.mode || 'route'} must seal Architecture Map baseline before mutation and produce a passing architecture-map-review before completion. Missing: ${(architectureMap.blockers || []).join(', ')}.`, { gate: ARCHITECTURE_MAP_REVIEW_ARTIFACT, missing: architectureMap.blockers });
|
|
300
|
+
}
|
|
292
301
|
if (state?.context7_required && !context7Ok) {
|
|
293
302
|
return complianceBlock(root, state, `SKS ${state.route_command || state.mode || 'route'} requires Context7 evidence before completion. Use Context7 resolve-library-id, then query-docs, so SKS can record context7-evidence.jsonl.`, { gate: 'context7-evidence' });
|
|
294
303
|
}
|
|
@@ -518,6 +527,8 @@ async function markReflectionInvalidatedForGateFailure(root, state = {}, detail
|
|
|
518
527
|
return;
|
|
519
528
|
if (/^work-order-ledger$/i.test(gate) || /^completion-proof$/i.test(gate))
|
|
520
529
|
return;
|
|
530
|
+
if (/^atlas:/.test(gate) || /^architecture-map:/.test(gate) || /(^|[\\/])?(architecture-atlas-review|architecture-map-review|atlas-gate)(\.json)?$/i.test(gate))
|
|
531
|
+
return;
|
|
521
532
|
await setCurrent(root, {
|
|
522
533
|
mission_id: state.mission_id,
|
|
523
534
|
reflection_invalidation_required: true,
|