@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,77 @@
1
+ import { assertDocument } from '../capabilities/package.mjs'
2
+ import { inquiryDigest, inquiryRef } from './contracts.mjs'
3
+ import { inspectInquiry } from './ledger.mjs'
4
+ import { restrictiveAudience } from '../harnesses/contracts.mjs'
5
+
6
+ // Files are proposed source edits. No graph source, relation, or review status
7
+ // is written by this function. The receiver owns disclosure and promotion.
8
+ export function inquiryGraphProposal(records, { namespace }) {
9
+ if (!/^[a-z][a-z0-9-]{0,63}$/.test(namespace)) throw new Error('invalid inquiry graph namespace')
10
+ const state = inspectInquiry(records), stale = new Set(state.reconsider.map(r => r.id))
11
+ const byId = new Map(records.map(r => [r.id, r])), files = new Map(), claims = []
12
+ const node = r => `${namespace}:inquiry-${state.campaign.id}-${r.id}`
13
+ const literal = value => {
14
+ const text = typeof value === 'string' ? value : JSON.stringify(value, null, 2)
15
+ const fence = '`'.repeat(Math.max(3, ...[...text.matchAll(/`+/g)].map(m => m[0].length + 1)))
16
+ return `${fence}text\n${text}\n${fence}`
17
+ }
18
+ // A file carries the most restrictive audience of the campaign and of every
19
+ // source whose material it copies; a sensitive quote is never labelled private.
20
+ const fileAudience = new Map()
21
+ function add(record, body, audience = state.campaign.data.audience) {
22
+ const id = node(record)
23
+ if (files.has(id)) return
24
+ fileAudience.set(`${record.id}.md`, audience)
25
+ files.set(id, { path: `${record.id}.md`, content: [
26
+ '---', `title: ${JSON.stringify(`Inquiry ${record.kind}: ${record.id}`)}`, 'kg:', ` id: ${JSON.stringify(id)}`, ' type: "document"',
27
+ ' status: "draft"', ` audience: ${JSON.stringify(audience)}`, ' relations: {}', '---', '',
28
+ `# Inquiry ${record.kind}: ${record.id}`, '', `Record digest: ${inquiryDigest(record)}`, '',
29
+ 'Proposed source. Review and admission belong to the receiving repository. Caller-reported evidence is not authenticated.', '', literal(body), '',
30
+ ].join('\n') })
31
+ }
32
+ function edge(subject, predicate, object) {
33
+ const claim = { schema: 'atelier-claim@v1', claimId: `claim:inquiry-${inquiryDigest([node(subject), predicate, node(object)]).slice(7)}`, subject: node(subject), predicate, object: node(object), provider: 'script', status: 'proposed', promoted: false, evidence: [inquiryDigest(subject), inquiryDigest(object)] }
34
+ if (!claims.some(c => c.claimId === claim.claimId)) claims.push(claim)
35
+ }
36
+ for (const decision of records.filter(r => r.kind === 'decision' && r.data.disposition === 'accepted' && !stale.has(r.id))) {
37
+ const assessment = byId.get(decision.data.assessment.id), hypothesis = byId.get(assessment.data.hypothesis.id)
38
+ // The assessment copies each cited bundle's conflicts, gaps and questions,
39
+ // so its label covers every source that bundle reports or asserts from.
40
+ const quoted = assessment.data.evidence.flatMap(item => {
41
+ const bundle = byId.get(item.bundle.id)
42
+ return [...bundle.data.reports.map(ref => ref.id), ...bundle.data.assertions.map(a => a.source.id)].map(id => byId.get(id).data.audience)
43
+ })
44
+ const audience = restrictiveAudience(state.campaign.data.audience, ...quoted)
45
+ add(decision, { conclusion: decision.data.conclusion, reason: decision.data.reason, reviewerReport: { by: decision.by, at: decision.at, basis: decision.data.reviewBasis }, nextQuestions: decision.data.nextQuestions }, audience)
46
+ add(assessment, { model: assessment.data.model, result: state.assessments[assessment.id], rationale: assessment.data.rationale,
47
+ evidence: assessment.data.evidence.map(item => {
48
+ const bundle = byId.get(item.bundle.id)
49
+ return { bundle: item.bundle, request: bundle.data.request, provider: bundle.data.provider,
50
+ assertion: bundle.data.assertions.find(a => a.id === item.assertion), conflicts: bundle.data.conflicts, gaps: bundle.data.gaps, newQuestions: bundle.data.newQuestions }
51
+ }) }, audience)
52
+ add(hypothesis, hypothesis.data)
53
+ edge(decision, 'depends_on', assessment); edge(assessment, 'related', hypothesis)
54
+ for (const item of assessment.data.evidence) {
55
+ const bundle = byId.get(item.bundle.id), assertion = bundle.data.assertions.find(a => a.id === item.assertion), source = byId.get(assertion.source.id)
56
+ // Preserve selected statements, provenance and conflicts, without copying
57
+ // raw captures or unrelated assertions into accepted knowledge proposals.
58
+ add(source, { locator: source.data.locator, digest: source.data.digest, family: source.data.family, scope: source.data.scope, method: source.data.method }, restrictiveAudience(state.campaign.data.audience, source.data.audience))
59
+ edge(source, 'evidences', assessment)
60
+ edge(source, assertion.stance === 'neutral' ? 'related' : assertion.stance, hypothesis)
61
+ }
62
+ }
63
+ return { schema: 'atelier-inquiry-graph-proposal@v1', campaign: state.campaign?.id ?? null, historyDigest: state.head, audience: state.campaign ? restrictiveAudience(state.campaign.data.audience, ...[...files.values()].map(file => fileAudience.get(file.path))) : null, files: [...files.values()], claims, reconsider: state.reconsider, canonicalMutation: false, authority: 'none' }
64
+ }
65
+
66
+ export function inquiryStewardObservation(records, feedbackId) {
67
+ inspectInquiry(records)
68
+ const feedback = records.find(r => r.id === feedbackId && r.kind === 'feedback')
69
+ if (!feedback) throw new Error('inquiry feedback missing')
70
+ const request = records.find(r => r.id === feedback.data.request.id), binding = request.data.binding
71
+ if (!binding) throw new Error('request has no capability binding provenance')
72
+ const reportedCause = feedback.data.cause
73
+ const cause = ['context', 'provider'].includes(reportedCause) ? 'unknown' : reportedCause
74
+ const event = { schema: 'mnstry.atelier-capability-event@v1', id: feedback.id, kind: 'feedback', ...binding, observer: feedback.by, outcome: feedback.data.outcome, cause, evidenceDigest: feedback.data.evidenceDigest, at: feedback.at }
75
+ assertDocument(event, 'event')
76
+ return { event, inquiryRecord: inquiryRef(feedback), reportedCause, causeMapping: cause === reportedCause ? 'exact' : 'unsupported-steward-cause-preserved-in-inquiry', assurance: 'caller-reported; current binding must be checked by capability observe', recorded: false }
77
+ }
@@ -0,0 +1,35 @@
1
+ import { jsonAt, stat, within, workspaceRoot, replaceJson } from '../capabilities/files.mjs'
2
+ import { withOperationLock } from '../capabilities/adoption.mjs'
3
+ import { assertInquiry, inquiryDigest, INQUIRY_LIMITS } from './contracts.mjs'
4
+ import { EMPTY_INQUIRY_HEAD, inspectInquiry } from './ledger.mjs'
5
+
6
+ function location(id) {
7
+ if (typeof id !== 'string' || !/^[a-z][a-z0-9-]{0,63}$/.test(id)) throw new Error('invalid campaign identity')
8
+ return `.atelier-local/inquiry/${id}/ledger.json`
9
+ }
10
+ function read(root, campaign) {
11
+ const file = location(campaign)
12
+ if (!stat(within(root, file))) return { records: [], head: EMPTY_INQUIRY_HEAD }
13
+ const ledger = assertInquiry(jsonAt(root, file), 'ledger')
14
+ const state = inspectInquiry(ledger.records)
15
+ if (state.head !== ledger.head || state.campaign.id !== campaign) throw new Error('inquiry ledger integrity mismatch')
16
+ return state
17
+ }
18
+ export function readInquiry({ workspaceRoot: input, campaign }) {
19
+ return inspectInquiry(read(workspaceRoot(input), campaign).records)
20
+ }
21
+ export function appendInquiry({ workspaceRoot: input, record, confirm }) {
22
+ assertInquiry(record)
23
+ const root = workspaceRoot(input, { write: true })
24
+ return withOperationLock(root, () => {
25
+ const before = read(root, record.campaign)
26
+ if (before.head !== confirm) throw new Error('inquiry append requires the current history digest')
27
+ const next = inspectInquiry([...before.records, record])
28
+ // A single atomic replacement retains the entire immutable record history.
29
+ // The shared lock serializes cooperating writers; it is not an OS sandbox.
30
+ const ledger = { schema: 'atelier-inquiry-ledger@v1', records: next.records, head: inquiryDigest(next.records) }
31
+ if (Buffer.byteLength(JSON.stringify(ledger, null, 2)) + 1 > INQUIRY_LIMITS.bytes) throw new Error('serialized inquiry ledger exceeds byte ceiling')
32
+ replaceJson(root, location(record.campaign), ledger)
33
+ return { recorded: record.id, head: next.head, assessment: next.assessments[record.id] ?? null, reconsider: next.reconsider, authority: 'none' }
34
+ })
35
+ }
@@ -0,0 +1,12 @@
1
+ // Internal coordinator capability, intentionally absent from the package's
2
+ // public exports. Only synchronous, library-owned read loops enter a scope;
3
+ // caller callbacks and mutations must not inherit placement admission.
4
+ const scopes = new WeakMap();
5
+
6
+ export function registerIntakeReadScope(store, run) { scopes.set(store, run); }
7
+
8
+ export function withIntakeReadScope(store, read) {
9
+ const run = scopes.get(store);
10
+ if (!run) throw new Error('intake read scope is unavailable');
11
+ return run(read);
12
+ }
@@ -1,4 +1,4 @@
1
- import { withPrivateLock, publishPrivateFile } from '../project/durable-state.mjs';
1
+ import { withPrivateLock, publishPrivateFile, isPendingPrivateWrite } from '../project/durable-state.mjs';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { createHash } from 'node:crypto';
@@ -6,6 +6,7 @@ import { execFileSync } from 'node:child_process';
6
6
  import { canonicalize } from '../attestation/jcs.mjs';
7
7
  import { validateJsonSchema } from '../export/atelier-export-contract.mjs';
8
8
  import { ensureContainedPrivateDirectory, openRegularFileNoFollow } from '../project/private-state.mjs';
9
+ import { registerIntakeReadScope } from './read-scope.mjs';
9
10
 
10
11
  export const INTAKE_MAX_BYTES = 16 * 1024 * 1024;
11
12
  const schema = JSON.parse(fs.readFileSync(new URL('../../contracts/atelier-intake.v1.schema.json', import.meta.url), 'utf8'));
@@ -34,21 +35,44 @@ function immutable(file, bytes) {
34
35
  // authority. Callers retain their source trees and choose their existing extractor.
35
36
  export function createIntakeStore({ workspaceRoot = process.cwd() } = {}) {
36
37
  const root = fs.realpathSync(workspaceRoot);
37
- function placement() {
38
+ let readScopeActive = false, placementChecked = false;
39
+ function placement(force = false) {
40
+ if (readScopeActive && placementChecked && !force) return;
38
41
  const env = Object.fromEntries(Object.entries(process.env).filter(([key]) => !key.toUpperCase().startsWith('GIT_')));
39
42
  try {
40
43
  if (execFileSync('git', ['-C', root, 'ls-files', '-z', '--', '.atelier-local'], { env, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] })) throw new Error('tracked state');
41
44
  execFileSync('git', ['-C', root, 'check-ignore', '--quiet', '.atelier-local/'], { env, stdio: 'ignore' });
42
45
  } catch { throw new Error('intake requires ignored, untracked .atelier-local/ in a Git workspace'); }
46
+ placementChecked = readScopeActive;
43
47
  }
44
48
  placement();
49
+ function readScope(read) {
50
+ const active = readScopeActive;
51
+ readScopeActive = true; placementChecked = false;
52
+ try {
53
+ placement();
54
+ const result = read();
55
+ // Result inspection must not pass admission to a thenable's accessor,
56
+ // and asynchronous work must obtain fresh admission after it resumes.
57
+ readScopeActive = false; placementChecked = false;
58
+ if (typeof result?.then === 'function') throw new Error('intake read scope requires a synchronous result');
59
+ // No result escapes if placement changed during the read-only operation.
60
+ placement(true);
61
+ return result;
62
+ } finally { readScopeActive = active; placementChecked = false; }
63
+ }
45
64
  function directory(...parts) {
46
65
  return ensureContainedPrivateDirectory({ workspaceRoot: root, directory: path.join(root, '.atelier-local', 'intake', ...parts), label: 'intake state' });
47
66
  }
48
67
  function locked(fn) {
49
- placement();
50
- const file = path.join(directory(), 'operation.lock');
51
- return withPrivateLock(file, fn);
68
+ // A mutation cannot inherit or leave behind read-scope admission.
69
+ const active = readScopeActive;
70
+ readScopeActive = false; placementChecked = false;
71
+ try {
72
+ placement();
73
+ const file = path.join(directory(), 'operation.lock');
74
+ return withPrivateLock(file, fn);
75
+ } finally { readScopeActive = active; placementChecked = false; }
52
76
  }
53
77
  function sourceFile(ref) {
54
78
  if (typeof ref !== 'string' || !ref || path.isAbsolute(ref) || ref.includes('\\') ||
@@ -66,7 +90,44 @@ export function createIntakeStore({ workspaceRoot = process.cwd() } = {}) {
66
90
  return bytes;
67
91
  }
68
92
  function record(dir, name, value) { valid(value); immutable(path.join(dir, name), canonicalize(value) + '\n'); return value; }
69
- return Object.freeze({
93
+ const store = Object.freeze({
94
+ // Explicit current-source reads stay behind intake's containment and byte
95
+ // checks. They do not enroll a source or interpret its contents.
96
+ readSource({ ref, expectedDigest } = {}) {
97
+ placement();
98
+ if (expectedDigest !== undefined) digest(expectedDigest);
99
+ const bytes = read(sourceFile(ref)), actual = intakeDigest(bytes);
100
+ if (expectedDigest !== undefined && actual !== expectedDigest) throw Object.assign(new Error('current source digest differs'), { code: 'INTAKE_SOURCE_CHANGED' });
101
+ return { ref, digest: actual, bytes };
102
+ },
103
+ // A missing directory is a cache miss. A broken committed attempt is an
104
+ // integrity failure, never permission to overwrite or retry it silently.
105
+ readAttempt(attemptId) {
106
+ placement(); id(attemptId);
107
+ const dir = path.join(directory('attempts'), attemptId);
108
+ try { fs.lstatSync(dir); }
109
+ catch (error) { if (error.code === 'ENOENT') return { status: 'absent', attempt: null, completion: null, output: null }; throw error; }
110
+ directory('attempts', attemptId);
111
+ try {
112
+ const names = fs.readdirSync(dir).filter(name => !isPendingPrivateWrite(name));
113
+ if (names.some(name => !['attempt.json', 'completion.json', 'output.txt'].includes(name))) throw new Error('unknown attempt file');
114
+ if (!names.includes('attempt.json')) {
115
+ if (names.length) throw new Error('orphaned attempt bytes');
116
+ return { status: 'absent', attempt: null, completion: null, output: null };
117
+ }
118
+ const attemptBytes = read(path.join(dir, 'attempt.json')), attempt = valid(JSON.parse(attemptBytes));
119
+ if (attempt.schema !== 'mnstry.atelier-intake-attempt@v1' || attempt.attemptId !== attemptId) throw new Error('attempt identity differs');
120
+ blob(attempt.blobId);
121
+ const outputBytes = names.includes('output.txt') ? read(path.join(dir, 'output.txt')) : null;
122
+ const output = outputBytes === null ? null : new TextDecoder('utf-8', { fatal: true }).decode(outputBytes);
123
+ if (!names.includes('completion.json')) return { status: output === null ? 'begun' : 'partial', attempt, completion: null, output };
124
+ const completion = valid(JSON.parse(read(path.join(dir, 'completion.json'))));
125
+ if (completion.schema !== 'mnstry.atelier-intake-completion@v1' || completion.attemptId !== attemptId ||
126
+ completion.integrity !== 'verified' || completion.semanticAcceptance !== 'pending' || outputBytes === null ||
127
+ completion.attemptDigest !== intakeDigest(attemptBytes) || completion.outputDigest !== intakeDigest(outputBytes) || completion.bytes !== outputBytes.length) throw new Error('completion integrity differs');
128
+ return { status: 'complete', attempt, completion, output };
129
+ } catch { throw Object.assign(new Error('intake attempt integrity refused'), { code: 'INTAKE_INTEGRITY' }); }
130
+ },
70
131
  ingest({ ref, expectedDigest }) {
71
132
  return locked(() => {
72
133
  digest(expectedDigest);
@@ -116,4 +177,6 @@ export function createIntakeStore({ workspaceRoot = process.cwd() } = {}) {
116
177
  return receipt;
117
178
  },
118
179
  });
180
+ registerIntakeReadScope(store, readScope);
181
+ return store;
119
182
  }
@@ -0,0 +1,91 @@
1
+ import { assertInteraction, qualifyReflection, reflectionReference, validateInteraction } from '../reflection/index.mjs'
2
+ import { boundedLearningValue, learningDigest as digest } from '../learning/contracts.mjs'
3
+ export { validateInteraction }
4
+
5
+ // Host contexts contain current source records, not just self-reported hashes.
6
+ // Intention/preference owners provide exact revision pins after their own checks.
7
+ export function selectInteractionAct({ act, policy, context, state, at }) {
8
+ assertInteraction(act, 'act'); assertInteraction(policy, 'policy')
9
+ boundedLearningValue(context); boundedLearningValue(state)
10
+ if (!Number.isFinite(Date.parse(at))) throw new Error('selection time required')
11
+ const reasons = [], scope = policy.scope, purpose = policy.purpose
12
+ if (act.scope !== scope || act.purpose !== purpose) reasons.push('scope-or-purpose-differs')
13
+ if (Date.parse(act.expiresAt) <= Date.parse(at)) reasons.push('expired')
14
+ // Reflective and coaching acts are Reflection whatever their origin; only
15
+ // ordinary Companion and work acts function with Reflection off.
16
+ const reflective = act.origin === 'witness' || act.mode !== 'ordinary'
17
+ if (act.origin === 'witness' && act.mode === 'ordinary') reasons.push('reflective-mode-required')
18
+ if (reflective && !policy.reflectionEnabled) reasons.push('reflection-disabled')
19
+ if (act.mode === 'coaching' && (!policy.coachingEnabled || !act.dependencies.some(p => p.kind === 'intention'))) reasons.push('coaching-unavailable')
20
+ if (act.kind === 'challenge' && !policy.challengeEnabled) reasons.push('challenge-disabled')
21
+ if (reflective && !act.dependencies.some(p => p.kind === 'assessment')) reasons.push('reflective-assessment-missing')
22
+ if (reflective && policy.initiative === 'responsive' && state.requestedReflection !== true) reasons.push('reflection-not-requested')
23
+ if (!context || Object.keys(context).sort().join() !== 'assessments,observations,orientations' || !Array.isArray(context.observations) || !Array.isArray(context.assessments) || !Array.isArray(context.orientations) || context.observations.length > 128 || context.assessments.length > 64 || context.orientations.length > 64) throw new Error('bounded current interaction context required')
24
+ const refs = []
25
+ for (const observation of context.observations) {
26
+ assertInteraction(observation, 'observation')
27
+ if (observation.scope === scope && observation.purpose === purpose && observation.status === 'active') refs.push(reflectionReference(observation))
28
+ }
29
+ for (const assessment of context.assessments) if (qualifyReflection({ assessment, observations: context.observations, scope, purpose }).current) refs.push(reflectionReference(assessment))
30
+ for (const orientation of context.orientations) {
31
+ if (!orientation || Object.keys(orientation).sort().join() !== 'active,digest,id,kind,purpose,scope' || !['intention', 'preference'].includes(orientation.kind) || typeof orientation.id !== 'string' || !/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/.test(orientation.id) || !/^sha256:[a-f0-9]{64}$/.test(orientation.digest) || typeof orientation.active !== 'boolean') throw new Error('invalid orientation reference')
32
+ if (orientation.active && orientation.scope === scope && orientation.purpose === purpose) refs.push({ kind: orientation.kind, id: orientation.id, digest: orientation.digest })
33
+ }
34
+ if (new Set(refs.map(r => `${r.kind}:${r.id}`)).size !== refs.length) throw new Error('ambiguous current context identity')
35
+ for (const pin of act.dependencies) if (!refs.some(r => digest(r) === digest(pin))) reasons.push(`dependency-not-current:${pin.kind}:${pin.id}`)
36
+ const defer = state.paused === true || state.busy === true || state.floor !== 'assistant'
37
+ return { actDigest: digest(act), policyDigest: digest(policy), contextDigest: digest(context),
38
+ selection: reasons.length ? 'declined' : defer ? 'deferred' : 'selected', reasons: reasons.length ? reasons : defer ? ['conversation-floor-unavailable'] : [],
39
+ qualityCriteria: [...policy.qualities], qualityEvaluated: false, executionAuthorized: false }
40
+ }
41
+
42
+ // One host owns floor, durable reservations and native delivery. This controller
43
+ // composes typed contributions; it never starts a second conversation or monitor.
44
+ export function createInteractionController({ authorityId, host }) {
45
+ if (typeof authorityId !== 'string' || !authorityId || host?.authorityId !== authorityId || ['current', 'authorize', 'reserve', 'send', 'read', 'interrupt'].some(k => typeof host[k] !== 'function')) throw new Error('one complete conversation authority required')
46
+ const active = new Map()
47
+ function checked(receipt, key, act) {
48
+ if (!receipt || receipt.key !== key || receipt.authorityId !== authorityId || receipt.actDigest !== digest(act) || !['reserved', 'begun', 'completed', 'interrupted', 'failed', 'unknown'].includes(receipt.status) || typeof receipt.deliveredText !== 'string' || !act.text.startsWith(receipt.deliveredText) || (receipt.status === 'completed' && receipt.deliveredText !== act.text)) throw new Error('native delivery readback does not match the intended act')
49
+ return { ...structuredClone(receipt), understandingVerified: false, improvementVerified: false }
50
+ }
51
+ return Object.freeze({
52
+ async deliver(act) {
53
+ act = boundedLearningValue(act); assertInteraction(act, 'act')
54
+ const key = digest({ authorityId, scope: act.scope, id: act.id })
55
+ if (active.has(key)) throw new Error('delivery already active; inspect or interrupt it')
56
+ const current = await host.current(), selection = selectInteractionAct({ act, ...current })
57
+ if (selection.selection !== 'selected') return { selection, delivery: null }
58
+ if (await host.authorize({ actDigest: digest(act), scope: act.scope, purpose: act.purpose, authorityId }) !== true) throw new Error('host did not authorize this interaction')
59
+ const reservation = await host.reserve({ key, authorityId, actDigest: digest(act), selection })
60
+ if (reservation?.created !== true) {
61
+ // A previous attempt may already have emitted content. Read it instead
62
+ // of turning uncertainty or a lost reply into duplicate guidance.
63
+ return { selection, delivery: checked(await host.read(key), key, act), replayed: true }
64
+ }
65
+ const controller = new AbortController(); active.set(key, controller)
66
+ try {
67
+ const fresh = await host.current(), recheck = selectInteractionAct({ act, ...fresh })
68
+ if (recheck.selection !== 'selected' || recheck.policyDigest !== selection.policyDigest || recheck.contextDigest !== selection.contextDigest) {
69
+ await host.interrupt({ key, reason: 'context-changed-before-delivery', authorityId })
70
+ return { selection: recheck, delivery: checked(await host.read(key), key, act) }
71
+ }
72
+ try { await host.send({ key, authorityId, act: structuredClone(act), signal: controller.signal }) }
73
+ catch { /* Native readback determines failed, interrupted or unknown. */ }
74
+ return { selection, delivery: checked(await host.read(key), key, act) }
75
+ } finally { active.delete(key) }
76
+ },
77
+ async interrupt(act, reason) {
78
+ assertInteraction(act, 'act')
79
+ if (typeof reason !== 'string' || !reason || reason.length > 1024) throw new Error('bounded interruption reason required')
80
+ const key = digest({ authorityId, scope: act.scope, id: act.id })
81
+ active.get(key)?.abort()
82
+ await host.interrupt({ key, reason, authorityId })
83
+ return checked(await host.read(key), key, act)
84
+ },
85
+ async inspect(act) {
86
+ assertInteraction(act, 'act')
87
+ const key = digest({ authorityId, scope: act.scope, id: act.id })
88
+ return checked(await host.read(key), key, act)
89
+ },
90
+ })
91
+ }
@@ -0,0 +1,82 @@
1
+ import fs from 'node:fs'
2
+ import Ajv from 'ajv/dist/2020.js'
3
+ import { boundedLearningValue, learningDigest } from '../learning/contracts.mjs'
4
+ import { assertAudience, contentDigest, harnessRef } from '../harnesses/contracts.mjs'
5
+ import { inspectKnowledge } from '../knowledge/ledger.mjs'
6
+ import { createHarnessHandoff, verifyHarnessHandoff } from '../harnesses/exchange.mjs'
7
+
8
+ const schema = JSON.parse(fs.readFileSync(new URL('../../contracts/atelier-judgment.v1.schema.json', import.meta.url)))
9
+ const ajv = new Ajv({ strict: true, allErrors: true }), validators = new Map()
10
+ export function validateJudgment(value, profile = 'case') {
11
+ try { boundedLearningValue(value) } catch (error) { return [error.message] }
12
+ if (!['case', 'decision'].includes(profile)) return ['unknown judgment profile']
13
+ if (!validators.has(profile)) validators.set(profile, ajv.compile({ $schema: schema.$schema, $defs: schema.$defs, $ref: `#/$defs/${profile}` }))
14
+ const validate = validators.get(profile)
15
+ if (!validate(value)) return validate.errors.map(e => `${e.instancePath || '/'}: ${e.message}`)
16
+ const errors = []
17
+ if (profile === 'case') {
18
+ const options = new Set(value.alternatives.map(a => a.id))
19
+ if (options.size !== value.alternatives.length) errors.push('alternative identities must be unique')
20
+ if (value.disposition.choice !== null && !options.has(value.disposition.choice)) errors.push('choice must name a considered alternative')
21
+ if (value.disposition.status === 'chosen' && value.disposition.choice === null) errors.push('chosen disposition requires an alternative')
22
+ if (value.disposition.status !== 'chosen' && value.disposition.choice !== null) errors.push('open deliberation cannot claim a choice')
23
+ } else {
24
+ if (value.supersedes?.id === value.native.id) errors.push('a decision cannot supersede its own native identity')
25
+ if (value.evidence.status === 'current' && !value.evidence.references.length) errors.push('current evidence requires exact references')
26
+ if (value.implementation.status === 'verified' && value.implementation.receipt === null) errors.push('verified implementation requires its own receipt')
27
+ }
28
+ return errors
29
+ }
30
+ function assert(value, profile) {
31
+ const errors = validateJudgment(value, profile)
32
+ if (errors.length) throw new Error(`invalid judgment ${profile}: ${errors.join('; ')}`)
33
+ return value
34
+ }
35
+ export function inspectPracticalCase(value) {
36
+ assert(value, 'case')
37
+ return { case: structuredClone(value), digest: learningDigest(value),
38
+ ruleRequired: false, disposition: value.disposition.status, wisdomVerified: false,
39
+ nextQuestions: value.questions, unresolvedDissent: value.voices.filter(v => v.position === 'dissent') }
40
+ }
41
+ // Native identity and decision status belong to the source repository. This
42
+ // adapter records a declared interpretation of exact source bytes, not a new ADR
43
+ // number, signature, status transition or repository-wide adoption.
44
+ export function importArchitectureDecision({ decision, sourceText }) {
45
+ assert(decision, 'decision')
46
+ if (typeof sourceText !== 'string' || Buffer.byteLength(sourceText) > 256 * 1024 || contentDigest(sourceText) !== decision.native.digest) throw new Error('native ADR source bytes differ')
47
+ return { schema: 'atelier-decision-import@v1', decision: structuredClone(decision), sourceVerified: true,
48
+ sourceDigest: contentDigest(sourceText), interpretationVerified: false, authorityTransferred: false }
49
+ }
50
+ export function renderArchitectureDecision(decision) {
51
+ assert(decision, 'decision')
52
+ return [`# ${decision.native.id}: ${decision.title}`, '', `Decision: ${decision.decision.status}`, `Implementation: ${decision.implementation.status}`, `Evidence: ${decision.evidence.status}`, '',
53
+ '## Context', '', decision.context, '', '## Choice and rationale', '', decision.decision.choice, '', decision.decision.reason,
54
+ '', '## Alternatives', '', ...decision.alternatives.map(a => `- ${a}`), '', '## Consequences and reconsideration', '', ...decision.consequences.map(c => `- ${c}`),
55
+ '', ...decision.reconsiderWhen.map(c => `- Reconsider when ${c}`), '', 'Native status remains owned by the source repository.', ''].join('\n')
56
+ }
57
+ export function prepareJudgmentContribution({ records, value, profile, title, term, rightsBasis, sourceText }) {
58
+ assert(value, profile)
59
+ if (profile === 'decision') importArchitectureDecision({ decision: value, sourceText })
60
+ const domain = inspectKnowledge(records).domain
61
+ if (!domain) throw new Error('establish a knowledge domain first')
62
+ assertAudience(domain.data.audience, value.audience)
63
+ const body = JSON.stringify({ profile: `atelier-judgment-${profile}@v1`, value }, null, 2)
64
+ return { data: { domain: harnessRef(domain), category: 'decision-rationale', title, term, body, audience: domain.data.audience, scope: domain.data.scope,
65
+ origin: { method: 'captured', locator: profile === 'decision' ? value.native.ref : `practical-case:${value.id}`, contentDigest: contentDigest(body), rightsBasis }, basedOn: [] },
66
+ semanticAcceptance: 'pending', authority: 'none' }
67
+ }
68
+ // Reviewed judgment travels through the existing Knowledge writer and Build
69
+ // dependency protocol. The typed payload is validated again, not hidden in ext.
70
+ export function createJudgmentDependency({ records, subjectId, target, dependencySnapshots = [], nativeSourceText }) {
71
+ const subject = records.find(r => r.id === subjectId)
72
+ if (subject?.kind !== 'contribution') throw new Error('judgment contribution required')
73
+ let payload
74
+ try { payload = JSON.parse(subject.data.body) } catch { throw new Error('typed judgment payload required') }
75
+ const profile = payload.profile === 'atelier-judgment-case@v1' ? 'case' : payload.profile === 'atelier-judgment-decision@v1' ? 'decision' : null
76
+ assert(payload.value, profile)
77
+ if (profile === 'decision') importArchitectureDecision({ decision: payload.value, sourceText: nativeSourceText })
78
+ const state = inspectKnowledge(records)
79
+ const handoff = createHarnessHandoff({ profile: 'knowledge', repository: state.domain.data.repository, records, subjectId, target, dependencySnapshots })
80
+ verifyHarnessHandoff({ handoff, records, dependencySnapshots })
81
+ return { profile: `atelier-judgment-${profile}@v1`, subjectDigest: learningDigest(payload.value), handoff, nativeAuthorityTransferred: false }
82
+ }
@@ -0,0 +1,70 @@
1
+ import { validateEvidenceDocument } from '../evidence-navigation/contracts.mjs'
2
+ import { assessEvidenceCurrency } from '../evidence-navigation/evaluate.mjs'
3
+ import { validateDecisionRequest, validateDecisionResult, decisionRequestDigest } from '../decisions/contracts.mjs'
4
+ import { contentDigest, harnessRef } from '../harnesses/contracts.mjs'
5
+ import { inspectKnowledge } from '../knowledge/ledger.mjs'
6
+ import { decisionPracticeJson, decisionPracticeDraftValid, readAdoptedDecisionPractice } from './practice.mjs'
7
+
8
+ const flags = { executionAuthorized: false, authorityTransferred: false, semanticTruthVerified: false }
9
+ const outcome = (status, reason) => ({ status, reason, ...flags })
10
+ const object = value => value !== null && typeof value === 'object' && !Array.isArray(value)
11
+ const closed = (value, keys) => object(value) && Object.keys(value).length === keys.length && keys.every(key => Object.hasOwn(value, key))
12
+ const canonical = value => JSON.stringify(value, (_key, item) => object(item) ? Object.fromEntries(Object.keys(item).sort().map(key => [key, item[key]])) : item)
13
+ const rubricFields = ({ id, state, evidence, ...rubric }) => rubric
14
+ const countKeys = ['stages', 'evidence', 'assessments', 'proposals']
15
+
16
+ /** Inspect supplied facts and assessments. Outcomes never execute a stage. */
17
+ export function evaluateDecisionPractice(input) {
18
+ try {
19
+ const value = decisionPracticeJson(input)
20
+ if (!closed(value, ['records', 'definitionRef', 'instance']) ||
21
+ !closed(value.instance, ['id', 'evidence', 'snapshots', 'at', 'prerequisites', 'spent', 'request', 'result', 'proposal']) ||
22
+ typeof value.instance.id !== 'string' || !/^[a-z][a-z0-9-]{0,63}$/.test(value.instance.id)) return outcome('refuse', 'invalid-instance')
23
+ const adopted = readAdoptedDecisionPractice({ records: value.records, definitionRef: value.definitionRef })
24
+ if (adopted.status !== 'resolved') return outcome('refuse', adopted.reason)
25
+ const definition = adopted.definition, instance = value.instance
26
+ const protectedIds = new Set([adopted.definitionRef.id, adopted.activationRef.id, ...value.records.filter(record => record.kind === 'review' && record.data.target.id === adopted.definitionRef.id).map(record => record.id)])
27
+ if (!closed(instance.proposal, ['type', 'target', 'term', 'title'])) return outcome('refuse', 'unsupported-proposal-type')
28
+ if (protectedIds.has(instance.proposal.target?.id)) return outcome('refuse', 'self-definition-proposal')
29
+ if (!definition.allowedProposals.includes(instance.proposal.type)) return outcome('refuse', 'unsupported-proposal-type')
30
+ if (!Array.isArray(instance.evidence) || instance.evidence.length < definition.evidenceRoles.length ||
31
+ instance.evidence.some(item => !closed(item, ['role', 'requestId', 'sourceRef', 'text', 'reference'])) ||
32
+ instance.evidence.some(item => !definition.evidenceRoles.includes(item.role)) ||
33
+ !definition.evidenceRoles.every(role => instance.evidence.some(item => item.role === role)) ||
34
+ new Set(instance.evidence.map(item => item.requestId)).size !== instance.evidence.length) return outcome('refuse', 'missing-evidence')
35
+ if (!closed(instance.spent, countKeys) || !Object.values(instance.spent).every(count => Number.isSafeInteger(count) && count >= 0 && count <= 256)) return outcome('refuse', 'invalid-budget')
36
+ const required = { stages: 1, evidence: instance.evidence.length, assessments: 1, proposals: 1 }
37
+ if (countKeys.some(key => instance.spent[key] + required[key] > definition.limits[key])) return outcome('refuse', 'budget-exhausted')
38
+ if (!Array.isArray(instance.prerequisites) || instance.prerequisites.length !== definition.prerequisites.length ||
39
+ instance.prerequisites.some(item => !closed(item, ['id', 'value']) || !definition.prerequisites.includes(item.id) || typeof item.value !== 'boolean') ||
40
+ new Set(instance.prerequisites.map(item => item.id)).size !== instance.prerequisites.length) return outcome('refuse', 'unknown-prerequisite')
41
+ for (const item of instance.evidence) {
42
+ if (!validateEvidenceDocument('evidenceRef', item.reference).valid || typeof item.text !== 'string' || contentDigest(item.text) !== item.reference.contentDigest) return outcome('refuse', 'changed-evidence-text')
43
+ if (assessEvidenceCurrency(item.reference, instance.snapshots, { at: instance.at }).status !== 'current') return outcome('refuse', 'stale-evidence')
44
+ }
45
+ const request = instance.request
46
+ if (!validateDecisionRequest(request).ok || canonical(rubricFields(request)) !== canonical(rubricFields(definition.rubric))) return outcome('refuse', 'changed-rubric')
47
+ if (request.evidence.length !== instance.evidence.length || !request.evidence.every(pin => closed(pin, ['id', 'sourceRef']) && instance.evidence.some(item => item.requestId === pin.id && item.sourceRef === pin.sourceRef)) ||
48
+ request.state !== request.evidence.map(pin => `${pin.id}: ${instance.evidence.find(item => item.requestId === pin.id).text}`).join('\n')) return outcome('refuse', 'unbound-request-evidence')
49
+ if (!validateDecisionResult(request, instance.result).ok) return outcome('refuse', 'invalid-rubric-result')
50
+ if (instance.prerequisites.some(item => !item.value)) return outcome('stop', 'prerequisite-false')
51
+ if (instance.result.status === 'abstained') return outcome('escalate', 'rubric-abstained')
52
+ const disposition = definition.outcomeMap.choices[instance.result.answers[definition.outcomeMap.question].choice]
53
+ if (disposition !== 'proceed') return outcome(disposition, 'rubric-disposition')
54
+ const state = inspectKnowledge(value.records), target = state.records.find(record => record.id === instance.proposal.target?.id)
55
+ if (!target || target.kind !== 'contribution' || !closed(instance.proposal.target, ['id', 'digest']) || harnessRef(target).digest !== instance.proposal.target.digest) return outcome('refuse', 'changed-proposal-target')
56
+ if (!state.domain.data.vocabulary.types.some(term => term.id === instance.proposal.term) ||
57
+ typeof instance.proposal.title !== 'string' || !instance.proposal.title.trim() || instance.proposal.title.length > 4000) return outcome('refuse', 'invalid-proposal')
58
+ const body = JSON.stringify({ format: 'atelier.decision-reconsideration/v0', instanceId: instance.id,
59
+ definitionRef: adopted.definitionRef, activationRef: adopted.activationRef, target: harnessRef(target),
60
+ evidence: instance.evidence.map(item => ({ role: item.role, reference: item.reference })), requestDigest: decisionRequestDigest(request),
61
+ assessment: instance.result, nativeAuthorityTransferred: false }, null, 2)
62
+ const data = { domain: harnessRef(state.domain), category: 'interpretation', term: instance.proposal.term, title: instance.proposal.title,
63
+ body, audience: state.domain.data.audience, scope: state.domain.data.scope,
64
+ origin: { method: 'captured', locator: `decision-reconsideration:${instance.id}`, contentDigest: contentDigest(body), rightsBasis: definition.rightsBasis }, basedOn: [] }
65
+ if (!decisionPracticeDraftValid(data)) return outcome('refuse', 'practice-output-exceeds-bounds')
66
+ return { ...outcome('proceed', 'reconsideration-draft-prepared'),
67
+ proposal: { data, semanticAcceptance: 'pending', ...flags },
68
+ declaredRemaining: Object.fromEntries(countKeys.map(key => [key, definition.limits[key] - instance.spent[key] - required[key]])) }
69
+ } catch (error) { return outcome('refuse', Object.getOwnPropertyDescriptor(error ?? {}, 'message')?.value === 'evidence value exceeds bounds' ? 'practice-input-exceeds-bounds' : 'invalid-instance') }
70
+ }