zob-harness 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/.pi/capabilities/zob-public-runtime-capabilities.json +16 -17
  2. package/.pi/extensions/zob-harness/index.ts +1 -1
  3. package/.pi/extensions/zob-harness/src/domains/autonomy/autonomous-runtime/dry-run.ts +1107 -0
  4. package/.pi/extensions/zob-harness/src/domains/autonomy/autonomous-runtime/report-writers.ts +325 -0
  5. package/.pi/extensions/zob-harness/src/domains/autonomy/autonomous-runtime/smoke-run.ts +1286 -0
  6. package/.pi/extensions/zob-harness/src/domains/autonomy/autonomous-runtime/types.ts +30 -0
  7. package/.pi/extensions/zob-harness/src/domains/autonomy/autonomous-runtime/validation.ts +184 -0
  8. package/.pi/extensions/zob-harness/src/domains/autonomy/autonomous-runtime.ts +4 -2912
  9. package/.pi/extensions/zob-harness/src/domains/compute/compute-profile.ts +2 -1
  10. package/.pi/extensions/zob-harness/src/domains/coms/coms-v2/registry.ts +24 -3
  11. package/.pi/extensions/zob-harness/src/domains/coms/coms-v2/types.ts +1 -0
  12. package/.pi/extensions/zob-harness/src/domains/coms/coms-v2/zpeer.ts +5 -3
  13. package/.pi/extensions/zob-harness/src/domains/delegation/child-runner.ts +28 -3
  14. package/.pi/extensions/zob-harness/src/domains/goal/goal-todos/constants.ts +19 -0
  15. package/.pi/extensions/zob-harness/src/domains/goal/goal-todos/formatting.ts +148 -0
  16. package/.pi/extensions/zob-harness/src/domains/goal/goal-todos/normalize.ts +476 -0
  17. package/.pi/extensions/zob-harness/src/domains/goal/goal-todos/operations.ts +393 -0
  18. package/.pi/extensions/zob-harness/src/domains/goal/goal-todos/parsing.ts +277 -0
  19. package/.pi/extensions/zob-harness/src/domains/goal/goal-todos/reducer.ts +110 -0
  20. package/.pi/extensions/zob-harness/src/domains/goal/goal-todos.ts +6 -1429
  21. package/.pi/extensions/zob-harness/src/domains/governance/governed-requests.ts +3 -1
  22. package/.pi/extensions/zob-harness/src/domains/governance/merge-queue.ts +3 -1
  23. package/.pi/extensions/zob-harness/src/domains/governance/sandbox/helpers.ts +124 -0
  24. package/.pi/extensions/zob-harness/src/domains/governance/sandbox/runners.ts +444 -0
  25. package/.pi/extensions/zob-harness/src/domains/governance/sandbox/simulation.ts +569 -0
  26. package/.pi/extensions/zob-harness/src/domains/governance/sandbox/types.ts +127 -0
  27. package/.pi/extensions/zob-harness/src/domains/governance/sandbox/validation.ts +273 -0
  28. package/.pi/extensions/zob-harness/src/domains/governance/sandbox.ts +4 -1508
  29. package/.pi/extensions/zob-harness/src/domains/governance/worker-pool.ts +3 -1
  30. package/.pi/extensions/zob-harness/src/domains/governance/workspace-claims.ts +3 -1
  31. package/.pi/extensions/zob-harness/src/domains/orchestration/room.ts +8 -2
  32. package/.pi/extensions/zob-harness/src/domains/promotion/coms.ts +8 -1
  33. package/.pi/extensions/zob-harness/src/runtime/commands/autonomy.ts +188 -0
  34. package/.pi/extensions/zob-harness/src/runtime/commands/compute.ts +165 -0
  35. package/.pi/extensions/zob-harness/src/runtime/commands/daemon.ts +191 -0
  36. package/.pi/extensions/zob-harness/src/runtime/commands/delegates.ts +47 -0
  37. package/.pi/extensions/zob-harness/src/runtime/commands/goal.ts +70 -0
  38. package/.pi/extensions/zob-harness/src/runtime/commands/intent.ts +383 -0
  39. package/.pi/extensions/zob-harness/src/runtime/commands/misc.ts +229 -0
  40. package/.pi/extensions/zob-harness/src/runtime/commands/project-dna.ts +130 -0
  41. package/.pi/extensions/zob-harness/src/runtime/commands/types.ts +3 -0
  42. package/.pi/extensions/zob-harness/src/runtime/commands/zcommit.ts +145 -0
  43. package/.pi/extensions/zob-harness/src/runtime/commands/zlive.ts +1606 -0
  44. package/.pi/extensions/zob-harness/src/runtime/commands/zmode.ts +42 -0
  45. package/.pi/extensions/zob-harness/src/runtime/commands.ts +26 -3109
  46. package/.pi/extensions/zob-harness/src/runtime/events.ts +67 -33
  47. package/.pi/extensions/zob-harness/src/runtime/goal-runtime/commands.ts +194 -0
  48. package/.pi/extensions/zob-harness/src/runtime/goal-runtime/events.ts +81 -0
  49. package/.pi/extensions/zob-harness/src/runtime/goal-runtime/state.ts +662 -0
  50. package/.pi/extensions/zob-harness/src/runtime/goal-runtime/tools.ts +1005 -0
  51. package/.pi/extensions/zob-harness/src/runtime/goal-runtime.ts +5 -1949
  52. package/.pi/extensions/zob-harness/src/runtime/tools-delegation/helpers.ts +786 -0
  53. package/.pi/extensions/zob-harness/src/runtime/tools-delegation/register.ts +1120 -0
  54. package/.pi/extensions/zob-harness/src/runtime/tools-delegation/types.ts +77 -0
  55. package/.pi/extensions/zob-harness/src/runtime/tools-delegation.ts +1 -1904
  56. package/.pi/extensions/zob-harness/src/runtime/zob-intro.ts +46 -15
  57. package/.pi/factories/project-dna/batch-manifest.json +1 -1
  58. package/.pi/factories/project-dna/pilot-manifest.json +1 -1
  59. package/.pi/factories/project-dna/smoke-manifest.json +1 -1
  60. package/README.md +29 -8
  61. package/package.json +14 -5
  62. package/scripts/git-ops/commit-policy-smoke.mjs +33 -6
  63. package/scripts/goal-todo/child-goal-ref-smoke.mjs +30 -3
  64. package/scripts/goal-todo/handoff-static-smoke.mjs +31 -3
  65. package/scripts/harness-intake/lib/cli-io.mjs +89 -0
  66. package/scripts/harness-intake/lib/constants.mjs +59 -0
  67. package/scripts/harness-intake/lib/infer-spec.mjs +127 -0
  68. package/scripts/harness-intake/lib/profiles.mjs +458 -0
  69. package/scripts/harness-intake/lib/run-init.mjs +307 -0
  70. package/scripts/harness-intake/lib/scan.mjs +266 -0
  71. package/scripts/harness-intake/lib/tmux.mjs +92 -0
  72. package/scripts/harness-intake/lib/validate.mjs +152 -0
  73. package/scripts/harness-intake/lib.mjs +8 -1521
  74. package/scripts/harness-switch/static-smoke.mjs +1 -1
  75. package/scripts/model-catalog/validate-economy.mjs +3 -1
  76. package/scripts/model-catalog/validate.mjs +3 -1
  77. package/scripts/project-dna/scan/scan.mjs +5 -2
  78. package/scripts/project-dna/scan/validate-scan-artifacts.mjs +3 -1
  79. package/scripts/project-dna/validation/validate-ontology.mjs +3 -1
  80. package/scripts/project-dna/validation/validate-scaffold.mjs +2 -2
  81. package/scripts/zagent-static-smoke.mjs +30 -2
  82. package/scripts/zpeer-local-e2e-smoke.mjs +18 -0
  83. package/scripts/zpeer-static-smoke.mjs +40 -5
  84. package/scripts/zteam-hot-add/smoke.mjs +30 -2
