@mnstry/atelier 0.2.0-alpha.11 → 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 (560) hide show
  1. package/CHANGELOG.md +1005 -0
  2. package/README.md +149 -9
  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-obsidian-generation-manifest.v2.schema.json +372 -0
  21. package/contracts/atelier-personal-workspace-manifest.v1.schema.json +87 -0
  22. package/contracts/atelier-personal-workspace-overlay.v1.schema.json +299 -0
  23. package/contracts/atelier-template-adoption.v1.schema.json +223 -0
  24. package/contracts/atelier-template-profile.v1.schema.json +1168 -0
  25. package/contracts/atelier-trackable.v1.schema.json +781 -0
  26. package/contracts/atelier-upgrade-plan.v3.schema.json +532 -0
  27. package/contracts/compat-baseline.json +1 -1
  28. package/docs/architecture.md +89 -0
  29. package/docs/assurance-controls.md +4 -3
  30. package/docs/blocks/capability-stewardship.md +17 -0
  31. package/docs/blocks/claims.md +16 -3
  32. package/docs/blocks/inquiry-harnesses.md +19 -0
  33. package/docs/blocks/learning-harnesses.md +17 -0
  34. package/docs/capability-stewardship.md +269 -0
  35. package/docs/coordination.md +51 -0
  36. package/docs/decision-practices.md +111 -0
  37. package/docs/decisions.md +29 -0
  38. package/docs/evidence-navigation.md +237 -0
  39. package/docs/exact-upgrades.md +3 -2
  40. package/docs/ingestion.md +181 -0
  41. package/docs/inquiry-harnesses.md +211 -0
  42. package/docs/install.md +80 -3
  43. package/docs/intake-and-guides.md +5 -0
  44. package/docs/integration-contract-decisions.md +24 -2
  45. package/docs/interaction-and-reflection.md +72 -0
  46. package/docs/knowledge-graph.md +20 -0
  47. package/docs/knowledge-health/api.md +30 -0
  48. package/docs/knowledge-health/assessment/api.md +96 -0
  49. package/docs/knowledge-health/assessment/capabilities.md +40 -0
  50. package/docs/knowledge-health/assessment/evaluation.md +27 -0
  51. package/docs/knowledge-health/assessment/facilitator.md +30 -0
  52. package/docs/knowledge-health/assessment/quickstart.md +61 -0
  53. package/docs/knowledge-health/assessment/troubleshooting.md +23 -0
  54. package/docs/knowledge-health/devday/facilitator.md +16 -0
  55. package/docs/knowledge-health/devday/participant-response.md +22 -0
  56. package/docs/knowledge-health/devday/public-default.md +107 -0
  57. package/docs/knowledge-health/devday/quickstart.md +18 -0
  58. package/docs/knowledge-health/devday/support.md +22 -0
  59. package/docs/knowledge-health/exercise.md +17 -0
  60. package/docs/knowledge-health/facilitator.md +20 -0
  61. package/docs/knowledge-health/quickstart.md +94 -0
  62. package/docs/knowledge-health/readme.md +15 -0
  63. package/docs/knowledge-health/support.md +34 -0
  64. package/docs/knowledge-setup.md +248 -0
  65. package/docs/knowledge-workspace.md +264 -0
  66. package/docs/learning-harnesses.md +238 -0
  67. package/docs/learning.md +215 -0
  68. package/docs/local-services.md +242 -26
  69. package/docs/obsidian-contract.md +878 -36
  70. package/docs/obsidian-plugin.md +619 -0
  71. package/docs/obsidian.md +809 -64
  72. package/docs/optional-ingestion.md +83 -0
  73. package/docs/personal-workspace.md +257 -0
  74. package/docs/practical-judgment.md +92 -0
  75. package/docs/progressive-ingestion-acceptance.md +89 -0
  76. package/docs/progressive-ingestion.md +235 -0
  77. package/docs/project-command-inventory.md +1 -0
  78. package/docs/release-engineering.md +56 -1
  79. package/docs/repo-boundary-guard.md +94 -0
  80. package/docs/research-starter-quickstart.md +66 -0
  81. package/docs/research-starter.md +114 -0
  82. package/docs/semantic-ingestion.md +198 -0
  83. package/docs/semantic-operation.md +317 -0
  84. package/docs/skill-steward.md +6 -0
  85. package/docs/template-profile.md +164 -0
  86. package/docs/template-upgrades.md +114 -0
  87. package/docs/trackables.md +111 -0
  88. package/docs/upgrade.md +68 -3
  89. package/fixtures/atelier-architecture/binding/invalid/document.json +19 -0
  90. package/fixtures/atelier-architecture/binding/valid/document.json +19 -0
  91. package/fixtures/atelier-architecture/catalog/invalid/document.json +290 -0
  92. package/fixtures/atelier-architecture/catalog/valid/document.json +343 -0
  93. package/fixtures/atelier-build-contract/attempt/invalid/document.json +20 -0
  94. package/fixtures/atelier-build-contract/attempt/valid/document.json +19 -0
  95. package/fixtures/atelier-build-contract/candidate/invalid/document.json +24 -0
  96. package/fixtures/atelier-build-contract/candidate/valid/document.json +23 -0
  97. package/fixtures/atelier-build-contract/decision/invalid/document.json +31 -0
  98. package/fixtures/atelier-build-contract/decision/valid/document.json +30 -0
  99. package/fixtures/atelier-build-contract/delivery/invalid/document.json +18 -0
  100. package/fixtures/atelier-build-contract/delivery/valid/document.json +17 -0
  101. package/fixtures/atelier-build-contract/gate/invalid/document.json +22 -0
  102. package/fixtures/atelier-build-contract/gate/valid/document.json +21 -0
  103. package/fixtures/atelier-build-contract/ledger/invalid/document.json +270 -0
  104. package/fixtures/atelier-build-contract/ledger/valid/document.json +269 -0
  105. package/fixtures/atelier-build-contract/objective/invalid/document.json +73 -0
  106. package/fixtures/atelier-build-contract/objective/valid/document.json +72 -0
  107. package/fixtures/atelier-build-contract/progress/invalid/document.json +18 -0
  108. package/fixtures/atelier-build-contract/progress/valid/document.json +17 -0
  109. package/fixtures/atelier-capability-contract/adoption/invalid/document.json +71 -0
  110. package/fixtures/atelier-capability-contract/adoption/valid/document.json +70 -0
  111. package/fixtures/atelier-capability-contract/event/invalid/document.json +18 -0
  112. package/fixtures/atelier-capability-contract/event/valid/document.json +17 -0
  113. package/fixtures/atelier-capability-contract/journal/invalid/document.json +382 -0
  114. package/fixtures/atelier-capability-contract/journal/valid/document.json +381 -0
  115. package/fixtures/atelier-capability-contract/notice/invalid/document.json +8 -0
  116. package/fixtures/atelier-capability-contract/notice/valid/document.json +7 -0
  117. package/fixtures/atelier-capability-contract/package/invalid/document.json +59 -0
  118. package/fixtures/atelier-capability-contract/package/valid/document.json +58 -0
  119. package/fixtures/atelier-capability-contract/plan/invalid/document.json +107 -0
  120. package/fixtures/atelier-capability-contract/plan/valid/document.json +106 -0
  121. package/fixtures/atelier-capability-contract/release/invalid/document.json +85 -0
  122. package/fixtures/atelier-capability-contract/release/valid/document.json +84 -0
  123. package/fixtures/atelier-capability-contract/state/invalid/document.json +316 -0
  124. package/fixtures/atelier-capability-contract/state/valid/document.json +315 -0
  125. package/fixtures/atelier-coordination/dependency/invalid/document.json +37 -0
  126. package/fixtures/atelier-coordination/dependency/valid/document.json +36 -0
  127. package/fixtures/atelier-coordination/directive/invalid/document.json +25 -0
  128. package/fixtures/atelier-coordination/directive/valid/document.json +24 -0
  129. package/fixtures/atelier-coordination/disposition/invalid/document.json +34 -0
  130. package/fixtures/atelier-coordination/disposition/valid/document.json +33 -0
  131. package/fixtures/atelier-coordination/outcome/invalid/document.json +39 -0
  132. package/fixtures/atelier-coordination/outcome/valid/document.json +38 -0
  133. package/fixtures/atelier-coordination/recovery/invalid/document.json +34 -0
  134. package/fixtures/atelier-coordination/recovery/valid/document.json +33 -0
  135. package/fixtures/atelier-harness-contract/handoff/invalid/document.json +25 -0
  136. package/fixtures/atelier-harness-contract/handoff/valid/document.json +24 -0
  137. package/fixtures/atelier-ingestion/invalid/authority.json +19 -0
  138. package/fixtures/atelier-ingestion/semantic-baseline.json +26 -0
  139. package/fixtures/atelier-ingestion/semantic-operation.json +75 -0
  140. package/fixtures/atelier-ingestion/valid/plan-input.json +18 -0
  141. package/fixtures/atelier-inquiry-contract/assessment/invalid/document.json +41 -0
  142. package/fixtures/atelier-inquiry-contract/assessment/valid/document.json +40 -0
  143. package/fixtures/atelier-inquiry-contract/bundle/invalid/document.json +51 -0
  144. package/fixtures/atelier-inquiry-contract/bundle/valid/document.json +50 -0
  145. package/fixtures/atelier-inquiry-contract/campaign/invalid/document.json +17 -0
  146. package/fixtures/atelier-inquiry-contract/campaign/valid/document.json +16 -0
  147. package/fixtures/atelier-inquiry-contract/decision/invalid/document.json +22 -0
  148. package/fixtures/atelier-inquiry-contract/decision/valid/document.json +21 -0
  149. package/fixtures/atelier-inquiry-contract/feedback/invalid/document.json +19 -0
  150. package/fixtures/atelier-inquiry-contract/feedback/valid/document.json +18 -0
  151. package/fixtures/atelier-inquiry-contract/handoff/invalid/document.json +92 -0
  152. package/fixtures/atelier-inquiry-contract/handoff/valid/document.json +91 -0
  153. package/fixtures/atelier-inquiry-contract/hypothesis/invalid/document.json +20 -0
  154. package/fixtures/atelier-inquiry-contract/hypothesis/valid/document.json +19 -0
  155. package/fixtures/atelier-inquiry-contract/ledger/invalid/document.json +680 -0
  156. package/fixtures/atelier-inquiry-contract/ledger/valid/document.json +679 -0
  157. package/fixtures/atelier-inquiry-contract/legacy-assessment/invalid/document.json +19 -0
  158. package/fixtures/atelier-inquiry-contract/legacy-assessment/valid/document.json +18 -0
  159. package/fixtures/atelier-inquiry-contract/request/invalid/document.json +50 -0
  160. package/fixtures/atelier-inquiry-contract/request/valid/document.json +49 -0
  161. package/fixtures/atelier-inquiry-contract/source/invalid/document.json +18 -0
  162. package/fixtures/atelier-inquiry-contract/source/valid/document.json +17 -0
  163. package/fixtures/atelier-inquiry-contract/withdrawal/invalid/document.json +16 -0
  164. package/fixtures/atelier-inquiry-contract/withdrawal/valid/document.json +15 -0
  165. package/fixtures/atelier-instruction-adoption/context-receipt/invalid/document.json +18 -0
  166. package/fixtures/atelier-instruction-adoption/context-receipt/valid/document.json +17 -0
  167. package/fixtures/atelier-instruction-adoption/plan/invalid/document.json +63 -0
  168. package/fixtures/atelier-instruction-adoption/plan/valid/document.json +62 -0
  169. package/fixtures/atelier-instruction-adoption/receipt/invalid/document.json +22 -0
  170. package/fixtures/atelier-instruction-adoption/receipt/valid/document.json +21 -0
  171. package/fixtures/atelier-instruction-adoption/state/invalid/document.json +30 -0
  172. package/fixtures/atelier-instruction-adoption/state/valid/document.json +29 -0
  173. package/fixtures/atelier-interaction/act/invalid/document.json +25 -0
  174. package/fixtures/atelier-interaction/act/valid/document.json +24 -0
  175. package/fixtures/atelier-interaction/assessment/invalid/document.json +32 -0
  176. package/fixtures/atelier-interaction/assessment/valid/document.json +31 -0
  177. package/fixtures/atelier-interaction/observation/invalid/document.json +22 -0
  178. package/fixtures/atelier-interaction/observation/valid/document.json +21 -0
  179. package/fixtures/atelier-interaction/policy/invalid/document.json +20 -0
  180. package/fixtures/atelier-interaction/policy/valid/document.json +19 -0
  181. package/fixtures/atelier-judgment/case/invalid/document.json +76 -0
  182. package/fixtures/atelier-judgment/case/valid/document.json +75 -0
  183. package/fixtures/atelier-judgment/decision/invalid/document.json +38 -0
  184. package/fixtures/atelier-judgment/decision/valid/document.json +37 -0
  185. package/fixtures/atelier-judgment/native-decision.md +3 -0
  186. package/fixtures/atelier-judgment/practice-reconsideration/definition.json +92 -0
  187. package/fixtures/atelier-judgment/practice-reconsideration/scenario.json +435 -0
  188. package/fixtures/atelier-knowledge-contract/activation/invalid/document.json +26 -0
  189. package/fixtures/atelier-knowledge-contract/activation/valid/document.json +25 -0
  190. package/fixtures/atelier-knowledge-contract/contribution/invalid/document.json +34 -0
  191. package/fixtures/atelier-knowledge-contract/contribution/valid/document.json +33 -0
  192. package/fixtures/atelier-knowledge-contract/domain/invalid/document.json +41 -0
  193. package/fixtures/atelier-knowledge-contract/domain/valid/document.json +40 -0
  194. package/fixtures/atelier-knowledge-contract/domain-revision/invalid/document.json +46 -0
  195. package/fixtures/atelier-knowledge-contract/domain-revision/valid/document.json +45 -0
  196. package/fixtures/atelier-knowledge-contract/evaluation/invalid/document.json +21 -0
  197. package/fixtures/atelier-knowledge-contract/evaluation/valid/document.json +20 -0
  198. package/fixtures/atelier-knowledge-contract/ledger/invalid/document.json +318 -0
  199. package/fixtures/atelier-knowledge-contract/ledger/valid/document.json +317 -0
  200. package/fixtures/atelier-knowledge-contract/relation/invalid/document.json +25 -0
  201. package/fixtures/atelier-knowledge-contract/relation/valid/document.json +24 -0
  202. package/fixtures/atelier-knowledge-contract/review/invalid/document.json +18 -0
  203. package/fixtures/atelier-knowledge-contract/review/valid/document.json +17 -0
  204. package/fixtures/atelier-knowledge-contract/withdrawal/invalid/document.json +16 -0
  205. package/fixtures/atelier-knowledge-contract/withdrawal/valid/document.json +15 -0
  206. package/fixtures/atelier-learning/invalid/authority.json +14 -0
  207. package/fixtures/atelier-learning/valid/capture.json +13 -0
  208. package/fixtures/atelier-personal-workspace-contract/manifest/invalid/authority-key.json +17 -0
  209. package/fixtures/atelier-personal-workspace-contract/manifest/invalid/nonempty-ext.json +25 -0
  210. package/fixtures/atelier-personal-workspace-contract/manifest/invalid/wrong-schema.json +22 -0
  211. package/fixtures/atelier-personal-workspace-contract/manifest/valid/manifest.json +22 -0
  212. package/fixtures/atelier-personal-workspace-contract/overlay/invalid/authority-key.json +25 -0
  213. package/fixtures/atelier-personal-workspace-contract/overlay/invalid/unknown-top-level-field.json +27 -0
  214. package/fixtures/atelier-personal-workspace-contract/overlay/invalid/wrong-schema.json +24 -0
  215. package/fixtures/atelier-trackable/definition/invalid/document.json +15 -0
  216. package/fixtures/atelier-trackable/definition/valid/document.json +14 -0
  217. package/fixtures/atelier-trackable/request/invalid/document.json +23 -0
  218. package/fixtures/atelier-trackable/request/valid/document.json +22 -0
  219. package/fixtures/boundary-delegations/invalid/authority-key.v1.json +30 -0
  220. package/fixtures/boundary-delegations/invalid/push-operation.v1.json +28 -0
  221. package/fixtures/boundary-delegations/invalid/unsigned.v1.json +25 -0
  222. package/fixtures/boundary-delegations/valid/empty.v1.json +4 -0
  223. package/fixtures/boundary-delegations/valid/signed-operator.v1.json +30 -0
  224. package/fixtures/boundary-owner-keys/invalid/wrong-algorithm.v1.json +15 -0
  225. package/fixtures/boundary-owner-keys/invalid/wrong-curve.v1.json +15 -0
  226. package/fixtures/boundary-owner-keys/valid/one-owner.v1.json +17 -0
  227. package/fixtures/capability-packages/adoption.example.json +70 -0
  228. package/fixtures/capability-packages/evidence-review/capability-package.json +58 -0
  229. package/fixtures/capability-packages/evidence-review/capability-release.json +84 -0
  230. package/fixtures/capability-packages/evidence-review/evaluation.md +15 -0
  231. package/fixtures/capability-packages/evidence-review/skills/evidence-review/SKILL.md +22 -0
  232. package/fixtures/capability-packages/evidence-review/skills/evidence-review/references/ledger.md +7 -0
  233. package/fixtures/capability-packages/research/capability-package.json +88 -0
  234. package/fixtures/capability-packages/research/capability-release.json +134 -0
  235. package/fixtures/capability-packages/research/evaluation.md +15 -0
  236. package/fixtures/capability-packages/research/skills/research-integrate/SKILL.md +29 -0
  237. package/fixtures/capability-packages/research/skills/research-integrate/references/integration.md +10 -0
  238. package/fixtures/capability-packages/research/skills/research-plan/SKILL.md +27 -0
  239. package/fixtures/capability-packages/research/skills/research-plan/references/inquiries.md +26 -0
  240. package/fixtures/capability-packages/research/skills/research-synthesize/SKILL.md +23 -0
  241. package/fixtures/capability-packages/research/skills/research-synthesize/references/synthesis.md +12 -0
  242. package/fixtures/evidence-navigation/invalid/duplicate-operation.json +16 -0
  243. package/fixtures/evidence-navigation/invalid/instruction-kind.json +36 -0
  244. package/fixtures/evidence-navigation/invalid/invalid-digest.json +36 -0
  245. package/fixtures/evidence-navigation/invalid/invalid-time.json +36 -0
  246. package/fixtures/evidence-navigation/invalid/missing-attribution.json +35 -0
  247. package/fixtures/evidence-navigation/invalid/reserved-extension.json +19 -0
  248. package/fixtures/evidence-navigation/invalid/unattributed-acceptance.json +36 -0
  249. package/fixtures/evidence-navigation/invalid/uncoerced-version.json +16 -0
  250. package/fixtures/evidence-navigation/invalid/unknown-currency.json +17 -0
  251. package/fixtures/evidence-navigation/invalid/unknown-selector-field.json +37 -0
  252. package/fixtures/evidence-navigation/invalid/unsupported-operation.json +15 -0
  253. package/fixtures/evidence-navigation/valid/claim.json +36 -0
  254. package/fixtures/evidence-navigation/valid/host.json +16 -0
  255. package/fixtures/evidence-navigation/valid/profile.json +16 -0
  256. package/fixtures/evidence-navigation/valid/snapshot.json +17 -0
  257. package/fixtures/harness-packages/build-harness/capability-package.json +61 -0
  258. package/fixtures/harness-packages/build-harness/capability-release.json +82 -0
  259. package/fixtures/harness-packages/build-harness/evaluation.md +3 -0
  260. package/fixtures/harness-packages/build-harness/skills/atelier-build-harness/SKILL.md +59 -0
  261. package/fixtures/harness-packages/knowledge-harness/capability-package.json +61 -0
  262. package/fixtures/harness-packages/knowledge-harness/capability-release.json +82 -0
  263. package/fixtures/harness-packages/knowledge-harness/evaluation.md +3 -0
  264. package/fixtures/harness-packages/knowledge-harness/skills/atelier-knowledge-harness/SKILL.md +60 -0
  265. package/fixtures/harnesses/learning-cycle.json +780 -0
  266. package/fixtures/inquiry/workshop.json +675 -0
  267. package/fixtures/inquiry-packages/discovery-harness/capability-package.json +61 -0
  268. package/fixtures/inquiry-packages/discovery-harness/capability-release.json +82 -0
  269. package/fixtures/inquiry-packages/discovery-harness/evaluation.md +3 -0
  270. package/fixtures/inquiry-packages/discovery-harness/skills/atelier-discovery-harness/SKILL.md +48 -0
  271. package/fixtures/inquiry-packages/research-harness/capability-package.json +61 -0
  272. package/fixtures/inquiry-packages/research-harness/capability-release.json +82 -0
  273. package/fixtures/inquiry-packages/research-harness/evaluation.md +3 -0
  274. package/fixtures/inquiry-packages/research-harness/skills/atelier-research-harness/SKILL.md +43 -0
  275. package/fixtures/knowledge-health/calibration-suite.json +26 -0
  276. package/fixtures/knowledge-health/calibration-trial.json +37 -0
  277. package/fixtures/knowledge-health/corrected/checklist.md +18 -0
  278. package/fixtures/knowledge-health/devday/participant-record.json +19 -0
  279. package/fixtures/knowledge-health/expected-summary.json +27 -0
  280. package/fixtures/knowledge-health/workshop/README.md +20 -0
  281. package/fixtures/knowledge-health/workshop/atelier.project.json +7 -0
  282. package/fixtures/knowledge-health/workshop/knowledge-plan.json +65 -0
  283. package/fixtures/knowledge-health/workshop/records/checklist.md +18 -0
  284. package/fixtures/knowledge-health/workshop/records/workshop.md +18 -0
  285. package/fixtures/knowledge-health/workshop/repo-access.v1.json +5 -0
  286. package/fixtures/knowledge-health/workspace/atelier.project.json +18 -0
  287. package/fixtures/knowledge-health/workspace/knowledge-plan.json +74 -0
  288. package/fixtures/knowledge-health/workspace/records/checklist.md +18 -0
  289. package/fixtures/knowledge-health/workspace/records/pilot.md +16 -0
  290. package/fixtures/knowledge-health/workspace/repo-access.v1.json +9 -0
  291. package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/case-only-collision.v2.json +160 -0
  292. package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/flat-note-path.v2.json +160 -0
  293. package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/hidden-folder.v2.json +160 -0
  294. package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/identity-in-the-body.v2.json +160 -0
  295. package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/link-breaking-name.v2.json +160 -0
  296. package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/missing-identity-region.v2.json +156 -0
  297. package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/missing-layout-version.v2.json +159 -0
  298. package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/note-named-like-a-folder.v2.json +160 -0
  299. package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/unknown-region-kind.v2.json +160 -0
  300. package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/v1-contract-version.v2.json +161 -0
  301. package/fixtures/obsidian/contracts/generation-manifest-v2/valid/three-notes.v2.json +160 -0
  302. package/fixtures/obsidian/edits/workspace.json +1 -1
  303. package/fixtures/obsidian/materialization/expected-full.json +21 -21
  304. package/fixtures/obsidian/materialization/expected-full.layout-1.json +99 -0
  305. package/fixtures/obsidian/materialization/expected-scoped.json +7 -7
  306. package/fixtures/obsidian/materialization/expected-scoped.layout-1.json +39 -0
  307. package/fixtures/personal-workspace/overlay.json +24 -0
  308. package/fixtures/templates/local-library.v1.json +75 -0
  309. package/fixtures/templates/upgrade-contracts/adoption-policy.v2/invalid.json +16 -0
  310. package/fixtures/templates/upgrade-contracts/adoption-policy.v2/valid.json +13 -0
  311. package/fixtures/templates/upgrade-contracts/migration.v3/invalid.json +24 -0
  312. package/fixtures/templates/upgrade-contracts/migration.v3/valid.json +21 -0
  313. package/fixtures/templates/upgrade-contracts/template-adoption.v1/invalid.json +60 -0
  314. package/fixtures/templates/upgrade-contracts/template-adoption.v1/valid.json +57 -0
  315. package/fixtures/templates/upgrade-contracts/upgrade-plan.v3/invalid.json +85 -0
  316. package/fixtures/templates/upgrade-contracts/upgrade-plan.v3/valid.json +82 -0
  317. package/package.json +64 -6
  318. package/plugins/obsidian/main.js +444 -0
  319. package/plugins/obsidian/manifest.json +9 -0
  320. package/plugins/obsidian/styles.css +22 -0
  321. package/skills/claude/atelier-build-harness/SKILL.md +59 -0
  322. package/skills/claude/atelier-coordination/SKILL.md +32 -0
  323. package/skills/claude/atelier-discovery-harness/SKILL.md +48 -0
  324. package/skills/claude/atelier-guided-upgrade/SKILL.md +29 -0
  325. package/skills/claude/atelier-interaction/SKILL.md +34 -0
  326. package/skills/claude/atelier-knowledge-harness/SKILL.md +60 -0
  327. package/skills/claude/atelier-knowledge-setup/SKILL.md +72 -0
  328. package/skills/claude/atelier-practical-judgment/SKILL.md +64 -0
  329. package/skills/claude/atelier-research-harness/SKILL.md +43 -0
  330. package/skills/claude/atelier-skill-steward/SKILL.md +53 -0
  331. package/skills/claude/atelier-trackables/SKILL.md +40 -0
  332. package/skills/codex/atelier-build-harness/SKILL.md +59 -0
  333. package/skills/codex/atelier-coordination/SKILL.md +32 -0
  334. package/skills/codex/atelier-discovery-harness/SKILL.md +48 -0
  335. package/skills/codex/atelier-guided-upgrade/SKILL.md +29 -0
  336. package/skills/codex/atelier-interaction/SKILL.md +34 -0
  337. package/skills/codex/atelier-knowledge-harness/SKILL.md +60 -0
  338. package/skills/codex/atelier-knowledge-setup/SKILL.md +72 -0
  339. package/skills/codex/atelier-practical-judgment/SKILL.md +64 -0
  340. package/skills/codex/atelier-research-harness/SKILL.md +43 -0
  341. package/skills/codex/atelier-skill-steward/SKILL.md +53 -0
  342. package/skills/codex/atelier-trackables/SKILL.md +40 -0
  343. package/src/architecture/catalog.mjs +355 -0
  344. package/src/architecture/index.mjs +93 -0
  345. package/src/boundary/content-rules.mjs +4 -2
  346. package/src/boundary/delegation-command.mjs +158 -0
  347. package/src/boundary/delegation.mjs +396 -0
  348. package/src/boundary/policy.mjs +52 -10
  349. package/src/build/git.mjs +18 -0
  350. package/src/build/index.mjs +3 -0
  351. package/src/build/ledger.mjs +88 -0
  352. package/src/capabilities/adoption.mjs +381 -0
  353. package/src/capabilities/evidence.mjs +140 -0
  354. package/src/capabilities/files.mjs +124 -0
  355. package/src/capabilities/index.mjs +4 -0
  356. package/src/capabilities/instructions.mjs +250 -0
  357. package/src/capabilities/package.mjs +136 -0
  358. package/src/cli/command-failure.mjs +36 -0
  359. package/src/cli/execute-command.mjs +16 -2
  360. package/src/cli/run.mjs +65 -9
  361. package/src/coauthor/store.mjs +43 -2
  362. package/src/collaboration/proposals.mjs +189 -0
  363. package/src/commands/architecture.mjs +27 -0
  364. package/src/commands/boundary.mjs +3 -0
  365. package/src/commands/capability.mjs +73 -0
  366. package/src/commands/enroll.mjs +3 -0
  367. package/src/commands/harness.mjs +79 -0
  368. package/src/commands/ingest.mjs +39 -0
  369. package/src/commands/init.mjs +4 -1
  370. package/src/commands/inquiry.mjs +66 -0
  371. package/src/commands/knowledge-semantic.mjs +128 -0
  372. package/src/commands/knowledge.mjs +119 -0
  373. package/src/commands/learn.mjs +61 -0
  374. package/src/commands/obsidian.mjs +832 -62
  375. package/src/commands/practice.mjs +24 -0
  376. package/src/commands/setup.mjs +22 -2
  377. package/src/commands/trackable.mjs +19 -0
  378. package/src/contracts/corpus.mjs +36 -0
  379. package/src/coordination/index.mjs +110 -0
  380. package/src/egress/forbidden-egress.mjs +2 -0
  381. package/src/evidence-navigation/contracts.mjs +60 -0
  382. package/src/evidence-navigation/evaluate.mjs +69 -0
  383. package/src/evidence-navigation/generation.mjs +22 -0
  384. package/src/evidence-navigation/index.mjs +2 -0
  385. package/src/evidence-navigation/local.mjs +167 -0
  386. package/src/evidence-navigation/schema.generated.mjs +604 -0
  387. package/src/evidence-navigation/types.mjs +12 -0
  388. package/src/export/atelier-export-contract.mjs +35 -8
  389. package/src/graph/enroll.mjs +248 -0
  390. package/src/graph/graph.mjs +17 -1
  391. package/src/graph/knowledge-graph.mjs +58 -8
  392. package/src/harnesses/contracts.mjs +41 -0
  393. package/src/harnesses/exchange.mjs +154 -0
  394. package/src/harnesses/feedback.mjs +16 -0
  395. package/src/harnesses/history.mjs +37 -0
  396. package/src/harnesses/index.mjs +4 -0
  397. package/src/harnesses/store.mjs +29 -0
  398. package/src/ingestion/contracts.mjs +41 -0
  399. package/src/ingestion/evaluation.mjs +119 -0
  400. package/src/ingestion/optional/composition/index.mjs +171 -0
  401. package/src/ingestion/optional/evaluation/index.mjs +219 -0
  402. package/src/ingestion/optional/graphify/composition-binding.mjs +60 -0
  403. package/src/ingestion/optional/graphify/composition_receiving.py +185 -0
  404. package/src/ingestion/optional/graphify/graphify_supplier.py +933 -0
  405. package/src/ingestion/optional/graphify/json_bridge.py +163 -0
  406. package/src/ingestion/optional/graphify/query_receiving.py +209 -0
  407. package/src/ingestion/optional/index.mjs +9 -0
  408. package/src/ingestion/optional/jev/bridge.mjs +166 -0
  409. package/src/ingestion/optional/jev/composition-binding.mjs +116 -0
  410. package/src/ingestion/optional/jev/judgments.mjs +174 -0
  411. package/src/ingestion/optional/jev/native-translation.mjs +32 -0
  412. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/__init__.py +7 -0
  413. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/adapter.py +966 -0
  414. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/artifacts.py +101 -0
  415. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/projection.py +146 -0
  416. package/src/ingestion/optional/lightrag/composition-binding.mjs +67 -0
  417. package/src/ingestion/optional/vanilla/composition-binding.mjs +102 -0
  418. package/src/ingestion/optional/vanilla/index.mjs +218 -0
  419. package/src/ingestion/optional/vanilla/native-normalization.mjs +187 -0
  420. package/src/ingestion/processors.mjs +218 -0
  421. package/src/ingestion/semantic.mjs +203 -0
  422. package/src/ingestion/store.mjs +372 -0
  423. package/src/inquiry/beliefs.mjs +32 -0
  424. package/src/inquiry/contracts.mjs +23 -0
  425. package/src/inquiry/index.mjs +5 -0
  426. package/src/inquiry/ledger.mjs +135 -0
  427. package/src/inquiry/lenses.mjs +15 -0
  428. package/src/inquiry/projection.mjs +77 -0
  429. package/src/inquiry/store.mjs +35 -0
  430. package/src/intake/read-scope.mjs +12 -0
  431. package/src/intake/store.mjs +69 -6
  432. package/src/interaction/index.mjs +91 -0
  433. package/src/judgment/index.mjs +82 -0
  434. package/src/judgment/practice-evaluation.mjs +70 -0
  435. package/src/judgment/practice.mjs +144 -0
  436. package/src/knowledge/context.mjs +217 -0
  437. package/src/knowledge/index.mjs +5 -0
  438. package/src/knowledge/ingestion.mjs +79 -0
  439. package/src/knowledge/intake.mjs +33 -0
  440. package/src/knowledge/ledger.mjs +110 -0
  441. package/src/knowledge/participatory/guidance.mjs +36 -0
  442. package/src/knowledge/participatory/guided-contribution.mjs +44 -0
  443. package/src/knowledge/participatory/index.mjs +2 -0
  444. package/src/knowledge/participatory/installed-workshop.mjs +108 -0
  445. package/src/knowledge/plan.mjs +67 -0
  446. package/src/knowledge/projection.mjs +43 -0
  447. package/src/knowledge/semantic-operation.mjs +567 -0
  448. package/src/knowledge/sessions.mjs +467 -0
  449. package/src/knowledge/workspace.mjs +295 -0
  450. package/src/knowledge-health/assessment.mjs +165 -0
  451. package/src/knowledge-health/capabilities.mjs +350 -0
  452. package/src/knowledge-health/context.mjs +62 -0
  453. package/src/knowledge-health/example.mjs +47 -0
  454. package/src/knowledge-health/index.mjs +10 -0
  455. package/src/knowledge-health/owner-join.mjs +88 -0
  456. package/src/knowledge-health/proof/common.mjs +24 -0
  457. package/src/knowledge-health/proof/installed-check.mjs +100 -0
  458. package/src/knowledge-health/proof/native-readback.mjs +37 -0
  459. package/src/knowledge-health/proof/rehearse.mjs +68 -0
  460. package/src/knowledge-health/proof/validate-participant.mjs +17 -0
  461. package/src/knowledge-health/proof/verify-native-capture.mjs +14 -0
  462. package/src/knowledge-health/proof/workshop-check.mjs +36 -0
  463. package/src/knowledge-health/rule-identity.mjs +44 -0
  464. package/src/knowledge-health/workshop-composition.mjs +19 -0
  465. package/src/knowledge-health/workshop-profile.mjs +176 -0
  466. package/src/knowledge-health/workshop.mjs +99 -0
  467. package/src/learning/adapters.mjs +68 -0
  468. package/src/learning/assistance.mjs +127 -0
  469. package/src/learning/contracts.mjs +65 -0
  470. package/src/learning/store.mjs +272 -0
  471. package/src/personal-workspace/index.mjs +391 -0
  472. package/src/personal-workspace/selection.mjs +385 -0
  473. package/src/project/config.mjs +8 -0
  474. package/src/project/durable-state.mjs +3 -1
  475. package/src/project/file-class.mjs +1 -1
  476. package/src/project/private-state.mjs +10 -1
  477. package/src/projection/obsidian/contracts.mjs +224 -18
  478. package/src/projection/obsidian/edits/apply.mjs +63 -19
  479. package/src/projection/obsidian/edits/regions.mjs +137 -42
  480. package/src/projection/obsidian/materialize/index.mjs +6 -3
  481. package/src/projection/obsidian/materialize/path-registry.mjs +443 -57
  482. package/src/projection/obsidian/materialize/prepare-view.mjs +382 -131
  483. package/src/projection/obsidian/materialize/redaction.mjs +327 -0
  484. package/src/projection/obsidian/materialize/settings.mjs +113 -34
  485. package/src/projection/obsidian/personal-workspace.mjs +436 -0
  486. package/src/projection/obsidian/plugin-bridge/bundle.mjs +50 -0
  487. package/src/projection/obsidian/plugin-bridge/channel.mjs +174 -0
  488. package/src/projection/obsidian/plugin-bridge/index.mjs +10 -0
  489. package/src/projection/obsidian/proposals/adapter.mjs +47 -8
  490. package/src/projection/obsidian/proposals/observation.mjs +20 -7
  491. package/src/projection/obsidian/publication/bridge-script.mjs +11 -5
  492. package/src/projection/obsidian/publication/index.mjs +2 -1
  493. package/src/projection/obsidian/publication/publisher.mjs +312 -36
  494. package/src/projection/obsidian/publication/transport.mjs +63 -8
  495. package/src/projection/obsidian/publication/vault-list.mjs +200 -0
  496. package/src/projection/obsidian/recovery/index.mjs +4 -1
  497. package/src/projection/obsidian/recovery/restart.mjs +3 -1
  498. package/src/projection/obsidian/recovery/store.mjs +168 -8
  499. package/src/projection/obsidian/selection-ui/contribution.mjs +6 -5
  500. package/src/projection/obsidian/selection-ui/focus.mjs +14 -7
  501. package/src/projection/obsidian/selection-ui/selection-state.mjs +2 -2
  502. package/src/projection/obsidian/selection-ui/selection.mjs +8 -3
  503. package/src/readiness/readiness.mjs +10 -3
  504. package/src/reflection/index.mjs +56 -0
  505. package/src/runtime/obsidian/app-capability.mjs +104 -12
  506. package/src/runtime/obsidian/app-production-seams.mjs +161 -42
  507. package/src/runtime/obsidian/app-registration.mjs +313 -0
  508. package/src/runtime/obsidian/app-restart.mjs +154 -0
  509. package/src/runtime/obsidian/engine.mjs +288 -29
  510. package/src/runtime/obsidian/extension-points.mjs +1 -1
  511. package/src/runtime/obsidian/index.mjs +15 -8
  512. package/src/runtime/obsidian/launch-plan.mjs +91 -0
  513. package/src/runtime/obsidian/lifecycle.mjs +193 -22
  514. package/src/runtime/obsidian/login-item.mjs +332 -0
  515. package/src/runtime/obsidian/machine-settings.mjs +119 -12
  516. package/src/runtime/obsidian/opening.mjs +369 -63
  517. package/src/runtime/obsidian/pending-edits.mjs +10 -0
  518. package/src/runtime/obsidian/pipeline.mjs +71 -3
  519. package/src/runtime/obsidian/plugin-channel.mjs +289 -0
  520. package/src/runtime/obsidian/plugin-choice.mjs +182 -0
  521. package/src/runtime/obsidian/plugin-drift.mjs +124 -0
  522. package/src/runtime/obsidian/plugin-presence.mjs +61 -0
  523. package/src/runtime/obsidian/process-identity.mjs +20 -10
  524. package/src/runtime/obsidian/project-views.mjs +282 -0
  525. package/src/runtime/obsidian/questions.mjs +48 -0
  526. package/src/runtime/obsidian/release-watch.mjs +56 -0
  527. package/src/runtime/obsidian/service-main.mjs +113 -17
  528. package/src/runtime/obsidian/service-manager-production.mjs +61 -0
  529. package/src/runtime/obsidian/service-managers.mjs +275 -0
  530. package/src/runtime/obsidian/service-record.mjs +105 -5
  531. package/src/runtime/obsidian/service-server.mjs +50 -12
  532. package/src/runtime/obsidian/service.mjs +134 -7
  533. package/src/runtime/obsidian/startup-adapters.mjs +59 -21
  534. package/src/runtime/obsidian/state-store.mjs +13 -1
  535. package/src/runtime/obsidian/unheld-evidence.mjs +84 -0
  536. package/src/runtime/obsidian/vault-location.mjs +300 -0
  537. package/src/runtime/obsidian/view-counts.mjs +34 -0
  538. package/src/server/local-sidecar.mjs +193 -7
  539. package/src/server/server.mjs +45 -6
  540. package/src/template-bindings/project.mjs +92 -0
  541. package/src/templates/profile.mjs +225 -0
  542. package/src/trackables/domain.mjs +175 -0
  543. package/src/trackables/store.mjs +114 -0
  544. package/src/ui/knowledge-page.mjs +1388 -0
  545. package/src/upgrade/explanation.mjs +1 -1
  546. package/src/upgrade/template-participant.mjs +171 -0
  547. package/src/upgrade/transaction.mjs +72 -25
  548. package/src/upgrade/upgrade.mjs +2 -1
  549. package/templates/external-project-workspace/pack-lifecycle.json +6 -1
  550. package/templates/knowledge-workspace/.gitattributes +2 -0
  551. package/templates/knowledge-workspace/AGENTS.md +27 -0
  552. package/templates/knowledge-workspace/README.md +44 -0
  553. package/templates/knowledge-workspace/atelier.project.json +22 -0
  554. package/templates/knowledge-workspace/gitignore +6 -0
  555. package/templates/knowledge-workspace/knowledge-plan.json +111 -0
  556. package/templates/knowledge-workspace/knowledge-plan.schema.json +281 -0
  557. package/templates/knowledge-workspace/records/forecast.md +22 -0
  558. package/templates/knowledge-workspace/records/inspection.md +25 -0
  559. package/templates/knowledge-workspace/records/telescope.md +24 -0
  560. package/templates/knowledge-workspace/repo-access.v1.json +9 -0
