@mnstry/atelier 0.2.0-alpha.12 → 0.2.0-alpha.13

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 (516) hide show
  1. package/CHANGELOG.md +661 -0
  2. package/README.md +142 -6
  3. package/contracts/atelier-adoption-policy.v2.schema.json +55 -0
  4. package/contracts/atelier-architecture.v1.schema.json +258 -0
  5. package/contracts/atelier-boundary-delegations.v1.schema.json +161 -0
  6. package/contracts/atelier-boundary-owner-keys.v1.schema.json +98 -0
  7. package/contracts/atelier-build.v1.schema.json +1076 -0
  8. package/contracts/atelier-capability.v1.schema.json +1252 -0
  9. package/contracts/atelier-coordination.v1.schema.json +1050 -0
  10. package/contracts/atelier-evidence-navigation.v1.schema.json +603 -0
  11. package/contracts/atelier-harness.v1.schema.json +234 -0
  12. package/contracts/atelier-ingestion.v1.schema.json +806 -0
  13. package/contracts/atelier-inquiry.v1.schema.json +1772 -0
  14. package/contracts/atelier-instruction-adoption.v1.schema.json +490 -0
  15. package/contracts/atelier-interaction.v1.schema.json +553 -0
  16. package/contracts/atelier-judgment.v1.schema.json +690 -0
  17. package/contracts/atelier-knowledge.v1.schema.json +1512 -0
  18. package/contracts/atelier-learning.v1.schema.json +1095 -0
  19. package/contracts/atelier-migration.v3.schema.json +64 -0
  20. package/contracts/atelier-personal-workspace-manifest.v1.schema.json +87 -0
  21. package/contracts/atelier-personal-workspace-overlay.v1.schema.json +299 -0
  22. package/contracts/atelier-template-adoption.v1.schema.json +223 -0
  23. package/contracts/atelier-template-profile.v1.schema.json +1168 -0
  24. package/contracts/atelier-trackable.v1.schema.json +781 -0
  25. package/contracts/atelier-upgrade-plan.v3.schema.json +532 -0
  26. package/docs/architecture.md +89 -0
  27. package/docs/assurance-controls.md +2 -2
  28. package/docs/blocks/capability-stewardship.md +17 -0
  29. package/docs/blocks/claims.md +16 -3
  30. package/docs/blocks/inquiry-harnesses.md +19 -0
  31. package/docs/blocks/learning-harnesses.md +17 -0
  32. package/docs/capability-stewardship.md +269 -0
  33. package/docs/coordination.md +51 -0
  34. package/docs/decision-practices.md +111 -0
  35. package/docs/decisions.md +29 -0
  36. package/docs/evidence-navigation.md +237 -0
  37. package/docs/exact-upgrades.md +3 -2
  38. package/docs/ingestion.md +181 -0
  39. package/docs/inquiry-harnesses.md +211 -0
  40. package/docs/install.md +80 -3
  41. package/docs/intake-and-guides.md +5 -0
  42. package/docs/integration-contract-decisions.md +24 -2
  43. package/docs/interaction-and-reflection.md +72 -0
  44. package/docs/knowledge-graph.md +20 -0
  45. package/docs/knowledge-health/api.md +30 -0
  46. package/docs/knowledge-health/assessment/api.md +96 -0
  47. package/docs/knowledge-health/assessment/capabilities.md +40 -0
  48. package/docs/knowledge-health/assessment/evaluation.md +27 -0
  49. package/docs/knowledge-health/assessment/facilitator.md +30 -0
  50. package/docs/knowledge-health/assessment/quickstart.md +61 -0
  51. package/docs/knowledge-health/assessment/troubleshooting.md +23 -0
  52. package/docs/knowledge-health/devday/facilitator.md +16 -0
  53. package/docs/knowledge-health/devday/participant-response.md +22 -0
  54. package/docs/knowledge-health/devday/public-default.md +107 -0
  55. package/docs/knowledge-health/devday/quickstart.md +18 -0
  56. package/docs/knowledge-health/devday/support.md +22 -0
  57. package/docs/knowledge-health/exercise.md +17 -0
  58. package/docs/knowledge-health/facilitator.md +20 -0
  59. package/docs/knowledge-health/quickstart.md +94 -0
  60. package/docs/knowledge-health/readme.md +15 -0
  61. package/docs/knowledge-health/support.md +34 -0
  62. package/docs/knowledge-setup.md +248 -0
  63. package/docs/knowledge-workspace.md +264 -0
  64. package/docs/learning-harnesses.md +238 -0
  65. package/docs/learning.md +215 -0
  66. package/docs/local-services.md +181 -16
  67. package/docs/obsidian-contract.md +223 -15
  68. package/docs/obsidian-plugin.md +38 -4
  69. package/docs/obsidian.md +613 -51
  70. package/docs/optional-ingestion.md +83 -0
  71. package/docs/personal-workspace.md +257 -0
  72. package/docs/practical-judgment.md +92 -0
  73. package/docs/progressive-ingestion-acceptance.md +89 -0
  74. package/docs/progressive-ingestion.md +235 -0
  75. package/docs/project-command-inventory.md +1 -0
  76. package/docs/release-engineering.md +49 -0
  77. package/docs/repo-boundary-guard.md +94 -0
  78. package/docs/research-starter-quickstart.md +66 -0
  79. package/docs/research-starter.md +114 -0
  80. package/docs/semantic-ingestion.md +198 -0
  81. package/docs/semantic-operation.md +317 -0
  82. package/docs/skill-steward.md +6 -0
  83. package/docs/template-profile.md +164 -0
  84. package/docs/template-upgrades.md +114 -0
  85. package/docs/trackables.md +111 -0
  86. package/docs/upgrade.md +47 -2
  87. package/fixtures/atelier-architecture/binding/invalid/document.json +19 -0
  88. package/fixtures/atelier-architecture/binding/valid/document.json +19 -0
  89. package/fixtures/atelier-architecture/catalog/invalid/document.json +290 -0
  90. package/fixtures/atelier-architecture/catalog/valid/document.json +343 -0
  91. package/fixtures/atelier-build-contract/attempt/invalid/document.json +20 -0
  92. package/fixtures/atelier-build-contract/attempt/valid/document.json +19 -0
  93. package/fixtures/atelier-build-contract/candidate/invalid/document.json +24 -0
  94. package/fixtures/atelier-build-contract/candidate/valid/document.json +23 -0
  95. package/fixtures/atelier-build-contract/decision/invalid/document.json +31 -0
  96. package/fixtures/atelier-build-contract/decision/valid/document.json +30 -0
  97. package/fixtures/atelier-build-contract/delivery/invalid/document.json +18 -0
  98. package/fixtures/atelier-build-contract/delivery/valid/document.json +17 -0
  99. package/fixtures/atelier-build-contract/gate/invalid/document.json +22 -0
  100. package/fixtures/atelier-build-contract/gate/valid/document.json +21 -0
  101. package/fixtures/atelier-build-contract/ledger/invalid/document.json +270 -0
  102. package/fixtures/atelier-build-contract/ledger/valid/document.json +269 -0
  103. package/fixtures/atelier-build-contract/objective/invalid/document.json +73 -0
  104. package/fixtures/atelier-build-contract/objective/valid/document.json +72 -0
  105. package/fixtures/atelier-build-contract/progress/invalid/document.json +18 -0
  106. package/fixtures/atelier-build-contract/progress/valid/document.json +17 -0
  107. package/fixtures/atelier-capability-contract/adoption/invalid/document.json +71 -0
  108. package/fixtures/atelier-capability-contract/adoption/valid/document.json +70 -0
  109. package/fixtures/atelier-capability-contract/event/invalid/document.json +18 -0
  110. package/fixtures/atelier-capability-contract/event/valid/document.json +17 -0
  111. package/fixtures/atelier-capability-contract/journal/invalid/document.json +382 -0
  112. package/fixtures/atelier-capability-contract/journal/valid/document.json +381 -0
  113. package/fixtures/atelier-capability-contract/notice/invalid/document.json +8 -0
  114. package/fixtures/atelier-capability-contract/notice/valid/document.json +7 -0
  115. package/fixtures/atelier-capability-contract/package/invalid/document.json +59 -0
  116. package/fixtures/atelier-capability-contract/package/valid/document.json +58 -0
  117. package/fixtures/atelier-capability-contract/plan/invalid/document.json +107 -0
  118. package/fixtures/atelier-capability-contract/plan/valid/document.json +106 -0
  119. package/fixtures/atelier-capability-contract/release/invalid/document.json +85 -0
  120. package/fixtures/atelier-capability-contract/release/valid/document.json +84 -0
  121. package/fixtures/atelier-capability-contract/state/invalid/document.json +316 -0
  122. package/fixtures/atelier-capability-contract/state/valid/document.json +315 -0
  123. package/fixtures/atelier-coordination/dependency/invalid/document.json +37 -0
  124. package/fixtures/atelier-coordination/dependency/valid/document.json +36 -0
  125. package/fixtures/atelier-coordination/directive/invalid/document.json +25 -0
  126. package/fixtures/atelier-coordination/directive/valid/document.json +24 -0
  127. package/fixtures/atelier-coordination/disposition/invalid/document.json +34 -0
  128. package/fixtures/atelier-coordination/disposition/valid/document.json +33 -0
  129. package/fixtures/atelier-coordination/outcome/invalid/document.json +39 -0
  130. package/fixtures/atelier-coordination/outcome/valid/document.json +38 -0
  131. package/fixtures/atelier-coordination/recovery/invalid/document.json +34 -0
  132. package/fixtures/atelier-coordination/recovery/valid/document.json +33 -0
  133. package/fixtures/atelier-harness-contract/handoff/invalid/document.json +25 -0
  134. package/fixtures/atelier-harness-contract/handoff/valid/document.json +24 -0
  135. package/fixtures/atelier-ingestion/invalid/authority.json +19 -0
  136. package/fixtures/atelier-ingestion/semantic-baseline.json +26 -0
  137. package/fixtures/atelier-ingestion/semantic-operation.json +75 -0
  138. package/fixtures/atelier-ingestion/valid/plan-input.json +18 -0
  139. package/fixtures/atelier-inquiry-contract/assessment/invalid/document.json +41 -0
  140. package/fixtures/atelier-inquiry-contract/assessment/valid/document.json +40 -0
  141. package/fixtures/atelier-inquiry-contract/bundle/invalid/document.json +51 -0
  142. package/fixtures/atelier-inquiry-contract/bundle/valid/document.json +50 -0
  143. package/fixtures/atelier-inquiry-contract/campaign/invalid/document.json +17 -0
  144. package/fixtures/atelier-inquiry-contract/campaign/valid/document.json +16 -0
  145. package/fixtures/atelier-inquiry-contract/decision/invalid/document.json +22 -0
  146. package/fixtures/atelier-inquiry-contract/decision/valid/document.json +21 -0
  147. package/fixtures/atelier-inquiry-contract/feedback/invalid/document.json +19 -0
  148. package/fixtures/atelier-inquiry-contract/feedback/valid/document.json +18 -0
  149. package/fixtures/atelier-inquiry-contract/handoff/invalid/document.json +92 -0
  150. package/fixtures/atelier-inquiry-contract/handoff/valid/document.json +91 -0
  151. package/fixtures/atelier-inquiry-contract/hypothesis/invalid/document.json +20 -0
  152. package/fixtures/atelier-inquiry-contract/hypothesis/valid/document.json +19 -0
  153. package/fixtures/atelier-inquiry-contract/ledger/invalid/document.json +680 -0
  154. package/fixtures/atelier-inquiry-contract/ledger/valid/document.json +679 -0
  155. package/fixtures/atelier-inquiry-contract/legacy-assessment/invalid/document.json +19 -0
  156. package/fixtures/atelier-inquiry-contract/legacy-assessment/valid/document.json +18 -0
  157. package/fixtures/atelier-inquiry-contract/request/invalid/document.json +50 -0
  158. package/fixtures/atelier-inquiry-contract/request/valid/document.json +49 -0
  159. package/fixtures/atelier-inquiry-contract/source/invalid/document.json +18 -0
  160. package/fixtures/atelier-inquiry-contract/source/valid/document.json +17 -0
  161. package/fixtures/atelier-inquiry-contract/withdrawal/invalid/document.json +16 -0
  162. package/fixtures/atelier-inquiry-contract/withdrawal/valid/document.json +15 -0
  163. package/fixtures/atelier-instruction-adoption/context-receipt/invalid/document.json +18 -0
  164. package/fixtures/atelier-instruction-adoption/context-receipt/valid/document.json +17 -0
  165. package/fixtures/atelier-instruction-adoption/plan/invalid/document.json +63 -0
  166. package/fixtures/atelier-instruction-adoption/plan/valid/document.json +62 -0
  167. package/fixtures/atelier-instruction-adoption/receipt/invalid/document.json +22 -0
  168. package/fixtures/atelier-instruction-adoption/receipt/valid/document.json +21 -0
  169. package/fixtures/atelier-instruction-adoption/state/invalid/document.json +30 -0
  170. package/fixtures/atelier-instruction-adoption/state/valid/document.json +29 -0
  171. package/fixtures/atelier-interaction/act/invalid/document.json +25 -0
  172. package/fixtures/atelier-interaction/act/valid/document.json +24 -0
  173. package/fixtures/atelier-interaction/assessment/invalid/document.json +32 -0
  174. package/fixtures/atelier-interaction/assessment/valid/document.json +31 -0
  175. package/fixtures/atelier-interaction/observation/invalid/document.json +22 -0
  176. package/fixtures/atelier-interaction/observation/valid/document.json +21 -0
  177. package/fixtures/atelier-interaction/policy/invalid/document.json +20 -0
  178. package/fixtures/atelier-interaction/policy/valid/document.json +19 -0
  179. package/fixtures/atelier-judgment/case/invalid/document.json +76 -0
  180. package/fixtures/atelier-judgment/case/valid/document.json +75 -0
  181. package/fixtures/atelier-judgment/decision/invalid/document.json +38 -0
  182. package/fixtures/atelier-judgment/decision/valid/document.json +37 -0
  183. package/fixtures/atelier-judgment/native-decision.md +3 -0
  184. package/fixtures/atelier-judgment/practice-reconsideration/definition.json +92 -0
  185. package/fixtures/atelier-judgment/practice-reconsideration/scenario.json +435 -0
  186. package/fixtures/atelier-knowledge-contract/activation/invalid/document.json +26 -0
  187. package/fixtures/atelier-knowledge-contract/activation/valid/document.json +25 -0
  188. package/fixtures/atelier-knowledge-contract/contribution/invalid/document.json +34 -0
  189. package/fixtures/atelier-knowledge-contract/contribution/valid/document.json +33 -0
  190. package/fixtures/atelier-knowledge-contract/domain/invalid/document.json +41 -0
  191. package/fixtures/atelier-knowledge-contract/domain/valid/document.json +40 -0
  192. package/fixtures/atelier-knowledge-contract/domain-revision/invalid/document.json +46 -0
  193. package/fixtures/atelier-knowledge-contract/domain-revision/valid/document.json +45 -0
  194. package/fixtures/atelier-knowledge-contract/evaluation/invalid/document.json +21 -0
  195. package/fixtures/atelier-knowledge-contract/evaluation/valid/document.json +20 -0
  196. package/fixtures/atelier-knowledge-contract/ledger/invalid/document.json +318 -0
  197. package/fixtures/atelier-knowledge-contract/ledger/valid/document.json +317 -0
  198. package/fixtures/atelier-knowledge-contract/relation/invalid/document.json +25 -0
  199. package/fixtures/atelier-knowledge-contract/relation/valid/document.json +24 -0
  200. package/fixtures/atelier-knowledge-contract/review/invalid/document.json +18 -0
  201. package/fixtures/atelier-knowledge-contract/review/valid/document.json +17 -0
  202. package/fixtures/atelier-knowledge-contract/withdrawal/invalid/document.json +16 -0
  203. package/fixtures/atelier-knowledge-contract/withdrawal/valid/document.json +15 -0
  204. package/fixtures/atelier-learning/invalid/authority.json +14 -0
  205. package/fixtures/atelier-learning/valid/capture.json +13 -0
  206. package/fixtures/atelier-personal-workspace-contract/manifest/invalid/authority-key.json +17 -0
  207. package/fixtures/atelier-personal-workspace-contract/manifest/invalid/nonempty-ext.json +25 -0
  208. package/fixtures/atelier-personal-workspace-contract/manifest/invalid/wrong-schema.json +22 -0
  209. package/fixtures/atelier-personal-workspace-contract/manifest/valid/manifest.json +22 -0
  210. package/fixtures/atelier-personal-workspace-contract/overlay/invalid/authority-key.json +25 -0
  211. package/fixtures/atelier-personal-workspace-contract/overlay/invalid/unknown-top-level-field.json +27 -0
  212. package/fixtures/atelier-personal-workspace-contract/overlay/invalid/wrong-schema.json +24 -0
  213. package/fixtures/atelier-trackable/definition/invalid/document.json +15 -0
  214. package/fixtures/atelier-trackable/definition/valid/document.json +14 -0
  215. package/fixtures/atelier-trackable/request/invalid/document.json +23 -0
  216. package/fixtures/atelier-trackable/request/valid/document.json +22 -0
  217. package/fixtures/boundary-delegations/invalid/authority-key.v1.json +30 -0
  218. package/fixtures/boundary-delegations/invalid/push-operation.v1.json +28 -0
  219. package/fixtures/boundary-delegations/invalid/unsigned.v1.json +25 -0
  220. package/fixtures/boundary-delegations/valid/empty.v1.json +4 -0
  221. package/fixtures/boundary-delegations/valid/signed-operator.v1.json +30 -0
  222. package/fixtures/boundary-owner-keys/invalid/wrong-algorithm.v1.json +15 -0
  223. package/fixtures/boundary-owner-keys/invalid/wrong-curve.v1.json +15 -0
  224. package/fixtures/boundary-owner-keys/valid/one-owner.v1.json +17 -0
  225. package/fixtures/capability-packages/adoption.example.json +70 -0
  226. package/fixtures/capability-packages/evidence-review/capability-package.json +58 -0
  227. package/fixtures/capability-packages/evidence-review/capability-release.json +84 -0
  228. package/fixtures/capability-packages/evidence-review/evaluation.md +15 -0
  229. package/fixtures/capability-packages/evidence-review/skills/evidence-review/SKILL.md +22 -0
  230. package/fixtures/capability-packages/evidence-review/skills/evidence-review/references/ledger.md +7 -0
  231. package/fixtures/capability-packages/research/capability-package.json +88 -0
  232. package/fixtures/capability-packages/research/capability-release.json +134 -0
  233. package/fixtures/capability-packages/research/evaluation.md +15 -0
  234. package/fixtures/capability-packages/research/skills/research-integrate/SKILL.md +29 -0
  235. package/fixtures/capability-packages/research/skills/research-integrate/references/integration.md +10 -0
  236. package/fixtures/capability-packages/research/skills/research-plan/SKILL.md +27 -0
  237. package/fixtures/capability-packages/research/skills/research-plan/references/inquiries.md +26 -0
  238. package/fixtures/capability-packages/research/skills/research-synthesize/SKILL.md +23 -0
  239. package/fixtures/capability-packages/research/skills/research-synthesize/references/synthesis.md +12 -0
  240. package/fixtures/evidence-navigation/invalid/duplicate-operation.json +16 -0
  241. package/fixtures/evidence-navigation/invalid/instruction-kind.json +36 -0
  242. package/fixtures/evidence-navigation/invalid/invalid-digest.json +36 -0
  243. package/fixtures/evidence-navigation/invalid/invalid-time.json +36 -0
  244. package/fixtures/evidence-navigation/invalid/missing-attribution.json +35 -0
  245. package/fixtures/evidence-navigation/invalid/reserved-extension.json +19 -0
  246. package/fixtures/evidence-navigation/invalid/unattributed-acceptance.json +36 -0
  247. package/fixtures/evidence-navigation/invalid/uncoerced-version.json +16 -0
  248. package/fixtures/evidence-navigation/invalid/unknown-currency.json +17 -0
  249. package/fixtures/evidence-navigation/invalid/unknown-selector-field.json +37 -0
  250. package/fixtures/evidence-navigation/invalid/unsupported-operation.json +15 -0
  251. package/fixtures/evidence-navigation/valid/claim.json +36 -0
  252. package/fixtures/evidence-navigation/valid/host.json +16 -0
  253. package/fixtures/evidence-navigation/valid/profile.json +16 -0
  254. package/fixtures/evidence-navigation/valid/snapshot.json +17 -0
  255. package/fixtures/harness-packages/build-harness/capability-package.json +61 -0
  256. package/fixtures/harness-packages/build-harness/capability-release.json +82 -0
  257. package/fixtures/harness-packages/build-harness/evaluation.md +3 -0
  258. package/fixtures/harness-packages/build-harness/skills/atelier-build-harness/SKILL.md +59 -0
  259. package/fixtures/harness-packages/knowledge-harness/capability-package.json +61 -0
  260. package/fixtures/harness-packages/knowledge-harness/capability-release.json +82 -0
  261. package/fixtures/harness-packages/knowledge-harness/evaluation.md +3 -0
  262. package/fixtures/harness-packages/knowledge-harness/skills/atelier-knowledge-harness/SKILL.md +60 -0
  263. package/fixtures/harnesses/learning-cycle.json +780 -0
  264. package/fixtures/inquiry/workshop.json +675 -0
  265. package/fixtures/inquiry-packages/discovery-harness/capability-package.json +61 -0
  266. package/fixtures/inquiry-packages/discovery-harness/capability-release.json +82 -0
  267. package/fixtures/inquiry-packages/discovery-harness/evaluation.md +3 -0
  268. package/fixtures/inquiry-packages/discovery-harness/skills/atelier-discovery-harness/SKILL.md +48 -0
  269. package/fixtures/inquiry-packages/research-harness/capability-package.json +61 -0
  270. package/fixtures/inquiry-packages/research-harness/capability-release.json +82 -0
  271. package/fixtures/inquiry-packages/research-harness/evaluation.md +3 -0
  272. package/fixtures/inquiry-packages/research-harness/skills/atelier-research-harness/SKILL.md +43 -0
  273. package/fixtures/knowledge-health/calibration-suite.json +26 -0
  274. package/fixtures/knowledge-health/calibration-trial.json +37 -0
  275. package/fixtures/knowledge-health/corrected/checklist.md +18 -0
  276. package/fixtures/knowledge-health/devday/participant-record.json +19 -0
  277. package/fixtures/knowledge-health/expected-summary.json +27 -0
  278. package/fixtures/knowledge-health/workshop/README.md +20 -0
  279. package/fixtures/knowledge-health/workshop/atelier.project.json +7 -0
  280. package/fixtures/knowledge-health/workshop/knowledge-plan.json +65 -0
  281. package/fixtures/knowledge-health/workshop/records/checklist.md +18 -0
  282. package/fixtures/knowledge-health/workshop/records/workshop.md +18 -0
  283. package/fixtures/knowledge-health/workshop/repo-access.v1.json +5 -0
  284. package/fixtures/knowledge-health/workspace/atelier.project.json +18 -0
  285. package/fixtures/knowledge-health/workspace/knowledge-plan.json +74 -0
  286. package/fixtures/knowledge-health/workspace/records/checklist.md +18 -0
  287. package/fixtures/knowledge-health/workspace/records/pilot.md +16 -0
  288. package/fixtures/knowledge-health/workspace/repo-access.v1.json +9 -0
  289. package/fixtures/personal-workspace/overlay.json +24 -0
  290. package/fixtures/templates/local-library.v1.json +75 -0
  291. package/fixtures/templates/upgrade-contracts/adoption-policy.v2/invalid.json +16 -0
  292. package/fixtures/templates/upgrade-contracts/adoption-policy.v2/valid.json +13 -0
  293. package/fixtures/templates/upgrade-contracts/migration.v3/invalid.json +24 -0
  294. package/fixtures/templates/upgrade-contracts/migration.v3/valid.json +21 -0
  295. package/fixtures/templates/upgrade-contracts/template-adoption.v1/invalid.json +60 -0
  296. package/fixtures/templates/upgrade-contracts/template-adoption.v1/valid.json +57 -0
  297. package/fixtures/templates/upgrade-contracts/upgrade-plan.v3/invalid.json +85 -0
  298. package/fixtures/templates/upgrade-contracts/upgrade-plan.v3/valid.json +82 -0
  299. package/package.json +59 -5
  300. package/skills/claude/atelier-build-harness/SKILL.md +59 -0
  301. package/skills/claude/atelier-coordination/SKILL.md +32 -0
  302. package/skills/claude/atelier-discovery-harness/SKILL.md +48 -0
  303. package/skills/claude/atelier-guided-upgrade/SKILL.md +29 -0
  304. package/skills/claude/atelier-interaction/SKILL.md +34 -0
  305. package/skills/claude/atelier-knowledge-harness/SKILL.md +60 -0
  306. package/skills/claude/atelier-knowledge-setup/SKILL.md +72 -0
  307. package/skills/claude/atelier-practical-judgment/SKILL.md +64 -0
  308. package/skills/claude/atelier-research-harness/SKILL.md +43 -0
  309. package/skills/claude/atelier-skill-steward/SKILL.md +53 -0
  310. package/skills/claude/atelier-trackables/SKILL.md +40 -0
  311. package/skills/codex/atelier-build-harness/SKILL.md +59 -0
  312. package/skills/codex/atelier-coordination/SKILL.md +32 -0
  313. package/skills/codex/atelier-discovery-harness/SKILL.md +48 -0
  314. package/skills/codex/atelier-guided-upgrade/SKILL.md +29 -0
  315. package/skills/codex/atelier-interaction/SKILL.md +34 -0
  316. package/skills/codex/atelier-knowledge-harness/SKILL.md +60 -0
  317. package/skills/codex/atelier-knowledge-setup/SKILL.md +72 -0
  318. package/skills/codex/atelier-practical-judgment/SKILL.md +64 -0
  319. package/skills/codex/atelier-research-harness/SKILL.md +43 -0
  320. package/skills/codex/atelier-skill-steward/SKILL.md +53 -0
  321. package/skills/codex/atelier-trackables/SKILL.md +40 -0
  322. package/src/architecture/catalog.mjs +355 -0
  323. package/src/architecture/index.mjs +93 -0
  324. package/src/boundary/content-rules.mjs +4 -2
  325. package/src/boundary/delegation-command.mjs +158 -0
  326. package/src/boundary/delegation.mjs +396 -0
  327. package/src/boundary/policy.mjs +52 -10
  328. package/src/build/git.mjs +18 -0
  329. package/src/build/index.mjs +3 -0
  330. package/src/build/ledger.mjs +88 -0
  331. package/src/capabilities/adoption.mjs +381 -0
  332. package/src/capabilities/evidence.mjs +140 -0
  333. package/src/capabilities/files.mjs +124 -0
  334. package/src/capabilities/index.mjs +4 -0
  335. package/src/capabilities/instructions.mjs +250 -0
  336. package/src/capabilities/package.mjs +136 -0
  337. package/src/cli/command-failure.mjs +36 -0
  338. package/src/cli/execute-command.mjs +16 -2
  339. package/src/cli/run.mjs +65 -9
  340. package/src/coauthor/store.mjs +43 -2
  341. package/src/collaboration/proposals.mjs +189 -0
  342. package/src/commands/architecture.mjs +27 -0
  343. package/src/commands/boundary.mjs +3 -0
  344. package/src/commands/capability.mjs +73 -0
  345. package/src/commands/enroll.mjs +3 -0
  346. package/src/commands/harness.mjs +79 -0
  347. package/src/commands/ingest.mjs +39 -0
  348. package/src/commands/init.mjs +4 -1
  349. package/src/commands/inquiry.mjs +66 -0
  350. package/src/commands/knowledge-semantic.mjs +128 -0
  351. package/src/commands/knowledge.mjs +119 -0
  352. package/src/commands/learn.mjs +61 -0
  353. package/src/commands/obsidian.mjs +754 -63
  354. package/src/commands/practice.mjs +24 -0
  355. package/src/commands/setup.mjs +22 -2
  356. package/src/commands/trackable.mjs +19 -0
  357. package/src/contracts/corpus.mjs +30 -0
  358. package/src/coordination/index.mjs +110 -0
  359. package/src/evidence-navigation/contracts.mjs +60 -0
  360. package/src/evidence-navigation/evaluate.mjs +69 -0
  361. package/src/evidence-navigation/generation.mjs +22 -0
  362. package/src/evidence-navigation/index.mjs +2 -0
  363. package/src/evidence-navigation/local.mjs +167 -0
  364. package/src/evidence-navigation/schema.generated.mjs +604 -0
  365. package/src/evidence-navigation/types.mjs +12 -0
  366. package/src/export/atelier-export-contract.mjs +35 -8
  367. package/src/graph/enroll.mjs +248 -0
  368. package/src/graph/graph.mjs +17 -1
  369. package/src/graph/knowledge-graph.mjs +58 -8
  370. package/src/harnesses/contracts.mjs +41 -0
  371. package/src/harnesses/exchange.mjs +154 -0
  372. package/src/harnesses/feedback.mjs +16 -0
  373. package/src/harnesses/history.mjs +37 -0
  374. package/src/harnesses/index.mjs +4 -0
  375. package/src/harnesses/store.mjs +29 -0
  376. package/src/ingestion/contracts.mjs +41 -0
  377. package/src/ingestion/evaluation.mjs +119 -0
  378. package/src/ingestion/optional/composition/index.mjs +171 -0
  379. package/src/ingestion/optional/evaluation/index.mjs +219 -0
  380. package/src/ingestion/optional/graphify/composition-binding.mjs +60 -0
  381. package/src/ingestion/optional/graphify/composition_receiving.py +185 -0
  382. package/src/ingestion/optional/graphify/graphify_supplier.py +933 -0
  383. package/src/ingestion/optional/graphify/json_bridge.py +163 -0
  384. package/src/ingestion/optional/graphify/query_receiving.py +209 -0
  385. package/src/ingestion/optional/index.mjs +9 -0
  386. package/src/ingestion/optional/jev/bridge.mjs +166 -0
  387. package/src/ingestion/optional/jev/composition-binding.mjs +116 -0
  388. package/src/ingestion/optional/jev/judgments.mjs +174 -0
  389. package/src/ingestion/optional/jev/native-translation.mjs +32 -0
  390. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/__init__.py +7 -0
  391. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/adapter.py +966 -0
  392. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/artifacts.py +101 -0
  393. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/projection.py +146 -0
  394. package/src/ingestion/optional/lightrag/composition-binding.mjs +67 -0
  395. package/src/ingestion/optional/vanilla/composition-binding.mjs +102 -0
  396. package/src/ingestion/optional/vanilla/index.mjs +218 -0
  397. package/src/ingestion/optional/vanilla/native-normalization.mjs +187 -0
  398. package/src/ingestion/processors.mjs +218 -0
  399. package/src/ingestion/semantic.mjs +203 -0
  400. package/src/ingestion/store.mjs +372 -0
  401. package/src/inquiry/beliefs.mjs +32 -0
  402. package/src/inquiry/contracts.mjs +23 -0
  403. package/src/inquiry/index.mjs +5 -0
  404. package/src/inquiry/ledger.mjs +135 -0
  405. package/src/inquiry/lenses.mjs +15 -0
  406. package/src/inquiry/projection.mjs +77 -0
  407. package/src/inquiry/store.mjs +35 -0
  408. package/src/intake/read-scope.mjs +12 -0
  409. package/src/intake/store.mjs +69 -6
  410. package/src/interaction/index.mjs +91 -0
  411. package/src/judgment/index.mjs +82 -0
  412. package/src/judgment/practice-evaluation.mjs +70 -0
  413. package/src/judgment/practice.mjs +144 -0
  414. package/src/knowledge/context.mjs +217 -0
  415. package/src/knowledge/index.mjs +5 -0
  416. package/src/knowledge/ingestion.mjs +79 -0
  417. package/src/knowledge/intake.mjs +33 -0
  418. package/src/knowledge/ledger.mjs +110 -0
  419. package/src/knowledge/participatory/guidance.mjs +36 -0
  420. package/src/knowledge/participatory/guided-contribution.mjs +44 -0
  421. package/src/knowledge/participatory/index.mjs +2 -0
  422. package/src/knowledge/participatory/installed-workshop.mjs +108 -0
  423. package/src/knowledge/plan.mjs +67 -0
  424. package/src/knowledge/projection.mjs +43 -0
  425. package/src/knowledge/semantic-operation.mjs +567 -0
  426. package/src/knowledge/sessions.mjs +467 -0
  427. package/src/knowledge/workspace.mjs +295 -0
  428. package/src/knowledge-health/assessment.mjs +165 -0
  429. package/src/knowledge-health/capabilities.mjs +350 -0
  430. package/src/knowledge-health/context.mjs +62 -0
  431. package/src/knowledge-health/example.mjs +47 -0
  432. package/src/knowledge-health/index.mjs +10 -0
  433. package/src/knowledge-health/owner-join.mjs +88 -0
  434. package/src/knowledge-health/proof/common.mjs +24 -0
  435. package/src/knowledge-health/proof/installed-check.mjs +100 -0
  436. package/src/knowledge-health/proof/native-readback.mjs +37 -0
  437. package/src/knowledge-health/proof/rehearse.mjs +68 -0
  438. package/src/knowledge-health/proof/validate-participant.mjs +17 -0
  439. package/src/knowledge-health/proof/verify-native-capture.mjs +14 -0
  440. package/src/knowledge-health/proof/workshop-check.mjs +36 -0
  441. package/src/knowledge-health/rule-identity.mjs +44 -0
  442. package/src/knowledge-health/workshop-composition.mjs +19 -0
  443. package/src/knowledge-health/workshop-profile.mjs +176 -0
  444. package/src/knowledge-health/workshop.mjs +99 -0
  445. package/src/learning/adapters.mjs +68 -0
  446. package/src/learning/assistance.mjs +127 -0
  447. package/src/learning/contracts.mjs +65 -0
  448. package/src/learning/store.mjs +272 -0
  449. package/src/personal-workspace/index.mjs +391 -0
  450. package/src/personal-workspace/selection.mjs +385 -0
  451. package/src/project/config.mjs +8 -0
  452. package/src/project/durable-state.mjs +3 -1
  453. package/src/project/file-class.mjs +1 -1
  454. package/src/projection/obsidian/edits/apply.mjs +55 -16
  455. package/src/projection/obsidian/personal-workspace.mjs +436 -0
  456. package/src/projection/obsidian/proposals/adapter.mjs +47 -8
  457. package/src/projection/obsidian/proposals/observation.mjs +10 -2
  458. package/src/projection/obsidian/publication/publisher.mjs +142 -13
  459. package/src/projection/obsidian/publication/vault-list.mjs +4 -3
  460. package/src/projection/obsidian/recovery/index.mjs +4 -1
  461. package/src/projection/obsidian/recovery/store.mjs +160 -7
  462. package/src/projection/obsidian/selection-ui/contribution.mjs +6 -5
  463. package/src/readiness/readiness.mjs +10 -3
  464. package/src/reflection/index.mjs +56 -0
  465. package/src/runtime/obsidian/app-production-seams.mjs +48 -16
  466. package/src/runtime/obsidian/app-registration.mjs +175 -28
  467. package/src/runtime/obsidian/app-restart.mjs +154 -0
  468. package/src/runtime/obsidian/engine.mjs +163 -20
  469. package/src/runtime/obsidian/extension-points.mjs +1 -1
  470. package/src/runtime/obsidian/index.mjs +10 -7
  471. package/src/runtime/obsidian/launch-plan.mjs +7 -4
  472. package/src/runtime/obsidian/lifecycle.mjs +92 -12
  473. package/src/runtime/obsidian/login-item.mjs +332 -0
  474. package/src/runtime/obsidian/machine-settings.mjs +119 -12
  475. package/src/runtime/obsidian/opening.mjs +171 -37
  476. package/src/runtime/obsidian/pipeline.mjs +71 -3
  477. package/src/runtime/obsidian/plugin-channel.mjs +11 -3
  478. package/src/runtime/obsidian/plugin-choice.mjs +16 -4
  479. package/src/runtime/obsidian/plugin-drift.mjs +59 -11
  480. package/src/runtime/obsidian/plugin-presence.mjs +14 -1
  481. package/src/runtime/obsidian/process-identity.mjs +20 -10
  482. package/src/runtime/obsidian/project-views.mjs +282 -0
  483. package/src/runtime/obsidian/questions.mjs +48 -0
  484. package/src/runtime/obsidian/release-watch.mjs +56 -0
  485. package/src/runtime/obsidian/service-main.mjs +99 -16
  486. package/src/runtime/obsidian/service-manager-production.mjs +61 -0
  487. package/src/runtime/obsidian/service-managers.mjs +275 -0
  488. package/src/runtime/obsidian/service-record.mjs +87 -23
  489. package/src/runtime/obsidian/service.mjs +36 -3
  490. package/src/runtime/obsidian/startup-adapters.mjs +59 -21
  491. package/src/runtime/obsidian/unheld-evidence.mjs +84 -0
  492. package/src/runtime/obsidian/vault-location.mjs +300 -0
  493. package/src/runtime/obsidian/view-counts.mjs +34 -0
  494. package/src/server/local-sidecar.mjs +169 -2
  495. package/src/server/server.mjs +28 -2
  496. package/src/template-bindings/project.mjs +92 -0
  497. package/src/templates/profile.mjs +225 -0
  498. package/src/trackables/domain.mjs +175 -0
  499. package/src/trackables/store.mjs +114 -0
  500. package/src/ui/knowledge-page.mjs +1388 -0
  501. package/src/upgrade/explanation.mjs +1 -1
  502. package/src/upgrade/template-participant.mjs +171 -0
  503. package/src/upgrade/transaction.mjs +72 -25
  504. package/src/upgrade/upgrade.mjs +1 -0
  505. package/templates/external-project-workspace/pack-lifecycle.json +6 -1
  506. package/templates/knowledge-workspace/.gitattributes +2 -0
  507. package/templates/knowledge-workspace/AGENTS.md +27 -0
  508. package/templates/knowledge-workspace/README.md +44 -0
  509. package/templates/knowledge-workspace/atelier.project.json +22 -0
  510. package/templates/knowledge-workspace/gitignore +6 -0
  511. package/templates/knowledge-workspace/knowledge-plan.json +111 -0
  512. package/templates/knowledge-workspace/knowledge-plan.schema.json +281 -0
  513. package/templates/knowledge-workspace/records/forecast.md +22 -0
  514. package/templates/knowledge-workspace/records/inspection.md +25 -0
  515. package/templates/knowledge-workspace/records/telescope.md +24 -0
  516. package/templates/knowledge-workspace/repo-access.v1.json +9 -0
