clinkx 1.1.0 → 1.1.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 (162) hide show
  1. package/CHANGELOG.md +39 -1
  2. package/README.md +210 -177
  3. package/clinkx-workflows/dist/architecture-comparison/admission.d.ts +5 -0
  4. package/clinkx-workflows/dist/architecture-comparison/admission.js +50 -0
  5. package/clinkx-workflows/dist/architecture-comparison/admission.js.map +1 -0
  6. package/clinkx-workflows/dist/architecture-comparison/contract.d.ts +995 -0
  7. package/clinkx-workflows/dist/architecture-comparison/contract.js +149 -0
  8. package/clinkx-workflows/dist/architecture-comparison/contract.js.map +1 -0
  9. package/clinkx-workflows/dist/architecture-comparison/runtime.d.ts +29 -0
  10. package/clinkx-workflows/dist/architecture-comparison/runtime.js +387 -0
  11. package/clinkx-workflows/dist/architecture-comparison/runtime.js.map +1 -0
  12. package/clinkx-workflows/dist/contained-file.js +1 -1
  13. package/clinkx-workflows/dist/contained-file.js.map +1 -1
  14. package/clinkx-workflows/dist/council-execution-policy.d.ts +4 -2
  15. package/clinkx-workflows/dist/council-execution-policy.js +5 -1
  16. package/clinkx-workflows/dist/council-execution-policy.js.map +1 -1
  17. package/clinkx-workflows/dist/dashboard/activity-contract.d.ts +72 -72
  18. package/clinkx-workflows/dist/dashboard/contracts.d.ts +1564 -122
  19. package/clinkx-workflows/dist/dashboard/contracts.js +4 -0
  20. package/clinkx-workflows/dist/dashboard/contracts.js.map +1 -1
  21. package/clinkx-workflows/dist/dashboard/progress-report-contract.d.ts +12 -12
  22. package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.d.ts +8 -8
  23. package/clinkx-workflows/dist/dashboard/scanner.d.ts +3 -0
  24. package/clinkx-workflows/dist/dashboard/scanner.js +27 -0
  25. package/clinkx-workflows/dist/dashboard/scanner.js.map +1 -1
  26. package/clinkx-workflows/dist/dashboard/session-log-contract.d.ts +48 -48
  27. package/clinkx-workflows/dist/dashboard/session-log-redaction.d.ts +2 -0
  28. package/clinkx-workflows/dist/dashboard/session-log-redaction.js +4 -0
  29. package/clinkx-workflows/dist/dashboard/session-log-redaction.js.map +1 -1
  30. package/clinkx-workflows/dist/dashboard/verified-repair-contract.d.ts +191 -0
  31. package/clinkx-workflows/dist/dashboard/verified-repair-contract.js +28 -0
  32. package/clinkx-workflows/dist/dashboard/verified-repair-contract.js.map +1 -0
  33. package/clinkx-workflows/dist/dashboard-ui/assets/index-BdpmbPps.js +115 -0
  34. package/clinkx-workflows/dist/dashboard-ui/assets/style-Im5i1iAs.css +1 -0
  35. package/clinkx-workflows/dist/dashboard-ui/index.html +2 -2
  36. package/clinkx-workflows/dist/engine.d.ts +6 -0
  37. package/clinkx-workflows/dist/engine.js +78 -7
  38. package/clinkx-workflows/dist/engine.js.map +1 -1
  39. package/clinkx-workflows/dist/index.d.ts +3 -0
  40. package/clinkx-workflows/dist/index.js +3 -2
  41. package/clinkx-workflows/dist/index.js.map +1 -1
  42. package/clinkx-workflows/dist/reducers/index.d.ts +9 -1
  43. package/clinkx-workflows/dist/reducers/index.js +22 -0
  44. package/clinkx-workflows/dist/reducers/index.js.map +1 -1
  45. package/clinkx-workflows/dist/state.js +17 -7
  46. package/clinkx-workflows/dist/state.js.map +1 -1
  47. package/clinkx-workflows/dist/validators/architecture-comparison.d.ts +2 -0
  48. package/clinkx-workflows/dist/validators/architecture-comparison.js +12 -0
  49. package/clinkx-workflows/dist/validators/architecture-comparison.js.map +1 -0
  50. package/clinkx-workflows/dist/validators/index.js +4 -0
  51. package/clinkx-workflows/dist/validators/index.js.map +1 -1
  52. package/clinkx-workflows/dist/validators/verified-repair.d.ts +2 -0
  53. package/clinkx-workflows/dist/validators/verified-repair.js +12 -0
  54. package/clinkx-workflows/dist/validators/verified-repair.js.map +1 -0
  55. package/clinkx-workflows/dist/verification-proof.d.ts +254 -0
  56. package/clinkx-workflows/dist/verification-proof.js +195 -0
  57. package/clinkx-workflows/dist/verification-proof.js.map +1 -0
  58. package/clinkx-workflows/dist/verified-repair/admission.d.ts +72 -0
  59. package/clinkx-workflows/dist/verified-repair/admission.js +63 -0
  60. package/clinkx-workflows/dist/verified-repair/admission.js.map +1 -0
  61. package/clinkx-workflows/dist/verified-repair/contract.d.ts +1910 -0
  62. package/clinkx-workflows/dist/verified-repair/contract.js +127 -0
  63. package/clinkx-workflows/dist/verified-repair/contract.js.map +1 -0
  64. package/clinkx-workflows/dist/verified-repair/host.d.ts +32 -0
  65. package/clinkx-workflows/dist/verified-repair/host.js +2 -0
  66. package/clinkx-workflows/dist/verified-repair/host.js.map +1 -0
  67. package/clinkx-workflows/dist/verified-repair/prompts.d.ts +12 -0
  68. package/clinkx-workflows/dist/verified-repair/prompts.js +58 -0
  69. package/clinkx-workflows/dist/verified-repair/prompts.js.map +1 -0
  70. package/clinkx-workflows/dist/verified-repair/result.d.ts +16 -0
  71. package/clinkx-workflows/dist/verified-repair/result.js +102 -0
  72. package/clinkx-workflows/dist/verified-repair/result.js.map +1 -0
  73. package/clinkx-workflows/dist/verified-repair/runtime.d.ts +28 -0
  74. package/clinkx-workflows/dist/verified-repair/runtime.js +186 -0
  75. package/clinkx-workflows/dist/verified-repair/runtime.js.map +1 -0
  76. package/clinkx-workflows/dist/workflow-tools.d.ts +3 -0
  77. package/clinkx-workflows/dist/workflow-tools.js +148 -14
  78. package/clinkx-workflows/dist/workflow-tools.js.map +1 -1
  79. package/clinkx-workflows/dist/workflow-verification-contract.d.ts +539 -0
  80. package/clinkx-workflows/dist/workflow-verification-contract.js +52 -0
  81. package/clinkx-workflows/dist/workflow-verification-contract.js.map +1 -0
  82. package/clinkx-workflows/dist/workflow-verification.d.ts +15 -0
  83. package/clinkx-workflows/dist/workflow-verification.js +218 -0
  84. package/clinkx-workflows/dist/workflow-verification.js.map +1 -0
  85. package/clinkx-workflows/templates/architecture-comparison/candidate.txt +29 -0
  86. package/clinkx-workflows/templates/architecture-comparison/judge.txt +31 -0
  87. package/clinkx-workflows/templates/verified-repair/investigate.txt +20 -0
  88. package/clinkx-workflows/templates/verified-repair/repair.txt +11 -0
  89. package/clinkx-workflows/templates/verified-repair/review.txt +18 -0
  90. package/clinkx-workflows/workflows/architecture-comparison.yaml +133 -0
  91. package/clinkx-workflows/workflows/verified-repair.yaml +104 -0
  92. package/dist/allowed-roots.js +4 -1
  93. package/dist/allowed-roots.js.map +1 -1
  94. package/dist/codex/app-server-client.d.ts +1 -0
  95. package/dist/codex/app-server-client.js +3 -2
  96. package/dist/codex/app-server-client.js.map +1 -1
  97. package/dist/context-builder/diagnostics.d.ts +1 -0
  98. package/dist/context-builder/diagnostics.js +1 -1
  99. package/dist/context-builder/diagnostics.js.map +1 -1
  100. package/dist/context-builder/discovery.d.ts +18 -1
  101. package/dist/context-builder/discovery.js +69 -1
  102. package/dist/context-builder/discovery.js.map +1 -1
  103. package/dist/context-builder/handler.js +8 -1
  104. package/dist/context-builder/handler.js.map +1 -1
  105. package/dist/context-builder/lifecycle-contract.d.ts +24 -24
  106. package/dist/context-builder/refine-handler.js +16 -1
  107. package/dist/context-builder/refine-handler.js.map +1 -1
  108. package/dist/context-builder/secrets.d.ts +11 -0
  109. package/dist/context-builder/secrets.js +81 -1
  110. package/dist/context-builder/secrets.js.map +1 -1
  111. package/dist/context-builder/versions.d.ts +5 -2
  112. package/dist/context-builder/versions.js +5 -2
  113. package/dist/context-builder/versions.js.map +1 -1
  114. package/dist/dashboard-cli.js +10 -3
  115. package/dist/dashboard-cli.js.map +1 -1
  116. package/dist/dashboard-gateway/main.js +8 -3
  117. package/dist/dashboard-gateway/main.js.map +1 -1
  118. package/dist/index.d.ts +2 -0
  119. package/dist/index.js +8 -2
  120. package/dist/index.js.map +1 -1
  121. package/dist/project-verification/contract.d.ts +537 -0
  122. package/dist/project-verification/contract.js +40 -0
  123. package/dist/project-verification/contract.js.map +1 -0
  124. package/dist/project-verification/files.d.ts +23 -0
  125. package/dist/project-verification/files.js +80 -0
  126. package/dist/project-verification/files.js.map +1 -0
  127. package/dist/project-verification/process.d.ts +7 -0
  128. package/dist/project-verification/process.js +115 -0
  129. package/dist/project-verification/process.js.map +1 -0
  130. package/dist/project-verification/runner.d.ts +35 -0
  131. package/dist/project-verification/runner.js +185 -0
  132. package/dist/project-verification/runner.js.map +1 -0
  133. package/dist/project-verification/service.d.ts +37 -0
  134. package/dist/project-verification/service.js +151 -0
  135. package/dist/project-verification/service.js.map +1 -0
  136. package/dist/provider-doctor.d.ts +22 -0
  137. package/dist/provider-doctor.js +22 -0
  138. package/dist/provider-doctor.js.map +1 -0
  139. package/dist/server.js +29 -1
  140. package/dist/server.js.map +1 -1
  141. package/dist/verification-tools.d.ts +90 -0
  142. package/dist/verification-tools.js +120 -0
  143. package/dist/verification-tools.js.map +1 -0
  144. package/dist/verified-repair/files.d.ts +22 -0
  145. package/dist/verified-repair/files.js +114 -0
  146. package/dist/verified-repair/files.js.map +1 -0
  147. package/dist/verified-repair/host.d.ts +14 -0
  148. package/dist/verified-repair/host.js +612 -0
  149. package/dist/verified-repair/host.js.map +1 -0
  150. package/docs/configuration.md +493 -0
  151. package/docs/engineering-recipes.md +415 -0
  152. package/docs/security.md +293 -0
  153. package/docs/verification/README.md +59 -0
  154. package/docs/verification/dashboard-real-disk.md +436 -0
  155. package/docs/verification/project-checks.example.json +14 -0
  156. package/docs/verification/project-checks.md +444 -0
  157. package/docs/verification/workflow-handoff.md +113 -0
  158. package/package.json +13 -6
  159. package/scripts/provider-doctor-core.mjs +364 -0
  160. package/scripts/provider-doctor-probe.mjs +34 -0
  161. package/clinkx-workflows/dist/dashboard-ui/assets/index-JPHQVtn9.js +0 -106
  162. package/clinkx-workflows/dist/dashboard-ui/assets/style-DOMHk-j6.css +0 -1