@@ -0,0 +1,444 @@
1
+ 'use strict'
2
+
3
+ // Atelier's own plugin. Atelier ships it into every vault it manages, under
4
+ // .obsidian/plugins/atelier-projection/, beside a data file that names the
5
+ // maintenance service of the workspace and this vault's key (its bearer). The
6
+ // person never installs it; Obsidian asks once per vault whether to trust the
7
+ // vault's plugins, and until then (or in restricted mode, or on an app older
8
+ // than 1.13.7) everything works without it.
9
+ //
10
+ // Phase 1: presence and status, read-only. While the vault is open the plugin
11
+ // tells the service so (a lease renewed every two seconds, released when the
12
+ // plugin unloads), reports the app version it runs in, and shows the view's
13
+ // freshness in the status bar and in "Atelier: show status".
14
+ //
15
+ // The key never leaves this machine's files. The plugin first asks whatever
16
+ // listens at the service's address to prove that it holds the key, and sends
17
+ // nothing that names this vault until it did; then it proves the same, and
18
+ // every later request and answer is sealed with a key for that session only.
19
+ //
20
+ // What it never does: write a file (a note, a setting, its own data file),
21
+ // run code it is sent, or reach anything but that one service, on a literal
22
+ // loopback address, with no name to resolve.
23
+
24
+ const obsidian = require('obsidian')
25
+
26
+ // Held equal to src/projection/obsidian/plugin-bridge/channel.mjs by the test suite.
27
+ const CHANNEL = Object.freeze({
28
+ pluginId: 'atelier-projection',
29
+ protocol: 'atelier-obsidian-plugin-channel/v2',
30
+ dataSchema: 'atelier-obsidian-plugin-data/v1',
31
+ statusSchema: 'atelier-obsidian-plugin-status/v1',
32
+ routes: Object.freeze({ challenge: '/plugin/challenge', hello: '/plugin/hello', lease: '/plugin/lease', release: '/plugin/release', status: '/plugin/status' }),
33
+ renewEveryMs: 2000,
34
+ requestTimeoutMs: 1500,
35
+ maxResponseBytes: 64 * 1024,
36
+ minimumAppVersion: '1.13.7',
37
+ })
38
+
39
+ const BEARER = /^[A-Za-z0-9_-]{43}$/
40
+ const IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/
41
+ const NONCE = /^[0-9a-f]{64}$/
42
+ const MAC = /^[0-9a-f]{64}$/
43
+ const HANDSHAKE_ID = /^ph-[0-9a-f]{32}$/
44
+ const SESSION_ID = /^ps-[0-9a-f]{32}$/
45
+ const VERSION = /^v?(\d{1,9})\.(\d{1,9})\.(\d{1,9})(?:-([0-9A-Za-z.]+))?/
46
+
47
+ // -1, 0 or 1; null when either side is not a version. A prerelease ranks below its release.
48
+ function compareVersions(left, right) {
49
+ const [a, b] = [VERSION.exec(String(left || '')), VERSION.exec(String(right || ''))]
50
+ if (!a || !b) return null
51
+ for (let index = 1; index <= 3; index += 1) if (Number(a[index]) !== Number(b[index])) return Number(a[index]) < Number(b[index]) ? -1 : 1
52
+ if (Boolean(a[4]) === Boolean(b[4])) return a[4] === b[4] || !a[4] ? 0 : a[4] < b[4] ? -1 : 1
53
+ return a[4] ? -1 : 1
54
+ }
55
+
56
+ function meetsFloor(version) {
57
+ const order = compareVersions(version, CHANNEL.minimumAppVersion)
58
+ return order !== null && order >= 0
59
+ }
60
+
61
+ const isPlainObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
62
+
63
+ // The handshake and session computations of plugin-bridge/channel.mjs; the
64
+ // test suite holds the two to each other. Every input but the vault path is a
65
+ // shape without a line break, and the vault path is the only input of its
66
+ // computation, so joining them by lines is unambiguous.
67
+ function transcript(label, fields) {
68
+ return [CHANNEL.protocol, label].concat(fields.map(String)).join('\n')
69
+ }
70
+ function hmac(crypto, key, label, fields) {
71
+ return crypto.createHmac('sha256', key).update(transcript(label, fields), 'utf8').digest()
72
+ }
73
+ function hmacHex(crypto, key, label, fields) {
74
+ return hmac(crypto, key, label, fields).toString('hex')
75
+ }
76
+ // Two MACs in hex, compared in time that does not depend on where they differ.
77
+ function sameMac(presented, expected) {
78
+ if (typeof presented !== 'string' || !MAC.test(presented) || presented.length !== expected.length) return false
79
+ let difference = 0
80
+ for (let index = 0; index < expected.length; index += 1) difference |= presented.charCodeAt(index) ^ expected.charCodeAt(index)
81
+ return difference === 0
82
+ }
83
+ // The exact address the service is reached at, as both proofs bind it.
84
+ const authorityOf = (channel) => (channel.host === '::1' ? `[::1]:${channel.port}` : `127.0.0.1:${channel.port}`)
85
+
86
+ // The channel this vault's data file names, or null when it names none that can be used.
87
+ function channelOf(data) {
88
+ if (!isPlainObject(data) || data.schema !== CHANNEL.dataSchema || !isPlainObject(data.channel)) return null
89
+ const { host, port } = data.channel
90
+ if (host !== '127.0.0.1' && host !== '::1') return null
91
+ if (!Number.isInteger(port) || port < 1024 || port > 65535) return null
92
+ if (typeof data.scopeId !== 'string' || !IDENTIFIER.test(data.scopeId) || typeof data.bearer !== 'string' || !BEARER.test(data.bearer)) return null
93
+ return Object.freeze({ host, port, scopeId: data.scopeId, bearer: data.bearer })
94
+ }
95
+
96
+ // What the status bar says. `held` carries the number of held edits.
97
+ const LABELS = Object.freeze({
98
+ connecting: 'Atelier: connecting',
99
+ current: 'Atelier: current',
100
+ updating: 'Atelier: updating',
101
+ stale: 'Atelier: stale',
102
+ unreachable: 'Atelier: service unreachable',
103
+ 'not-set-up': 'Atelier: not set up',
104
+ unsupported: 'Atelier: needs a newer Obsidian',
105
+ })
106
+
107
+ function labelOf(view) {
108
+ return view.state === 'held' ? `Atelier: held (${view.held})` : LABELS[view.state]
109
+ }
110
+
111
+ const plural = (count, one, many) => (count === 1 ? one : many)
112
+
113
+ // The two ways a round can fail to reach the view. Between them the status bar moves only once two rounds agree.
114
+ const ROUND_FAILURES = new Set(['not-set-up', 'unreachable'])
115
+
116
+ // Notices on a transition into a state that needs a person, and back out of one.
117
+ const ATTENTION = Object.freeze({
118
+ held: (view) => `Atelier kept ${plural(view.held, 'an edit', `${view.held} edits`)} you made. This view is not updated over ${plural(view.held, 'it', 'them')} until ${plural(view.held, 'it is', 'they are')} applied or withdrawn.`,
119
+ stale: () => 'Atelier: this view is not current. "Atelier: show status" says why.',
120
+ unreachable: () => 'Atelier: the maintenance service does not answer. The vault stays as it is.',
121
+ unsupported: () => `Atelier's plugin needs Obsidian ${CHANNEL.minimumAppVersion} or later. The vault keeps working without it.`,
122
+ })
123
+
124
+ // The view as the service reports it. Anything but current, updating or held is stale.
125
+ function viewOfStatus(body) {
126
+ const view = isPlainObject(body) && body.schema === CHANNEL.statusSchema && isPlainObject(body.view) ? body.view : null
127
+ const common = { reason: view && typeof view.reason === 'string' ? view.reason : 'no-freshness-recorded', report: isPlainObject(body) ? body : null }
128
+ if (view === null) return { state: 'stale', ...common }
129
+ if (view.state === 'current') return { state: 'current', ...common }
130
+ if (view.state === 'updating') return { state: 'updating', ...common }
131
+ if (view.state === 'held-for-your-edit') return { state: 'held', held: Number.isInteger(view.heldNoteCount) ? view.heldNoteCount : 0, ...common }
132
+ return { state: 'stale', ...common }
133
+ }
134
+
135
+ const readable = (code) => (typeof code === 'string' && code !== '' ? code.replace(/[-_]+/g, ' ') : 'none')
136
+ const byteLength = (text) => new TextEncoder().encode(text).length
137
+
138
+ // One request to the service. Resolves, never rejects:
139
+ // { kind: 'response', statusCode, body } body is a JSON object or null
140
+ // { kind: 'unreachable', code } nothing usable came back
141
+ function post(http, channel, route, body) {
142
+ return new Promise((resolve) => {
143
+ let settled = false
144
+ const settle = (value) => { if (!settled) { settled = true; resolve(value) } }
145
+ const text = JSON.stringify(body)
146
+ const authority = authorityOf(channel)
147
+ let request
148
+ try {
149
+ // A literal loopback address, whatever the data file said: nothing is resolved by name.
150
+ request = http.request({ host: channel.host === '::1' ? '::1' : '127.0.0.1', family: channel.host === '::1' ? 6 : 4, port: channel.port, method: 'POST', path: route, agent: false, timeout: CHANNEL.requestTimeoutMs,
151
+ headers: { Host: authority, 'Content-Type': 'application/json', 'Content-Length': byteLength(text), Connection: 'close' } }, (response) => {
152
+ let size = 0
153
+ let received = ''
154
+ response.setEncoding('utf8')
155
+ response.on('data', (chunk) => {
156
+ size += chunk.length
157
+ if (size > CHANNEL.maxResponseBytes) { settle({ kind: 'unreachable', code: 'answer-too-large' }); request.destroy() } else received += chunk
158
+ })
159
+ response.on('end', () => {
160
+ let parsed = null
161
+ try { parsed = JSON.parse(received) } catch { parsed = null }
162
+ settle({ kind: 'response', statusCode: response.statusCode, body: isPlainObject(parsed) ? parsed : null })
163
+ })
164
+ response.on('error', () => settle({ kind: 'unreachable', code: 'answer-failed' }))
165
+ })
166
+ } catch {
167
+ settle({ kind: 'unreachable', code: 'request-failed' })
168
+ return
169
+ }
170
+ request.on('timeout', () => { settle({ kind: 'unreachable', code: 'timeout' }); request.destroy() })
171
+ request.on('error', (error) => settle({ kind: 'unreachable', code: error && error.code === 'ECONNREFUSED' ? 'refused' : 'request-failed' }))
172
+ request.end(text)
173
+ })
174
+ }
175
+
176
+ class AtelierStatusModal extends obsidian.Modal {
177
+ constructor(app, rows) {
178
+ super(app)
179
+ this.rows = rows
180
+ }
181
+
182
+ onOpen() {
183
+ this.setTitle('Atelier status')
184
+ const list = this.contentEl.createEl('dl', { cls: 'atelier-projection-status' })
185
+ for (const [label, value] of this.rows) {
186
+ list.createEl('dt', { text: label })
187
+ list.createEl('dd', { text: value })
188
+ }
189
+ }
190
+
191
+ onClose() {
192
+ this.contentEl.empty()
193
+ }
194
+ }
195
+
196
+ class AtelierProjectionPlugin extends obsidian.Plugin {
197
+ async onload() {
198
+ this.channel = null
199
+ this.session = null
200
+ this.cycling = null
201
+ this.unloaded = false
202
+ this.view = { state: 'connecting', reason: 'not-yet-asked', report: null }
203
+ this.shownState = null
204
+ // A round's failure that differs from the failure shown, not yet seen twice in a row.
205
+ this.pendingFailure = null
206
+ this.appVersion = typeof obsidian.apiVersion === 'string' ? obsidian.apiVersion : null
207
+ this.statusBarEl = this.addStatusBarItem()
208
+ this.statusBarEl.addClass('atelier-projection-status-bar')
209
+ this.registerDomEvent(this.statusBarEl, 'click', () => this.showStatus())
210
+ this.addCommand({ id: 'show-status', name: 'Show status', callback: () => this.showStatus() })
211
+ this.setView(this.view)
212
+
213
+ if (!meetsFloor(this.appVersion)) {
214
+ // Older than the floor, or a version that cannot be read: visible, and the channel stays closed.
215
+ this.setView({ state: 'unsupported', reason: 'app-below-minimum-version', report: null })
216
+ return
217
+ }
218
+ try {
219
+ this.http = require('http')
220
+ this.fs = require('fs')
221
+ this.crypto = require('crypto')
222
+ } catch {
223
+ this.http = null
224
+ }
225
+ if (!this.http || typeof this.http.request !== 'function' || !this.fs || typeof this.fs.realpathSync !== 'function' || !this.crypto || typeof this.crypto.createHmac !== 'function' || typeof this.crypto.randomBytes !== 'function') {
226
+ this.setView({ state: 'not-set-up', reason: 'node-modules-unavailable', report: null })
227
+ return
228
+ }
229
+ // This launch of the plugin: the service tells two apps holding the same vault apart by it.
230
+ this.instanceId = `pi-${this.crypto.randomBytes(16).toString('hex')}`
231
+ await this.readChannel()
232
+ this.registerInterval(globalThis.setInterval(() => { void this.cycle() }, CHANNEL.renewEveryMs))
233
+ // Not awaited: the app finishes loading while the first round trip is under way.
234
+ void this.cycle()
235
+ }
236
+
237
+ onunload() {
238
+ // The lease lapses by itself; releasing it says at once that the vault closed. A round still under way stops at its
239
+ // next step, and a session it opens after this is released at once.
240
+ this.unloaded = true
241
+ const session = this.session
242
+ this.session = null
243
+ if (this.channel && session) void this.release(this.channel, session)
244
+ }
245
+
246
+ // Obsidian calls this when data.json changed on disk: Atelier republished the channel.
247
+ async onExternalSettingsChange() {
248
+ await this.readChannel()
249
+ // A round under way still speaks for the old channel; the next one uses the new.
250
+ if (this.cycling) await this.cycling
251
+ await this.cycle()
252
+ }
253
+
254
+ async readChannel() {
255
+ let data = null
256
+ try { data = await this.loadData() } catch { data = null }
257
+ const next = channelOf(data)
258
+ const same = next && this.channel && next.host === this.channel.host && next.port === this.channel.port && next.scopeId === this.channel.scopeId && next.bearer === this.channel.bearer
259
+ if (!same) this.session = null
260
+ this.channel = next
261
+ if (next === null) this.setView({ state: 'not-set-up', reason: data === null ? 'no-channel-data' : 'channel-data-unusable', report: null })
262
+ }
263
+
264
+ // One round: shake hands (once per session), renew the lease, read the status.
265
+ cycle() {
266
+ if (this.cycling) return this.cycling
267
+ this.cycling = this.runCycle().finally(() => { this.cycling = null })
268
+ return this.cycling
269
+ }
270
+
271
+ // Whether a round that started for `channel` may still act.
272
+ current(channel) {
273
+ return !this.unloaded && channel === this.channel
274
+ }
275
+
276
+ async runCycle() {
277
+ const channel = this.channel
278
+ if (channel === null || this.unloaded) return
279
+ if (this.session === null) {
280
+ if (!(await this.handshake(channel))) return
281
+ } else {
282
+ const lease = await this.request(channel, 'lease')
283
+ if (!this.current(channel)) return
284
+ if (lease.kind !== 'sealed') {
285
+ // Whatever answered did not seal its answer with the session's key: the session ends here, and the next request
286
+ // starts a handshake, which only the service can answer. An unproven listener gets no second request of it.
287
+ this.session = null
288
+ if (!(lease.kind === 'refused' && (lease.error === 'session-unknown' || lease.statusCode === 401))) {
289
+ this.showRound(this.unreachable(lease))
290
+ return
291
+ }
292
+ // The service started again since, the vault's key changed, or the session is not accepted: shake hands at once.
293
+ if (!(await this.handshake(channel))) return
294
+ }
295
+ }
296
+ const status = await this.request(channel, 'status')
297
+ if (!this.current(channel)) return
298
+ if (status.kind !== 'sealed') this.session = null
299
+ this.showRound(status.kind === 'sealed' ? viewOfStatus(status.document) : this.unreachable(status))
300
+ }
301
+
302
+ // The handshake. Nothing that names this vault is sent before the listener proved it holds the vault's key.
303
+ async handshake(channel) {
304
+ let vaultPath = null
305
+ // As the file system stores the path, as the service proves it: the app may have the vault in another letter case.
306
+ // On Windows Node's own resolution, as the service's (the native one also expands short names).
307
+ const native = globalThis.process?.platform !== 'win32' && typeof this.fs.realpathSync.native === 'function'
308
+ try { vaultPath = native ? this.fs.realpathSync.native(this.app.vault.adapter.getBasePath()) : this.fs.realpathSync(this.app.vault.adapter.getBasePath()) } catch { vaultPath = null }
309
+ if (typeof vaultPath !== 'string') {
310
+ this.showRound({ state: 'not-set-up', reason: 'vault-path-unknown', report: null })
311
+ return false
312
+ }
313
+ const crypto = this.crypto
314
+ const clientNonce = crypto.randomBytes(32).toString('hex')
315
+ const issuedAt = Date.now()
316
+ const challenge = await post(this.http, channel, CHANNEL.routes.challenge, { protocol: CHANNEL.protocol, keyHint: hmacHex(crypto, channel.bearer, 'key-hint', [clientNonce, issuedAt]), clientNonce, issuedAt })
317
+ if (!this.current(channel)) return false
318
+ const offer = challenge.kind === 'response' && challenge.statusCode === 200 ? challenge.body : null
319
+ if (offer === null) {
320
+ // A 401 is a key the service does not know, unless the service says the challenge itself came too late or was
321
+ // answered already: the key is not in question then, and the next round's fresh challenge tries again.
322
+ const refusal = challenge.kind === 'response' && challenge.body ? challenge.body.error : null
323
+ const keyUnknown = challenge.kind === 'response' && challenge.statusCode === 401 && refusal !== 'challenge-stale' && refusal !== 'challenge-replayed'
324
+ this.showRound(keyUnknown ? { state: 'not-set-up', reason: 'key-not-known-to-the-service', report: null } : this.unreachable(challenge))
325
+ return false
326
+ }
327
+ const bound = [channel.scopeId, authorityOf(channel), clientNonce, offer.serverNonce, offer.handshakeId]
328
+ if (offer.protocol !== CHANNEL.protocol || typeof offer.handshakeId !== 'string' || !HANDSHAKE_ID.test(offer.handshakeId) || typeof offer.serverNonce !== 'string' || !NONCE.test(offer.serverNonce)
329
+ || !sameMac(offer.serverProof, hmacHex(crypto, channel.bearer, 'server-proof', bound))) {
330
+ // Whatever answers there does not hold this vault's key: it is told nothing more.
331
+ this.showRound({ state: 'unreachable', reason: 'listener-not-proven', report: null })
332
+ return false
333
+ }
334
+ const key = hmac(crypto, channel.bearer, 'session-key', bound)
335
+ const vaultProof = hmacHex(crypto, key, 'vault', [vaultPath])
336
+ const pluginVersion = String(this.manifest.version)
337
+ const clientProof = hmacHex(crypto, channel.bearer, 'client-proof', bound.concat([pluginVersion, this.appVersion, this.instanceId, vaultProof]))
338
+ const answer = await post(this.http, channel, CHANNEL.routes.hello, { handshakeId: offer.handshakeId, pluginVersion, appVersion: this.appVersion, instanceId: this.instanceId, vaultProof, clientProof })
339
+ const sealed = this.opened(answer, 'hello', { key, id: null }, 0)
340
+ if (sealed.kind === 'sealed') {
341
+ const session = { id: sealed.sessionId, key, counter: 0 }
342
+ if (!this.current(channel)) {
343
+ // Unloaded, or a new channel, while the hello was under way: the session it opened is let go at once.
344
+ void this.release(channel, session)
345
+ return false
346
+ }
347
+ this.session = session
348
+ return true
349
+ }
350
+ if (!this.current(channel)) return false
351
+ // A copy of a vault carries its data file, but the service maintains the original only.
352
+ if (sealed.kind === 'refused' && sealed.statusCode === 409 && sealed.error === 'wrong-vault') this.showRound({ state: 'not-set-up', reason: 'not-the-vault-atelier-maintains', report: null })
353
+ else this.showRound(this.unreachable(sealed))
354
+ return false
355
+ }
356
+
357
+ // One command of the session: a counter that only goes up, and a MAC over it under the session's key.
358
+ request(channel, command) {
359
+ const session = this.session
360
+ session.counter += 1
361
+ const counter = session.counter
362
+ return post(this.http, channel, CHANNEL.routes[command], { sessionId: session.id, counter, mac: hmacHex(this.crypto, session.key, 'request', [command, session.id, counter]) })
363
+ .then((answer) => this.opened(answer, command, session, counter))
364
+ }
365
+
366
+ release(channel, session) {
367
+ session.counter += 1
368
+ return post(this.http, channel, CHANNEL.routes.release, { sessionId: session.id, counter: session.counter, mac: hmacHex(this.crypto, session.key, 'request', ['release', session.id, session.counter]) })
369
+ }
370
+
371
+ // An answer counts only when it is sealed with the session's key over this very request:
372
+ // { kind: 'sealed', document, sessionId } the service's own answer
373
+ // { kind: 'refused', statusCode, error } an error; nobody vouches for it, so it only ever makes the plugin ask again
374
+ // { kind: 'unreachable', code } nothing usable came back
375
+ opened(answer, command, session, counter) {
376
+ if (answer.kind !== 'response') return answer
377
+ const body = answer.body
378
+ if (answer.statusCode !== 200) return { kind: 'refused', statusCode: answer.statusCode, error: body && typeof body.error === 'string' ? body.error : null }
379
+ let document = null
380
+ try { document = body && typeof body.payload === 'string' ? JSON.parse(body.payload) : null } catch { document = null }
381
+ // A hello's answer names the session it opened; the MAC over it is what vouches for that name.
382
+ const sessionId = command === 'hello' ? (isPlainObject(document) && typeof document.sessionId === 'string' && SESSION_ID.test(document.sessionId) ? document.sessionId : null) : session.id
383
+ if (!isPlainObject(document) || sessionId === null || !sameMac(body.mac, hmacHex(this.crypto, session.key, 'response', [command, sessionId, counter, body.payload]))) return { kind: 'unreachable', code: 'answer-not-authenticated' }
384
+ return { kind: 'sealed', document, sessionId }
385
+ }
386
+
387
+ unreachable(answer) {
388
+ const reason = answer.kind === 'unreachable' ? answer.code : typeof answer.error === 'string' ? answer.error : answer.body && typeof answer.body.error === 'string' ? answer.body.error : `answered-${answer.statusCode}`
389
+ return { state: 'unreachable', reason, report: null }
390
+ }
391
+
392
+ // What a round found. A failure other than the one shown ('not set up' where 'service unreachable' is shown, or the other
393
+ // way round) is shown only when the next round finds it too, so answers that alternate between them do not make the
394
+ // status bar flip. Anything else is shown at once.
395
+ showRound(view) {
396
+ if (ROUND_FAILURES.has(view.state) && ROUND_FAILURES.has(this.shownState) && view.state !== this.shownState && this.pendingFailure !== view.state) {
397
+ this.pendingFailure = view.state
398
+ return
399
+ }
400
+ this.setView(view)
401
+ }
402
+
403
+ setView(view) {
404
+ // Nothing is shown once the plugin unloaded.
405
+ if (this.unloaded) return
406
+ this.pendingFailure = null
407
+ const previous = this.shownState
408
+ this.view = view
409
+ this.statusBarEl.setText(labelOf(view))
410
+ this.statusBarEl.setAttr('aria-label', `${labelOf(view)} (${readable(view.reason)})`)
411
+ this.shownState = view.state
412
+ if (previous === view.state || previous === null) return
413
+ if (Object.prototype.hasOwnProperty.call(ATTENTION, view.state)) new obsidian.Notice(ATTENTION[view.state](view))
414
+ else if (view.state === 'current' && Object.prototype.hasOwnProperty.call(ATTENTION, previous)) new obsidian.Notice('Atelier: this view is current again.')
415
+ }
416
+
417
+ statusRows() {
418
+ const report = this.view.report || {}
419
+ const view = isPlainObject(report.view) ? report.view : {}
420
+ const count = (value) => (Number.isInteger(value) ? String(value) : 'unknown')
421
+ const channel = this.channel
422
+ return [
423
+ ['View', channel ? channel.scopeId : 'not set up'],
424
+ ['State', labelOf(this.view).replace(/^Atelier: /, '')],
425
+ ['Reason', readable(this.view.reason)],
426
+ ['Generation', typeof view.generationId === 'string' ? view.generationId : 'none yet'],
427
+ ['Prepared generation', typeof view.preparedGenerationId === 'string' ? view.preparedGenerationId : 'none yet'],
428
+ ['Checked at', typeof view.checkedAt === 'string' ? view.checkedAt : 'not yet'],
429
+ ['Held edits', count(view.heldNoteCount)],
430
+ ['Retained edits', count(view.retainedEdits)],
431
+ ['Pending edits', count(isPlainObject(report.pendingEdits) ? report.pendingEdits.open : null)],
432
+ ['Service', channel ? `${channel.host === '::1' ? '[::1]' : '127.0.0.1'}:${channel.port}, ${isPlainObject(report.service) && typeof report.service.status === 'string' ? report.service.status : 'no answer'}` : 'not set up'],
433
+ ['Plugin', String(this.manifest.version)],
434
+ ['Obsidian', this.appVersion || 'unknown'],
435
+ ]
436
+ }
437
+
438
+ showStatus() {
439
+ new AtelierStatusModal(this.app, this.statusRows()).open()
440
+ }
441
+ }
442
+
443
+ AtelierProjectionPlugin.channel = CHANNEL
444
+ module.exports = AtelierProjectionPlugin
@@ -0,0 +1,9 @@
1
+ {
2
+ "id": "atelier-projection",
3
+ "name": "Atelier",
4
+ "version": "1.1.1",
5
+ "minAppVersion": "1.13.7",
6
+ "description": "Shows whether this Atelier view is current and tells Atelier's maintenance service that the vault is open. Shipped by Atelier into the vaults it manages.",
7
+ "author": "MNSTRY",
8
+ "isDesktopOnly": true
9
+ }
@@ -0,0 +1,22 @@
1
+ /* Atelier's plugin: the status bar item and the status modal. */
2
+
3
+ .atelier-projection-status-bar {
4
+ cursor: pointer;
5
+ }
6
+
7
+ .atelier-projection-status {
8
+ display: grid;
9
+ grid-template-columns: max-content 1fr;
10
+ gap: var(--size-4-1) var(--size-4-4);
11
+ margin: 0;
12
+ }
13
+
14
+ .atelier-projection-status dt {
15
+ color: var(--text-muted);
16
+ }
17
+
18
+ .atelier-projection-status dd {
19
+ margin: 0;
20
+ font-variant-numeric: tabular-nums;
21
+ overflow-wrap: anywhere;
22
+ }
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: atelier-build-harness
3
+ description: Turn an accepted objective into a bounded, evidence-backed deliverable with candidate custody, dependencies, verification gates, recovery and delivery acceptance. Use for implementation and cross-repository delivery coordination.
4
+ ---
5
+
6
+ # Build Harness
7
+
8
+ People establish the objective and acceptance criteria; agents implement admitted
9
+ work; owners review consequential decisions and actual delivery. Coordinate with
10
+ the user's existing coding, testing, review and CI tools. Fabric may consume the
11
+ coordination proposal; creating that proposal does not enroll or wake an owner.
12
+
13
+ ## Bound the work
14
+
15
+ Establish purpose, owner, scope, acceptance criteria, required gates, admitted
16
+ effects, attempt budget and stopping rule. A dependency names the exact producer
17
+ artifact and the receiving need. Shared initiative membership creates no dependency
18
+ or authority. Keep independent work moving while a concrete prerequisite is absent.
19
+
20
+ Use `atelier harness build` and `@mnstry/atelier/build`, with the shared
21
+ `@mnstry/atelier/harnesses` records. `atelier build` retains its older projection
22
+ meaning. The reference example has simulated reviews and CI: never reuse its
23
+ approval reports as real evidence. If tooling is missing, prepare a plan and report
24
+ the gap without fabricating execution.
25
+
26
+ ## Implement and verify
27
+
28
+ Reserve an isolated writer lane or follow the repository's existing custody
29
+ mechanism. Preserve local edits and do not claim another task's ownership.
30
+ Implement against the admitted inputs. Use existing tools to run appropriate
31
+ tests and actual review/CI workflows only within the task's authority.
32
+
33
+ The read-only Git adapter binds clean committed source and selected artifact bytes.
34
+ A writer declaration remains caller-reported. Record the exact commit, tree,
35
+ artifact digest, skill binding and evidence; a changed candidate needs new proof.
36
+
37
+ Persist an attempt intent before invoking an external executor. These records do
38
+ not invoke tools. On uncertain dispatch, preserve its identity and reconcile the
39
+ existing attempt before retrying. A completed transport or command does not satisfy
40
+ a review or CI gate. Keep unavailable, failed and passed evidence distinct.
41
+
42
+ ## Integrate and return learning
43
+
44
+ Evaluate the current candidate, every required gate and current dependency
45
+ snapshots. Report missing evidence and candidate changes without treating stale
46
+ receipts as current. Review, CI, integration, delivery and recipient acceptance
47
+ remain distinct. Record only the actual owner's decision and observed delivery.
48
+ The harness reports consistency; repository and host controls enforce authority.
49
+
50
+ Prepare a coordination proposal for the existing owner/coordinator. Do not create
51
+ tasks, send messages, publish or deploy from a manifest alone. Emit an accepted
52
+ artifact handoff to Knowledge Harness, preserving assumptions, limitations and
53
+ the evidence behind the result. Research quality or business usefulness cannot
54
+ be inferred from a successful build.
55
+
56
+ When an upstream source changes, refresh dependency snapshots and prepare the
57
+ affected decisions for reconsideration. Route observed skill, tool, host, context
58
+ or provider problems through version-bound Steward feedback. Preserve unknown
59
+ causes and adopter consent; do not automatically rewrite or upgrade skills.
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: atelier-coordination
3
+ description: Coordinate bounded outcomes across repositories using exact producer and receiver references, independent gates, directive dispositions and retained recovery history.
4
+ ---
5
+
6
+ # Portable Coordination
7
+
8
+ Name the outcome, integration owner, scope, exact candidate or artifact, receiving
9
+ need, next action and forecast. Discover the existing native source of each fact.
10
+ Reuse Build, Harness and repository coordination records rather than starting a
11
+ parallel approval system. Local operation does not require a Fabric service.
12
+
13
+ Use the installed Coordination contracts for bounded outcome, dependency,
14
+ directive, disposition and recovery observations. Preserve source references,
15
+ observation time and expiry. Missing, stale, changed or future-dated observations
16
+ cannot become fresh merely because a dashboard can render them. Detect dependency
17
+ cycles and keep receiving acceptance separate from producer source completion.
18
+
19
+ Bind each gate to its candidate. Tests, independent review, CI, merge, deployment,
20
+ activation and recipient acceptance retain separate evidence and authority.
21
+ A reported waiver is not a passed test. A receipt reference is not authenticated
22
+ verification. Use native verification where acceptance depends on that receipt.
23
+
24
+ Directives preserve target, scope, expiry, supersession and proposed/sent/read/
25
+ applied/verified distinctions. Do not infer a later stage from an earlier report.
26
+ A directive or skill grants no messaging, execution or repository adoption power.
27
+ Act only within existing user authority and the destination's actual contracts.
28
+
29
+ For interruption or retirement, preserve exact prior state, recovery evidence and
30
+ successor identity. Do not wake another owner, overwrite dirty work or delete
31
+ uncertain journals to make a view appear settled. Report the smallest concrete
32
+ receiving dependency and keep unrelated admitted work moving.
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: atelier-discovery-harness
3
+ description: Frame uncertain questions, compare explanations, plan evidence collection and prepare accountable decisions through the Atelier inquiry ledger.
4
+ ---
5
+
6
+ # Discovery Harness
7
+
8
+ Start with the person's purpose and the repository's actual rules, tools and
9
+ source boundaries. Resolve the installed Atelier version and use `atelier
10
+ inquiry help` when available. This source capability uses `@mnstry/atelier/inquiry`
11
+ and `contracts/atelier-inquiry.v1.schema.json`; older packages may lack them.
12
+
13
+ Record a bounded campaign, competing explanations and a hypothesis with a
14
+ context, scope and prospective test plan. Exploratory work can remain qualitative.
15
+ Use conceptual lenses where useful: definitions, mechanisms, systems and causal
16
+ structure, alternatives, counterfactuals, context variation and consequences.
17
+ For each lens say what it can reveal and what evidence would challenge it.
18
+
19
+ Prepare a request with independent purposes for each inquiry, source standards,
20
+ budget and admitted effects. Emit a standalone handoff for the user's chosen
21
+ research workflow. A provider-specific skill can fulfill this contract; do not
22
+ replace an existing skill merely because its name differs. Package installation
23
+ and effect declarations grant no execution permission.
24
+
25
+ On return, inspect complete captures, exact quotes, verification states, evidence
26
+ families, contradictions and new questions. Use current immutable references.
27
+ Record delayed answers against their original request; revise the hypothesis
28
+ explicitly if the question changes. Unsupported conclusions remain gaps.
29
+
30
+ Prefer qualitative assessment when no defensible numerical model exists.
31
+ For elicited odds, identify the source of the prior and every likelihood ratio,
32
+ state conditional-independence assumptions and show sensitivity. For a rate
33
+ model, define the population and binary trial before supplying counts. Interview
34
+ enthusiasm is not automatically a trial or a likelihood ratio. Disclose evidence
35
+ already used in the prior. Repeated reports from one family do not create new
36
+ independent observations. Broad graph links never justify confidence arithmetic.
37
+
38
+ Use `inquiry append` with the current history digest. The ledger checks references
39
+ and arithmetic; verification and reviewer identities are caller reports. Record
40
+ only actual owner dispositions within existing authority. Use `inquiry graph`
41
+ to prepare a source diff and relation proposals, then follow the receiving
42
+ repository's review and graph workflow. Keep raw captures outside accepted
43
+ knowledge. A source withdrawal requires reconsidering affected decisions.
44
+
45
+ Send only permitted, version-bound feedback to Skill Steward. A failure can come
46
+ from a method, tool, source, context or provider. Feedback proposes evaluation;
47
+ it never edits the skill or adopts an upgrade. Retain prior heuristic scores as
48
+ `legacy-assessment` records, without turning them into probabilities.
@@ -44,6 +44,35 @@ Verify the resolved identity and inventory before running its commands. Inspect
44
44
  migration/compatibility effects before rewriting the old Atelier lock. Retain the
