@interf/compiler 0.33.0 → 0.50.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 (234) hide show
  1. package/README.md +122 -226
  2. package/dist/cli/commands/agents.js +1 -32
  3. package/dist/cli/commands/benchmark.d.ts +2 -3
  4. package/dist/cli/commands/benchmark.js +1 -31
  5. package/dist/cli/commands/build-plan.js +26 -50
  6. package/dist/cli/commands/build.d.ts +2 -3
  7. package/dist/cli/commands/build.js +1 -31
  8. package/dist/cli/commands/graphs.js +177 -32
  9. package/dist/cli/commands/mcp.d.ts +1 -0
  10. package/dist/cli/commands/mcp.js +223 -126
  11. package/dist/cli/commands/project.js +10 -36
  12. package/dist/cli/commands/reset.d.ts +2 -3
  13. package/dist/cli/commands/reset.js +1 -22
  14. package/dist/cli/commands/runs.js +86 -33
  15. package/dist/cli/commands/status.js +3 -24
  16. package/dist/cli/commands/traces.js +1 -29
  17. package/dist/cli/commands/wizard.js +17 -29
  18. package/dist/cli/lib/http-client.d.ts +39 -0
  19. package/dist/cli/lib/http-client.js +73 -0
  20. package/dist/packages/build-plans/authoring/brief.d.ts +25 -4
  21. package/dist/packages/build-plans/authoring/build-plan-authoring.d.ts +42 -1
  22. package/dist/packages/build-plans/authoring/build-plan-authoring.js +470 -63
  23. package/dist/packages/build-plans/authoring/build-plan-edit-session.d.ts +9 -0
  24. package/dist/packages/build-plans/authoring/build-plan-edit-session.js +27 -10
  25. package/dist/packages/build-plans/authoring/build-plan-improvement.js +62 -8
  26. package/dist/packages/build-plans/authoring/lib/build-plan-edit-utils.d.ts +1 -0
  27. package/dist/packages/build-plans/package/build-plan-definitions.d.ts +0 -1
  28. package/dist/packages/build-plans/package/build-plan-definitions.js +5 -3
  29. package/dist/packages/build-plans/package/build-plan-stage-runner.d.ts +1 -0
  30. package/dist/packages/build-plans/package/build-plan-stage-runner.js +2 -1
  31. package/dist/packages/build-plans/package/builtin-build-plan.d.ts +2 -2
  32. package/dist/packages/build-plans/package/builtin-build-plan.js +3 -3
  33. package/dist/packages/build-plans/package/context-interface.d.ts +3 -0
  34. package/dist/packages/build-plans/package/context-interface.js +5 -5
  35. package/dist/packages/build-plans/package/interf-build-plan-package.js +22 -22
  36. package/dist/packages/build-plans/package/local-build-plans.d.ts +10 -5
  37. package/dist/packages/build-plans/package/local-build-plans.js +57 -32
  38. package/dist/packages/contracts/index.d.ts +4 -3
  39. package/dist/packages/contracts/index.js +2 -1
  40. package/dist/packages/contracts/lib/context-graph-layer.d.ts +161 -0
  41. package/dist/packages/contracts/lib/context-graph-layer.js +216 -0
  42. package/dist/packages/contracts/lib/project-paths.d.ts +7 -0
  43. package/dist/packages/contracts/lib/project-paths.js +9 -0
  44. package/dist/packages/contracts/lib/project-schema.d.ts +264 -1
  45. package/dist/packages/contracts/lib/project-schema.js +38 -13
  46. package/dist/packages/contracts/lib/schema.d.ts +556 -23
  47. package/dist/packages/contracts/lib/schema.js +279 -18
  48. package/dist/packages/contracts/utils/filesystem.d.ts +1 -0
  49. package/dist/packages/contracts/utils/filesystem.js +29 -1
  50. package/dist/packages/projects/lib/schema.d.ts +6 -8
  51. package/dist/packages/projects/lib/schema.js +3 -1
  52. package/dist/packages/projects/source-config.d.ts +0 -5
  53. package/dist/packages/projects/source-config.js +9 -22
  54. package/dist/packages/runtime/actions/fields.d.ts +4 -0
  55. package/dist/packages/runtime/actions/form-builders.js +79 -31
  56. package/dist/packages/runtime/actions/form-validators.js +9 -3
  57. package/dist/packages/runtime/actions/helpers.js +3 -3
  58. package/dist/packages/runtime/actions/registry.d.ts +1 -1
  59. package/dist/packages/runtime/actions/registry.js +1 -1
  60. package/dist/packages/runtime/actions/requests.d.ts +1 -1
  61. package/dist/packages/runtime/actions/requests.js +12 -6
  62. package/dist/packages/runtime/actions/schemas.d.ts +7 -0
  63. package/dist/packages/runtime/actions/schemas.js +1 -0
  64. package/dist/packages/runtime/agent-handoff.js +8 -7
  65. package/dist/packages/runtime/agents/lib/execution-profile.d.ts +14 -0
  66. package/dist/packages/runtime/agents/lib/execution-profile.js +23 -0
  67. package/dist/packages/runtime/agents/lib/execution.js +14 -8
  68. package/dist/packages/runtime/agents/lib/executors.d.ts +1 -0
  69. package/dist/packages/runtime/agents/lib/executors.js +11 -2
  70. package/dist/packages/runtime/agents/lib/logs.d.ts +10 -0
  71. package/dist/packages/runtime/agents/lib/logs.js +32 -8
  72. package/dist/packages/runtime/agents/lib/preflight.js +4 -1
  73. package/dist/packages/runtime/agents/lib/render.d.ts +18 -0
  74. package/dist/packages/runtime/agents/lib/render.js +44 -18
  75. package/dist/packages/runtime/agents/lib/shell-templates.js +105 -63
  76. package/dist/packages/runtime/agents/lib/shells.d.ts +29 -0
  77. package/dist/packages/runtime/agents/lib/shells.js +158 -32
  78. package/dist/packages/runtime/agents/lib/source-context-scan.d.ts +10 -0
  79. package/dist/packages/runtime/agents/lib/source-context-scan.js +388 -0
  80. package/dist/packages/runtime/agents/lib/status.js +1 -14
  81. package/dist/packages/runtime/agents/lib/string-utils.d.ts +16 -0
  82. package/dist/packages/runtime/agents/lib/string-utils.js +36 -0
  83. package/dist/packages/runtime/agents/lib/types.d.ts +1 -0
  84. package/dist/packages/runtime/agents/providers/codex.js +2 -0
  85. package/dist/packages/runtime/agents/role-executors.js +2 -1
  86. package/dist/packages/runtime/auth/session-store.js +11 -3
  87. package/dist/packages/runtime/benchmark-question-draft.d.ts +3 -0
  88. package/dist/packages/runtime/benchmark-question-draft.js +57 -28
  89. package/dist/packages/runtime/build/artifact-status.d.ts +1 -1
  90. package/dist/packages/runtime/build/artifact-status.js +1 -1
  91. package/dist/packages/runtime/build/build-evidence.d.ts +2 -1
  92. package/dist/packages/runtime/build/build-evidence.js +11 -5
  93. package/dist/packages/runtime/build/build-pipeline.js +89 -5
  94. package/dist/packages/runtime/build/build-stage-plan.js +3 -1
  95. package/dist/packages/runtime/build/build-stage-runner.js +169 -32
  96. package/dist/packages/runtime/build/build-target.d.ts +3 -0
  97. package/dist/packages/runtime/build/build-target.js +25 -1
  98. package/dist/packages/runtime/build/check-evaluator.d.ts +1 -1
  99. package/dist/packages/runtime/build/check-evaluator.js +655 -4
  100. package/dist/packages/runtime/build/context-graph-paths.d.ts +13 -0
  101. package/dist/packages/runtime/build/context-graph-paths.js +27 -0
  102. package/dist/packages/runtime/build/index.d.ts +2 -2
  103. package/dist/packages/runtime/build/index.js +2 -2
  104. package/dist/packages/runtime/build/inspect-map.d.ts +10 -0
  105. package/dist/packages/runtime/build/inspect-map.js +270 -0
  106. package/dist/packages/runtime/build/lib/schema.d.ts +246 -53
  107. package/dist/packages/runtime/build/lib/schema.js +173 -15
  108. package/dist/packages/runtime/build/native-entrypoint.d.ts +2 -0
  109. package/dist/packages/runtime/build/native-entrypoint.js +286 -0
  110. package/dist/packages/runtime/build/runtime-contracts.js +9 -3
  111. package/dist/packages/runtime/build/runtime-log-paths.d.ts +3 -0
  112. package/dist/packages/runtime/build/runtime-log-paths.js +16 -0
  113. package/dist/packages/runtime/build/runtime-prompt.js +6 -4
  114. package/dist/packages/runtime/build/runtime-runs.js +63 -10
  115. package/dist/packages/runtime/build/runtime-types.d.ts +4 -1
  116. package/dist/packages/runtime/build/runtime.d.ts +3 -1
  117. package/dist/packages/runtime/build/runtime.js +3 -1
  118. package/dist/packages/runtime/build/source-files.js +11 -2
  119. package/dist/packages/runtime/build/source-inventory.d.ts +1 -0
  120. package/dist/packages/runtime/build/source-inventory.js +246 -7
  121. package/dist/packages/runtime/build/source-manifest.d.ts +11 -0
  122. package/dist/packages/runtime/build/source-manifest.js +30 -2
  123. package/dist/packages/runtime/build/stage-evidence.js +80 -11
  124. package/dist/packages/runtime/build/stage-manifest.d.ts +45 -0
  125. package/dist/packages/runtime/build/stage-manifest.js +1125 -0
  126. package/dist/packages/runtime/build/stage-reuse.js +12 -0
  127. package/dist/packages/runtime/build/stage-session.d.ts +81 -0
  128. package/dist/packages/runtime/build/stage-session.js +308 -0
  129. package/dist/packages/runtime/build/state-io.js +10 -11
  130. package/dist/packages/runtime/build/state-view.js +1 -1
  131. package/dist/packages/runtime/build/state.d.ts +1 -1
  132. package/dist/packages/runtime/build/state.js +1 -1
  133. package/dist/packages/runtime/build/summary-coverage-index.d.ts +21 -0
  134. package/dist/packages/runtime/build/summary-coverage-index.js +189 -0
  135. package/dist/packages/runtime/build/traces.js +3 -3
  136. package/dist/packages/runtime/build/validate-context-graph.d.ts +1 -1
  137. package/dist/packages/runtime/build/validate-context-graph.js +5 -5
  138. package/dist/packages/runtime/build/validate.d.ts +1 -1
  139. package/dist/packages/runtime/build/validate.js +1 -1
  140. package/dist/packages/runtime/client.d.ts +3 -3
  141. package/dist/packages/runtime/client.js +8 -13
  142. package/dist/packages/runtime/context-checks.js +13 -0
  143. package/dist/packages/runtime/context-graph-scaffold.js +2 -1
  144. package/dist/packages/runtime/context-graph-semantic-graph.d.ts +9 -0
  145. package/dist/packages/runtime/context-graph-semantic-graph.js +416 -0
  146. package/dist/packages/runtime/execution/lib/schema.d.ts +34 -31
  147. package/dist/packages/runtime/index.d.ts +2 -2
  148. package/dist/packages/runtime/index.js +1 -1
  149. package/dist/packages/runtime/native-run-handlers.d.ts +38 -0
  150. package/dist/packages/runtime/native-run-handlers.js +52 -33
  151. package/dist/packages/runtime/plan-artifact-contract.js +1 -1
  152. package/dist/packages/runtime/project-source-state.d.ts +4 -4
  153. package/dist/packages/runtime/project-source-state.js +5 -2
  154. package/dist/packages/runtime/project-store.d.ts +5 -0
  155. package/dist/packages/runtime/project-store.js +30 -3
  156. package/dist/packages/runtime/requested-artifacts.js +1 -1
  157. package/dist/packages/runtime/run-observability.js +9 -4
  158. package/dist/packages/runtime/runtime-action-proposals.js +3 -3
  159. package/dist/packages/runtime/runtime-build-plans.js +47 -3
  160. package/dist/packages/runtime/runtime-build-runs.js +9 -16
  161. package/dist/packages/runtime/runtime-caches.d.ts +26 -0
  162. package/dist/packages/runtime/runtime-caches.js +47 -0
  163. package/dist/packages/runtime/runtime-jobs.js +6 -6
  164. package/dist/packages/runtime/runtime-project-mutations.js +1 -0
  165. package/dist/packages/runtime/runtime-project-reads.d.ts +4 -1
  166. package/dist/packages/runtime/runtime-project-reads.js +229 -36
  167. package/dist/packages/runtime/runtime-proposal-helpers.js +6 -6
  168. package/dist/packages/runtime/runtime-resource-builders.d.ts +4 -2
  169. package/dist/packages/runtime/runtime-resource-builders.js +16 -14
  170. package/dist/packages/runtime/runtime-status.d.ts +14 -0
  171. package/dist/packages/runtime/runtime-status.js +15 -0
  172. package/dist/packages/runtime/runtime-verify-runs.js +6 -5
  173. package/dist/packages/runtime/runtime.d.ts +439 -22
  174. package/dist/packages/runtime/runtime.js +16 -2
  175. package/dist/packages/runtime/schemas/actions.d.ts +24 -0
  176. package/dist/packages/runtime/schemas/agents.d.ts +28 -0
  177. package/dist/packages/runtime/schemas/agents.js +33 -0
  178. package/dist/packages/runtime/schemas/build-plans.d.ts +181 -8
  179. package/dist/packages/runtime/schemas/build-plans.js +36 -2
  180. package/dist/packages/runtime/schemas/context-graphs.d.ts +1522 -0
  181. package/dist/packages/runtime/schemas/context-graphs.js +110 -0
  182. package/dist/packages/runtime/schemas/files.d.ts +7 -347
  183. package/dist/packages/runtime/schemas/files.js +1 -24
  184. package/dist/packages/runtime/schemas/index.d.ts +1 -0
  185. package/dist/packages/runtime/schemas/index.js +1 -0
  186. package/dist/packages/runtime/schemas/jobs.js +4 -0
  187. package/dist/packages/runtime/schemas/projects.d.ts +48 -21
  188. package/dist/packages/runtime/schemas/projects.js +34 -10
  189. package/dist/packages/runtime/schemas/runs.d.ts +1009 -240
  190. package/dist/packages/runtime/schemas/runs.js +17 -0
  191. package/dist/packages/runtime/service/openapi.js +1 -0
  192. package/dist/packages/runtime/service/operations.d.ts +1666 -145
  193. package/dist/packages/runtime/service/operations.js +147 -17
  194. package/dist/packages/runtime/service/routes.d.ts +11 -3
  195. package/dist/packages/runtime/service/routes.js +11 -3
  196. package/dist/packages/runtime/service/server-app-boot.js +2 -2
  197. package/dist/packages/runtime/service/server-helpers.d.ts +11 -0
  198. package/dist/packages/runtime/service/server-helpers.js +19 -0
  199. package/dist/packages/runtime/service/server-routes-action-proposals.js +4 -2
  200. package/dist/packages/runtime/service/server-routes-agents.js +19 -85
  201. package/dist/packages/runtime/service/server-routes-build-plans.js +14 -11
  202. package/dist/packages/runtime/service/server-routes-project-context.js +102 -7
  203. package/dist/packages/runtime/service/server-routes-project-jobs.js +19 -12
  204. package/dist/packages/runtime/service/server-routes-project-runs.js +5 -2
  205. package/dist/packages/runtime/service/server-routes-projects.js +6 -2
  206. package/dist/packages/runtime/service/server-routes-runs.js +11 -4
  207. package/dist/packages/runtime/verify/lib/schema.js +12 -0
  208. package/dist/packages/runtime/verify/test-file-guard.d.ts +2 -0
  209. package/dist/packages/runtime/verify/test-file-guard.js +29 -0
  210. package/dist/packages/runtime/verify/verify-execution.d.ts +7 -0
  211. package/dist/packages/runtime/verify/verify-execution.js +109 -35
  212. package/dist/packages/runtime/verify/verify-paths.d.ts +1 -0
  213. package/dist/packages/runtime/verify/verify-paths.js +4 -0
  214. package/dist/packages/runtime/verify/verify-specs.js +49 -39
  215. package/dist/packages/runtime/wire-schemas.d.ts +1 -1
  216. package/dist/packages/runtime/wire-schemas.js +1 -1
  217. package/package.json +2 -8
  218. package/public-repo/CONTRIBUTING.md +10 -3
  219. package/public-repo/README.md +122 -226
  220. package/public-repo/build-plans/interf-default/README.md +15 -12
  221. package/public-repo/build-plans/interf-default/build/stages/entrypoint/SKILL.md +74 -0
  222. package/public-repo/build-plans/interf-default/build/stages/knowledge/SKILL.md +95 -0
  223. package/public-repo/build-plans/interf-default/build/stages/summarize/SKILL.md +38 -5
  224. package/public-repo/build-plans/interf-default/build-plan.json +27 -23
  225. package/public-repo/build-plans/interf-default/build-plan.schema.json +24 -20
  226. package/public-repo/build-plans/interf-default/use/query/SKILL.md +8 -7
  227. package/public-repo/openapi/local-service.openapi.json +11637 -4213
  228. package/public-repo/skills/interf/SKILL.md +174 -134
  229. package/dist/packages/runtime/build/runtime-paths.d.ts +0 -8
  230. package/dist/packages/runtime/build/runtime-paths.js +0 -26
  231. package/dist/packages/runtime/build/state-paths.d.ts +0 -7
  232. package/dist/packages/runtime/build/state-paths.js +0 -22
  233. package/public-repo/build-plans/interf-default/build/stages/shape/SKILL.md +0 -34
  234. package/public-repo/build-plans/interf-default/build/stages/structure/SKILL.md +0 -28
