@interf/compiler 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/LICENSE.md +1 -0
  2. package/README.md +10 -7
  3. package/TRADEMARKS.md +4 -4
  4. package/builtin-methods/interf-default/README.md +6 -7
  5. package/builtin-methods/interf-default/method.json +7 -68
  6. package/builtin-methods/interf-default/method.schema.json +52 -50
  7. package/dist/cli/commands/prep.js +58 -2
  8. package/dist/cli/commands/verify.d.ts +2 -0
  9. package/dist/cli/commands/verify.js +17 -8
  10. package/dist/cli/commands/wizard.js +122 -14
  11. package/dist/compiler-ui/404.html +1 -1
  12. package/dist/compiler-ui/__next.__PAGE__.txt +2 -2
  13. package/dist/compiler-ui/__next._full.txt +3 -3
  14. package/dist/compiler-ui/__next._head.txt +1 -1
  15. package/dist/compiler-ui/__next._index.txt +2 -2
  16. package/dist/compiler-ui/__next._tree.txt +2 -2
  17. package/dist/compiler-ui/_next/static/chunks/{13awzu4tooflw.css → 0_c_tvh-cukjz.css} +1 -1
  18. package/dist/compiler-ui/_next/static/chunks/{0jipmpez3_ehh.js → 0f_geuwdesg_c.js} +42 -17
  19. package/dist/compiler-ui/_not-found/__next._full.txt +2 -2
  20. package/dist/compiler-ui/_not-found/__next._head.txt +1 -1
  21. package/dist/compiler-ui/_not-found/__next._index.txt +2 -2
  22. package/dist/compiler-ui/_not-found/__next._not-found.__PAGE__.txt +1 -1
  23. package/dist/compiler-ui/_not-found/__next._not-found.txt +1 -1
  24. package/dist/compiler-ui/_not-found/__next._tree.txt +2 -2
  25. package/dist/compiler-ui/_not-found.html +1 -1
  26. package/dist/compiler-ui/_not-found.txt +2 -2
  27. package/dist/compiler-ui/index.html +1 -1
  28. package/dist/compiler-ui/index.txt +3 -3
  29. package/dist/packages/contracts/index.d.ts +2 -2
  30. package/dist/packages/contracts/index.js +1 -1
  31. package/dist/packages/contracts/lib/schema.d.ts +271 -72
  32. package/dist/packages/contracts/lib/schema.js +243 -83
  33. package/dist/packages/engine/action-definitions.js +1 -1
  34. package/dist/packages/engine/agents/lib/shells.d.ts +12 -4
  35. package/dist/packages/engine/agents/lib/shells.js +127 -120
  36. package/dist/packages/engine/cloud-seams.d.ts +115 -0
  37. package/dist/packages/engine/cloud-seams.js +84 -0
  38. package/dist/packages/engine/compile/artifact-counts.d.ts +1 -1
  39. package/dist/packages/engine/compile/artifact-counts.js +3 -3
  40. package/dist/packages/engine/compile/artifact-status.d.ts +41 -0
  41. package/dist/packages/engine/compile/artifact-status.js +166 -0
  42. package/dist/packages/engine/compile/billing-events.d.ts +89 -0
  43. package/dist/packages/engine/compile/billing-events.js +74 -0
  44. package/dist/packages/engine/compile/check-evaluator.d.ts +66 -0
  45. package/dist/packages/engine/compile/check-evaluator.js +298 -0
  46. package/dist/packages/engine/compile/compiled-schema.d.ts +7 -17
  47. package/dist/packages/engine/compile/compiled-schema.js +55 -70
  48. package/dist/packages/engine/compile/compiled-stage-plan.d.ts +1 -0
  49. package/dist/packages/engine/compile/compiled-stage-plan.js +32 -15
  50. package/dist/packages/engine/compile/compiled-stage-runner.js +1 -1
  51. package/dist/packages/engine/compile/index.d.ts +0 -1
  52. package/dist/packages/engine/compile/index.js +0 -1
  53. package/dist/packages/engine/compile/lib/schema.d.ts +111 -92
  54. package/dist/packages/engine/compile/lib/schema.js +35 -39
  55. package/dist/packages/engine/compile/method-primitives.d.ts +2 -2
  56. package/dist/packages/engine/compile/method-primitives.js +1 -1
  57. package/dist/packages/engine/compile/reset.js +4 -4
  58. package/dist/packages/engine/compile/runtime-contracts.js +2 -1
  59. package/dist/packages/engine/compile/runtime-prompt.js +3 -2
  60. package/dist/packages/engine/compile/runtime-reconcile.js +35 -35
  61. package/dist/packages/engine/compile/runtime-runs.js +0 -1
  62. package/dist/packages/engine/compile/runtime-types.d.ts +7 -8
  63. package/dist/packages/engine/compile/runtime.d.ts +1 -2
  64. package/dist/packages/engine/compile/runtime.js +0 -1
  65. package/dist/packages/engine/compile/state-health.js +6 -6
  66. package/dist/packages/engine/compile/state-view.js +7 -6
  67. package/dist/packages/engine/compile/validate-compiled.js +61 -30
  68. package/dist/packages/engine/compile/validate.js +26 -24
  69. package/dist/packages/engine/execution/lib/schema.d.ts +79 -33
  70. package/dist/packages/engine/execution/lib/schema.js +13 -5
  71. package/dist/packages/engine/index.d.ts +2 -2
  72. package/dist/packages/engine/index.js +1 -1
  73. package/dist/packages/engine/lib/schema.d.ts +551 -242
  74. package/dist/packages/engine/lib/schema.js +53 -17
  75. package/dist/packages/engine/native-run-handlers.js +15 -7
  76. package/dist/packages/engine/preparation-store.d.ts +6 -0
  77. package/dist/packages/engine/preparation-store.js +8 -0
  78. package/dist/packages/engine/routes.d.ts +6 -0
  79. package/dist/packages/engine/routes.js +6 -0
  80. package/dist/packages/engine/run-observability.js +1 -2
  81. package/dist/packages/engine/runtime-event-applier.js +7 -0
  82. package/dist/packages/engine/runtime-proposal-helpers.js +1 -1
  83. package/dist/packages/engine/runtime-resource-builders.d.ts +6 -6
  84. package/dist/packages/engine/runtime-resource-builders.js +5 -4
  85. package/dist/packages/engine/runtime.d.ts +67 -7
  86. package/dist/packages/engine/runtime.js +159 -29
  87. package/dist/packages/engine/server.d.ts +25 -0
  88. package/dist/packages/engine/server.js +62 -3
  89. package/dist/packages/engine/verify/index.d.ts +10 -10
  90. package/dist/packages/engine/verify/index.js +8 -8
  91. package/dist/packages/engine/verify/readiness-check-run.d.ts +27 -4
  92. package/dist/packages/engine/verify/readiness-check-run.js +92 -24
  93. package/dist/packages/engine/verify/{test-execution.d.ts → verify-execution.d.ts} +2 -2
  94. package/dist/packages/engine/verify/{test-execution.js → verify-execution.js} +2 -2
  95. package/dist/packages/engine/verify/{test-paths.d.ts → verify-paths.d.ts} +1 -1
  96. package/dist/packages/engine/verify/{test-sandbox.d.ts → verify-sandbox.d.ts} +1 -1
  97. package/dist/packages/engine/verify/{test-specs.d.ts → verify-specs.d.ts} +1 -1
  98. package/dist/packages/engine/verify/{test-specs.js → verify-specs.js} +1 -1
  99. package/dist/packages/engine/verify/{test-targets.d.ts → verify-targets.d.ts} +1 -1
  100. package/dist/packages/engine/verify/{test.d.ts → verify.d.ts} +4 -4
  101. package/dist/packages/engine/verify/{test.js → verify.js} +3 -3
  102. package/dist/packages/engine/wire-schemas.d.ts +545 -0
  103. package/dist/packages/engine/wire-schemas.js +59 -0
  104. package/dist/packages/methods/authoring/method-authoring.d.ts +2 -0
  105. package/dist/packages/methods/authoring/method-authoring.js +99 -18
  106. package/dist/packages/methods/authoring/method-edit-session.js +5 -5
  107. package/dist/packages/methods/authoring/method-improvement.js +1 -1
  108. package/dist/packages/methods/package/builtin-compiled-method.d.ts +12 -12
  109. package/dist/packages/methods/package/builtin-compiled-method.js +25 -22
  110. package/dist/packages/methods/package/context-interface.d.ts +39 -26
  111. package/dist/packages/methods/package/context-interface.js +48 -39
  112. package/dist/packages/methods/package/interf-method-package.js +28 -47
  113. package/dist/packages/methods/package/local-methods.d.ts +3 -4
  114. package/dist/packages/methods/package/local-methods.js +34 -62
  115. package/dist/packages/methods/package/method-definitions.d.ts +4 -6
  116. package/dist/packages/methods/package/method-definitions.js +0 -4
  117. package/dist/packages/methods/package/method-helpers.d.ts +0 -2
  118. package/dist/packages/methods/package/method-helpers.js +0 -4
  119. package/dist/packages/project/interf-scaffold.js +12 -12
  120. package/dist/packages/project/source-config.js +2 -1
  121. package/package.json +6 -16
  122. package/dist/packages/engine/compile/runtime-acceptance.d.ts +0 -9
  123. package/dist/packages/engine/compile/runtime-acceptance.js +0 -265
  124. /package/dist/compiler-ui/_next/static/{a3UiUF0DiMEbfWy_0gihg → 6qyE1u9m_oBUkvAhhoCmO}/_buildManifest.js +0 -0
  125. /package/dist/compiler-ui/_next/static/{a3UiUF0DiMEbfWy_0gihg → 6qyE1u9m_oBUkvAhhoCmO}/_clientMiddlewareManifest.js +0 -0
  126. /package/dist/compiler-ui/_next/static/{a3UiUF0DiMEbfWy_0gihg → 6qyE1u9m_oBUkvAhhoCmO}/_ssgManifest.js +0 -0
  127. /package/dist/packages/engine/verify/{test-paths.js → verify-paths.js} +0 -0
  128. /package/dist/packages/engine/verify/{test-profile-presets.d.ts → verify-profile-presets.d.ts} +0 -0
  129. /package/dist/packages/engine/verify/{test-profile-presets.js → verify-profile-presets.js} +0 -0
  130. /package/dist/packages/engine/verify/{test-sandbox.js → verify-sandbox.js} +0 -0
  131. /package/dist/packages/engine/verify/{test-targets.js → verify-targets.js} +0 -0
  132. /package/dist/packages/engine/verify/{test-types.d.ts → verify-types.d.ts} +0 -0
  133. /package/dist/packages/engine/verify/{test-types.js → verify-types.js} +0 -0
