onto-mcp 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/.onto/processes/reconstruct/actionable-ontology-seed-recomposition-design.md +447 -0
  2. package/.onto/processes/reconstruct/foundry-style-ontology-seed-contract.md +934 -0
  3. package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +303 -725
  4. package/.onto/processes/reconstruct/reconstruct-contract-registry.yaml +1645 -0
  5. package/.onto/processes/reconstruct/reconstruct-execution-ux-contract.md +26 -22
  6. package/.onto/processes/reconstruct/source-profile-contract.md +49 -23
  7. package/.onto/processes/reconstruct/source-profiles/code.md +6 -3
  8. package/.onto/processes/reconstruct/source-profiles/database.md +5 -2
  9. package/.onto/processes/reconstruct/source-profiles/document.md +5 -2
  10. package/.onto/processes/reconstruct/source-profiles/spreadsheet.md +5 -4
  11. package/.onto/processes/review/review-execution-ux-contract.md +40 -0
  12. package/.onto/processes/shared/pipeline-execution-ledger-contract.md +26 -10
  13. package/.onto/processes/shared/target-material-kind-contract.md +29 -16
  14. package/AGENTS.md +6 -4
  15. package/README.md +135 -76
  16. package/dist/cli.js +8 -8
  17. package/dist/core-api/reconstruct-api.js +117 -31
  18. package/dist/core-api/review-api.js +47 -0
  19. package/dist/core-runtime/cli/codex-review-unit-executor.js +39 -2
  20. package/dist/core-runtime/cli/complete-review-session.js +2 -2
  21. package/dist/core-runtime/cli/mock-review-unit-executor.js +1 -1
  22. package/dist/core-runtime/cli/review-invoke.js +9 -9
  23. package/dist/core-runtime/cli/run-review-prompt-execution.js +39 -5
  24. package/dist/core-runtime/cli/spawn-watcher.js +266 -47
  25. package/dist/core-runtime/cli/start-review-session.js +3 -3
  26. package/dist/core-runtime/llm/llm-caller.js +11 -0
  27. package/dist/core-runtime/llm/llm-tool-loop.js +2 -0
  28. package/dist/core-runtime/observability/runtime-stream-observation.js +118 -0
  29. package/dist/core-runtime/onboard/cli-host.js +149 -0
  30. package/dist/core-runtime/onboard/host-target.js +22 -0
  31. package/dist/core-runtime/onboard/json-config-host.js +122 -0
  32. package/dist/core-runtime/onboard/path-scan.js +26 -0
  33. package/dist/core-runtime/onboard/prompt.js +51 -0
  34. package/dist/core-runtime/onboard/register.js +207 -0
  35. package/dist/core-runtime/onboard/types.js +27 -0
  36. package/dist/core-runtime/reconstruct/actionable-seed-validation.js +1777 -0
  37. package/dist/core-runtime/reconstruct/artifact-types.js +10 -4
  38. package/dist/core-runtime/reconstruct/contract-registry.js +623 -0
  39. package/dist/core-runtime/reconstruct/domain-id.js +10 -0
  40. package/dist/core-runtime/reconstruct/governing-snapshot.js +716 -0
  41. package/dist/core-runtime/reconstruct/material-profile-validation.js +191 -0
  42. package/dist/core-runtime/reconstruct/materialize-preparation.js +49 -11
  43. package/dist/core-runtime/reconstruct/pipeline-execution-ledger.js +269 -79
  44. package/dist/core-runtime/reconstruct/post-seed-validation.js +1194 -51
  45. package/dist/core-runtime/reconstruct/record.js +104 -20
  46. package/dist/core-runtime/reconstruct/run.js +2107 -413
  47. package/dist/core-runtime/reconstruct/seed-claim-projections.js +268 -0
  48. package/dist/core-runtime/reconstruct/source-profiles.js +93 -4
  49. package/dist/core-runtime/reconstruct/terminal-validation.js +807 -0
  50. package/dist/core-runtime/review/review-invocation-runner.js +4 -4
  51. package/dist/mcp/server.js +110 -38
  52. package/dist/mcp/tool-schemas.js +20 -6
  53. package/package.json +8 -17
  54. package/scripts/onto-review-watch.sh +486 -0
  55. package/scripts/onto-runtime-watch.sh +122 -0
  56. package/scripts/postinstall-hint.js +22 -0
  57. package/.onto/processes/reconstruct/top-level-concept-discovery-contract.md +0 -387
  58. package/dist/core-runtime/cli/bootstrap-review-binding.js +0 -186
  59. package/dist/core-runtime/cli/codex-nested-dispatch.test.js +0 -390
  60. package/dist/core-runtime/cli/codex-nested-teamlead-executor.test.js +0 -335
  61. package/dist/core-runtime/cli/coordinator-helpers.js +0 -583
  62. package/dist/core-runtime/cli/coordinator-state-machine-deliberation.test.js +0 -167
  63. package/dist/core-runtime/cli/coordinator-state-machine.js +0 -794
  64. package/dist/core-runtime/cli/e2e-codex-multi-agent-fixes.test.js +0 -615
  65. package/dist/core-runtime/cli/e2e-start-review-session.test.js +0 -312
  66. package/dist/core-runtime/cli/health.js +0 -44
  67. package/dist/core-runtime/cli/inline-http-review-unit-executor.test.js +0 -567
  68. package/dist/core-runtime/cli/materialize-review-execution-preparation.js +0 -104
  69. package/dist/core-runtime/cli/migrate-session-roots.js +0 -118
  70. package/dist/core-runtime/cli/repo-layout-migration-replace.smoke.test.js +0 -106
  71. package/dist/core-runtime/cli/review-invoke-auto-resolution.test.js +0 -268
  72. package/dist/core-runtime/cli/review-invoke-coordinator-topology.test.js +0 -136
  73. package/dist/core-runtime/cli/review-invoke-resolver-caching.test.js +0 -201
  74. package/dist/core-runtime/cli/review-invoke-topology-dispatch.test.js +0 -192
  75. package/dist/core-runtime/cli/session-root-guard.js +0 -168
  76. package/dist/core-runtime/cli/spawn-watcher.test.js +0 -457
  77. package/dist/core-runtime/cli/strip-wrapping-code-fence.test.js +0 -79
  78. package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.js +0 -412
  79. package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.test.js +0 -351
  80. package/dist/core-runtime/cli/topology-executor-mapping.js +0 -139
  81. package/dist/core-runtime/cli/topology-executor-mapping.test.js +0 -173
  82. package/dist/core-runtime/cli/write-review-interpretation.js +0 -81
  83. package/dist/core-runtime/config/onto-config-cli.js +0 -278
  84. package/dist/core-runtime/config/onto-config-key-path.js +0 -288
  85. package/dist/core-runtime/config/onto-config-key-path.test.js +0 -195
  86. package/dist/core-runtime/config/onto-config-preview.js +0 -108
  87. package/dist/core-runtime/config/onto-config-preview.test.js +0 -132
  88. package/dist/core-runtime/discovery/config-chain.js +0 -118
  89. package/dist/core-runtime/discovery/config-chain.test.js +0 -103
  90. package/dist/core-runtime/discovery/config-profile.js +0 -199
  91. package/dist/core-runtime/discovery/config-profile.test.js +0 -233
  92. package/dist/core-runtime/discovery/host-detection.test.js +0 -186
  93. package/dist/core-runtime/discovery/installation-paths.test.js +0 -65
  94. package/dist/core-runtime/discovery/lens-registry.test.js +0 -81
  95. package/dist/core-runtime/discovery/path-normalization.test.js +0 -22
  96. package/dist/core-runtime/discovery/plugin-path.js +0 -72
  97. package/dist/core-runtime/discovery/plugin-path.test.js +0 -95
  98. package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.js +0 -344
  99. package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.test.js +0 -915
  100. package/dist/core-runtime/evolve/adapters/code-product/compile/compile.js +0 -564
  101. package/dist/core-runtime/evolve/adapters/code-product/compile/compile.test.js +0 -708
  102. package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.js +0 -165
  103. package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.test.js +0 -227
  104. package/dist/core-runtime/evolve/adapters/code-product/validators/validate.js +0 -59
  105. package/dist/core-runtime/evolve/adapters/code-product/validators/validate.test.js +0 -205
  106. package/dist/core-runtime/evolve/adapters/methodology/adapter.js +0 -16
  107. package/dist/core-runtime/evolve/adapters/methodology/adapter.test.js +0 -9
  108. package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.js +0 -298
  109. package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.test.js +0 -70
  110. package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.js +0 -46
  111. package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.test.js +0 -73
  112. package/dist/core-runtime/evolve/adapters/registry.js +0 -47
  113. package/dist/core-runtime/evolve/adapters/registry.test.js +0 -67
  114. package/dist/core-runtime/evolve/cli.js +0 -256
  115. package/dist/core-runtime/evolve/commands/align.js +0 -194
  116. package/dist/core-runtime/evolve/commands/align.test.js +0 -82
  117. package/dist/core-runtime/evolve/commands/apply.js +0 -161
  118. package/dist/core-runtime/evolve/commands/apply.test.js +0 -138
  119. package/dist/core-runtime/evolve/commands/close.js +0 -39
  120. package/dist/core-runtime/evolve/commands/close.test.js +0 -99
  121. package/dist/core-runtime/evolve/commands/defer.js +0 -40
  122. package/dist/core-runtime/evolve/commands/defer.test.js +0 -134
  123. package/dist/core-runtime/evolve/commands/draft.js +0 -323
  124. package/dist/core-runtime/evolve/commands/draft.test.js +0 -178
  125. package/dist/core-runtime/evolve/commands/e2e-evolve-full-cycle.test.js +0 -208
  126. package/dist/core-runtime/evolve/commands/error-messages.js +0 -125
  127. package/dist/core-runtime/evolve/commands/error-messages.test.js +0 -167
  128. package/dist/core-runtime/evolve/commands/propose-align.js +0 -222
  129. package/dist/core-runtime/evolve/commands/propose-align.test.js +0 -136
  130. package/dist/core-runtime/evolve/commands/reconstruct.js +0 -330
  131. package/dist/core-runtime/evolve/commands/reconstruct.test.js +0 -278
  132. package/dist/core-runtime/evolve/commands/shared.js +0 -22
  133. package/dist/core-runtime/evolve/commands/stale-check.js +0 -103
  134. package/dist/core-runtime/evolve/commands/stale-check.test.js +0 -84
  135. package/dist/core-runtime/evolve/commands/start.js +0 -887
  136. package/dist/core-runtime/evolve/commands/start.test.js +0 -396
  137. package/dist/core-runtime/evolve/config/project-config.js +0 -99
  138. package/dist/core-runtime/evolve/config/project-config.test.js +0 -170
  139. package/dist/core-runtime/evolve/renderers/align-packet.js +0 -280
  140. package/dist/core-runtime/evolve/renderers/align-packet.test.js +0 -332
  141. package/dist/core-runtime/evolve/renderers/draft-packet.js +0 -303
  142. package/dist/core-runtime/evolve/renderers/draft-packet.test.js +0 -377
  143. package/dist/core-runtime/evolve/renderers/format.js +0 -5
  144. package/dist/core-runtime/evolve/renderers/scope-md.js +0 -237
  145. package/dist/core-runtime/evolve/renderers/scope-md.test.js +0 -306
  146. package/dist/core-runtime/govern/cli.js +0 -369
  147. package/dist/core-runtime/govern/cli.test.js +0 -314
  148. package/dist/core-runtime/govern/drift-engine.js +0 -103
  149. package/dist/core-runtime/govern/drift-engine.test.js +0 -319
  150. package/dist/core-runtime/govern/promote-principle.js +0 -206
  151. package/dist/core-runtime/govern/promote-principle.test.js +0 -368
  152. package/dist/core-runtime/govern/queue.js +0 -81
  153. package/dist/core-runtime/govern/types.js +0 -16
  154. package/dist/core-runtime/install/cli.js +0 -530
  155. package/dist/core-runtime/install/detect.js +0 -128
  156. package/dist/core-runtime/install/detect.test.js +0 -155
  157. package/dist/core-runtime/install/gitignore-update.js +0 -74
  158. package/dist/core-runtime/install/gitignore-update.test.js +0 -64
  159. package/dist/core-runtime/install/install-integration.test.js +0 -373
  160. package/dist/core-runtime/install/prompts.js +0 -389
  161. package/dist/core-runtime/install/prompts.test.js +0 -293
  162. package/dist/core-runtime/install/types.js +0 -26
  163. package/dist/core-runtime/install/validation.js +0 -295
  164. package/dist/core-runtime/install/validation.test.js +0 -313
  165. package/dist/core-runtime/install/writer.js +0 -254
  166. package/dist/core-runtime/install/writer.test.js +0 -218
  167. package/dist/core-runtime/learning/extractor.js +0 -461
  168. package/dist/core-runtime/learning/feedback.js +0 -179
  169. package/dist/core-runtime/learning/health-report.js +0 -165
  170. package/dist/core-runtime/learning/health-report.test.js +0 -169
  171. package/dist/core-runtime/learning/loader.js +0 -388
  172. package/dist/core-runtime/learning/loader.test.js +0 -102
  173. package/dist/core-runtime/learning/promote/apply-state.js +0 -240
  174. package/dist/core-runtime/learning/promote/audit-obligation.js +0 -195
  175. package/dist/core-runtime/learning/promote/collector.js +0 -432
  176. package/dist/core-runtime/learning/promote/degraded-state.js +0 -125
  177. package/dist/core-runtime/learning/promote/domain-doc-proposer.js +0 -166
  178. package/dist/core-runtime/learning/promote/e2e-promote.test.js +0 -6385
  179. package/dist/core-runtime/learning/promote/health-snapshot.js +0 -150
  180. package/dist/core-runtime/learning/promote/insight-reclassifier.js +0 -544
  181. package/dist/core-runtime/learning/promote/judgment-auditor.js +0 -517
  182. package/dist/core-runtime/learning/promote/panel-reviewer.js +0 -1158
  183. package/dist/core-runtime/learning/promote/promote-executor.js +0 -1675
  184. package/dist/core-runtime/learning/promote/promoter.js +0 -307
  185. package/dist/core-runtime/learning/promote/retirement.js +0 -122
  186. package/dist/core-runtime/learning/promote/types.js +0 -23
  187. package/dist/core-runtime/learning/prompt-sections.js +0 -51
  188. package/dist/core-runtime/learning/shared/artifact-registry-init.js +0 -45
  189. package/dist/core-runtime/learning/shared/artifact-registry.js +0 -254
  190. package/dist/core-runtime/learning/shared/audit-obligation-kernel.js +0 -73
  191. package/dist/core-runtime/learning/shared/audit-state.js +0 -99
  192. package/dist/core-runtime/learning/shared/duplicate-check.js +0 -28
  193. package/dist/core-runtime/learning/shared/llm-caller.js +0 -831
  194. package/dist/core-runtime/learning/shared/llm-caller.test.js +0 -601
  195. package/dist/core-runtime/learning/shared/llm-tool-loop.js +0 -393
  196. package/dist/core-runtime/learning/shared/mode.js +0 -25
  197. package/dist/core-runtime/learning/shared/paths.js +0 -84
  198. package/dist/core-runtime/learning/shared/paths.test.js +0 -79
  199. package/dist/core-runtime/learning/shared/patterns.js +0 -37
  200. package/dist/core-runtime/learning/shared/recoverability.js +0 -355
  201. package/dist/core-runtime/learning/shared/recovery-context.js +0 -374
  202. package/dist/core-runtime/learning/shared/scope.js +0 -1
  203. package/dist/core-runtime/learning/shared/semantic-classifier.js +0 -94
  204. package/dist/core-runtime/learning/shared/specs/apply-execution-state-spec.js +0 -42
  205. package/dist/core-runtime/learning/shared/specs/audit-state-spec.js +0 -37
  206. package/dist/core-runtime/learning/shared/specs/backup-metadata-spec.js +0 -39
  207. package/dist/core-runtime/learning/shared/specs/emergency-log-spec.js +0 -41
  208. package/dist/core-runtime/learning/shared/specs/layout-version-spec.js +0 -38
  209. package/dist/core-runtime/learning/shared/specs/promote-decisions-spec.js +0 -43
  210. package/dist/core-runtime/learning/shared/specs/promote-report-spec.js +0 -113
  211. package/dist/core-runtime/learning/shared/specs/prune-log-spec.js +0 -36
  212. package/dist/core-runtime/learning/shared/specs/recovery-resolution-spec.js +0 -48
  213. package/dist/core-runtime/learning/shared/specs/restore-manifest-spec.js +0 -43
  214. package/dist/core-runtime/learning/shared/specs/spec-helpers.js +0 -64
  215. package/dist/core-runtime/learning/usage-tracker.js +0 -190
  216. package/dist/core-runtime/learning/usage-tracker.test.js +0 -176
  217. package/dist/core-runtime/onboard/detect-review-axes.js +0 -122
  218. package/dist/core-runtime/onboard/detect-review-axes.test.js +0 -127
  219. package/dist/core-runtime/onboard/write-review-block.js +0 -188
  220. package/dist/core-runtime/onboard/write-review-block.test.js +0 -240
  221. package/dist/core-runtime/readers/brownfield-builder.js +0 -150
  222. package/dist/core-runtime/readers/brownfield-builder.test.js +0 -136
  223. package/dist/core-runtime/readers/code-chunk-collector.js +0 -53
  224. package/dist/core-runtime/readers/code-chunk-collector.test.js +0 -136
  225. package/dist/core-runtime/readers/file-utils.js +0 -240
  226. package/dist/core-runtime/readers/file-utils.test.js +0 -146
  227. package/dist/core-runtime/readers/lexicon-citation-check.js +0 -93
  228. package/dist/core-runtime/readers/lexicon-citation-check.test.js +0 -77
  229. package/dist/core-runtime/readers/mcp-figma.js +0 -30
  230. package/dist/core-runtime/readers/mcp-figma.test.js +0 -82
  231. package/dist/core-runtime/readers/mcp-generic.js +0 -31
  232. package/dist/core-runtime/readers/mcp-generic.test.js +0 -76
  233. package/dist/core-runtime/readers/ontology-index.js +0 -148
  234. package/dist/core-runtime/readers/ontology-index.test.js +0 -245
  235. package/dist/core-runtime/readers/ontology-query.js +0 -168
  236. package/dist/core-runtime/readers/ontology-query.test.js +0 -311
  237. package/dist/core-runtime/readers/ontology-resolve.js +0 -48
  238. package/dist/core-runtime/readers/ontology-resolve.test.js +0 -48
  239. package/dist/core-runtime/readers/patterns/index.js +0 -7
  240. package/dist/core-runtime/readers/review-log.js +0 -213
  241. package/dist/core-runtime/readers/review-log.test.js +0 -313
  242. package/dist/core-runtime/readers/scan-local.js +0 -102
  243. package/dist/core-runtime/readers/scan-local.test.js +0 -102
  244. package/dist/core-runtime/readers/scan-tarball.js +0 -121
  245. package/dist/core-runtime/readers/scan-tarball.test.js +0 -283
  246. package/dist/core-runtime/readers/scan-vault.js +0 -34
  247. package/dist/core-runtime/readers/scan-vault.test.js +0 -81
  248. package/dist/core-runtime/readers/types.js +0 -42
  249. package/dist/core-runtime/readers/types.test.js +0 -94
  250. package/dist/core-runtime/readers/viewpoint-collectors.js +0 -229
  251. package/dist/core-runtime/reconstruct/seed-candidate-validation.js +0 -385
  252. package/dist/core-runtime/review/citation-audit.test.js +0 -165
  253. package/dist/core-runtime/review/execution-plan-resolver.js +0 -247
  254. package/dist/core-runtime/review/execution-plan-resolver.test.js +0 -243
  255. package/dist/core-runtime/review/execution-topology-resolver-axis-first.test.js +0 -246
  256. package/dist/core-runtime/review/execution-topology-resolver.js +0 -401
  257. package/dist/core-runtime/review/execution-topology-resolver.test.js +0 -315
  258. package/dist/core-runtime/review/inline-context-embedder.test.js +0 -154
  259. package/dist/core-runtime/review/legacy-mode-policy.js +0 -88
  260. package/dist/core-runtime/review/materializers-effort-persist.test.js +0 -79
  261. package/dist/core-runtime/review/ontology-path-classifier.js +0 -179
  262. package/dist/core-runtime/review/ontology-path-classifier.test.js +0 -216
  263. package/dist/core-runtime/review/packet-boundary-policy.test.js +0 -107
  264. package/dist/core-runtime/review/participating-lens-paths.test.js +0 -73
  265. package/dist/core-runtime/review/review-config-legacy-translate.js +0 -244
  266. package/dist/core-runtime/review/review-config-legacy-translate.test.js +0 -161
  267. package/dist/core-runtime/review/review-config-validator.js +0 -289
  268. package/dist/core-runtime/review/review-config-validator.test.js +0 -236
  269. package/dist/core-runtime/review/shape-pipeline-audit.test.js +0 -311
  270. package/dist/core-runtime/review/shape-to-topology-id.js +0 -117
  271. package/dist/core-runtime/review/shape-to-topology-id.test.js +0 -132
  272. package/dist/core-runtime/review/topology-shape-derivation.js +0 -155
  273. package/dist/core-runtime/review/topology-shape-derivation.test.js +0 -195
  274. package/dist/core-runtime/scope-runtime/constants.js +0 -12
  275. package/dist/core-runtime/scope-runtime/constraint-pool.js +0 -166
  276. package/dist/core-runtime/scope-runtime/constraint-pool.test.js +0 -674
  277. package/dist/core-runtime/scope-runtime/domain-validation-log.js +0 -135
  278. package/dist/core-runtime/scope-runtime/domain-validation-log.test.js +0 -156
  279. package/dist/core-runtime/scope-runtime/eval-persistence.js +0 -65
  280. package/dist/core-runtime/scope-runtime/eval-persistence.test.js +0 -84
  281. package/dist/core-runtime/scope-runtime/event-pipeline.js +0 -64
  282. package/dist/core-runtime/scope-runtime/event-pipeline.test.js +0 -450
  283. package/dist/core-runtime/scope-runtime/event-store.js +0 -39
  284. package/dist/core-runtime/scope-runtime/event-store.test.js +0 -95
  285. package/dist/core-runtime/scope-runtime/gate-guard.js +0 -348
  286. package/dist/core-runtime/scope-runtime/gate-guard.test.js +0 -1047
  287. package/dist/core-runtime/scope-runtime/hash.js +0 -4
  288. package/dist/core-runtime/scope-runtime/hash.test.js +0 -33
  289. package/dist/core-runtime/scope-runtime/id.js +0 -4
  290. package/dist/core-runtime/scope-runtime/id.test.js +0 -17
  291. package/dist/core-runtime/scope-runtime/reducer.js +0 -297
  292. package/dist/core-runtime/scope-runtime/reducer.test.js +0 -759
  293. package/dist/core-runtime/scope-runtime/scope-manager.js +0 -161
  294. package/dist/core-runtime/scope-runtime/state-machine.js +0 -309
  295. package/dist/core-runtime/scope-runtime/state-machine.test.js +0 -704
  296. package/dist/core-runtime/scope-runtime/types.js +0 -116
  297. package/dist/core-runtime/scope-runtime/types.test.js +0 -69
  298. package/dist/core-runtime/translate/render-for-user.js +0 -169
  299. package/dist/core-runtime/translate/render-for-user.test.js +0 -122
  300. package/dist/providers/capability-contract.js +0 -1
@@ -1,3 +1,4 @@
1
+ import crypto from "node:crypto";
1
2
  import fs from "node:fs/promises";
2
3
  import path from "node:path";
3
4
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
@@ -5,29 +6,224 @@ import { callLlm } from "../llm/llm-caller.js";
5
6
  import { loadCoreLensRegistry } from "../discovery/lens-registry.js";
6
7
  import { writeSourceObservationDirectiveValidationArtifact } from "./directive-validation.js";
7
8
  import { materializeReconstructPreparationArtifacts } from "./materialize-preparation.js";
8
- import { validateFinalOutputProvenance, writeClaimRealizationMapValidationArtifact, writeCompetencyQuestionAssessmentValidationArtifact, writeCompetencyQuestionsValidationArtifact, writeFailureClassificationValidationArtifact, writeRevisionProposalValidationArtifact, writeSeedConfirmationValidationArtifact, } from "./post-seed-validation.js";
9
+ import { writeTargetMaterialProfileValidationArtifact } from "./material-profile-validation.js";
10
+ import { ANSWER_STATUSES, validateFinalOutputProvenance, writeClaimRealizationMapValidationForOntologySeedArtifact, writeCompetencyQuestionAssessmentValidationArtifact, writeCompetencyQuestionsValidationForOntologySeedArtifact, writeFailureClassificationValidationArtifact, writeRevisionProposalValidationArtifact, writeSeedConfirmationValidationForOntologySeedArtifact, } from "./post-seed-validation.js";
9
11
  import { assembleReconstructRecord } from "./record.js";
10
- import { writeSeedCandidateValidationArtifact } from "./seed-candidate-validation.js";
12
+ import { writeActionableOntologySeedValidationArtifact, writeCandidateDispositionValidationArtifact, } from "./actionable-seed-validation.js";
13
+ import { loadReconstructContractRegistry, } from "./contract-registry.js";
14
+ import { buildReconstructRunGoverningSnapshot } from "./governing-snapshot.js";
15
+ import { writeHandoffDecisionValidationArtifact, writeReconstructRunManifestValidationArtifact, } from "./terminal-validation.js";
16
+ import { ontologySeedAnswerabilitySummary, ontologySeedClaimProjections, ontologySeedExcludedClaimIds, } from "./seed-claim-projections.js";
11
17
  function isoNow() {
12
18
  return new Date().toISOString();
13
19
  }