@@ -0,0 +1,186 @@
1
+ import { SchemaValidationError, OutputSizeError } from "../artifacts.js";
2
+ import { relative } from "node:path";
3
+ import { readContainedRelativeFile } from "../contained-file.js";
4
+ import { FixProposalSchema, InvestigationSchema, MAX_REPAIR_PACKET_BYTES, MAX_REPAIR_PROPOSAL_BYTES, RepairPacketSchema, RepairRecordSchema, RepairReviewSchema, REPAIR_REFS, assertRepairBounded, } from "./contract.js";
5
+ import { bytesDigest } from "../architecture-comparison/contract.js";
6
+ import { publishRepairRecord } from "./result.js";
7
+ import { hasCredentialTokenShape } from "../dashboard/session-log-redaction.js";
8
+ import { WorkflowCancellationError } from "../errors.js";
9
+ const PROVIDER_PHASES = {
10
+ [REPAIR_REFS.investigate]: { phase: "investigate", packet: "capture" },
11
+ [REPAIR_REFS.repair]: { phase: "repair", packet: "reproduce" },
12
+ [REPAIR_REFS.review]: { phase: "review", packet: "fixed" },
13
+ };
14
+ /** Fixed phase policy; the existing engine remains the only dispatcher. */
15
+ export class VerifiedRepairRuntime {
16
+ host;
17
+ runId;
18
+ runDir;
19
+ packet;
20
+ providerPackets = new Map();
21
+ retained = new Map();
22
+ finalization;
23
+ invalidArtifact;
24
+ constructor(host, runId, runDir) {
25
+ this.host = host;
26
+ this.runId = runId;
27
+ this.runDir = runDir;
28
+ }
29
+ async prepareProvider(reference, signal) {
30
+ if (this.invalidArtifact !== undefined)
31
+ throw new Error(`invalid repair provider artifact: ${this.invalidArtifact.phase}`);
32
+ const binding = PROVIDER_PHASES[reference];
33
+ if (binding === undefined)
34
+ throw new Error("unexpected repair provider call");
35
+ if (this.packet?.phase !== binding.packet)
36
+ throw new Error(`repair prerequisite unavailable for ${binding.phase}`);
37
+ await this.verifyRetained();
38
+ await this.host.assertProviderPhase(binding.phase, signal);
39
+ assertRepairBounded(this.packet, MAX_REPAIR_PACKET_BYTES);
40
+ this.providerPackets.set(reference, JSON.stringify(this.packet));
41
+ }
42
+ providerPacket(reference) {
43
+ const packet = this.providerPackets.get(reference);
44
+ if (packet === undefined)
45
+ throw new Error("repair provider packet was not prepared");
46
+ return packet;
47
+ }
48
+ async beforeDispatch(reference, input, signal) {
49
+ const binding = PROVIDER_PHASES[reference];
50
+ if (binding === undefined || input["continuation_id"] !== undefined ||
51
+ typeof input["prompt"] !== "string" || !input["prompt"].endsWith(`\n\nFROZEN REPAIR PACKET\n${this.providerPacket(reference)}`)) {
52
+ throw new Error("repair dispatch is not the fresh frozen packet");
53
+ }
54
+ await this.verifyRetained();
55
+ await this.host.assertProviderPhase(binding.phase, signal);
56
+ }
57
+ validateOutput(reference, value) {
58
+ const schema = reference === REPAIR_REFS.investigate ? InvestigationSchema
59
+ : reference === REPAIR_REFS.repair ? FixProposalSchema
60
+ : reference === REPAIR_REFS.review ? RepairReviewSchema
61
+ : reference === REPAIR_REFS.record ? RepairRecordSchema : RepairPacketSchema;
62
+ const parsed = schema.parse(value);
63
+ assertRepairBounded(parsed, MAX_REPAIR_PROPOSAL_BYTES);
64
+ if (hasCredentialTokenShape(JSON.stringify(parsed)))
65
+ throw new Error("repair artifact contains credential-like material; publication is rejected");
66
+ this.host.validateProviderOutput?.(parsed);
67
+ if (this.packet !== undefined && parsed.frozen_digest !== this.packet.frozen_digest)
68
+ throw new Error("repair artifact frozen identity mismatch");
69
+ }
70
+ noteInvalidArtifact(reference, error) {
71
+ if (!(reference in PROVIDER_PHASES))
72
+ return;
73
+ // JSON parser errors can include excerpts of untrusted provider text.
74
+ // Preserve the phase and failure class without copying those excerpts.
75
+ const message = error instanceof SchemaValidationError ? "provider artifact failed strict JSON/schema validation"
76
+ : error instanceof OutputSizeError ? "provider artifact exceeded repair byte limits"
77
+ : "provider artifact identity or semantic contract is invalid";
78
+ this.invalidArtifact ??= { kind: "invalid_artifact", phase: reference, message };
79
+ }
80
+ recordWritten(artifact) {
81
+ this.retained.set(artifact.reference, {
82
+ path: relative(this.runDir, artifact.filePath),
83
+ sha256: bytesDigest(`${JSON.stringify(artifact.parsed, null, 2)}\n`),
84
+ });
85
+ }
86
+ async reduce(operation, artifacts, signal) {
87
+ if (operation !== "record" && this.invalidArtifact !== undefined)
88
+ throw new Error(`invalid repair provider artifact: ${this.invalidArtifact.phase}`);
89
+ await this.verifyRetained();
90
+ const proposal = (reference) => {
91
+ const artifact = artifacts.find((entry) => entry.reference === reference);
92
+ if (artifact === undefined || !this.retained.has(reference))
93
+ throw new Error(`repair prerequisite unavailable: ${reference}`);
94
+ this.validateOutput(reference, artifact.parsed);
95
+ return artifact.parsed;
96
+ };
97
+ if (operation === "record") {
98
+ // The run owner publishes again after cleanup with actual terminal state.
99
+ // A final reducer is never the interruption publication boundary.
100
+ return JSON.stringify(RepairRecordSchema.parse(await this.host.record("completed")));
101
+ }
102
+ const packet = operation === "capture" ? await this.host.capture(signal)
103
+ : operation === "reproduce" ? await this.host.reproduce(proposal(REPAIR_REFS.investigate), signal)
104
+ : operation === "fixed" ? await this.host.fixed(proposal(REPAIR_REFS.repair), signal)
105
+ : await this.host.independently(proposal(REPAIR_REFS.review), signal);
106
+ const parsed = RepairPacketSchema.parse(packet);
107
+ if (parsed.phase !== operation || (this.packet !== undefined && parsed.frozen_digest !== this.packet.frozen_digest))
108
+ throw new Error("repair host packet phase or frozen identity mismatch");
109
+ assertRepairBounded(parsed, MAX_REPAIR_PACKET_BYTES);
110
+ this.packet = parsed;
111
+ return JSON.stringify(this.packet);
112
+ }
113
+ /** Await all owned cleanup before publication, even with an aborted run signal. */
114
+ finalize(status, reason, signal) {
115
+ this.finalization ??= this.finalizeOnce(status, reason, signal);
116
+ return this.finalization;
117
+ }
118
+ async cleanupUnadmitted(reason) {
119
+ try {
120
+ await this.host.abort(reason);
121
+ }
122
+ finally {
123
+ await this.host.cleanup();
124
+ }
125
+ }
126
+ async finalizeOnce(status, reason, signal) {
127
+ const requestedCompletion = status === "completed";
128
+ const finalizationErrors = [];
129
+ const abort = async (error) => {
130
+ try {
131
+ await this.host.abort(error);
132
+ }
133
+ catch (abortError) {
134
+ finalizationErrors.push(abortError);
135
+ }
136
+ };
137
+ if (this.invalidArtifact !== undefined)
138
+ await abort(this.invalidArtifact);
139
+ if (status !== "completed")
140
+ await abort(reason ?? status);
141
+ try {
142
+ await this.host.cleanup();
143
+ }
144
+ catch (error) {
145
+ finalizationErrors.push(error);
146
+ status = status === "completed" ? "failed" : status;
147
+ await abort(error);
148
+ }
149
+ if (status === "completed" && finalizationErrors.length > 0)
150
+ status = "failed";
151
+ if (requestedCompletion && signal?.aborted) {
152
+ status = "cancelled";
153
+ await abort(signal.reason ?? "cancelled during finalization");
154
+ }
155
+ let record = RepairRecordSchema.parse(await this.host.record(status));
156
+ if (record.run_id !== this.runId || record.execution_status !== status)
157
+ throw new Error("repair terminal record identity mismatch");
158
+ await publishRepairRecord(this.runDir, record);
159
+ // Cancellation can arrive while the host projection or atomic publication
160
+ // awaits I/O. Reproject partial facts before the owner commits terminal state.
161
+ if (requestedCompletion && signal?.aborted && status !== "cancelled") {
162
+ await abort(signal.reason ?? "cancelled during publication");
163
+ status = "cancelled";
164
+ record = RepairRecordSchema.parse(await this.host.record(status));
165
+ if (record.run_id !== this.runId || record.execution_status !== status)
166
+ throw new Error("repair terminal record identity mismatch");
167
+ await publishRepairRecord(this.runDir, record);
168
+ }
169
+ if (requestedCompletion && status === "cancelled")
170
+ throw new WorkflowCancellationError();
171
+ if (finalizationErrors.length > 0)
172
+ throw new AggregateError(finalizationErrors, "repair finalization failed after retaining terminal facts");
173
+ return JSON.stringify(record);
174
+ }
175
+ async verifyRetained() {
176
+ for (const [reference, fact] of this.retained) {
177
+ const read = await readContainedRelativeFile(this.runDir, fact.path, {
178
+ wantContent: true, requireRegular: true, requireExactRequestedPath: true,
179
+ maxBytes: MAX_REPAIR_PROPOSAL_BYTES,
180
+ });
181
+ if (bytesDigest(read.content) !== fact.sha256)
182
+ throw new Error(`retained repair artifact changed: ${reference}`);
183
+ }
184
+ }
185
+ }
186
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/verified-repair/runtime.ts"],"names":[],"mappings":"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"}
@@ -26,7 +26,10 @@ import type { Variable } from "./schema.js";
26
26
  import { type WorkflowContextRequestedMode, type WorkflowContextPolicy } from "./context-mode-resolver.js";