@@ -23,7 +23,7 @@ import type { StageRun } from "../execution/lib/schema.js";
23
23
  * the run record carries the real causal signal.
24
24
  */
25
25
  export declare function computeArtifactStatuses(options: {
26
- buildPlan: Pick<BuildPlanDefinition<string>, "stages" | "contextInterface" | "schema">;
26
+ buildPlan: Pick<BuildPlanDefinition<string>, "stages" | "contextInterface">;
27
27
  contextGraphPath: string;
28
28
  stageRuns: StageRun[];
29
29
  /**
@@ -39,7 +39,7 @@ export function computeArtifactStatuses(options) {
39
39
  }));
40
40
  }
41
41
  function pickContextInterface(buildPlan) {
42
- return buildPlan.contextInterface ?? buildPlan.schema;
42
+ return buildPlan.contextInterface;
43
43
  }
44
44
  function buildStageWriteIndex(stages) {
45
45
  const index = new Map();
@@ -1,4 +1,4 @@
1
- import { type BuildEvidenceResource, type Readiness } from "../../contracts/lib/schema.js";
1
+ import { type BuildEvidenceResource, type MetricCount, type Readiness } from "../../contracts/lib/schema.js";
2
2
  import type { BuildRun } from "../execution/lib/schema.js";
3
3
  import type { StageEvidenceReconciliation } from "./lib/schema.js";
4
4
  interface BuildBuildEvidenceInput {
@@ -9,6 +9,7 @@ interface BuildBuildEvidenceInput {
9
9
  expectedStageCount?: number;
10
10
  expectedOutputCount?: number;
11
11
  stageEvidence?: readonly StageEvidenceReconciliation[];
12
+ primaryMetrics?: readonly MetricCount[];
12
13
  generatedAt?: string;
13
14
  }
14
15
  export declare function buildBuildEvidence(input: BuildBuildEvidenceInput): BuildEvidenceResource;
@@ -25,6 +25,10 @@ function sourceFilesProcessed(stages) {
25
25
  }
26
26
  return observed;
27
27
  }
28
+ function primaryMetricValue(metrics, key) {
29
+ const value = metrics?.find((entry) => entry.key === key)?.value;
30
+ return typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.trunc(value)) : null;
31
+ }
28
32
  function requiredArtifactCheckResults(artifacts) {
29
33
  return artifacts
30
34
  .flatMap((artifact) => artifact.check_results ?? [])
@@ -61,8 +65,10 @@ export function buildBuildEvidence(input) {
61
65
  const acceptedFilesProcessed = acceptedEvidenceCounts
62
66
  .filter((count) => count.key === "files_processed")
63
67
  .reduce((max, count) => Math.max(max, count.value), 0);
68
+ const graphFilesProcessed = primaryMetricValue(input.primaryMetrics, "files_processed");
64
69
  const filesObserved = buildRun
65
- ? Math.min(hasAcceptedStageEvidence ? acceptedFilesProcessed : sourceFilesProcessed(stages), filesTotal)
70
+ ? Math.min(graphFilesProcessed ??
71
+ (hasAcceptedStageEvidence ? acceptedFilesProcessed : sourceFilesProcessed(stages)), filesTotal)
66
72
  : 0;
67
73
  const filesState = issueState(filesObserved, filesTotal, { reviewWhenEmpty: true });
68
74
  rows.push({
@@ -74,7 +80,7 @@ export function buildBuildEvidence(input) {
74
80
  label: buildRun ? "Build stage records" : "Source inventory",
75
81
  ...(buildRun ? { run_id: buildRun.run_id, ref: `run:${buildRun.run_id}` } : { ref: "source-files" }),
76
82
  },
77
- ...rowStateIssue(filesState, `${filesTotal - filesObserved} Source file${filesTotal - filesObserved === 1 ? "" : "s"} lack accepted Build evidence.`),
83
+ ...rowStateIssue(filesState, `${filesTotal - filesObserved} Source file${filesTotal - filesObserved === 1 ? "" : "s"} lack accepted coverage records.`),
78
84
  });
79
85
  const stageTotal = input.expectedStageCount ?? stages[0]?.stage_total ?? stages.length;
80
86
  const stagesSucceeded = stages.filter((stage) => stage.status === "succeeded").length;
@@ -141,16 +147,16 @@ export function buildBuildEvidence(input) {
141
147
  }
142
148
  const failed = buildRun?.status === "failed";
143
149
  const hasBlockingRows = rowsHaveBlockingIssue(rows);
144
- // Build evidence explains the runtime readiness verdict; it does not
150
+ // Supplemental diagnostics explain the runtime readiness verdict; they do not
145
151
  // create a second readiness source of truth.
146
152
  const ready = Boolean(input.readiness?.ready) && !failed;
147
153
  const summary = failed
148
154
  ? "Latest Build failed before the Context Graph was ready."
149
155
  : ready
150
156
  ? hasBlockingRows
151
- ? "Ready by runtime readiness; review Build evidence rows for follow-up."
157
+ ? "Ready by runtime readiness; review supplemental diagnostic rows for follow-up."
152
158
  : "Ready for agent task."
153
- : "Context Graph is not ready; review missing Build evidence.";
159
+ : "Context Graph is not ready; review missing coverage diagnostics.";
154
160
  return BuildEvidenceResourceSchema.parse({
155
161
  kind: "interf-build-evidence",
156
162
  version: 1,
@@ -3,11 +3,15 @@ import { validateBuildPlanPackage } from "../../build-plans/package/local-build-
3
3
  import { reportValidationFailure, } from "../../build-plans/package/build-plan-helpers.js";
4
4
  import { validateContextGraph, } from "./validate.js";
5
5
  import { pruneStageExecutionShells, } from "../agents/lib/shells.js";
6
+ import { reconcilePrunedStageExecutionSessions, } from "./stage-session.js";
6
7
  import { buildExecutionStages, resolveBuildContext, } from "./build-target.js";
7
8
  import { runBuildStage } from "./build-stage-runner.js";
8
9
  import { buildPlanPackagePathForContextGraph } from "./context-graph-paths.js";
9
10
  import { runSourceInventory } from "./source-inventory.js";
10
11
  import { stageReuseDecision } from "./stage-reuse.js";
12
+ import { loadStageManifest, writeGraphManifest, } from "./stage-manifest.js";
13
+ import { writeContextGraphInspectMap } from "./inspect-map.js";
14
+ import { ensureSummaryCoverageIndex } from "./summary-coverage-index.js";
11
15
  import { createRunEventId, createRunEventTimestamp, } from "../execution/events.js";
12
16
  function pickStageExecutor(fallback, stage, resolve) {
13
17
  if (!resolve)
@@ -53,6 +57,24 @@ async function emitReusedStagePassed(options) {
53
57
  function reusedStageResult(summary = "reused (verified, unchanged)") {
54
58
  return { ok: true, code: 0, summary };
55
59
  }
60
+ /**
61
+ * Deterministic connectivity floor, applied after the stage agents have produced
62
+ * the graph but BEFORE readiness validation. Writes a managed coverage block into
63
+ * `home.md` (the entrypoint spine) wikilinking every summary the build produced,
64
+ * so every summary note has a guaranteed inbound edge no matter how the stage
65
+ * agent behaved. Best-effort: assembly is already complete, so a finalization
66
+ * error must never fail the build (the `graph_notes_connected` check still runs
67
+ * and will report any real gap).
68
+ */
69
+ function finalizeGraphConnectivity(contextGraphPath) {
70
+ try {
71
+ ensureSummaryCoverageIndex(contextGraphPath);
72
+ }
73
+ catch {
74
+ // Never fail a built graph on the navigation-index write. The connectivity
75
+ // check runs next and is the source of truth on readiness.
76
+ }
77
+ }
56
78
  export async function runBuildSummarize(options) {
57
79
  const context = resolveBuildContext(options.contextGraphPath);
58
80
  const stageDefinition = options.stageDefinition
@@ -69,6 +91,7 @@ export async function runBuildSummarize(options) {
69
91
  executor: pickStageExecutor(options.executor, stageDefinition, options.resolveStageExecutor),
70
92
  contextGraphPath: options.contextGraphPath,
71
93
  project: context.contextGraphName,
94
+ projectIntent: context.projectIntent,
72
95
  sourceLocator: context.sourcePath,
73
96
  buildPlanId: context.buildPlanId,
74
97
  stageIds: [stageDefinition.id],
@@ -90,7 +113,7 @@ export async function runBuildSummarize(options) {
90
113
  contextGraphPath: options.contextGraphPath,
91
114
  stageDefinition,
92
115
  });
93
- if (reuse.reuse) {
116
+ if (reuse.reuse && loadStageManifest(options.contextGraphPath, stageDefinition.id)) {
94
117
  await emitReusedStagePassed({
95
118
  events: options.events,
96
119
  runId: options.runId,
@@ -128,7 +151,7 @@ export async function runBuildSummarize(options) {
128
151
  };
129
152
  }
130
153
  export async function runBuildStages(options) {
131
- const preserveMode = options.preserveStageShells ?? "on-failure";
154
+ const preserveMode = options.preserveStageShells ?? "always";
132
155
  if (preserveMode !== "always") {
133
156
  pruneStageExecutionShells(options.contextGraphPath);
134
157
  }
@@ -141,6 +164,7 @@ export async function runBuildStages(options) {
141
164
  executor: sourceInventoryExecutor,
142
165
  contextGraphPath: options.contextGraphPath,
143
166
  project: context.contextGraphName,
167
+ projectIntent: context.projectIntent,
144
168
  sourceLocator: context.sourcePath,
145
169
  buildPlanId: context.buildPlanId,
146
170
  stageIds: stages.map((stage) => stage.id),
@@ -158,7 +182,7 @@ export async function runBuildStages(options) {
158
182
  contextGraphPath: options.contextGraphPath,
159
183
  stageDefinition,
160
184
  });
161
- if (reuse.reuse) {
185
+ if (reuse.reuse && loadStageManifest(options.contextGraphPath, stageDefinition.id)) {
162
186
  await emitReusedStagePassed({
163
187
  events: options.events,
164
188
  runId: options.runId,
@@ -188,16 +212,36 @@ export async function runBuildStages(options) {
188
212
  if (!result.ok)
189
213
  return result;
190
214
  }
215
+ // Connectivity floor: link every summary into a deterministic navigation
216
+ // index before the GraphManifest rolls up coverage and connectivity metrics.
217
+ finalizeGraphConnectivity(options.contextGraphPath);
218
+ writeGraphManifest({
219
+ contextGraphPath: options.contextGraphPath,
220
+ projectId: context.contextGraphName,
221
+ buildPlanId: context.buildPlanId,
222
+ intent: context.projectIntent,
223
+ runId: options.runId ?? null,
224
+ });
225
+ // Refresh the developer/agent map of the built folder from already-recorded
226
+ // state. Best-effort: it never fails the build.
227
+ writeContextGraphInspectMap(options.contextGraphPath);
191
228
  return lastResult;
192
229
  }
193
230
  finally {
194
231
  if (preserveMode !== "always" && lastResult.ok) {
195
232
  pruneStageExecutionShells(options.contextGraphPath);
233
+ // Pruning deleted the shells the sessions point at; downgrade those
234
+ // sessions so none dangles with replay_ready:true (F2).
235
+ reconcilePrunedStageExecutionSessions({ contextGraphPath: options.contextGraphPath });
236
+ // The in-try map render above reflected pre-reconcile sessions (shells the
237
+ // prune was about to delete). Re-render from the reconciled state so the
238
+ // map points only at shells still on disk (F1). Best-effort, never fails.
239
+ writeContextGraphInspectMap(options.contextGraphPath);
196
240
  }
197
241
  }
198
242
  }
199
243
  export async function buildContextGraph(options) {
200
- const preserveMode = options.preserveStageShells ?? "on-failure";
244
+ const preserveMode = options.preserveStageShells ?? "always";
201
245
  if (preserveMode !== "always") {
202
246
  pruneStageExecutionShells(options.contextGraphPath);
203
247
  }
@@ -232,6 +276,7 @@ export async function buildContextGraph(options) {
232
276
  executor: sourceInventoryExecutor,
233
277
  contextGraphPath: options.contextGraphPath,
234
278
  project: context.contextGraphName,
279
+ projectIntent: context.projectIntent,
235
280
  sourceLocator: context.sourcePath,
236
281
  buildPlanId: context.buildPlanId,
237
282
  stageIds: stages.map((stage) => stage.id),
@@ -253,7 +298,7 @@ export async function buildContextGraph(options) {
253
298
  contextGraphPath: options.contextGraphPath,
254
299
  stageDefinition,
255
300
  });
256
- if (reuse.reuse) {
301
+ if (reuse.reuse && loadStageManifest(options.contextGraphPath, stageDefinition.id)) {
257
302
  await emitReusedStagePassed({
258
303
  events: options.events,
259
304
  runId: options.runId,
@@ -286,6 +331,9 @@ export async function buildContextGraph(options) {
286
331
  return result;
287
332
  }
288
333
  }
334
+ // Connectivity floor: ensure every produced summary is reachable through a
335
+ // deterministic navigation index BEFORE readiness is validated.
336
+ finalizeGraphConnectivity(options.contextGraphPath);
289
337
  const buildPlanValidationResult = validateContextGraph(options.contextGraphPath);
290
338
  result.ok = buildPlanValidationResult.ok;
291
339
  result.failedStage = buildPlanValidationResult.ok ? null : buildPlanValidationResult.stage;
@@ -294,11 +342,47 @@ export async function buildContextGraph(options) {
294
342
  code: buildPlanValidationResult.ok ? 0 : 1,
295
343
  summary: buildPlanValidationResult.summary,
296
344
  };
345
+ if (buildPlanValidationResult.ok) {
346
+ try {
347
+ const graphManifest = writeGraphManifest({
348
+ contextGraphPath: options.contextGraphPath,
349
+ projectId: context.contextGraphName,
350
+ buildPlanId: context.buildPlanId,
351
+ intent: context.projectIntent,
352
+ runId: options.runId ?? null,
353
+ });
354
+ result.stageResults["graph-manifest"] = {
355
+ ok: true,
356
+ code: 0,
357
+ summary: `GraphManifest recorded ${graphManifest.resources.length} resource${graphManifest.resources.length === 1 ? "" : "s"} and ${graphManifest.graph_outputs.edges} graph edge${graphManifest.graph_outputs.edges === 1 ? "" : "s"}.`,
358
+ };
359
+ // Refresh the developer/agent map (.interf/INSPECT.md) of the built
360
+ // folder from already-recorded state. Best-effort: it never fails the
361
+ // build, so a render error does not flip a ready graph to failed.
362
+ writeContextGraphInspectMap(options.contextGraphPath);
363
+ }
364
+ catch (error) {
365
+ result.ok = false;
366
+ result.failedStage = "graph-manifest";
367
+ result.stageResults["graph-manifest"] = {
368
+ ok: false,
369
+ code: 1,
370
+ summary: `Could not write GraphManifest: ${error instanceof Error ? error.message : String(error)}`,
371
+ };
372
+ }
373
+ }
297
374
  return result;
298
375
  }
299
376
  finally {
300
377
  if (preserveMode !== "always" && result.ok) {
301
378
  pruneStageExecutionShells(options.contextGraphPath);
379
+ // Pruning deleted the shells the sessions point at; downgrade those
380
+ // sessions so none dangles with replay_ready:true (F2).
381
+ reconcilePrunedStageExecutionSessions({ contextGraphPath: options.contextGraphPath });
382
+ // The in-try map render above reflected pre-reconcile sessions (shells the
383
+ // prune was about to delete). Re-render from the reconciled state so the
384
+ // map points only at shells still on disk (F1). Best-effort, never fails.
385
+ writeContextGraphInspectMap(options.contextGraphPath);
302
386
  }
303
387
  }
304
388
  }
@@ -4,7 +4,7 @@ import { listFilesRecursive } from "../../contracts/utils/filesystem.js";
4
4
  import { contextGraphArtifactPath, contextGraphArtifactPathsForArtifactIds, findBuildPlanContextArtifact, readBuildPlanContextFile, } from "./context-graph-schema.js";
5
5
  import { buildLocalSkillContractExtension, buildStageInstructions, buildPlanStageDirectory, } from "../../build-plans/package/build-plan-helpers.js";
6
6
  import { loadContextGraphSourceManifest } from "./source-manifest.js";
7
- import { getActiveBuildPlanStagePolicyNotes, } from "../../build-plans/package/build-plan-definitions.js";
7
+ import { getActiveBuildPlan, getActiveBuildPlanStagePolicyNotes, } from "../../build-plans/package/build-plan-definitions.js";
8
8
  import { buildPlanPackagePathForContextGraph } from "./context-graph-paths.js";
9
9
  import { readInterfConfig } from "../../projects/interf-detect.js";
10
10
  import { resolveBuildContext, } from "./build-target.js";
@@ -72,6 +72,7 @@ export function buildStageContract(contextGraphPath, stageDefinition, instructio
72
72
  const stageArtifacts = resolveStageContractArtifacts(contextGraphPath, stageDefinition);
73
73
  return buildRuntimeStageContract({
74
74
  contextGraphName: config?.name ?? "context-graph",
75
+ project: resolveBuildContext(contextGraphPath).project,
75
76
  stageId: stageDefinition.id,
76
77
  stageLabel: stageDefinition.label,
77
78
  counts: buildStageCounts(contextGraphPath, stageDefinition),
@@ -82,6 +83,7 @@ export function buildStageContract(contextGraphPath, stageDefinition, instructio
82
83
  stageReadArtifacts: stageArtifacts.reads,
83
84
  stageWriteArtifacts: stageArtifacts.writes,
84
85
  stageWriteContracts: stageArtifacts.writeContracts,
86
+ contextChecks: getActiveBuildPlan(contextGraphPath).brief?.checks ?? [],
85
87
  buildPlanNotes: getActiveBuildPlanStagePolicyNotes(contextGraphPath, stageDefinition.id),
86
88
  localSkillDocs: instructions.local_docs,
87
89
  instructions,
@@ -1,11 +1,15 @@
1
1
  import { writeFileSync } from "node:fs";
2
- import { join } from "node:path";
2
+ import { join, relative } from "node:path";
3
3
  import { createStageExecutionShell, freezeStageExecutionShell, syncStageExecutionShellWrites, validateStageExecutionShellInputs, } from "../agents/lib/shells.js";
4
4
  import { reconcileBuildStageRun } from "./runtime-reconcile.js";
5
5
  import { refreshContextGraphArtifacts } from "./state.js";
6
6
  import { validateBuildStage } from "./validate.js";
7
7
  import { reconcileStageEvidence, stageEvidenceAcceptanceFailure, supportsStageEvidenceHarness, } from "./stage-evidence.js";
8
+ import { persistStageReviewedInputsFromShell, writeStageExpectedInputs, writeStageManifestFromOutputs, } from "./stage-manifest.js";
9
+ import { createNativeEntrypointExecutor, } from "./native-entrypoint.js";
8
10
  import { executeValidatedStage, } from "../../build-plans/package/build-plan-stage-runner.js";
11
+ import { loadExecutionStageLedger, } from "./runtime.js";
12
+ import { markStageExecutionSessionsShellPreserved, recordStageExecutionSessionValidationAttempt, } from "./stage-session.js";
9
13
  import { formatActiveBuildPlanStageLabel, } from "../../build-plans/package/build-plan-definitions.js";
10
14
  import { reportBlankLine, reportLine, } from "../../build-plans/package/build-plan-helpers.js";
11
15
  import { buildBuildStageExecutionPlan, } from "./build-stage-plan.js";
@@ -20,50 +24,156 @@ function boundedStageValidationAttempts(value) {
20
24
  return 2;
21
25
  return Math.max(1, Math.min(5, Math.trunc(value)));
22
26
  }
27
+ function stageOutputValidationForActiveRun(validation, stageId) {
28
+ if (validation.ok)
29
+ return validation;
30
+ const terminalStateErrors = new Set([
31
+ `Stage "${stageId}" has no finished_at evidence in runtime state.`,
32
+ `Stage "${stageId}" is not marked succeeded in runtime state.`,
33
+ ]);
34
+ const activeOutputErrors = validation.errors.filter((error) => !terminalStateErrors.has(error));
35
+ if (activeOutputErrors.length > 0) {
36
+ return {
37
+ ...validation,
38
+ errors: activeOutputErrors,
39
+ summary: `Stage "${stageId}" failed — ${activeOutputErrors[0]}`,
40
+ };
41
+ }
42
+ return {
43
+ ...validation,
44
+ ok: true,
45
+ errors: [],
46
+ summary: `Stage "${stageId}" output checks passed.`,
47
+ };
48
+ }
23
49
  function stageValidationRetryStatusLines(options) {
24
50
  if (!options.lastFailureSummary || options.attempt <= 1)
25
51
  return [];
26
52
  return [
27
53
  `Previous service validation for this stage failed on attempt ${options.attempt - 1}/${options.maxValidationAttempts}: ${options.lastFailureSummary}`,
28
- "Inspect the existing outputs in this same shell, fix the exact validation failure, then rerun `node runtime/check-stage.mjs` until it prints `VALID:`.",
54
+ "This is a fresh retry shell. Read `runtime/retry-feedback.md`, use previous shells as read-only logs, fix the exact validation failure, then rerun `node runtime/check-stage.mjs` until it prints `VALID:`.",
29
55
  ];
30
56
  }
57
+ function contextGraphRelativePath(contextGraphPath, path) {
58
+ return relative(contextGraphPath, path).replaceAll("\\", "/");
59
+ }
60
+ function writeStageRetryFeedback(options) {
61
+ if (options.attempts.length === 0)
62
+ return;
63
+ writeFileSync(join(options.shellRoot, "runtime", "previous-attempts.json"), `${JSON.stringify({
64
+ kind: "interf-stage-previous-attempts",
65
+ version: 1,
66
+ stage_id: options.stageId,
67
+ attempts: options.attempts,
68
+ }, null, 2)}\n`);
69
+ writeFileSync(join(options.shellRoot, "runtime", "retry-feedback.md"), [
70
+ "# Retry Feedback",
71
+ "",
72
+ "This shell is a fresh retry for the current stage.",
73
+ "Previous attempt shells are preserved as read-only context. Do not mutate them.",
74
+ "Use their prompts, logs, outputs, and validation failures to repair this attempt.",
75
+ "",
76
+ "## Previous Attempts",
77
+ "",
78
+ ...options.attempts.flatMap((attempt) => [
79
+ `### Attempt ${attempt.attempt}`,
80
+ "",
81
+ `- stage_run_id: ${attempt.stage_run_id ?? "unknown"}`,
82
+ `- shell: ${attempt.context_graph_relative_shell_path}`,
83
+ `- status: ${attempt.status}`,
84
+ `- validation: ${attempt.summary}`,
85
+ "",
86
+ ]),
87
+ "## Required Action",
88
+ "",
89
+ "Write the declared outputs in this shell, record `runtime/reviewed-inputs.json`, and run `node runtime/check-stage.mjs` until it reports `VALID:`.",
90
+ "",
91
+ ].join("\n"));
92
+ }
31
93
  export async function runBuildStage(options) {
32
94
  const stageDefinition = options.stageDefinition;
33
95
  const plan = buildBuildStageExecutionPlan(options.contextGraphPath, stageDefinition);
96
+ writeStageExpectedInputs({
97
+ contextGraphPath: options.contextGraphPath,
98
+ stage: stageDefinition,
99
+ });
34
100
  if (options.reportStep !== false) {
35
101
  reportBlankLine(options.reporter);
36
102
  reportLine(options.reporter, `${formatActiveBuildPlanStageLabel(options.contextGraphPath, stageDefinition.id)} (${stageDefinition.description.toLowerCase()})`);
37
103
  }
38
- const shell = createStageExecutionShell(options.contextGraphPath, plan.context.contextGraphName, plan.context.buildPlanId, stageDefinition, plan.contract.artifacts.writes);
104
+ const executor = stageDefinition.contractType === "build-entrypoint"
105
+ ? createNativeEntrypointExecutor()
106
+ : options.executor;
39
107
  const stageEvidenceHarness = supportsStageEvidenceHarness(stageDefinition);
40
108
  const maxValidationAttempts = boundedStageValidationAttempts(options.maxValidationAttempts);
41
- const validateStageOutputsAndEvidence = () => {
109
+ const validateStageOutputsAndEvidence = (shellRoot) => {
42
110
  const shellInputValidation = validateStageExecutionShellInputs({
43
111
  contextGraphPath: options.contextGraphPath,
44
- shellRoot: shell.rootPath,
112
+ shellRoot,
45
113
  stage: stageDefinition,
46
114
  });
47
115
  if (!shellInputValidation.ok)
48
116
  return shellInputValidation;
49
- const outputValidation = validateBuildStage(options.contextGraphPath, stageDefinition.id);
50
- if (!outputValidation.ok || !stageEvidenceHarness)
117
+ const outputValidation = stageOutputValidationForActiveRun(validateBuildStage(options.contextGraphPath, stageDefinition.id), stageDefinition.id);
118
+ if (!outputValidation.ok)
51
119
  return outputValidation;
52
- const reconciliation = reconcileStageEvidence({
120
+ if (stageEvidenceHarness) {
121
+ const reconciliation = reconcileStageEvidence({
122
+ contextGraphPath: options.contextGraphPath,
123
+ shellRoot,
124
+ stage: stageDefinition,
125
+ });
126
+ const evidenceFailure = stageEvidenceAcceptanceFailure(reconciliation);
127
+ if (evidenceFailure) {
128
+ return { ok: false, summary: evidenceFailure };
129
+ }
130
+ }
131
+ const reviewedInputs = persistStageReviewedInputsFromShell({
53
132
  contextGraphPath: options.contextGraphPath,
54
- shellRoot: shell.rootPath,
55
- stage: stageDefinition,
133
+ shellRoot,
134
+ stageId: stageDefinition.id,
56
135
  });
57
- const evidenceFailure = stageEvidenceAcceptanceFailure(reconciliation);
58
- if (evidenceFailure) {
59
- return { ok: false, summary: evidenceFailure };
136
+ if (!reviewedInputs.ok) {
137
+ return {
138
+ ok: false,
139
+ summary: `${outputValidation.summary} ${reviewedInputs.summary}`,
140
+ };
141
+ }
142
+ try {
143
+ const manifest = writeStageManifestFromOutputs({
144
+ contextGraphPath: options.contextGraphPath,
145
+ buildPlanId: plan.context.buildPlanId,
146
+ projectId: plan.context.contextGraphName,
147
+ runId: options.runId ?? null,
148
+ stage: stageDefinition,
149
+ });
150
+ if (!manifest) {
151
+ return { ok: false, summary: `Could not write StageManifest for ${stageDefinition.id}.` };
152
+ }
153
+ return {
154
+ ...outputValidation,
155
+ summary: `${outputValidation.summary} ${reviewedInputs.summary} StageManifest recorded ${manifest.produced.length} produced resource${manifest.produced.length === 1 ? "" : "s"}.`,
156
+ };
157
+ }
158
+ catch (error) {
159
+ return {
160
+ ok: false,
161
+ summary: `Could not write StageManifest for ${stageDefinition.id}: ${error instanceof Error ? error.message : String(error)}`,
162
+ };
60
163
  }
61
- return outputValidation;
62
164
  };
63
165
  let lastResult = { ok: false, code: 1 };
64
166
  let lastFailureSummary = null;
65
- try {
66
- for (let attempt = 1; attempt <= maxValidationAttempts; attempt += 1) {
167
+ const previousAttempts = [];
168
+ for (let attempt = 1; attempt <= maxValidationAttempts; attempt += 1) {
169
+ const shell = createStageExecutionShell(options.contextGraphPath, plan.context.contextGraphName, plan.context.buildPlanId, stageDefinition, plan.contract.artifacts.writes);
170
+ writeStageRetryFeedback({
171
+ contextGraphPath: options.contextGraphPath,
172
+ shellRoot: shell.rootPath,
173
+ stageId: stageDefinition.id,
174
+ attempts: previousAttempts,
175
+ });
176
+ try {
67
177
  if (options.runId && options.events) {
68
178
  await emitRunEvent(options.events, {
69
179
  type: "stage.started",
@@ -76,12 +186,13 @@ export async function runBuildStage(options) {
76
186
  });
77
187
  }
78
188
  const result = await executeValidatedStage({
79
- executor: options.executor,
189
+ executor,
80
190
  contextGraphPath: options.contextGraphPath,
81
191
  executionPath: shell.rootPath,
82
192
  targetName: plan.context.contextGraphName,
83
193
  buildPlan: plan.context.buildPlanId,
84
194
  buildPlanSourcePath: options.contextGraphPath,
195
+ buildRunId: options.runId ?? null,
85
196
  stageDefinition,
86
197
  instructions: plan.instructions,
87
198
  summary: `Executing ${stageDefinition.label.toLowerCase()}.`,
@@ -94,13 +205,15 @@ export async function runBuildStage(options) {
94
205
  "Write `runtime/stage-evidence.json` with source/output refs before DONE; status text alone is not accepted evidence.",
95
206
  ]
96
207
  : []),
208
+ "Read `runtime/expected-inputs.json` before writing outputs.",
209
+ "Write `runtime/reviewed-inputs.json` with one decision per required expected input before DONE.",
97
210
  ...stageValidationRetryStatusLines({ attempt, maxValidationAttempts, lastFailureSummary }),
98
211
  "Emit STATUS: reading declared inputs after you confirm the shell contract and local docs.",
99
- "Emit STATUS: writing declared outputs after the stage starts updating the built Artifacts.",
100
- `Emit DONE: ${stageDefinition.id} complete when the declared outputs and evidence are on disk.`,
212
+ "Emit STATUS: writing declared outputs after the stage starts updating the requested outputs.",
213
+ `Emit DONE: ${stageDefinition.id} complete when the declared outputs, coverage review, and evidence are on disk.`,
101
214
  ],
102
215
  reporter: options.reporter,
103
- completionCheck: () => validateStageOutputsAndEvidence().ok,
216
+ completionCheck: () => validateStageOutputsAndEvidence(shell.rootPath).ok,
104
217
  onStatus: options.runId && options.events
105
218
  ? (line) => {
106
219
  void options.events?.emit({
@@ -117,9 +230,21 @@ export async function runBuildStage(options) {
117
230
  syncWrites: () => syncStageExecutionShellWrites(options.contextGraphPath, shell.rootPath, stageDefinition, plan.contract.artifacts.writes),
118
231
  reconcile: () => reconcileBuildStageRun(options.contextGraphPath, stageDefinition),
119
232
  refreshArtifacts: () => refreshContextGraphArtifacts(options.contextGraphPath, { ensureViewSpec: true }),
120
- validate: validateStageOutputsAndEvidence,
233
+ validate: () => validateStageOutputsAndEvidence(shell.rootPath),
121
234
  });
122
235
  lastResult = result;
236
+ const stageRun = loadExecutionStageLedger(options.contextGraphPath);
237
+ const stageRunId = stageRun?.stage === stageDefinition.id ? stageRun.run_id : null;
238
+ if (stageRun?.stage === stageDefinition.id) {
239
+ recordStageExecutionSessionValidationAttempt({
240
+ contextGraphPath: options.contextGraphPath,
241
+ stageId: stageDefinition.id,
242
+ stageRunId: stageRun.run_id,
243
+ attempt,
244
+ status: result.ok ? "succeeded" : "failed",
245
+ summary: result.summary ?? `${stageDefinition.label} ${result.ok ? "passed" : "failed"}.`,
246
+ });
247
+ }
123
248
  if (result.ok) {
124
249
  if (options.runId && options.events) {
125
250
  await emitRunEvent(options.events, {
@@ -135,6 +260,14 @@ export async function runBuildStage(options) {
135
260
  }
136
261
  lastFailureSummary = result.summary ?? `${stageDefinition.label} failed with code ${result.code}.`;
137
262
  writeFileSync(join(shell.rootPath, "runtime", "last-validation-failure.txt"), `${lastFailureSummary}\n`);
263
+ previousAttempts.push({
264
+ attempt,
265
+ stage_run_id: stageRunId,
266
+ shell_path: shell.rootPath,
267
+ context_graph_relative_shell_path: contextGraphRelativePath(options.contextGraphPath, shell.rootPath),
268
+ status: "failed",
269
+ summary: lastFailureSummary,
270
+ });
138
271
  if (attempt < maxValidationAttempts && options.runId && options.events) {
139
272
  await emitRunEvent(options.events, {
140
273
  type: "log.appended",
@@ -147,19 +280,23 @@ export async function runBuildStage(options) {
147
280
  });
148
281
  }
149
282
  }
150
- if (options.runId && options.events) {
151
- await emitRunEvent(options.events, {
152
- type: "stage.failed",
153
- event_id: createRunEventId("event"),
154
- run_id: options.runId,
155
- timestamp: createRunEventTimestamp(),
156
- stage_id: stageDefinition.id,
157
- error: lastResult.summary ?? `${stageDefinition.label} failed.`,
283
+ finally {
284
+ freezeStageExecutionShell(shell.rootPath);
285
+ markStageExecutionSessionsShellPreserved({
286
+ contextGraphPath: options.contextGraphPath,
287
+ shellRoot: shell.rootPath,
158
288
  });
159
289
  }
160
- return lastResult;
161
290
  }
162
- finally {
163
- freezeStageExecutionShell(shell.rootPath);
291
+ if (options.runId && options.events) {
292
+ await emitRunEvent(options.events, {
293
+ type: "stage.failed",
294
+ event_id: createRunEventId("event"),
295
+ run_id: options.runId,
296
+ timestamp: createRunEventTimestamp(),
297
+ stage_id: stageDefinition.id,
298
+ error: lastResult.summary ?? `${stageDefinition.label} failed.`,
299
+ });
164
300
  }
301
+ return lastResult;
165
302
  }
@@ -1,9 +1,12 @@
1
1
  import { type BuildPlanStageDefinition } from "../../build-plans/package/build-plan-definitions.js";
2
2
  import { type ResolvedBuildPlanId } from "../../build-plans/package/build-plan-definitions.js";
3
+ import type { RuntimeProjectContext } from "./lib/schema.js";
3
4
  export interface BuildStageExecutionDefinition extends BuildPlanStageDefinition {
4
5
  }
5
6
  export declare function resolveBuildContext(contextGraphPath: string): {
6
7
  contextGraphName: string;
8
+ project: RuntimeProjectContext;
9
+ projectIntent: string | null;
7
10
  sourcePath: string;
8
11
  projectDataDir: string;
9
12
  buildPlanId: ResolvedBuildPlanId;
@@ -1,10 +1,34 @@
1
1
  import { getActiveBuildPlan, resolveRequiredBuildPlanFromConfig, } from "../../build-plans/package/build-plan-definitions.js";
2
2
  import { readInterfConfig, resolveSourceFolderPath, resolveSourceControlPath, } from "../../projects/interf-detect.js";
3
+ function normalizedIntent(value) {
4
+ if (typeof value !== "string")
5
+ return null;
6
+ const trimmed = value.trim();
7
+ return trimmed.length > 0 ? trimmed : null;
8
+ }
9
+ function readPersistedProjectIntent(contextGraphPath, config) {
10
+ const parsedIntent = normalizedIntent(config?.intent);
11
+ if (parsedIntent)
12
+ return parsedIntent;
13
+ try {
14
+ return normalizedIntent(getActiveBuildPlan(contextGraphPath).brief?.intent);
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
3
20
  export function resolveBuildContext(contextGraphPath) {
4
21
  const config = readInterfConfig(contextGraphPath);
5
22
  const buildPlanId = resolveRequiredBuildPlanFromConfig(config, `.interf/interf.json for ${contextGraphPath}`);
23
+ const contextGraphName = config?.name ?? "context-graph";
24
+ const projectIntent = readPersistedProjectIntent(contextGraphPath, config);
6
25
  return {
7
- contextGraphName: config?.name ?? "context-graph",
26
+ contextGraphName,
27
+ project: {
28
+ id: contextGraphName,
29
+ intent: projectIntent,
30
+ },
31
+ projectIntent,
8
32
  sourcePath: resolveSourceFolderPath(contextGraphPath, config),
9
33
  projectDataDir: resolveSourceControlPath(contextGraphPath),
10
34
  buildPlanId,