45
45
  old lock and all lineage. Keep installation changes distinct from generated files.
46
46
 
47
+ When the package manager identified above is npm, check advisory-pinned
48
+ dependencies in the staged candidate: the selected package's exact-version
49
+ `overrides` entries and any package the owner names. Record an override that is
50
+ not an exact version as unchecked. A dependency publisher's root-project
51
+ `overrides` are not inherited by its consumers. `npm ls <package> --all` lists
52
+ every installed copy and reports copies outside a declared range; a valid range
53
+ need not equal the resolved version literally. Each copy must be at its pin or
54
+ an owner-approved version; more than one copy can be valid in a consumer's
55
+ tree. `npm ls` alone does not compare with the lock. Using the lock of the
56
+ candidate's npm root project, compare `npm ls --all --json` with
57
+ `npm ls --all --json --package-lock-only` by dependency path and version, and
58
+ refuse a tree that reports `problems`. Classify each difference on evidence.
59
+ Two different versions at one dependency path are a stale installation. A lock
60
+ entry with no installed version is not installed: call it a package for another
61
+ platform only when its entry in the lock file lists an `os`, `cpu` or `libc`
62
+ that excludes this host as npm is configured. Otherwise record it as missing,
63
+ with the cause when known, and as stale unless the owner confirms the omission.
64
+ Do not report that the tree agrees with the lock while any difference is
65
+ unexplained. Changing a pin or an override in the owner's project is an
66
+ installation effect that needs the owner's consent; adoption requires the
67
+ completed change and its readback. This skill does not prove an offline
68
+ reinstall. When the owner or the repository's procedure requires offline
69
+ installs, follow that procedure and record its result separately. The lock
70
+ comparison was observed once on one development tree whose only differences
71
+ were packages for other platforms, on macOS with npm 10. Other platforms, npm
72
+ versions, real workspaces and missing packages are unqualified. Record the Node
73
+ and npm versions, registry and platform in private evidence, and whether each
74
+ observation used a real registry or a fixture.
75
+
47
76
  Check exact-plan eligibility: Linux/macOS, one managed repository at `.`, config
48
77
  and workspace at its root, linked candidate worktree, clean state and supported
49
78
  Git settings. Packs, overlays and other unsupported participants require the