20
+ function isRecord(value) {
21
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22
+ }
23
+ function stableJson(value) {
24
+ if (Array.isArray(value)) {
25
+ return `[${value.map(stableJson).join(",")}]`;
26
+ }
27
+ if (isRecord(value)) {
28
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`;
29
+ }
30
+ return JSON.stringify(value);
31
+ }
32
+ function sha256Text(text) {
33
+ return crypto.createHash("sha256").update(text).digest("hex");
34
+ }
35
+ async function sha256File(filePath) {
36
+ return crypto.createHash("sha256").update(await fs.readFile(filePath)).digest("hex");
37
+ }
14
38
  async function writeYamlDocument(filePath, value) {
15
39
  await fs.mkdir(path.dirname(filePath), { recursive: true });
16
40
  await fs.writeFile(filePath, stringifyYaml(value), "utf8");
17
41
  }
42
+ function validationViolationSummary(violations) {
43
+ if (!Array.isArray(violations) || violations.length === 0) {
44
+ return "no violation details recorded";
45
+ }
46
+ return violations.slice(0, 8).map((violation, index) => {
47
+ if (violation === null || typeof violation !== "object" || Array.isArray(violation)) {
48
+ return `${index + 1}. ${String(violation)}`;
49
+ }
50
+ const record = violation;
51
+ const code = typeof record.code === "string" ? record.code : "unknown";
52
+ const message = typeof record.message === "string" ? record.message : JSON.stringify(record);
53
+ const subject = typeof record.subject_id === "string"
54
+ ? record.subject_id
55
+ : typeof record.claim_id === "string"
56
+ ? record.claim_id
57
+ : typeof record.candidate_id === "string"
58
+ ? record.candidate_id
59
+ : null;
60
+ return `${index + 1}. ${code}${subject ? ` (${subject})` : ""}: ${message}`;
61
+ }).join("; ");
62
+ }
63
+ function validationDetailSummary(validation) {
64
+ if (Array.isArray(validation.violations) && validation.violations.length > 0) {
65
+ return validationViolationSummary(validation.violations);
66
+ }
67
+ if (Array.isArray(validation.rejected_frontier_refs) &&
68
+ validation.rejected_frontier_refs.length > 0) {
69
+ return validation.rejected_frontier_refs.slice(0, 8).map((item, index) => {
70
+ if (item === null || typeof item !== "object" || Array.isArray(item)) {
71
+ return `${index + 1}. ${String(item)}`;
72
+ }
73
+ const record = item;
74
+ return `${index + 1}. ${String(record.reason ?? "rejected_frontier_ref")}: ${String(record.source_ref ?? record.frontier_ref_id ?? "unknown")}`;
75
+ }).join("; ");
76
+ }
77
+ return "no validation details recorded";
78
+ }
79
+ function assertRuntimeValidationValid(args) {
80
+ if (args.validation.validation_status === "valid")
81
+ return;
82
+ throw new Error(`${args.artifactName} validation failed at ${args.artifactRef}: ${validationDetailSummary(args.validation)}`);
83
+ }
18
84
  async function readYamlDocument(filePath) {
19
85
  return parseYaml(await fs.readFile(filePath, "utf8"));
20
86
  }
21
- function allClaims(seedCandidate) {
22
- return [
23
- seedCandidate.purpose,
24
- ...seedCandidate.non_goals,
25
- ...seedCandidate.entities,
26
- ...seedCandidate.relations,
27
- ...seedCandidate.actions,
28
- ...seedCandidate.properties,
29
- ...seedCandidate.rules,
30
- ];
87
+ function isMissingFile(error) {
88
+ return (typeof error === "object" &&
89
+ error !== null &&
90
+ "code" in error &&
91
+ error.code === "ENOENT");
92
+ }
93
+ async function readYamlDocumentIfPresent(filePath) {
94
+ try {
95
+ return await readYamlDocument(filePath);
96
+ }
97
+ catch (error) {
98
+ if (isMissingFile(error))
99
+ return null;
100
+ throw error;
101
+ }
102
+ }
103
+ async function readTextIfPresent(filePath) {
104
+ try {
105
+ return await fs.readFile(filePath, "utf8");
106
+ }
107
+ catch (error) {
108
+ if (isMissingFile(error))
109
+ return null;
110
+ throw error;
111
+ }
112
+ }
113
+ async function exists(filePath) {
114
+ try {
115
+ await fs.access(filePath);
116
+ return true;
117
+ }
118
+ catch (error) {
119
+ if (isMissingFile(error))
120
+ return false;
121
+ throw error;
122
+ }
123
+ }
124
+ function authoredArtifactProvenancePath(filePath) {
125
+ return `${filePath}.reuse-provenance.yaml`;
126
+ }
127
+ function compatibilityHash(compatibility) {
128
+ return sha256Text(stableJson(compatibility));
129
+ }
130
+ function authoredArtifactCompatibility(args) {
131
+ return {
132
+ session_id: args.sessionId,
133
+ intent_sha256: sha256Text(args.intent),
134
+ target_refs_sha256: sha256Text(stableJson(args.targetRefs.map((ref) => path.resolve(ref)).sort())),
135
+ target_material_profile_sha256: sha256Text(stableJson({
136
+ target_refs: args.targetMaterialProfile.target_refs.map((ref) => path.resolve(ref)).sort(),
137
+ target_material_kind: args.targetMaterialProfile.target_material_kind,
138
+ target_material_kind_candidates: args.targetMaterialProfile.target_material_kind_candidates,
139
+ support_status: args.targetMaterialProfile.support_status,
140
+ selected_source_profiles: args.targetMaterialProfile.selected_source_profiles,
141
+ detection: args.targetMaterialProfile.detection.per_ref.map((item) => ({
142
+ ref: path.resolve(item.ref),
143
+ exists: item.exists,
144
+ kind: item.kind,
145
+ confidence: item.confidence,
146
+ })),
147
+ })),
148
+ source_inventory_sha256: sha256Text(stableJson(args.sourceInventory.inventory_units.map((unit) => ({
149
+ ref: path.resolve(unit.ref),
150
+ exists: unit.exists,
151
+ target_material_kind: unit.target_material_kind,
152
+ inventory_unit: unit.inventory_unit,
153
+ profile_ref: unit.profile_ref ? path.resolve(unit.profile_ref) : null,
154
+ scan_status: unit.scan_status,
155
+ skip_reason: unit.skip_reason,
156
+ })))),
157
+ source_observations_sha256: sha256Text(stableJson({
158
+ observations: args.sourceObservations.observations.map((observation) => ({
159
+ observation_id: observation.observation_id,
160
+ target_material_kind: observation.target_material_kind,
161
+ adapter_id: observation.adapter_id,
162
+ source_ref: path.resolve(observation.source_ref),
163
+ location: path.resolve(observation.location),
164
+ structural_data: {
165
+ path_kind: observation.structural_data.path_kind ?? null,
166
+ size_bytes: observation.structural_data.size_bytes ?? null,
167
+ line_count: observation.structural_data.line_count ?? null,
168
+ char_count: observation.structural_data.char_count ?? null,
169
+ content_sha256: observation.structural_data.content_sha256 ?? null,
170
+ excerpt_truncated: observation.structural_data.excerpt_truncated ?? null,
171
+ },
172
+ })),
173
+ skipped_refs: args.sourceObservations.skipped_refs.map((skipped) => ({
174
+ ref: path.resolve(skipped.ref),
175
+ target_material_kind: skipped.target_material_kind,
176
+ reason: skipped.reason,
177
+ })),
178
+ })),
179
+ governing_snapshot_sha256: sha256Text(stableJson(args.governingSnapshot)),
180
+ requested_domain_ids: args.governingSnapshot.requested_domain_ids,
181
+ semantic_author_realization: args.semanticAuthorRealization,
182
+ confirmation_provider_realization: args.confirmationProviderRealization,
183
+ directive_author_id: args.directiveAuthor.authorId,
184
+ confirmation_provider_id: args.confirmationProvider.providerId,
185
+ };
186
+ }
187
+ async function writeFreshAuthoredYamlDocument(filePath, artifactName, create, options = {}) {
188
+ const currentCompatibilityHash = options.compatibility
189
+ ? compatibilityHash(options.compatibility)
190
+ : null;
191
+ if (await exists(filePath)) {
192
+ if (options.reuseExisting) {
193
+ const provenancePath = authoredArtifactProvenancePath(filePath);
194
+ const provenance = await readYamlDocumentIfPresent(provenancePath);
195
+ if (!provenance) {
196
+ throw new Error(`${artifactName} already exists at ${filePath}, but ${provenancePath} is missing; explicit resume cannot prove authored artifact compatibility.`);
197
+ }
198
+ if (currentCompatibilityHash &&
199
+ provenance.compatibility_hash !== currentCompatibilityHash) {
200
+ throw new Error(`${artifactName} resume provenance mismatch at ${provenancePath}; existing authored artifact was produced for compatibility_hash=${provenance.compatibility_hash}, current compatibility_hash=${currentCompatibilityHash}.`);
201
+ }
202
+ const currentArtifactSha256 = await sha256File(filePath);
203
+ if (provenance.artifact_sha256 !== currentArtifactSha256) {
204
+ throw new Error(`${artifactName} artifact hash mismatch at ${filePath}; expected ${provenance.artifact_sha256}, got ${currentArtifactSha256}.`);
205
+ }
206
+ return readYamlDocument(filePath);
207
+ }
208
+ throw new Error(`${artifactName} already exists at ${filePath}; explicit resume or supersession is required before rewriting authored semantic artifacts.`);
209
+ }
210
+ const created = await create();
211
+ await writeYamlDocument(filePath, created);
212
+ if (options.compatibility && currentCompatibilityHash) {
213
+ await writeYamlDocument(authoredArtifactProvenancePath(filePath), {
214
+ schema_version: "1",
215
+ artifact_name: artifactName,
216
+ artifact_ref: filePath,
217
+ artifact_sha256: await sha256File(filePath),
218
+ created_at: isoNow(),
219
+ compatibility_hash: currentCompatibilityHash,
220
+ compatibility: options.compatibility,
221
+ });
222
+ }
223
+ return created;
224
+ }
225
+ function ontologyClaims(ontologySeed) {
226
+ return ontologySeedClaimProjections(ontologySeed);
31
227
  }
32
228
  function compactStatement(statement) {
33
229
  const limit = 240;
@@ -36,19 +232,9 @@ function compactStatement(statement) {
36
232
  function sourceBasename(sourceRef) {
37
233
  return path.basename(sourceRef) || sourceRef;
38
234
  }
39
- function summarizeSeedClaimsForConfirmation(seedCandidate) {
40
- const groups = [
41
- ["purpose", [seedCandidate.purpose]],
42
- ["non_goal", seedCandidate.non_goals],
43
- ["entity", seedCandidate.entities],
44
- ["relation", seedCandidate.relations],
45
- ["action", seedCandidate.actions],
46
- ["property", seedCandidate.properties],
47
- ["rule", seedCandidate.rules],
48
- ];
49
- return groups.flatMap(([claimKind, claims]) => claims.map((claim) => ({
235
+ function claimRealizationTargets(claims) {
236
+ return claims.map((claim) => ({
50
237
  claim_id: claim.claim_id,
51
- claim_kind: claimKind,
52
238
  name: claim.name,
53
239
  statement: compactStatement(claim.statement),
54
240
  evidence_observation_ids: [
@@ -57,7 +243,20 @@ function summarizeSeedClaimsForConfirmation(seedCandidate) {
57
243
  evidence_source_basenames: [
58
244
  ...new Set(claim.evidence_refs.map((ref) => sourceBasename(ref.source_ref))),
59
245
  ],
60
- })));
246
+ }));
247
+ }
248
+ function answerabilitySummary(ontologySeed) {
249
+ return ontologySeedAnswerabilitySummary(ontologySeed);
250
+ }
251
+ function ontologySeedSummaryLines(ontologySeed) {
252
+ const claims = ontologyClaims(ontologySeed);
253
+ const summary = ontologySeedAnswerabilitySummary(ontologySeed);
254
+ return [
255
+ `- Ontology seed projected claims: ${claims.length}`,
256
+ `- Coverage axes: ${summary.declared_question_count}`,
257
+ `- Action types: ${summary.supported_action_count + summary.unsupported_action_count}`,
258
+ `- Limited action types: ${summary.unsupported_action_count}`,
259
+ ];
61
260
  }
62
261
  function countBy(values, selected) {
63
262
  const counts = Object.fromEntries(values.map((value) => [value, 0]));
@@ -66,6 +265,15 @@ function countBy(values, selected) {
66
265
  }
67
266
  return counts;
68
267
  }
268
+ function stopDecisionAllowedDecisions(input) {
269
+ const materialFailureCount = input.failureClassification.failures.filter((failure) => failure.materiality === "material").length;
270
+ const hasUnresolvedWork = input.metrics.unresolved_question_count > 0 ||
271
+ materialFailureCount > 0 ||
272
+ input.metrics.confirmation_state_counts.rejected > 0 ||
273
+ input.metrics.confirmation_state_counts.partial > 0 ||
274
+ input.metrics.confirmation_state_counts.deferred > 0;
275
+ return hasUnresolvedWork ? ["continue", "ask_user"] : ["stop", "continue", "ask_user"];
276
+ }
69
277
  const CLAIM_REALIZATION_STANCES = [
70
278
  "observed_runtime_behavior",
71
279
  "declared_design_intent",
@@ -74,13 +282,6 @@ const CLAIM_REALIZATION_STANCES = [
74
282
  "deferred_or_non_goal",
75
283
  "unknown",
76
284
  ];
77
- const ANSWER_STATUSES = [
78
- "answered",
79
- "partially_answered",
80
- "not_answered",
81
- "needs_evidence",
82
- "out_of_scope",
83
- ];
84
285
  const FAILURE_KINDS = [
85
286
  "unsupported_claim",
86
287
  "unanswered_question",
@@ -112,10 +313,26 @@ function requireFirstObservation(sourceObservations) {
112
313
  }
113
314
  return observation;
114
315
  }
316
+ function assertSemanticAuthoringHasObservedEvidence(args) {
317
+ if (args.sourceObservations.observations.length > 0)
318
+ return;
319
+ const skipped = args.sourceInventory.inventory_units
320
+ .filter((unit) => unit.scan_status === "skipped")
321
+ .map((unit) => `${path.basename(unit.ref)}:${unit.target_material_kind}:${unit.skip_reason ?? "skipped"}`);
322
+ throw new Error([
323
+ "reconstruct semantic authoring requires at least one runtime source observation",
324
+ `target_material_kind=${args.targetMaterialProfile.target_material_kind}`,
325
+ `support_status=${args.targetMaterialProfile.support_status}`,
326
+ `unsupported_reason=${args.targetMaterialProfile.unsupported_reason ?? "none"}`,
327
+ `skipped_refs=${skipped.join(", ") || "none"}`,
328
+ ].join("; "));
329
+ }
115
330
  function calculateMetrics(args) {
116
331
  const validationStatus = {
332
+ target_material_profile: args.targetMaterialProfileValidation.validation_status,
117
333
  source_observation_directive: args.sourceObservationDirectiveValidation.validation_status,
118
- seed_candidate: args.seedCandidateValidation.validation_status,
334
+ candidate_disposition: args.candidateDispositionValidation.validation_status,
335
+ ontology_seed: args.ontologySeedValidation.validation_status,
119
336
  seed_confirmation: args.seedConfirmation.confirmation_status,
120
337
  claim_realization: args.claimRealizationMapValidation.validation_status,
121
338
  seed_confirmation_validation: args.seedConfirmationValidation.validation_status,
@@ -129,7 +346,9 @@ function calculateMetrics(args) {
129
346
  const deferredClaimCount = args.seedConfirmationValidation.deferred_claim_ids.length;
130
347
  const invalidGateCount = [
131
348
  validationStatus.source_observation_directive,
132
- validationStatus.seed_candidate,
349
+ validationStatus.target_material_profile,
350
+ validationStatus.candidate_disposition,
351
+ validationStatus.ontology_seed,
133
352
  validationStatus.claim_realization,
134
353
  validationStatus.seed_confirmation_validation,
135
354
  validationStatus.competency_questions,
@@ -139,20 +358,22 @@ function calculateMetrics(args) {
139
358
  ].filter((status) => status !== "valid").length;
140
359
  const unresolvedQuestionCount = rejectedClaimCount +
141
360
  partialClaimCount +
361
+ args.sourceObservations.skipped_refs.length +
142
362
  args.failureClassificationValidation.material_failure_count +
143
363
  args.competencyQuestions.open_questions.length +
144
364
  invalidGateCount;
145
365
  const competencyQuestionCount = args.competencyQuestions.questions.length;
146
366
  const passedQuestions = Math.max(0, competencyQuestionCount - unresolvedQuestionCount);
147
367
  const answerStatusCounts = args.competencyQuestionAssessmentValidation.answer_status_counts;
368
+ const projectedOntologyClaims = ontologyClaims(args.ontologySeed);
148
369
  return {
149
370
  schema_version: "1",
150
371
  session_id: args.sessionId,
151
372
  created_at: isoNow(),
152
373
  source_observation_count: args.sourceObservations.observations.length,
153
374
  selected_observation_count: args.sourceObservationDirectiveValidation.selected_observation_count,
154
- semantic_claim_count: args.seedCandidateValidation.semantic_claim_count,
155
- evidence_ref_count: args.seedCandidateValidation.evidence_ref_count,
375
+ semantic_claim_count: projectedOntologyClaims.length,
376
+ evidence_ref_count: args.ontologySeedValidation.evidence_ref_count,
156
377
  confirmed_claim_count: args.seedConfirmationValidation.accepted_claim_ids.length,
157
378
  rejected_claim_count: rejectedClaimCount,
158
379
  partial_claim_count: partialClaimCount,
@@ -161,8 +382,9 @@ function calculateMetrics(args) {
161
382
  competency_question_assessment_count: args.competencyQuestionAssessmentValidation.assessment_count,
162
383
  unresolved_question_count: unresolvedQuestionCount,
163
384
  deferred_count: deferredClaimCount +
164
- answerStatusCounts.out_of_scope +
385
+ answerStatusCounts.deferred +
165
386
  args.failureClassificationValidation.failure_kind_counts.deferred_scope,
387
+ answerability_summary: answerabilitySummary(args.ontologySeed),
166
388
  claim_realization_stance_counts: args.claimRealizationMapValidation.stance_counts,
167
389
  confirmation_state_counts: {
168
390
  accepted: args.seedConfirmationValidation.accepted_claim_ids.length,
@@ -182,6 +404,7 @@ function calculateMetrics(args) {
182
404
  function artifactRefsWithDefaults(args) {
183
405
  return {
184
406
  target_material_profile: args.refs.target_material_profile ?? null,
407
+ target_material_profile_validation: args.refs.target_material_profile_validation ?? null,
185
408
  source_inventory: args.refs.source_inventory ?? null,
186
409
  initial_source_frontier: args.refs.initial_source_frontier ?? null,
187
410
  source_observations: args.refs.source_observations ?? null,
@@ -191,10 +414,11 @@ function artifactRefsWithDefaults(args) {
191
414
  exploration_synthesis: args.refs.exploration_synthesis ?? null,
192
415
  source_frontier: args.refs.source_frontier ?? null,
193
416
  source_frontier_validation: args.refs.source_frontier_validation ?? null,
194
- domain_context_selection: args.refs.domain_context_selection ?? null,
195
- domain_context_selection_validation: args.refs.domain_context_selection_validation ?? null,
196
- seed_candidate: args.refs.seed_candidate ?? null,
197
- seed_candidate_validation: args.refs.seed_candidate_validation ?? null,
417
+ candidate_inventory: args.refs.candidate_inventory ?? null,
418
+ candidate_disposition: args.refs.candidate_disposition ?? null,
419
+ candidate_disposition_validation: args.refs.candidate_disposition_validation ?? null,
420
+ ontology_seed: args.refs.ontology_seed ?? null,
421
+ ontology_seed_validation: args.refs.ontology_seed_validation ?? null,
198
422
  claim_realization_map: args.refs.claim_realization_map ?? null,
199
423
  claim_realization_map_validation: args.refs.claim_realization_map_validation ?? null,
200
424
  seed_confirmation: args.refs.seed_confirmation ?? null,
@@ -209,7 +433,11 @@ function artifactRefsWithDefaults(args) {
209
433
  revision_proposal_validation: args.refs.revision_proposal_validation ?? null,
210
434
  reconstruct_metrics: args.refs.reconstruct_metrics ?? null,
211
435
  stop_decision: args.refs.stop_decision ?? null,
436
+ pre_handoff_run_manifest_validation: args.refs.pre_handoff_run_manifest_validation ?? null,
437
+ post_publication_run_manifest_validation: args.refs.post_publication_run_manifest_validation ?? null,
438
+ handoff_decision_validation: args.refs.handoff_decision_validation ?? null,
212
439
  final_output: args.refs.final_output ?? null,
440
+ final_output_provenance_validation: args.refs.final_output_provenance_validation ?? null,
213
441
  reconstruct_run_manifest: args.refs.reconstruct_run_manifest ?? null,
214
442
  };
215
443
  }
@@ -255,6 +483,13 @@ function confirmationProviderPerformer(confirmationProvider) {
255
483
  };
256
484
  }
257
485
  function createRunManifest(args) {
486
+ const artifactRefs = args.terminalArtifactsCompleted
487
+ ? args.artifactRefs
488
+ : {
489
+ ...args.artifactRefs,
490
+ handoff_decision_validation: null,
491
+ final_output: null,
492
+ };
258
493
  return {
259
494
  schema_version: "1",
260
495
  session_id: args.sessionId,
@@ -279,12 +514,16 @@ function createRunManifest(args) {
279
514
  : "Runtime completed the live integral reconstruct path for the produced and explicitly skipped artifacts.",
280
515
  },
281
516
  artifact_refs: {
282
- ...args.artifactRefs,
283
- reconstruct_record: args.reconstructRecordPath,
517
+ ...artifactRefs,
518
+ reconstruct_record: args.terminalArtifactsCompleted
519
+ ? args.reconstructRecordPath
520
+ : null,
284
521
  },
522
+ governing_snapshot: args.governingSnapshot,
285
523
  happy_path_scope: {
286
524
  implemented_artifacts: [
287
525
  "target_material_profile",
526
+ "target_material_profile_validation",
288
527
  "source_inventory",
289
528
  "initial_source_frontier",
290
529
  "source_observations",
@@ -294,8 +533,11 @@ function createRunManifest(args) {
294
533
  "exploration_synthesis",
295
534
  "source_frontier",
296
535
  "source_frontier_validation",
297
- "seed_candidate",
298
- "seed_candidate_validation",
536
+ "candidate_inventory",
537
+ "candidate_disposition",
538
+ "candidate_disposition_validation",
539
+ "ontology_seed",
540
+ "ontology_seed_validation",
299
541
  "claim_realization_map",
300
542
  "claim_realization_map_validation",
301
543
  "seed_confirmation",
@@ -310,21 +552,31 @@ function createRunManifest(args) {
310
552
  "revision_proposal_validation",
311
553
  "reconstruct_metrics",
312
554
  "stop_decision",
313
- "final_output",
555
+ "pre_handoff_run_manifest_validation",
556
+ "handoff_decision_validation",
314
557
  "reconstruct_run_manifest",
315
- "reconstruct_record",
316
- ],
317
- deferred_artifacts: [
318
- "domain_context_selection",
319
- "domain_context_selection_validation",
558
+ ...(args.terminalArtifactsCompleted
559
+ ? [
560
+ "final_output",
561
+ "final_output_provenance_validation",
562
+ "post_publication_run_manifest_validation",
563
+ "reconstruct_record",
564
+ ]
565
+ : []),
320
566
  ],
321
- deferred_reason: "The current runner does not yet select domain context; downstream authority is narrowed to source-grounded reconstruction without selected domain-document alignment.",
567
+ deferred_artifacts: [],
568
+ deferred_reason: args.governingSnapshot.requested_domain_ids.length > 0
569
+ ? "Domain competency admission is recorded in governing_snapshot; no separate domain competency selection artifact is active."
570
+ : "No reconstruct artifacts are deferred by the active runtime contract.",
322
571
  },
323
572
  steps: [
324
573
  completedStep("invocation_binding", "runtime", runtimePerformer(), []),
325
574
  completedStep("target_material_profile", "runtime", runtimePerformer(), [
326
575
  args.artifactRefs.target_material_profile,
327
576
  ].filter((ref) => ref !== null)),
577
+ completedStep("target_material_profile_validation", "runtime", runtimePerformer(), [
578
+ args.artifactRefs.target_material_profile_validation,
579
+ ].filter((ref) => ref !== null)),
328
580
  completedStep("source_inventory", "runtime", runtimePerformer(), [
329
581
  args.artifactRefs.source_inventory,
330
582
  ].filter((ref) => ref !== null)),
@@ -348,12 +600,17 @@ function createRunManifest(args) {
348
600
  completedStep("source_frontier_validation", "runtime", runtimePerformer(), [
349
601
  args.artifactRefs.source_frontier_validation,
350
602
  ].filter((ref) => ref !== null)),
351
- skippedStep("domain_context_selection", "host_llm", directiveAuthorPerformer(args.directiveAuthor), "domain context selection is not implemented in this direct-call runner.", "Final output cannot claim selected domain-document alignment."),
352
- skippedStep("domain_context_selection_validation", "runtime", runtimePerformer(), "domain context selection was skipped.", "Runtime cannot validate domain snapshot identity for this run."),
353
- completedStep("seed_candidate", "host_llm", directiveAuthorPerformer(args.directiveAuthor), [args.artifactRefs.seed_candidate]
603
+ completedStep("candidate_inventory", "host_llm", directiveAuthorPerformer(args.directiveAuthor), [args.artifactRefs.candidate_inventory]
354
604
  .filter((ref) => ref !== null)),
355
- completedStep("seed_candidate_validation", "runtime", runtimePerformer(), [
356
- args.artifactRefs.seed_candidate_validation,
605
+ completedStep("candidate_disposition", "host_llm", directiveAuthorPerformer(args.directiveAuthor), [args.artifactRefs.candidate_disposition]
606
+ .filter((ref) => ref !== null)),
607
+ completedStep("candidate_disposition_validation", "runtime", runtimePerformer(), [
608
+ args.artifactRefs.candidate_disposition_validation,
609
+ ].filter((ref) => ref !== null)),
610
+ completedStep("ontology_seed", "host_llm", directiveAuthorPerformer(args.directiveAuthor), [args.artifactRefs.ontology_seed]
611
+ .filter((ref) => ref !== null)),
612
+ completedStep("ontology_seed_validation", "runtime", runtimePerformer(), [
613
+ args.artifactRefs.ontology_seed_validation,
357
614
  ].filter((ref) => ref !== null)),
358
615
  completedStep("claim_realization", "host_llm", directiveAuthorPerformer(args.directiveAuthor), [args.artifactRefs.claim_realization_map]
359
616
  .filter((ref) => ref !== null)),
@@ -390,11 +647,29 @@ function createRunManifest(args) {
390
647
  ].filter((ref) => ref !== null)),
391
648
  completedStep("stop_decision", "host_llm", directiveAuthorPerformer(args.directiveAuthor), [args.artifactRefs.stop_decision]
392
649
  .filter((ref) => ref !== null)),
393
- completedStep("final_output", "host_llm", directiveAuthorPerformer(args.directiveAuthor), [args.artifactRefs.final_output]
394
- .filter((ref) => ref !== null)),
395
- completedStep("record_assembly", "runtime", runtimePerformer(), [
396
- args.reconstructRecordPath,
397
- ]),
650
+ completedStep("pre_handoff_run_manifest_validation", "runtime", runtimePerformer(), [
651
+ args.artifactRefs.pre_handoff_run_manifest_validation,
652
+ ].filter((ref) => ref !== null)),
653
+ args.terminalArtifactsCompleted
654
+ ? completedStep("handoff_decision_validation", "runtime", runtimePerformer(), [
655
+ args.artifactRefs.handoff_decision_validation,
656
+ ].filter((ref) => ref !== null))
657
+ : skippedStep("handoff_decision_validation", "runtime", runtimePerformer(), "handoff-decision-validation.yaml is emitted after pre-handoff manifest validation.", "Pre-handoff manifest validation must not certify future handoff validation."),
658
+ args.terminalArtifactsCompleted
659
+ ? completedStep("final_output", "host_llm", directiveAuthorPerformer(args.directiveAuthor), [args.artifactRefs.final_output]
660
+ .filter((ref) => ref !== null))
661
+ : skippedStep("final_output", "host_llm", directiveAuthorPerformer(args.directiveAuthor), "final-output.md is emitted after handoff validation.", "Pre-handoff manifest validation must not certify future final output."),
662
+ args.terminalArtifactsCompleted
663
+ ? completedStep("final_output_provenance_validation", "runtime", runtimePerformer(), [args.artifactRefs.final_output_provenance_validation]
664
+ .filter((ref) => ref !== null))
665
+ : skippedStep("final_output_provenance_validation", "runtime", runtimePerformer(), "final-output-provenance-validation.yaml is emitted after final output.", "Pre-handoff manifest validation must not certify future final-output provenance."),
666
+ args.terminalArtifactsCompleted
667
+ ? completedStep("record_assembly", "runtime", runtimePerformer(), [args.reconstructRecordPath])
668
+ : skippedStep("record_assembly", "runtime", runtimePerformer(), "reconstruct-record.yaml is assembled after final output provenance validation.", "Pre-handoff manifest validation must not certify future record assembly."),
669
+ args.terminalArtifactsCompleted
670
+ ? completedStep("post_publication_run_manifest_validation", "runtime", runtimePerformer(), [args.artifactRefs.post_publication_run_manifest_validation]
671
+ .filter((ref) => ref !== null))
672
+ : skippedStep("post_publication_run_manifest_validation", "runtime", runtimePerformer(), "post-publication run-manifest validation is emitted after final output and record refs exist.", "Pre-handoff manifest validation must not certify future post-publication audit."),
398
673
  ],
399
674
  runtime_boundary: {
400
675
  semantic_generation: "not_performed",
@@ -454,6 +729,59 @@ function stringArray(value, fieldName) {
454
729
  throw new Error(`${fieldName} must be an array.`);
455
730
  return value.map((item, index) => stringValue(item, `${fieldName}[${index}]`));
456
731
  }
732
+ function downstreamEffectForAnswerStatus(answerStatus) {
733
+ switch (answerStatus) {
734
+ case "answerable":
735
+ return "ready";
736
+ case "partially_answerable":
737
+ return "limited";
738
+ case "deferred":
739
+ return "blocked_by_missing_source_or_confirmation";
740
+ case "not_applicable":
741
+ return "not_applicable";
742
+ case "unsupported":
743
+ case "contradicted":
744
+ return "blocks_handoff";
745
+ }
746
+ }
747
+ function recordValue(value, fieldName) {
748
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
749
+ throw new Error(`${fieldName} must be an object.`);
750
+ }
751
+ return value;
752
+ }
753
+ function enumString(value, allowed, fieldName) {
754
+ const raw = stringValue(value, fieldName);
755
+ if (!allowed.includes(raw)) {
756
+ throw new Error(`${fieldName} must be one of: ${allowed.join(", ")}.`);
757
+ }
758
+ return raw;
759
+ }
760
+ function enumChoices(values) {
761
+ return values.join("|");
762
+ }
763
+ const ACTIONABLE_ONTOLOGY_SEED_JSON_SHAPE = [
764
+ "Return exactly one JSON object with these root fields:",
765
+ "seed_identity={schema_version,seed_id,title,target_refs,generated_at,authoring_profile}",
766
+ "purpose={declared_purpose,intended_decisions,intended_actions,non_goals,evidence_refs}",
767
+ "decision_context={principal_user,downstream_use,decision_boundary,risk_notes}",
768
+ "conceptual_frame={concepts:[{concept_id,name,definition,purpose_role,evidence_refs,confidence}],associations:[{association_id,source_concept_id,target_concept_id,association_kind,statement,evidence_refs}]}",
769
+ "semantic_layer={object_types:[{object_type_id,name,object_kind,description,primary_key:{property_id,name,value_type,evidence_refs},properties:[{property_id,name,value_type,nullable,description,constraints,evidence_refs}],backing_source_refs,evidence_refs,status}],link_types:[{link_type_id,source_object_type_id,target_object_type_id,cardinality,business_meaning,evidence_refs}],value_types:[{value_type_id,name,representation,constraints,evidence_refs}],constraints:[{constraint_id,target_ref,constraint_kind,statement,evidence_refs}]}",
770
+ "kinetic_layer={action_types:[{action_type_id,name,description,actor_type_ids,target_object_type_ids,affected_object_type_ids,parameters:[{parameter_id,name,value_source,value_type,required}],preconditions:[{precondition_id,statement,evidence_refs}],postconditions:[{postcondition_id,statement,evidence_refs}],side_effects:[{side_effect_id,statement,failure_behavior,evidence_refs}],writeback_behavior:{writes,writeback_source_refs,rationale},evidence_refs,status}],functions:[{function_id,name,input_type_refs,return_type_ref,purity,evidence_refs}],workflows:[{workflow_id,name,ordered_action_type_ids,trigger,terminal_state,evidence_refs}]}",
771
+ "dynamic_layer={actor_types:[{actor_type_id,name,actor_kind,role_refs,description,evidence_refs}],actor_roles:[{role_id,name,holder_actor_type_ids,authority_scope_refs,evidence_refs}],permission_policies:[{policy_id,actor_type_id,action_type_id,object_type_id,permission_kind,condition,evidence_refs}],state_models:[{state_model_id,object_type_id,states,transitions:[{transition_id,from_state,to_state,action_type_id,evidence_refs}]}],lifecycle_rules:[{rule_id,target_ref,statement,evidence_refs}]}",
772
+ "data_binding_layer={source_bindings:[{binding_id,seed_ref,source_ref,binding_kind,statement,evidence_refs}],read_models:[{read_model_id,name,object_type_ids,source_refs,transformation_summary,evidence_refs}],writebacks:[{writeback_id,action_type_id,target_source_refs,write_mode,evidence_refs}],provenance_bindings:[{provenance_id,seed_ref,source_ref,author_or_system,timestamp_ref,evidence_refs}]}",
773
+ "validation_layer={question_authority_ref:{authority_scope,projection_policy},coverage_axes,unsupported_question_candidates:[{candidate_id,question,unsupported_reason,needed_source_or_confirmation}],runtime_validation_refs:[{authority_scope,projection_policy}]}",
774
+ "candidate_disposition_authority_ref={authority_scope,projection_policy}",
775
+ "ontology_handoff={readiness_claim,classification_mapping,entity_identity_mapping,instance_assertion_mapping,terminology_mapping,relation_type_mapping,constraint_mapping,modularity_boundary,reasoning_or_formalism_profile,application_context_mapping,metadata_mapping,provenance_mapping,change_tracking_mapping,competency_scope_mapping,alignment_mapping,modeling_concern_applicability,reference_standard_mapping,pattern_catalog_mapping,query_access_contract,visualization_contract,graph_exploration_contract,graph_connectivity,limitation_refs}",
776
+ "source_authority={evidence_scope,permission_scope,trust_boundary,instruction_authority,external_content_handling,included_source_refs,excluded_source_refs,restricted_source_refs,source_gaps,rationale}",
777
+ "handoff_limitations=[{limitation_id,limitation_kind,description,affected_refs,missing_source_refs,mitigation_or_next_action,evidence_refs}]",
778
+ "Every evidence_refs item must be an object copied from an observed source with observation_id,target_material_kind,source_ref,location. Do not use a bare observation id string in evidence_refs.",
779
+ "Use the exact *_id key names above. Do not use id, claim_id, or candidate_id as a substitute for concept_id, object_type_id, actor_type_id, action_type_id, workflow_id, limitation_id, etc.",
780
+ "data_binding_layer.source_bindings.source_ref, read_models.source_refs, writebacks.target_source_refs, provenance_bindings.source_ref, source_authority.included_source_refs, and source_authority.excluded_source_refs must use only observed_source_refs.",
781
+ "Do not put runtime artifact refs such as source-observations.yaml, candidate-disposition.yaml, validation files, or final-output.md into source_ref fields. Runtime artifacts may be named in timestamp_ref, authority_ref, rationale, or mapping text only.",
782
+ "Skipped or unsupported material refs must not appear in included_source_refs or excluded_source_refs; record them in source_authority.source_gaps or handoff_limitations.missing_source_refs instead.",
783
+ "Every semantic_layer.object_types[].object_type_id must be covered by at least one of source_bindings.seed_ref, read_models.object_type_ids, provenance_bindings.seed_ref, or handoff_limitations.affected_refs.",
784
+ ].join("\n");
457
785
  function evidenceRefByObservationId(sourceObservations) {
458
786
  return new Map(sourceObservations.observations.map((observation) => [
459
787
  observation.observation_id,
@@ -474,37 +802,545 @@ function evidenceRefsFromIds(args) {
474
802
  }
475
803
  return refs;
476
804
  }
477
- function claimFromLlm(args) {
478
- const claimId = optionalString(args.raw.claim_id) ?? args.fallbackId;
805
+ function candidateKindIds(registry) {
806
+ return registry.candidate_kind_registry.map((record) => record.candidate_kind_id);
807
+ }
808
+ function candidateDispositionIds(registry) {
809
+ return registry.candidate_disposition_registry.map((record) => record.disposition_id);
810
+ }
811
+ function coverageAxisIds(registry) {
812
+ return registry.coverage_axis_registry.map((record) => record.axis_id);
813
+ }
814
+ function facetIds(records) {
815
+ return records.map((record) => record.facet_id);
816
+ }
817
+ function modelingConcernIds(registry) {
818
+ return registry.modeling_concern_applicability_registry.map((record) => record.concern_id);
819
+ }
820
+ function proofContractIds(records) {
821
+ return records.map((record) => record.contract_ref_id);
822
+ }
823
+ function candidateInventoryItemFromLlm(args) {
824
+ const fieldName = `candidates[${args.index}]`;
825
+ const candidateId = stringValue(args.raw.candidate_id, `${fieldName}.candidate_id`);
479
826
  return {
480
- claim_id: claimId,
481
- name: stringValue(args.raw.name, `${args.fieldName}.name`),
482
- statement: stringValue(args.raw.statement, `${args.fieldName}.statement`),
827
+ candidate_id: candidateId,
828
+ candidate_kind: stringValue(args.raw.candidate_kind, `${fieldName}.candidate_kind`),
829
+ name: stringValue(args.raw.name, `${fieldName}.name`),
830
+ description: stringValue(args.raw.description, `${fieldName}.description`),
831
+ salience: enumString(args.raw.salience, ["high", "medium", "low"], `${fieldName}.salience`),
483
832
  evidence_refs: evidenceRefsFromIds({
484
- observationIds: stringArray(args.raw.evidence_observation_ids, `${args.fieldName}.evidence_observation_ids`),
833
+ observationIds: stringArray(args.raw.evidence_observation_ids, `${fieldName}.evidence_observation_ids`),
485
834
  sourceObservations: args.sourceObservations,
486
- fieldName: `${args.fieldName}.evidence_observation_ids`,
835
+ fieldName: `${fieldName}.evidence_observation_ids`,
487
836
  }),
488
837
  };
489
838
  }
490
- function claimsFromLlm(args) {
491
- return records(args.value ?? [], args.prefix).map((raw, index) => claimFromLlm({
492
- raw,
493
- fallbackId: `${args.prefix}-${index + 1}`,
494
- sourceObservations: args.sourceObservations,
495
- fieldName: `${args.prefix}[${index}]`,
496
- }));
839
+ function candidateDispositionItemFromLlm(args) {
840
+ const fieldName = `dispositions[${args.index}]`;
841
+ return {
842
+ candidate_id: stringValue(args.raw.candidate_id, `${fieldName}.candidate_id`),
843
+ disposition_id: stringValue(args.raw.disposition_id, `${fieldName}.disposition_id`),
844
+ target_seed_refs: stringArray(args.raw.target_seed_refs, `${fieldName}.target_seed_refs`),
845
+ rationale: stringValue(args.raw.rationale, `${fieldName}.rationale`),
846
+ evidence_refs: evidenceRefsFromIds({
847
+ observationIds: stringArray(args.raw.evidence_observation_ids, `${fieldName}.evidence_observation_ids`),
848
+ sourceObservations: args.sourceObservations,
849
+ fieldName: `${fieldName}.evidence_observation_ids`,
850
+ }),
851
+ };
497
852
  }
498
- function observationPromptPayload(sourceObservations) {
499
- return sourceObservations.observations.map((observation) => ({
853
+ function firstEvidenceRef(sourceObservations) {
854
+ return evidenceRefFromObservation(requireFirstObservation(sourceObservations));
855
+ }
856
+ function mockCandidateInventory(args) {
857
+ const evidence = firstEvidenceRef(args.sourceObservations);
858
+ return {
859
+ schema_version: "1",
860
+ session_id: args.sessionId,
861
+ created_at: isoNow(),
862
+ source_observations_ref: "source-observations.yaml",
863
+ candidates: [
864
+ {
865
+ candidate_id: "candidate-observed-material",
866
+ candidate_kind: "object",
867
+ name: "Observed Material",
868
+ description: "The observed source material represented as a seed object.",
869
+ salience: "high",
870
+ evidence_refs: [evidence],
871
+ },
872
+ {
873
+ candidate_id: "candidate-reconstruct-user",
874
+ candidate_kind: "actor",
875
+ name: "Reconstruct User",
876
+ description: "The user who will consume the reconstructed seed.",
877
+ salience: "high",
878
+ evidence_refs: [evidence],
879
+ },
880
+ {
881
+ candidate_id: "candidate-explain-seed",
882
+ candidate_kind: "action",
883
+ name: "Explain Seed",
884
+ description: "The action of explaining the observed material through the seed.",
885
+ salience: "high",
886
+ evidence_refs: [evidence],
887
+ },
888
+ {
889
+ candidate_id: "candidate-observed-source",
890
+ candidate_kind: "data_source",
891
+ name: "Observed Source",
892
+ description: "The runtime-observed source ref used as evidence.",
893
+ salience: "high",
894
+ evidence_refs: [evidence],
895
+ },
896
+ ],
897
+ directive_author: {
898
+ owner: "mock",
899
+ author_id: args.authorId,
900
+ },
901
+ };
902
+ }
903
+ function mockCandidateDisposition(args) {
904
+ const targetByCandidateId = new Map([
905
+ ["candidate-observed-material", "object-observed-material"],
906
+ ["candidate-reconstruct-user", "actor-reconstruct-user"],
907
+ ["candidate-explain-seed", "action-explain-seed"],
908
+ ["candidate-observed-source", "binding-observed-source"],
909
+ ]);
910
+ return {
911
+ schema_version: "1",
912
+ session_id: args.sessionId,
913
+ created_at: isoNow(),
914
+ candidate_inventory_ref: "candidate-inventory.yaml",
915
+ dispositions: args.candidateInventory.candidates.map((candidate) => ({
916
+ candidate_id: candidate.candidate_id,
917
+ disposition_id: "promoted_to_seed_layer",
918
+ target_seed_refs: [
919
+ targetByCandidateId.get(candidate.candidate_id) ?? `seed-ref-${candidate.candidate_id}`,
920
+ ],
921
+ rationale: `${candidate.name} is promoted into the mock actionable seed surface.`,
922
+ evidence_refs: candidate.evidence_refs,
923
+ })),
924
+ directive_author: {
925
+ owner: "mock",
926
+ author_id: args.authorId,
927
+ },
928
+ };
929
+ }
930
+ function mockOntologyHandoff() {
931
+ return {
932
+ readiness_claim: "ready",
933
+ classification_mapping: {
934
+ ontology_scope_kind: "application_ontology_seed",
935
+ classification_axis_policy: "object, actor, action, and data-binding layers",
936
+ classification_level_axis_refs: [
937
+ "object-observed-material",
938
+ "actor-reconstruct-user",
939
+ "action-explain-seed",
940
+ ],
941
+ inheritance_model: "flat_seed_layer",
942
+ mece_status: "not_asserted",
943
+ seed_refs: [
944
+ "object-observed-material",
945
+ "actor-reconstruct-user",
946
+ "action-explain-seed",
947
+ ],
948
+ limitation_refs: [],
949
+ },
950
+ entity_identity_mapping: {
951
+ entity_id_policy: "stable seed ids",
952
+ uri_or_iri_policy: "not_assigned",
953
+ canonical_identifier_refs: [
954
+ "object-observed-material",
955
+ "actor-reconstruct-user",
956
+ "action-explain-seed",
957
+ ],
958
+ alias_identifier_refs: [],
959
+ primitive_vs_defined_status: "defined_by_seed_record",
960
+ definition_criteria_refs: ["object-observed-material"],
961
+ limitation_refs: [],
962
+ },
963
+ instance_assertion_mapping: {
964
+ instance_availability_status: "present",
965
+ instance_refs: ["object-observed-material"],
966
+ example_assertion_refs: ["action-explain-seed"],
967
+ abox_assertion_refs: [],
968
+ limitation_refs: [],
969
+ },
970
+ terminology_mapping: {
971
+ canonical_label_policy: "seed names are canonical labels",
972
+ alias_policy: "aliases are not asserted",
973
+ hidden_label_policy: "hidden labels are not asserted",
974
+ homonym_policy: "not assessed in mock path",
975
+ multilingual_label_policy: "single-language mock labels",
976
+ language_tag_policy: "und",
977
+ limitation_refs: [],
978
+ },
979
+ relation_type_mapping: {
980
+ relation_type_refs: [],
981
+ formal_relation_semantics: "No link types are asserted; action bindings express operational relations.",
982
+ domain_range_declaration_refs: ["action-explain-seed"],
983
+ relation_property_constraint_refs: [],
984
+ unsupported_relation_candidates: [],
985
+ limitation_refs: [],
986
+ },
987
+ constraint_mapping: {
988
+ constraint_refs: [],
989
+ tbox_constraint_refs: [],
990
+ abox_assertion_constraint_refs: [],
991
+ shape_or_validation_constraint_refs: ["runtime_seed_validator"],
992
+ policy_constraint_refs: ["policy-explain-seed"],
993
+ unsupported_constraint_candidates: [],
994
+ limitation_refs: [],
995
+ },
996
+ modularity_boundary: {
997
+ module_candidates: ["observed_material_seed_module"],
998
+ import_or_reuse_refs: [],
999
+ limitation_refs: [],
1000
+ },
1001
+ reasoning_or_formalism_profile: {
1002
+ representation_formalism: "informal_actionable_graph",
1003
+ vocabulary_systems: ["custom_controlled_vocabulary"],
1004
+ validation_formalisms: ["custom_runtime_validator"],
1005
+ ontology_type: "application_ontology",
1006
+ owl_profile: "not_applicable",
1007
+ alignment_posture: "custom_alignment",
1008
+ reasoning_expectations: ["runtime validation gates preserve seed truth"],
1009
+ validation_expectations: ["seed validator and handoff validator must pass"],
1010
+ limitation_refs: [],
1011
+ },
1012
+ application_context_mapping: {
1013
+ application_context_refs: ["object-observed-material"],
1014
+ actor_or_surface_refs: ["actor-reconstruct-user", "object-observed-material"],
1015
+ limitation_refs: [],
1016
+ },
1017
+ metadata_mapping: {
1018
+ descriptive_metadata_refs: ["seed_identity"],
1019
+ bibliographic_metadata_refs: [],
1020
+ resource_metadata_refs: ["source-observations.yaml"],
1021
+ limitation_refs: [],
1022
+ },
1023
+ provenance_mapping: {
1024
+ provenance_binding_refs: ["provenance-observed-source"],
1025
+ evidence_scope_refs: ["source-observations.yaml"],
1026
+ limitation_refs: [],
1027
+ },
1028
+ change_tracking_mapping: {
1029
+ state_model_refs: [],
1030
+ lifecycle_rule_refs: [],
1031
+ migration_or_versioning_refs: ["seed_identity.generated_at"],
1032
+ limitation_refs: [],
1033
+ },
1034
+ competency_scope_mapping: {
1035
+ expected_coverage_axes: [
1036
+ "purpose",
1037
+ "semantic_layer",
1038
+ "kinetic_layer",
1039
+ "dynamic_layer",
1040
+ "data_binding_layer",
1041
+ "ontology_handoff",
1042
+ ],
1043
+ required_handoff_axes: ["classification", "entity_identity", "provenance"],
1044
+ unsupported_axes: [],
1045
+ limitation_refs: [],
1046
+ },
1047
+ alignment_mapping: {
1048
+ external_vocab_or_domain_refs: [],
1049
+ mapped_seed_refs: [
1050
+ "object-observed-material",
1051
+ "actor-reconstruct-user",
1052
+ "action-explain-seed",
1053
+ ],
1054
+ limitation_refs: [],
1055
+ },
1056
+ modeling_concern_applicability: {
1057
+ rows: [
1058
+ {
1059
+ concern_id: "instance_assertion_coverage",
1060
+ applies: false,
1061
+ applicability_predicate_ref: "mock path has no separate instance catalog",
1062
+ trace_refs: ["object-observed-material"],
1063
+ limitation_refs: [],
1064
+ },
1065
+ ],
1066
+ },
1067
+ reference_standard_mapping: {
1068
+ standard_refs: ["foundry_style_seed_contract"],
1069
+ mapped_concern_refs: ["classification", "entity_identity"],
1070
+ limitation_refs: [],
1071
+ },
1072
+ pattern_catalog_mapping: {
1073
+ pattern_catalog_refs: ["actionable_seed_pattern"],
1074
+ mapped_concern_refs: ["purpose", "ontology_handoff"],
1075
+ limitation_refs: [],
1076
+ },
1077
+ query_access_contract: { applies: "not_applicable", limitation_refs: [] },
1078
+ visualization_contract: { applies: "not_applicable", limitation_refs: [] },
1079
+ graph_exploration_contract: { applies: "not_applicable", limitation_refs: [] },
1080
+ graph_connectivity: {
1081
+ connected_seed_refs: [
1082
+ "object-observed-material",
1083
+ "actor-reconstruct-user",
1084
+ "action-explain-seed",
1085
+ ],
1086
+ isolated_seed_refs: [],
1087
+ isolation_rationale_refs: [],
1088
+ },
1089
+ limitation_refs: [],
1090
+ };
1091
+ }
1092
+ function mockActionableOntologySeed(args) {
1093
+ const evidence = firstEvidenceRef(args.sourceObservations);
1094
+ const sourceRef = evidence.source_ref;
1095
+ return {
1096
+ seed_identity: {
1097
+ schema_version: "1",
1098
+ seed_id: `seed-${args.sessionId}`,
1099
+ title: "Mock Actionable Ontology Seed",
1100
+ target_refs: args.targetMaterialProfile.target_refs,
1101
+ generated_at: isoNow(),
1102
+ authoring_profile: args.authorId,
1103
+ },
1104
+ purpose: {
1105
+ declared_purpose: args.intent,
1106
+ intended_decisions: ["Decide whether the observed material can be handed off as a bounded seed."],
1107
+ intended_actions: ["Explain the observed material from validated evidence."],
1108
+ non_goals: ["Full formal ontology generation is outside this mock path."],
1109
+ evidence_refs: [evidence],
1110
+ },
1111
+ decision_context: {
1112
+ principal_user: "Reconstruct user",
1113
+ downstream_use: "bounded_seed_handoff",
1114
+ decision_boundary: "Observed runtime evidence only.",
1115
+ risk_notes: [],
1116
+ },
1117
+ conceptual_frame: {
1118
+ concepts: [
1119
+ {
1120
+ concept_id: "concept-observed-material",
1121
+ name: "Observed Material",
1122
+ definition: "The source material observed by reconstruct runtime.",
1123
+ purpose_role: "orients the seed around the declared purpose",
1124
+ evidence_refs: [evidence],
1125
+ confidence: "confirmed",
1126
+ },
1127
+ ],
1128
+ associations: [],
1129
+ },
1130
+ semantic_layer: {
1131
+ object_types: [
1132
+ {
1133
+ object_type_id: "object-observed-material",
1134
+ name: "Observed Material",
1135
+ object_kind: "document",
1136
+ description: "A bounded object representing the observed source material.",
1137
+ primary_key: {
1138
+ property_id: "property-observed-material-ref",
1139
+ name: "source ref",
1140
+ value_type: "string",
1141
+ evidence_refs: [evidence],
1142
+ },
1143
+ properties: [],
1144
+ backing_source_refs: [sourceRef],
1145
+ evidence_refs: [evidence],
1146
+ status: "confirmed",
1147
+ },
1148
+ ],
1149
+ link_types: [],
1150
+ value_types: [],
1151
+ constraints: [],
1152
+ },
1153
+ kinetic_layer: {
1154
+ action_types: [
1155
+ {
1156
+ action_type_id: "action-explain-seed",
1157
+ name: "Explain Seed",
1158
+ description: "Explain the observed material as a bounded seed.",
1159
+ actor_type_ids: ["actor-reconstruct-user"],
1160
+ target_object_type_ids: ["object-observed-material"],
1161
+ affected_object_type_ids: [],
1162
+ parameters: [],
1163
+ preconditions: [],
1164
+ postconditions: [],
1165
+ side_effects: [],
1166
+ writeback_behavior: {
1167
+ writes: false,
1168
+ writeback_source_refs: [],
1169
+ rationale: "The action is explanatory and does not write source material.",
1170
+ },
1171
+ evidence_refs: [evidence],
1172
+ status: "confirmed",
1173
+ },
1174
+ ],
1175
+ functions: [],
1176
+ workflows: [
1177
+ {
1178
+ workflow_id: "workflow-explain-seed",
1179
+ name: "Explain Seed Workflow",
1180
+ ordered_action_type_ids: ["action-explain-seed"],
1181
+ trigger: "User requests reconstruct output.",
1182
+ terminal_state: "Bounded seed explanation is available.",
1183
+ evidence_refs: [evidence],
1184
+ },
1185
+ ],
1186
+ },
1187
+ dynamic_layer: {
1188
+ actor_types: [
1189
+ {
1190
+ actor_type_id: "actor-reconstruct-user",
1191
+ name: "Reconstruct User",
1192
+ actor_kind: "human_user",
1193
+ role_refs: ["role-seed-reader"],
1194
+ description: "Human user consuming the reconstructed seed.",
1195
+ evidence_refs: [evidence],
1196
+ },
1197
+ ],
1198
+ actor_roles: [
1199
+ {
1200
+ role_id: "role-seed-reader",
1201
+ name: "Seed Reader",
1202
+ holder_actor_type_ids: ["actor-reconstruct-user"],
1203
+ authority_scope_refs: [],
1204
+ evidence_refs: [evidence],
1205
+ },
1206
+ ],
1207
+ permission_policies: [
1208
+ {
1209
+ policy_id: "policy-explain-seed",
1210
+ actor_type_id: "actor-reconstruct-user",
1211
+ action_type_id: "action-explain-seed",
1212
+ object_type_id: "object-observed-material",
1213
+ permission_kind: "allowed",
1214
+ condition: "Within the reconstruct session boundary.",
1215
+ evidence_refs: [evidence],
1216
+ },
1217
+ ],
1218
+ state_models: [],
1219
+ lifecycle_rules: [],
1220
+ },
1221
+ data_binding_layer: {
1222
+ source_bindings: [
1223
+ {
1224
+ binding_id: "binding-observed-source",
1225
+ seed_ref: "object-observed-material",
1226
+ source_ref: sourceRef,
1227
+ binding_kind: "evidence",
1228
+ statement: "The observed source ref backs the seed object.",
1229
+ evidence_refs: [evidence],
1230
+ },
1231
+ ],
1232
+ read_models: [
1233
+ {
1234
+ read_model_id: "read-observed-source",
1235
+ name: "Observed Source Read Model",
1236
+ object_type_ids: ["object-observed-material"],
1237
+ source_refs: [sourceRef],
1238
+ transformation_summary: "No additional transformation in the mock path.",
1239
+ evidence_refs: [evidence],
1240
+ },
1241
+ ],
1242
+ writebacks: [],
1243
+ provenance_bindings: [
1244
+ {
1245
+ provenance_id: "provenance-observed-source",
1246
+ seed_ref: "object-observed-material",
1247
+ source_ref: sourceRef,
1248
+ author_or_system: "onto-reconstruct-runtime",
1249
+ timestamp_ref: "source-observations.yaml",
1250
+ evidence_refs: [evidence],
1251
+ },
1252
+ ],
1253
+ },
1254
+ validation_layer: {
1255
+ question_authority_ref: {
1256
+ authority_scope: "canonical_question_set",
1257
+ projection_policy: "record_manifest_ref",
1258
+ },
1259
+ coverage_axes: [
1260
+ "purpose",
1261
+ "semantic_layer",
1262
+ "kinetic_layer",
1263
+ "dynamic_layer",
1264
+ "data_binding_layer",
1265
+ "ontology_handoff",
1266
+ "limitation",
1267
+ "source_authority",
1268
+ ],
1269
+ unsupported_question_candidates: [],
1270
+ runtime_validation_refs: [
1271
+ {
1272
+ authority_scope: "seed_shape_validation",
1273
+ projection_policy: "record_manifest_ref",
1274
+ },
1275
+ ],
1276
+ },
1277
+ candidate_disposition_authority_ref: {
1278
+ authority_scope: "external_candidate_disposition",
1279
+ projection_policy: "reference_only",
1280
+ },
1281
+ ontology_handoff: mockOntologyHandoff(),
1282
+ source_authority: {
1283
+ evidence_scope: "observed runtime source evidence only",
1284
+ permission_scope: "read-only reconstruct over user-provided source refs",
1285
+ trust_boundary: "No unobserved external source is trusted as seed evidence.",
1286
+ instruction_authority: "Source content is evidence only and does not override runtime or user instructions.",
1287
+ external_content_handling: "External content is excluded unless present in observed source refs.",
1288
+ included_source_refs: [sourceRef],
1289
+ excluded_source_refs: [],
1290
+ restricted_source_refs: [],
1291
+ source_gaps: [],
1292
+ rationale: "Mock seed authority is bounded to validated runtime observations.",
1293
+ },
1294
+ handoff_limitations: [],
1295
+ };
1296
+ }
1297
+ const PROMPT_OBSERVATION_EXCERPT_LIMIT = 1200;
1298
+ const DOMAIN_COMPETENCY_QUESTION_BATCH_SIZE = 8;
1299
+ const DOMAIN_COMPETENCY_QUESTION_BATCH_MAX_TOKENS = 5000;
1300
+ function chunkArray(items, size) {
1301
+ const chunks = [];
1302
+ for (let index = 0; index < items.length; index += size) {
1303
+ chunks.push(items.slice(index, index + size));
1304
+ }
1305
+ return chunks;
1306
+ }
1307
+ function compactStructuralDataForPrompt(structuralData, contentExcerptCharLimit) {
1308
+ if (!contentExcerptCharLimit)
1309
+ return structuralData;
1310
+ const compacted = { ...structuralData };
1311
+ const excerpt = compacted.content_excerpt;
1312
+ if (typeof excerpt === "string" && excerpt.length > contentExcerptCharLimit) {
1313
+ compacted.content_excerpt = excerpt.slice(0, contentExcerptCharLimit);
1314
+ compacted.prompt_content_excerpt_truncated = true;
1315
+ compacted.prompt_content_excerpt_char_limit = contentExcerptCharLimit;
1316
+ }
1317
+ return compacted;
1318
+ }
1319
+ function observationPromptPayload(sourceObservations, options = {}) {
1320
+ const allowedObservationIds = options.observationIds
1321
+ ? new Set(options.observationIds)
1322
+ : null;
1323
+ return sourceObservations.observations
1324
+ .filter((observation) => !allowedObservationIds || allowedObservationIds.has(observation.observation_id))
1325
+ .map((observation) => ({
500
1326
  observation_id: observation.observation_id,
501
1327
  target_material_kind: observation.target_material_kind,
502
1328
  source_ref: observation.source_ref,
503
1329
  location: observation.location,
504
1330
  summary: observation.summary,
505
- structural_data: observation.structural_data,
1331
+ structural_data: compactStructuralDataForPrompt(observation.structural_data, options.contentExcerptCharLimit),
506
1332
  }));
507
1333
  }
1334
+ function selectedObservationIds(directive) {
1335
+ return [
1336
+ ...new Set(directive.selected_observations.map((observation) => observation.observation_id)),
1337
+ ];
1338
+ }
1339
+ function claimEvidenceObservationIds(claims) {
1340
+ return [
1341
+ ...new Set(claims.flatMap((claim) => claim.evidence_refs.map((ref) => ref.observation_id))),
1342
+ ];
1343
+ }
508
1344
  function lensJudgmentPromptPayload(lensJudgments) {
509
1345
  return lensJudgments.map((judgment) => ({
510
1346
  lens_id: judgment.lens_id,
@@ -543,6 +1379,7 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
543
1379
  owner: "host_llm",
544
1380
  async writeSourceObservationDirective(input) {
545
1381
  requireFirstObservation(input.sourceObservations);
1382
+ const availableObservationIds = input.sourceObservations.observations.map((observation) => observation.observation_id);
546
1383
  const raw = await callJsonAuthor({
547
1384
  llmCall,
548
1385
  llmConfig,
@@ -551,11 +1388,14 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
551
1388
  systemPrompt: [
552
1389
  baseSystem,
553
1390
  "Select observations that should become evidence candidates for the declared reconstruct purpose.",
1391
+ "selected_observations is a set keyed by observation_id. Include each observation_id at most once; if one observation supports multiple rationales, combine them in one selection_rationale.",
1392
+ "Copy observation_id verbatim from available_observation_ids. Do not invent, rename, or duplicate observation ids.",
554
1393
  "JSON shape: {\"selected_observations\":[{\"observation_id\":\"...\",\"selection_rationale\":\"...\"}],\"open_questions\":[\"...\"]}",
555
1394
  ].join("\n"),
556
1395
  userPayload: {
557
1396
  intent: input.intent,
558
1397
  target_material_profile: input.targetMaterialProfile,
1398
+ available_observation_ids: availableObservationIds,
559
1399
  source_observations: observationPromptPayload(input.sourceObservations),
560
1400
  },
561
1401
  });
@@ -563,8 +1403,13 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
563
1403
  observation.observation_id,
564
1404
  observation,
565
1405
  ]));
1406
+ const selectedIds = new Set();
566
1407
  const selected = records(raw.selected_observations, "selected_observations").map((selection, index) => {
567
1408
  const observationId = stringValue(selection.observation_id, `selected_observations[${index}].observation_id`);
1409
+ if (selectedIds.has(observationId)) {
1410
+ throw new Error(`SourceObservationDirective repeats observation id: ${observationId}`);
1411
+ }
1412
+ selectedIds.add(observationId);
568
1413
  const observation = byId.get(observationId);
569
1414
  if (!observation) {
570
1415
  throw new Error(`SourceObservationDirective selected unknown observation id: ${observationId}`);
@@ -590,7 +1435,7 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
590
1435
  maxTokens: 3200,
591
1436
  systemPrompt: [
592
1437
  baseSystem,
593
- `You are the ${input.lensId} reconstruct lens. Apply this perspective:`,
1438
+ `You are the ${input.lensId} reconstruct lens. Apply this lens contract:`,
594
1439
  input.lensPrompt,
595
1440
  "JSON shape: {\"candidate_labels\":[{\"label_id\":\"...\",\"label\":\"...\",\"evidence_observation_ids\":[\"...\"],\"rationale\":\"...\"}],\"semantic_gaps\":[{\"gap_id\":\"...\",\"description\":\"...\",\"evidence_observation_ids\":[\"...\"],\"requested_source_refs\":[\"...\"],\"materiality_rationale\":\"...\"}],\"no_next_frontier_rationale\":\"... or null\"}",
596
1441
  ].join("\n"),
@@ -599,7 +1444,10 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
599
1444
  round_id: input.roundId,
600
1445
  source_observation_directive_ref: input.sourceObservationDirectiveRef,
601
1446
  selected_observations: input.sourceObservationDirective.selected_observations,
602
- source_observations: observationPromptPayload(input.sourceObservations),
1447
+ source_observations: observationPromptPayload(input.sourceObservations, {
1448
+ observationIds: selectedObservationIds(input.sourceObservationDirective),
1449
+ contentExcerptCharLimit: PROMPT_OBSERVATION_EXCERPT_LIMIT,
1450
+ }),
603
1451
  },
604
1452
  });
605
1453
  return {
@@ -654,28 +1502,10 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
654
1502
  intent: input.intent,
655
1503
  round_id: input.roundId,
656
1504
  lens_judgment_index_ref: input.lensJudgmentIndexRef,
1505
+ source_observations_ref: input.sourceObservationsRef,
657
1506
  lens_judgments: lensJudgmentPromptPayload(input.lensJudgments),
658
1507
  },
659
1508
  });
660
- const sourceObservations = {
661
- schema_version: "1",
662
- session_id: input.sessionId,
663
- created_at: isoNow(),
664
- observations: input.lensJudgments.flatMap((judgment) => [
665
- ...judgment.candidate_labels.flatMap((label) => label.evidence_refs),
666
- ...judgment.semantic_gaps.flatMap((gap) => gap.evidence_refs),
667
- ].map((ref) => ({
668
- observation_id: ref.observation_id,
669
- target_material_kind: ref.target_material_kind,
670
- adapter_id: "evidence-ref-projection",
671
- source_ref: ref.source_ref,
672
- location: ref.location,
673
- summary: "Projected from lens judgment evidence refs.",
674
- structural_data: {},
675
- }))),
676
- skipped_refs: [],
677
- validation_results: [],
678
- };
679
1509
  return {
680
1510
  schema_version: "1",
681
1511
  session_id: input.sessionId,
@@ -689,7 +1519,7 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
689
1519
  description: stringValue(gap.description, `accepted_gaps[${index}].description`),
690
1520
  evidence_refs: evidenceRefsFromIds({
691
1521
  observationIds: stringArray(gap.evidence_observation_ids, `accepted_gaps[${index}].evidence_observation_ids`),
692
- sourceObservations,
1522
+ sourceObservations: input.sourceObservations,
693
1523
  fieldName: `accepted_gaps[${index}].evidence_observation_ids`,
694
1524
  }),
695
1525
  })),
@@ -721,6 +1551,8 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
721
1551
  systemPrompt: [
722
1552
  baseSystem,
723
1553
  "Convert exploration synthesis into a concrete source frontier. If no new source should be read, return an empty frontier_refs array and a no_next_frontier_rationale.",
1554
+ "Frontier refs are only for not-yet-observed refs that are already present in inventory_source_refs. Do not request refs listed in observed_source_refs. Do not invent relative paths outside inventory_source_refs.",
1555
+ "If every useful next source is already observed, return frontier_refs: [] and explain the remaining source-depth limitation in no_next_frontier_rationale.",
724
1556
  "JSON shape: {\"frontier_refs\":[{\"source_ref\":\"...\",\"rationale\":\"...\",\"priority\":\"high|medium|low\"}],\"no_next_frontier_rationale\":\"... or null\"}",
725
1557
  ].join("\n"),
726
1558
  userPayload: {
@@ -728,6 +1560,10 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
728
1560
  round_id: input.roundId,
729
1561
  exploration_synthesis_ref: input.explorationSynthesisRef,
730
1562
  exploration_synthesis: input.explorationSynthesis,
1563
+ inventory_source_refs: input.sourceInventory.inventory_units
1564
+ .map((unit) => unit.ref),
1565
+ observed_source_refs: input.sourceObservations.observations
1566
+ .map((observation) => observation.source_ref),
731
1567
  },
732
1568
  });
733
1569
  const frontierRefs = records(raw.frontier_refs ?? [], "frontier_refs")
@@ -759,102 +1595,181 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
759
1595
  },
760
1596
  };
761
1597
  },
762
- async writeSeedCandidate(input) {
1598
+ async writeCandidateInventory(input) {
763
1599
  const raw = await callJsonAuthor({
764
1600
  llmCall,
765
1601
  llmConfig,
766
- artifactName: "SeedCandidate",
767
- maxTokens: 4200,
1602
+ artifactName: "CandidateInventory",
1603
+ maxTokens: 4000,
768
1604
  systemPrompt: [
769
1605
  baseSystem,
770
- "Author an ontology Seed candidate for the declared purpose. Claims must be evidence-backed by observation ids. Cover purpose, non-goals, entities, relations, actions, properties, rules, and open questions.",
771
- "Each claim must include claim_id for artifact linkage and name for user-facing meaning. name must be a concise meaningful label such as RawIngestEvent, Usage Mart, or Dashboard Overview, not Entity 1 or a numbered placeholder.",
772
- "Each claim shape: {\"claim_id\":\"...\",\"name\":\"...\",\"statement\":\"...\",\"evidence_observation_ids\":[\"...\"]}",
773
- "JSON shape: {\"purpose\":claim,\"non_goals\":[claim],\"entities\":[claim],\"relations\":[claim],\"actions\":[claim],\"properties\":[claim],\"rules\":[claim],\"open_questions\":[\"...\"]}",
1606
+ "Author candidate-inventory.yaml. Inventory every high-salience object, actor, action, workflow, permission, data source, constraint, and concept candidate that the observed evidence may support.",
1607
+ "Every provided source observation must appear in at least one candidate evidence_observation_ids array. If an observation only shows absence, boundary, or limitation evidence, create a low-salience validation or limitation candidate for that observation.",
1608
+ `Allowed candidate_kind values: ${candidateKindIds(input.contractRegistry).join(", ")}.`,
1609
+ "Do not decide placement here. This artifact only records candidates that must not vanish before disposition.",
1610
+ "Each candidate shape: {\"candidate_id\":\"candidate-...\",\"candidate_kind\":\"...\",\"name\":\"...\",\"description\":\"...\",\"salience\":\"high|medium|low\",\"evidence_observation_ids\":[\"...\"]}.",
1611
+ "JSON shape: {\"candidates\":[candidate]}",
774
1612
  ].join("\n"),
775
1613
  userPayload: {
1614
+ session_id: input.sessionId,
776
1615
  intent: input.intent,
777
1616
  selected_observations: input.sourceObservationDirective.selected_observations,
778
- source_observations: observationPromptPayload(input.sourceObservations),
1617
+ source_observations_ref: input.sourceObservationsRef,
1618
+ source_observations: observationPromptPayload(input.sourceObservations, {
1619
+ contentExcerptCharLimit: PROMPT_OBSERVATION_EXCERPT_LIMIT,
1620
+ }),
779
1621
  lens_judgment_index: input.lensJudgmentIndex,
780
1622
  exploration_synthesis: input.explorationSynthesis,
781
1623
  source_frontier_validation: input.sourceFrontierValidation,
782
1624
  },
783
1625
  });
784
- const purposeRaw = raw.purpose && typeof raw.purpose === "object" && !Array.isArray(raw.purpose)
785
- ? raw.purpose
786
- : null;
787
- if (!purposeRaw)
788
- throw new Error("SeedCandidate.purpose must be an object.");
789
1626
  return {
790
1627
  schema_version: "1",
791
1628
  session_id: input.sessionId,
792
1629
  created_at: isoNow(),
793
- purpose: claimFromLlm({
794
- raw: purposeRaw,
795
- fallbackId: "purpose-1",
796
- sourceObservations: input.sourceObservations,
797
- fieldName: "purpose",
798
- }),
799
- non_goals: claimsFromLlm({
800
- value: raw.non_goals,
801
- prefix: "non-goal",
1630
+ source_observations_ref: input.sourceObservationsRef,
1631
+ candidates: records(raw.candidates, "candidates").map((candidate, index) => candidateInventoryItemFromLlm({
1632
+ raw: candidate,
1633
+ index,
802
1634
  sourceObservations: input.sourceObservations,
803
- }),
804
- entities: claimsFromLlm({
805
- value: raw.entities,
806
- prefix: "entity",
807
- sourceObservations: input.sourceObservations,
808
- }),
809
- relations: claimsFromLlm({
810
- value: raw.relations,
811
- prefix: "relation",
812
- sourceObservations: input.sourceObservations,
813
- }),
814
- actions: claimsFromLlm({
815
- value: raw.actions,
816
- prefix: "action",
817
- sourceObservations: input.sourceObservations,
818
- }),
819
- properties: claimsFromLlm({
820
- value: raw.properties,
821
- prefix: "property",
822
- sourceObservations: input.sourceObservations,
823
- }),
824
- rules: claimsFromLlm({
825
- value: raw.rules,
826
- prefix: "rule",
1635
+ })),
1636
+ directive_author: {
1637
+ owner: "host_llm",
1638
+ author_id: authorId,
1639
+ },
1640
+ };
1641
+ },
1642
+ async writeCandidateDisposition(input) {
1643
+ const raw = await callJsonAuthor({
1644
+ llmCall,
1645
+ llmConfig,
1646
+ artifactName: "CandidateDisposition",
1647
+ maxTokens: 4000,
1648
+ systemPrompt: [
1649
+ baseSystem,
1650
+ "Author candidate-disposition.yaml. Every candidate from candidate-inventory.yaml must receive exactly one disposition.",
1651
+ `Allowed disposition_id values: ${candidateDispositionIds(input.contractRegistry).join(", ")}.`,
1652
+ "Use promoted_to_seed_layer only when target_seed_refs names planned canonical seed refs that ontology-seed.yaml must later realize. Use non-promoted dispositions when the candidate is represented, deferred, rejected, or only validation-facing.",
1653
+ "Each disposition shape: {\"candidate_id\":\"...\",\"disposition_id\":\"...\",\"target_seed_refs\":[\"...\"],\"rationale\":\"...\",\"evidence_observation_ids\":[\"...\"]}.",
1654
+ "JSON shape: {\"dispositions\":[disposition]}",
1655
+ ].join("\n"),
1656
+ userPayload: {
1657
+ intent: input.intent,
1658
+ candidate_inventory_ref: input.candidateInventoryRef,
1659
+ candidate_inventory: input.candidateInventory,
1660
+ source_observations: observationPromptPayload(input.sourceObservations, {
1661
+ contentExcerptCharLimit: PROMPT_OBSERVATION_EXCERPT_LIMIT,
1662
+ }),
1663
+ },
1664
+ });
1665
+ return {
1666
+ schema_version: "1",
1667
+ session_id: input.sessionId,
1668
+ created_at: isoNow(),
1669
+ candidate_inventory_ref: input.candidateInventoryRef,
1670
+ dispositions: records(raw.dispositions, "dispositions").map((disposition, index) => candidateDispositionItemFromLlm({
1671
+ raw: disposition,
1672
+ index,
827
1673
  sourceObservations: input.sourceObservations,
828
- }),
829
- open_questions: stringArray(raw.open_questions, "open_questions"),
1674
+ })),
1675
+ directive_author: {
1676
+ owner: "host_llm",
1677
+ author_id: authorId,
1678
+ },
830
1679
  };
831
1680
  },
1681
+ async writeOntologySeed(input) {
1682
+ const raw = await callJsonAuthor({
1683
+ llmCall,
1684
+ llmConfig,
1685
+ artifactName: "ActionableOntologySeed",
1686
+ maxTokens: 9000,
1687
+ systemPrompt: [
1688
+ baseSystem,
1689
+ "Author ontology-seed.yaml as an ActionableOntologySeed. This is not a concept map only; it must include operational objects, actors, actions, permissions, data bindings, validation requirements, ontology handoff mapping, source authority, and limitations.",
1690
+ "Use candidate-disposition.yaml as the disposition authority. Do not duplicate the full disposition ledger in ontology-seed.yaml.",
1691
+ `validation_layer.coverage_axes allowed values: ${coverageAxisIds(input.contractRegistry).join(", ")}.`,
1692
+ ACTIONABLE_ONTOLOGY_SEED_JSON_SHAPE,
1693
+ "candidate_disposition_authority_ref must be {\"authority_scope\":\"external_candidate_disposition\",\"projection_policy\":\"reference_only\"}; concrete candidate artifact refs are owned by reconstruct-record.yaml and reconstruct-run-manifest.yaml.",
1694
+ "validation_layer.question_authority_ref must declare {\"authority_scope\":\"canonical_question_set\",\"projection_policy\":\"record_manifest_ref\"}; validation_layer.runtime_validation_refs may name authority scopes, but must not contain concrete runtime artifact filenames.",
1695
+ "ontology_handoff.readiness_claim must be one of ready, limited, not_ready, blocked. Use limited or not_ready when source evidence leaves explicit handoff limitations.",
1696
+ "When ontology_handoff.readiness_claim is ready, every ontology_handoff mapping object must include concrete mapping content or limitation_refs. Empty shells such as {\"limitation_refs\":[]} are invalid.",
1697
+ "Object types need object_type_id and properties arrays. Actor types belong in dynamic_layer.actor_types with actor_type_id, not semantic_layer.actor_types. Actions belong in kinetic_layer.action_types with action_type_id.",
1698
+ "Every concept_id/object_type_id/actor_type_id/action_type_id/limitation_id must be stable and meaningful, for example object_user or action_review_session; do not use generic ids like ontology_seed.",
1699
+ "Every *_id value must be globally unique across the seed, except semantic_layer.object_types[].primary_key.property_id may reference a property_id from that same object's properties array.",
1700
+ "Use only observed_source_refs for every source_ref field. Use skipped_source_refs only in source_authority.source_gaps or handoff_limitations.missing_source_refs.",
1701
+ "Do not use reconstruct runtime artifact names as source_ref values; they are artifact truth refs, not source evidence refs.",
1702
+ "Before returning, check every object_type_id has data binding coverage or appears in a handoff limitation affected_refs array.",
1703
+ "Every action must have actor_type_ids and object refs, or a handoff limitation. Every action must have permission policy coverage or a limitation. Every object must have source/read/provenance data binding coverage or a limitation.",
1704
+ "Any field named evidence_refs is reserved for evidence arrays only. Never put prose, policy text, artifact names, or source_ref strings in evidence_refs; use statement, rationale, policy, authority_scope, timestamp_ref, or *_mapping text fields instead.",
1705
+ "Use evidence_refs arrays with full evidence ref objects from the provided source_observations. Return the complete ontology seed as one JSON object with no wrapper.",
1706
+ ].join("\n"),
1707
+ userPayload: {
1708
+ intent: input.intent,
1709
+ target_material_profile: input.targetMaterialProfile,
1710
+ candidate_inventory_ref: input.candidateInventoryRef,
1711
+ candidate_inventory: input.candidateInventory,
1712
+ candidate_disposition_ref: input.candidateDispositionRef,
1713
+ candidate_disposition: input.candidateDisposition,
1714
+ source_observations_ref: input.sourceObservationsRef,
1715
+ source_observations: observationPromptPayload(input.sourceObservations, {
1716
+ contentExcerptCharLimit: PROMPT_OBSERVATION_EXCERPT_LIMIT,
1717
+ }),
1718
+ observed_source_refs: input.sourceObservations.observations
1719
+ .map((observation) => observation.source_ref),
1720
+ skipped_source_refs: input.targetMaterialProfile.detection.per_ref
1721
+ .filter((ref) => !input.sourceObservations.observations.some((observation) => path.resolve(observation.source_ref) === path.resolve(ref.ref)))
1722
+ .map((ref) => ({
1723
+ source_ref: ref.ref,
1724
+ target_material_kind: ref.kind,
1725
+ confidence_basis: ref.confidence_basis,
1726
+ })),
1727
+ },
1728
+ });
1729
+ return raw;
1730
+ },
832
1731
  async writeClaimRealizationMap(input) {
1732
+ const claims = ontologyClaims(input.ontologySeed);
1733
+ const allowedClaims = claimRealizationTargets(claims);
833
1734
  const raw = await callJsonAuthor({
834
1735
  llmCall,
835
1736
  llmConfig,
836
1737
  artifactName: "ClaimRealizationMap",
837
- maxTokens: 3000,
1738
+ maxTokens: 8000,
838
1739
  systemPrompt: [
839
1740
  baseSystem,
840
1741
  `Classify every Seed claim with one stance from: ${CLAIM_REALIZATION_STANCES.join(", ")}.`,
1742
+ "For this artifact, Seed claim means exactly one item in userPayload.allowed_claims.",
1743
+ "Return exactly one claim_realizations item for every allowed_claims item.",
1744
+ "Copy claim_id verbatim from allowed_claims[].claim_id. Do not invent, rename, normalize, shorten, or derive claim_id values from limitations, unsupported question candidates, source refs, or runtime artifact names.",
1745
+ "Do not include any claim_id outside allowed_claims. If a claim is limited or not realized, keep the allowed claim_id and use deferred_or_non_goal or unknown with rationale.",
841
1746
  "JSON shape: {\"claim_realizations\":[{\"claim_id\":\"...\",\"stance\":\"...\",\"rationale\":\"...\"}]}",
842
1747
  ].join("\n"),
843
1748
  userPayload: {
844
- seed_candidate_ref: input.seedCandidateRef,
845
- seed_candidate: input.seedCandidate,
846
- source_observations: observationPromptPayload(input.sourceObservations),
1749
+ ontology_seed_ref: input.ontologySeedRef,
1750
+ allowed_claims: allowedClaims,
1751
+ ontology_seed: input.ontologySeed,
1752
+ ontology_seed_validation: input.ontologySeedValidation,
1753
+ source_observations: observationPromptPayload(input.sourceObservations, {
1754
+ observationIds: claimEvidenceObservationIds(claims),
1755
+ contentExcerptCharLimit: PROMPT_OBSERVATION_EXCERPT_LIMIT,
1756
+ }),
847
1757
  },
848
1758
  });
849
- const claimById = new Map(allClaims(input.seedCandidate).map((claim) => [
1759
+ const claimById = new Map(claims.map((claim) => [
850
1760
  claim.claim_id,
851
1761
  claim,
852
1762
  ]));
1763
+ const seenClaimIds = new Set();
853
1764
  const realizations = records(raw.claim_realizations, "claim_realizations").map((realization, index) => {
854
1765
  const claimId = stringValue(realization.claim_id, `claim_realizations[${index}].claim_id`);
855
1766
  const claim = claimById.get(claimId);
856
1767
  if (!claim)
857
1768
  throw new Error(`ClaimRealizationMap references unknown claim id: ${claimId}`);
1769
+ if (seenClaimIds.has(claimId)) {
1770
+ throw new Error(`ClaimRealizationMap repeats claim id: ${claimId}`);
1771
+ }
1772
+ seenClaimIds.add(claimId);
858
1773
  const stance = stringValue(realization.stance, `claim_realizations[${index}].stance`);
859
1774
  if (!CLAIM_REALIZATION_STANCES.includes(stance)) {
860
1775
  throw new Error(`ClaimRealizationMap stance is invalid for ${claimId}: ${stance}`);
@@ -866,11 +1781,17 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
866
1781
  rationale: stringValue(realization.rationale, `claim_realizations[${index}].rationale`),
867
1782
  };
868
1783
  });
1784
+ const missingClaimIds = claims
1785
+ .map((claim) => claim.claim_id)
1786
+ .filter((claimId) => !seenClaimIds.has(claimId));
1787
+ if (missingClaimIds.length > 0) {
1788
+ throw new Error(`ClaimRealizationMap is missing allowed claim ids: ${missingClaimIds.slice(0, 12).join(", ")}${missingClaimIds.length > 12 ? ", ..." : ""}`);
1789
+ }
869
1790
  return {
870
1791
  schema_version: "1",
871
1792
  session_id: input.sessionId,
872
1793
  created_at: isoNow(),
873
- seed_candidate_ref: input.seedCandidateRef,
1794
+ ontology_seed_ref: input.ontologySeedRef,
874
1795
  claim_realizations: realizations,
875
1796
  directive_author: {
876
1797
  owner: "host_llm",
@@ -879,30 +1800,139 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
879
1800
  };
880
1801
  },
881
1802
  async writeCompetencyQuestions(input) {
882
- const raw = await callJsonAuthor({
883
- llmCall,
884
- llmConfig,
885
- artifactName: "CompetencyQuestions",
886
- maxTokens: 3200,
887
- systemPrompt: [
888
- baseSystem,
889
- "Write competency questions that test accepted or CQ-eligible Seed claims for the declared purpose.",
890
- "Every cq_eligible_claim_id must appear in at least one linked_claim_ids array. Group related claims when useful, but do not leave an eligible claim untested.",
891
- "JSON shape: {\"questions\":[{\"question_id\":\"...\",\"question\":\"...\",\"linked_claim_ids\":[\"...\"],\"evidence_observation_ids\":[\"...\"]}],\"open_questions\":[\"...\"]}",
892
- ].join("\n"),
893
- userPayload: {
894
- seed_candidate: input.seedCandidate,
895
- seed_confirmation: input.seedConfirmation,
896
- seed_confirmation_validation: input.seedConfirmationValidation,
897
- claim_realization_map: input.claimRealizationMap,
898
- },
899
- });
900
1803
  const eligibleClaimIds = new Set(input.seedConfirmationValidation.cq_eligible_claim_ids);
1804
+ const eligibleClaims = ontologyClaims(input.ontologySeed)
1805
+ .filter((claim) => eligibleClaimIds.has(claim.claim_id));
1806
+ const requiredDomainCompetencyIds = new Set(input.governingSnapshot.required_admitted_competency_ids);
1807
+ const domainCompetencyRows = input.governingSnapshot.admitted_domain_competency_snapshots.flatMap((snapshot) => snapshot.admitted_competencies).filter((competency) => requiredDomainCompetencyIds.has(competency.qualified_competency_id));
1808
+ const domainCompetencyPromptRows = domainCompetencyRows.map((competency) => ({
1809
+ competency_id: competency.qualified_competency_id,
1810
+ priority: competency.priority,
1811
+ question: competency.question,
1812
+ section_heading: competency.section_heading,
1813
+ inference_path: competency.inference_path,
1814
+ verification_criteria: competency.verification_criteria,
1815
+ source_anchor: competency.source_anchor,
1816
+ }));
1817
+ const allowedPayload = {
1818
+ allowed_coverage_axis_ids: input.contractRegistry.coverage_axis_registry.map((record) => record.axis_id),
1819
+ allowed_ontology_handoff_axis_ids: input.contractRegistry.ontology_handoff_axis_registry.map((record) => record.axis_id),
1820
+ allowed_reference_standard_ids: input.contractRegistry.reference_standard_registry.map((record) => record.standard_ref_id),
1821
+ allowed_pattern_catalog_ref_ids: input.contractRegistry.reference_pattern_catalog_registry.map((record) => record.pattern_catalog_ref_id),
1822
+ allowed_reasoning_or_formalism_facet_ids: facetIds(input.contractRegistry.reasoning_or_formalism_facet_registry),
1823
+ allowed_entity_identity_facet_ids: facetIds(input.contractRegistry.entity_identity_facet_registry),
1824
+ allowed_instance_assertion_facet_ids: facetIds(input.contractRegistry.instance_assertion_facet_registry),
1825
+ allowed_terminology_facet_ids: facetIds(input.contractRegistry.terminology_facet_registry),
1826
+ allowed_relation_type_facet_ids: facetIds(input.contractRegistry.relation_type_facet_registry),
1827
+ allowed_classification_facet_ids: facetIds(input.contractRegistry.classification_facet_registry),
1828
+ allowed_constraint_facet_ids: facetIds(input.contractRegistry.constraint_facet_registry),
1829
+ allowed_modeling_concern_ids: modelingConcernIds(input.contractRegistry),
1830
+ allowed_query_access_contract_ref_ids: proofContractIds(input.contractRegistry.query_access_contract_registry),
1831
+ allowed_visualization_contract_ref_ids: proofContractIds(input.contractRegistry.visualization_contract_registry),
1832
+ allowed_graph_exploration_contract_ref_ids: proofContractIds(input.contractRegistry.graph_exploration_contract_registry),
1833
+ };
1834
+ const rawQuestionRows = [];
1835
+ const openQuestions = [];
1836
+ const callCompetencyQuestionBatch = async (args) => {
1837
+ const batchSeedConfirmationValidation = {
1838
+ ...input.seedConfirmationValidation,
1839
+ cq_eligible_claim_ids: args.eligibleClaimRows.map((claim) => claim.claim_id),
1840
+ };
1841
+ const domainBatchOnly = args.domainRows.length > 0 && args.eligibleClaimRows.length === 0;
1842
+ const rawBatch = await callJsonAuthor({
1843
+ llmCall,
1844
+ llmConfig,
1845
+ artifactName: "CompetencyQuestions",
1846
+ maxTokens: domainBatchOnly
1847
+ ? DOMAIN_COMPETENCY_QUESTION_BATCH_MAX_TOKENS
1848
+ : 3200,
1849
+ systemPrompt: [
1850
+ baseSystem,
1851
+ "Write competency questions that test accepted or CQ-eligible Seed claims for the declared purpose.",
1852
+ domainBatchOnly
1853
+ ? "This is a required domain competency batch. Do not attempt broad claim coverage in this call; emit exactly one question for each required_domain_competency_question_rows item."
1854
+ : "Every cq_eligible_claim_id in the payload must appear in at least one linked_claim_ids array. Group related claims when useful, but do not leave an eligible claim untested.",
1855
+ "Each question must also declare coverage axis refs, ontology handoff refs, facet refs, modeling concern refs, proof contract refs, domain trace refs, disposition, answer kind, handoff relevance, lifecycle status, rationale, seed refs, limitation refs, reference standard refs, and pattern catalog refs. Use [] only when a category is intentionally not applicable. Runtime derives required_evidence_scope from these refs.",
1856
+ "domain_competency_trace_refs may only use required_admitted_competency_ids from the payload. Domain admission refs and source document refs are not valid trace refs.",
1857
+ "If required_domain_competency_question_rows is non-empty, emit exactly one question for each row. That question must include domain_competency_trace_refs with that row's competency_id exactly once across the whole batch.",
1858
+ "For each domain competency trace, include one domain_competency_semantic_assessments row. The row is LLM-authored semantic judgment; runtime validates refs, source_anchor, enum values, rationale, and evidence, but does not perform string-similarity semantic judging.",
1859
+ "coverage_disposition must be one of covered, limited, unsupported, deferred, not_applicable. Non-covered questions must cite limitation_refs.",
1860
+ domainBatchOnly
1861
+ ? "Use the allowed axis and facet refs that apply to this domain competency row; do not invent refs outside the allowed lists."
1862
+ : "Across the question set, cover every allowed coverage axis and every allowed ontology handoff axis at least once; use limitation_refs for limited axes.",
1863
+ "JSON shape: {\"questions\":[{\"question_id\":\"...\",\"question\":\"...\",\"linked_claim_ids\":[\"...\"],\"coverage_axis_refs\":[\"...\"],\"ontology_handoff_axis_refs\":[\"...\"],\"seed_ref_refs\":[\"...\"],\"limitation_refs\":[\"...\"],\"reasoning_or_formalism_facets\":[\"...\"],\"entity_identity_facets\":[\"...\"],\"instance_assertion_facets\":[\"...\"],\"terminology_facets\":[\"...\"],\"relation_type_facets\":[\"...\"],\"classification_facets\":[\"...\"],\"constraint_facets\":[\"...\"],\"modeling_concern_facets\":[\"...\"],\"domain_competency_trace_refs\":[\"...\"],\"domain_competency_semantic_assessments\":[{\"competency_id\":\"...\",\"source_anchor\":\"...\",\"applicability_verdict\":\"applicable|not_applicable|deferred\",\"semantic_alignment\":\"preserved|limited|not_assessed\",\"rationale\":\"...\",\"evidence_observation_ids\":[\"...\"]}],\"reference_standard_refs\":[\"...\"],\"pattern_catalog_refs\":[\"...\"],\"query_access_contract_refs\":[\"...\"],\"visualization_contract_refs\":[\"...\"],\"graph_exploration_contract_refs\":[\"...\"],\"coverage_disposition\":\"covered|limited|unsupported|deferred|not_applicable\",\"expected_answer_kind\":\"yes_no|explanation|list|mapping|gap_statement\",\"handoff_relevance\":\"required|supporting|diagnostic\",\"lifecycle_status\":\"active|deferred|unsupported_candidate\",\"rationale\":\"...\",\"evidence_observation_ids\":[\"...\"]}],\"open_questions\":[\"...\"]}",
1864
+ ].join("\n"),
1865
+ userPayload: {
1866
+ ontology_seed_ref: input.ontologySeedRef,
1867
+ ontology_seed: input.ontologySeed,
1868
+ ontology_seed_validation: input.ontologySeedValidation,
1869
+ source_observations_ref: input.sourceObservationsRef,
1870
+ source_observations: observationPromptPayload(input.sourceObservations, {
1871
+ observationIds: args.observationIds,
1872
+ contentExcerptCharLimit: PROMPT_OBSERVATION_EXCERPT_LIMIT,
1873
+ }),
1874
+ seed_confirmation_validation_ref: input.seedConfirmationValidationRef,
1875
+ seed_confirmation_validation: batchSeedConfirmationValidation,
1876
+ admitted_domain_competency_refs: input.governingSnapshot.admitted_domain_competency_refs,
1877
+ admitted_domain_competency_source_refs: input.governingSnapshot.admitted_domain_competency_source_refs,
1878
+ required_admitted_competency_ids: input.governingSnapshot.required_admitted_competency_ids,
1879
+ admitted_competency_priorities: input.governingSnapshot.admitted_competency_priorities,
1880
+ required_domain_competency_question_rows: args.domainRows,
1881
+ ...allowedPayload,
1882
+ eligible_claims: args.eligibleClaimRows.map((claim) => ({
1883
+ claim_id: claim.claim_id,
1884
+ name: claim.name,
1885
+ statement: compactStatement(claim.statement),
1886
+ evidence_observation_ids: [
1887
+ ...new Set(claim.evidence_refs.map((ref) => ref.observation_id)),
1888
+ ],
1889
+ })),
1890
+ claim_realization_map: input.claimRealizationMap,
1891
+ },
1892
+ });
1893
+ rawQuestionRows.push(...records(rawBatch.questions, "questions").map((question, index) => ({
1894
+ ...question,
1895
+ question_id: `${args.questionIdPrefix}-${index + 1}`,
1896
+ })));
1897
+ openQuestions.push(...stringArray(rawBatch.open_questions, "open_questions"));
1898
+ };
1899
+ if (domainCompetencyPromptRows.length > DOMAIN_COMPETENCY_QUESTION_BATCH_SIZE) {
1900
+ await callCompetencyQuestionBatch({
1901
+ eligibleClaimRows: eligibleClaims,
1902
+ domainRows: [],
1903
+ observationIds: claimEvidenceObservationIds(eligibleClaims),
1904
+ questionIdPrefix: "cq-claim",
1905
+ });
1906
+ const domainObservationIds = input.sourceObservations.observations.map((observation) => observation.observation_id);
1907
+ for (const [batchIndex, domainRows] of chunkArray(domainCompetencyPromptRows, DOMAIN_COMPETENCY_QUESTION_BATCH_SIZE).entries()) {
1908
+ await callCompetencyQuestionBatch({
1909
+ eligibleClaimRows: [],
1910
+ domainRows,
1911
+ observationIds: domainObservationIds,
1912
+ questionIdPrefix: `cq-domain-${batchIndex + 1}`,
1913
+ });
1914
+ }
1915
+ }
1916
+ else {
1917
+ await callCompetencyQuestionBatch({
1918
+ eligibleClaimRows: eligibleClaims,
1919
+ domainRows: domainCompetencyPromptRows,
1920
+ observationIds: domainCompetencyRows.length > 0
1921
+ ? input.sourceObservations.observations.map((observation) => observation.observation_id)
1922
+ : claimEvidenceObservationIds(eligibleClaims),
1923
+ questionIdPrefix: "cq",
1924
+ });
1925
+ }
1926
+ const raw = {
1927
+ questions: rawQuestionRows,
1928
+ open_questions: openQuestions,
1929
+ };
901
1930
  return {
902
1931
  schema_version: "1",
903
1932
  session_id: input.sessionId,
904
1933
  created_at: isoNow(),
905
- seed_confirmation_ref: input.seedConfirmationRef,
1934
+ seed_confirmation_ref: null,
1935
+ ontology_seed_ref: input.ontologySeedRef,
906
1936
  questions: records(raw.questions, "questions").map((question, index) => {
907
1937
  const linkedClaimIds = stringArray(question.linked_claim_ids, `questions[${index}].linked_claim_ids`);
908
1938
  for (const claimId of linkedClaimIds) {
@@ -910,28 +1940,67 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
910
1940
  throw new Error(`CompetencyQuestions linked non-eligible claim id: ${claimId}`);
911
1941
  }
912
1942
  }
1943
+ const coverageAxisRefs = stringArray(question.coverage_axis_refs, `questions[${index}].coverage_axis_refs`);
1944
+ const ontologyHandoffAxisRefs = stringArray(question.ontology_handoff_axis_refs, `questions[${index}].ontology_handoff_axis_refs`);
1945
+ const seedRefRefs = stringArray(question.seed_ref_refs, `questions[${index}].seed_ref_refs`);
1946
+ const limitationRefs = stringArray(question.limitation_refs, `questions[${index}].limitation_refs`);
1947
+ const reasoningOrFormalismFacets = stringArray(question.reasoning_or_formalism_facets, `questions[${index}].reasoning_or_formalism_facets`);
1948
+ const entityIdentityFacets = stringArray(question.entity_identity_facets, `questions[${index}].entity_identity_facets`);
1949
+ const instanceAssertionFacets = stringArray(question.instance_assertion_facets, `questions[${index}].instance_assertion_facets`);
1950
+ const terminologyFacets = stringArray(question.terminology_facets, `questions[${index}].terminology_facets`);
1951
+ const relationTypeFacets = stringArray(question.relation_type_facets, `questions[${index}].relation_type_facets`);
1952
+ const classificationFacets = stringArray(question.classification_facets, `questions[${index}].classification_facets`);
1953
+ const constraintFacets = stringArray(question.constraint_facets, `questions[${index}].constraint_facets`);
1954
+ const modelingConcernFacets = stringArray(question.modeling_concern_facets, `questions[${index}].modeling_concern_facets`);
1955
+ const domainCompetencyTraceRefs = stringArray(question.domain_competency_trace_refs, `questions[${index}].domain_competency_trace_refs`);
1956
+ const domainCompetencySemanticAssessments = records(question.domain_competency_semantic_assessments ?? [], `questions[${index}].domain_competency_semantic_assessments`).map((assessment, assessmentIndex) => ({
1957
+ competency_id: stringValue(assessment.competency_id, `questions[${index}].domain_competency_semantic_assessments[${assessmentIndex}].competency_id`),
1958
+ source_anchor: stringValue(assessment.source_anchor, `questions[${index}].domain_competency_semantic_assessments[${assessmentIndex}].source_anchor`),
1959
+ applicability_verdict: stringValue(assessment.applicability_verdict, `questions[${index}].domain_competency_semantic_assessments[${assessmentIndex}].applicability_verdict`),
1960
+ semantic_alignment: stringValue(assessment.semantic_alignment, `questions[${index}].domain_competency_semantic_assessments[${assessmentIndex}].semantic_alignment`),
1961
+ rationale: stringValue(assessment.rationale, `questions[${index}].domain_competency_semantic_assessments[${assessmentIndex}].rationale`),
1962
+ evidence_refs: evidenceRefsFromIds({
1963
+ observationIds: stringArray(assessment.evidence_observation_ids, `questions[${index}].domain_competency_semantic_assessments[${assessmentIndex}].evidence_observation_ids`),
1964
+ sourceObservations: input.sourceObservations,
1965
+ fieldName: `questions[${index}].domain_competency_semantic_assessments[${assessmentIndex}].evidence_observation_ids`,
1966
+ }),
1967
+ }));
1968
+ const referenceStandardRefs = stringArray(question.reference_standard_refs, `questions[${index}].reference_standard_refs`);
1969
+ const patternCatalogRefs = stringArray(question.pattern_catalog_refs, `questions[${index}].pattern_catalog_refs`);
1970
+ const queryAccessContractRefs = stringArray(question.query_access_contract_refs, `questions[${index}].query_access_contract_refs`);
1971
+ const visualizationContractRefs = stringArray(question.visualization_contract_refs, `questions[${index}].visualization_contract_refs`);
1972
+ const graphExplorationContractRefs = stringArray(question.graph_exploration_contract_refs, `questions[${index}].graph_exploration_contract_refs`);
913
1973
  return {
914
1974
  question_id: optionalString(question.question_id) ?? `cq-${index + 1}`,
915
1975
  question: stringValue(question.question, `questions[${index}].question`),
916
1976
  linked_claim_ids: linkedClaimIds,
1977
+ coverage_axis_refs: coverageAxisRefs,
1978
+ ontology_handoff_axis_refs: ontologyHandoffAxisRefs,
1979
+ seed_ref_refs: seedRefRefs,
1980
+ limitation_refs: limitationRefs,
1981
+ reasoning_or_formalism_facets: reasoningOrFormalismFacets,
1982
+ entity_identity_facets: entityIdentityFacets,
1983
+ instance_assertion_facets: instanceAssertionFacets,
1984
+ terminology_facets: terminologyFacets,
1985
+ relation_type_facets: relationTypeFacets,
1986
+ classification_facets: classificationFacets,
1987
+ constraint_facets: constraintFacets,
1988
+ modeling_concern_facets: modelingConcernFacets,
1989
+ domain_competency_trace_refs: domainCompetencyTraceRefs,
1990
+ domain_competency_semantic_assessments: domainCompetencySemanticAssessments,
1991
+ reference_standard_refs: referenceStandardRefs,
1992
+ pattern_catalog_refs: patternCatalogRefs,
1993
+ query_access_contract_refs: queryAccessContractRefs,
1994
+ visualization_contract_refs: visualizationContractRefs,
1995
+ graph_exploration_contract_refs: graphExplorationContractRefs,
1996
+ coverage_disposition: stringValue(question.coverage_disposition, `questions[${index}].coverage_disposition`),
1997
+ expected_answer_kind: stringValue(question.expected_answer_kind, `questions[${index}].expected_answer_kind`),
1998
+ handoff_relevance: stringValue(question.handoff_relevance, `questions[${index}].handoff_relevance`),
1999
+ lifecycle_status: stringValue(question.lifecycle_status, `questions[${index}].lifecycle_status`),
2000
+ rationale: stringValue(question.rationale, `questions[${index}].rationale`),
917
2001
  evidence_refs: evidenceRefsFromIds({
918
2002
  observationIds: stringArray(question.evidence_observation_ids, `questions[${index}].evidence_observation_ids`),
919
- sourceObservations: {
920
- schema_version: "1",
921
- session_id: input.sessionId,
922
- created_at: isoNow(),
923
- observations: allClaims(input.seedCandidate).flatMap((claim) => claim.evidence_refs.map((ref) => ({
924
- observation_id: ref.observation_id,
925
- target_material_kind: ref.target_material_kind,
926
- adapter_id: "seed-evidence-ref-projection",
927
- source_ref: ref.source_ref,
928
- location: ref.location,
929
- summary: "Projected from Seed evidence refs.",
930
- structural_data: {},
931
- }))),
932
- skipped_refs: [],
933
- validation_results: [],
934
- },
2003
+ sourceObservations: input.sourceObservations,
935
2004
  fieldName: `questions[${index}].evidence_observation_ids`,
936
2005
  }),
937
2006
  };
@@ -952,7 +2021,8 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
952
2021
  systemPrompt: [
953
2022
  baseSystem,
954
2023
  `Assess every competency question exactly once. answer_status must be one of: ${ANSWER_STATUSES.join(", ")}.`,
955
- "JSON shape: {\"assessments\":[{\"question_id\":\"...\",\"answer_status\":\"...\",\"rationale\":\"...\"}]}",
2024
+ "Runtime derives required_seed_refs, evidence_refs, and downstream_effect from the question row and answer_status; the author must supply answer_summary, missing_source_or_confirmation when applicable, ambiguity_notes, and rationale.",
2025
+ "JSON shape: {\"assessments\":[{\"question_id\":\"...\",\"answer_status\":\"...\",\"answer_summary\":\"...\",\"missing_source_or_confirmation\":\"...|null\",\"ambiguity_notes\":[\"...\"],\"rationale\":\"...\"}]}",
956
2026
  ].join("\n"),
957
2027
  userPayload: {
958
2028
  competency_questions_ref: input.competencyQuestionsRef,
@@ -984,8 +2054,14 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
984
2054
  return {
985
2055
  question_id: questionId,
986
2056
  answer_status: answerStatus,
2057
+ answer_summary: optionalString(assessment.answer_summary) ??
2058
+ stringValue(assessment.rationale, `assessments[${index}].rationale`),
2059
+ required_seed_refs: question.seed_ref_refs,
987
2060
  linked_claim_ids: question.linked_claim_ids,
988
2061
  evidence_refs: question.evidence_refs,
2062
+ missing_source_or_confirmation: optionalString(assessment.missing_source_or_confirmation),
2063
+ ambiguity_notes: stringArray(assessment.ambiguity_notes, `assessments[${index}].ambiguity_notes`),
2064
+ downstream_effect: downstreamEffectForAnswerStatus(answerStatus),
989
2065
  rationale: stringValue(assessment.rationale, `assessments[${index}].rationale`),
990
2066
  };
991
2067
  }),
@@ -1095,6 +2171,7 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
1095
2171
  };
1096
2172
  },
1097
2173
  async writeStopDecision(input) {
2174
+ const allowedDecisions = stopDecisionAllowedDecisions(input);
1098
2175
  const raw = await callJsonAuthor({
1099
2176
  llmCall,
1100
2177
  llmConfig,
@@ -1103,11 +2180,18 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
1103
2180
  systemPrompt: [
1104
2181
  baseSystem,
1105
2182
  "Decide whether the current reconstructed result is decision-ready for the declared purpose. This is a presentation decision, not user control.",
2183
+ "Use ActionableOntologySeed and downstream runtime validations as the primary authority.",
2184
+ `Allowed decision values for this run: ${allowedDecisions.join(", ")}.`,
2185
+ "Return decision must be copied from the allowed decision values. If material failures, partial/deferred/rejected claims, or unresolved questions remain, do not return stop.",
1106
2186
  "JSON shape: {\"decision\":\"stop|continue|ask_user\",\"rationale\":\"...\",\"next_actions\":[\"...\"]}",
1107
2187
  ].join("\n"),
1108
2188
  userPayload: {
1109
2189
  intent: input.intent,
1110
2190
  metrics: input.metrics,
2191
+ allowed_decisions: allowedDecisions,
2192
+ primary_authority: {
2193
+ seed_artifact: "ontology-seed.yaml",
2194
+ },
1111
2195
  failure_classification: input.failureClassification,
1112
2196
  revision_proposal: input.revisionProposal,
1113
2197
  },
@@ -1116,6 +2200,9 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
1116
2200
  if (decision !== "stop" && decision !== "continue" && decision !== "ask_user") {
1117
2201
  throw new Error(`StopDecision decision is invalid: ${decision}`);
1118
2202
  }
2203
+ if (!allowedDecisions.includes(decision)) {
2204
+ throw new Error(`StopDecision decision ${decision} is not allowed for current readiness; allowed: ${allowedDecisions.join(", ")}`);
2205
+ }
1119
2206
  return {
1120
2207
  schema_version: "1",
1121
2208
  session_id: input.sessionId,
@@ -1136,13 +2223,18 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
1136
2223
  "You are writing the final reconstruct result for the user.",
1137
2224
  "Write concise Markdown. Ground every important statement in artifact refs or ids.",
1138
2225
  "Use claim.name as the user-facing label. Include claim_id only where artifact truth or traceability needs it.",
1139
- "Include execution profile, completion scope, skipped/deferred stages, confirmed Seed content, CQ assessment, material failures, revision proposals, and artifact truth.",
1140
- "Do not claim full domain-context alignment when domain context selection was skipped.",
2226
+ "ActionableOntologySeed is the primary and only active seed authority.",
2227
+ "Include execution profile, completion scope, skipped/deferred stages, confirmed Seed content, Seed answerability buckets, CQ assessment, material failures, revision proposals, and artifact truth.",
2228
+ "Do not claim full domain-document alignment beyond governing_snapshot domain competency admission.",
1141
2229
  ].join("\n"), JSON.stringify({
1142
2230
  session_id: input.sessionId,
1143
2231
  intent: input.intent,
1144
2232
  target_material_profile: input.targetMaterialProfile,
1145
- seed_candidate: input.seedCandidate,
2233
+ candidate_inventory: input.candidateInventory,
2234
+ candidate_disposition: input.candidateDisposition,
2235
+ candidate_disposition_validation: input.candidateDispositionValidation,
2236
+ ontology_seed: input.ontologySeed,
2237
+ ontology_seed_validation: input.ontologySeedValidation,
1146
2238
  claim_realization_map: input.claimRealizationMap,
1147
2239
  seed_confirmation: input.seedConfirmation,
1148
2240
  seed_confirmation_validation: input.seedConfirmationValidation,
@@ -1152,6 +2244,8 @@ export function createDirectCallReconstructDirectiveAuthor(args = {}) {
1152
2244
  revision_proposal: input.revisionProposal,
1153
2245
  metrics: input.metrics,
1154
2246
  stop_decision: input.stopDecision,
2247
+ pre_handoff_run_manifest_validation: input.preHandoffRunManifestValidation,
2248
+ handoff_decision_validation: input.handoffDecisionValidation,
1155
2249
  artifact_refs: input.artifactRefs,
1156
2250
  reconstruct_record_path: input.reconstructRecordPath,
1157
2251
  reconstruct_run_manifest_path: input.reconstructRunManifestPath,
@@ -1244,105 +2338,43 @@ export function createMockReconstructDirectiveAuthor() {
1244
2338
  },
1245
2339
  };
1246
2340
  },
1247
- async writeSeedCandidate(input) {
1248
- const selections = input.sourceObservationDirective.selected_observations;
1249
- if (selections.length === 0) {
1250
- throw new Error("SeedCandidate author requires a selected source observation.");
1251
- }
1252
- const evidenceRefs = selections.map((selection) => ({
1253
- observation_id: selection.observation_id,
1254
- target_material_kind: selection.target_material_kind,
1255
- source_ref: selection.source_ref,
1256
- location: selection.location,
1257
- }));
1258
- const materialKinds = new Set(selections.map((selection) => selection.target_material_kind));
1259
- const firstEvidence = evidenceRefs[0];
1260
- return {
1261
- schema_version: "1",
1262
- session_id: input.sessionId,
1263
- created_at: isoNow(),
1264
- purpose: {
1265
- claim_id: "purpose-1",
1266
- name: "Bounded Ontology Seed Purpose",
1267
- statement: `Reconstruct a bounded ontology Seed for the declared purpose: ${input.intent}`,
1268
- evidence_refs: evidenceRefs,
1269
- },
1270
- non_goals: [
1271
- {
1272
- claim_id: "non-goal-1",
1273
- name: "Runtime Authorship Boundary",
1274
- statement: "The runtime does not author ontology meaning; semantic expansion remains host-owned.",
1275
- evidence_refs: [firstEvidence],
1276
- },
1277
- ],
1278
- entities: [
1279
- {
1280
- claim_id: "entity-1",
1281
- name: "Observed Source Evidence Set",
1282
- statement: `The target material exposes ${selections.length} observed source unit(s) as ontology Seed evidence.`,
1283
- evidence_refs: evidenceRefs,
1284
- },
1285
- ],
1286
- relations: [
1287
- {
1288
- claim_id: "relation-1",
1289
- name: "Observation Evidence Boundary",
1290
- statement: "Selected source observations provide the evidence boundary for every Seed claim.",
1291
- evidence_refs: evidenceRefs,
1292
- },
1293
- ],
1294
- actions: [
1295
- {
1296
- claim_id: "action-1",
1297
- name: "Competency Question Assessment",
1298
- statement: "The reconstruct process can ask competency questions against confirmed Seed claims.",
1299
- evidence_refs: [firstEvidence],
1300
- },
1301
- ],
1302
- properties: [
1303
- {
1304
- claim_id: "property-1",
1305
- name: "Target Material Kind",
1306
- statement: `The target material kind is ${selections[0]?.target_material_kind ?? "unknown"} for at least one selected evidence unit.`,
1307
- evidence_refs: [firstEvidence],
1308
- },
1309
- ],
1310
- rules: [
1311
- {
1312
- claim_id: "rule-1",
1313
- name: "Artifact Truth Rule",
1314
- statement: "Any final output must cite artifact truth rather than becoming a second ontology authority.",
1315
- evidence_refs: [firstEvidence],
1316
- },
1317
- ],
1318
- open_questions: [
1319
- ...(input.sourceObservationDirectiveValidation.validation_status === "valid"
1320
- ? []
1321
- : ["Source observation directive needs revision before Seed use."]),
1322
- ...(materialKinds.size > 1
1323
- ? [
1324
- "Mixed target material requires a host-authored mapping from each selected observation to ontology terms before expanding beyond the bounded Seed purpose.",
1325
- ]
1326
- : []),
1327
- ],
1328
- };
2341
+ async writeCandidateInventory(input) {
2342
+ return mockCandidateInventory({
2343
+ sessionId: input.sessionId,
2344
+ sourceObservations: input.sourceObservations,
2345
+ authorId,
2346
+ });
2347
+ },
2348
+ async writeCandidateDisposition(input) {
2349
+ return mockCandidateDisposition({
2350
+ sessionId: input.sessionId,
2351
+ candidateInventory: input.candidateInventory,
2352
+ authorId,
2353
+ });
2354
+ },
2355
+ async writeOntologySeed(input) {
2356
+ return mockActionableOntologySeed({
2357
+ sessionId: input.sessionId,
2358
+ intent: input.intent,
2359
+ targetMaterialProfile: input.targetMaterialProfile,
2360
+ sourceObservations: input.sourceObservations,
2361
+ authorId,
2362
+ });
1329
2363
  },
1330
2364
  async writeClaimRealizationMap(input) {
1331
- const claims = allClaims(input.seedCandidate);
2365
+ const claims = ontologyClaims(input.ontologySeed);
1332
2366
  return {
1333
2367
  schema_version: "1",
1334
2368
  session_id: input.sessionId,
1335
2369
  created_at: isoNow(),
1336
- seed_candidate_ref: input.seedCandidateRef,
1337
- claim_realizations: claims.map((claim, index) => {
1338
- const stance = CLAIM_REALIZATION_STANCES[index % CLAIM_REALIZATION_STANCES.length] ?? "unknown";
2370
+ ontology_seed_ref: input.ontologySeedRef,
2371
+ claim_realizations: claims.map((claim) => {
2372
+ const stance = "observed_runtime_behavior";
1339
2373
  return {
1340
2374
  claim_id: claim.claim_id,
1341
2375
  stance,
1342
2376
  evidence_refs: claim.evidence_refs,
1343
- rationale: stance === "observed_runtime_behavior"
1344
- ? "Mock author treats this claim as directly supported by runtime observations."
1345
- : `Mock author records ${stance} so downstream gates exercise non-happy-path evidence states.`,
2377
+ rationale: "Mock author treats this claim as directly supported by runtime observations.",
1346
2378
  };
1347
2379
  }),
1348
2380
  directive_author: {
@@ -1352,25 +2384,98 @@ export function createMockReconstructDirectiveAuthor() {
1352
2384
  };
1353
2385
  },
1354
2386
  async writeCompetencyQuestions(input) {
1355
- const confirmedClaims = new Set(input.seedConfirmationValidation.cq_eligible_claim_ids);
1356
- const questions = allClaims(input.seedCandidate)
1357
- .filter((claim) => confirmedClaims.has(claim.claim_id))
1358
- .map((claim, index) => ({
1359
- question_id: `cq-${index + 1}`,
1360
- question: `Can the reconstructed Seed explain claim ${claim.claim_id} for its declared purpose?`,
1361
- linked_claim_ids: [claim.claim_id],
1362
- evidence_refs: claim.evidence_refs,
1363
- }));
2387
+ const eligibleClaims = new Set(input.seedConfirmationValidation.cq_eligible_claim_ids);
2388
+ const claimQuestions = ontologyClaims(input.ontologySeed)
2389
+ .filter((claim) => eligibleClaims.has(claim.claim_id))
2390
+ .map((claim, index) => {
2391
+ const question = {
2392
+ question_id: `cq-${index + 1}`,
2393
+ question: `Can the reconstructed Seed explain claim ${claim.claim_id} for its declared purpose?`,
2394
+ linked_claim_ids: [claim.claim_id],
2395
+ coverage_axis_refs: input.contractRegistry.coverage_axis_registry.map((record) => record.axis_id),
2396
+ ontology_handoff_axis_refs: input.contractRegistry.ontology_handoff_axis_registry.map((record) => record.axis_id),
2397
+ seed_ref_refs: [claim.claim_id],
2398
+ limitation_refs: [],
2399
+ reasoning_or_formalism_facets: facetIds(input.contractRegistry.reasoning_or_formalism_facet_registry),
2400
+ entity_identity_facets: facetIds(input.contractRegistry.entity_identity_facet_registry),
2401
+ instance_assertion_facets: facetIds(input.contractRegistry.instance_assertion_facet_registry),
2402
+ terminology_facets: facetIds(input.contractRegistry.terminology_facet_registry),
2403
+ relation_type_facets: facetIds(input.contractRegistry.relation_type_facet_registry),
2404
+ classification_facets: facetIds(input.contractRegistry.classification_facet_registry),
2405
+ constraint_facets: facetIds(input.contractRegistry.constraint_facet_registry),
2406
+ modeling_concern_facets: modelingConcernIds(input.contractRegistry),
2407
+ domain_competency_trace_refs: [],
2408
+ domain_competency_semantic_assessments: [],
2409
+ reference_standard_refs: [],
2410
+ pattern_catalog_refs: [],
2411
+ query_access_contract_refs: [],
2412
+ visualization_contract_refs: [],
2413
+ graph_exploration_contract_refs: [],
2414
+ coverage_disposition: "covered",
2415
+ expected_answer_kind: "yes_no",
2416
+ handoff_relevance: "required",
2417
+ lifecycle_status: "active",
2418
+ rationale: `Mock competency question covers claim ${claim.claim_id} and all registry-required happy-path axes.`,
2419
+ evidence_refs: claim.evidence_refs,
2420
+ };
2421
+ return question;
2422
+ });
2423
+ const requiredDomainCompetencyIds = new Set(input.governingSnapshot.required_admitted_competency_ids);
2424
+ const admittedDomainCompetencies = input.governingSnapshot.admitted_domain_competency_snapshots.flatMap((snapshot) => snapshot.admitted_competencies).filter((competency) => requiredDomainCompetencyIds.has(competency.qualified_competency_id));
2425
+ const domainEvidenceRef = input.sourceObservations.observations[0]
2426
+ ? evidenceRefFromObservation(input.sourceObservations.observations[0])
2427
+ : null;
2428
+ const domainCompetencyQuestions = admittedDomainCompetencies.map((competency, index) => {
2429
+ const question = {
2430
+ question_id: `domain-cq-${index + 1}`,
2431
+ question: `Can the reconstructed Seed answer ${competency.qualified_competency_id}: ${competency.question}`,
2432
+ linked_claim_ids: [],
2433
+ coverage_axis_refs: [],
2434
+ ontology_handoff_axis_refs: [],
2435
+ seed_ref_refs: [],
2436
+ limitation_refs: [],
2437
+ reasoning_or_formalism_facets: [],
2438
+ entity_identity_facets: [],
2439
+ instance_assertion_facets: [],
2440
+ terminology_facets: [],
2441
+ relation_type_facets: [],
2442
+ classification_facets: [],
2443
+ constraint_facets: [],
2444
+ modeling_concern_facets: [],
2445
+ domain_competency_trace_refs: [competency.qualified_competency_id],
2446
+ domain_competency_semantic_assessments: [
2447
+ {
2448
+ competency_id: competency.qualified_competency_id,
2449
+ source_anchor: competency.source_anchor,
2450
+ applicability_verdict: "applicable",
2451
+ semantic_alignment: "preserved",
2452
+ rationale: `Mock semantic assessment preserves admitted domain competency ${competency.qualified_competency_id}.`,
2453
+ evidence_refs: domainEvidenceRef ? [domainEvidenceRef] : [],
2454
+ },
2455
+ ],
2456
+ reference_standard_refs: [],
2457
+ pattern_catalog_refs: [],
2458
+ query_access_contract_refs: [],
2459
+ visualization_contract_refs: [],
2460
+ graph_exploration_contract_refs: [],
2461
+ coverage_disposition: "covered",
2462
+ expected_answer_kind: "gap_statement",
2463
+ handoff_relevance: "diagnostic",
2464
+ lifecycle_status: "active",
2465
+ rationale: `Mock domain competency disposition row for ${competency.qualified_competency_id}. Verification criteria: ${competency.verification_criteria}`,
2466
+ evidence_refs: domainEvidenceRef ? [domainEvidenceRef] : [],
2467
+ };
2468
+ return question;
2469
+ });
2470
+ const questions = [...claimQuestions, ...domainCompetencyQuestions];
1364
2471
  return {
1365
2472
  schema_version: "1",
1366
2473
  session_id: input.sessionId,
1367
2474
  created_at: isoNow(),
1368
- seed_confirmation_ref: input.seedConfirmationRef,
2475
+ seed_confirmation_ref: null,
2476
+ ontology_seed_ref: input.ontologySeedRef,
1369
2477
  questions,
1370
- open_questions: [
1371
- ...input.seedCandidate.open_questions,
1372
- ...input.seedConfirmation.notes,
1373
- ],
2478
+ open_questions: [],
1374
2479
  directive_author: {
1375
2480
  owner: "mock",
1376
2481
  author_id: authorId,
@@ -1392,20 +2497,27 @@ export function createMockReconstructDirectiveAuthor() {
1392
2497
  const firstClaimId = question.linked_claim_ids[0] ?? null;
1393
2498
  const stance = firstClaimId
1394
2499
  ? realizationByClaim.get(firstClaimId)?.stance ?? "unknown"
1395
- : "unknown";
2500
+ : question.domain_competency_trace_refs.length > 0
2501
+ ? "schema_or_contract_presence"
2502
+ : "unknown";
1396
2503
  const answerStatus = stance === "observed_runtime_behavior" ||
1397
2504
  stance === "schema_or_contract_presence"
1398
- ? "answered"
2505
+ ? "answerable"
1399
2506
  : stance === "declared_design_intent"
1400
- ? "partially_answered"
2507
+ ? "partially_answerable"
1401
2508
  : stance === "deferred_or_non_goal"
1402
- ? "out_of_scope"
1403
- : "needs_evidence";
2509
+ ? "deferred"
2510
+ : "unsupported";
1404
2511
  return {
1405
2512
  question_id: question.question_id,
1406
2513
  answer_status: answerStatus,
2514
+ answer_summary: `Mock assessment maps claim realization stance ${stance} to answer status ${answerStatus}.`,
2515
+ required_seed_refs: question.seed_ref_refs,
1407
2516
  linked_claim_ids: question.linked_claim_ids,
1408
2517
  evidence_refs: question.evidence_refs,
2518
+ missing_source_or_confirmation: answerStatus === "answerable" ? null : `Mock unresolved stance: ${stance}`,
2519
+ ambiguity_notes: [],
2520
+ downstream_effect: downstreamEffectForAnswerStatus(answerStatus),
1409
2521
  rationale: `Mock assessment maps claim realization stance ${stance} to answer status ${answerStatus}.`,
1410
2522
  };
1411
2523
  }),
@@ -1417,13 +2529,16 @@ export function createMockReconstructDirectiveAuthor() {
1417
2529
  },
1418
2530
  async writeFailureClassification(input) {
1419
2531
  const failures = input.competencyQuestionAssessment.assessments
1420
- .filter((assessment) => assessment.answer_status !== "answered")
2532
+ .filter((assessment) => assessment.answer_status !== "answerable")
2533
+ .filter((assessment) => assessment.answer_status !== "not_applicable")
1421
2534
  .map((assessment, index) => {
1422
- const failureKind = assessment.answer_status === "out_of_scope"
2535
+ const failureKind = assessment.answer_status === "deferred"
1423
2536
  ? "deferred_scope"
1424
- : assessment.answer_status === "partially_answered"
2537
+ : assessment.answer_status === "partially_answerable"
1425
2538
  ? "insufficient_evidence"
1426
- : "unanswered_question";
2539
+ : assessment.answer_status === "contradicted"
2540
+ ? "contradicted_evidence"
2541
+ : "unsupported_claim";
1427
2542
  return {
1428
2543
  failure_id: `failure-${index + 1}`,
1429
2544
  failure_kind: failureKind,
@@ -1472,8 +2587,11 @@ export function createMockReconstructDirectiveAuthor() {
1472
2587
  };
1473
2588
  },
1474
2589
  async writeStopDecision(input) {
1475
- const shouldStop = input.metrics.validation_status.source_observation_directive === "valid" &&
1476
- input.metrics.validation_status.seed_candidate === "valid" &&
2590
+ const allowedDecisions = stopDecisionAllowedDecisions(input);
2591
+ const shouldStop = allowedDecisions.includes("stop") &&
2592
+ input.metrics.validation_status.source_observation_directive === "valid" &&
2593
+ input.metrics.validation_status.candidate_disposition === "valid" &&
2594
+ input.metrics.validation_status.ontology_seed === "valid" &&
1477
2595
  input.metrics.validation_status.seed_confirmation_validation === "valid" &&
1478
2596
  input.metrics.unresolved_question_count === 0;
1479
2597
  return {
@@ -1484,7 +2602,7 @@ export function createMockReconstructDirectiveAuthor() {
1484
2602
  declared_purpose: input.intent,
1485
2603
  metrics_ref: input.metricsRef,
1486
2604
  rationale: shouldStop
1487
- ? "All happy-path runtime gates passed and the Seed candidate was accepted."
2605
+ ? "All happy-path runtime gates passed and the primary ontology seed was accepted."
1488
2606
  : "One or more reconstruct gates remains unresolved.",
1489
2607
  next_actions: shouldStop
1490
2608
  ? []
@@ -1496,10 +2614,10 @@ export function createMockReconstructDirectiveAuthor() {
1496
2614
  };
1497
2615
  },
1498
2616
  async writeFinalOutput(input) {
1499
- const confirmedClaims = allClaims(input.seedCandidate).filter((claim) => input.seedConfirmationValidation.accepted_claim_ids.includes(claim.claim_id));
2617
+ const confirmedClaims = ontologyClaims(input.ontologySeed).filter((claim) => input.seedConfirmationValidation.accepted_claim_ids.includes(claim.claim_id));
1500
2618
  const claimLines = confirmedClaims.length === 0
1501
2619
  ? ["- No Seed claims were confirmed."]
1502
- : confirmedClaims.map((claim) => `- ${claim.name} (${claim.claim_id}): ${claim.statement} (seed-candidate.yaml, seed-confirmation-validation.yaml)`);
2620
+ : confirmedClaims.map((claim) => `- ${claim.name} (${claim.claim_id}): ${claim.statement} (ontology-seed.yaml, seed-confirmation-validation.yaml)`);
1503
2621
  const realizationLines = input.claimRealizationMap.claim_realizations.map((realization) => `- ${realization.claim_id}: ${realization.stance} (claim-realization-map.yaml)`);
1504
2622
  const assessmentLines = input.competencyQuestionAssessment.assessments.length === 0
1505
2623
  ? ["- No competency question assessments recorded."]
@@ -1511,12 +2629,12 @@ export function createMockReconstructDirectiveAuthor() {
1511
2629
  ? ["- No revision proposals recorded."]
1512
2630
  : input.revisionProposal.proposals.map((proposal) => `- ${proposal.proposal_id}: ${proposal.action} ${proposal.target_type} ${proposal.target_id} (revision-proposal.yaml)`);
1513
2631
  const unresolvedQuestions = [
1514
- ...input.seedCandidate.open_questions,
1515
2632
  ...input.competencyQuestions.open_questions,
1516
2633
  ];
1517
2634
  const unresolvedLines = unresolvedQuestions.length === 0
1518
2635
  ? ["- None recorded."]
1519
2636
  : unresolvedQuestions.map((question) => `- ${question}`);
2637
+ const answerabilityLines = ontologySeedSummaryLines(input.ontologySeed);
1520
2638
  const skippedLines = input.sourceObservations.skipped_refs.length === 0
1521
2639
  ? ["- None recorded."]
1522
2640
  : input.sourceObservations.skipped_refs.map((skipped) => `- ${skipped.ref} (${skipped.target_material_kind}): ${skipped.reason}`);
@@ -1545,6 +2663,12 @@ export function createMockReconstructDirectiveAuthor() {
1545
2663
  `- Material failures: ${input.failureClassificationValidation.material_failure_count}`,
1546
2664
  `- Revision proposals: ${input.revisionProposalValidation.proposal_count}`,
1547
2665
  `- Pass rate: ${input.metrics.pass_rate}`,
2666
+ `- Handoff readiness: ${input.handoffDecisionValidation.readiness_projection}`,
2667
+ `- Handoff decision validation: ${input.handoffDecisionValidation.validation_status}`,
2668
+ "",
2669
+ "## Seed Answerability",
2670
+ "",
2671
+ ...answerabilityLines,
1548
2672
  "",
1549
2673
  "## Claim Realization Summary",
1550
2674
  "",
@@ -1576,12 +2700,15 @@ export function createMockReconstructDirectiveAuthor() {
1576
2700
  "",
1577
2701
  "## Artifact Truth",
1578
2702
  "",
1579
- `- Seed candidate: ${input.artifactRefs.seed_candidate}`,
2703
+ `- Ontology seed: ${input.artifactRefs.ontology_seed}`,
2704
+ `- Ontology seed validation: ${input.artifactRefs.ontology_seed_validation}`,
1580
2705
  `- Claim realization map: ${input.artifactRefs.claim_realization_map}`,
1581
2706
  `- Seed confirmation validation: ${input.artifactRefs.seed_confirmation_validation}`,
1582
2707
  `- Competency question assessment: ${input.artifactRefs.competency_question_assessment}`,
1583
2708
  `- Failure classification: ${input.artifactRefs.failure_classification}`,
1584
2709
  `- Revision proposal: ${input.artifactRefs.revision_proposal}`,
2710
+ `- Pre-handoff run manifest validation: ${input.artifactRefs.pre_handoff_run_manifest_validation}`,
2711
+ `- Handoff decision validation: ${input.artifactRefs.handoff_decision_validation}`,
1585
2712
  `- Reconstruct record: ${input.reconstructRecordPath}`,
1586
2713
  `- Reconstruct run manifest: ${input.reconstructRunManifestPath}`,
1587
2714
  `- Record stage at final output authoring: ${input.record.record_stage}`,
@@ -1596,29 +2723,45 @@ export function createAutoAcceptReconstructConfirmationProvider() {
1596
2723
  return {
1597
2724
  providerId,
1598
2725
  owner: "mock",
1599
- async confirmSeedCandidate(input) {
1600
- const claims = allClaims(input.seedCandidate);
1601
- const canAccept = input.seedCandidateValidation.validation_status === "valid";
1602
- const acceptedClaims = canAccept ? claims.slice(0, 3) : [];
1603
- const partialClaims = canAccept ? claims.slice(3, 4) : [];
1604
- const deferredClaims = canAccept ? claims.slice(4, 5) : [];
1605
- const rejectedClaims = canAccept ? claims.slice(5) : claims;
2726
+ async confirmOntologySeed(input) {
2727
+ const claims = ontologyClaims(input.ontologySeed);
2728
+ const canAccept = input.ontologySeedValidation.validation_status === "valid";
2729
+ const excludedClaimIds = ontologySeedExcludedClaimIds(input.ontologySeed);
2730
+ const acceptedClaims = canAccept
2731
+ ? claims.filter((claim) => !excludedClaimIds.has(claim.claim_id))
2732
+ : [];
2733
+ const partialClaims = [];
2734
+ const deferredClaims = canAccept
2735
+ ? claims.filter((claim) => excludedClaimIds.has(claim.claim_id))
2736
+ : [];
2737
+ const classifiedClaimIds = new Set([
2738
+ ...acceptedClaims.map((claim) => claim.claim_id),
2739
+ ...partialClaims.map((claim) => claim.claim_id),
2740
+ ...deferredClaims.map((claim) => claim.claim_id),
2741
+ ]);
2742
+ const rejectedClaims = canAccept
2743
+ ? claims.filter((claim) => !classifiedClaimIds.has(claim.claim_id))
2744
+ : claims;
1606
2745
  return {
1607
2746
  schema_version: "1",
1608
2747
  session_id: input.sessionId,
1609
2748
  created_at: isoNow(),
1610
- seed_candidate_ref: input.seedCandidateRef,
1611
- seed_candidate_validation_ref: input.seedCandidateValidationRef,
1612
- confirmation_status: canAccept ? "partial" : "rejected",
2749
+ ontology_seed_ref: input.ontologySeedRef,
2750
+ ontology_seed_validation_ref: input.ontologySeedValidationRef,
2751
+ confirmation_status: rejectedClaims.length === 0 && partialClaims.length === 0 && deferredClaims.length === 0
2752
+ ? "accepted"
2753
+ : canAccept
2754
+ ? "partial"
2755
+ : "rejected",
1613
2756
  confirmed_claim_ids: acceptedClaims.map((claim) => claim.claim_id),
1614
2757
  rejected_claim_ids: rejectedClaims.map((claim) => claim.claim_id),
1615
2758
  partial_claim_ids: partialClaims.map((claim) => claim.claim_id),
1616
2759
  deferred_claim_ids: deferredClaims.map((claim) => claim.claim_id),
1617
2760
  notes: canAccept
1618
2761
  ? [
1619
- "Mock confirmation intentionally emits mixed claim states to exercise downstream reconstruct gates.",
2762
+ "Mock confirmation accepts ontology seed claims before competency-question authoring.",
1620
2763
  ]
1621
- : ["Seed candidate validation failed; confirmation rejected by provider."],
2764
+ : ["Ontology seed validation failed; confirmation rejected by provider."],
1622
2765
  confirmation_provider: {
1623
2766
  owner: "mock",
1624
2767
  provider_id: providerId,
@@ -1634,20 +2777,32 @@ export function createDirectCallReconstructConfirmationProvider(args = {}) {
1634
2777
  return {
1635
2778
  providerId,
1636
2779
  owner: "host_or_user",
1637
- async confirmSeedCandidate(input) {
1638
- const claimSummaries = summarizeSeedClaimsForConfirmation(input.seedCandidate);
2780
+ async confirmOntologySeed(input) {
2781
+ const claimSummaries = ontologyClaims(input.ontologySeed).map((claim) => ({
2782
+ claim_id: claim.claim_id,
2783
+ claim_kind: "ontology_seed_claim",
2784
+ name: claim.name,
2785
+ statement: compactStatement(claim.statement),
2786
+ evidence_observation_ids: [
2787
+ ...new Set(claim.evidence_refs.map((ref) => ref.observation_id)),
2788
+ ],
2789
+ evidence_source_basenames: [
2790
+ ...new Set(claim.evidence_refs.map((ref) => sourceBasename(ref.source_ref))),
2791
+ ],
2792
+ }));
1639
2793
  const result = await llmCall([
1640
2794
  "You are mediating reconstruct Seed confirmation for a non-interactive host.",
1641
2795
  "Return only valid JSON. Do not wrap in Markdown.",
1642
2796
  "Classify every Seed claim summary into confirmed, rejected, partial, or deferred for the declared purpose.",
1643
2797
  "Use the claim id, claim kind, short statement, validation status, and evidence observation ids. Do not invent new claim ids.",
1644
- "Do not re-author Seed content. This step only assigns confirmation state.",
2798
+ "Deferred or unsupported answerability summaries confirm boundary disclosure only; they do not make a claim eligible for competency-question testing.",
2799
+ "Do not re-author Seed content or assess competency-question answerability. This step only assigns seed-claim confirmation state before competency questions are authored.",
1645
2800
  "JSON shape: {\"confirmation_status\":\"accepted|rejected|partial|deferred\",\"confirmed_claim_ids\":[\"...\"],\"rejected_claim_ids\":[\"...\"],\"partial_claim_ids\":[\"...\"],\"deferred_claim_ids\":[\"...\"],\"notes\":[\"...\"]}",
1646
2801
  ].join("\n"), JSON.stringify({
1647
- seed_candidate_ref: input.seedCandidateRef,
1648
- seed_candidate_validation_status: input.seedCandidateValidation.validation_status,
1649
- seed_candidate_validation_results: input.seedCandidateValidation.validation_results,
1650
- seed_candidate_validation_violation_count: input.seedCandidateValidation.violations.length,
2802
+ ontology_seed_ref: input.ontologySeedRef,
2803
+ ontology_seed_validation_status: input.ontologySeedValidation.validation_status,
2804
+ ontology_seed_validation_results: input.ontologySeedValidation.validation_results,
2805
+ ontology_seed_validation_violation_count: input.ontologySeedValidation.violations.length,
1651
2806
  claim_summaries: claimSummaries,
1652
2807
  }, null, 2), { ...llmConfig, max_tokens: 2400 });
1653
2808
  const raw = parseLlmJsonObject(result.text, "SeedConfirmation");
@@ -1659,8 +2814,8 @@ export function createDirectCallReconstructConfirmationProvider(args = {}) {
1659
2814
  schema_version: "1",
1660
2815
  session_id: input.sessionId,
1661
2816
  created_at: isoNow(),
1662
- seed_candidate_ref: input.seedCandidateRef,
1663
- seed_candidate_validation_ref: input.seedCandidateValidationRef,
2817
+ ontology_seed_ref: input.ontologySeedRef,
2818
+ ontology_seed_validation_ref: input.ontologySeedValidationRef,
1664
2819
  confirmation_status: confirmationStatus,
1665
2820
  confirmed_claim_ids: stringArray(raw.confirmed_claim_ids, "confirmed_claim_ids"),
1666
2821
  rejected_claim_ids: stringArray(raw.rejected_claim_ids, "rejected_claim_ids"),
@@ -1679,6 +2834,9 @@ async function readLensPrompt(args) {
1679
2834
  const ontoRoot = path.resolve(args.profilesRoot, "..", "..", "..");
1680
2835
  return fs.readFile(path.join(ontoRoot, "roles", `${args.lensId}.md`), "utf8");
1681
2836
  }
2837
+ function reconstructContractRegistryPathFromProfilesRoot(profilesRoot) {
2838
+ return path.join(path.dirname(path.resolve(profilesRoot)), "reconstruct-contract-registry.yaml");
2839
+ }
1682
2840
  function validateSourceFrontier(args) {
1683
2841
  const inventoryRefs = new Set(args.sourceInventory.inventory_units.map((unit) => path.resolve(unit.ref)));
1684
2842
  const observedRefs = new Set(args.sourceObservations.observations.map((observation) => path.resolve(observation.source_ref)));
@@ -1717,7 +2875,16 @@ function validateSourceFrontier(args) {
1717
2875
  const noNextFrontierAccepted = args.sourceFrontier.frontier_refs.length === 0 &&
1718
2876
  typeof args.sourceFrontier.no_next_frontier_rationale === "string" &&
1719
2877
  args.sourceFrontier.no_next_frontier_rationale.length > 0;
1720
- const valid = rejected.length === 0 &&
2878
+ const upstreamValid = args.targetMaterialProfileValidation.validation_status === "valid";
2879
+ if (!upstreamValid) {
2880
+ rejected.push({
2881
+ frontier_ref_id: null,
2882
+ source_ref: null,
2883
+ reason: "target_material_profile_validation_invalid",
2884
+ });
2885
+ }
2886
+ const valid = upstreamValid &&
2887
+ rejected.length === 0 &&
1721
2888
  (accepted.length > 0 || noNextFrontierAccepted);
1722
2889
  return {
1723
2890
  schema_version: "1",
@@ -1727,35 +2894,259 @@ function validateSourceFrontier(args) {
1727
2894
  source_frontier_ref: args.sourceFrontierRef,
1728
2895
  source_inventory_ref: args.sourceInventoryRef,
1729
2896
  source_observations_ref: args.sourceObservationsRef,
2897
+ target_material_profile_validation_ref: args.targetMaterialProfileValidationRef,
2898
+ upstream_validation_statuses: {
2899
+ target_material_profile: args.targetMaterialProfileValidation.validation_status,
2900
+ },
1730
2901
  validation_status: valid ? "valid" : "invalid",
1731
2902
  accepted_frontier_ref_ids: accepted,
1732
2903
  rejected_frontier_refs: rejected,
1733
2904
  no_next_frontier_accepted: noNextFrontierAccepted,
1734
2905
  validation_results: [
1735
2906
  ...(valid ? ["source_frontier_boundary_valid"] : []),
2907
+ ...(upstreamValid ? ["target_material_profile_validation_valid"] : []),
1736
2908
  ...(noNextFrontierAccepted ? ["no_next_frontier_rationale_present"] : []),
1737
2909
  ],
1738
2910
  };
1739
2911
  }
1740
2912
  function appendFinalOutputProvenanceFooter(finalOutputText, requiredFragments) {
1741
- const missing = requiredFragments.filter((fragment) => !finalOutputText.includes(fragment));
1742
- if (missing.length === 0)
2913
+ const heading = "## Runtime Artifact Truth Footer";
2914
+ const footer = [
2915
+ heading,
2916
+ "",
2917
+ ...requiredFragments.map((fragment) => `- ${fragment}`),
2918
+ "",
2919
+ ].join("\n");
2920
+ if (finalOutputText.includes(heading)) {
2921
+ const lines = finalOutputText.split(/\r?\n/);
2922
+ const start = lines.findIndex((line) => line.trim() === heading);
2923
+ let end = lines.length;
2924
+ for (let index = start + 1; index < lines.length; index += 1) {
2925
+ if (/^##\s+/.test(lines[index]?.trim() ?? "")) {
2926
+ end = index;
2927
+ break;
2928
+ }
2929
+ }
2930
+ return [
2931
+ ...lines.slice(0, start),
2932
+ footer.trimEnd(),
2933
+ ...lines.slice(end),
2934
+ ].join("\n");
2935
+ }
2936
+ return [
2937
+ finalOutputText.trimEnd(),
2938
+ "",
2939
+ footer,
2940
+ ].join("\n");
2941
+ }
2942
+ function appendFinalOutputProvenanceBindingsSection(finalOutputText, sectionBindings) {
2943
+ const heading = "## Runtime Provenance Bindings";
2944
+ const content = [
2945
+ heading,
2946
+ "",
2947
+ ...sectionBindings.flatMap((binding) => [
2948
+ `- ${binding.section_id}: ${binding.claim_summary}`,
2949
+ ` - section: ${binding.heading}`,
2950
+ ` - authority_refs: ${binding.authority_refs.join(", ")}`,
2951
+ ` - validation_refs: ${binding.validation_refs.join(", ")}`,
2952
+ ]),
2953
+ "",
2954
+ ].join("\n");
2955
+ if (!finalOutputText.includes(heading)) {
2956
+ return [
2957
+ finalOutputText.trimEnd(),
2958
+ "",
2959
+ content,
2960
+ ].join("\n");
2961
+ }
2962
+ const lines = finalOutputText.split(/\r?\n/);
2963
+ const start = lines.findIndex((line) => line.trim() === heading);
2964
+ if (start < 0)
2965
+ return finalOutputText;
2966
+ let end = lines.length;
2967
+ for (let index = start + 1; index < lines.length; index += 1) {
2968
+ if (/^##\s+/.test(lines[index]?.trim() ?? "")) {
2969
+ end = index;
2970
+ break;
2971
+ }
2972
+ }
2973
+ return [
2974
+ ...lines.slice(0, start),
2975
+ content.trimEnd(),
2976
+ ...lines.slice(end),
2977
+ ].join("\n");
2978
+ }
2979
+ function appendFinalOutputAnswerabilitySection(finalOutputText, ontologySeed) {
2980
+ if (finalOutputText.includes("## Seed Answerability"))
1743
2981
  return finalOutputText;
1744
2982
  return [
1745
2983
  finalOutputText.trimEnd(),
1746
2984
  "",
1747
- "## Runtime Artifact Truth Footer",
2985
+ "## Seed Answerability",
1748
2986
  "",
1749
- ...missing.map((fragment) => `- ${fragment}`),
2987
+ ...ontologySeedSummaryLines(ontologySeed),
1750
2988
  "",
1751
2989
  ].join("\n");
1752
2990
  }
2991
+ function appendFinalOutputArtifactTruthSection(finalOutputText, args) {
2992
+ const heading = "## Artifact Truth";
2993
+ const content = [
2994
+ heading,
2995
+ "",
2996
+ `- Ontology seed: ${args.ontologySeedPath}`,
2997
+ `- Ontology seed validation: ${args.ontologySeedValidationPath}`,
2998
+ `- Claim realization map: ${args.claimRealizationMapPath}`,
2999
+ `- Seed confirmation validation: ${args.seedConfirmationValidationPath}`,
3000
+ `- Competency question assessment: ${args.competencyQuestionAssessmentPath}`,
3001
+ `- Failure classification: ${args.failureClassificationPath}`,
3002
+ `- Revision proposal: ${args.revisionProposalPath}`,
3003
+ `- Pre-handoff run manifest: ${args.preHandoffManifestPath}`,
3004
+ `- Pre-handoff run manifest validation: ${args.preHandoffRunManifestValidationPath}`,
3005
+ `- Handoff decision validation: ${args.handoffDecisionValidationPath}`,
3006
+ `- Reconstruct record: ${args.recordPath}`,
3007
+ `- Reconstruct run manifest: ${args.manifestPath}`,
3008
+ "",
3009
+ ].join("\n");
3010
+ if (!finalOutputText.includes(heading)) {
3011
+ return [
3012
+ finalOutputText.trimEnd(),
3013
+ "",
3014
+ content,
3015
+ ].join("\n");
3016
+ }
3017
+ const lines = finalOutputText.split(/\r?\n/);
3018
+ const start = lines.findIndex((line) => line.trim() === heading);
3019
+ if (start < 0)
3020
+ return finalOutputText;
3021
+ let end = lines.length;
3022
+ for (let index = start + 1; index < lines.length; index += 1) {
3023
+ if (/^##\s+/.test(lines[index]?.trim() ?? "")) {
3024
+ end = index;
3025
+ break;
3026
+ }
3027
+ }
3028
+ return [
3029
+ ...lines.slice(0, start),
3030
+ content.trimEnd(),
3031
+ ...lines.slice(end),
3032
+ ].join("\n");
3033
+ }
3034
+ async function writeFinalOutputProvenanceValidationArtifact(args) {
3035
+ const finalOutputText = await fs.readFile(args.finalOutputPath, "utf8");
3036
+ const requiredFragments = [
3037
+ ...new Set(args.sectionBindings.flatMap((binding) => binding.required_fragments)),
3038
+ ];
3039
+ const violations = validateFinalOutputProvenance({
3040
+ finalOutputText,
3041
+ sectionBindings: args.sectionBindings,
3042
+ });
3043
+ const violationSubjects = new Set(violations.map((item) => item.subject_id).filter((item) => item !== null));
3044
+ const artifact = {
3045
+ schema_version: "1",
3046
+ session_id: args.sessionId,
3047
+ created_at: isoNow(),
3048
+ final_output_ref: args.finalOutputPath,
3049
+ validation_status: violations.length === 0 ? "valid" : "invalid",
3050
+ required_fragments: requiredFragments,
3051
+ section_bindings: args.sectionBindings.map((binding) => {
3052
+ const missing = binding.required_fragments.some((fragment) => violationSubjects.has(`${binding.section_id}:${fragment}`)) || violationSubjects.has(binding.section_id);
3053
+ return {
3054
+ section_id: binding.section_id,
3055
+ heading: binding.heading,
3056
+ claim_summary: binding.claim_summary,
3057
+ authority_refs: binding.authority_refs,
3058
+ validation_refs: binding.validation_refs,
3059
+ required_fragments: binding.required_fragments,
3060
+ binding_status: missing
3061
+ ? "missing"
3062
+ : "present",
3063
+ trust_status: missing
3064
+ ? "unbound"
3065
+ : "grounded",
3066
+ };
3067
+ }),
3068
+ validation_results: violations.length === 0
3069
+ ? ["final_output_provenance_valid"]
3070
+ : ["final_output_provenance_invalid"],
3071
+ violations,
3072
+ };
3073
+ await writeYamlDocument(args.outputPath, artifact);
3074
+ return artifact;
3075
+ }
3076
+ function finalOutputProvenanceSectionBindings(args) {
3077
+ return [
3078
+ {
3079
+ section_id: "seed-answerability",
3080
+ heading: "Seed Answerability",
3081
+ claim_summary: "Seed answerability is grounded in the seed and competency-question artifacts.",
3082
+ authority_refs: [args.ontologySeedPath, args.competencyQuestionsPath],
3083
+ validation_refs: [
3084
+ args.ontologySeedValidationPath,
3085
+ args.competencyQuestionsValidationPath,
3086
+ ],
3087
+ required_fragments: ["Ontology seed projected claims", "Coverage axes"],
3088
+ },
3089
+ {
3090
+ section_id: "artifact-truth",
3091
+ heading: "Artifact Truth",
3092
+ claim_summary: "Terminal artifact truth is grounded in the pre-handoff manifest validation, handoff readiness validation, final output provenance, and planned terminal record paths.",
3093
+ authority_refs: [args.recordPath, args.manifestPath, args.preHandoffManifestPath],
3094
+ validation_refs: [
3095
+ args.preHandoffRunManifestValidationPath,
3096
+ args.handoffDecisionValidationPath,
3097
+ args.finalOutputProvenanceValidationPath,
3098
+ ],
3099
+ required_fragments: [
3100
+ args.ontologySeedPath,
3101
+ args.ontologySeedValidationPath,
3102
+ args.claimRealizationMapPath,
3103
+ args.seedConfirmationValidationPath,
3104
+ args.competencyQuestionAssessmentPath,
3105
+ args.failureClassificationPath,
3106
+ args.revisionProposalPath,
3107
+ args.preHandoffManifestPath,
3108
+ args.preHandoffRunManifestValidationPath,
3109
+ args.handoffDecisionValidationPath,
3110
+ args.recordPath,
3111
+ args.manifestPath,
3112
+ ],
3113
+ },
3114
+ {
3115
+ section_id: "runtime-artifact-truth-footer",
3116
+ heading: "Runtime Artifact Truth Footer",
3117
+ claim_summary: "The runtime footer enumerates all required provenance fragments for audit.",
3118
+ authority_refs: [args.manifestPath, args.recordPath],
3119
+ validation_refs: [args.finalOutputProvenanceValidationPath],
3120
+ required_fragments: args.finalFragments,
3121
+ },
3122
+ {
3123
+ section_id: "runtime-provenance-bindings",
3124
+ heading: "Runtime Provenance Bindings",
3125
+ claim_summary: "The runtime-emitted provenance binding section lists section-to-authority bindings.",
3126
+ authority_refs: [args.finalOutputProvenanceValidationPath],
3127
+ validation_refs: [args.finalOutputProvenanceValidationPath],
3128
+ required_fragments: [
3129
+ "seed-answerability",
3130
+ "artifact-truth",
3131
+ "runtime-artifact-truth-footer",
3132
+ ],
3133
+ },
3134
+ ];
3135
+ }
1753
3136
  export async function runReconstruct(params) {
1754
3137
  const projectRoot = path.resolve(params.projectRoot);
1755
3138
  const sessionRoot = path.resolve(params.sessionRoot);
1756
3139
  const sessionId = path.basename(sessionRoot);
1757
3140
  const targetRefs = params.targetRefs.map((targetRef) => path.resolve(targetRef));
1758
3141
  const { directiveAuthor, confirmationProvider } = params;
3142
+ const reuseExistingAuthoredArtifacts = params.resumeMode === "reuse_existing_authored_artifacts";
3143
+ let currentAuthoredArtifactCompatibility = null;
3144
+ const writeAuthoredYamlDocument = (filePath, artifactName, create) => writeFreshAuthoredYamlDocument(filePath, artifactName, create, {
3145
+ reuseExisting: reuseExistingAuthoredArtifacts,
3146
+ ...(currentAuthoredArtifactCompatibility
3147
+ ? { compatibility: currentAuthoredArtifactCompatibility }
3148
+ : {}),
3149
+ });
1759
3150
  if (params.semanticAuthorRealization !== "mock" &&
1760
3151
  params.semanticAuthorRealization !== "direct_call") {
1761
3152
  throw new Error(`Unsupported reconstruct semanticAuthorRealization: ${params.semanticAuthorRealization}`);
@@ -1782,20 +3173,67 @@ export async function runReconstruct(params) {
1782
3173
  const targetMaterialProfile = await readYamlDocument(preparationRefs.target_material_profile);
1783
3174
  const sourceObservations = await readYamlDocument(preparationRefs.source_observations);
1784
3175
  const sourceInventory = await readYamlDocument(preparationRefs.source_inventory);
1785
- const sourceObservationDirectivePath = path.join(sessionRoot, "source-observation-directive.yaml");
1786
- const sourceObservationDirective = await directiveAuthor.writeSourceObservationDirective({
3176
+ const contractRegistryPath = reconstructContractRegistryPathFromProfilesRoot(params.profilesRoot);
3177
+ const contractRegistry = await loadReconstructContractRegistry({
3178
+ registryPath: contractRegistryPath,
3179
+ });
3180
+ const manifestPath = path.join(sessionRoot, "reconstruct-run-manifest.yaml");
3181
+ const targetMaterialProfileValidationPath = path.join(sessionRoot, "target-material-profile-validation.yaml");
3182
+ const targetMaterialProfileValidation = await writeTargetMaterialProfileValidationArtifact({
3183
+ targetMaterialProfilePath: preparationRefs.target_material_profile,
3184
+ registryPath: contractRegistryPath,
3185
+ outputPath: targetMaterialProfileValidationPath,
3186
+ });
3187
+ assertRuntimeValidationValid({
3188
+ artifactName: "target-material-profile",
3189
+ artifactRef: targetMaterialProfileValidationPath,
3190
+ validation: targetMaterialProfileValidation,
3191
+ });
3192
+ assertSemanticAuthoringHasObservedEvidence({
3193
+ targetMaterialProfile,
3194
+ sourceInventory,
3195
+ sourceObservations,
3196
+ });
3197
+ const lensIds = loadCoreLensRegistry().full_review_lens_ids;
3198
+ const governingSnapshot = await buildReconstructRunGoverningSnapshot({
3199
+ projectRoot,
3200
+ registryPath: contractRegistryPath,
3201
+ contractRegistry,
3202
+ selectedSourceProfiles: targetMaterialProfile.selected_source_profiles,
3203
+ lensIds,
3204
+ admittedDomainIds: params.domain ? [params.domain] : [],
3205
+ });
3206
+ currentAuthoredArtifactCompatibility = authoredArtifactCompatibility({
1787
3207
  sessionId,
1788
3208
  intent: params.intent,
3209
+ targetRefs,
1789
3210
  targetMaterialProfile,
3211
+ sourceInventory,
1790
3212
  sourceObservations,
3213
+ governingSnapshot,
3214
+ semanticAuthorRealization: params.semanticAuthorRealization,
3215
+ confirmationProviderRealization: params.confirmationProviderRealization,
3216
+ directiveAuthor,
3217
+ confirmationProvider,
1791
3218
  });
1792
- await writeYamlDocument(sourceObservationDirectivePath, sourceObservationDirective);
3219
+ const sourceObservationDirectivePath = path.join(sessionRoot, "source-observation-directive.yaml");
3220
+ const sourceObservationDirective = await writeAuthoredYamlDocument(sourceObservationDirectivePath, "source-observation-directive.yaml", () => directiveAuthor.writeSourceObservationDirective({
3221
+ sessionId,
3222
+ intent: params.intent,
3223
+ targetMaterialProfile,
3224
+ sourceObservations,
3225
+ }));
1793
3226
  const sourceObservationDirectiveValidationPath = path.join(sessionRoot, "source-observation-directive-validation.yaml");
1794
3227
  const sourceObservationDirectiveValidation = await writeSourceObservationDirectiveValidationArtifact({
1795
3228
  directivePath: sourceObservationDirectivePath,
1796
3229
  sourceObservationsPath: preparationRefs.source_observations,
1797
3230
  outputPath: sourceObservationDirectiveValidationPath,
1798
3231
  });
3232
+ assertRuntimeValidationValid({
3233
+ artifactName: "source-observation-directive",
3234
+ artifactRef: sourceObservationDirectiveValidationPath,
3235
+ validation: sourceObservationDirectiveValidation,
3236
+ });
1799
3237
  const roundId = "round-1";
1800
3238
  const roundRoot = path.join(sessionRoot, "rounds", roundId);
1801
3239
  const roundObservationDirectivePath = path.join(roundRoot, "source-observation-directive.yaml");
@@ -1803,7 +3241,6 @@ export async function runReconstruct(params) {
1803
3241
  await writeYamlDocument(roundObservationDirectivePath, sourceObservationDirective);
1804
3242
  await writeYamlDocument(roundObservationDirectiveValidationPath, sourceObservationDirectiveValidation);
1805
3243
  const lensJudgmentRoot = path.join(roundRoot, "lens-judgments");
1806
- const lensIds = loadCoreLensRegistry().full_review_lens_ids;
1807
3244
  const lensJudgments = [];
1808
3245
  const lensJudgmentRefs = [];
1809
3246
  for (const lensId of lensIds) {
@@ -1811,7 +3248,8 @@ export async function runReconstruct(params) {
1811
3248
  profilesRoot: path.resolve(params.profilesRoot),
1812
3249
  lensId,
1813
3250
  });
1814
- const lensJudgment = await directiveAuthor.writeLensJudgment({
3251
+ const lensJudgmentPath = path.join(lensJudgmentRoot, `${lensId}.yaml`);
3252
+ const lensJudgment = await writeAuthoredYamlDocument(lensJudgmentPath, `lens judgment ${lensId}`, () => directiveAuthor.writeLensJudgment({
1815
3253
  sessionId,
1816
3254
  intent: params.intent,
1817
3255
  roundId,
@@ -1820,9 +3258,7 @@ export async function runReconstruct(params) {
1820
3258
  sourceObservations,
1821
3259
  sourceObservationDirective,
1822
3260
  sourceObservationDirectiveRef: roundObservationDirectivePath,
1823
- });
1824
- const lensJudgmentPath = path.join(lensJudgmentRoot, `${lensId}.yaml`);
1825
- await writeYamlDocument(lensJudgmentPath, lensJudgment);
3261
+ }));
1826
3262
  lensJudgments.push(lensJudgment);
1827
3263
  lensJudgmentRefs.push({
1828
3264
  lens_id: lensId,
@@ -1839,23 +3275,25 @@ export async function runReconstruct(params) {
1839
3275
  };
1840
3276
  await writeYamlDocument(lensJudgmentIndexPath, lensJudgmentIndex);
1841
3277
  const explorationSynthesisPath = path.join(roundRoot, "exploration-synthesis.yaml");
1842
- const explorationSynthesis = await directiveAuthor.writeExplorationSynthesis({
3278
+ const explorationSynthesis = await writeAuthoredYamlDocument(explorationSynthesisPath, "exploration-synthesis.yaml", () => directiveAuthor.writeExplorationSynthesis({
1843
3279
  sessionId,
1844
3280
  intent: params.intent,
1845
3281
  roundId,
1846
3282
  lensJudgments,
1847
3283
  lensJudgmentIndexRef: lensJudgmentIndexPath,
1848
- });
1849
- await writeYamlDocument(explorationSynthesisPath, explorationSynthesis);
3284
+ sourceObservations,
3285
+ sourceObservationsRef: preparationRefs.source_observations,
3286
+ }));
1850
3287
  const sourceFrontierPath = path.join(roundRoot, "source-frontier.yaml");
1851
- const sourceFrontier = await directiveAuthor.writeSourceFrontier({
3288
+ const sourceFrontier = await writeAuthoredYamlDocument(sourceFrontierPath, "source-frontier.yaml", () => directiveAuthor.writeSourceFrontier({
1852
3289
  sessionId,
1853
3290
  intent: params.intent,
1854
3291
  roundId,
1855
3292
  explorationSynthesis,
1856
3293
  explorationSynthesisRef: explorationSynthesisPath,
1857
- });
1858
- await writeYamlDocument(sourceFrontierPath, sourceFrontier);
3294
+ sourceInventory,
3295
+ sourceObservations,
3296
+ }));
1859
3297
  const sourceFrontierValidationPath = path.join(roundRoot, "source-frontier-validation.yaml");
1860
3298
  const sourceFrontierValidation = validateSourceFrontier({
1861
3299
  sessionId,
@@ -1866,102 +3304,181 @@ export async function runReconstruct(params) {
1866
3304
  sourceInventoryRef: preparationRefs.source_inventory,
1867
3305
  sourceObservations,
1868
3306
  sourceObservationsRef: preparationRefs.source_observations,
3307
+ targetMaterialProfileValidation,
3308
+ targetMaterialProfileValidationRef: targetMaterialProfileValidationPath,
1869
3309
  });
1870
3310
  await writeYamlDocument(sourceFrontierValidationPath, sourceFrontierValidation);
1871
- const seedCandidatePath = path.join(sessionRoot, "seed-candidate.yaml");
1872
- const seedCandidate = await directiveAuthor.writeSeedCandidate({
3311
+ assertRuntimeValidationValid({
3312
+ artifactName: "source-frontier",
3313
+ artifactRef: sourceFrontierValidationPath,
3314
+ validation: sourceFrontierValidation,
3315
+ });
3316
+ if (sourceFrontierValidation.accepted_frontier_ref_ids.length > 0) {
3317
+ throw new Error([
3318
+ "source-frontier accepted new source refs, but this runner has no multi-round observation loop yet.",
3319
+ "Use no_next_frontier_rationale for terminal frontier or implement observation of accepted refs before semantic authoring.",
3320
+ `accepted_frontier_ref_ids=${sourceFrontierValidation.accepted_frontier_ref_ids.join(",")}`,
3321
+ ].join(" "));
3322
+ }
3323
+ const candidateInventoryPath = path.join(sessionRoot, "candidate-inventory.yaml");
3324
+ const candidateInventory = await writeAuthoredYamlDocument(candidateInventoryPath, "candidate-inventory.yaml", () => directiveAuthor.writeCandidateInventory({
1873
3325
  sessionId,
1874
3326
  intent: params.intent,
1875
3327
  sourceObservations,
3328
+ sourceObservationsRef: preparationRefs.source_observations,
1876
3329
  sourceObservationDirective,
1877
- sourceObservationDirectiveValidation,
1878
3330
  lensJudgmentIndex,
1879
3331
  explorationSynthesis,
1880
3332
  sourceFrontierValidation,
3333
+ contractRegistry,
3334
+ }));
3335
+ const candidateDispositionPath = path.join(sessionRoot, "candidate-disposition.yaml");
3336
+ const candidateDisposition = await writeAuthoredYamlDocument(candidateDispositionPath, "candidate-disposition.yaml", () => directiveAuthor.writeCandidateDisposition({
3337
+ sessionId,
3338
+ intent: params.intent,
3339
+ candidateInventory,
3340
+ candidateInventoryRef: candidateInventoryPath,
3341
+ sourceObservations,
3342
+ contractRegistry,
3343
+ }));
3344
+ const candidateDispositionValidationPath = path.join(sessionRoot, "candidate-disposition-validation.yaml");
3345
+ const candidateDispositionValidation = await writeCandidateDispositionValidationArtifact({
3346
+ candidateInventoryPath,
3347
+ candidateDispositionPath,
3348
+ sourceObservationsPath: preparationRefs.source_observations,
3349
+ registryPath: contractRegistryPath,
3350
+ outputPath: candidateDispositionValidationPath,
3351
+ });
3352
+ assertRuntimeValidationValid({
3353
+ artifactName: "candidate-disposition",
3354
+ artifactRef: candidateDispositionValidationPath,
3355
+ validation: candidateDispositionValidation,
1881
3356
  });
1882
- await writeYamlDocument(seedCandidatePath, seedCandidate);
1883
- const seedCandidateValidationPath = path.join(sessionRoot, "seed-candidate-validation.yaml");
1884
- const seedCandidateValidation = await writeSeedCandidateValidationArtifact({
1885
- seedCandidatePath,
3357
+ const ontologySeedPath = path.join(sessionRoot, "ontology-seed.yaml");
3358
+ const ontologySeed = await writeAuthoredYamlDocument(ontologySeedPath, "ontology-seed.yaml", () => directiveAuthor.writeOntologySeed({
3359
+ sessionId,
3360
+ intent: params.intent,
3361
+ targetMaterialProfile,
3362
+ candidateInventory,
3363
+ candidateInventoryRef: candidateInventoryPath,
3364
+ candidateDisposition,
3365
+ candidateDispositionRef: candidateDispositionPath,
3366
+ sourceObservations,
3367
+ sourceObservationsRef: preparationRefs.source_observations,
3368
+ contractRegistry,
3369
+ }));
3370
+ const ontologySeedValidationPath = path.join(sessionRoot, "ontology-seed-validation.yaml");
3371
+ const ontologySeedValidation = await writeActionableOntologySeedValidationArtifact({
3372
+ ontologySeedPath,
3373
+ candidateDispositionPath,
1886
3374
  sourceObservationsPath: preparationRefs.source_observations,
1887
- outputPath: seedCandidateValidationPath,
1888
- sourceObservationDirectivePath,
1889
- sourceObservationDirectiveValidationPath,
3375
+ registryPath: contractRegistryPath,
3376
+ outputPath: ontologySeedValidationPath,
3377
+ });
3378
+ assertRuntimeValidationValid({
3379
+ artifactName: "ontology-seed",
3380
+ artifactRef: ontologySeedValidationPath,
3381
+ validation: ontologySeedValidation,
1890
3382
  });
1891
3383
  const claimRealizationMapPath = path.join(sessionRoot, "claim-realization-map.yaml");
1892
- const claimRealizationMap = await directiveAuthor.writeClaimRealizationMap({
3384
+ const claimRealizationMap = await writeAuthoredYamlDocument(claimRealizationMapPath, "claim-realization-map.yaml", () => directiveAuthor.writeClaimRealizationMap({
1893
3385
  sessionId,
1894
- seedCandidate,
1895
- seedCandidateRef: seedCandidatePath,
3386
+ ontologySeed,
3387
+ ontologySeedRef: ontologySeedPath,
3388
+ ontologySeedValidation,
1896
3389
  sourceObservations,
1897
- });
1898
- await writeYamlDocument(claimRealizationMapPath, claimRealizationMap);
3390
+ }));
1899
3391
  const claimRealizationMapValidationPath = path.join(sessionRoot, "claim-realization-map-validation.yaml");
1900
- const claimRealizationMapValidation = await writeClaimRealizationMapValidationArtifact({
3392
+ const claimRealizationMapValidation = await writeClaimRealizationMapValidationForOntologySeedArtifact({
1901
3393
  claimRealizationMapPath,
1902
- seedCandidatePath,
3394
+ ontologySeedPath,
1903
3395
  sourceObservationsPath: preparationRefs.source_observations,
1904
3396
  outputPath: claimRealizationMapValidationPath,
1905
3397
  });
3398
+ assertRuntimeValidationValid({
3399
+ artifactName: "claim-realization-map",
3400
+ artifactRef: claimRealizationMapValidationPath,
3401
+ validation: claimRealizationMapValidation,
3402
+ });
1906
3403
  const seedConfirmationPath = path.join(sessionRoot, "seed-confirmation.yaml");
1907
- const seedConfirmation = await confirmationProvider.confirmSeedCandidate({
3404
+ const seedConfirmation = await writeAuthoredYamlDocument(seedConfirmationPath, "seed-confirmation.yaml", () => confirmationProvider.confirmOntologySeed({
1908
3405
  sessionId,
1909
- seedCandidate,
1910
- seedCandidateRef: seedCandidatePath,
1911
- seedCandidateValidation,
1912
- seedCandidateValidationRef: seedCandidateValidationPath,
1913
- });
1914
- await writeYamlDocument(seedConfirmationPath, seedConfirmation);
3406
+ ontologySeed,
3407
+ ontologySeedRef: ontologySeedPath,
3408
+ ontologySeedValidation,
3409
+ ontologySeedValidationRef: ontologySeedValidationPath,
3410
+ }));
1915
3411
  const seedConfirmationValidationPath = path.join(sessionRoot, "seed-confirmation-validation.yaml");
1916
- const seedConfirmationValidation = await writeSeedConfirmationValidationArtifact({
3412
+ const seedConfirmationValidation = await writeSeedConfirmationValidationForOntologySeedArtifact({
1917
3413
  seedConfirmationPath,
1918
- seedCandidatePath,
1919
- seedCandidateValidationPath,
3414
+ ontologySeedPath,
3415
+ ontologySeedValidationPath,
1920
3416
  outputPath: seedConfirmationValidationPath,
1921
3417
  });
3418
+ assertRuntimeValidationValid({
3419
+ artifactName: "seed-confirmation",
3420
+ artifactRef: seedConfirmationValidationPath,
3421
+ validation: seedConfirmationValidation,
3422
+ });
1922
3423
  const competencyQuestionsPath = path.join(sessionRoot, "competency-questions.yaml");
1923
- const competencyQuestions = await directiveAuthor.writeCompetencyQuestions({
3424
+ const competencyQuestions = await writeAuthoredYamlDocument(competencyQuestionsPath, "competency-questions.yaml", () => directiveAuthor.writeCompetencyQuestions({
1924
3425
  sessionId,
1925
- seedCandidate,
1926
- seedConfirmation,
1927
- seedConfirmationRef: seedConfirmationPath,
3426
+ ontologySeed,
3427
+ ontologySeedRef: ontologySeedPath,
3428
+ ontologySeedValidation,
1928
3429
  seedConfirmationValidation,
1929
3430
  seedConfirmationValidationRef: seedConfirmationValidationPath,
1930
3431
  claimRealizationMap,
1931
- });
1932
- await writeYamlDocument(competencyQuestionsPath, competencyQuestions);
3432
+ sourceObservations,
3433
+ sourceObservationsRef: preparationRefs.source_observations,
3434
+ contractRegistry,
3435
+ governingSnapshot,
3436
+ }));
1933
3437
  const competencyQuestionsValidationPath = path.join(sessionRoot, "competency-questions-validation.yaml");
1934
- const competencyQuestionsValidation = await writeCompetencyQuestionsValidationArtifact({
3438
+ const competencyQuestionsValidation = await writeCompetencyQuestionsValidationForOntologySeedArtifact({
1935
3439
  competencyQuestionsPath,
3440
+ ontologySeedPath,
3441
+ ontologySeedValidationPath,
1936
3442
  seedConfirmationValidationPath,
1937
3443
  sourceObservationsPath: preparationRefs.source_observations,
3444
+ registryPath: contractRegistryPath,
3445
+ reconstructRunManifestPath: manifestPath,
3446
+ governingSnapshot,
1938
3447
  outputPath: competencyQuestionsValidationPath,
1939
3448
  });
3449
+ assertRuntimeValidationValid({
3450
+ artifactName: "competency-questions",
3451
+ artifactRef: competencyQuestionsValidationPath,
3452
+ validation: competencyQuestionsValidation,
3453
+ });
1940
3454
  const competencyQuestionAssessmentPath = path.join(sessionRoot, "competency-question-assessment.yaml");
1941
- const competencyQuestionAssessment = await directiveAuthor.writeCompetencyQuestionAssessment({
3455
+ const competencyQuestionAssessment = await writeAuthoredYamlDocument(competencyQuestionAssessmentPath, "competency-question-assessment.yaml", () => directiveAuthor.writeCompetencyQuestionAssessment({
1942
3456
  sessionId,
1943
3457
  competencyQuestions,
1944
3458
  competencyQuestionsRef: competencyQuestionsPath,
1945
3459
  competencyQuestionsValidation,
1946
3460
  competencyQuestionsValidationRef: competencyQuestionsValidationPath,
1947
3461
  claimRealizationMap,
1948
- });
1949
- await writeYamlDocument(competencyQuestionAssessmentPath, competencyQuestionAssessment);
3462
+ }));
1950
3463
  const competencyQuestionAssessmentValidationPath = path.join(sessionRoot, "competency-question-assessment-validation.yaml");
1951
3464
  const competencyQuestionAssessmentValidation = await writeCompetencyQuestionAssessmentValidationArtifact({
1952
3465
  competencyQuestionAssessmentPath,
1953
3466
  competencyQuestionsPath,
1954
3467
  outputPath: competencyQuestionAssessmentValidationPath,
1955
3468
  });
3469
+ assertRuntimeValidationValid({
3470
+ artifactName: "competency-question-assessment",
3471
+ artifactRef: competencyQuestionAssessmentValidationPath,
3472
+ validation: competencyQuestionAssessmentValidation,
3473
+ });
1956
3474
  const failureClassificationPath = path.join(sessionRoot, "failure-classification.yaml");
1957
- const failureClassification = await directiveAuthor.writeFailureClassification({
3475
+ const failureClassification = await writeAuthoredYamlDocument(failureClassificationPath, "failure-classification.yaml", () => directiveAuthor.writeFailureClassification({
1958
3476
  sessionId,
1959
3477
  competencyQuestionAssessment,
1960
3478
  competencyQuestionAssessmentRef: competencyQuestionAssessmentPath,
1961
3479
  competencyQuestionAssessmentValidation,
1962
3480
  seedConfirmationValidation,
1963
- });
1964
- await writeYamlDocument(failureClassificationPath, failureClassification);
3481
+ }));
1965
3482
  const failureClassificationValidationPath = path.join(sessionRoot, "failure-classification-validation.yaml");
1966
3483
  const failureClassificationValidation = await writeFailureClassificationValidationArtifact({
1967
3484
  failureClassificationPath,
@@ -1969,26 +3486,38 @@ export async function runReconstruct(params) {
1969
3486
  seedConfirmationValidationPath,
1970
3487
  outputPath: failureClassificationValidationPath,
1971
3488
  });
3489
+ assertRuntimeValidationValid({
3490
+ artifactName: "failure-classification",
3491
+ artifactRef: failureClassificationValidationPath,
3492
+ validation: failureClassificationValidation,
3493
+ });
1972
3494
  const revisionProposalPath = path.join(sessionRoot, "revision-proposal.yaml");
1973
- const revisionProposal = await directiveAuthor.writeRevisionProposal({
3495
+ const revisionProposal = await writeAuthoredYamlDocument(revisionProposalPath, "revision-proposal.yaml", () => directiveAuthor.writeRevisionProposal({
1974
3496
  sessionId,
1975
3497
  failureClassification,
1976
3498
  failureClassificationRef: failureClassificationPath,
1977
3499
  failureClassificationValidation,
1978
- });
1979
- await writeYamlDocument(revisionProposalPath, revisionProposal);
3500
+ }));
1980
3501
  const revisionProposalValidationPath = path.join(sessionRoot, "revision-proposal-validation.yaml");
1981
3502
  const revisionProposalValidation = await writeRevisionProposalValidationArtifact({
1982
3503
  revisionProposalPath,
1983
3504
  failureClassificationPath,
1984
3505
  outputPath: revisionProposalValidationPath,
1985
3506
  });
3507
+ assertRuntimeValidationValid({
3508
+ artifactName: "revision-proposal",
3509
+ artifactRef: revisionProposalValidationPath,
3510
+ validation: revisionProposalValidation,
3511
+ });
1986
3512
  const metricsPath = path.join(sessionRoot, "reconstruct-metrics.yaml");
1987
3513
  const metrics = calculateMetrics({
1988
3514
  sessionId,
1989
3515
  sourceObservations,
3516
+ targetMaterialProfileValidation,
1990
3517
  sourceObservationDirectiveValidation,
1991
- seedCandidateValidation,
3518
+ candidateDispositionValidation,
3519
+ ontologySeed,
3520
+ ontologySeedValidation,
1992
3521
  claimRealizationMapValidation,
1993
3522
  seedConfirmation,
1994
3523
  seedConfirmationValidation,
@@ -2000,21 +3529,26 @@ export async function runReconstruct(params) {
2000
3529
  });
2001
3530
  await writeYamlDocument(metricsPath, metrics);
2002
3531
  const stopDecisionPath = path.join(sessionRoot, "stop-decision.yaml");
2003
- const stopDecision = await directiveAuthor.writeStopDecision({
3532
+ const stopDecision = await writeAuthoredYamlDocument(stopDecisionPath, "stop-decision.yaml", () => directiveAuthor.writeStopDecision({
2004
3533
  sessionId,
2005
3534
  intent: params.intent,
2006
3535
  metrics,
2007
3536
  metricsRef: metricsPath,
2008
3537
  failureClassification,
2009
3538
  revisionProposal,
2010
- });
2011
- await writeYamlDocument(stopDecisionPath, stopDecision);
3539
+ }));
2012
3540
  const finalOutputPath = path.join(sessionRoot, "final-output.md");
2013
- const manifestPath = path.join(sessionRoot, "reconstruct-run-manifest.yaml");
3541
+ const finalOutputProvenanceValidationPath = path.join(sessionRoot, "final-output-provenance-validation.yaml");
3542
+ const preHandoffManifestPath = path.join(sessionRoot, "reconstruct-run-manifest.pre-handoff.yaml");
3543
+ const preHandoffRunManifestValidationPath = path.join(sessionRoot, "reconstruct-run-manifest.pre-handoff-validation.yaml");
3544
+ const postPublicationRunManifestValidationPath = path.join(sessionRoot, "reconstruct-run-manifest.post-publication-validation.yaml");
3545
+ const handoffDecisionValidationPath = path.join(sessionRoot, "handoff-decision-validation.yaml");
2014
3546
  const recordPath = path.join(sessionRoot, "reconstruct-record.yaml");
3547
+ const prePublicationRecordPath = path.join(sessionRoot, "reconstruct-record.pre-publication.yaml");
2015
3548
  const artifactRefs = artifactRefsWithDefaults({
2016
3549
  refs: {
2017
3550
  target_material_profile: preparationRefs.target_material_profile,
3551
+ target_material_profile_validation: targetMaterialProfileValidationPath,
2018
3552
  source_inventory: preparationRefs.source_inventory,
2019
3553
  initial_source_frontier: preparationRefs.initial_source_frontier,
2020
3554
  source_observations: preparationRefs.source_observations,
@@ -2024,8 +3558,11 @@ export async function runReconstruct(params) {
2024
3558
  exploration_synthesis: explorationSynthesisPath,
2025
3559
  source_frontier: sourceFrontierPath,
2026
3560
  source_frontier_validation: sourceFrontierValidationPath,
2027
- seed_candidate: seedCandidatePath,
2028
- seed_candidate_validation: seedCandidateValidationPath,
3561
+ candidate_inventory: candidateInventoryPath,
3562
+ candidate_disposition: candidateDispositionPath,
3563
+ candidate_disposition_validation: candidateDispositionValidationPath,
3564
+ ontology_seed: ontologySeedPath,
3565
+ ontology_seed_validation: ontologySeedValidationPath,
2029
3566
  claim_realization_map: claimRealizationMapPath,
2030
3567
  claim_realization_map_validation: claimRealizationMapValidationPath,
2031
3568
  seed_confirmation: seedConfirmationPath,
@@ -2040,11 +3577,26 @@ export async function runReconstruct(params) {
2040
3577
  revision_proposal_validation: revisionProposalValidationPath,
2041
3578
  reconstruct_metrics: metricsPath,
2042
3579
  stop_decision: stopDecisionPath,
3580
+ pre_handoff_run_manifest_validation: preHandoffRunManifestValidationPath,
3581
+ post_publication_run_manifest_validation: postPublicationRunManifestValidationPath,
3582
+ handoff_decision_validation: handoffDecisionValidationPath,
2043
3583
  final_output: finalOutputPath,
3584
+ final_output_provenance_validation: finalOutputProvenanceValidationPath,
2044
3585
  reconstruct_run_manifest: manifestPath,
2045
3586
  },
2046
3587
  });
2047
- const reconstructRunManifest = createRunManifest({
3588
+ const preHandoffArtifactRefs = artifactRefsWithDefaults({
3589
+ refs: {
3590
+ ...artifactRefs,
3591
+ pre_handoff_run_manifest_validation: preHandoffRunManifestValidationPath,
3592
+ post_publication_run_manifest_validation: null,
3593
+ handoff_decision_validation: null,
3594
+ final_output: null,
3595
+ final_output_provenance_validation: null,
3596
+ reconstruct_run_manifest: preHandoffManifestPath,
3597
+ },
3598
+ });
3599
+ const preHandoffRunManifest = createRunManifest({
2048
3600
  sessionId,
2049
3601
  targetRefs,
2050
3602
  intent: params.intent,
@@ -2052,20 +3604,63 @@ export async function runReconstruct(params) {
2052
3604
  confirmationProviderRealization: params.confirmationProviderRealization,
2053
3605
  directiveAuthor,
2054
3606
  confirmationProvider,
2055
- artifactRefs,
3607
+ artifactRefs: preHandoffArtifactRefs,
2056
3608
  reconstructRecordPath: recordPath,
3609
+ governingSnapshot,
3610
+ terminalArtifactsCompleted: false,
3611
+ });
3612
+ await writeYamlDocument(preHandoffManifestPath, preHandoffRunManifest);
3613
+ const preHandoffRunManifestValidation = await writeReconstructRunManifestValidationArtifact({
3614
+ manifestPath: preHandoffManifestPath,
3615
+ projectRoot,
3616
+ registryPath: contractRegistryPath,
3617
+ targetMaterialProfilePath: preparationRefs.target_material_profile,
3618
+ lensIds,
3619
+ admittedDomainIds: params.domain ? [params.domain] : [],
3620
+ outputPath: preHandoffRunManifestValidationPath,
3621
+ });
3622
+ assertRuntimeValidationValid({
3623
+ artifactName: "reconstruct-run-manifest",
3624
+ artifactRef: preHandoffRunManifestValidationPath,
3625
+ validation: preHandoffRunManifestValidation,
3626
+ });
3627
+ const handoffDecisionValidation = await writeHandoffDecisionValidationArtifact({
3628
+ stopDecisionPath,
3629
+ manifestValidationPath: preHandoffRunManifestValidationPath,
3630
+ metricsPath,
3631
+ targetMaterialProfileValidationPath,
3632
+ sourceObservationDirectiveValidationPath,
3633
+ sourceFrontierValidationPath,
3634
+ candidateDispositionValidationPath,
3635
+ ontologySeedValidationPath,
3636
+ claimRealizationMapValidationPath,
3637
+ competencyQuestionsValidationPath,
3638
+ competencyQuestionAssessmentValidationPath,
3639
+ seedConfirmationValidationPath,
3640
+ failureClassificationValidationPath,
3641
+ revisionProposalValidationPath,
3642
+ registryPath: contractRegistryPath,
3643
+ outputPath: handoffDecisionValidationPath,
3644
+ });
3645
+ assertRuntimeValidationValid({
3646
+ artifactName: "handoff-decision",
3647
+ artifactRef: handoffDecisionValidationPath,
3648
+ validation: handoffDecisionValidation,
2057
3649
  });
2058
- await writeYamlDocument(manifestPath, reconstructRunManifest);
2059
3650
  const interimRecord = await assembleReconstructRecord({
2060
3651
  sessionRoot,
2061
3652
  artifactRefs,
2062
- outputPath: recordPath,
3653
+ outputPath: prePublicationRecordPath,
2063
3654
  });
2064
3655
  const authoredFinalOutputText = await directiveAuthor.writeFinalOutput({
2065
3656
  sessionId,
2066
3657
  intent: params.intent,
2067
3658
  targetMaterialProfile,
2068
- seedCandidate,
3659
+ candidateInventory,
3660
+ candidateDisposition,
3661
+ candidateDispositionValidation,
3662
+ ontologySeed,
3663
+ ontologySeedValidation,
2069
3664
  claimRealizationMap,
2070
3665
  claimRealizationMapValidation,
2071
3666
  seedConfirmation,
@@ -2080,35 +3675,134 @@ export async function runReconstruct(params) {
2080
3675
  revisionProposalValidation,
2081
3676
  metrics,
2082
3677
  stopDecision,
3678
+ preHandoffRunManifestValidation,
3679
+ handoffDecisionValidation,
2083
3680
  sourceObservations,
2084
3681
  artifactRefs,
2085
3682
  reconstructRecordPath: recordPath,
2086
- reconstructRunManifestPath: manifestPath,
2087
- reconstructRunManifest,
3683
+ reconstructRunManifestPath: preHandoffManifestPath,
3684
+ reconstructRunManifest: preHandoffRunManifest,
2088
3685
  record: interimRecord,
2089
3686
  });
2090
3687
  const requiredFinalOutputFragments = [
2091
3688
  recordPath,
2092
3689
  manifestPath,
2093
- seedCandidatePath,
3690
+ candidateInventoryPath,
3691
+ candidateDispositionPath,
3692
+ candidateDispositionValidationPath,
3693
+ ontologySeedPath,
3694
+ ontologySeedValidationPath,
2094
3695
  claimRealizationMapPath,
2095
3696
  seedConfirmationValidationPath,
2096
3697
  competencyQuestionAssessmentPath,
2097
3698
  failureClassificationPath,
2098
3699
  revisionProposalPath,
3700
+ preHandoffManifestPath,
3701
+ preHandoffRunManifestValidationPath,
3702
+ handoffDecisionValidationPath,
3703
+ finalOutputProvenanceValidationPath,
3704
+ preHandoffRunManifestValidation.validation_status,
3705
+ handoffDecisionValidation.readiness_projection,
3706
+ handoffDecisionValidation.validation_status,
2099
3707
  ...seedConfirmationValidation.accepted_claim_ids,
3708
+ ...candidateDispositionValidation.violations.map((violation) => violation.code),
3709
+ ...ontologySeedValidation.violations.map((violation) => violation.code),
2100
3710
  ...failureClassification.failures.map((failure) => failure.failure_id),
2101
3711
  ...revisionProposal.proposals.map((proposal) => proposal.proposal_id),
2102
3712
  ];
2103
- const finalOutputText = appendFinalOutputProvenanceFooter(authoredFinalOutputText, requiredFinalOutputFragments);
3713
+ const requiredFinalOutputSectionBindings = finalOutputProvenanceSectionBindings({
3714
+ ontologySeedPath,
3715
+ ontologySeedValidationPath,
3716
+ claimRealizationMapPath,
3717
+ claimRealizationMapValidationPath,
3718
+ seedConfirmationValidationPath,
3719
+ competencyQuestionsPath,
3720
+ competencyQuestionsValidationPath,
3721
+ competencyQuestionAssessmentPath,
3722
+ competencyQuestionAssessmentValidationPath,
3723
+ failureClassificationPath,
3724
+ failureClassificationValidationPath,
3725
+ revisionProposalPath,
3726
+ revisionProposalValidationPath,
3727
+ metricsPath,
3728
+ stopDecisionPath,
3729
+ preHandoffManifestPath,
3730
+ preHandoffRunManifestValidationPath,
3731
+ handoffDecisionValidationPath,
3732
+ recordPath,
3733
+ manifestPath,
3734
+ finalOutputProvenanceValidationPath,
3735
+ finalFragments: requiredFinalOutputFragments,
3736
+ });
3737
+ const finalOutputWithAnswerability = appendFinalOutputAnswerabilitySection(authoredFinalOutputText, ontologySeed);
3738
+ const finalOutputWithArtifactTruth = appendFinalOutputArtifactTruthSection(finalOutputWithAnswerability, {
3739
+ ontologySeedPath,
3740
+ ontologySeedValidationPath,
3741
+ claimRealizationMapPath,
3742
+ seedConfirmationValidationPath,
3743
+ competencyQuestionAssessmentPath,
3744
+ failureClassificationPath,
3745
+ revisionProposalPath,
3746
+ preHandoffManifestPath,
3747
+ preHandoffRunManifestValidationPath,
3748
+ handoffDecisionValidationPath,
3749
+ recordPath,
3750
+ manifestPath,
3751
+ });
3752
+ let finalOutputText = appendFinalOutputProvenanceFooter(finalOutputWithArtifactTruth, requiredFinalOutputFragments);
3753
+ finalOutputText = appendFinalOutputProvenanceBindingsSection(finalOutputText, requiredFinalOutputSectionBindings);
2104
3754
  const finalOutputViolations = validateFinalOutputProvenance({
2105
3755
  finalOutputText,
2106
- requiredFragments: requiredFinalOutputFragments,
3756
+ sectionBindings: requiredFinalOutputSectionBindings,
2107
3757
  });
2108
3758
  if (finalOutputViolations.length > 0) {
2109
3759
  throw new Error(`final-output.md failed provenance validation: ${finalOutputViolations.map((item) => item.message).join("; ")}`);
2110
3760
  }
2111
3761
  await fs.writeFile(finalOutputPath, finalOutputText, "utf8");
3762
+ const finalOutputProvenanceValidation = await writeFinalOutputProvenanceValidationArtifact({
3763
+ sessionId,
3764
+ finalOutputPath,
3765
+ sectionBindings: requiredFinalOutputSectionBindings,
3766
+ outputPath: finalOutputProvenanceValidationPath,
3767
+ });
3768
+ assertRuntimeValidationValid({
3769
+ artifactName: "final-output-provenance",
3770
+ artifactRef: finalOutputProvenanceValidationPath,
3771
+ validation: finalOutputProvenanceValidation,
3772
+ });
3773
+ await assembleReconstructRecord({
3774
+ sessionRoot,
3775
+ artifactRefs,
3776
+ outputPath: recordPath,
3777
+ });
3778
+ const reconstructRunManifest = createRunManifest({
3779
+ sessionId,
3780
+ targetRefs,
3781
+ intent: params.intent,
3782
+ semanticAuthorRealization: params.semanticAuthorRealization,
3783
+ confirmationProviderRealization: params.confirmationProviderRealization,
3784
+ directiveAuthor,
3785
+ confirmationProvider,
3786
+ artifactRefs,
3787
+ reconstructRecordPath: recordPath,
3788
+ governingSnapshot,
3789
+ terminalArtifactsCompleted: true,
3790
+ });
3791
+ await writeYamlDocument(manifestPath, reconstructRunManifest);
3792
+ const postPublicationRunManifestValidation = await writeReconstructRunManifestValidationArtifact({
3793
+ manifestPath,
3794
+ projectRoot,
3795
+ registryPath: contractRegistryPath,
3796
+ targetMaterialProfilePath: preparationRefs.target_material_profile,
3797
+ lensIds,
3798
+ admittedDomainIds: params.domain ? [params.domain] : [],
3799
+ outputPath: postPublicationRunManifestValidationPath,
3800
+ });
3801
+ assertRuntimeValidationValid({
3802
+ artifactName: "reconstruct-run-manifest",
3803
+ artifactRef: postPublicationRunManifestValidationPath,
3804
+ validation: postPublicationRunManifestValidation,
3805
+ });
2112
3806
  const finalRecord = await assembleReconstructRecord({
2113
3807
  sessionRoot,
2114
3808
  artifactRefs,