@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,187 @@
1
+ import { createHash } from 'node:crypto'
2
+ import { MAX_CAPTURE_BYTES } from './index.mjs'
3
+
4
+ const sha = bytes => createHash('sha256').update(bytes).digest('hex')
5
+ const candidateId = value => typeof value === 'string' && /^[a-z][a-z0-9-]{0,63}$/.test(value)
6
+ const own = (value, key) => value !== null && typeof value === 'object' && Object.hasOwn(value, key)
7
+ const same = (a, b) => a?.id === b?.id && a?.digest === b?.digest
8
+ const modalities = new Set(['asserted', 'conditional', 'proposed', 'possible', 'uncertain', 'unknown'])
9
+ const nativeAuxiliary = {
10
+ graphify: new Set(['id', 'source', 'target', 'relation', 'description', 'source_file', 'source_location', 'source_url', 'confidence', 'confidence_score', 'weight']),
11
+ 'lightrag-json': new Set(['id', 'source', 'target', 'description', 'keywords', 'source_id', 'file_path', 'timestamp', 'weight']),
12
+ }
13
+
14
+ export class NativeHandoffError extends Error {
15
+ constructor(code, message, normalization = null) {
16
+ super(message); this.name = 'NativeHandoffError'; this.code = code
17
+ if (normalization) this.normalization = normalization
18
+ }
19
+ }
20
+ const check = (condition, code, message) => { if (!condition) throw new NativeHandoffError(code, message) }
21
+ function call(mapper, context) {
22
+ const value = mapper(structuredClone(context))
23
+ check(!value || typeof value.then !== 'function', 'NATIVE_MAPPER_ASYNC', 'Mapping callbacks must be cheap synchronous owner mappings')
24
+ return value
25
+ }
26
+ function atPath(record, path) {
27
+ check(Array.isArray(path) && path.length > 0 && path.every(key => typeof key === 'string' || Number.isSafeInteger(key)),
28
+ 'NATIVE_QUALIFIER_MISSING', 'Explicit raw-field qualifier paths are required')
29
+ let value = record
30
+ for (const key of path) {
31
+ check(own(value, key), 'NATIVE_QUALIFIER_MISSING', 'The qualifier is absent from the received native object')
32
+ value = value[key]
33
+ }
34
+ return structuredClone(value)
35
+ }
36
+ function approved(mapping, input, vocabulary) {
37
+ return mapping?.approved === true && same(mapping.ownerRef, input.domainRef) && vocabulary.has(mapping.id)
38
+ }
39
+ function fieldsAccounted(record, paths, auxiliary, prefix = []) {
40
+ if (paths.some(path => path.length === prefix.length && path.every((key, index) => key === prefix[index]))) return true
41
+ if (prefix.length === 1 && auxiliary.has(prefix[0])) return true
42
+ if (!record || typeof record !== 'object') return false
43
+ return Object.keys(record).every(key => {
44
+ const next = [...prefix, key]
45
+ if (next.length === 1 && auxiliary.has(key)) return true
46
+ return paths.some(path => path.length >= next.length && next.every((item, index) => path[index] === item)) &&
47
+ fieldsAccounted(record[key], paths, auxiliary, next)
48
+ })
49
+ }
50
+
51
+ /** Pure conversion of received raw Graphify nodes/edges or LightRAG model JSON.
52
+ * It does not run either tool, find evidence, approve mappings or resolve identity.
53
+ */
54
+ export function normalizeNativeExtraction({ bytes, input, profile, mappers }) {
55
+ check(bytes instanceof Uint8Array && bytes.length <= MAX_CAPTURE_BYTES, 'NATIVE_RAW_LIMIT', 'Bounded original native bytes are required')
56
+ check(['graphify', 'lightrag-json'].includes(profile), 'NATIVE_PROFILE_UNSUPPORTED', 'Select an inspected native JSON profile')
57
+ check(input?.schema === 'atelier.semantic-input/v0' && input.coverage === 'selected-spans-only' && input.readScope === 'all-plan',
58
+ 'NATIVE_INPUT_BINDING', 'The existing pinned semantic input is required')
59
+ for (const name of ['entityType', 'identity', 'predicate', 'evidence', 'participants', 'qualifiers'])
60
+ check(typeof mappers?.[name] === 'function', 'NATIVE_MAPPER_MISSING', `Existing owner ${name} mapping callback is required`)
61
+ let raw
62
+ try { raw = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes)) }
63
+ catch { throw new NativeHandoffError('NATIVE_RAW_INVALID', 'Native output must be exact UTF-8 JSON; original bytes stay with intake') }
64
+ const entityKey = profile === 'graphify' ? 'nodes' : 'entities', assertionKey = profile === 'graphify' ? 'edges' : 'relationships'
65
+ check(raw && Array.isArray(raw[entityKey]) && Array.isArray(raw[assertionKey]), 'NATIVE_PROFILE_UNSUPPORTED', 'The selected native collection shape is required')
66
+ check(raw.hyperedges === undefined || Array.isArray(raw.hyperedges), 'NATIVE_PROFILE_UNSUPPORTED', 'Native hyperedges must retain their actual collection shape')
67
+ check(raw[entityKey].length <= 64 && raw[assertionKey].length <= 64 && (raw.hyperedges?.length ?? 0) <= 64,
68
+ 'NATIVE_HANDOFF_LIMIT', 'Existing candidate collections require an owner-selected bounded native slice')
69
+ const candidates = { schema: 'atelier.semantic-candidate/v0', inputDigest: input.digest, entities: [], assertions: [], unknowns: [] }
70
+ const unresolved = [], mappings = [], ids = new Set(), entities = new Map()
71
+ const types = new Set(input.domain.data.vocabulary.types.map(x => x.id)), predicates = new Set(input.domain.data.vocabulary.relations.map(x => x.id))
72
+ const context = (record, kind, index, collection) => ({ native: record, nativeRef: { profile, collection, index }, kind, input })
73
+ function support(ctx) {
74
+ const selected = call(mappers.evidence, ctx)
75
+ check(Array.isArray(selected) && selected.length > 0 && selected.length <= 16, 'NATIVE_SUPPORT_MISSING', 'Exact existing located input support is required')
76
+ const seen = new Set()
77
+ return selected.map(value => {
78
+ const matches = input.evidence.filter(span => {
79
+ const a = span.reference, b = value.reference
80
+ return b && a.sourceId === b.sourceId && a.sourceDigest === b.sourceDigest && a.attemptId === b.attemptId &&
81
+ a.locator.kind === b.locator?.kind && a.locator.value === b.locator.value
82
+ })
83
+ check(matches.length === 1 && !seen.has(matches[0].id), 'NATIVE_SUPPORT_BINDING', 'Support must resolve to one exact current selected input reference')
84
+ const span = matches[0]; seen.add(span.id)
85
+ check(typeof value.quote === 'string' && value.quote.length > 0 && span.receipt.text.includes(value.quote),
86
+ 'NATIVE_SUPPORT_QUOTE', 'Owner-supplied quote must occur in its exact input span')
87
+ check(!/[\r\n]/u.test(value.quote), 'NATIVE_LOCATOR_UNSUPPORTED', 'Current runner does not represent multiline assertion quotes')
88
+ return { id: span.id, quote: value.quote }
89
+ })
90
+ }
91
+ function loss(ctx, code, reason, located = []) {
92
+ let unknownId = null
93
+ if (located.length && candidates.unknowns.length < 64) {
94
+ unknownId = `native-unresolved-${candidates.unknowns.length + 1}`
95
+ while (ids.has(unknownId)) unknownId += '-x'
96
+ ids.add(unknownId)
97
+ candidates.unknowns.push({ id: unknownId, relatedCandidateId: null,
98
+ reason: `${code}: ${reason}; retained ${profile} ${ctx.nativeRef.collection}[${ctx.nativeRef.index}] in raw sha256:${sha(bytes)}`,
99
+ evidence: located.map(x => x.id) })
100
+ }
101
+ unresolved.push({ code, reason, nativeRef: ctx.nativeRef, native: structuredClone(ctx.native),
102
+ representedUnknownId: unknownId, support: located })
103
+ }
104
+ function identity(ctx, located) {
105
+ const choice = call(mappers.identity, ctx)
106
+ check(choice && same(choice.ownerRef, input.domainRef) && candidateId(choice.id) && !ids.has(choice.id),
107
+ 'NATIVE_IDENTITY_UNMAPPED', 'Explicit unique owner-mapped source candidate identity is required; labels do not merge IDs')
108
+ const selected = ctx.kind === 'entity' ? choice.identity : null
109
+ check(ctx.kind !== 'entity' || selected && ['source-local', 'existing-candidate', 'unknown'].includes(selected.status) && Array.isArray(selected.candidateIds),
110
+ 'NATIVE_IDENTITY_UNMAPPED', 'Existing candidate identity semantics must be supplied explicitly')
111
+ // The existing semantic validator checks matching supplied canonical candidates.
112
+ ids.add(choice.id)
113
+ return { id: choice.id, identity: structuredClone(selected), evidence: located.map(x => x.id) }
114
+ }
115
+ for (const [index, native] of raw[entityKey].entries()) {
116
+ const ctx = context(native, 'entity', index, entityKey); let located = []
117
+ if (!native || typeof native !== 'object' || Array.isArray(native)) { loss(ctx, 'NATIVE_OBJECT_UNSUPPORTED', 'A received native entity object is required'); continue }
118
+ try {
119
+ located = support(ctx)
120
+ const type = call(mappers.entityType, ctx)
121
+ check(approved(type, input, types), 'NATIVE_TYPE_UNMAPPED', 'Explicit owner-approved existing vocabulary entity type is required')
122
+ const mapped = identity(ctx, located), label = profile === 'graphify' ? native.label : native.name
123
+ const nativeId = profile === 'graphify' ? native.id : native.name
124
+ check(typeof label === 'string' && label.length > 0, 'NATIVE_LABEL_MISSING', 'Native display label is required')
125
+ check(typeof nativeId === 'string' && nativeId.length > 0, 'NATIVE_IDENTITY_UNMAPPED', 'Actual native identifier is required before participant mapping')
126
+ candidates.entities.push({ ...mapped, label, type: type.id })
127
+ entities.set(mapped.id, { native, nativeRef: ctx.nativeRef, nativeId })
128
+ mappings.push({ nativeRef: ctx.nativeRef, candidateId: mapped.id, entityType: type })
129
+ } catch (error) {
130
+ if (!(error instanceof NativeHandoffError)) throw error
131
+ loss(ctx, error.code, error.message, located)
132
+ }
133
+ }
134
+ for (const [index, native] of raw[assertionKey].entries()) {
135
+ const ctx = context(native, 'assertion', index, assertionKey); let located = []
136
+ if (!native || typeof native !== 'object' || Array.isArray(native)) { loss(ctx, 'NATIVE_OBJECT_UNSUPPORTED', 'A received native assertion object is required'); continue }
137
+ try {
138
+ located = support(ctx)
139
+ const predicate = call(mappers.predicate, ctx)
140
+ check(approved(predicate, input, predicates), 'NATIVE_PREDICATE_UNMAPPED', 'Explicit owner-approved existing vocabulary predicate is required')
141
+ const choice = call(mappers.participants, { ...ctx, entityMappings: [...entities].map(([id, entity]) => ({ id, ...entity })) })
142
+ check(same(choice?.ownerRef, input.domainRef) && entities.has(choice.subjectId) &&
143
+ (choice.objectId === null || entities.has(choice.objectId)), 'NATIVE_PARTICIPANT_UNMAPPED', 'Explicit mapped source participants are required')
144
+ check(native.source === entities.get(choice.subjectId).nativeId &&
145
+ (choice.objectId === null ? native.target === null : native.target === entities.get(choice.objectId).nativeId),
146
+ 'NATIVE_PARTICIPANT_BINDING', 'Mapped participants differ from actual native source/target fields')
147
+ const proof = call(mappers.qualifiers, ctx), qualifier = {}
148
+ check(proof?.paths && Object.keys(proof.paths).length === 5 && ['direction', 'negated', 'modality', 'scope', 'time'].every(field => own(proof.paths, field)),
149
+ 'NATIVE_QUALIFIER_MISSING', 'Provide exactly the five existing qualifier paths; extra qualifiers require a separate supported mapping')
150
+ for (const field of ['direction', 'negated', 'modality', 'scope', 'time']) qualifier[field] = atPath(native, proof?.paths?.[field])
151
+ check(qualifier.direction === (choice.objectId === null ? 'subject-only' : 'subject-to-object') && typeof qualifier.negated === 'boolean' &&
152
+ modalities.has(qualifier.modality), 'NATIVE_QUALIFIER_UNSUPPORTED', 'Explicit native direction, polarity and supported modality are required')
153
+ check(typeof qualifier.scope === 'string' && qualifier.scope === input.domain.data.scope, 'NATIVE_SCOPE_UNSUPPORTED', 'Native assertion scope must equal the existing domain scope')
154
+ const time = qualifier.time
155
+ check(time && ['from', 'until', 'expression', 'unknowns'].every(field => own(time, field)) && Object.keys(time).length === 4,
156
+ 'NATIVE_TIME_UNSUPPORTED', 'Native time must explicitly retain the existing four-field qualification')
157
+ check(fieldsAccounted(native, Object.values(proof.paths), nativeAuxiliary[profile]),
158
+ 'NATIVE_QUALIFIER_UNMAPPED', 'Additional native fields require an explicit reviewed mapping; retained unresolved rather than dropped')
159
+ const mapped = identity(ctx, located)
160
+ candidates.assertions.push({ id: mapped.id, subjectId: choice.subjectId, predicate: predicate.id, objectId: choice.objectId,
161
+ ...qualifier, evidence: located })
162
+ mappings.push({ nativeRef: ctx.nativeRef, candidateId: mapped.id, predicate, qualifierPaths: proof.paths })
163
+ } catch (error) {
164
+ if (!(error instanceof NativeHandoffError)) throw error
165
+ loss(ctx, error.code, error.message, located)
166
+ }
167
+ }
168
+ for (const [index, native] of (raw.hyperedges ?? []).entries()) {
169
+ const ctx = context(native, 'hyperedge', index, 'hyperedges'); let located = []
170
+ try { located = support(ctx) } catch (error) { if (!(error instanceof NativeHandoffError)) throw error }
171
+ loss(ctx, 'NATIVE_HYPEREDGE_UNSUPPORTED', 'Current candidate profile has unary/binary assertions only', located)
172
+ }
173
+ return { candidates, mappings, unresolved,
174
+ refused: unresolved.some(item => item.representedUnknownId === null),
175
+ rawBinding: { bytes: bytes.length, sha256: sha(bytes) },
176
+ coverage: input.coverage, readScope: input.readScope,
177
+ semanticAcceptance: 'pending', authority: 'none', canonicalMutation: false }
178
+ }
179
+
180
+ /** Pass directly as bridge.normalize; immutable provider/tool bytes stay intact. */
181
+ export function createNativeNormalizer({ profile, mappers }) {
182
+ return ({ bytes, input }) => {
183
+ const handoff = normalizeNativeExtraction({ bytes, input, profile, mappers })
184
+ if (handoff.refused) throw new NativeHandoffError('NATIVE_HANDOFF_UNRESOLVED', 'Native objects lack representable existing-profile support; reopen retained raw capture', handoff)
185
+ return handoff.candidates
186
+ }
187
+ }
@@ -0,0 +1,218 @@
1
+ // Pure structural projections. No source reference or embedded instruction is executed.
2
+ const VERSION = '1.0.0';
3
+ const MAX_BYTES = 16 * 1024 * 1024;
4
+ const MAX_ITEMS = 100000;
5
+ const DISCOVERY = 'Processor selection uses the filename extension only; content type is not verified.';
6
+ const REFERENCES = 'Embedded media, external references and instructions are not processed or followed.';
7
+ const UTF8 = 'Input must be valid UTF-8; one leading UTF-8 BOM prefix is removed.';
8
+
9
+ function refuse(code, message, limitKind) {
10
+ throw Object.assign(new Error(message), { code, ...(limitKind ? { limitKind } : {}) });
11
+ }
12
+ function limit(message, kind) { refuse('INGESTION_LIMIT', message, kind); }
13
+
14
+ export function describeIngestionProcessor(ref) {
15
+ if (typeof ref !== 'string' || !ref || ref.length > 4096 || ref.includes('\0')) {
16
+ refuse('INGESTION_ARGUMENT', 'A bounded source reference is required');
17
+ }
18
+ const filename = ref.split(/[\\/]/).at(-1);
19
+ const extension = filename.includes('.') ? filename.slice(filename.lastIndexOf('.') + 1).toLowerCase() : '';
20
+ const definitions = {
21
+ txt: ['utf8-lines', 'text', 'text', 'Line evidence preserves text and blank lines, excludes line terminators and does not create a final empty line after a terminator.'],
22
+ text: ['utf8-lines', 'text', 'text', 'Line evidence preserves text and blank lines, excludes line terminators and does not create a final empty line after a terminator.'],
23
+ md: ['utf8-lines', 'markdown', 'text', 'Markdown is projected as source lines, not rendered or interpreted; line terminators are excluded and a final terminator creates no extra empty line.'],
24
+ markdown: ['utf8-lines', 'markdown', 'text', 'Markdown is projected as source lines, not rendered or interpreted; line terminators are excluded and a final terminator creates no extra empty line.'],
25
+ csv: ['csv-cells', 'csv', 'tabular', 'CSV evidence contains decoded cell strings including headers and empty cells; ragged rows are retained, and types, headers and formulas are not interpreted.'],
26
+ json: ['json-leaves', 'json', 'structured', 'JSON evidence contains primitive leaves only; empty containers have no evidence. Strings are decoded; number tokens, booleans and null retain their source spelling. Duplicate decoded object keys are refused.'],
27
+ };
28
+ if (Object.hasOwn(definitions, extension)) {
29
+ const [id, format, modality, projection] = definitions[extension];
30
+ return { id, version: VERSION, format, modality, supported: true,
31
+ limitations: [DISCOVERY, UTF8, REFERENCES, projection, 'Complete coverage applies only to the named structural projection, not semantic acceptance.'] };
32
+ }
33
+ const unsupported = {
34
+ pdf: 'document', doc: 'document', docx: 'document', rtf: 'document', odt: 'document',
35
+ html: 'document', htm: 'document', xml: 'document', xlsx: 'tabular', xls: 'tabular',
36
+ png: 'image', jpg: 'image', jpeg: 'image', gif: 'image', webp: 'image', svg: 'image', tiff: 'image',
37
+ mp3: 'audio', wav: 'audio', m4a: 'audio', opus: 'audio', ogg: 'audio', flac: 'audio',
38
+ mp4: 'video', mov: 'video', webm: 'video', zip: 'archive', gz: 'archive', tar: 'archive',
39
+ };
40
+ const known = Object.hasOwn(unsupported, extension);
41
+ return { id: 'unsupported-source', version: VERSION, format: known ? extension : 'unknown',
42
+ modality: known ? unsupported[extension] : 'unknown', supported: false,
43
+ limitations: [DISCOVERY, REFERENCES, 'No built-in structural processor supports this source type; no content was extracted.'] };
44
+ }
45
+
46
+ function argumentsFor(bytes, limits) {
47
+ if (!(bytes instanceof Uint8Array)) refuse('INGESTION_ARGUMENT', 'Input bytes must be a Uint8Array or Buffer');
48
+ if (bytes.byteLength > MAX_BYTES) limit('Input exceeds the 16 MiB processor ceiling', 'input-bytes');
49
+ if (!limits || typeof limits !== 'object' || Array.isArray(limits) ||
50
+ Object.keys(limits).some(key => !['maxOutputBytes', 'maxEvidenceItems'].includes(key))) {
51
+ refuse('INGESTION_ARGUMENT', 'Explicit output and evidence limits are required');
52
+ }
53
+ for (const [key, ceiling] of [['maxOutputBytes', MAX_BYTES], ['maxEvidenceItems', MAX_ITEMS]]) {
54
+ if (!Number.isSafeInteger(limits[key]) || limits[key] < 0 || limits[key] > ceiling) {
55
+ refuse('INGESTION_ARGUMENT', 'Processor limits must be nonnegative integers within the built-in ceilings');
56
+ }
57
+ }
58
+ }
59
+
60
+ function lines(text, emit) {
61
+ const endings = /\r\n|\n|\r/g;
62
+ let start = 0, line = 1, match;
63
+ while ((match = endings.exec(text))) {
64
+ emit('line', String(line++), text.slice(start, match.index));
65
+ start = match.index + match[0].length;
66
+ }
67
+ if (start < text.length) emit('line', String(line), text.slice(start));
68
+ }
69
+
70
+ function csvCells(text, emit) {
71
+ let cursor = 0, row = 1, column = 1;
72
+ const invalid = () => refuse('INGESTION_INVALID_CSV', 'CSV has invalid quoting');
73
+ while (cursor < text.length) {
74
+ let value;
75
+ if (text[cursor] === '"') {
76
+ cursor++;
77
+ let start = cursor, closed = false;
78
+ const parts = [];
79
+ while (cursor < text.length) {
80
+ if (text[cursor] !== '"') { cursor++; continue; }
81
+ parts.push(text.slice(start, cursor));
82
+ if (text[cursor + 1] === '"') {
83
+ parts.push('"'); cursor += 2; start = cursor; continue;
84
+ }
85
+ cursor++; closed = true; break;
86
+ }
87
+ if (!closed) invalid();
88
+ if (cursor < text.length && ![',', '\r', '\n'].includes(text[cursor])) invalid();
89
+ value = parts.join('');
90
+ } else {
91
+ const start = cursor;
92
+ while (cursor < text.length && ![',', '\r', '\n'].includes(text[cursor])) {
93
+ if (text[cursor] === '"') invalid();
94
+ cursor++;
95
+ }
96
+ value = text.slice(start, cursor);
97
+ }
98
+ emit('csv-cell', `row:${row},column:${column}`, value);
99
+ if (cursor === text.length) break;
100
+ if (text[cursor] === ',') {
101
+ cursor++; column++;
102
+ if (cursor === text.length) emit('csv-cell', `row:${row},column:${column}`, '');
103
+ } else {
104
+ const crlf = text[cursor] === '\r' && text[cursor + 1] === '\n';
105
+ cursor += crlf ? 2 : 1; row++; column = 1;
106
+ }
107
+ }
108
+ }
109
+
110
+ function jsonLeaves(text, emit) {
111
+ let cursor = 0;
112
+ const invalid = () => refuse('INGESTION_INVALID_JSON', 'JSON is malformed or contains duplicate object keys');
113
+ const whitespace = () => { while (cursor < text.length && /[ \t\r\n]/.test(text[cursor])) cursor++; };
114
+ const pointerKey = key => key.replaceAll('~', '~0').replaceAll('/', '~1');
115
+ function string() {
116
+ if (text[cursor] !== '"') invalid();
117
+ const start = cursor++;
118
+ while (cursor < text.length) {
119
+ const current = text[cursor++];
120
+ if (current === '"') {
121
+ try { return JSON.parse(text.slice(start, cursor)); } catch { invalid(); }
122
+ }
123
+ if (current.charCodeAt(0) < 0x20) invalid();
124
+ if (current !== '\\') continue;
125
+ if (cursor === text.length) invalid();
126
+ const escape = text[cursor++];
127
+ if (escape === 'u') {
128
+ if (!/^[0-9a-fA-F]{4}$/.test(text.slice(cursor, cursor + 4))) invalid();
129
+ cursor += 4;
130
+ } else if (!'"\\/bfnrt'.includes(escape)) invalid();
131
+ }
132
+ invalid();
133
+ }
134
+ function value(pointer, depth) {
135
+ if (depth > 128) limit('JSON exceeds the nesting ceiling of 128', 'json-depth');
136
+ whitespace();
137
+ const next = text[cursor];
138
+ if (next === '"') { emit('json-pointer', pointer, string()); return; }
139
+ if (next === '{') {
140
+ cursor++; whitespace();
141
+ if (text[cursor] === '}') { cursor++; return; }
142
+ const keys = new Set();
143
+ while (cursor < text.length) {
144
+ whitespace();
145
+ const key = string();
146
+ if (keys.has(key)) invalid();
147
+ keys.add(key); whitespace();
148
+ if (text[cursor++] !== ':') invalid();
149
+ value(`${pointer}/${pointerKey(key)}`, depth + 1); whitespace();
150
+ const separator = text[cursor++];
151
+ if (separator === '}') return;
152
+ if (separator !== ',') invalid();
153
+ }
154
+ invalid();
155
+ }
156
+ if (next === '[') {
157
+ cursor++; whitespace();
158
+ if (text[cursor] === ']') { cursor++; return; }
159
+ let index = 0;
160
+ while (cursor < text.length) {
161
+ value(`${pointer}/${index++}`, depth + 1); whitespace();
162
+ const separator = text[cursor++];
163
+ if (separator === ']') return;
164
+ if (separator !== ',') invalid();
165
+ }
166
+ invalid();
167
+ }
168
+ for (const literal of ['true', 'false', 'null']) {
169
+ if (text.startsWith(literal, cursor)) {
170
+ cursor += literal.length; emit('json-pointer', pointer, literal); return;
171
+ }
172
+ }
173
+ const number = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
174
+ number.lastIndex = cursor;
175
+ const match = number.exec(text);
176
+ if (!match) invalid();
177
+ cursor = number.lastIndex;
178
+ emit('json-pointer', pointer, match[0]);
179
+ }
180
+ value('', 0); whitespace();
181
+ if (cursor !== text.length) invalid();
182
+ }
183
+
184
+ export function extractIngestionEvidence({ ref, bytes, limits } = {}) {
185
+ const descriptor = describeIngestionProcessor(ref);
186
+ argumentsFor(bytes, limits);
187
+ const evidence = [];
188
+ let evidenceBytes = 2;
189
+ const emit = (kind, value, text) => {
190
+ if (evidence.length >= limits.maxEvidenceItems) limit('Extraction exceeds the evidence item limit', 'evidence-items');
191
+ const item = { locator: { kind, value }, text };
192
+ evidenceBytes += Buffer.byteLength(JSON.stringify(item), 'utf8') + (evidence.length ? 1 : 0);
193
+ if (evidenceBytes > limits.maxOutputBytes) limit('Extraction exceeds the output byte limit', 'output-bytes');
194
+ evidence.push(item);
195
+ };
196
+ let unit = 'source';
197
+ if (descriptor.supported) {
198
+ let text;
199
+ try { text = new TextDecoder('utf-8', { fatal: true }).decode(bytes); }
200
+ catch { refuse('INGESTION_INVALID_UTF8', 'Source is not valid UTF-8'); }
201
+ if (descriptor.id === 'utf8-lines') { unit = 'line'; lines(text, emit); }
202
+ else if (descriptor.id === 'csv-cells') { unit = 'csv-cell'; csvCells(text, emit); }
203
+ else { unit = 'json-leaf'; jsonLeaves(text, emit); }
204
+ }
205
+ const result = {
206
+ schema: 'mnstry.atelier-ingestion-extraction@v1',
207
+ processor: { id: descriptor.id, version: descriptor.version },
208
+ format: descriptor.format, modality: descriptor.modality,
209
+ coverage: { unit, total: descriptor.supported ? evidence.length : 1,
210
+ processed: evidence.length, omitted: descriptor.supported ? 0 : 1,
211
+ complete: descriptor.supported, limitations: [...descriptor.limitations] },
212
+ evidence,
213
+ };
214
+ if (Buffer.byteLength(JSON.stringify(result), 'utf8') > limits.maxOutputBytes) {
215
+ limit('Extraction including its coverage envelope exceeds the output byte limit', 'output-bytes');
216
+ }
217
+ return result;
218
+ }
@@ -0,0 +1,203 @@
1
+ import { ingestionDigest, ingestionJson } from './contracts.mjs'
2
+ import { assertHarness, harnessRef } from '../harnesses/contracts.mjs'
3
+
4
+ // Internal first-consumer formats. These are not registered public contracts.
5
+ export const SEMANTIC_CANDIDATE_VERSION = 'atelier.semantic-candidate/v0'
6
+ const INPUT_VERSION = 'atelier.semantic-input/v0'
7
+ const PROPOSAL_VERSION = 'atelier.semantic-proposals/v0'
8
+ const modalities = new Set(['asserted', 'conditional', 'proposed', 'possible', 'uncertain', 'unknown'])
9
+ const identifier = value => typeof value === 'string' && /^[a-z][a-z0-9-]{0,63}$/.test(value)
10
+ const string = (value, max = 8192) => {
11
+ if (typeof value === 'string') check(value.length <= max, 'SEMANTIC_LIMIT', 'Semantic text length exceeded')
12
+ return typeof value === 'string' && value.length > 0
13
+ }
14
+ const array = (value, max) => {
15
+ if (Array.isArray(value)) check(value.length <= max, 'SEMANTIC_LIMIT', 'Semantic collection limit exceeded')
16
+ return Array.isArray(value)
17
+ }
18
+ const digest = value => typeof value === 'string' && /^[a-f0-9]{64}$/.test(value)
19
+
20
+ export class SemanticProposalError extends Error {
21
+ constructor(code, message) { super(message); this.name = 'SemanticProposalError'; this.code = code; this.refusalCount = 1 }
22
+ }
23
+ function check(condition, code, message) { if (!condition) throw new SemanticProposalError(code, message) }
24
+ function plain(value) {
25
+ try { return ingestionJson(value) }
26
+ catch (error) {
27
+ const limit = ['ingestion JSON depth exceeded', 'ingestion member ceiling exceeded', 'ingestion document byte ceiling exceeded'].includes(error?.message)
28
+ throw new SemanticProposalError(limit ? 'SEMANTIC_LIMIT' : 'SEMANTIC_INVALID', limit ? 'Semantic JSON limit exceeded' : 'Bounded plain JSON is required')
29
+ }
30
+ }
31
+ function closed(value, fields, code = 'SEMANTIC_INVALID') {
32
+ check(value && !Array.isArray(value) && typeof value === 'object' && Object.keys(value).length === fields.length && fields.every(field => Object.hasOwn(value, field)), code, 'The declared semantic shape is required')
33
+ }
34
+ function profile(value) {
35
+ const domain = plain(value)
36
+ try { assertHarness(domain, 'knowledge') }
37
+ catch { throw new SemanticProposalError('SEMANTIC_PROFILE', 'A valid existing knowledge domain is required') }
38
+ check(['domain', 'domain-revision'].includes(domain.kind), 'SEMANTIC_PROFILE', 'A domain definition is required')
39
+ for (const entries of [domain.data.vocabulary.types, domain.data.vocabulary.relations]) {
40
+ check(new Set(entries.map(entry => entry.id)).size === entries.length, 'SEMANTIC_PROFILE', 'Vocabulary identifiers must be unambiguous')
41
+ }
42
+ return domain
43
+ }
44
+ function evidenceReference(value) {
45
+ closed(value, ['sourceId', 'sourceDigest', 'attemptId', 'locator'])
46
+ check(identifier(value.sourceId) && digest(value.sourceDigest) && string(value.attemptId, 256), 'SEMANTIC_EVIDENCE', 'Exact source and attempt bindings are required')
47
+ closed(value.locator, ['kind', 'value'])
48
+ check(['line', 'csv-cell', 'json-pointer'].includes(value.locator.kind) && typeof value.locator.value === 'string', 'SEMANTIC_EVIDENCE', 'A supported exact locator is required')
49
+ check(value.locator.value.length <= 16384, 'SEMANTIC_LIMIT', 'Semantic locator length exceeded')
50
+ }
51
+ function readEvidence(store, plan, reference) {
52
+ check(typeof store?.getEvidence === 'function', 'SEMANTIC_EVIDENCE', 'The existing exact evidence reader is required')
53
+ let receipt
54
+ try { receipt = plain(store.getEvidence(plain({ ...plan, ...reference }))) }
55
+ catch (error) {
56
+ if (error instanceof SemanticProposalError) throw error
57
+ throw new SemanticProposalError(error?.code === 'INGESTION_STALE' ? 'SEMANTIC_STALE' : 'SEMANTIC_EVIDENCE', 'Current verified evidence could not be read')
58
+ }
59
+ check(receipt && typeof receipt === 'object' && !Array.isArray(receipt), 'SEMANTIC_EVIDENCE', 'An evidence receipt object is required')
60
+ check(receipt.readScope === 'all-plan', 'SEMANTIC_READ_SCOPE', 'This profile requires the existing all-plan read scope')
61
+ check(receipt.schema === 'mnstry.atelier-ingestion-evidence@v1', 'SEMANTIC_EVIDENCE', 'The existing evidence receipt schema is required')
62
+ check(receipt.freshness === 'current', 'SEMANTIC_EVIDENCE', 'Current source evidence is required')
63
+ check(receipt.integrity === 'verified', 'SEMANTIC_EVIDENCE', 'Verified source evidence integrity is required')
64
+ check(receipt.semanticAcceptance === 'pending', 'SEMANTIC_EVIDENCE', 'Evidence semantic acceptance must remain pending')
65
+ check(receipt.synthesized === false, 'SEMANTIC_EVIDENCE', 'Unsynthesized source evidence is required')
66
+ check(string(receipt.ref, 16384) && typeof receipt.text === 'string', 'SEMANTIC_EVIDENCE', 'Located source evidence text is required')
67
+ for (const key of ['planId', 'planDigest', 'sourceId', 'sourceDigest', 'attemptId']) check(receipt[key] === { ...plan, ...reference }[key], 'SEMANTIC_BINDING', 'Evidence differs from its requested binding')
68
+ closed(receipt.locator, ['kind', 'value'], 'SEMANTIC_EVIDENCE')
69
+ check(ingestionDigest(receipt.locator) === ingestionDigest(reference.locator), 'SEMANTIC_BINDING', 'Evidence locator differs from its requested binding')
70
+ return receipt
71
+ }
72
+ function payload(input) { const { digest: ignored, ...value } = input; return value }
73
+
74
+ // The trusted host supplies a permitted all-plan reader and current domain.
75
+ // It invokes its chosen extractor separately, using the returned pinned input.
76
+ export function prepareSemanticInput({ store, plan, domain, references, identityCandidates = [] }) {
77
+ const selected = plain({ plan, references, identityCandidates }), definition = profile(domain)
78
+ closed(selected.plan, ['planId', 'planDigest'])
79
+ check(string(selected.plan.planId, 256) && /^sha256:[a-f0-9]{64}$/.test(selected.plan.planDigest), 'SEMANTIC_BINDING', 'A bound ingestion plan is required')
80
+ check(array(selected.references, 64), 'SEMANTIC_INVALID', 'Evidence references must be an array')
81
+ check(selected.references.length > 0, 'SEMANTIC_EVIDENCE', 'At least one evidence span is required')
82
+ check(array(selected.identityCandidates, 64), 'SEMANTIC_IDENTITY', 'Identity candidates must be an array')
83
+ const identities = new Set(), types = new Set(definition.data.vocabulary.types.map(t => t.id))
84
+ for (const candidate of selected.identityCandidates) {
85
+ closed(candidate, ['id', 'label', 'type'], 'SEMANTIC_IDENTITY')
86
+ check(identifier(candidate.id), 'SEMANTIC_IDENTITY', 'A valid supplied identity candidate identifier is required')
87
+ check(!identities.has(candidate.id), 'SEMANTIC_IDENTITY', 'Supplied identity candidate identifiers must be unique')
88
+ check(string(candidate.label), 'SEMANTIC_IDENTITY', 'A supplied identity candidate label is required')
89
+ check(types.has(candidate.type), 'SEMANTIC_IDENTITY', 'Supplied identity candidate types must fit the domain'); identities.add(candidate.id)
90
+ }
91
+ const seen = new Set(), evidence = []
92
+ let sourceId
93
+ for (const reference of selected.references) {
94
+ evidenceReference(reference)
95
+ sourceId ??= reference.sourceId
96
+ check(sourceId === reference.sourceId, 'SEMANTIC_SCOPE', 'The first semantic profile processes one source per input')
97
+ const key = ingestionDigest(reference)
98
+ check(!seen.has(key), 'SEMANTIC_EVIDENCE', 'Duplicate evidence references are refused'); seen.add(key)
99
+ evidence.push({ id: `span-${evidence.length + 1}`, reference, receipt: readEvidence(store, selected.plan, reference) })
100
+ }
101
+ const input = plain({ schema: INPUT_VERSION, plan: selected.plan, domain: definition, domainRef: harnessRef(definition), identityCandidates: selected.identityCandidates, evidence,
102
+ coverage: 'selected-spans-only', readScope: 'all-plan', authority: 'none' })
103
+ return { ...input, digest: ingestionDigest(input) }
104
+ }
105
+ function currentInput(store, value) {
106
+ const input = plain(value)
107
+ closed(input, ['schema', 'plan', 'domain', 'domainRef', 'identityCandidates', 'evidence', 'coverage', 'readScope', 'authority', 'digest'])
108
+ check(input.schema === INPUT_VERSION && input.authority === 'none' && input.coverage === 'selected-spans-only' && input.readScope === 'all-plan', 'SEMANTIC_BINDING', 'The pinned semantic input is required')
109
+ check(input.digest === ingestionDigest(payload(input)), 'SEMANTIC_BINDING', 'Semantic input digest differs')
110
+ check(array(input.evidence, 64) && input.evidence.length > 0, 'SEMANTIC_BINDING', 'A nonempty evidence array is required')
111
+ for (const span of input.evidence) closed(span, ['id', 'reference', 'receipt'])
112
+ const rebuilt = prepareSemanticInput({ store, plan: input.plan, domain: input.domain, references: input.evidence.map(e => e.reference), identityCandidates: input.identityCandidates })
113
+ check(rebuilt.digest === input.digest, 'SEMANTIC_BINDING', 'Current evidence or profile binding differs')
114
+ return rebuilt
115
+ }
116
+ function date(value) {
117
+ if (value === null) return true
118
+ if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(value)) return false
119
+ const parsed = new Date(`${value}T00:00:00Z`)
120
+ return Number.isFinite(parsed.getTime()) && parsed.toISOString().slice(0, 10) === value
121
+ }
122
+
123
+ export function prepareSemanticProposals({ store, input: original, candidates: supplied }) {
124
+ const candidates = plain(supplied), input = currentInput(store, original)
125
+ closed(candidates, ['schema', 'inputDigest', 'entities', 'assertions', 'unknowns'])
126
+ check(candidates.schema === SEMANTIC_CANDIDATE_VERSION && candidates.inputDigest === input.digest, 'SEMANTIC_BINDING', 'Candidates must bind the exact extractor input')
127
+ for (const key of ['entities', 'assertions', 'unknowns']) check(array(candidates[key], 64), 'SEMANTIC_INVALID', 'Semantic candidate collections must be arrays')
128
+ const ids = new Set(), entities = new Map(), spans = new Map(input.evidence.map(e => [e.id, e])), identityCandidates = new Map(input.identityCandidates.map(c => [c.id, c]))
129
+ const types = new Set(input.domain.data.vocabulary.types.map(t => t.id)), predicates = new Set(input.domain.data.vocabulary.relations.map(r => r.id))
130
+ function identity(id) { check(identifier(id) && !ids.has(id), 'SEMANTIC_IDENTITY', 'Unique source-local candidate identities are required'); ids.add(id) }
131
+ function supports(references, quoteRequired = false) {
132
+ check(array(references, 16) && references.length > 0, 'SEMANTIC_EVIDENCE', 'At least one bounded supporting span is required')
133
+ const seen = new Set()
134
+ return references.map(value => {
135
+ if (quoteRequired) closed(value, ['id', 'quote'], 'SEMANTIC_EVIDENCE')
136
+ const id = quoteRequired ? value.id : value, span = spans.get(id)
137
+ check(span && !seen.has(id), 'SEMANTIC_EVIDENCE', 'Supporting evidence must resolve uniquely'); seen.add(id)
138
+ const quote = quoteRequired ? value.quote : span.receipt.text
139
+ check(string(quote, 65536) && span.receipt.text.includes(quote), 'SEMANTIC_EVIDENCE', 'The quote must occur in the declared span')
140
+ return { id, ...span.reference, ref: span.receipt.ref, quote }
141
+ })
142
+ }
143
+ const preparedEntities = candidates.entities.map(entity => {
144
+ closed(entity, ['id', 'label', 'type', 'identity', 'evidence']); identity(entity.id)
145
+ check(types.has(entity.type) && string(entity.label), 'SEMANTIC_TYPE', 'Entity type and label must fit the supplied domain')
146
+ closed(entity.identity, ['status', 'candidateIds'], 'SEMANTIC_IDENTITY')
147
+ check(['source-local', 'existing-candidate', 'unknown'].includes(entity.identity.status) && array(entity.identity.candidateIds, 16), 'SEMANTIC_IDENTITY', 'Explicit candidate identity status is required')
148
+ const candidateIds = entity.identity.candidateIds
149
+ check(new Set(candidateIds).size === candidateIds.length, 'SEMANTIC_IDENTITY', 'Identity candidate mappings must be unique')
150
+ check(candidateIds.every(id => identityCandidates.has(id)), 'SEMANTIC_IDENTITY', 'Identity mappings must use supplied candidates')
151
+ check(candidateIds.every(id => !identityCandidates.has(id) || identityCandidates.get(id).type === entity.type), 'SEMANTIC_IDENTITY', 'Identity mappings must use matching candidate types')
152
+ check(entity.identity.status === 'existing-candidate' ? candidateIds.length > 0 : candidateIds.length === 0, 'SEMANTIC_IDENTITY', 'Identity status and candidates differ')
153
+ const prepared = { ...entity, evidence: supports(entity.evidence), identityAcceptance: 'pending' }
154
+ entities.set(entity.id, prepared); return prepared
155
+ })
156
+ const preparedAssertions = candidates.assertions.map(assertion => {
157
+ closed(assertion, ['id', 'subjectId', 'predicate', 'objectId', 'direction', 'negated', 'modality', 'scope', 'time', 'evidence']); identity(assertion.id)
158
+ check(entities.has(assertion.subjectId), 'SEMANTIC_IDENTITY', 'Assertion subject must resolve to a supplied entity')
159
+ check(assertion.objectId === null || entities.has(assertion.objectId), 'SEMANTIC_IDENTITY', 'Assertion object must resolve to a supplied entity')
160
+ check(predicates.has(assertion.predicate), 'SEMANTIC_PREDICATE', 'Unmodeled predicates must remain explicit findings')
161
+ check(assertion.direction === (assertion.objectId === null ? 'subject-only' : 'subject-to-object'), 'SEMANTIC_DIRECTION', 'Unary or directed binary roles must match the supplied endpoints')
162
+ check(typeof assertion.negated === 'boolean', 'SEMANTIC_NEGATION', 'Explicit Boolean negation is required')
163
+ check(modalities.has(assertion.modality), 'SEMANTIC_MODALITY', 'Explicit supported modality is required')
164
+ check(assertion.scope === input.domain.data.scope, 'SEMANTIC_SCOPE', 'Assertion scope differs from its supplied domain')
165
+ const evidence = supports(assertion.evidence, true), time = assertion.time
166
+ closed(time, ['from', 'until', 'expression', 'unknowns'], 'SEMANTIC_TIME')
167
+ check(date(time.from) && date(time.until) && (!time.from || !time.until || time.from <= time.until), 'SEMANTIC_TIME', 'Valid ordered calendar dates are required')
168
+ check((time.expression === null || string(time.expression)) && array(time.unknowns, 16) && time.unknowns.every(value => string(value)), 'SEMANTIC_TIME', 'Explicit bounded time qualifications are required')
169
+ check(time.expression === null || evidence.some(item => item.quote.includes(time.expression)), 'SEMANTIC_TIME', 'A temporal expression must be located in its cited passage')
170
+ check(time.expression === null || time.from !== null || time.until !== null || time.unknowns.length > 0, 'SEMANTIC_TIME', 'Unresolved temporal expressions must preserve their unknowns')
171
+ return { ...assertion, evidence, proposalAcceptance: 'pending' }
172
+ })
173
+ const unknowns = candidates.unknowns.map(unknown => {
174
+ closed(unknown, ['id', 'relatedCandidateId', 'reason', 'evidence'], 'SEMANTIC_UNKNOWN'); identity(unknown.id)
175
+ check(string(unknown.reason) && (unknown.relatedCandidateId === null || [...entities.keys(), ...preparedAssertions.map(a => a.id)].includes(unknown.relatedCandidateId)), 'SEMANTIC_UNKNOWN', 'An explicit finding reason and valid optional subject are required')
176
+ return { ...unknown, evidence: supports(unknown.evidence) }
177
+ })
178
+ return plain({ schema: PROPOSAL_VERSION, inputDigest: input.digest, domainRef: input.domainRef,
179
+ entities: preparedEntities, assertions: preparedAssertions, unknowns, rawCandidates: candidates,
180
+ counts: { entities: preparedEntities.length, assertions: preparedAssertions.length, abstentions: unknowns.length, refusals: 0 },
181
+ semanticAcceptance: 'pending', authority: 'none', canonicalMutation: false, coverage: input.coverage, readScope: input.readScope })
182
+ }
183
+
184
+ // A fresh, derived proposal view. Acceptance is still owned by knowledge review.
185
+ export function readSemanticProposals({ store, input, proposals: supplied, query, limit = 64 }) {
186
+ check(string(query, 512) && query.trim().length > 0, 'SEMANTIC_INVALID', 'A bounded nonempty query is required')
187
+ check(Number.isSafeInteger(limit), 'SEMANTIC_INVALID', 'The result limit must be a safe integer')
188
+ check(limit > 0 && limit <= 64, 'SEMANTIC_LIMIT', 'The result limit must be between one and 64')
189
+ const proposals = plain(supplied)
190
+ closed(proposals, ['schema', 'inputDigest', 'domainRef', 'entities', 'assertions', 'unknowns', 'rawCandidates', 'counts', 'semanticAcceptance', 'authority', 'canonicalMutation', 'coverage', 'readScope'])
191
+ const current = prepareSemanticProposals({ store, input, candidates: proposals.rawCandidates })
192
+ check(ingestionDigest(current) === ingestionDigest(proposals), 'SEMANTIC_BINDING', 'The proposal view differs from its validated candidates')
193
+ const byId = new Map(current.entities.map(entity => [entity.id, entity])), terms = query.toLowerCase().trim().split(/\s+/u)
194
+ const matched = current.assertions.filter(assertion => {
195
+ const subject = byId.get(assertion.subjectId), object = byId.get(assertion.objectId)
196
+ const description = [subject.id, subject.label, object?.id ?? '', object?.label ?? '', assertion.predicate,
197
+ ...assertion.evidence.map(item => item.quote), assertion.time.expression ?? ''].join('\n').toLowerCase()
198
+ return terms.every(term => description.includes(term))
199
+ })
200
+ return plain({ schema: 'atelier.semantic-proposal-view/v0', inputDigest: current.inputDigest, domainRef: current.domainRef, entities: current.entities,
201
+ assertions: matched.slice(0, limit), unknowns: current.unknowns, totalMatched: matched.length, omitted: Math.max(0, matched.length - limit),
202
+ counts: current.counts, coverage: current.coverage, readScope: current.readScope, semanticAcceptance: 'pending', synthesized: false, canonicalMutation: false, authority: 'none' })
203
+ }