@@ -0,0 +1,101 @@
1
+ """Private supplier artifacts. These receipts do not replace Atelier intake."""
2
+ from __future__ import annotations
3
+
4
+ import dataclasses
5
+ import hashlib
6
+ import json
7
+ from enum import Enum
8
+ from pathlib import Path
9
+
10
+
11
+ def portable(value):
12
+ """Preserve native data fields without repr-based or lossy coercion."""
13
+ if dataclasses.is_dataclass(value):
14
+ value = dataclasses.asdict(value)
15
+ elif isinstance(value, Enum):
16
+ value = value.value
17
+ elif hasattr(value, "model_dump"):
18
+ value = value.model_dump(mode="json")
19
+ if value is None or isinstance(value, (str, bool, int, float)):
20
+ # Reject NaN/Infinity, which are not portable JSON.
21
+ json.dumps(value, allow_nan=False)
22
+ return value
23
+ if isinstance(value, (list, tuple)):
24
+ return [portable(item) for item in value]
25
+ if isinstance(value, dict) and all(isinstance(key, str) for key in value):
26
+ return {key: portable(item) for key, item in value.items()}
27
+ raise TypeError("Native artifact needs a host JSON serializer; object was not discarded")
28
+
29
+
30
+ def encoded(value):
31
+ return json.dumps(portable(value), ensure_ascii=False, sort_keys=True,
32
+ separators=(",", ":"), allow_nan=False).encode("utf-8")
33
+
34
+
35
+ def digest(value):
36
+ return "sha256:" + hashlib.sha256(encoded(value)).hexdigest()
37
+
38
+
39
+ class MemoryArtifacts:
40
+ """Test/host injection sink; the host must retain its returned bytes."""
41
+ def __init__(self):
42
+ self.objects = {}
43
+
44
+ def put_bytes(self, kind, data):
45
+ if not isinstance(data, bytes):
46
+ raise TypeError("Artifact bytes are required")
47
+ sha = hashlib.sha256(data).hexdigest()
48
+ self.objects.setdefault(sha, data)
49
+ return {"artifactId": "sha256:" + sha, "kind": kind,
50
+ "bytes": len(data), "storage": "host-memory"}
51
+
52
+ def put_json(self, kind, value):
53
+ return self.put_bytes(kind, encoded(value))
54
+
55
+ def read_json(self, ref):
56
+ return json.loads(self.read_bytes(ref))
57
+
58
+ def read_bytes(self, ref):
59
+ data = self.objects[ref["artifactId"].removeprefix("sha256:")]
60
+ if "sha256:" + hashlib.sha256(data).hexdigest() != ref["artifactId"]:
61
+ raise ValueError("Artifact readback digest differs")
62
+ return data
63
+
64
+
65
+ class FileArtifacts:
66
+ """Immutable, content addressed files under an explicitly allocated root."""
67
+ def __init__(self, root, *, owner_root):
68
+ self.root, owner = Path(root).resolve(), Path(owner_root).resolve()
69
+ if not self.root.is_relative_to(owner):
70
+ raise ValueError("Artifact root is outside the supplier allocation")
71
+ self.root.mkdir(parents=True, exist_ok=True)
72
+
73
+ def put_bytes(self, kind, data):
74
+ if not isinstance(data, bytes):
75
+ raise TypeError("Artifact bytes are required")
76
+ sha = hashlib.sha256(data).hexdigest()
77
+ target = self.root / (sha + ".artifact")
78
+ try:
79
+ with target.open("xb") as output:
80
+ output.write(data)
81
+ output.flush()
82
+ import os
83
+ os.fsync(output.fileno())
84
+ except FileExistsError:
85
+ if target.read_bytes() != data:
86
+ raise ValueError("Existing artifact differs from its content address")
87
+ return {"artifactId": "sha256:" + sha, "kind": kind,
88
+ "bytes": len(data), "storage": "supplier-file", "path": str(target)}
89
+
90
+ def put_json(self, kind, value):
91
+ return self.put_bytes(kind, encoded(value))
92
+
93
+ def read_json(self, ref):
94
+ return json.loads(self.read_bytes(ref))
95
+
96
+ def read_bytes(self, ref):
97
+ target = self.root / (ref["artifactId"].removeprefix("sha256:") + ".artifact")
98
+ data = target.read_bytes()
99
+ if "sha256:" + hashlib.sha256(data).hexdigest() != ref["artifactId"]:
100
+ raise ValueError("Artifact readback digest differs")
101
+ return data
@@ -0,0 +1,146 @@
1
+ """Derived native projection of the actual semantic runner project() result.
2
+
3
+ Canonical acceptance/identity remains with the host's existing knowledge runner.
4
+ Opaque IDs are native-normalization-safe. Native traversal stays undirected.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import hashlib
9
+ import re
10
+ from .artifacts import digest, encoded, portable
11
+
12
+
13
+ def record_ref(value):
14
+ if not (isinstance(value, dict) and isinstance(value.get("id"), str)
15
+ and re.fullmatch(r"sha256:[a-f0-9]{64}", value.get("digest", ""))):
16
+ raise ValueError("An exact existing harnessRef {id,digest} is required")
17
+ return portable(value)
18
+
19
+
20
+ def opaque(kind, value):
21
+ return "ATELIER_" + kind + "_" + hashlib.sha256(encoded(value)).hexdigest().upper()
22
+
23
+
24
+ def build_projection(project, *, profile="assertion-incidence"):
25
+ if (project.get("schema") != "atelier-knowledge-graph-proposal@v1"
26
+ or project.get("semanticProfile") != "atelier.semantic-operation-profile/v0"
27
+ or project.get("canonicalMutation") is not False or project.get("authority") != "none"):
28
+ raise ValueError("The existing runner semantic projection profile is required")
29
+ if profile not in {"assertion-incidence", "semantic-adjacency"}:
30
+ raise ValueError("Declare a supported projection profile")
31
+ result = {"chunks": [], "entities": [], "relationships": []}
32
+ mapping = {"entities": {}, "assertions": {}, "roles": {}, "chunks": {}}
33
+ losses = ["Native traversal is undirected; resolve direction from retained assertion records",
34
+ "Native summaries, weights and edits do not establish canonical truth",
35
+ "Native chunk IDs hash content: identical quote chunks can coalesce; exact evidence remains retained",
36
+ "Native entity/assertion source links use their first evidence alias; all evidence remains retained and indexed as chunks"]
37
+ entity_by_candidate, entity_by_record, seen_records = {}, {}, set()
38
+ for item in project.get("semanticEntities", []):
39
+ ref, candidate = record_ref(item["record"]), portable(item["candidate"])
40
+ if ref["id"] in seen_records or candidate["id"] in entity_by_candidate:
41
+ raise ValueError("Semantic entity identities are ambiguous")
42
+ seen_records.add(ref["id"])
43
+ name = opaque("ENTITY", ref)
44
+ entity_by_candidate[candidate["id"]] = name
45
+ entity_by_record[(ref["id"], ref["digest"])] = name
46
+ mapping["entities"][name] = {"record": ref, "candidate": candidate}
47
+ aliases = []
48
+ for index, evidence in enumerate(candidate.get("evidence", [])):
49
+ if not isinstance(evidence.get("quote"), str) or not evidence.get("quote"):
50
+ raise ValueError("Entity evidence needs its actual located quote")
51
+ alias = opaque("EVIDENCE", {"entity": ref, "index": index, "evidence": evidence})
52
+ aliases.append(alias)
53
+ mapping["chunks"][alias] = {"entity": ref, "evidence": evidence}
54
+ result["chunks"].append({"content": evidence["quote"], "source_id": alias,
55
+ "file_path": evidence.get("ref", "retained-evidence:" + alias), "chunk_order_index": index})
56
+ if not aliases:
57
+ losses.append("Entity " + ref["id"] + " has no native chunk source; exact canonical identity reference remains retained")
58
+ result["entities"].append({"entity_name": name, "entity_type": candidate["type"],
59
+ "description": encoded({"label": candidate["label"], "record": ref,
60
+ "identity": candidate.get("identity")}).decode(),
61
+ "source_id": aliases[0] if aliases else ""})
62
+
63
+ adjacency_pairs = {}
64
+ for item in project.get("semanticAssertions", []):
65
+ ref, candidate = record_ref(item["record"]), portable(item["candidate"])
66
+ if ref["id"] in seen_records:
67
+ raise ValueError("Duplicate canonical assertion record")
68
+ seen_records.add(ref["id"])
69
+ evidence = candidate.get("evidence", [])
70
+ if not evidence:
71
+ raise ValueError("An assertion requires retained located evidence")
72
+ aliases = []
73
+ for index, evidence_item in enumerate(evidence):
74
+ if not isinstance(evidence_item.get("quote"), str) or not evidence_item.get("quote"):
75
+ raise ValueError("The actual candidate's exact evidence quote is required")
76
+ alias = opaque("EVIDENCE", {"assertion": ref, "index": index, "evidence": evidence_item})
77
+ aliases.append(alias)
78
+ mapping["chunks"][alias] = {"assertion": ref, "evidence": evidence_item}
79
+ result["chunks"].append({"content": evidence_item["quote"], "source_id": alias,
80
+ "file_path": evidence_item.get("ref", "retained-evidence:" + alias),
81
+ "chunk_order_index": index})
82
+
83
+ # Endpoints returned by the real runner use resolved canonical records.
84
+ # A source-local candidate ID is not a canonical identity decision.
85
+ endpoints = item.get("endpoints", {})
86
+ participants = []
87
+ for role, field in [("subject", "subjectId"), ("object", "objectId")]:
88
+ if candidate.get(field) is None:
89
+ continue
90
+ endpoint = endpoints.get(role)
91
+ if endpoint is None:
92
+ raise ValueError("The runner's resolved endpoint record is required")
93
+ endpoint = record_ref(endpoint)
94
+ name = entity_by_record.get((endpoint["id"], endpoint["digest"]))
95
+ if name is None:
96
+ # Existing identities can resolve outside selected semanticEntities.
97
+ # Do not invent their type/label; host must hydrate them explicitly.
98
+ hydrated = project.get("resolvedEntities", [])
99
+ selected = [entity for entity in hydrated if entity.get("record") == endpoint]
100
+ if len(selected) != 1:
101
+ raise ValueError("A resolved canonical endpoint needs exact owner-hydrated identity data")
102
+ entity = selected[0]
103
+ name = opaque("ENTITY", endpoint)
104
+ entity_by_record[(endpoint["id"], endpoint["digest"])] = name
105
+ mapping["entities"][name] = portable(entity)
106
+ result["entities"].append({"entity_name": name, "entity_type": entity["type"],
107
+ "description": encoded({"label": entity["label"], "record": endpoint}).decode()})
108
+ losses.append("Hydrated endpoint " + endpoint["id"] + " has no native source chunk; authority stays in exact canonical record")
109
+ participants.append((role, name, endpoint))
110
+ assertion_name = opaque("ASSERTION", ref)
111
+ mapping["assertions"][assertion_name] = portable(item)
112
+ description = encoded({"record": ref, "candidate": candidate,
113
+ "endpoints": endpoints}).decode()
114
+ if profile == "assertion-incidence":
115
+ result["entities"].append({"entity_name": assertion_name, "entity_type": "DERIVED_ASSERTION",
116
+ "description": description, "source_id": aliases[0]})
117
+ for role, entity_name, endpoint in participants:
118
+ role_name = opaque("ROLE", {"assertion": ref, "role": role})
119
+ mapping["roles"][role_name] = {"assertion": ref, "role": role, "entity": endpoint}
120
+ result["entities"].append({"entity_name": role_name, "entity_type": "DERIVED_ROLE_BINDING",
121
+ "description": encoded(mapping["roles"][role_name]).decode(), "source_id": aliases[0]})
122
+ for source, target in [(assertion_name, role_name), (role_name, entity_name)]:
123
+ result["relationships"].append({"src_id": source, "tgt_id": target,
124
+ "description": description, "keywords": candidate["predicate"] + "," + role,
125
+ "source_id": aliases[0], "weight": 1.0})
126
+ else:
127
+ if len(participants) != 2 or participants[0][1] == participants[1][1]:
128
+ losses.append("Adjacency omitted native edge for unary/self assertion " + ref["id"])
129
+ continue
130
+ pair = tuple(sorted([participants[0][1], participants[1][1]]))
131
+ adjacency_pairs.setdefault(pair, []).append(ref)
132
+ result["relationships"].append({"src_id": participants[0][1], "tgt_id": participants[1][1],
133
+ "description": description, "keywords": candidate["predicate"],
134
+ "source_id": aliases[0], "weight": 1.0})
135
+ if profile == "semantic-adjacency":
136
+ losses.append("Adjacency coalesces direction, predicates, negation, modality and time on a native pair")
137
+ for pair, refs in adjacency_pairs.items():
138
+ if len(refs) > 1:
139
+ losses.append("Native pair collapses assertions: " + ",".join(ref["id"] for ref in refs))
140
+ # Ensure entities have native source aliases when exact assertion evidence is available.
141
+ for entity in result["entities"]:
142
+ entity.setdefault("source_id", "")
143
+ return {"custom_kg": result, "mapping": mapping, "profile": profile,
144
+ "canonicalProjection": portable(project), "inputDigest": digest(project),
145
+ "losses": losses, "authority": "none", "canonicalMutation": False,
146
+ "nativeWeightMeaning": "native evidence floor/boost, never semantic confidence"}
@@ -0,0 +1,67 @@
1
+ import { isDeepStrictEqual } from 'node:util'
2
+
3
+ const own = (value, key) => value && typeof value === 'object' ? Object.getOwnPropertyDescriptor(value, key)?.value : undefined
4
+ const object = value => value !== null && typeof value === 'object' && !Array.isArray(value)
5
+ const nonempty = value => typeof value === 'string' && value.length > 0
6
+ const artifact = value => object(value) && nonempty(own(value, 'artifactId'))
7
+ const sources = value => Array.isArray(value) && value.length > 0 && value.every(source => object(source) &&
8
+ ['sourceId', 'sourceDigest', 'attemptId'].every(key => nonempty(own(source, key))))
9
+
10
+ export class LightRAGCompositionBindingError extends TypeError {
11
+ constructor(message, returned, { snapshotState = 'received', snapshotError = null } = {}) {
12
+ super(message, snapshotError ? { cause: snapshotError } : undefined)
13
+ this.name = 'LightRAGCompositionBindingError'
14
+ this.retainedReturn = returned
15
+ this.snapshotState = snapshotState
16
+ this.snapshotError = snapshotError
17
+ this.effectUncertain = true
18
+ this.retryAuthorized = false
19
+ // Failure data/costs are custody, never a successful host receipt identity.
20
+ for (const [key, value] of [['usage', own(own(returned, 'envelope'), 'usage') ?? null], ['supplierCosts', own(returned, 'costs') ?? null]]) {
21
+ try { this[key] = structuredClone(value) }
22
+ catch (error) { this[key] = value; this[`${key}SnapshotError`] = error }
23
+ }
24
+ }
25
+ }
26
+
27
+ /** Private host-dispatched binding; no Python/SDK process or receipt principal is
28
+ * constructed here. The actual host owns execution and the verified receipt bridge.
29
+ */
30
+ export function createLightRAGCompositionBinding({ dispatch }) {
31
+ if (typeof dispatch !== 'function') throw new TypeError('Existing host supplier dispatch required')
32
+ const run = async (operation, payload) => {
33
+ // The host dispatches exactly one selected supplier query, canonical citation
34
+ // receiving, then receive_composition with its actual verified receipt owner.
35
+ const returned = await dispatch({ operation, payload })
36
+ let received
37
+ try { received = structuredClone(returned) }
38
+ catch (snapshotError) {
39
+ throw new LightRAGCompositionBindingError('Original supplier return could not be snapshotted', returned,
40
+ { snapshotState: 'failed', snapshotError })
41
+ }
42
+ const envelope = received?.envelope
43
+ if (received?.operation !== 'receive-composition' || received.outcome !== 'composition-envelope-received' ||
44
+ !object(envelope) || envelope.provider !== 'lightrag' || !nonempty(received.generationId) || envelope.generation !== received.generationId ||
45
+ envelope.nativeOperation !== operation || !envelope.receiptRef || !envelope.bridgeReceipt ||
46
+ envelope.receiptAssurance !== 'explicit-verified-existing-host-bridge' ||
47
+ !artifact(received.supplierQueryReceipt) || !artifact(received.supplierReceivingReceipt) ||
48
+ !artifact(received.envelopeArtifact) || !artifact(received.artifact) ||
49
+ !artifact(envelope.supplierQueryReceipt) || !artifact(envelope.supplierReceivingReceipt) || !artifact(envelope.artifactRef) ||
50
+ !sources(received.sourceBindings) || !sources(envelope.sourceBindings) ||
51
+ !Array.isArray(envelope.hits) || !Array.isArray(envelope.unresolvedReferences) ||
52
+ !isDeepStrictEqual(envelope.artifactRef, received.supplierReceivingReceipt) ||
53
+ !isDeepStrictEqual(envelope.supplierReceivingReceipt, received.supplierReceivingReceipt) ||
54
+ !isDeepStrictEqual(envelope.supplierQueryReceipt, received.supplierQueryReceipt) ||
55
+ !isDeepStrictEqual(envelope.sourceBindings, received.sourceBindings)) {
56
+ throw new LightRAGCompositionBindingError('Original supplier descriptors, source binding/capture and actual verified host receipt bridge required', received)
57
+ }
58
+ if (operation === 'answer' && !envelope.nativeResult?.llm_response) throw new LightRAGCompositionBindingError('Original coupled native answer required', received)
59
+ return structuredClone(envelope)
60
+ }
61
+ return Object.freeze({
62
+ bindings: Object.freeze({ retrieve: payload => run('retrieve', payload), nativeAnswer: payload => run('answer', payload) }),
63
+ operationRoles: Object.freeze({ retrieve: 'retrieve', nativeAnswer: 'native-answer' }),
64
+ hostRequired: Object.freeze(['single-selected-supplier-query', 'existing-canonical-citation-hydration',
65
+ 'existing-current-source-and-quote-support', 'actual-verified-host-receipt-bridge']),
66
+ })
67
+ }
@@ -0,0 +1,102 @@
1
+ import { createVanillaIngestionBridge, normalizeCandidateJson, readVanillaCapture, VanillaIngestionError } from './index.mjs'
2
+
3
+ const check = (value, message) => { if (!value) throw new VanillaIngestionError('VANILLA_COMPOSITION_BINDING', message) }
4
+
5
+ /** Private host adapter for the parent's createComposition callable interface.
6
+ * Receipt references come from the host, not from a new supplier receipt owner.
7
+ */
8
+ export function createVanillaCompositionBinding({ runner, captureAttempt, extract,
9
+ normalize = normalizeCandidateJson, receiptFor, now, monotonic }) {
10
+ check(typeof extract === 'function' && typeof receiptFor === 'function', 'Existing host extractor and receipt-reference callback are required')
11
+ check(typeof runner?.context === 'function', 'The existing fresh knowledge context owner is required')
12
+ const bridge = createVanillaIngestionBridge({ runner, captureAttempt, now, monotonic })
13
+
14
+ async function bound(operationId) {
15
+ const status = await runner.status({ operationId })
16
+ check(status.phase === 'completed' && status.freshness === 'current', 'Current completed semantic operation is required')
17
+ const saved = readVanillaCapture(status)
18
+ return { status, operationBinding: {
19
+ operationId: status.operationId,
20
+ attemptId: status.attempt.attempt.attemptId,
21
+ inputDigest: status.input.digest,
22
+ domainRef: structuredClone(status.input.domainRef),
23
+ configurationDigest: status.extractor.configurationDigest,
24
+ completion: structuredClone(status.attempt.completion),
25
+ rawOutputDigest: saved.capture.raw.sha256,
26
+ historyDigest: status.head,
27
+ sourceReferences: status.input.evidence.map(span => structuredClone(span.reference)),
28
+ } }
29
+ }
30
+ async function receipt(operation, current, extra = {}) {
31
+ const receiptRef = await receiptFor({ operation, operationBinding: structuredClone(current.operationBinding),
32
+ usageAssurance: 'host-reported', authority: 'none', ...extra })
33
+ check(receiptRef !== undefined && receiptRef !== null && receiptRef !== '', 'Host must return its actual receipt/state reference')
34
+ return receiptRef
35
+ }
36
+ function operationId(input, extraction) {
37
+ const id = extraction?.operationBinding?.operationId ?? input?.resume?.operationId
38
+ check(typeof id === 'string' && id.length > 0, 'Use the actual extraction operation or an explicit saved operation')
39
+ return id
40
+ }
41
+ function query(input) {
42
+ check(typeof input?.proposalQuery === 'string' && input.proposalQuery.trim().length > 0, 'Explicit proposal query is required for the current knowledge view')
43
+ return input.proposalQuery
44
+ }
45
+
46
+ const extractOperation = async ({ input }, { signal } = {}) => {
47
+ check(Boolean(input?.begin) !== Boolean(input?.resume), 'Select one new reservation or one explicit saved-operation recovery')
48
+ const result = input.begin
49
+ ? await bridge.execute({ begin: input.begin, extract, normalize, signal })
50
+ : await bridge.resume({ operationId: input.resume.operationId, normalize, signal })
51
+ // A cache hit can return an older operation ID than the requested new one.
52
+ // Bind the actual runner result, never the caller's requested reservation.
53
+ const current = await bound(result.status.operationId)
54
+ return { result, operationBinding: current.operationBinding,
55
+ receiptRef: await receipt('extract', current, { cacheReuse: result.cacheReuse }),
56
+ usage: result.cacheReuse ? null : current.status.usage,
57
+ captureUsage: current.status.usage, cacheReuse: result.cacheReuse,
58
+ receiptAssurance: 'host-reference-to-existing-state', authority: 'none', semanticAcceptance: 'pending' }
59
+ }
60
+
61
+ const readKnowledgeView = async ({ requestedView, input, extraction }) => {
62
+ check(['native-exploration', 'accepted-knowledge'].includes(requestedView), 'Select an existing knowledge view')
63
+ const current = await bound(operationId(input, extraction)), selectedQuery = query(input)
64
+ // A domain reference identifies existing ledger/domain custody. It does not
65
+ // authenticate a human receiver or assert that any candidate was admitted.
66
+ const knowledgeView = requestedView === 'native-exploration'
67
+ ? await runner.proposals({ operationId: current.status.operationId, query: selectedQuery })
68
+ : await runner.context({ query: selectedQuery })
69
+ return { kind: requestedView, ownerRef: current.status.input.domainRef,
70
+ ownerRefSemantics: 'existing-knowledge-domain-reference', operationBinding: current.operationBinding,
71
+ knowledgeView, authority: 'none', canonicalMutation: false }
72
+ }
73
+
74
+ const retrieveOperation = async ({ input, question, view }) => {
75
+ check(view?.kind === 'native-exploration', 'This located proposal retriever serves native exploration only; accepted context stays with its receiver')
76
+ const current = await bound(view.operationBinding?.operationId)
77
+ // Revalidate evidence at retrieval, rather than serving a captured view object.
78
+ const proposalView = await runner.proposals({ operationId: current.status.operationId,
79
+ query: typeof question === 'string' && question.trim() ? question : query(input) })
80
+ const hits = proposalView.assertions.flatMap(assertion => assertion.evidence.map(citation => ({
81
+ evidenceRef: { sourceId: citation.sourceId, revision: citation.sourceDigest,
82
+ representationId: citation.attemptId, locator: structuredClone(citation.locator) },
83
+ quote: citation.quote, assertion: structuredClone(assertion),
84
+ score: null, scoreSemantics: 'literal-pending-proposal-match', semanticAcceptance: 'pending',
85
+ })))
86
+ return { hits, proposalView, operationBinding: current.operationBinding,
87
+ generation: proposalView.inputDigest,
88
+ artifactRef: { attemptId: current.operationBinding.attemptId,
89
+ outputDigest: current.operationBinding.completion.outputDigest },
90
+ receiptRef: await receipt('retrieve', current, { viewBinding: {
91
+ inputDigest: proposalView.inputDigest, domainRef: proposalView.domainRef,
92
+ answerClass: proposalView.answerClass, query: question ?? input.proposalQuery,
93
+ } }),
94
+ usage: null, receiptAssurance: 'host-reference-to-existing-state',
95
+ coverage: proposalView.coverage, readScope: proposalView.readScope,
96
+ authority: 'none', canonicalMutation: false, semanticAcceptance: 'pending' }
97
+ }
98
+ return Object.freeze({ bindings: Object.freeze({ extract: extractOperation, retrieve: retrieveOperation }),
99
+ // Private execution declaration for the receiver's own-property role checks.
100
+ // This does not register a capability or establish admission authority.
101
+ operationRoles: Object.freeze({ extract: 'extract', retrieve: 'retrieve' }), readKnowledgeView })
102
+ }
@@ -0,0 +1,218 @@
1
+ import { createHash } from 'node:crypto'
2
+ import { performance } from 'node:perf_hooks'
3
+
4
+ // Private supplier serialization, not an ontology, ledger, or public contract.
5
+ export const VANILLA_CAPTURE_FORMAT = 'atelier.vanilla-extraction-capture/v0'
6
+ export const MAX_CAPTURE_BYTES = 16 * 1024 * 1024 // Existing intake UTF-8 ceiling.
7
+ const digest = bytes => createHash('sha256').update(bytes).digest('hex')
8
+ const fields = ['inputTokens', 'outputTokens', 'cost', 'currency', 'elapsedMs', 'retries']
9
+
10
+ export class VanillaIngestionError extends Error {
11
+ constructor(code, message, { cause, recovery, recorded, captured, attemptedCapture, uncaptured } = {}) {
12
+ super(message, { cause }); this.name = 'VanillaIngestionError'; this.code = code
13
+ if (recovery) this.recovery = recovery
14
+ if (recorded) this.recorded = recorded
15
+ if (captured) this.captured = captured
16
+ if (attemptedCapture) this.attemptedCapture = attemptedCapture
17
+ if (uncaptured) this.uncaptured = uncaptured
18
+ }
19
+ }
20
+ function check(value, code, message) { if (!value) throw new VanillaIngestionError(code, message) }
21
+ function ownData(value, key) {
22
+ if (value === null || !['object', 'function'].includes(typeof value)) return undefined
23
+ try { return Object.getOwnPropertyDescriptor(value, key)?.value } catch { return undefined }
24
+ }
25
+ function same(left, right) {
26
+ // Object key order is not an intake or runner receipt contract.
27
+ const stable = value => value === null || typeof value !== 'object' ? JSON.stringify(value)
28
+ : Array.isArray(value) ? `[${value.map(stable).join(',')}]`
29
+ : `{${Object.keys(value).sort().map(key => `${JSON.stringify(key)}:${stable(value[key])}`).join(',')}}`
30
+ return stable(left) === stable(right)
31
+ }
32
+ function rawBytes(output) {
33
+ check(typeof output === 'string' || output instanceof Uint8Array, 'VANILLA_OUTPUT', 'Extractor output must be text or bytes')
34
+ return Buffer.from(output) // Copy: the host cannot mutate the captured buffer later.
35
+ }
36
+ function captureFor(status, output, suppliedUsage, elapsedMs) {
37
+ const bytes = rawBytes(output)
38
+ const usage = Object.fromEntries(fields.map(key => [key, suppliedUsage?.[key] ?? (key === 'elapsedMs' ? elapsedMs : null)]))
39
+ for (const value of Object.values(usage)) check(typeof value !== 'number' || Number.isFinite(value),
40
+ 'VANILLA_USAGE_ENCODING', 'Nonfinite reported usage cannot be losslessly encoded; retain returned bytes and settle host accounting')
41
+ const capture = {
42
+ format: VANILLA_CAPTURE_FORMAT,
43
+ inputDigest: status.input.digest,
44
+ extractor: status.extractor,
45
+ raw: { encoding: 'base64', bytes: bytes.length, sha256: digest(bytes), data: bytes.toString('base64') },
46
+ usage, usageAssurance: 'host-reported',
47
+ timing: { extractionElapsedMs: elapsedMs, assurance: 'host-measured-monotonic' },
48
+ coverage: status.input.coverage,
49
+ }
50
+ const outputEnvelope = JSON.stringify(capture)
51
+ check(Buffer.byteLength(outputEnvelope) <= MAX_CAPTURE_BYTES, 'VANILLA_CAPTURE_LIMIT', 'Capture exceeds the existing intake byte ceiling')
52
+ return { capture, outputEnvelope, outputDigest: digest(outputEnvelope) }
53
+ }
54
+
55
+ /** Verify the immutable wrapper and exact producer/input pins before reuse. */
56
+ export function readVanillaCapture(status) {
57
+ check(['partial', 'complete'].includes(status?.attempt?.status) && typeof status.attempt.output === 'string', 'VANILLA_CAPTURE_MISSING', 'No saved extraction bytes are available')
58
+ const outputEnvelope = status.attempt.output
59
+ check(Buffer.byteLength(outputEnvelope) <= MAX_CAPTURE_BYTES, 'VANILLA_CAPTURE_LIMIT', 'Saved capture exceeds the intake ceiling')
60
+ let capture
61
+ try { capture = JSON.parse(outputEnvelope) } catch (cause) { throw new VanillaIngestionError('VANILLA_CAPTURE_INTEGRITY', 'Saved output is not a vanilla capture', { cause }) }
62
+ check(capture?.format === VANILLA_CAPTURE_FORMAT && capture.inputDigest === status.input.digest &&
63
+ same(capture.extractor, status.extractor) && capture.coverage === status.input.coverage &&
64
+ capture.usageAssurance === 'host-reported' && same(Object.keys(capture.usage ?? {}).sort(), [...fields].sort()),
65
+ 'VANILLA_CAPTURE_INTEGRITY', 'Capture producer, input, coverage or usage pins differ')
66
+ const raw = capture.raw
67
+ check(raw?.encoding === 'base64' && typeof raw.data === 'string' && Number.isSafeInteger(raw.bytes) && raw.bytes >= 0,
68
+ 'VANILLA_CAPTURE_INTEGRITY', 'Capture must retain exact encoded raw bytes')
69
+ const bytes = Buffer.from(raw.data, 'base64')
70
+ check(bytes.toString('base64') === raw.data && bytes.length === raw.bytes && digest(bytes) === raw.sha256,
71
+ 'VANILLA_CAPTURE_INTEGRITY', 'Extractor raw-byte digest differs')
72
+ const outputDigest = digest(outputEnvelope)
73
+ check(status.attempt.status !== 'complete' || status.attempt.completion?.outputDigest === outputDigest,
74
+ 'VANILLA_CAPTURE_INTEGRITY', 'Intake envelope digest differs')
75
+ if (status.phase === 'completed') check(same(status.usage, capture.usage), 'VANILLA_CAPTURE_INTEGRITY', 'Recorded usage differs from immutable capture')
76
+ return { capture, bytes, outputEnvelope, outputDigest }
77
+ }
78
+
79
+ export function normalizeCandidateJson({ bytes }) {
80
+ return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes))
81
+ }
82
+
83
+ /** A provider-free authored/deterministic callback; vocabulary remains host-owned. */
84
+ export function createCandidateExtractor(buildCandidates) {
85
+ check(typeof buildCandidates === 'function', 'VANILLA_EXTRACTOR', 'A candidate authoring function is required')
86
+ return async ({ input, extractor, signal }) => {
87
+ check(['authored', 'deterministic'].includes(extractor.route), 'VANILLA_EXTRACTOR', 'This helper only implements provider-free routes')
88
+ const candidates = await buildCandidates({ input, signal })
89
+ return { output: JSON.stringify(candidates), usage: { inputTokens: 0, outputTokens: 0, cost: 0, currency: null, retries: 0 } }
90
+ }
91
+ }
92
+
93
+ /** Host composition supplies the existing createSemanticOperation result. */
94
+ export function createVanillaIngestionBridge({ runner, captureAttempt = null, now = () => new Date().toISOString(), monotonic = () => performance.now() }) {
95
+ for (const method of ['begin', 'status', 'complete', 'proposals']) check(typeof runner?.[method] === 'function', 'VANILLA_RUNNER', `Existing semantic runner.${method} is required`)
96
+ check(captureAttempt === null || typeof captureAttempt === 'function', 'VANILLA_CAPTURE', 'The existing intake completion callback is required when supplied')
97
+ function notAborted(signal) { check(!signal?.aborted, 'VANILLA_ABORTED', 'Host cancelled extraction or interpretation; reopen saved state') }
98
+ async function failure(error, operationId, stage, extra = {}) {
99
+ let status = null
100
+ try { status = await runner.status({ operationId }) } catch { /* Never erase original saved receipts. */ }
101
+ let captured = extra.captured
102
+ const attemptedCapture = extra.attemptedCapture ?? ownData(error, 'captured')
103
+ const expectedOutputDigest = extra.expectedOutputDigest ?? ownData(ownData(attemptedCapture, 'completion'), 'outputDigest')
104
+ const expectedAttemptId = extra.expectedAttemptId ?? ownData(attemptedCapture, 'attemptId')
105
+ if (!captured && !extra.captureReadbackFailed && (expectedOutputDigest || stage === 'recovery') &&
106
+ ['partial', 'complete'].includes(status?.attempt?.status)) {
107
+ try {
108
+ const saved = readVanillaCapture(status)
109
+ if (status.operationId === operationId && (!expectedOutputDigest || saved.outputDigest === expectedOutputDigest) &&
110
+ (!expectedAttemptId || status.attempt.attempt.attemptId === expectedAttemptId)) captured = { attemptId: status.attempt.attempt.attemptId,
111
+ completion: status.attempt.completion, head: status.head, nextAction: 'reopen-captured-output' }
112
+ } catch { /* Unverified readback is never presented as a saved receipt. */ }
113
+ }
114
+ const code = ownData(error, 'code'), message = ownData(error, 'message')
115
+ return new VanillaIngestionError(typeof code === 'string' ? code : 'VANILLA_INTERRUPTED', typeof message === 'string' ? message : 'Host operation was interrupted', {
116
+ cause: error, recorded: ownData(error, 'recorded'), captured, attemptedCapture, uncaptured: captured ? undefined : extra.uncaptured,
117
+ recovery: { operationId, stage, phase: status?.phase ?? null, execution: status?.execution ?? 'unknown',
118
+ nextAction: captured ? 'resume-interpretation-from-capture' : 'inspect-and-explicitly-reconcile-execution',
119
+ extractorMayRunAgain: false },
120
+ })
121
+ }
122
+ async function verifyCapture({ operationId, attemptId, expectedOutputDigest, completion }) {
123
+ const reread = await runner.status({ operationId })
124
+ const verified = readVanillaCapture(reread)
125
+ check(reread.operationId === operationId && reread.attempt.attempt.attemptId === attemptId &&
126
+ reread.attempt.status === 'complete' && verified.outputDigest === expectedOutputDigest && same(completion, reread.attempt.completion),
127
+ 'VANILLA_CAPTURE_INTEGRITY', 'Existing intake completion readback differs')
128
+ return { attemptId, completion: reread.attempt.completion, head: reread.head, nextAction: 'reopen-captured-output' }
129
+ }
130
+ async function result(status, { query, proposals = null, cacheReuse = false } = {}) {
131
+ check(status.freshness === 'current', 'VANILLA_STALE', 'Saved extraction is stale; use a new structural plan and extraction operation')
132
+ const saved = readVanillaCapture(status)
133
+ return { status, capture: saved.capture, proposals,
134
+ proposalView: query === undefined ? null : await runner.proposals({ operationId: status.operationId, query }),
135
+ cacheReuse, coverage: status.input.coverage, readScope: status.input.readScope,
136
+ sourceReferences: status.input.evidence.map(span => span.reference),
137
+ semanticAcceptance: 'pending', canonicalMutation: false, authority: 'none' }
138
+ }
139
+ async function interpret(status, { normalize, query, signal }) {
140
+ check(status.freshness === 'current', 'VANILLA_STALE', 'Captured output is retained but its source or domain is stale')
141
+ const saved = readVanillaCapture(status)
142
+ if (status.phase === 'completed') return result(status, { query, cacheReuse: true })
143
+ check(status.phase === 'reserved', 'VANILLA_RECOVERY_REQUIRED', 'Only a reserved capture may finish interpretation')
144
+ notAborted(signal)
145
+ const candidates = await normalize({ bytes: Buffer.from(saved.bytes), input: structuredClone(status.input), extractor: structuredClone(status.extractor) })
146
+ notAborted(signal)
147
+ // Reopen after asynchronous normalization. The actual runner rechecks source,
148
+ // input, immutable raw bytes and history before recording candidates.
149
+ const current = await runner.status({ operationId: status.operationId })
150
+ if (current.phase === 'completed') return result(current, { query, cacheReuse: true })
151
+ check(current.freshness === 'current', 'VANILLA_STALE', 'Source or adopted domain changed during interpretation')
152
+ const completed = await runner.complete({ operationId: status.operationId, output: saved.outputEnvelope,
153
+ expectedOutputDigest: saved.outputDigest, candidates, usage: saved.capture.usage, at: now(), confirm: current.head })
154
+ return result(completed, { query, proposals: completed.proposals })
155
+ }
156
+ async function execute({ begin, extract, normalize = normalizeCandidateJson, query, signal }) {
157
+ check(typeof extract === 'function' && typeof normalize === 'function', 'VANILLA_EXTRACTOR', 'Host extraction and pure normalization callbacks are required')
158
+ notAborted(signal)
159
+ let ready, extracted, retainedOutput, saved, captured, attemptedCapture, captureReadbackFailed = false, stage = 'reservation'
160
+ try {
161
+ ready = await runner.begin(begin)
162
+ if (ready.cacheReuse) return await result(ready, { query, cacheReuse: true })
163
+ check(ready.execution === 'ready-for-host', 'VANILLA_EXECUTION_UNKNOWN', 'Only a new ready reservation permits host extraction')
164
+ notAborted(signal); stage = 'extraction'
165
+ const started = monotonic()
166
+ extracted = await extract({ input: structuredClone(ready.input), extractor: structuredClone(ready.extractor), signal,
167
+ limits: { maxCaptureBytes: MAX_CAPTURE_BYTES, rawEncoding: 'base64' } })
168
+ const elapsedMs = Math.max(0, Math.round(monotonic() - started))
169
+ stage = 'capture'
170
+ retainedOutput = { output: rawBytes(extracted?.output), usage: structuredClone(extracted?.usage) }
171
+ saved = captureFor(ready, extracted?.output, extracted?.usage, elapsedMs)
172
+ const current = await runner.status({ operationId: ready.operationId })
173
+ if (captureAttempt) {
174
+ // The manifest is the runner's reservation. Capture uses that same
175
+ // existing intake owner; runner.complete subsequently verifies it again.
176
+ const attemptId = current.attempt.attempt?.attemptId
177
+ check(current.phase === 'reserved' && attemptId === ready.attempt.attempt.attemptId,
178
+ 'VANILLA_CAPTURE_INTEGRITY', 'Capture requires the original reserved intake manifest')
179
+ attemptedCapture = { attemptId, expectedOutputDigest: saved.outputDigest, head: current.head, nextAction: 'inspect-capture-custody' }
180
+ attemptedCapture.completion = await captureAttempt({ attemptId, output: saved.outputEnvelope, expectedOutputDigest: saved.outputDigest })
181
+ stage = 'capture-readback'; captureReadbackFailed = true
182
+ captured = await verifyCapture({ operationId: ready.operationId, attemptId, expectedOutputDigest: saved.outputDigest, completion: attemptedCapture.completion })
183
+ captureReadbackFailed = false
184
+ } else {
185
+ // Runner-only compatibility fallback. There is currently no runner
186
+ // capture-only method; absent candidates produce an expected refusal.
187
+ try {
188
+ await runner.complete({ operationId: ready.operationId, output: saved.outputEnvelope, expectedOutputDigest: saved.outputDigest,
189
+ candidates: null, usage: saved.capture.usage, at: now(), confirm: current.head })
190
+ throw new VanillaIngestionError('VANILLA_RUNNER_PROFILE', 'Runner unexpectedly admitted absent candidates')
191
+ } catch (error) {
192
+ const receipt = ownData(error, 'captured')
193
+ if (!receipt) throw error
194
+ attemptedCapture = receipt
195
+ if (ownData(error, 'code') !== 'SEMANTIC_INVALID') throw error
196
+ stage = 'capture-readback'; captureReadbackFailed = true
197
+ captured = await verifyCapture({ operationId: ready.operationId, attemptId: ready.attempt.attempt.attemptId,
198
+ expectedOutputDigest: saved.outputDigest, completion: ownData(receipt, 'completion') })
199
+ captureReadbackFailed = false
200
+ }
201
+ }
202
+ stage = 'interpretation'
203
+ return await interpret(await runner.status({ operationId: ready.operationId }), { normalize, query, signal })
204
+ } catch (error) {
205
+ throw await failure(error, ready?.operationId ?? begin?.operationId, stage,
206
+ { captured, attemptedCapture, captureReadbackFailed, expectedOutputDigest: saved?.outputDigest,
207
+ expectedAttemptId: ready?.attempt?.attempt?.attemptId,
208
+ uncaptured: stage.startsWith('capture') && !captured && extracted ? retainedOutput ?? extracted : undefined })
209
+ }
210
+ }
211
+ // No extractor argument by design: recovery cannot charge extraction again.
212
+ async function resume({ operationId, normalize = normalizeCandidateJson, query, signal }) {
213
+ check(typeof normalize === 'function', 'VANILLA_EXTRACTOR', 'A pure normalization callback is required')
214
+ try { return await interpret(await runner.status({ operationId }), { normalize, query, signal }) }
215
+ catch (error) { throw await failure(error, operationId, 'recovery') }
216
+ }
217
+ return Object.freeze({ execute, resume })
218
+ }