@@ -8,7 +8,7 @@ import { MethodListingCache, MtimeListingCache, ReadinessCache, RunListingCache,
8
8
  import { applyEventToCompileRun, applyEventToLocalJob, } from "./runtime-event-applier.js";
9
9
  import { buildMethodResource, buildPreparationResource, createRunId, logsForRuntimeRun, logsForStageRun, proofForStage, readinessStateToPreparationReadiness, readinessSummaryForStatus, readinessTargetResult, stageArtifactRefs, } from "./runtime-resource-builders.js";
10
10
  import { ACTION_PLANNER_CLARIFICATION_MESSAGE, actionAssistantMessage, actionCommandPreview, actionTypeFromValues, actionValueMethodTaskPrompt, configuredAgentName, createActionProposalId, detachMethodFromPreparation, detectedExecutorOptions, directServiceEndpointForAction, hasCompiledTestTarget, methodAuthoringHintFromPrompt, methodAuthoringPromptFallback, methodIdForProposal, methodLabelFromId, numberValue, requireSelectedMethod, sanitizeActionProposalPlan, stringValue, testModeFromValues, } from "./runtime-proposal-helpers.js";
11
- import { ReadinessStateSchema, } from "../contracts/lib/schema.js";
11
+ import { ReadinessSchema, } from "../contracts/lib/schema.js";
12
12
  import { discoverSourceFiles, } from "./compile/discovery.js";
13
13
  import { resetCompiledGeneratedState, } from "./compile/reset.js";
14
14
  import { ensurePortableContextScaffold, readInterfConfig, } from "../project/interf.js";
@@ -16,7 +16,8 @@ import { findSourcePreparationConfig, fingerprintReadinessChecks, listSourcePrep
16
16
  import { listSourceFolderChoices, } from "../project/source-folders.js";
17
17
  import { asPreparationDataDir, preparationPortableContextPath, userMethodsRoot, preparationConfigPath, preparationMethodPackagePath, preparationMethodsRoot, } from "../contracts/lib/preparation-paths.js";
18
18
  import { getCompiledMethod, listCompiledMethodChoices, } from "../methods/package/method-definitions.js";
19
- import { contextInterfaceArtifactPath, } from "../methods/package/context-interface.js";
19
+ import { computeArtifactStatuses, } from "./compile/artifact-status.js";
20
+ import { JsonlBillingEventSink, buildCompilationEventsForRun, defaultBillingEventLogPath, } from "./compile/billing-events.js";
20
21
  import { methodDefinitionPath, resolveMethodPackageSourcePath, } from "../methods/package/local-methods.js";
21
22
  import { seedLocalMethodPackageFromBase, } from "../methods/package/interf-method-package.js";
22
23
  import { PACKAGE_ROOT } from "../methods/package/lib/package-root.js";
@@ -24,7 +25,7 @@ import { resolveAgent, detectAgents, supportsAutomatedRuns, } from "./agents/lib
24
25
  import { loadUserConfig, saveUserConfig, } from "./agents/lib/user-config.js";
25
26
  import { loadAgentsRegistry, registerCustomAgent, unregisterCustomAgent, patchRoleMap, setActiveAgent, } from "./agents/registry.js";
26
27
  import { readSavedReadinessCheckRun, } from "./verify/readiness-check-run.js";
27
- import { createCompiledTestTarget, } from "./verify/test-targets.js";
28
+ import { createCompiledTestTarget, } from "./verify/verify-targets.js";
28
29
  import { ActionProposalApprovalRequestSchema, ActionProposalCreateRequestSchema, ActionProposalPlanSchema, ActionProposalResourceSchema, ActionProposalTypeSchema, CompileRunCreateRequestSchema, CompileRunResourceSchema, LocalExecutorStatusSchema, LocalExecutorSelectRequestSchema, LocalServiceHealthSchema, LocalRunHandlerResultSchema, LocalJobEventAppendRequestSchema, LocalJobRunCreateRequestSchema, LocalJobRunResourceSchema, SourceFileResourceSchema, WorkspaceFileResourceSchema, PortableContextResourceSchema, PreparationSetupCreateRequestSchema, PreparationSetupResultSchema, MethodChangeCreateRequestSchema, MethodChangeResultSchema, PreparationChangeCreateRequestSchema, PreparationChangeResultSchema, ReadinessCheckDraftCreateRequestSchema, ReadinessCheckDraftResultSchema, ResetRequestSchema, ResetResultSchema, ServiceRegistryWorkspaceSchema, VerifyRunCreateRequestSchema, VerifyRunResourceSchema, MethodAuthoringCreateRequestSchema, MethodAuthoringResultSchema, } from "./lib/schema.js";
29
30
  import { buildLocalServiceUrl, } from "./routes.js";
30
31
  import { MethodAuthoringActionValuesSchema, PreparationSetupActionValuesSchema, } from "./action-values.js";
@@ -33,6 +34,10 @@ import { compileRunToObservability, jobRunToObservability, verifyRunToObservabil
33
34
  const IDEMPOTENCY_TTL_MS = 60 * 60 * 1000;
34
35
  /** Idempotency cache size at which to schedule an opportunistic prune. */
35
36
  const IDEMPOTENCY_PRUNE_THRESHOLD = 64;
37
+ const INTERRUPTED_COMPILE_RUN_MESSAGE = "Compile run interrupted because the Interf engine stopped before the run reached a terminal state.";
38
+ function isTerminalCompileRunStatus(status) {
39
+ return status === "succeeded" || status === "failed" || status === "cancelled";
40
+ }
36
41
  export class LocalServiceRuntime {
37
42
  host;
38
43
  port;
@@ -62,6 +67,11 @@ export class LocalServiceRuntime {
62
67
  * when a compile run is launched and cleared once the run reaches a
63
68
  * terminal state. Each entry remembers where the persisted record lives
64
69
  * so cancel can mark it without re-resolving the Preparation.
70
+ *
71
+ * TODO(cloud): when the cloud variant lands, wire `RunLeaseStore`
72
+ * (see `cloud-seams.ts` B4.2) through this map. Multi-replica engines
73
+ * need a shared lease store so a replica can take over a run whose
74
+ * owning replica died.
65
75
  */
66
76
  activeCompileRuns = new Map();
67
77
  /**
@@ -71,6 +81,11 @@ export class LocalServiceRuntime {
71
81
  * tenants on the same engine (CSO finding: a malicious preparation could
72
82
  * otherwise hijack another preparation's run id by reusing its key).
73
83
  * Entries expire after `IDEMPOTENCY_TTL_MS`.
84
+ *
85
+ * TODO(cloud): when the cloud variant lands, wire `IdempotencyStore`
86
+ * (see `cloud-seams.ts` B4.1) through this map. Multi-replica engines
87
+ * need a shared store so retries that land on a different replica
88
+ * still hit the same dedupe entry.
74
89
  */
75
90
  idempotencyKeyCache = new Map();
76
91
  /**
@@ -85,6 +100,22 @@ export class LocalServiceRuntime {
85
100
  readinessCache = new ReadinessCache();
86
101
  sourceFilesCache = new MtimeListingCache();
87
102
  methodListingCache = new MethodListingCache();
103
+ /**
104
+ * 0.17 — sink for per-Artifact billing events. Set once at construction.
105
+ * Lazy-defaults to a per-run JSONL writer when no override was injected.
106
+ */
107
+ billingEventSink;
108
+ /**
109
+ * 0.17 — cloud-variant injection points. The local engine accepts
110
+ * these on the options surface but does not consume them yet — the
111
+ * in-process Maps remain authoritative for idempotency and
112
+ * run-lease state. The cloud variant fork will swap to these stores;
113
+ * the option-fields are documented here so the cloud build has a
114
+ * stable target. See `cloud-seams.ts` for the contracts.
115
+ */
116
+ cloudIdempotencyStore;
117
+ cloudRunLeaseStore;
118
+ cloudTokenValidator = null;
88
119
  constructor(options) {
89
120
  this.host = options.host;
90
121
  this.port = options.port;
@@ -93,6 +124,9 @@ export class LocalServiceRuntime {
93
124
  this.handlers = options.handlers ?? {};
94
125
  this.authToken = options.authToken ?? null;
95
126
  this.rootPath = resolve(options.rootPath);
127
+ this.billingEventSink = options.billingEventSink ?? null;
128
+ this.cloudIdempotencyStore = options.idempotencyStore ?? null;
129
+ this.cloudRunLeaseStore = options.runLeaseStore ?? null;
96
130
  // Auto-register the initial preparation so single-preparation callers
97
131
  // (existing tests, the current `interf web` command) work without
98
132
  // additional bootstrapping. The constructor seed is the only role
@@ -103,6 +137,18 @@ export class LocalServiceRuntime {
103
137
  setBoundPort(port) {
104
138
  this.port = port;
105
139
  }
140
+ /**
141
+ * 0.17 — token validator setter for cloud variants. Stored on the
142
+ * runtime so `isAuthorizedMutation` in `server.ts` can opt into the
143
+ * async per-account check when present. Local default: never set —
144
+ * the static bearer-token check runs.
145
+ */
146
+ setTokenValidator(validator) {
147
+ this.cloudTokenValidator = validator;
148
+ }
149
+ getTokenValidator() {
150
+ return this.cloudTokenValidator;
151
+ }
106
152
  /** Set a hook that fires whenever the registered preparations change. */
107
153
  setOnRegistryChanged(handler) {
108
154
  this.onRegistryChanged = handler;
@@ -126,6 +172,7 @@ export class LocalServiceRuntime {
126
172
  lastActivity: now,
127
173
  };
128
174
  this.preparationContexts.set(resolved, context);
175
+ this.finalizeInterruptedCompileRuns(resolved);
129
176
  this.onRegistryChanged?.();
130
177
  return context;
131
178
  }
@@ -258,7 +305,11 @@ export class LocalServiceRuntime {
258
305
  const compileRuns = this.listCompileRunsForPreparation(prepDataDir, preparation.name);
259
306
  const verifyRuns = this.listVerifyRunsForPreparation(prepDataDir, preparation.name);
260
307
  const readiness = this.computePreparationReadiness(prepDataDir, preparation);
261
- return buildPreparationResource(prepDataDir, preparation, readiness, compileRuns[0]?.run_id ?? null, verifyRuns[0]?.run_id ?? null);
308
+ return buildPreparationResource(prepDataDir, preparation, readiness, compileRuns[0]?.run_id ?? null, verifyRuns[0]?.run_id ?? null,
309
+ // 0.17 — surface per-Artifact status from the latest compile
310
+ // run so the UI can render artifact rows on the Preparation
311
+ // page without a separate fetch.
312
+ compileRuns[0]?.artifacts ?? []);
262
313
  });
263
314
  }
264
315
  getPreparation(prepDataDir, preparationName) {
@@ -391,7 +442,7 @@ export class LocalServiceRuntime {
391
442
  return contextResult.total > 0 && contextResult.passed === contextResult.total ? "ready" : "not-ready";
392
443
  })();
393
444
  const ready = status === "ready";
394
- return ReadinessStateSchema.parse({
445
+ return ReadinessSchema.parse({
395
446
  kind: "interf-readiness-state",
396
447
  version: 1,
397
448
  generated_at: generatedAt,
@@ -502,10 +553,7 @@ export class LocalServiceRuntime {
502
553
  source_kind: method.scope === "builtin" ? "builtin" : "local",
503
554
  built_in: method.scope === "builtin",
504
555
  active_for_preparations: activeForPreparations,
505
- output_paths: (method.contextInterface?.zones ?? [])
506
- .filter((zone) => zone.role === "output")
507
- .map((zone) => contextInterfaceArtifactPath(zone))
508
- .sort(),
556
+ artifacts: method.contextInterface?.artifacts ?? [],
509
557
  stages: method.stages.map((stage) => ({
510
558
  id: stage.id,
511
559
  label: stage.label,
@@ -515,7 +563,6 @@ export class LocalServiceRuntime {
515
563
  role: stage.role && stage.role.trim().length > 0 ? stage.role : "general",
516
564
  reads: stage.reads,
517
565
  writes: stage.writes,
518
- ...(stage.acceptance ? { acceptance: stage.acceptance } : {}),
519
566
  })),
520
567
  });
521
568
  });
@@ -1030,6 +1077,7 @@ export class LocalServiceRuntime {
1030
1077
  method_id: request.method_id,
1031
1078
  label: request.label,
1032
1079
  task_prompt: request.task_prompt,
1080
+ artifact_requirements: request.artifact_requirements.length,
1033
1081
  },
1034
1082
  },
1035
1083
  {
@@ -1068,6 +1116,7 @@ export class LocalServiceRuntime {
1068
1116
  method_id: request.method_id,
1069
1117
  label: request.label,
1070
1118
  task_prompt: request.task_prompt,
1119
+ artifact_requirements: request.artifact_requirements.length,
1071
1120
  },
1072
1121
  });
1073
1122
  void this.runMethodAuthoringInBackground(prepDataDir, request, job.run_id);
@@ -1187,7 +1236,6 @@ export class LocalServiceRuntime {
1187
1236
  stage_total: stageTotal,
1188
1237
  reads: stage.reads,
1189
1238
  writes: stage.writes,
1190
- ...(stage.acceptance ? { acceptance: stage.acceptance } : {}),
1191
1239
  },
1192
1240
  artifacts: [],
1193
1241
  };
@@ -1226,7 +1274,7 @@ export class LocalServiceRuntime {
1226
1274
  }
1227
1275
  /**
1228
1276
  * Cancel an in-flight compile run. Marks the persisted record as
1229
- * `cancelled`, emits a `run.failed` event to capture the cancellation in
1277
+ * `cancelled`, emits a `run.cancelled` event to capture the cancellation in
1230
1278
  * the run timeline, and clears the active handle so retries may start a
1231
1279
  * fresh run. If the run already finished, returns
1232
1280
  * `{ cancelled: false, reason: "already finished" }` and persists nothing.
@@ -1246,23 +1294,14 @@ export class LocalServiceRuntime {
1246
1294
  handle.cancelled = true;
1247
1295
  handle.cancelledAt = cancelledAt;
1248
1296
  const current = this.readCompileRun(handle.compiledPath, runId);
1249
- if (current && current.status !== "succeeded" && current.status !== "failed" && current.status !== "cancelled") {
1250
- const cancelledRun = {
1251
- ...current,
1252
- status: "cancelled",
1253
- finished_at: current.finished_at ?? cancelledAt,
1254
- events: [
1255
- ...current.events,
1256
- {
1257
- type: "run.failed",
1258
- event_id: createRunEventId("event"),
1259
- run_id: runId,
1260
- timestamp: cancelledAt,
1261
- error: "Compile run cancelled by request.",
1262
- },
1263
- ],
1264
- };
1265
- this.writeCompileRun(handle.prepDataDir, handle.compiledPath, cancelledRun);
1297
+ if (current && !isTerminalCompileRunStatus(current.status)) {
1298
+ this.writeCompileRun(handle.prepDataDir, handle.compiledPath, applyEventToCompileRun(current, {
1299
+ type: "run.cancelled",
1300
+ event_id: createRunEventId("event"),
1301
+ run_id: runId,
1302
+ timestamp: cancelledAt,
1303
+ reason: "Compile run cancelled by request.",
1304
+ }));
1266
1305
  }
1267
1306
  return { cancelled: true };
1268
1307
  }
@@ -1433,6 +1472,9 @@ export class LocalServiceRuntime {
1433
1472
  });
1434
1473
  }
1435
1474
  await this.recordCompileRunEvent(prepDataDir, context.compiledPath, context.runId, this.readinessUpdatedEvent(context.runId, context.preparationConfig.name, this.computePreparationReadiness(prepDataDir, context.preparationConfig)));
1475
+ // 0.17 — emit per-Artifact billing events (stub form: JSONL).
1476
+ // Production sink (Metronome HTTP) wires in 0.18+.
1477
+ this.emitBillingEventsForRun(prepDataDir, context);
1436
1478
  }
1437
1479
  catch (error) {
1438
1480
  await this.recordCompileRunEvent(prepDataDir, context.compiledPath, context.runId, {
@@ -2066,6 +2108,81 @@ export class LocalServiceRuntime {
2066
2108
  readCompileRun(compiledPath, runId) {
2067
2109
  return readCompileRunAt(compileRunPath(compiledPath, runId));
2068
2110
  }
2111
+ finalizeInterruptedCompileRuns(prepDataDir) {
2112
+ let preparations;
2113
+ try {
2114
+ preparations = listSourcePreparationConfigs(loadSourceFolderConfig(prepDataDir));
2115
+ }
2116
+ catch {
2117
+ return;
2118
+ }
2119
+ for (const preparation of preparations) {
2120
+ const compiledPath = preparationPortableContextPath(asPreparationDataDir(prepDataDir), preparation.name);
2121
+ for (const run of listJsonFiles(compileRunsRoot(compiledPath))
2122
+ .map(readCompileRunAt)
2123
+ .filter((entry) => entry !== null)) {
2124
+ if (isTerminalCompileRunStatus(run.status) || this.activeCompileRuns.has(run.run_id))
2125
+ continue;
2126
+ const timestamp = createRunEventTimestamp();
2127
+ const interruptedRun = {
2128
+ ...run,
2129
+ stages: run.stages.map((stage) => {
2130
+ if (stage.status !== "running")
2131
+ return stage;
2132
+ return {
2133
+ ...stage,
2134
+ status: "failed",
2135
+ finished_at: stage.finished_at ?? timestamp,
2136
+ summary: stage.summary ?? INTERRUPTED_COMPILE_RUN_MESSAGE,
2137
+ failure: stage.failure ?? INTERRUPTED_COMPILE_RUN_MESSAGE,
2138
+ };
2139
+ }),
2140
+ };
2141
+ this.writeCompileRun(prepDataDir, compiledPath, applyEventToCompileRun(interruptedRun, {
2142
+ type: "run.cancelled",
2143
+ event_id: createRunEventId("event"),
2144
+ run_id: run.run_id,
2145
+ timestamp,
2146
+ reason: INTERRUPTED_COMPILE_RUN_MESSAGE,
2147
+ }));
2148
+ }
2149
+ }
2150
+ }
2151
+ /**
2152
+ * 0.17 — emit per-Artifact billing events when a compile run reaches
2153
+ * a terminal state. STUB FORM: writes a JSONL file alongside the run
2154
+ * record by default. Production sink (Metronome HTTP) wires in 0.18+.
2155
+ * The JSONL output is observability/dev fixture, NOT production
2156
+ * billing data.
2157
+ */
2158
+ emitBillingEventsForRun(prepDataDir, context) {
2159
+ try {
2160
+ const run = this.readCompileRun(context.compiledPath, context.runId);
2161
+ if (!run || run.artifacts.length === 0)
2162
+ return;
2163
+ const sink = this.billingEventSink ?? new JsonlBillingEventSink(defaultBillingEventLogPath({
2164
+ preparationDataDir: prepDataDir,
2165
+ preparationName: run.preparation,
2166
+ runId: context.runId,
2167
+ }));
2168
+ const events = buildCompilationEventsForRun({
2169
+ runId: context.runId,
2170
+ preparation: run.preparation,
2171
+ methodId: run.method,
2172
+ accountId: null, // 0.17 — loopback only; cloud variant fills via tokenValidator (B4.3).
2173
+ artifacts: run.artifacts,
2174
+ startedAt: run.started_at ?? null,
2175
+ finishedAt: run.finished_at ?? null,
2176
+ });
2177
+ for (const event of events) {
2178
+ sink.emit(event);
2179
+ }
2180
+ }
2181
+ catch {
2182
+ // Billing is observability-only in 0.17; never let stub failures
2183
+ // block a successful compile.
2184
+ }
2185
+ }
2069
2186
  writeCompileRun(prepDataDir, compiledPath, run) {
2070
2187
  mkdirSync(compileRunsRoot(compiledPath), { recursive: true });
2071
2188
  writeJsonFile(compileRunPath(compiledPath, run.run_id), CompileRunSchema.parse(run));
@@ -2156,6 +2273,19 @@ export class LocalServiceRuntime {
2156
2273
  }),
2157
2274
  };
2158
2275
  next.latest_proof = [...next.stages].reverse().find((stage) => Boolean(stage.latest_proof))?.latest_proof ?? next.latest_proof;
2276
+ // Recompute per-Artifact status whenever the compile run is
2277
+ // refreshed from runtime state.
2278
+ try {
2279
+ const method = getCompiledMethod(current.method, { prepDataDir });
2280
+ next.artifacts = computeArtifactStatuses({
2281
+ method,
2282
+ compiledPath,
2283
+ stageRuns: next.stages,
2284
+ });
2285
+ }
2286
+ catch {
2287
+ next.artifacts = current.artifacts ?? [];
2288
+ }
2159
2289
  this.writeCompileRun(prepDataDir, compiledPath, next);
2160
2290
  }
2161
2291
  async emitRuntimeDerivedEvents(prepDataDir, compiledPath, runId) {
@@ -1,5 +1,7 @@
1
1
  import { type Server } from "node:http";
2
2
  import { type LocalServiceRunHandlers, type LocalServiceRuntime } from "./runtime.js";
3
+ import type { IdempotencyStore, RunLeaseStore, TokenValidator } from "./cloud-seams.js";
4
+ import type { BillingEventSink } from "./compile/billing-events.js";
3
5
  /** Generate a fresh per-instance bearer token. */
4
6
  export declare function createLocalServiceAuthToken(): string;
5
7
  export interface StartLocalServiceOptions {
@@ -21,6 +23,29 @@ export interface StartLocalServiceOptions {
21
23
  * and any caller that explicitly opts in).
22
24
  */
23
25
  authToken?: string | null | "auto";
26
+ /**
27
+ * 0.17 — cloud-variant auth seam (B4.3). When provided, every
28
+ * mutating request runs through this validator instead of the local
29
+ * constant-time bearer check, and the resulting `account_id` is
30
+ * stashed on the runtime context for billing-event attribution.
31
+ * Local default: `undefined` — fall back to `runtime.authToken`
32
+ * comparison.
33
+ */
34
+ tokenValidator?: TokenValidator;
35
+ /**
36
+ * 0.17 — cloud-variant interface seams forwarded to
37
+ * `LocalServiceRuntime`. Local default: in-process `Map`s on the
38
+ * runtime. Cloud variants pass shared implementations (Redis,
39
+ * Cassandra, etc.) so multi-replica engines coordinate. See
40
+ * `cloud-seams.ts` for the contracts.
41
+ */
42
+ idempotencyStore?: IdempotencyStore;
43
+ runLeaseStore?: RunLeaseStore;
44
+ /**
45
+ * 0.17 — billing event sink. Local default writes per-run JSONL.
46
+ * Cloud variants inject a Metronome HTTP sender once 0.18+ ships.
47
+ */
48
+ billingEventSink?: BillingEventSink;
24
49
  }
25
50
  export interface StartedLocalService {
26
51
  runtime: LocalServiceRuntime;
@@ -309,9 +309,18 @@ function sendFile(res, filePath) {
309
309
  try {
310
310
  if (!statSync(filePath).isFile())
311
311
  return false;
312
- writeHeaders(res, 200, {
313
- "content-type": contentType(filePath),
314
- });
312
+ const type = contentType(filePath);
313
+ const headers = { "content-type": type };
314
+ // 0.17 — never cache HTML responses. UI deploys ship a fresh
315
+ // dist via `npm run web:build` and a restart; without `no-store`,
316
+ // a browser sitting on a stale `index.html` would keep loading
317
+ // hashed asset paths that no longer exist. Hashed Next.js bundles
318
+ // under `_next/static/<hash>/` keep the default long-cache
319
+ // because the filename itself changes when content changes.
320
+ if (type.startsWith("text/html")) {
321
+ headers["cache-control"] = "no-store";
322
+ }
323
+ writeHeaders(res, 200, headers);
315
324
  res.end(readFileSync(filePath));
316
325
  return true;
317
326
  }
@@ -497,6 +506,17 @@ async function routeApi(req, res, runtime) {
497
506
  sendError(res, 400, "Missing required field: source.locator");
498
507
  return true;
499
508
  }
509
+ // TODO(cloud): activate remote-folder validator branch when the
510
+ // cloud variant lands. The local binary only knows how to read
511
+ // bytes from a local path; a `remote-folder` binding requires
512
+ // the cloud variant's per-account object-storage mount layer.
513
+ // Until then, reject any kind other than `local-folder` so the
514
+ // wire shape and runtime stay consistent.
515
+ const requestedKind = typeof body.source.kind === "string" ? body.source.kind : "local-folder";
516
+ if (requestedKind !== "local-folder") {
517
+ sendError(res, 400, `Unsupported source kind: ${requestedKind}. The local engine only accepts local-folder bindings; remote-folder requires the cloud variant.`);
518
+ return true;
519
+ }
500
520
  const stored = createStoredPreparation(runtime, {
501
521
  id: body.id,
502
522
  source: { kind: "local-folder", locator: body.source.locator },
@@ -544,6 +564,7 @@ async function routeApi(req, res, runtime) {
544
564
  const updated = updateStoredPreparation(decodedPrepId, {
545
565
  method_id: body.method_id,
546
566
  about: body.about,
567
+ ...(body.checks !== undefined ? { checks: body.checks } : {}),
547
568
  });
548
569
  sendJson(res, 200, preparationWireShape(updated));
549
570
  }
@@ -738,6 +759,29 @@ async function routeApi(req, res, runtime) {
738
759
  return true;
739
760
  }
740
761
  }
762
+ else if (subPath.startsWith(`${PREPARATION_SUBRESOURCES.artifacts}/`)) {
763
+ // GET /v1/preparations/<id>/artifacts/<artifact-id> — per-Artifact
764
+ // status from the latest compile run. 0.17.
765
+ if (method === "GET") {
766
+ const rawArtifactId = subPath.slice(PREPARATION_SUBRESOURCES.artifacts.length + 1);
767
+ let artifactId;
768
+ try {
769
+ artifactId = decodeURIComponent(rawArtifactId);
770
+ }
771
+ catch {
772
+ sendError(res, 400, "Artifact id is not valid URI-encoded UTF-8.");
773
+ return true;
774
+ }
775
+ const preparation = runtime.getPreparation(storedPrep.prepDataDir, storedPrep.id);
776
+ const status = preparation?.artifacts.find((entry) => entry.artifact_id === artifactId);
777
+ if (!status) {
778
+ sendError(res, 404, `Artifact not found: ${artifactId}`);
779
+ return true;
780
+ }
781
+ sendJson(res, 200, status);
782
+ return true;
783
+ }
784
+ }
741
785
  sendError(res, 404, `Unknown preparation sub-route: ${subPath}`);
742
786
  return true;
743
787
  }
@@ -1181,7 +1225,22 @@ export async function startLocalService(options = {}) {
1181
1225
  packageVersion: options.packageVersion,
1182
1226
  handlers: options.handlers,
1183
1227
  ...(authToken ? { authToken } : {}),
1228
+ // 0.17 — forward cloud-variant injection points. Local default
1229
+ // ignores idempotencyStore / runLeaseStore (the runtime's
1230
+ // in-process maps stay authoritative); they're accepted on the
1231
+ // options surface so cloud forks have a stable target.
1232
+ ...(options.billingEventSink ? { billingEventSink: options.billingEventSink } : {}),
1233
+ ...(options.idempotencyStore ? { idempotencyStore: options.idempotencyStore } : {}),
1234
+ ...(options.runLeaseStore ? { runLeaseStore: options.runLeaseStore } : {}),
1184
1235
  });
1236
+ // 0.17 — token validator (B4.3). Local default: undefined. Cloud
1237
+ // variants pass an async per-account validator. Stashed on the
1238
+ // runtime via `setTokenValidator` so `isAuthorizedMutation` can
1239
+ // pick it up; the local engine ignores it (the static bearer
1240
+ // check still runs).
1241
+ if (options.tokenValidator) {
1242
+ runtime.setTokenValidator(options.tokenValidator);
1243
+ }
1185
1244
  // Rehydrate 0.13 preparations as synthetic workspaces so subsequent
1186
1245
  // compile / test / readiness calls find them after a service restart.
1187
1246
  try {
@@ -1,13 +1,13 @@
1
1
  export * as schema from "./lib/schema.js";
2
- export * as test from "./test.js";
3
- export * as execution from "./test-execution.js";
4
- export * as paths from "./test-paths.js";
5
- export * as profilePresets from "./test-profile-presets.js";
2
+ export * as verify from "./verify.js";
3
+ export * as execution from "./verify-execution.js";
4
+ export * as paths from "./verify-paths.js";
5
+ export * as profilePresets from "./verify-profile-presets.js";
6
6
  export * as readinessCheckRun from "./readiness-check-run.js";
7
- export * as sandbox from "./test-sandbox.js";
8
- export * as specs from "./test-specs.js";
9
- export * as targets from "./test-targets.js";
10
- export * as types from "./test-types.js";
7
+ export * as sandbox from "./verify-sandbox.js";
8
+ export * as specs from "./verify-specs.js";
9
+ export * as targets from "./verify-targets.js";
10
+ export * as types from "./verify-types.js";
11
11
  export type { TestCase, TestCaseExpect, TestCheckResult, TestCaseResult, TestSpec, TestTargetResult, TestTargetRun, ReadinessCheckRun, TestTargetType, } from "./lib/schema.js";
12
- export type { LoadedTestSpec, TestTargetCandidate, } from "./test-types.js";
13
- export type { TestSandboxRetentionMode, } from "./test-sandbox.js";
12
+ export type { LoadedTestSpec, TestTargetCandidate, } from "./verify-types.js";
13
+ export type { TestSandboxRetentionMode, } from "./verify-sandbox.js";
@@ -1,10 +1,10 @@
1
1
  export * as schema from "./lib/schema.js";
2
- export * as test from "./test.js";
3
- export * as execution from "./test-execution.js";
4
- export * as paths from "./test-paths.js";
5
- export * as profilePresets from "./test-profile-presets.js";
2
+ export * as verify from "./verify.js";
3
+ export * as execution from "./verify-execution.js";
4
+ export * as paths from "./verify-paths.js";
5
+ export * as profilePresets from "./verify-profile-presets.js";
6
6
  export * as readinessCheckRun from "./readiness-check-run.js";
7
- export * as sandbox from "./test-sandbox.js";
8
- export * as specs from "./test-specs.js";
9
- export * as targets from "./test-targets.js";
10
- export * as types from "./test-types.js";
7
+ export * as sandbox from "./verify-sandbox.js";
8
+ export * as specs from "./verify-specs.js";
9
+ export * as targets from "./verify-targets.js";
10
+ export * as types from "./verify-types.js";
@@ -1,7 +1,8 @@
1
1
  import type { MethodExecutor } from "../agents/lib/executors.js";
2
2
  import type { SourcePreparationConfig } from "../../project/lib/schema.js";
3
- import { type TestTargetCandidate, type TestTargetResult } from "./test.js";
4
- import type { TestSandboxRetentionMode } from "./test-sandbox.js";
3
+ import type { TestTargetType } from "../../contracts/lib/schema.js";
4
+ import { type TestTargetCandidate, type TestTargetResult } from "./verify.js";
5
+ import type { TestSandboxRetentionMode } from "./verify-sandbox.js";
5
6
  import { type ReadinessCheckRun } from "./lib/schema.js";
6
7
  export interface SavedReadinessCheckOutcome {
7
8
  runPath: string;
@@ -14,8 +15,9 @@ export interface ReadinessCheckRunResult {
14
15
  preparationConfig: SourcePreparationConfig;
15
16
  portableContextPath: string | null;
16
17
  /**
17
- * 0.15`sourceFilesOutcome` is always `null`. Kept on the type so
18
- * older readers parse cleanly during the rollout; remove in 0.16+.
18
+ * 0.17restored. Populated when the verify run targets
19
+ * `source-files`; null when targeting `compiled`. Aggregates back
20
+ * onto the saved `ReadinessCheckRun` payload's `source_files` field.
19
21
  */
20
22
  sourceFilesOutcome: SavedReadinessCheckOutcome | null;
21
23
  compiledOutcome: SavedReadinessCheckOutcome | null;
@@ -39,6 +41,7 @@ export declare function saveReadinessCheckRun(options: {
39
41
  portableContextPath: string | null;
40
42
  preparationName: string;
41
43
  checksFingerprint: string;
44
+ sourceFilesOutcome?: SavedReadinessCheckOutcome | null;
42
45
  compiledOutcome: SavedReadinessCheckOutcome | null;
43
46
  }): string;
44
47
  export declare function runSavedPortableContextCheck(options: {
@@ -49,6 +52,20 @@ export declare function runSavedPortableContextCheck(options: {
49
52
  preserveSandboxes?: TestSandboxRetentionMode;
50
53
  runSuffix?: string | null;
51
54
  }): Promise<SavedReadinessCheckOutcome | null>;
55
+ /**
56
+ * 0.17 — restored. Runs the saved readiness checks against the source
57
+ * folder baseline (no portable-context indirection) so users can see how
58
+ * much value the Method actually adds. The lower-level `verify-execution`
59
+ * + `verify-sandbox` source-files paths have stayed in tree since 0.13;
60
+ * this is the orchestrator hook that was missing.
61
+ */
62
+ export declare function runSavedSourceFilesCheck(options: {
63
+ sourcePath: string;
64
+ preparationConfig: SourcePreparationConfig;
65
+ executor?: MethodExecutor | null;
66
+ preserveSandboxes?: TestSandboxRetentionMode;
67
+ runSuffix?: string | null;
68
+ }): Promise<SavedReadinessCheckOutcome | null>;
52
69
  export declare function runReadinessChecksForExecutor(options: {
53
70
  sourcePath: string;
54
71
  preparationConfig: SourcePreparationConfig;
@@ -57,4 +74,10 @@ export declare function runReadinessChecksForExecutor(options: {
57
74
  preserveSandboxes?: TestSandboxRetentionMode;
58
75
  runSuffix?: string | null;
59
76
  saveLatest?: boolean;
77
+ /**
78
+ * 0.17 — selects which target the readiness checks judge against.
79
+ * Defaults to `compiled` for backward compatibility with existing
80
+ * callers.
81
+ */
82
+ target?: TestTargetType;
60
83
  }): Promise<ReadinessCheckRunResult>;