@@ -0,0 +1,1107 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { buildCapabilityIndex, buildReuseScoutReport } from "../../delegation/capabilities.js";
4
+ import { selectFactoryForDemands } from "../../factory/factory-selector.js";
5
+ import { evaluateStrictBudgetDispatchGate } from "../../governance/budget-policy.js";
6
+ import { evaluateBudgetPreflightDryRun } from "../../telemetry/chronicle.js";
7
+ import { buildBrainLookupResult, buildContextPack, buildDefaultContextScope, validateContextPack, validateContextScope } from "../../context/context-gbrain.js";
8
+ import { evaluateModelRoutingDispatchGate, evaluateModelRoutingDryRun } from "../../models/model-routing.js";
9
+ import { sha256 } from "../../../core/utils/hashing.js";
10
+ import { safeFileStem } from "../../../core/utils/paths.js";
11
+ import { isRecord } from "../../../core/utils/records.js";
12
+ import type { AutonomousApplyPolicy, AutonomousBudgetProfile, AutonomousLevel, AutonomousRisk, AutonomousRuntimeDryRunInput } from "./types.js";
13
+
14
+ export const FORBIDDEN_BODY_KEYS = new Set(["task", "prompt", "output", "body", "content", "patch", "diff", "raw", "messages", "conversationHistory"]);
15
+ export const AMBIGUOUS_PATTERNS = [/\bstuff\b/i, /\bsomething\b/i, /\bwhatever\b/i, /\bfix it\b/i, /\bmake it better\b/i, /\betc\.?\b/i];
16
+ export const SECRET_PATTERNS = [/\.env\b/i, /api[_-]?key/i, /secret/i, /password/i, /token/i, /private[_-]?key/i, /ssh[_-]?key/i];
17
+ export const DEFAULT_AUTONOMOUS_FORBIDDEN_PATHS = [".env", ".env.*", "secrets", "raw-conversation-history", "node_modules", "dist", "build"];
18
+ export const UNSAFE_AUTONOMOUS_ALLOWED_SEGMENTS = new Set(["node_modules", "dist", "build", "secrets", "raw-conversation-history"]);
19
+ export const AUTONOMOUS_CURRENT_SOURCE_FINGERPRINT_FILES = [
20
+ "package.json",
21
+ "tsconfig.json",
22
+ "scripts/harness-smoke.mjs",
23
+ "docs/AUTONOMY_FACTORY_AGENT_DETAILED_PLAN.md",
24
+ ".pi/budget-policy.json",
25
+ ".pi/model-routing.json",
26
+ ".pi/daemon-policy.json",
27
+ ".pi/teams/zob-core.json",
28
+ ".pi/extensions/zob-harness/index.ts",
29
+ ".pi/extensions/zob-harness/src/domains/autonomy/autonomous-runtime.ts",
30
+ ".pi/extensions/zob-harness/src/domains/autonomy/autonomy-readiness.ts",
31
+ ".pi/extensions/zob-harness/src/runtime/tools-autonomous.ts",
32
+ ".pi/extensions/zob-harness/src/runtime/schemas.ts",
33
+ ".pi/extensions/zob-harness/src/domains/factory/run.ts",
34
+ ".pi/extensions/zob-harness/src/domains/models/model-routing.ts",
35
+ ".pi/extensions/zob-harness/src/domains/governance/budget-policy.ts",
36
+ ".pi/extensions/zob-harness/src/domains/autonomy/daemon-policy.ts",
37
+ ".pi/extensions/zob-harness/src/domains/coms/mission-control.ts",
38
+ ".pi/extensions/zob-harness/src/domains/governance/sandbox.ts",
39
+ ];
40
+
41
+ export function hasForbiddenBodyKeys(value: unknown): boolean {
42
+ if (!value || typeof value !== "object") return false;
43
+ if (Array.isArray(value)) return value.some(hasForbiddenBodyKeys);
44
+ return Object.entries(value as Record<string, unknown>).some(([key, child]) => FORBIDDEN_BODY_KEYS.has(key) || hasForbiddenBodyKeys(child));
45
+ }
46
+
47
+ export function stableStrings(values: string[] | undefined): string[] {
48
+ return [...new Set((values ?? []).filter((value) => typeof value === "string" && value.trim().length > 0).map((value) => value.trim()))].sort();
49
+ }
50
+
51
+ export function normalizeAutonomousSpecPath(value: string): string {
52
+ return value.trim().replace(/\\+/g, "/").replace(/\/+/g, "/").replace(/^\.\//, "").replace(/\/+$/, "");
53
+ }
54
+
55
+ export function isBroadAutonomousAllowedPath(value: string): boolean {
56
+ const normalized = normalizeAutonomousSpecPath(value);
57
+ return normalized === "" || normalized === "." || normalized === "/" || normalized === "*" || normalized === "**" || normalized === "~" || normalized === "~/";
58
+ }
59
+
60
+ export function forbiddenPatternBase(value: string): string {
61
+ return normalizeAutonomousSpecPath(value)
62
+ .replace(/\/\*\*$/, "")
63
+ .replace(/\/\*$/, "")
64
+ .replace(/\.\*$/, "");
65
+ }
66
+
67
+ export function pathConflict(left: string, right: string): boolean {
68
+ const a = forbiddenPatternBase(left).toLowerCase();
69
+ const b = forbiddenPatternBase(right).toLowerCase();
70
+ if (!a || !b) return false;
71
+ return a === b || a.startsWith(`${b}/`) || b.startsWith(`${a}/`);
72
+ }
73
+
74
+ export function unsafeAllowedPathReason(value: string, forbiddenPaths: string[]): string | undefined {
75
+ const normalized = normalizeAutonomousSpecPath(value);
76
+ const lower = normalized.toLowerCase();
77
+ if (value.includes("\0")) return "allowed_path_contains_nul_byte";
78
+ if (isBroadAutonomousAllowedPath(value)) return "allowed_path_too_broad";
79
+ if (lower.startsWith("/") || lower.startsWith("~/") || /^[a-z]:\//i.test(lower)) return "allowed_path_must_be_repo_relative";
80
+ if (lower.split("/").includes("..")) return "allowed_path_must_not_traverse_parent";
81
+ const segments = lower.split("/").filter(Boolean);
82
+ if (segments.some((segment) => segment === ".env" || segment.startsWith(".env."))) return "allowed_path_references_secret_path";
83
+ if (segments.some((segment) => UNSAFE_AUTONOMOUS_ALLOWED_SEGMENTS.has(segment))) return "allowed_path_references_forbidden_segment";
84
+ if (forbiddenPaths.some((forbidden) => pathConflict(normalized, forbidden))) return "allowed_path_conflicts_with_forbidden_path";
85
+ return undefined;
86
+ }
87
+
88
+ export function validateAutonomousSpecPathGate(allowedPaths: string[], forbiddenPaths: string[]): string[] {
89
+ if (allowedPaths.length === 0) return ["allowed_paths_required_before_execution"];
90
+ return allowedPaths.flatMap((allowedPath) => {
91
+ const reason = unsafeAllowedPathReason(allowedPath, forbiddenPaths);
92
+ return reason ? [reason] : [];
93
+ });
94
+ }
95
+
96
+ export function hashes(values: string[]): string[] {
97
+ return values.map((value) => sha256(value)).sort();
98
+ }
99
+
100
+ export function defaultAutonomousAllowedActions(applyPolicy: AutonomousApplyPolicy): string[] {
101
+ const base = ["read_repo", "context_lookup", "select_factory", "run_factory_smoke", "run_factory_pilot", "run_factory_batch", "post_run_validation", "post_run_oracle"];
102
+ return applyPolicy === "auto_apply_in_scope"
103
+ ? [...base, "sandbox_edit", "apply_in_scope", "post_apply_validation", "post_apply_oracle"]
104
+ : base;
105
+ }
106
+
107
+ export function inferAutonomousLevel(applyPolicy: AutonomousApplyPolicy): AutonomousLevel {
108
+ return applyPolicy === "auto_apply_in_scope" ? "L6" : "L4";
109
+ }
110
+
111
+ export function capabilityFactories(capabilityIndex: Record<string, unknown>): Record<string, unknown>[] {
112
+ const capabilities = Array.isArray(capabilityIndex.capabilities) ? capabilityIndex.capabilities.filter(isRecord) : [];
113
+ return capabilities.filter((capability) => capability.kind === "factory");
114
+ }
115
+
116
+ export function textSignals(...values: string[]): string[] {
117
+ const text = values.join("\n").toLowerCase();
118
+ const signals: string[] = [];
119
+ const add = (condition: boolean, signal: string): void => {
120
+ if (condition) signals.push(signal);
121
+ };
122
+ add(/\b(code review|review code|review changes|oracle matrix|security review|qa review|correctness|architecture)\b/.test(text), "code_review");
123
+ add(/\b(budget|cost|costs|cap|caps|preflight|strict budget|max runs|max cost|parallel children)\b/.test(text), "budget_preflight");
124
+ add(/\b(roadmap|lot|lots|milestone|unchecked item|execution queue)\b/.test(text), "roadmap_lots");
125
+ add(/\b(opencode|pattern|patterns|canonizer|canonical|taxonomy|workflow rules|quality gates)\b/.test(text), "opencode_patterns");
126
+ add(/\b(projectdna|project dna|project-dna|knowledge graph|code knowledge|context pack|repo scan|reference project)\b/.test(text), "project_dna");
127
+ add(/\b(new factory|create factory|generate factory|factory scaffold|quarantine|factory-forge|forge)\b/.test(text), "factory_forge");
128
+ return [...new Set(signals)].sort();
129
+ }
130
+
131
+ export function scoreFactoryCandidate(factory: Record<string, unknown>, signals: string[]): Record<string, unknown> {
132
+ const id = typeof factory.id === "string" ? factory.id : "unknown";
133
+ const reasonCodes: string[] = [];
134
+ let score = 0;
135
+ const add = (condition: boolean, points: number, reason: string): void => {
136
+ if (condition) {
137
+ score += points;
138
+ reasonCodes.push(reason);
139
+ }
140
+ };
141
+ add(id === "code-review-matrix" && signals.includes("code_review"), 8, "signal:code_review");
142
+ add(id === "budget-preflight-dry-run" && signals.includes("budget_preflight"), 8, "signal:budget_preflight");
143
+ add(id === "roadmap-smoke-lots" && signals.includes("roadmap_lots"), 8, "signal:roadmap_lots");
144
+ add(id === "opencode-pattern-canonizer" && signals.includes("opencode_patterns"), 8, "signal:opencode_patterns");
145
+ add(id === "project-dna" && signals.includes("project_dna"), 8, "signal:project_dna");
146
+ add(id === "factory-forge" && signals.includes("factory_forge"), 8, "signal:factory_forge");
147
+ const metadata = isRecord(factory.metadata) ? factory.metadata : {};
148
+ const manifests = Array.isArray(metadata.manifests) ? metadata.manifests.filter((item): item is string => typeof item === "string") : [];
149
+ add(manifests.includes("smoke-manifest.json"), 1, "manifest:smoke");
150
+ add(manifests.includes("pilot-manifest.json"), 1, "manifest:pilot");
151
+ add(manifests.includes("batch-manifest.json"), 1, "manifest:batch");
152
+ const confidence = Math.max(0, Math.min(0.99, score / 12));
153
+ return {
154
+ kind: "factory",
155
+ id,
156
+ sourcePath: factory.sourcePath,
157
+ score,
158
+ confidence,
159
+ reasonCodes: reasonCodes.sort(),
160
+ summaryHash: typeof factory.summary === "string" ? sha256(factory.summary) : undefined,
161
+ };
162
+ }
163
+
164
+ export function selectAutonomousFactory(input: { factories: Record<string, unknown>[]; refinedSpec: string; acceptanceCriteria: string[]; expectedArtifacts: string[] }): Record<string, unknown> {
165
+ return selectFactoryForDemands({
166
+ schema: "zob.autonomous-factory-selection-score.v1",
167
+ factories: input.factories,
168
+ refinedSpec: input.refinedSpec,
169
+ acceptanceCriteria: input.acceptanceCriteria,
170
+ expectedArtifacts: input.expectedArtifacts,
171
+ }) as unknown as Record<string, unknown>;
172
+ }
173
+
174
+ export function factoryManifestAvailability(repoRoot: string, factoryName: string | undefined): Record<string, unknown> {
175
+ if (!factoryName) return { smoke: false, pilot: false, batch: false };
176
+ return {
177
+ smoke: existsSync(join(repoRoot, ".pi", "factories", factoryName, "smoke-manifest.json")),
178
+ pilot: existsSync(join(repoRoot, ".pi", "factories", factoryName, "pilot-manifest.json")),
179
+ batch: existsSync(join(repoRoot, ".pi", "factories", factoryName, "batch-manifest.json")),
180
+ };
181
+ }
182
+
183
+ export function readFactoryRegistryReadiness(repoRoot: string, factoryName: string | undefined): Record<string, unknown> {
184
+ const reportPath = "reports/factory-registry-readiness-audit-smoke.json";
185
+ const absolutePath = join(repoRoot, reportPath);
186
+ const base = {
187
+ schema: "zob.autonomous-factory-readiness-snapshot.v1",
188
+ reportPath,
189
+ reportPresent: false,
190
+ reportHash: undefined,
191
+ selectedFactory: factoryName,
192
+ registeredBatchReady: false,
193
+ arbitraryFactoryNoShip: true,
194
+ currentSourceProofRequired: true,
195
+ proofBeforeExecutionRequired: true,
196
+ readinessFreshness: "missing_registry_snapshot",
197
+ bodyStored: false,
198
+ promptBodiesStored: false,
199
+ outputBodiesStored: false,
200
+ };
201
+ if (!existsSync(absolutePath)) return base;
202
+ try {
203
+ const rawJson = readFileSync(absolutePath, "utf8");
204
+ const parsed = JSON.parse(rawJson) as unknown;
205
+ const registry = isRecord(parsed) ? parsed : {};
206
+ const readyFactories = Array.isArray(registry.registeredAgenticBatchReadyFactories) ? registry.registeredAgenticBatchReadyFactories.filter((item): item is string => typeof item === "string") : [];
207
+ const missingFactories = Array.isArray(registry.factoriesMissingRegisteredBatchProof) ? registry.factoriesMissingRegisteredBatchProof.filter((item): item is string => typeof item === "string") : [];
208
+ const registeredBatchReady = typeof factoryName === "string" && readyFactories.includes(factoryName);
209
+ return {
210
+ ...base,
211
+ reportPresent: true,
212
+ reportHash: sha256(rawJson),
213
+ registeredBatchReady,
214
+ arbitraryFactoryNoShip: registry.arbitraryFactoryNoShip !== false,
215
+ currentSourceProofRequired: true,
216
+ proofBeforeExecutionRequired: !registeredBatchReady,
217
+ readinessFreshness: "snapshot_requires_current_source_refresh_before_execution",
218
+ registeredAgenticBatchReadyFactoryCount: readyFactories.length,
219
+ factoriesMissingRegisteredBatchProofCount: missingFactories.length,
220
+ selectedFactoryMissingRegisteredBatchProof: typeof factoryName === "string" ? missingFactories.includes(factoryName) : undefined,
221
+ };
222
+ } catch {
223
+ return { ...base, reportPresent: true, readinessFreshness: "invalid_registry_snapshot", reportHash: undefined };
224
+ }
225
+ }
226
+
227
+ export function buildAutonomousContextArtifacts(repoRoot: string, scope: Record<string, unknown>, queryHash: string): Record<string, unknown> {
228
+ const scopeErrors = validateContextScope(repoRoot, scope);
229
+ if (scopeErrors.length > 0) return { lookupResults: [], contextPack: undefined, contextPackValid: false, contextPackErrors: scopeErrors };
230
+ const allowedSources = Array.isArray(scope.allowedSources) ? scope.allowedSources.filter((source): source is string => typeof source === "string") : [];
231
+ try {
232
+ const lookupResults: Record<string, unknown>[] = [];
233
+ if (allowedSources.includes("zob-harness-docs")) {
234
+ const citation = "harness-system:zob-harness-docs:docs/AUTONOMOUS_SUPER_FACTORY_GOAL.md#phase-3";
235
+ lookupResults.push(buildBrainLookupResult(repoRoot, {
236
+ scope,
237
+ brainId: "harness-system",
238
+ sourceId: "zob-harness-docs",
239
+ queryHash,
240
+ facts: [{ factHash: sha256("autonomous loop requires spec context factory oracle final report"), citations: [citation], confidence: "HIGH" }],
241
+ gaps: [{ gapHash: sha256("P0 dry-run does not execute live factories"), citations: [citation], noShipIfTreatedAsPass: true }],
242
+ confidence: "HIGH",
243
+ }));
244
+ }
245
+ if (allowedSources.includes("factory-run-reports")) {
246
+ const citation = "factory-evidence:factory-run-reports:reports/factory-registry-readiness-audit-smoke.json";
247
+ lookupResults.push(buildBrainLookupResult(repoRoot, {
248
+ scope,
249
+ brainId: "factory-evidence",
250
+ sourceId: "factory-run-reports",
251
+ queryHash,
252
+ facts: [{ factHash: sha256("registered factory current-source proof is required before execution"), citations: [citation], confidence: "HIGH", sourcePresent: existsSync(join(repoRoot, "reports", "factory-registry-readiness-audit-smoke.json")) }],
253
+ gaps: [{ gapHash: sha256("selected factory may still require current-source proof refresh"), citations: [citation], noShipIfTreatedAsPass: true }],
254
+ confidence: "HIGH",
255
+ }));
256
+ }
257
+ if (lookupResults.length === 0 && allowedSources.includes("zob-harness-src")) {
258
+ const citation = "harness-system:zob-harness-src:.pi/extensions/zob-harness/src/domains/autonomy/autonomous-runtime.ts";
259
+ lookupResults.push(buildBrainLookupResult(repoRoot, {
260
+ scope,
261
+ brainId: "harness-system",
262
+ sourceId: "zob-harness-src",
263
+ queryHash,
264
+ facts: [{ factHash: sha256("autonomous dry-run implementation is repo-local metadata-only"), citations: [citation], confidence: "MEDIUM" }],
265
+ confidence: "MEDIUM",
266
+ }));
267
+ }
268
+ if (lookupResults.length === 0) return { lookupResults: [], contextPack: undefined, contextPackValid: false, contextPackErrors: ["no_allowed_context_source_for_autonomous_lookup"] };
269
+ const contextPack = buildContextPack(repoRoot, scope, lookupResults);
270
+ const contextPackErrors = validateContextPack(repoRoot, contextPack);
271
+ return { lookupResults, contextPack, contextPackValid: contextPackErrors.length === 0, contextPackErrors };
272
+ } catch (error) {
273
+ const message = error instanceof Error ? error.message : String(error);
274
+ return { lookupResults: [], contextPack: undefined, contextPackValid: false, contextPackErrors: [message] };
275
+ }
276
+ }
277
+
278
+ export function buildAutonomousRuntimeGates(input: { runId: string; risk: AutonomousRisk; budgetProfile: AutonomousBudgetProfile; applyPolicy: AutonomousApplyPolicy; maxContextTokens?: number }): Record<string, unknown> {
279
+ const budgetGate = evaluateBudgetPreflightDryRun({
280
+ runs: 0,
281
+ durationMs: 0,
282
+ parallelChildren: 0,
283
+ caps: { maxRuns: 0, maxParallelChildren: 0 },
284
+ strictRequested: input.budgetProfile === "strict_requested",
285
+ });
286
+ const modelRoutingGate = evaluateModelRoutingDryRun({
287
+ mode: "factory",
288
+ taskType: "autonomous-runtime-dry-run",
289
+ risk: input.risk,
290
+ contextTokens: input.maxContextTokens,
291
+ estimatedRuns: 0,
292
+ estimatedParallelChildren: 0,
293
+ caps: { maxRuns: 0, maxParallelChildren: 0 },
294
+ strictRequested: input.budgetProfile === "strict_requested",
295
+ });
296
+ const sandboxGate = {
297
+ schema: "zob.autonomous-sandbox-gate.v1",
298
+ applyPolicy: input.applyPolicy,
299
+ sandboxSimulationPlanned: input.applyPolicy === "sandbox_simulation",
300
+ manualApplyOnly: input.applyPolicy === "manual_apply_only",
301
+ launchAuthorizedApplyPlanned: input.applyPolicy === "auto_apply_in_scope",
302
+ launchAuthorizationRequiredForApply: input.applyPolicy === "auto_apply_in_scope",
303
+ productionWritesPerformed: false,
304
+ autoApply: false,
305
+ rollbackRequiredBeforeRealApply: true,
306
+ oracleDiffReviewRequiredBeforeRealApply: true,
307
+ childDispatchAllowed: false,
308
+ noExecution: true,
309
+ bodyStored: false,
310
+ promptBodiesStored: false,
311
+ outputBodiesStored: false,
312
+ };
313
+ const daemonGate = {
314
+ schema: "zob.autonomous-daemon-gate.v1",
315
+ autoStartDaemon: false,
316
+ continuousLoop: false,
317
+ daemonStarted: false,
318
+ manualOneShotOnly: true,
319
+ killSwitchRequiredBeforeLiveAutonomy: true,
320
+ childDispatchAllowed: false,
321
+ noExecution: true,
322
+ bodyStored: false,
323
+ promptBodiesStored: false,
324
+ outputBodiesStored: false,
325
+ };
326
+ const missionControlGate = {
327
+ schema: "zob.autonomous-mission-control-gate.v1",
328
+ proposalOnly: true,
329
+ directWorkerWrites: false,
330
+ transportDispatch: false,
331
+ networkComsEnabled: false,
332
+ topologyGuardRequired: true,
333
+ hashOnlyLedgerRequired: true,
334
+ childDispatchAllowed: false,
335
+ noExecution: true,
336
+ bodyStored: false,
337
+ promptBodiesStored: false,
338
+ outputBodiesStored: false,
339
+ };
340
+ const autonomousStrictBudgetGate = {
341
+ schema: "zob.autonomous-strict-budget-gate.v1",
342
+ strictBudgetRequiredForAutonomy: true,
343
+ budgetProfile: input.budgetProfile,
344
+ strictRequested: input.budgetProfile === "strict_requested",
345
+ strictEnabled: false,
346
+ globalDefaultEnabled: false,
347
+ budgetEnforced: false,
348
+ childDispatchAllowed: false,
349
+ dispatchBlockedUntilLiveStrictGate: true,
350
+ noExecution: true,
351
+ bodyStored: false,
352
+ promptBodiesStored: false,
353
+ outputBodiesStored: false,
354
+ };
355
+ const checks = [
356
+ { name: "autonomous_strict_budget_requested_no_dispatch", passed: autonomousStrictBudgetGate.strictRequested === true && autonomousStrictBudgetGate.noExecution === true && autonomousStrictBudgetGate.budgetEnforced === false && autonomousStrictBudgetGate.childDispatchAllowed === false },
357
+ { name: "budget_preflight_advisory_no_dispatch", passed: budgetGate.noExecution === true && budgetGate.childDispatchAllowed === false && budgetGate.budgetEnforced === false && budgetGate.wouldBlockDispatch === false },
358
+ { name: "model_routing_dry_run_no_dispatch", passed: modelRoutingGate.noExecution === true && modelRoutingGate.modelRouterUsed === false && modelRoutingGate.routingApplied === false && modelRoutingGate.childDispatchAllowed === false },
359
+ { name: "sandbox_no_production_apply", passed: sandboxGate.productionWritesPerformed === false && sandboxGate.autoApply === false && sandboxGate.noExecution === true },
360
+ { name: "daemon_not_started", passed: daemonGate.daemonStarted === false && daemonGate.autoStartDaemon === false && daemonGate.continuousLoop === false },
361
+ { name: "mission_control_proposals_only", passed: missionControlGate.proposalOnly === true && missionControlGate.directWorkerWrites === false && missionControlGate.transportDispatch === false && missionControlGate.networkComsEnabled === false },
362
+ ];
363
+ const failedChecks = checks.filter((check) => !check.passed).map((check) => check.name);
364
+ const gates = {
365
+ schema: "zob.autonomous-runtime-gates.v1",
366
+ runId: input.runId,
367
+ passed: failedChecks.length === 0,
368
+ failedChecks,
369
+ checks,
370
+ budgetGate,
371
+ autonomousStrictBudgetGate,
372
+ modelRoutingGate,
373
+ sandboxGate,
374
+ daemonGate,
375
+ missionControlGate,
376
+ dryRun: true,
377
+ noExecution: true,
378
+ childDispatchAllowed: false,
379
+ globalBudgetEnforced: false,
380
+ globalModelRoutingEnabled: false,
381
+ daemonStarted: false,
382
+ productionWritesPerformed: false,
383
+ autoApply: false,
384
+ networkAccessed: false,
385
+ bodyStored: false,
386
+ promptBodiesStored: false,
387
+ outputBodiesStored: false,
388
+ };
389
+ if (hasForbiddenBodyKeys(gates)) throw new Error("autonomous runtime gates would store forbidden plaintext body keys");
390
+ return gates;
391
+ }
392
+
393
+ export function buildAutonomousStrictBudgetProofPlan(input: { runId: string; runtimeGates: Record<string, unknown>; validation: Record<string, unknown> }): Record<string, unknown> {
394
+ const scenarioSpecs = [
395
+ { name: "strict_gate_allows_within_caps", gateInput: { runId: `${input.runId}-strict-budget-allow`, mode: "smoke", execution: "agentic", taskCount: 1, budget: { strictEnabled: true, maxRuns: 2, estimatedRuns: 1, maxParallelChildren: 1, estimatedParallelChildren: 1 } } },
396
+ { name: "strict_gate_blocks_exceedance_pre_dispatch", gateInput: { runId: `${input.runId}-strict-budget-block`, mode: "smoke", execution: "agentic", taskCount: 3, budget: { strictEnabled: true, maxRuns: 2, estimatedRuns: 3, maxParallelChildren: 1, estimatedParallelChildren: 1 } } },
397
+ { name: "strict_gate_default_disabled_advisory", gateInput: { runId: `${input.runId}-strict-budget-default`, mode: "smoke", execution: "agentic", taskCount: 3, budget: { strictRequested: true, maxRuns: 2, estimatedRuns: 3, maxParallelChildren: 1, estimatedParallelChildren: 1 } } },
398
+ ].map((scenario) => {
399
+ const gate = evaluateStrictBudgetDispatchGate(scenario.gateInput);
400
+ return {
401
+ name: scenario.name,
402
+ inputHash: sha256(JSON.stringify(scenario.gateInput)),
403
+ strictRequested: gate.strictRequested === true,
404
+ strictEnabled: gate.strictEnabled === true,
405
+ budgetEnforced: gate.budgetEnforced === true,
406
+ wouldExceed: gate.wouldExceed === true,
407
+ wouldBlockDispatch: gate.wouldBlockDispatch === true,
408
+ gateChildDispatchAllowed: gate.childDispatchAllowed === true,
409
+ dispatchDecision: gate.dispatchDecision,
410
+ stopCondition: gate.stopCondition,
411
+ noExecution: gate.noExecution === true,
412
+ failures: Array.isArray(gate.failures) ? gate.failures.filter((failure): failure is string => typeof failure === "string") : [],
413
+ bodyStored: false,
414
+ promptBodiesStored: false,
415
+ outputBodiesStored: false,
416
+ };
417
+ });
418
+ const allow = scenarioSpecs.find((scenario) => scenario.name === "strict_gate_allows_within_caps");
419
+ const block = scenarioSpecs.find((scenario) => scenario.name === "strict_gate_blocks_exceedance_pre_dispatch");
420
+ const defaultDisabled = scenarioSpecs.find((scenario) => scenario.name === "strict_gate_default_disabled_advisory");
421
+ const autonomousStrictBudgetGate = isRecord(input.runtimeGates.autonomousStrictBudgetGate) ? input.runtimeGates.autonomousStrictBudgetGate : {};
422
+ const checks = [
423
+ { name: "strict_gate_allows_within_caps", passed: allow?.strictEnabled === true && allow.budgetEnforced === true && allow.wouldBlockDispatch === false && allow.gateChildDispatchAllowed === true && allow.dispatchDecision === "allow_strict" },
424
+ { name: "strict_gate_blocks_exceedance_pre_dispatch", passed: block?.strictEnabled === true && block.budgetEnforced === true && block.wouldBlockDispatch === true && block.gateChildDispatchAllowed === false && block.dispatchDecision === "block" && block.stopCondition === "blocked" },
425
+ { name: "strict_gate_default_disabled_advisory", passed: defaultDisabled?.strictRequested === true && defaultDisabled.strictEnabled === false && defaultDisabled.budgetEnforced === false && defaultDisabled.wouldBlockDispatch === false && defaultDisabled.dispatchDecision === "allow_advisory" },
426
+ { name: "autonomous_runtime_global_budget_still_disabled", passed: autonomousStrictBudgetGate.strictRequested === true && autonomousStrictBudgetGate.strictEnabled === false && autonomousStrictBudgetGate.budgetEnforced === false && autonomousStrictBudgetGate.childDispatchAllowed === false },
427
+ { name: "run_scope_no_global_autonomy", passed: input.validation.globalAutonomyReady === false && input.validation.globalAutonomyNoShip === true && input.validation.childDispatchAllowed === false && input.validation.productionWritesPerformed === false && input.validation.autoApply === false },
428
+ ];
429
+ const failedChecks = checks.filter((check) => check.passed !== true).map((check) => check.name);
430
+ const proof = {
431
+ schema: "zob.autonomous-strict-budget-proof-plan.v1",
432
+ runId: input.runId,
433
+ phase: "5B",
434
+ status: failedChecks.length === 0 ? "strict_budget_dispatch_gate_proof_ready_global_default_blocked" : "strict_budget_dispatch_gate_proof_incomplete",
435
+ strictBudgetProofReady: failedChecks.length === 0,
436
+ strictBudgetDispatchGateAvailable: true,
437
+ strictBudgetAllowProofPassed: allow?.dispatchDecision === "allow_strict" && allow.budgetEnforced === true,
438
+ strictBudgetBlockProofPassed: block?.dispatchDecision === "block" && block.wouldBlockDispatch === true,
439
+ strictBudgetDefaultDisabledProofPassed: defaultDisabled?.dispatchDecision === "allow_advisory" && defaultDisabled.strictEnabled === false,
440
+ finalE2ERequirementCleared: false,
441
+ no_ship: true,
442
+ checks,
443
+ failedChecks,
444
+ scenarios: scenarioSpecs,
445
+ evidenceRefs: [
446
+ `reports/autonomous-runs/${safeFileStem(input.runId)}/runtime-gates.json`,
447
+ `reports/autonomous-runs/${safeFileStem(input.runId)}/validation.json`,
448
+ ],
449
+ blockers: [
450
+ "live_autonomous_strict_budget_not_enforced",
451
+ "global_default_strict_budget_disabled",
452
+ "final_e2e_strict_budget_evidence_required",
453
+ ],
454
+ autonomousRuntimeStrictBudgetEnforced: false,
455
+ globalStrictBudgetEnabled: false,
456
+ globalBudgetEnforced: false,
457
+ liveAutonomousBudgetEnforced: false,
458
+ budgetEnforced: false,
459
+ strictEnabled: false,
460
+ childDispatchAllowed: false,
461
+ daemonStarted: false,
462
+ productionWritesPerformed: false,
463
+ autoApply: false,
464
+ noExecution: true,
465
+ globalAutonomyReady: false,
466
+ globalAutonomyNoShip: true,
467
+ bodyStored: false,
468
+ promptBodiesStored: false,
469
+ outputBodiesStored: false,
470
+ };
471
+ if (hasForbiddenBodyKeys(proof)) throw new Error("autonomous strict budget proof plan would store forbidden plaintext body keys");
472
+ return proof;
473
+ }
474
+
475
+ export function buildAutonomousModelRoutingPlan(input: { runId: string; risk: AutonomousRisk; budgetProfile: AutonomousBudgetProfile; maxContextTokens?: number; specText: string; selectedFactory?: string }): Record<string, unknown> {
476
+ const strictRequested = input.budgetProfile === "strict_requested";
477
+ const contextTokens = typeof input.maxContextTokens === "number" && Number.isFinite(input.maxContextTokens) ? Math.max(0, Math.floor(input.maxContextTokens)) : 0;
478
+ const highContextRequired = contextTokens >= 120_000;
479
+ const securitySensitive = input.risk === "high" || /\b(security|secure|vulnerability|vulnerabilities|auth|permission|permissions|sandbox|apply|write|privilege|injection)\b/i.test(input.specText);
480
+ const routeSpecs: Array<{ stage: string; mode: "explore" | "plan" | "implement" | "oracle" | "factory"; taskType: string; outputContract?: string; risk: AutonomousRisk; contextTokens?: number; expectedModelClass: string; securityCritical?: boolean; oracleCritical?: boolean }> = [
481
+ { stage: "context_reuse_scout", mode: "explore", taskType: "read-only-inspection", risk: "low", expectedModelClass: "cheap_scout" },
482
+ { stage: "context_pack", mode: "explore", taskType: "context-pack-read-only", risk: "low", contextTokens: contextTokens || undefined, expectedModelClass: highContextRequired ? "high_context" : "cheap_scout" },
483
+ { stage: "factory_selection", mode: "factory", taskType: securitySensitive ? "security-critical-plan" : "factory-selection", risk: securitySensitive ? "high" : input.risk, expectedModelClass: securitySensitive ? "strong_reasoning" : "balanced_worker", securityCritical: securitySensitive },
484
+ { stage: "factory_smoke_plan", mode: "factory", taskType: `factory-smoke:${input.selectedFactory ?? "unselected"}`, risk: input.risk, expectedModelClass: input.risk === "high" ? "strong_reasoning" : "balanced_worker" },
485
+ { stage: "smoke_oracle", mode: "oracle", taskType: "oracle-review", outputContract: "oracle.v1", risk: "high", expectedModelClass: "strong_oracle", oracleCritical: true },
486
+ { stage: "pilot_oracle", mode: "oracle", taskType: "oracle-review", outputContract: "oracle.v1", risk: "high", expectedModelClass: "strong_oracle", oracleCritical: true },
487
+ { stage: "final_report_synthesis", mode: "implement", taskType: "synthesis-final-report", risk: input.risk, expectedModelClass: input.risk === "high" ? "strong_reasoning" : "balanced_worker" },
488
+ ];
489
+ if (securitySensitive) {
490
+ routeSpecs.push({ stage: "security_reasoning_gate", mode: "plan", taskType: "security-critical-plan", risk: "high", expectedModelClass: "strong_reasoning", securityCritical: true });
491
+ }
492
+ const routes = routeSpecs.map((spec) => {
493
+ const route = evaluateModelRoutingDryRun({
494
+ mode: spec.mode,
495
+ taskType: spec.taskType,
496
+ outputContract: spec.outputContract,
497
+ risk: spec.risk,
498
+ contextTokens: spec.contextTokens,
499
+ estimatedRuns: 0,
500
+ estimatedParallelChildren: 0,
501
+ caps: { maxRuns: 0, maxParallelChildren: 0 },
502
+ strictRequested,
503
+ });
504
+ return {
505
+ stage: spec.stage,
506
+ mode: spec.mode,
507
+ taskType: spec.taskType,
508
+ outputContract: spec.outputContract,
509
+ risk: spec.risk,
510
+ contextTokens: spec.contextTokens,
511
+ expectedModelClass: spec.expectedModelClass,
512
+ recommendedModelClass: route.recommendedModelClass,
513
+ matchedExpectedClass: route.recommendedModelClass === spec.expectedModelClass,
514
+ reasonCodes: Array.isArray(route.reasonCodes) ? route.reasonCodes : [],
515
+ budgetWouldExceed: route.budgetWouldExceed === true,
516
+ budgetEnforced: route.budgetEnforced === true,
517
+ strictRequested: route.strictRequested === true,
518
+ strictEnabled: route.strictEnabled === true,
519
+ modelRouterUsed: route.modelRouterUsed === true,
520
+ routingApplied: route.routingApplied === true,
521
+ childDispatchAllowed: route.childDispatchAllowed === true,
522
+ noExecution: route.noExecution === true,
523
+ securityCritical: spec.securityCritical === true,
524
+ oracleCritical: spec.oracleCritical === true,
525
+ bodyStored: false,
526
+ promptBodiesStored: false,
527
+ outputBodiesStored: false,
528
+ };
529
+ });
530
+ const oracleRoutes = routes.filter((route) => route.oracleCritical === true);
531
+ const securityRoutes = routes.filter((route) => route.securityCritical === true);
532
+ const checks = [
533
+ { name: "model_routing_plan_present", passed: routes.length >= 7 },
534
+ { name: "low_risk_readonly_uses_cheap_scout", passed: routes.some((route) => route.stage === "context_reuse_scout" && route.recommendedModelClass === "cheap_scout") },
535
+ { name: "oracle_uses_strong_oracle", passed: oracleRoutes.length > 0 && oracleRoutes.every((route) => route.recommendedModelClass === "strong_oracle") },
536
+ { name: "high_context_uses_high_context", passed: !highContextRequired || routes.some((route) => route.stage === "context_pack" && route.recommendedModelClass === "high_context") },
537
+ { name: "security_not_downgraded", passed: !securitySensitive || (securityRoutes.length > 0 && securityRoutes.every((route) => route.recommendedModelClass === "strong_reasoning" || route.recommendedModelClass === "strong_oracle" || route.recommendedModelClass === "high_context")) },
538
+ { name: "budget_aware_strict_requested", passed: strictRequested && routes.every((route) => route.strictRequested === true && route.budgetEnforced === false && route.strictEnabled === false) },
539
+ { name: "routing_dry_run_no_dispatch", passed: routes.every((route) => route.noExecution === true && route.modelRouterUsed === false && route.routingApplied === false && route.childDispatchAllowed === false) },
540
+ { name: "global_live_routing_disabled", passed: true },
541
+ ];
542
+ const failedChecks = checks.filter((check) => check.passed !== true).map((check) => check.name);
543
+ const plan = {
544
+ schema: "zob.autonomous-model-routing-plan.v1",
545
+ runId: input.runId,
546
+ selectedFactory: input.selectedFactory,
547
+ routingRequiredForAutonomy: true,
548
+ routingPlanReady: failedChecks.length === 0,
549
+ failedChecks,
550
+ checks,
551
+ routes,
552
+ highContextRequired,
553
+ securitySensitive,
554
+ budgetAware: strictRequested,
555
+ strictRequested,
556
+ strictEnabled: false,
557
+ budgetEnforced: false,
558
+ liveRoutingEnabled: false,
559
+ globalLiveRoutingEnabled: false,
560
+ modelRouterUsed: false,
561
+ routingApplied: false,
562
+ childDispatchAllowed: false,
563
+ noExecution: true,
564
+ bodyStored: false,
565
+ promptBodiesStored: false,
566
+ outputBodiesStored: false,
567
+ };
568
+ if (hasForbiddenBodyKeys(plan)) throw new Error("autonomous model routing plan would store forbidden plaintext body keys");
569
+ return plan;
570
+ }
571
+
572
+ export function buildAutonomousModelRoutingProofPlan(input: { runId: string; modelRoutingPlan: Record<string, unknown>; validation: Record<string, unknown> }): Record<string, unknown> {
573
+ const proofModelByClass = { cheap_scout: "scout-model", balanced_worker: "worker-model", strong_reasoning: "reasoning-model", strong_oracle: "oracle-model", high_context: "long-context-model" };
574
+ const scenarioSpecs = [
575
+ { name: "routing_default_disabled", gateInput: { runId: `${input.runId}-routing-default`, mode: "factory" as const, stage: "map", agent: "explore", outputContract: "explore.v1", modelRouting: { enabled: false, modelByClass: proofModelByClass } } },
576
+ { name: "routing_oracle_applies_when_enabled", gateInput: { runId: `${input.runId}-routing-oracle`, mode: "factory" as const, stage: "validate", agent: "oracle-merge", outputContract: "oracle-merge.v1", modelRouting: { enabled: true, modelByClass: proofModelByClass } } },
577
+ { name: "routing_high_context_applies_when_enabled", gateInput: { runId: `${input.runId}-routing-high-context`, mode: "factory" as const, stage: "reduce", agent: "synthesis", outputContract: "synthesis.v1", modelRouting: { enabled: true, contextTokens: 150_000, modelByClass: proofModelByClass } } },
578
+ { name: "routing_security_not_downgraded_when_enabled", gateInput: { runId: `${input.runId}-routing-security`, mode: "plan" as const, stage: "security_reasoning_gate", agent: "planner", outputContract: "plan.v1", risk: "high" as const, taskType: "security-critical-plan", modelRouting: { enabled: true, modelByClass: proofModelByClass } } },
579
+ ].map((scenario) => {
580
+ const gate = evaluateModelRoutingDispatchGate(scenario.gateInput);
581
+ return {
582
+ name: scenario.name,
583
+ inputHash: sha256(JSON.stringify(scenario.gateInput)),
584
+ liveRoutingRequested: gate.liveRoutingRequested === true,
585
+ liveRoutingEnabled: gate.liveRoutingEnabled === true,
586
+ modelRouterUsed: gate.modelRouterUsed === true,
587
+ routingApplied: gate.routingApplied === true,
588
+ selectedModelClass: gate.selectedModelClass,
589
+ recommendedModelClass: gate.recommendedModelClass,
590
+ selectedModelHash: typeof gate.selectedModelHash === "string" ? gate.selectedModelHash : undefined,
591
+ selectedModelStored: gate.selectedModelStored === true,
592
+ modelByClassProvided: gate.modelByClassProvided === true,
593
+ gateChildDispatchAllowed: gate.childDispatchAllowed === true,
594
+ defaultDispatchDecision: gate.defaultDispatchDecision,
595
+ noExecution: gate.noExecution === true,
596
+ budgetEnforced: gate.budgetEnforced === true,
597
+ strictEnabled: gate.strictEnabled === true,
598
+ reasonCodes: Array.isArray(gate.reasonCodes) ? gate.reasonCodes.filter((reason): reason is string => typeof reason === "string") : [],
599
+ bodyStored: false,
600
+ promptBodiesStored: false,
601
+ outputBodiesStored: false,
602
+ };
603
+ });
604
+ const defaultDisabled = scenarioSpecs.find((scenario) => scenario.name === "routing_default_disabled");
605
+ const oracle = scenarioSpecs.find((scenario) => scenario.name === "routing_oracle_applies_when_enabled");
606
+ const highContext = scenarioSpecs.find((scenario) => scenario.name === "routing_high_context_applies_when_enabled");
607
+ const security = scenarioSpecs.find((scenario) => scenario.name === "routing_security_not_downgraded_when_enabled");
608
+ const checks = [
609
+ { name: "routing_default_disabled", passed: defaultDisabled?.liveRoutingEnabled === false && defaultDisabled.modelRouterUsed === false && defaultDisabled.routingApplied === false && defaultDisabled.gateChildDispatchAllowed === false && defaultDisabled.defaultDispatchDecision === "allow_default_model" },
610
+ { name: "routing_oracle_uses_strong_oracle_when_enabled", passed: oracle?.liveRoutingEnabled === true && oracle.modelRouterUsed === true && oracle.routingApplied === true && oracle.selectedModelClass === "strong_oracle" && typeof oracle.selectedModelHash === "string" && oracle.selectedModelStored === false },
611
+ { name: "routing_high_context_uses_high_context_when_enabled", passed: highContext?.liveRoutingEnabled === true && highContext.selectedModelClass === "high_context" && typeof highContext.selectedModelHash === "string" && highContext.selectedModelStored === false },
612
+ { name: "routing_security_not_downgraded_when_enabled", passed: security?.liveRoutingEnabled === true && security.selectedModelClass === "strong_reasoning" && typeof security.selectedModelHash === "string" && security.selectedModelStored === false },
613
+ { name: "autonomous_model_routing_plan_still_disabled", passed: input.modelRoutingPlan.liveRoutingEnabled === false && input.modelRoutingPlan.globalLiveRoutingEnabled === false && input.modelRoutingPlan.modelRouterUsed === false && input.modelRoutingPlan.routingApplied === false && input.modelRoutingPlan.childDispatchAllowed === false },
614
+ { name: "run_scope_no_global_autonomy", passed: input.validation.globalAutonomyReady === false && input.validation.globalAutonomyNoShip === true && input.validation.childDispatchAllowed === false && input.validation.productionWritesPerformed === false && input.validation.autoApply === false },
615
+ ];
616
+ const failedChecks = checks.filter((check) => check.passed !== true).map((check) => check.name);
617
+ const proof = {
618
+ schema: "zob.autonomous-model-routing-proof-plan.v1",
619
+ runId: input.runId,
620
+ phase: "6B",
621
+ status: failedChecks.length === 0 ? "model_routing_dispatch_gate_proof_ready_global_default_blocked" : "model_routing_dispatch_gate_proof_incomplete",
622
+ modelRoutingProofReady: failedChecks.length === 0,
623
+ liveRoutingDispatchGateAvailable: true,
624
+ routingDefaultDisabledProofPassed: defaultDisabled?.defaultDispatchDecision === "allow_default_model" && defaultDisabled.liveRoutingEnabled === false,
625
+ routingOracleProofPassed: oracle?.selectedModelClass === "strong_oracle" && oracle.routingApplied === true,
626
+ routingHighContextProofPassed: highContext?.selectedModelClass === "high_context" && highContext.routingApplied === true,
627
+ routingSecurityNoDowngradeProofPassed: security?.selectedModelClass === "strong_reasoning" && security.routingApplied === true,
628
+ selectedModelsStored: false,
629
+ selectedModelHashesOnly: scenarioSpecs.every((scenario) => scenario.selectedModelStored === false && (scenario.liveRoutingEnabled === false || typeof scenario.selectedModelHash === "string")),
630
+ finalE2ERequirementCleared: false,
631
+ no_ship: true,
632
+ checks,
633
+ failedChecks,
634
+ scenarios: scenarioSpecs,
635
+ evidenceRefs: [
636
+ `reports/autonomous-runs/${safeFileStem(input.runId)}/model-routing-plan.json`,
637
+ `reports/autonomous-runs/${safeFileStem(input.runId)}/validation.json`,
638
+ ],
639
+ blockers: [
640
+ "live_autonomous_model_routing_not_enabled",
641
+ "global_default_model_routing_disabled",
642
+ "final_e2e_model_routing_evidence_required",
643
+ ],
644
+ globalLiveRoutingEnabled: false,
645
+ liveAutonomousRoutingApplied: false,
646
+ modelRouterUsed: false,
647
+ routingApplied: false,
648
+ budgetEnforced: false,
649
+ strictEnabled: false,
650
+ childDispatchAllowed: false,
651
+ daemonStarted: false,
652
+ productionWritesPerformed: false,
653
+ autoApply: false,
654
+ noExecution: true,
655
+ globalAutonomyReady: false,
656
+ globalAutonomyNoShip: true,
657
+ bodyStored: false,
658
+ promptBodiesStored: false,
659
+ outputBodiesStored: false,
660
+ };
661
+ if (hasForbiddenBodyKeys(proof)) throw new Error("autonomous model routing proof plan would store forbidden plaintext body keys");
662
+ return proof;
663
+ }
664
+
665
+ export function buildAutonomousRunGraph(input: {
666
+ runId: string;
667
+ specLocked: boolean;
668
+ contextScopeValid: boolean;
669
+ contextPackValid: boolean;
670
+ runtimeGatesValid: boolean;
671
+ modelRoutingPlanValid: boolean;
672
+ factorySelected: boolean;
673
+ registeredBatchReady: boolean;
674
+ proofBeforeExecutionRequired: boolean;
675
+ selectedFactory?: string;
676
+ }): Record<string, unknown> {
677
+ const nodes = [
678
+ { id: "spec_gate", kind: "gate", artifactRef: "spec-gate.json", passed: input.specLocked, stopOnFail: true },
679
+ { id: "context_scope", kind: "context", artifactRef: "context-scope.json", passed: input.contextScopeValid, stopOnFail: true },
680
+ { id: "context_lookup", kind: "context", artifactRef: "context-lookup.json", passed: input.contextPackValid, stopOnFail: true },
681
+ { id: "context_pack", kind: "context", artifactRef: "context-pack.json", passed: input.contextPackValid, stopOnFail: true },
682
+ { id: "runtime_gates", kind: "gate", artifactRef: "runtime-gates.json", passed: input.runtimeGatesValid, stopOnFail: true },
683
+ { id: "model_routing_plan", kind: "gate", artifactRef: "model-routing-plan.json", passed: input.modelRoutingPlanValid, stopOnFail: true },
684
+ { id: "factory_selection", kind: "selection", artifactRef: "factory-selection.json", passed: input.factorySelected, selectedFactory: input.selectedFactory, stopOnFail: true },
685
+ { id: "registered_factory_current_source_proof", kind: "proof", artifactRef: "proof-plan.json", passed: input.registeredBatchReady, proofBeforeExecutionRequired: input.proofBeforeExecutionRequired, stopOnFail: false },
686
+ { id: "smoke", kind: "future_execution", artifactRef: "SMOKE_PASSED.sentinel", passed: false, dispatchAllowed: false },
687
+ { id: "smoke_oracle", kind: "future_oracle", artifactRef: "oracle-review-pass.json", passed: false, dispatchAllowed: false },
688
+ { id: "pilot", kind: "future_execution", artifactRef: "PILOT_PASSED.sentinel", passed: false, dispatchAllowed: false },
689
+ { id: "pilot_oracle", kind: "future_oracle", artifactRef: "oracle-review-pass.json", passed: false, dispatchAllowed: false },
690
+ { id: "batch", kind: "future_execution", artifactRef: "BATCH_PASSED.sentinel", passed: false, dispatchAllowed: false },
691
+ { id: "final_report", kind: "report", artifactRef: "final-report.md", passed: false, dispatchAllowed: false },
692
+ ];
693
+ const edges = [
694
+ ["spec_gate", "context_scope"],
695
+ ["context_scope", "context_lookup"],
696
+ ["context_lookup", "context_pack"],
697
+ ["context_pack", "runtime_gates"],
698
+ ["runtime_gates", "model_routing_plan"],
699
+ ["model_routing_plan", "factory_selection"],
700
+ ["factory_selection", "registered_factory_current_source_proof"],
701
+ ["registered_factory_current_source_proof", "smoke"],
702
+ ["smoke", "smoke_oracle"],
703
+ ["smoke_oracle", "pilot"],
704
+ ["pilot", "pilot_oracle"],
705
+ ["pilot_oracle", "batch"],
706
+ ["batch", "final_report"],
707
+ ].map(([from, to]) => ({ from, to, parentOwned: true, dispatchAllowed: false }));
708
+ const runGraph = {
709
+ schema: "zob.autonomous-run-graph.v1",
710
+ runId: input.runId,
711
+ status: input.specLocked && input.contextScopeValid && input.contextPackValid && input.runtimeGatesValid && input.modelRoutingPlanValid && input.factorySelected ? "dry_run_graph_ready" : "dry_run_graph_blocked",
712
+ parentOwned: true,
713
+ nodes,
714
+ edges,
715
+ stopConditions: ["clarification_required", "context_scope_invalid", "context_pack_invalid", "runtime_gates_invalid", "model_routing_plan_invalid", "factory_selection_missing", "current_source_proof_missing", "oracle_fail", "budget_exceeded", "secret_reference", "production_apply_requested"],
716
+ futureExecutionNodesDispatchAllowed: false,
717
+ childDispatchAllowed: false,
718
+ noExecution: true,
719
+ daemonStarted: false,
720
+ productionWritesPerformed: false,
721
+ autoApply: false,
722
+ globalAutonomyReady: false,
723
+ globalAutonomyNoShip: true,
724
+ bodyStored: false,
725
+ promptBodiesStored: false,
726
+ outputBodiesStored: false,
727
+ };
728
+ if (hasForbiddenBodyKeys(runGraph)) throw new Error("autonomous run graph would store forbidden plaintext body keys");
729
+ return runGraph;
730
+ }
731
+
732
+ export function detectContextNeedTags(specText: string): string[] {
733
+ const lower = specText.toLowerCase();
734
+ const tags = new Set<string>(["harness-system", "factory-evidence"]);
735
+ if (/factory|batch|pilot|smoke|oracle/.test(lower)) tags.add("factory-evidence");
736
+ if (/context|gbrain|brain|citation|source/.test(lower)) tags.add("context-gbrain");
737
+ if (/budget|cost|cap/.test(lower)) tags.add("budget-policy");
738
+ if (/model|routing|oracle/.test(lower)) tags.add("model-routing");
739
+ if (/sandbox|apply|write|patch|edit/.test(lower)) tags.add("sandbox-policy");
740
+ if (/daemon|queue|worker|mission|coms|heartbeat/.test(lower)) tags.add("mission-control");
741
+ return [...tags].sort();
742
+ }
743
+
744
+ export function buildClarificationQuestions(input: {
745
+ shortSpec: boolean;
746
+ missingAcceptance: boolean;
747
+ missingArtifacts: boolean;
748
+ missingAllowedPaths: boolean;
749
+ unsafeAllowedPaths: boolean;
750
+ missingApplyPolicy: boolean;
751
+ missingBudgetProfile: boolean;
752
+ riskyApply: boolean;
753
+ sensitiveReference: boolean;
754
+ }): string[] {
755
+ const questions: string[] = [];
756
+ if (input.shortSpec) questions.push("What exact deliverable should the autonomous dry-run plan target?");
757
+ if (input.missingAcceptance) questions.push("What acceptance criteria must be true before the run can proceed past spec lock?");
758
+ if (input.missingArtifacts) questions.push("Which final artifacts or reports should be produced?");
759
+ if (input.missingAllowedPaths) questions.push("Which repo-relative allowed_paths should bound future autonomous work?");
760
+ if (input.unsafeAllowedPaths) questions.push("Please remove unsafe or forbidden entries from allowed_paths and keep them in forbidden_paths only.");
761
+ if (input.missingApplyPolicy) questions.push("Which apply_policy should govern this autonomous run: no_apply, sandbox_simulation, manual_apply_only, or auto_apply_in_scope?");
762
+ if (input.missingBudgetProfile) questions.push("Which budget_profile should govern this autonomous run: advisory or strict_requested?");
763
+ if (input.riskyApply) questions.push("Should this remain no-apply/manual-apply, or is a sandbox simulation explicitly required?");
764
+ if (input.sensitiveReference) questions.push("Please remove or replace any secret-like values with safe placeholders before planning.");
765
+ return questions;
766
+ }
767
+
768
+ export function buildAutonomousRuntimeDryRun(repoRoot: string, input: AutonomousRuntimeDryRunInput): Record<string, unknown> {
769
+ const userNeed = typeof input.userNeed === "string" ? input.userNeed.trim() : "";
770
+ const refinedSpec = typeof input.refinedSpec === "string" && input.refinedSpec.trim().length > 0 ? input.refinedSpec.trim() : userNeed;
771
+ const constraints = stableStrings(input.constraints);
772
+ const acceptanceCriteria = stableStrings(input.acceptanceCriteria);
773
+ const expectedArtifacts = stableStrings(input.expectedArtifacts);
774
+ const allowedPaths = stableStrings(input.allowedPaths);
775
+ const forbiddenPaths = stableStrings(input.forbiddenPaths ?? DEFAULT_AUTONOMOUS_FORBIDDEN_PATHS);
776
+ const applyPolicyProvided = typeof input.applyPolicy === "string";
777
+ const budgetProfileProvided = typeof input.budgetProfile === "string";
778
+ const applyPolicy = input.applyPolicy ?? "no_apply";
779
+ const budgetProfile = input.budgetProfile ?? "advisory";
780
+ const risk = input.risk ?? "medium";
781
+ const authorizedAutonomyLevel = input.authorizedAutonomyLevel ?? inferAutonomousLevel(applyPolicy);
782
+ const userLaunchConfirmed = input.userLaunchConfirmed === true;
783
+ const allowedActions = stableStrings(input.allowedActions ?? defaultAutonomousAllowedActions(applyPolicy));
784
+ const runId = safeFileStem(input.runId ?? `autonomous-dry-run-${sha256(refinedSpec || "missing-spec").slice(0, 12)}`);
785
+ const specText = `${userNeed}\n${refinedSpec}\n${constraints.join("\n")}\n${acceptanceCriteria.join("\n")}\n${expectedArtifacts.join("\n")}`;
786
+ const shortSpec = refinedSpec.length < 24;
787
+ const ambiguous = AMBIGUOUS_PATTERNS.some((pattern) => pattern.test(refinedSpec));
788
+ const sensitiveReference = SECRET_PATTERNS.some((pattern) => pattern.test(specText));
789
+ const missingAcceptance = acceptanceCriteria.length === 0;
790
+ const missingArtifacts = expectedArtifacts.length === 0;
791
+ const pathGateErrors = validateAutonomousSpecPathGate(allowedPaths, forbiddenPaths);
792
+ const missingAllowedPaths = allowedPaths.length === 0;
793
+ const unsafeAllowedPaths = pathGateErrors.some((error) => error !== "allowed_paths_required_before_execution");
794
+ const missingApplyPolicy = !applyPolicyProvided;
795
+ const missingBudgetProfile = !budgetProfileProvided;
796
+ const riskyApply = applyPolicy !== "no_apply" && allowedPaths.length === 0;
797
+ const clarificationRequired = !userNeed || shortSpec || ambiguous || sensitiveReference || missingAcceptance || missingArtifacts || missingAllowedPaths || unsafeAllowedPaths || missingApplyPolicy || missingBudgetProfile || riskyApply;
798
+ const clarificationQuestions = buildClarificationQuestions({ shortSpec: !userNeed || shortSpec || ambiguous, missingAcceptance, missingArtifacts, missingAllowedPaths, unsafeAllowedPaths, missingApplyPolicy, missingBudgetProfile, riskyApply, sensitiveReference });
799
+
800
+ const contextScope = buildDefaultContextScope(repoRoot, {
801
+ runId,
802
+ allowedSources: input.allowedSources,
803
+ forbiddenSources: forbiddenPaths,
804
+ agentProfile: "autonomous-runtime-dry-run-p0",
805
+ maxContextTokens: input.maxContextTokens,
806
+ });
807
+ const contextScopeErrors = validateContextScope(repoRoot, contextScope);
808
+ const contextArtifacts = buildAutonomousContextArtifacts(repoRoot, contextScope, sha256(refinedSpec));
809
+ const contextPackValid = contextArtifacts.contextPackValid === true;
810
+ const contextPackErrors = Array.isArray(contextArtifacts.contextPackErrors) ? contextArtifacts.contextPackErrors : [];
811
+ const runtimeGates = buildAutonomousRuntimeGates({ runId, risk, budgetProfile, applyPolicy, maxContextTokens: input.maxContextTokens });
812
+ const runtimeGatesValid = runtimeGates.passed === true;
813
+ const capabilityIndex = buildCapabilityIndex(repoRoot);
814
+ const reuseScout = buildReuseScoutReport(repoRoot, { query: refinedSpec, run_id: runId, limit: 8 });
815
+ const candidates = Array.isArray(reuseScout.candidates) ? reuseScout.candidates : [];
816
+ const factories = capabilityFactories(capabilityIndex);
817
+ const factoryForgeAvailable = factories.some((factory) => factory.id === "factory-forge");
818
+ const factoryScore = selectAutonomousFactory({ factories, refinedSpec, acceptanceCriteria, expectedArtifacts });
819
+ const selectedFactory = typeof factoryScore.selectedFactory === "string" ? factoryScore.selectedFactory : (factoryForgeAvailable ? "factory-forge" : undefined);
820
+ const selectionStatus = typeof factoryScore.selectionStatus === "string" && factoryScore.selectionStatus !== "no_factory_available"
821
+ ? factoryScore.selectionStatus
822
+ : (factoryForgeAvailable ? "factory_forge_quarantine_recommended" : "no_factory_available");
823
+ const manifestAvailability = factoryManifestAvailability(repoRoot, selectedFactory);
824
+ const factoryReadiness = readFactoryRegistryReadiness(repoRoot, selectedFactory);
825
+ const proofBeforeExecutionRequired = factoryReadiness.proofBeforeExecutionRequired === true;
826
+ const modelRoutingPlan = buildAutonomousModelRoutingPlan({ runId, risk, budgetProfile, maxContextTokens: input.maxContextTokens, specText, selectedFactory });
827
+ const modelRoutingPlanValid = modelRoutingPlan.routingPlanReady === true;
828
+ const selectionBlockers = selectedFactory ? [] : ["no_factory_available_for_spec"];
829
+
830
+ const strictBudgetMissing = budgetProfile !== "strict_requested";
831
+ const blockers = [
832
+ ...(!userNeed ? ["user_need_required"] : []),
833
+ ...(clarificationRequired ? ["clarification_required_before_execution"] : []),
834
+ ...pathGateErrors,
835
+ ...(missingApplyPolicy ? ["apply_policy_required_before_execution"] : []),
836
+ ...(missingBudgetProfile ? ["budget_profile_required_before_execution"] : []),
837
+ ...(!missingBudgetProfile && strictBudgetMissing ? ["autonomous_strict_budget_required_before_execution"] : []),
838
+ ...(contextScopeErrors.length > 0 ? ["context_scope_invalid"] : []),
839
+ ...(!contextPackValid ? ["context_pack_invalid"] : []),
840
+ ...(!runtimeGatesValid ? ["runtime_gates_invalid"] : []),
841
+ ...(!modelRoutingPlanValid ? ["model_routing_plan_invalid"] : []),
842
+ ...selectionBlockers,
843
+ ];
844
+ const specLocked = blockers.length === 0;
845
+ const launchAuthorization = {
846
+ schema: "zob.launch-authorization.v1",
847
+ runId,
848
+ originalUserAskHash: sha256(userNeed),
849
+ refinedSpecHash: sha256(refinedSpec),
850
+ specLocked,
851
+ userLaunchConfirmed,
852
+ launchConfirmedAt: userLaunchConfirmed && typeof input.launchConfirmedAt === "string" && input.launchConfirmedAt.trim().length > 0 ? input.launchConfirmedAt.trim() : undefined,
853
+ authorizedAutonomyLevel,
854
+ allowedActions,
855
+ allowedPaths,
856
+ forbiddenPaths,
857
+ applyPolicy: {
858
+ mode: applyPolicy,
859
+ rollbackRequired: applyPolicy !== "no_apply",
860
+ exactDiffHashRequired: applyPolicy !== "no_apply",
861
+ postApplyValidationRequired: applyPolicy !== "no_apply",
862
+ postApplyOracleRequired: applyPolicy !== "no_apply",
863
+ },
864
+ budgetPolicy: {
865
+ mode: budgetProfile,
866
+ strict: budgetProfile === "strict_requested",
867
+ strictBudgetRequired: true,
868
+ strictBudgetSatisfied: budgetProfile === "strict_requested",
869
+ },
870
+ stopConditions: ["scope_drift", "secret_required", "validation_fail_exhausted", "oracle_no_ship", "budget_exceeded", "stale_worker_unrecoverable"],
871
+ launchAuthorizesInScopeActions: specLocked && userLaunchConfirmed,
872
+ actionExecutionBlockedUntilLaunch: !userLaunchConfirmed,
873
+ exceptionApprovalRequiredOnlyForOutOfScope: true,
874
+ bodyStored: false,
875
+ promptBodiesStored: false,
876
+ outputBodiesStored: false,
877
+ };
878
+ const status = specLocked ? "dry_run_plan_ready" : "clarification_or_gate_required";
879
+ const runGraph = buildAutonomousRunGraph({
880
+ runId,
881
+ specLocked,
882
+ contextScopeValid: contextScopeErrors.length === 0,
883
+ contextPackValid,
884
+ runtimeGatesValid,
885
+ modelRoutingPlanValid,
886
+ factorySelected: Boolean(selectedFactory),
887
+ registeredBatchReady: factoryReadiness.registeredBatchReady === true,
888
+ proofBeforeExecutionRequired,
889
+ selectedFactory,
890
+ });
891
+
892
+ const report = {
893
+ schema: "zob.autonomous-runtime-dry-run.v1",
894
+ runId,
895
+ status,
896
+ no_ship: true,
897
+ noShipReason: "P0 dry-run only; global autonomy remains disabled until current-source proof and policy gates pass.",
898
+ globalAutonomyReady: false,
899
+ globalAutonomyNoShip: true,
900
+ dryRun: true,
901
+ noExecution: true,
902
+ childDispatchAllowed: false,
903
+ daemonStarted: false,
904
+ productionWritesPerformed: false,
905
+ autoApply: false,
906
+ networkAccessed: false,
907
+ bodyStored: false,
908
+ promptBodiesStored: false,
909
+ outputBodiesStored: false,
910
+ specGate: {
911
+ schema: "zob.autonomous-spec-gate.v1",
912
+ userNeedHash: sha256(userNeed),
913
+ refinedSpecHash: sha256(refinedSpec),
914
+ constraintHashes: hashes(constraints),
915
+ acceptanceCriteriaHashes: hashes(acceptanceCriteria),
916
+ expectedArtifactHashes: hashes(expectedArtifacts),
917
+ allowedPaths,
918
+ forbiddenPaths,
919
+ allowedPathsRequired: true,
920
+ pathGatePassed: pathGateErrors.length === 0,
921
+ pathGateErrors,
922
+ applyPolicyRequired: true,
923
+ applyPolicyProvided,
924
+ applyPolicy,
925
+ budgetProfileRequired: true,
926
+ budgetProfileProvided,
927
+ budgetProfile,
928
+ autonomousStrictBudgetRequired: true,
929
+ autonomousStrictBudgetSatisfied: budgetProfile === "strict_requested",
930
+ risk,
931
+ specTextStored: false,
932
+ specLocked,
933
+ launchAuthorizationRequired: true,
934
+ userLaunchConfirmed,
935
+ launchAuthorizesInScopeActions: launchAuthorization.launchAuthorizesInScopeActions,
936
+ actionExecutionBlockedUntilLaunch: launchAuthorization.actionExecutionBlockedUntilLaunch,
937
+ clarificationRequired,
938
+ clarificationQuestions,
939
+ blockers,
940
+ },
941
+ launchAuthorization,
942
+ contextPlan: {
943
+ schema: "zob.autonomous-context-plan.v1",
944
+ contextNeedTags: detectContextNeedTags(specText),
945
+ contextScope,
946
+ contextScopeValid: contextScopeErrors.length === 0,
947
+ contextScopeErrors,
948
+ lookupResults: contextArtifacts.lookupResults,
949
+ contextPack: contextArtifacts.contextPack,
950
+ contextPackValid,
951
+ contextPackErrors,
952
+ lookupPlan: {
953
+ queryHash: sha256(refinedSpec),
954
+ allowedSources: contextScope.allowedSources,
955
+ citationRequired: true,
956
+ boundedContextOnly: true,
957
+ gbrainImportEnabled: false,
958
+ gbrainEmbedEnabled: false,
959
+ gbrainSyncEnabled: false,
960
+ gbrainWriteEnabled: false,
961
+ },
962
+ },
963
+ runtimeGates,
964
+ modelRoutingPlan,
965
+ runGraph,
966
+ factorySelection: {
967
+ schema: "zob.autonomous-factory-selection.v1",
968
+ queryHash: reuseScout.queryHash,
969
+ selectionStatus,
970
+ selectedFactory,
971
+ selectedFactorySourcePath: selectedFactory ? `.pi/factories/${selectedFactory}/factory.json` : undefined,
972
+ manifestAvailability,
973
+ candidateCount: candidates.length,
974
+ reuseScoutCandidates: candidates.filter(isRecord).map((candidate) => ({
975
+ kind: candidate.kind,
976
+ id: candidate.id,
977
+ sourcePath: candidate.sourcePath,
978
+ score: candidate.score,
979
+ reasonCodes: candidate.reasonCodes,
980
+ summaryHash: candidate.summaryHash,
981
+ })),
982
+ deterministicScoring: factoryScore,
983
+ factoryForgeAvailable,
984
+ factoryReadiness,
985
+ currentSourceProofRequired: true,
986
+ proofBeforeExecutionRequired,
987
+ noAutoActivation: true,
988
+ quarantineRequiredForNewFactory: selectionStatus === "factory_forge_quarantine_recommended",
989
+ },
990
+ proofPlan: {
991
+ schema: "zob.autonomous-proof-plan.v1",
992
+ parentOwned: true,
993
+ stages: [
994
+ { name: "spec_lock", required: true, passed: specLocked },
995
+ { name: "launch_authorization", required: true, passed: launchAuthorization.launchAuthorizesInScopeActions, executionBlockedUntilLaunch: launchAuthorization.actionExecutionBlockedUntilLaunch, dispatchAllowed: false, noExecution: true },
996
+ { name: "context_scope", required: true, passed: contextScopeErrors.length === 0, citationRequired: true },
997
+ { name: "context_lookup_and_pack", required: true, passed: contextPackValid, citationRequired: true, boundedContextOnly: true, dispatchAllowed: false },
998
+ { name: "runtime_gates_preflight", required: true, passed: runtimeGatesValid, dispatchAllowed: false, noExecution: true },
999
+ { name: "model_routing_plan", required: true, passed: modelRoutingPlanValid, dispatchAllowed: false, liveRoutingEnabled: false },
1000
+ { name: "factory_selection", required: true, passed: Boolean(selectedFactory) },
1001
+ { name: "registered_factory_current_source_proof", required: true, passed: factoryReadiness.registeredBatchReady === true, dispatchAllowed: false, proofBeforeExecutionRequired },
1002
+ { name: "smoke", required: true, dispatchAllowed: false, sentinelRequired: "SMOKE_PASSED.sentinel" },
1003
+ { name: "smoke_oracle", required: true, dispatchAllowed: false, verdictRequired: "PASS", noShipRequired: false },
1004
+ { name: "pilot", required: true, dispatchAllowed: false, requiresSmokeOracle: true, sentinelRequired: "PILOT_PASSED.sentinel" },
1005
+ { name: "pilot_oracle", required: true, dispatchAllowed: false, verdictRequired: "PASS", noShipRequired: false },
1006
+ { name: "batch", required: true, dispatchAllowed: false, requiresPilotOracle: true, sentinelRequired: "BATCH_PASSED.sentinel", batchConcurrencyCapRequired: true },
1007
+ { name: "final_report", required: true, dispatchAllowed: false, validationJsonRequired: true, doneSentinelRequired: true },
1008
+ ],
1009
+ gates: ["strict_goal_spec", "context_scope", "context_lookup_and_pack", "runtime_gates_preflight", "model_routing_plan", "run_graph_ready", "registered_factory_current_source_proof", "budget_preflight", "model_routing_policy", "sandbox_apply_policy", "daemon_policy", "oracle_review", "mission_control_proposals_only"],
1010
+ noShipConditions: ["clarification_required", "context_scope_invalid", "context_pack_invalid", "runtime_gates_invalid", "model_routing_plan_invalid", "factory_selection_missing", "oracle_fail", "budget_exceeded", "secret_reference", "production_apply_requested", "current_source_proof_missing"],
1011
+ },
1012
+ finalReportPlan: {
1013
+ schema: "zob.autonomous-final-report-plan.v1",
1014
+ artifactPath: `reports/autonomous-runs/${runId}/dry-run-report.json`,
1015
+ includesEvidenceRefs: true,
1016
+ includesBlockers: true,
1017
+ includesNoShipDecision: true,
1018
+ rawSpecStored: false,
1019
+ },
1020
+ validation: {
1021
+ passed: blockers.length === 0,
1022
+ blockers,
1023
+ warnings: ["dry_run_only", "global_autonomy_no_ship", "no_child_dispatch", ...(proofBeforeExecutionRequired ? ["selected_factory_current_source_proof_required_before_execution"] : [])],
1024
+ },
1025
+ generatedAt: new Date().toISOString(),
1026
+ };
1027
+ if (hasForbiddenBodyKeys(report)) throw new Error("autonomous dry-run report would store forbidden plaintext body keys");
1028
+ return report;
1029
+ }
1030
+
1031
+ export function buildAutonomousRuntimeDryRunValidation(report: Record<string, unknown>): Record<string, unknown> {
1032
+ const validation = {
1033
+ schema: "zob.autonomous-runtime-dry-run-validation.v1",
1034
+ runId: report.runId,
1035
+ status: report.status,
1036
+ passed: report.status === "dry_run_plan_ready",
1037
+ no_ship: report.no_ship,
1038
+ dryRun: report.dryRun,
1039
+ noExecution: report.noExecution,
1040
+ childDispatchAllowed: report.childDispatchAllowed,
1041
+ daemonStarted: report.daemonStarted,
1042
+ productionWritesPerformed: report.productionWritesPerformed,
1043
+ autoApply: report.autoApply,
1044
+ networkAccessed: report.networkAccessed,
1045
+ globalAutonomyReady: report.globalAutonomyReady,
1046
+ globalAutonomyNoShip: report.globalAutonomyNoShip,
1047
+ blockers: isRecord(report.validation) && Array.isArray(report.validation.blockers) ? report.validation.blockers : [],
1048
+ requiredArtifacts: ["spec-gate.json", "context-scope.json", "context-lookup.json", "context-pack.json", "runtime-gates.json", "model-routing-plan.json", "run-graph.json", "factory-selection.json", "proof-plan.json", "dry-run-report.json", "validation.json", "final-report.md", "DRY_RUN_READY.sentinel"],
1049
+ sentinel: report.status === "dry_run_plan_ready" ? "DRY_RUN_READY.sentinel" : undefined,
1050
+ bodyStored: false,
1051
+ promptBodiesStored: false,
1052
+ outputBodiesStored: false,
1053
+ generatedAt: new Date().toISOString(),
1054
+ };
1055
+ if (hasForbiddenBodyKeys(validation)) throw new Error("autonomous dry-run validation would store forbidden plaintext body keys");
1056
+ return validation;
1057
+ }
1058
+
1059
+ export function buildAutonomousRuntimeDryRunFinalReport(report: Record<string, unknown>): string {
1060
+ const factorySelection = isRecord(report.factorySelection) ? report.factorySelection : {};
1061
+ const validation = isRecord(report.validation) ? report.validation : {};
1062
+ const blockers = Array.isArray(validation.blockers) ? validation.blockers.map((blocker) => `- ${String(blocker)}`).join("\n") : "";
1063
+ return [
1064
+ "# Autonomous Runtime Dry-Run Report",
1065
+ "",
1066
+ `Run ID: ${String(report.runId ?? "unknown")}`,
1067
+ `Status: ${String(report.status ?? "unknown")}`,
1068
+ `No-ship: ${String(report.no_ship ?? true)}`,
1069
+ "",
1070
+ "## Safety posture",
1071
+ "",
1072
+ `- Dry-run only: ${String(report.dryRun === true)}`,
1073
+ `- No execution: ${String(report.noExecution === true)}`,
1074
+ `- Child dispatch allowed: ${String(report.childDispatchAllowed === true)}`,
1075
+ `- Daemon started: ${String(report.daemonStarted === true)}`,
1076
+ `- Production writes performed: ${String(report.productionWritesPerformed === true)}`,
1077
+ `- Auto-apply: ${String(report.autoApply === true)}`,
1078
+ `- Global autonomy no-ship: ${String(report.globalAutonomyNoShip === true)}`,
1079
+ "",
1080
+ "## Factory selection",
1081
+ "",
1082
+ `- Status: ${String(factorySelection.selectionStatus ?? "unknown")}`,
1083
+ `- Selected factory: ${String(factorySelection.selectedFactory ?? "none")}`,
1084
+ "",
1085
+ "## Blockers",
1086
+ "",
1087
+ blockers || "- None for dry-run plan readiness.",
1088
+ "",
1089
+ "## Evidence refs",
1090
+ "",
1091
+ "- spec-gate.json",
1092
+ "- context-scope.json",
1093
+ "- context-lookup.json",
1094
+ "- context-pack.json",
1095
+ "- runtime-gates.json",
1096
+ "- model-routing-plan.json",
1097
+ "- run-graph.json",
1098
+ "- factory-selection.json",
1099
+ "- proof-plan.json",
1100
+ "- dry-run-report.json",
1101
+ "- validation.json",
1102
+ "- DRY_RUN_READY.sentinel when status=dry_run_plan_ready",
1103
+ "",
1104
+ "Compliance: P0 dry-run artifact only; no global autonomy claim.",
1105
+ "",
1106
+ ].join("\n");
1107
+ }