27
27
  import { type AvailableCliCapability, type ResolvedRoster } from "./roster-contract.js";
28
28
  import type { RosterLoader } from "./rosters.js";
29
+ import type { VerifiedRepairHost } from "./verified-repair/host.js";
29
30
  export interface WorkflowToolsOptions {
31
+ /** Root-owned contract capture, scoped edits, and native verification. */
32
+ readonly verifiedRepairHost?: VerifiedRepairHost | undefined;
30
33
  /**
31
34
  * Factory that creates a ClinkBackend for a given run.
32
35
  * For standalone server: `(runId) => new ClinkSession({ runId })`
@@ -25,7 +25,7 @@ import { readRunStateForStatus, reapRunCancelled, WorkflowStateStore } from "./s
25
25
  import { isTerminalContextBuilderLifecycleStatus, parseContextBuilderLifecycleStateV1, } from "./context-builder-lifecycle-contract.js";
26
26
  import { validateRunId } from "./run-id.js";
27
27
  import { validateDynamicPaths } from "./path-validation.js";
28
- import { getMaxPromptBytes, getRunStateDir, getTemplatesPath, getWorkflowsContextDefault, getWorkflowsContextDefaultCurator, getWorkflowsMaxConcurrentAsync, resolveWorkspaceRoot, } from "./config.js";
28
+ import { getMaxPromptBytes, getRunStateDir, getRunsDir, getTemplatesPath, getWorkflowsContextDefault, getWorkflowsContextDefaultCurator, getWorkflowsMaxConcurrentAsync, resolveWorkspaceRoot, } from "./config.js";
29
29
  import { WorkflowCancellationError, WorkflowValidationError, } from "./errors.js";
30
30
  import { shutdownCoordinator } from "./shutdown.js";
31
31
  import { logger } from "./logger.js";
@@ -54,6 +54,14 @@ import { validatePlanReviewCallBindings, validatePlanReviewPreparedInputPolicy,
54
54
  import { ContainedFilePolicyError, readContainedRelativeFile, } from "./contained-file.js";
55
55
  import { createDashboardRunReader } from "./dashboard/read-model.js";
56
56
  import { ROSTER_NAME_PATTERN, ResolvedRosterSchema, } from "./roster-contract.js";
57
+ import { materializeArchitectureRoutes } from "./architecture-comparison/admission.js";
58
+ import { ARCHITECTURE_WORKFLOW } from "./architecture-comparison/contract.js";
59
+ import { inspectArchitectureComparisonRecord } from "./architecture-comparison/runtime.js";
60
+ import { VERIFIED_REPAIR_WORKFLOW, MAX_REPAIR_RECORD_BYTES, RepairRecordSchema, assertRepairBounded } from "./verified-repair/contract.js";
61
+ import { materializeVerifiedRepairRoutes, repairRoutesFromVariables } from "./verified-repair/admission.js";
62
+ import { VerifiedRepairRuntime } from "./verified-repair/runtime.js";
63
+ import { inspectVerifiedRepairRecord } from "./verified-repair/result.js";
64
+ import { readWorkflowVerification } from "./workflow-verification.js";
57
65
  async function inspectLegacyWorkflowSessionLogGeneration(runDir, runId) {
58
66
  try {
59
67
  const result = await createDashboardRunReader().inspectGeneration?.(dirname(runDir), runId);
@@ -1339,7 +1347,7 @@ async function executeRunWorkflow(server, options, args, signal, progressToken)
1339
1347
  throw new McpError(ErrorCode.InvalidParams, `Invalid run_id "${runId}". Must match [A-Za-z0-9_-]{1,64}.`);
1340
1348
  }
1341
1349
  const validatorRegistry = createValidatorRegistry();
1342
- const loaded = loadWorkflow(workflow, {
1350
+ let loaded = loadWorkflow(workflow, {
1343
1351
  templatesRoot: options.templatesRoot ?? getTemplatesPath(),
1344
1352
  workflowsPath: options.workflowsPath,
1345
1353
  validatorRegistry,
@@ -1400,20 +1408,30 @@ async function executeRunWorkflow(server, options, args, signal, progressToken)
1400
1408
  throw new McpError(ErrorCode.InvalidParams, `chairman_effort parameter is not supported for workflow "${workflow}"`);
1401
1409
  }
1402
1410
  resolvedVariables = validateVariables(suppliedVariables, loaded.definition.variables);
1411
+ try {
1412
+ loaded = { ...loaded, normalized: materializeArchitectureRoutes(loaded.normalized, resolvedVariables, options.planReviewAvailableCliNames ?? options.availableCliNames, options.validateInvocationOverrides) };
1413
+ loaded = { ...loaded, normalized: materializeVerifiedRepairRoutes(loaded.normalized, resolvedVariables, options.planReviewAvailableCliNames ?? options.availableCliNames, options.validateInvocationOverrides) };
1414
+ if (workflow === VERIFIED_REPAIR_WORKFLOW && options.verifiedRepairHost === undefined) {
1415
+ throw new Error("verified-repair requires the root host capability");
1416
+ }
1417
+ }
1418
+ catch (error) {
1419
+ throw new McpError(ErrorCode.InvalidParams, error instanceof Error ? error.message : String(error));
1420
+ }
1403
1421
  // When the runner is absent (preflight disabled / hard kill), the boundary
1404
1422
  // validator is inert. Skip it WITHOUT evaluating the context-default env
1405
1423
  // parsers — getWorkflowsContextDefaultCurator() throws on empty env, and a
1406
1424
  // runner-less run_workflow must never trip context env parsing.
1407
1425
  let contextPolicy;
1408
- if (options.contextBuilderRunner != null) {
1426
+ if (workflow !== VERIFIED_REPAIR_WORKFLOW && options.contextBuilderRunner != null) {
1409
1427
  contextPolicy = validateContextBuilderAnchorSufficiency(resolvedVariables, options.contextBuilderRunner, options.contextDefault ?? getWorkflowsContextDefault(), options.defaultCurator ?? getWorkflowsContextDefaultCurator());
1410
1428
  }
1411
1429
  validateContextSeedSourceAtAdmission(resolvedVariables, contextPolicy);
1412
1430
  // Pre-mutex, pre-state, pre-preflight: an out-of-roots caller path costs
1413
1431
  // zero delegate round-trips and leaves no run directory behind.
1414
1432
  assertCallerDynamicPathsAllowed(loaded.normalized, resolvedVariables, workflow, runId);
1415
- initialContextPolicy = contextPolicy ?? resolveWorkflowContextMode(undefined, options.contextDefault ?? "off", false, undefined, options.defaultCurator);
1416
- if (options.contextBuilderRunner != null) {
1433
+ initialContextPolicy = contextPolicy ?? resolveWorkflowContextMode(undefined, workflow === VERIFIED_REPAIR_WORKFLOW ? "off" : options.contextDefault ?? "off", false, undefined, options.defaultCurator);
1434
+ if (workflow !== VERIFIED_REPAIR_WORKFLOW && options.contextBuilderRunner != null) {
1417
1435
  try {
1418
1436
  options.contextBuilderRunner.assertTaskSecretsAllowed(resolvedVariables);
1419
1437
  }
@@ -1475,6 +1493,32 @@ async function executeRunWorkflow(server, options, args, signal, progressToken)
1475
1493
  }
1476
1494
  const isAsync = args["async"] === true;
1477
1495
  const ownership = acquireWorkflowRun(runId, options, isAsync ? undefined : signal);
1496
+ let verifiedRepair;
1497
+ if (workflow === VERIFIED_REPAIR_WORKFLOW) {
1498
+ try {
1499
+ ownership.throwIfCancelled();
1500
+ const runDir = getRunStateDir(runId);
1501
+ if (existsSync(runDir))
1502
+ throw new McpError(ErrorCode.InvalidParams, `run_id ${runId} already has persisted state at ${runDir}`);
1503
+ const prepared = await options.verifiedRepairHost.prepare({
1504
+ runId, runDir, contractPath: resolvedVariables["repair_contract_path"],
1505
+ routes: repairRoutesFromVariables(resolvedVariables), signal: ownership.signal,
1506
+ });
1507
+ verifiedRepair = new VerifiedRepairRuntime(prepared, runId, runDir);
1508
+ ownership.throwIfCancelled();
1509
+ }
1510
+ catch (error) {
1511
+ try {
1512
+ await verifiedRepair?.cleanupUnadmitted(error);
1513
+ }
1514
+ finally {
1515
+ await ownership.finish(undefined);
1516
+ }
1517
+ if (ownership.signal.aborted)
1518
+ throw new WorkflowCancellationError();
1519
+ throw new McpError(ErrorCode.InvalidParams, error instanceof Error ? error.message : String(error));
1520
+ }
1521
+ }
1478
1522
  if (isAsync) {
1479
1523
  // Everything between acquireMutex and the detached spawn must release the
1480
1524
  // mutex on ANY throw, or the run slot leaks permanently (bricks the server
@@ -1562,14 +1606,24 @@ async function executeRunWorkflow(server, options, args, signal, progressToken)
1562
1606
  throw err;
1563
1607
  }
1564
1608
  finally {
1565
- await ownership.finish(store);
1609
+ try {
1610
+ if (verifiedRepair !== undefined) {
1611
+ if (store === undefined)
1612
+ await verifiedRepair.cleanupUnadmitted(err);
1613
+ else
1614
+ await verifiedRepair.finalize(ownership.signal.aborted ? "cancelled" : "failed", err);
1615
+ }
1616
+ }
1617
+ finally {
1618
+ await ownership.finish(store);
1619
+ }
1566
1620
  }
1567
1621
  }
1568
1622
  if (store === undefined || effectiveDefinition === undefined) {
1569
1623
  await ownership.finish(store);
1570
1624
  throw new McpError(ErrorCode.InternalError, `Failed to initialize async run ${runId}`);
1571
1625
  }
1572
- void runWorkflowDetached(server, options, workflow, runId, resolvedVariables, debug, receipt, validatorRegistry, loaded, parsedMembers, parsedChairman, parsedChairmanModel, parsedChairmanEffort, true, ownership, undefined, store, effectiveDefinition, undefined, initializedPlanReview, initialContextPolicy, admittedRosterName).catch((err) => {
1626
+ void runWorkflowDetached(server, options, workflow, runId, resolvedVariables, debug, receipt, validatorRegistry, loaded, parsedMembers, parsedChairman, parsedChairmanModel, parsedChairmanEffort, true, ownership, undefined, store, effectiveDefinition, undefined, initializedPlanReview, initialContextPolicy, admittedRosterName, verifiedRepair).catch((err) => {
1573
1627
  if (err instanceof WorkflowCancellationError) {
1574
1628
  logger.info({ runId }, "workflow run cancelled");
1575
1629
  return;
@@ -1597,7 +1651,7 @@ async function executeRunWorkflow(server, options, args, signal, progressToken)
1597
1651
  }],
1598
1652
  };
1599
1653
  }
1600
- return await runWorkflowDetached(server, options, workflow, runId, resolvedVariables, debug, receipt, validatorRegistry, loaded, parsedMembers, parsedChairman, parsedChairmanModel, parsedChairmanEffort, false, ownership, progressToken, undefined, undefined, planReviewPlan, undefined, initialContextPolicy, admittedRosterName);
1654
+ return await runWorkflowDetached(server, options, workflow, runId, resolvedVariables, debug, receipt, validatorRegistry, loaded, parsedMembers, parsedChairman, parsedChairmanModel, parsedChairmanEffort, false, ownership, progressToken, undefined, undefined, planReviewPlan, undefined, initialContextPolicy, admittedRosterName, verifiedRepair);
1601
1655
  }
1602
1656
  async function preparePlanReviewSnapshot(plan) {
1603
1657
  try {
@@ -1789,7 +1843,7 @@ preparedSnapshot) {
1789
1843
  ? expandCouncilComposition(definition, parsedMembers, workflow, parsedChairman, parsedChairmanModel, parsedChairmanEffort)
1790
1844
  : definition;
1791
1845
  }
1792
- async function runWorkflowDetached(server, options, workflow, runId, resolvedVariables, debug, receipt, validatorRegistry, loaded, parsedMembers, parsedChairman, parsedChairmanModel, parsedChairmanEffort, isAsync, ownership, progressToken, preCreatedStore, preExpandedDefinition, planReviewPlan, preInitializedPlanReview, initialContextPolicy, rosterName) {
1846
+ async function runWorkflowDetached(server, options, workflow, runId, resolvedVariables, debug, receipt, validatorRegistry, loaded, parsedMembers, parsedChairman, parsedChairmanModel, parsedChairmanEffort, isAsync, ownership, progressToken, preCreatedStore, preExpandedDefinition, planReviewPlan, preInitializedPlanReview, initialContextPolicy, rosterName, verifiedRepair) {
1793
1847
  let store = preCreatedStore ?? null;
1794
1848
  let backend = null;
1795
1849
  let reporter;
@@ -1849,6 +1903,24 @@ async function runWorkflowDetached(server, options, workflow, runId, resolvedVar
1849
1903
  const rpt = reporter; // local const for closure narrowing
1850
1904
  const hooks = {
1851
1905
  ...storeRef.hooks,
1906
+ ...(verifiedRepair === undefined ? {} : {
1907
+ onRunStateChange: async (event) => {
1908
+ if (event.state === "succeeded" || event.state === "failed" || event.state === "cancelled") {
1909
+ try {
1910
+ await backend?.terminate();
1911
+ await verifiedRepair.finalize(event.state === "succeeded" ? "completed" : event.state, event.error, signal);
1912
+ if (event.state === "succeeded")
1913
+ ownership.throwIfCancelled();
1914
+ }
1915
+ catch (error) {
1916
+ if (event.state === "succeeded")
1917
+ throw error;
1918
+ logger.error({ err: error, runId }, "repair terminal publication failed; preserving original execution failure");
1919
+ }
1920
+ }
1921
+ await storeRef.hooks.onRunStateChange?.(event);
1922
+ },
1923
+ }),
1852
1924
  ...(rpt != null
1853
1925
  ? {
1854
1926
  onProgress: async (event) => {
@@ -1872,11 +1944,12 @@ async function runWorkflowDetached(server, options, workflow, runId, resolvedVar
1872
1944
  runDir: storeRef.runDir,
1873
1945
  signal,
1874
1946
  hooks,
1875
- contextBuilderRunner: options.contextBuilderRunner,
1947
+ contextBuilderRunner: verifiedRepair === undefined ? options.contextBuilderRunner : undefined,
1876
1948
  contextDefault: options.contextDefault,
1877
1949
  defaultCurator: options.defaultCurator,
1878
1950
  commitPreflightContext: storeRef.commitPreflightContext?.bind(storeRef),
1879
1951
  initialContextPolicy,
1952
+ verifiedRepair,
1880
1953
  ...(options.deriveInvocationAudit === undefined
1881
1954
  ? {}
1882
1955
  : { deriveInvocationAudit: options.deriveInvocationAudit }),
@@ -1893,6 +1966,7 @@ async function runWorkflowDetached(server, options, workflow, runId, resolvedVar
1893
1966
  : {}),
1894
1967
  });
1895
1968
  const result = await engine.execute();
1969
+ const terminalRepair = await verifiedRepair?.finalize("completed", undefined, signal);
1896
1970
  // Build summary (fail-open)
1897
1971
  let summary;
1898
1972
  if (receipt) {
@@ -1905,7 +1979,7 @@ async function runWorkflowDetached(server, options, workflow, runId, resolvedVar
1905
1979
  }
1906
1980
  }
1907
1981
  const content = finalizeWorkflowPresentation({
1908
- outputText: result.outputText,
1982
+ outputText: terminalRepair ?? result.outputText,
1909
1983
  receipt,
1910
1984
  debug,
1911
1985
  summary,
@@ -1916,6 +1990,18 @@ async function runWorkflowDetached(server, options, workflow, runId, resolvedVar
1916
1990
  return { content };
1917
1991
  }
1918
1992
  catch (error) {
1993
+ if (verifiedRepair !== undefined) {
1994
+ try {
1995
+ await backend?.terminate();
1996
+ if (store === null)
1997
+ await verifiedRepair.cleanupUnadmitted(error);
1998
+ else
1999
+ await verifiedRepair.finalize(signal.aborted || error instanceof WorkflowCancellationError ? "cancelled" : "failed", error);
2000
+ }
2001
+ catch (publicationError) {
2002
+ logger.error({ err: publicationError, runId }, "repair error publication failed; preserving original execution failure");
2003
+ }
2004
+ }
1919
2005
  if (signal.aborted || error instanceof WorkflowCancellationError) {
1920
2006
  await markWorkflowCancelled(store);
1921
2007
  throw new WorkflowCancellationError();
@@ -1992,6 +2078,9 @@ async function executeResumeWorkflow(server, options, args, signal, progressToke
1992
2078
  persistedBeforeMutex = null;
1993
2079
  }
1994
2080
  const persistedState = persistedBeforeMutex?.state;
2081
+ if (persistedState?.workflowName === VERIFIED_REPAIR_WORKFLOW) {
2082
+ throw new McpError(ErrorCode.InvalidParams, "verified-repair mutation cannot be resumed; inspect the retained result and submit a fresh explicit contract");
2083
+ }
1995
2084
  if (persistedState != null &&
1996
2085
  isPlanReviewRunState(persistedState) &&
1997
2086
  (persistedState.status === "failed" ||
@@ -2022,6 +2111,9 @@ async function executeResumeWorkflow(server, options, args, signal, progressToke
2022
2111
  debugKeepArtifacts: debug,
2023
2112
  };
2024
2113
  store = await WorkflowStateStore.resume(resumeOptions);
2114
+ if (store.runState.workflowName === VERIFIED_REPAIR_WORKFLOW) {
2115
+ throw new McpError(ErrorCode.InvalidParams, "verified-repair mutation cannot be resumed; inspect the retained result and submit a fresh explicit contract");
2116
+ }
2025
2117
  // Open this attempt before classifying an abort during reconstruction;
2026
2118
  // otherwise a prior terminal record would suppress markCancelled.
2027
2119
  await store.beginResumeAttempt();
@@ -2336,7 +2428,7 @@ function parseLifecycleForStatus(value) {
2336
2428
  return undefined;
2337
2429
  }
2338
2430
  }
2339
- async function executeWorkflowRunStatus(_options, args) {
2431
+ async function executeWorkflowRunStatus(options, args) {
2340
2432
  const runId = args["run_id"];
2341
2433
  const includeResult = args["include_result"] === true;
2342
2434
  if (typeof runId !== "string" || runId === "") {
@@ -2396,6 +2488,7 @@ async function executeWorkflowRunStatus(_options, args) {
2396
2488
  };
2397
2489
  // artifacts_dir is cheap (pure join, no I/O) and present for every found run.
2398
2490
  projection["artifacts_dir"] = join(runDir, "artifacts");
2491
+ projection["verification"] = await readWorkflowVerification(getRunsDir(), runId);
2399
2492
  // Read-only context-selection observability from already-persisted state.
2400
2493
  // No file I/O — only projects state.workflow_context.context_builder and
2401
2494
  // the state.context_builder_lifecycle snapshot.
@@ -2578,6 +2671,47 @@ async function executeWorkflowRunStatus(_options, args) {
2578
2671
  }
2579
2672
  }
2580
2673
  }
2674
+ if (state.workflowName === ARCHITECTURE_WORKFLOW) {
2675
+ const comparison = await inspectArchitectureComparisonRecord(runDir, runId, includeResult);
2676
+ const { result, ...status } = comparison;
2677
+ projection["comparison"] = status;
2678
+ projection["result_available"] = status["status"] === "complete" || status["status"] === "incomplete";
2679
+ if (result !== undefined)
2680
+ projection["result"] = result;
2681
+ else
2682
+ delete projection["result"];
2683
+ }
2684
+ if (state.workflowName === VERIFIED_REPAIR_WORKFLOW) {
2685
+ let inspected = await inspectVerifiedRepairRecord(runDir, runId, includeResult);
2686
+ if (inspected.availability === "unrecorded" && lock === "stale_or_absent" && !activeRuns.has(runId)) {
2687
+ try {
2688
+ const value = await options.verifiedRepairHost?.readInterruptedRun?.({ runId, runDir });
2689
+ if (value === undefined)
2690
+ throw new Error("interrupted capture unavailable");
2691
+ const record = RepairRecordSchema.parse(value);
2692
+ if (record.run_id !== runId || record.execution_status !== "interrupted")
2693
+ throw new Error("interrupted repair record identity mismatch");
2694
+ assertRepairBounded(record, MAX_REPAIR_RECORD_BYTES);
2695
+ const serialized = JSON.stringify(record);
2696
+ inspected = { availability: "available", result_available: true,
2697
+ result_bytes: Buffer.byteLength(serialized), owner_acceptance: "not_recorded",
2698
+ execution_status: "interrupted", repair_status: record.repair_status,
2699
+ ...(includeResult ? { result: serialized, record } : {}) };
2700
+ }
2701
+ catch {
2702
+ inspected = { availability: "unavailable", result_available: false, result_bytes: 0,
2703
+ owner_acceptance: "not_recorded", reason: "interrupted_capture_unavailable" };
2704
+ }
2705
+ }
2706
+ const { result, record: _record, result_available, result_bytes, ...repair } = inspected;
2707
+ projection["repair"] = { ...repair, scope: repair.execution_status === "interrupted" ? "inspected_at" : "recorded_at" };
2708
+ projection["result_available"] = result_available;
2709
+ projection["result_bytes"] = result_bytes;
2710
+ if (result !== undefined)
2711
+ projection["result"] = result;
2712
+ else
2713
+ delete projection["result"];
2714
+ }
2581
2715
  return {
2582
2716
  content: [{ type: "text", text: JSON.stringify(projection) }],
2583
2717
  };
@@ -2680,7 +2814,7 @@ function executeListWorkflows(options) {
2680
2814
  supports_members: runtimeMembers,
2681
2815
  supports_chairman: runtimeMembers,
2682
2816
  supports_context_preflight: contextStrategy.supports_context_preflight,
2683
- effective_context_default: effectiveContextDefault,
2817
+ effective_context_default: name === VERIFIED_REPAIR_WORKFLOW ? "disabled" : effectiveContextDefault,
2684
2818
  fails_on_empty_selection: contextStrategy.fails_on_empty_selection,
2685
2819
  context_anchor_variables: contextStrategy.context_anchor_variables,
2686
2820
  context_override_variables: contextStrategy.context_override_variables,
@@ -3131,7 +3265,7 @@ export function getWorkflowToolDefinitions(workflowsPath, availableCliNames) {
3131
3265
  },
3132
3266
  {
3133
3267
  name: "workflow_run_status",
3134
- description: "Read-only status/progress of a workflow run. The full result is included only with include_result:true. Generic workflows preserve succeeded-final-call behavior; plan-review-receipts reports marker-driven availability and bytes independently of terminal status, with body-blind default polling. Every found run also carries a top-level `health` block {classification: \"ok\"|\"degraded\", reasons: string[]} computed read-time from persisted data — a run can be status:\"succeeded\" yet degraded when on_failure:continue swallowed failed calls or context preflight was partial/degraded (reasons: failed_calls_in_succeeded_run, context_partial, context_lifecycle_failed, coverage_degraded, delegate_fallback_used, context_external_gaps — the finalizer reported evidence gaps outside the delegate packet under external_gap_policy:\"degrade\", so conclusions depending on them are conditional). When a context-builder lifecycle snapshot is persisted, the `context` block additionally includes `lifecycle_status` and `coverage` {policy, status, required, selected, missing}. A parsed snapshot also projects `context.delegate.finalizer` {effective_enabled, execution_status, score?}; `score` is present only for a succeeded finalizer that recorded one, and the finalizer key is omitted when the lifecycle is missing, unparseable, or those fields are absent. While context preflight is still running (non-terminal lifecycle, no committed context yet) the `context` block is absent and a top-level `context_progress` {phase, status, updated_at, counts} reports scan progress instead. Found council runs also include a top-level `resolved_roster` of requested seat and delegate values (no provenance) when the run persisted one; older runs omit the key.",
3268
+ description: "Read-only status/progress of a workflow run. The full result is included only with include_result:true. Generic workflows preserve succeeded-final-call behavior; plan-review-receipts reports marker-driven availability and bytes independently of terminal status, with body-blind default polling. Every found run also carries a top-level `health` block {classification: \"ok\"|\"degraded\", reasons: string[]} computed read-time from persisted data — a run can be status:\"succeeded\" yet degraded when on_failure:continue swallowed failed calls or context preflight was partial/degraded (reasons: failed_calls_in_succeeded_run, context_partial, context_lifecycle_failed, coverage_degraded, delegate_fallback_used, context_external_gaps — the finalizer reported evidence gaps outside the delegate packet under external_gap_policy:\"degrade\", so conclusions depending on them are conditional). When a context-builder lifecycle snapshot is persisted, the `context` block additionally includes `lifecycle_status` and `coverage` {policy, status, required, selected, missing}. A parsed snapshot also projects `context.delegate.finalizer` {effective_enabled, execution_status, score?}; `score` is present only for a succeeded finalizer that recorded one, and the finalizer key is omitted when the lifecycle is missing, unparseable, or those fields are absent. While context preflight is still running (non-terminal lifecycle, no committed context yet) the `context` block is absent and a top-level `context_progress` {phase, status, updated_at, counts} reports scan progress instead. Found council runs also include a top-level `resolved_roster` of requested seat and delegate values (no provenance) when the run persisted one; older runs omit the key. Architecture comparisons additionally project comparison completeness and retained record availability independently of run execution status. Every found run has a separately versioned verification projection of historical inspected-at evidence; it establishes neither current source/runtime applicability nor owner acceptance.",
3135
3269
  inputSchema: WORKFLOW_RUN_STATUS_SCHEMA,
3136
3270
  annotations: { readOnlyHint: true },
3137
3271
  },