@mnstry/atelier 0.2.0-alpha.1

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 (260) hide show
  1. package/CHANGELOG.md +383 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +5 -0
  4. package/README.md +262 -0
  5. package/SECURITY.md +93 -0
  6. package/TRADEMARKS.md +88 -0
  7. package/announcements/2026-08-06-announcements-channel.v1.json +12 -0
  8. package/announcements/keys/mnstry-announcements.public.v1.json +9 -0
  9. package/bin/atelier.mjs +2 -0
  10. package/bin/mnstry-atelier.mjs +3 -0
  11. package/contracts/analysis-adapter.v1.schema.json +248 -0
  12. package/contracts/atelier-action-intent.v1.schema.json +143 -0
  13. package/contracts/atelier-analysis-adapter.v1.schema.json +360 -0
  14. package/contracts/atelier-attestation.v1.schema.json +239 -0
  15. package/contracts/atelier-boundary-policy.v1.schema.json +339 -0
  16. package/contracts/atelier-claim.v1.schema.json +97 -0
  17. package/contracts/atelier-export.v1.schema.json +1015 -0
  18. package/contracts/atelier-extension-pack.v1.schema.json +290 -0
  19. package/contracts/atelier-kit-manifest.v1.schema.json +273 -0
  20. package/contracts/atelier-lock.v1.schema.json +364 -0
  21. package/contracts/atelier-migration.v1.schema.json +162 -0
  22. package/contracts/atelier-project-config.v1.schema.json +352 -0
  23. package/contracts/atelier-readiness-protocol.v1.schema.json +517 -0
  24. package/contracts/atelier-readiness-run.v1.schema.json +229 -0
  25. package/contracts/atelier-readiness.v1.schema.json +457 -0
  26. package/contracts/compat-baseline.json +10 -0
  27. package/contracts/git-promote-event.v1.schema.json +145 -0
  28. package/contracts/knowledge-source-sidecar.v1.schema.json +157 -0
  29. package/contracts/mnstry-atelier-semantic-profile.v1.json +254 -0
  30. package/docs/announcements.md +101 -0
  31. package/docs/atelier-runtime.md +34 -0
  32. package/docs/attestation.md +201 -0
  33. package/docs/continuity.md +55 -0
  34. package/docs/contract-stability.md +111 -0
  35. package/docs/distributions.md +220 -0
  36. package/docs/install.md +140 -0
  37. package/docs/knowledge-graph.md +140 -0
  38. package/docs/ontology.md +206 -0
  39. package/docs/release-engineering.md +151 -0
  40. package/docs/repo-boundary-guard.md +199 -0
  41. package/docs/tenant-readiness.md +64 -0
  42. package/docs/upgrade.md +124 -0
  43. package/fixtures/analysis/invalid/native-graph.v1.json +4 -0
  44. package/fixtures/analysis/invalid/promoted-claim.v1.json +17 -0
  45. package/fixtures/analysis/invalid/runtime-import.v1.json +20 -0
  46. package/fixtures/analysis/valid/output.claims.v1.json +17 -0
  47. package/fixtures/analysis-adapter/invalid/manifest-hidden-provider.v1.json +24 -0
  48. package/fixtures/analysis-adapter/invalid/output-frontmatter-mutation.v1.json +21 -0
  49. package/fixtures/analysis-adapter/invalid/output-native-graph.v1.json +14 -0
  50. package/fixtures/analysis-adapter/manifest.disabled.v1.json +22 -0
  51. package/fixtures/analysis-adapter/manifest.enabled-local.v1.json +23 -0
  52. package/fixtures/analysis-adapter/output.claims.v1.json +21 -0
  53. package/fixtures/atelier-action-intent/invalid/runtime-mutation-authority.v1.json +16 -0
  54. package/fixtures/atelier-action-intent/invalid/unknown-top-level-field.v1.json +17 -0
  55. package/fixtures/atelier-action-intent/invalid/writes-beyond-clipboard.v1.json +16 -0
  56. package/fixtures/atelier-action-intent/valid/copy-agent-prompt.v1.json +16 -0
  57. package/fixtures/atelier-action-intent/valid/copy-repo-path.v1.json +22 -0
  58. package/fixtures/atelier-analysis-adapter/invalid/hidden-model-provider.v1.json +24 -0
  59. package/fixtures/atelier-analysis-adapter/invalid/inert-with-execute-command.v1.json +24 -0
  60. package/fixtures/atelier-analysis-adapter/invalid/proposals-with-runtime-import.v1.json +30 -0
  61. package/fixtures/atelier-analysis-adapter/valid/manifest-inert.v1.json +24 -0
  62. package/fixtures/atelier-analysis-adapter/valid/proposals-claim-only.v1.json +27 -0
  63. package/fixtures/atelier-attestation/invalid/bad-digest.v1.json +23 -0
  64. package/fixtures/atelier-attestation/invalid/conformance-scope.v1.json +23 -0
  65. package/fixtures/atelier-attestation/invalid/missing-signature.v1.json +22 -0
  66. package/fixtures/atelier-attestation/invalid/unknown-root-field.v1.json +24 -0
  67. package/fixtures/atelier-attestation/keys/roundtrip-issuer.public.v1.json +9 -0
  68. package/fixtures/atelier-attestation/valid/rejected-with-reasons.v1.json +49 -0
  69. package/fixtures/atelier-attestation/valid/signed-admitted.v1.json +35 -0
  70. package/fixtures/atelier-attestation/valid/signed-roundtrip.v1.json +29 -0
  71. package/fixtures/atelier-attestation/valid/unsigned-advisory.v1.json +23 -0
  72. package/fixtures/atelier-claim/invalid/unknown-provider.v1.json +15 -0
  73. package/fixtures/atelier-claim/invalid/unknown-top-level-field.v1.json +16 -0
  74. package/fixtures/atelier-claim/invalid/wrong-schema-const.v1.json +15 -0
  75. package/fixtures/atelier-claim/valid/adapter-style-proposed-relation.v1.json +19 -0
  76. package/fixtures/atelier-claim/valid/codex-proposed-relation.v1.json +16 -0
  77. package/fixtures/atelier-claim/valid/manual-proposed-relation.v1.json +16 -0
  78. package/fixtures/atelier-claim/valid/readiness-proposed-relation.v1.json +18 -0
  79. package/fixtures/atelier-export/invalid/dirty-unforced-empty-taint.v1.json +19 -0
  80. package/fixtures/atelier-export/invalid/object-local-audience-visibility.v1.json +11 -0
  81. package/fixtures/atelier-export/invalid/open-object-class-owner.v1.json +23 -0
  82. package/fixtures/atelier-export/invalid/pricing-legacy-amount.v1.json +23 -0
  83. package/fixtures/atelier-export/invalid/public-disguised-internal-source-ref.v1.json +11 -0
  84. package/fixtures/atelier-export/invalid/public-nested-private-source-ref.v1.json +17 -0
  85. package/fixtures/atelier-export/invalid/public-resolved-private-source-ref.v1.json +13 -0
  86. package/fixtures/atelier-export/invalid/public-resolved-sensitive-source-ref.v1.json +13 -0
  87. package/fixtures/atelier-export/invalid/public-source-ref-missing-provenance.v1.json +20 -0
  88. package/fixtures/atelier-export/invalid/public-source-team-kg.json +12 -0
  89. package/fixtures/atelier-export/invalid/source-node-legacy-visibility.v1.json +21 -0
  90. package/fixtures/atelier-export/invalid/source-node-unknown-field.v1.json +18 -0
  91. package/fixtures/atelier-export/invalid/unresolved-public-source-ref.v1.json +11 -0
  92. package/fixtures/atelier-export/sample-studio-offer.v1.json +397 -0
  93. package/fixtures/atelier-extension-pack/invalid/bundled-slug-collision.v1.json +22 -0
  94. package/fixtures/atelier-extension-pack/invalid/escapes-root.v1.json +22 -0
  95. package/fixtures/atelier-extension-pack/invalid/posture-tampered.v1.json +22 -0
  96. package/fixtures/atelier-extension-pack/invalid/protocols/autonomous-authority.v1.json +118 -0
  97. package/fixtures/atelier-extension-pack/invalid/protocols/offer-map.v1.json +109 -0
  98. package/fixtures/atelier-extension-pack/invalid/redefines-runtime-term.v1.json +19 -0
  99. package/fixtures/atelier-extension-pack/invalid/wrong-namespace.v1.json +19 -0
  100. package/fixtures/atelier-extension-pack/valid/protocols/contract-gate.v1.json +109 -0
  101. package/fixtures/atelier-extension-pack/valid/sample-pack.v1.json +48 -0
  102. package/fixtures/atelier-kit-manifest/invalid/runtime-copy-without-canonical-role.v1.json +53 -0
  103. package/fixtures/atelier-kit-manifest/invalid/telemetry-send-path.v1.json +21 -0
  104. package/fixtures/atelier-kit-manifest/valid/mnstry-atelier.valid.v1.json +76 -0
  105. package/fixtures/atelier-lock/invalid/absolute-contract-path.v1.json +40 -0
  106. package/fixtures/atelier-lock/invalid/runtime-mutation-enabled.v1.json +41 -0
  107. package/fixtures/atelier-lock/invalid/unknown-top-level-field.v1.json +42 -0
  108. package/fixtures/atelier-lock/valid/extension-pack.v1.json +55 -0
  109. package/fixtures/atelier-lock/valid/minimal.v1.json +44 -0
  110. package/fixtures/atelier-migration/invalid/live-apply-mode.v1.json +21 -0
  111. package/fixtures/atelier-migration/invalid/missing-review-evidence.v1.json +20 -0
  112. package/fixtures/atelier-migration/invalid/runtime-mutation-enabled.v1.json +21 -0
  113. package/fixtures/atelier-migration/valid/minimal.v1.json +32 -0
  114. package/fixtures/atelier-project-config/invalid/absolute-repo-path.v1.json +11 -0
  115. package/fixtures/atelier-project-config/invalid/ext-not-object.v1.json +12 -0
  116. package/fixtures/atelier-project-config/invalid/external-kind-read-boundary.v1.json +12 -0
  117. package/fixtures/atelier-project-config/invalid/missing-repos-and-alignment.v1.json +7 -0
  118. package/fixtures/atelier-project-config/invalid/unknown-top-level-field.v1.json +14 -0
  119. package/fixtures/atelier-project-config/valid/alignment-scaffold.v1.json +15 -0
  120. package/fixtures/atelier-project-config/valid/ext-extension-packs.v1.json +36 -0
  121. package/fixtures/atelier-project-config/valid/repo-workspace.v1.json +23 -0
  122. package/fixtures/atelier-project-config/validator-only/ext-member-not-object.v1.json +14 -0
  123. package/fixtures/atelier-readiness/invalid/dry-run-only-false.v1.json +87 -0
  124. package/fixtures/atelier-readiness/invalid/support-bundle-send-path.v1.json +87 -0
  125. package/fixtures/atelier-readiness/invalid/unknown-top-level-field.v1.json +88 -0
  126. package/fixtures/atelier-readiness/valid/ready-workspace.v1.json +84 -0
  127. package/fixtures/boundary-policy/invalid/content-rule-exception-blanket-path.v1.json +67 -0
  128. package/fixtures/boundary-policy/invalid/invalid-actor-private-repo-mapping.v1.json +20 -0
  129. package/fixtures/boundary-policy/invalid/legacy-warning-missing-warning.v1.json +20 -0
  130. package/fixtures/boundary-policy/invalid/missing-repo-coverage.v1.json +19 -0
  131. package/fixtures/boundary-policy/invalid/unknown-key.v1.json +12 -0
  132. package/fixtures/boundary-policy/valid/content-rule-exception.v1.json +67 -0
  133. package/fixtures/boundary-policy/valid/legacy-warning.v1.json +33 -0
  134. package/fixtures/boundary-policy/valid/strict-private-shared.v1.json +40 -0
  135. package/fixtures/git-promote/invalid/provision-named-revocable.v1.json +29 -0
  136. package/fixtures/git-promote/private-to-team.v1.json +29 -0
  137. package/fixtures/knowledge-source-sidecar/invalid/legacy-visibility-field.v1.json +17 -0
  138. package/fixtures/knowledge-source-sidecar/invalid/missing-audience.v1.json +15 -0
  139. package/fixtures/knowledge-source-sidecar/invalid/unknown-relation-kind.v1.json +18 -0
  140. package/fixtures/knowledge-source-sidecar/valid/html-source.v1.json +18 -0
  141. package/fixtures/knowledge-source-sidecar/valid/pdf-evidence.v1.json +18 -0
  142. package/fixtures/projects/neutral-project/atelier.project.json +15 -0
  143. package/fixtures/projects/neutral-project/ops/config/repo-access.v1.json +12 -0
  144. package/fixtures/projects/neutral-project/project-knowledge.graph.json +69 -0
  145. package/fixtures/projects/sample-workspace/atelier.project.json +23 -0
  146. package/fixtures/projects/sample-workspace/boundary-policy.v1.json +59 -0
  147. package/fixtures/projects/sample-workspace/content/README.md +16 -0
  148. package/fixtures/projects/sample-workspace/content/source.html +5 -0
  149. package/fixtures/projects/sample-workspace/content/source.html.kg.json +15 -0
  150. package/fixtures/projects/sample-workspace/repo-access.v1.json +9 -0
  151. package/fixtures/projects/source-formats-workspace/atelier.project.json +23 -0
  152. package/fixtures/projects/source-formats-workspace/content/README.md +17 -0
  153. package/fixtures/projects/source-formats-workspace/content/data.json +7 -0
  154. package/fixtures/projects/source-formats-workspace/content/data.json.kg.json +15 -0
  155. package/fixtures/projects/source-formats-workspace/content/logo.png.kg.json +15 -0
  156. package/fixtures/projects/source-formats-workspace/content/metrics.csv +3 -0
  157. package/fixtures/projects/source-formats-workspace/content/metrics.csv.kg.json +15 -0
  158. package/fixtures/projects/source-formats-workspace/content/pipeline.yaml +4 -0
  159. package/fixtures/projects/source-formats-workspace/content/pipeline.yaml.kg.json +15 -0
  160. package/fixtures/projects/source-formats-workspace/repo-access.v1.json +9 -0
  161. package/fixtures/readiness-protocols/extension-pack/invalid/protocol-missing-path.v1.json +20 -0
  162. package/fixtures/readiness-protocols/extension-pack/valid/with-protocol.v1.json +24 -0
  163. package/fixtures/readiness-protocols/protocol/invalid/missing-check-target.v1.json +103 -0
  164. package/fixtures/readiness-protocols/protocol/invalid/runtime-mutation-enabled.v1.json +107 -0
  165. package/fixtures/readiness-protocols/protocol/valid/minimal.v1.json +100 -0
  166. package/fixtures/readiness-protocols/run/invalid/missing-evidence.v1.json +37 -0
  167. package/fixtures/readiness-protocols/run/invalid/pass-with-blocker.v1.json +22 -0
  168. package/fixtures/readiness-protocols/run/invalid/runtime-mutation-enabled.v1.json +22 -0
  169. package/fixtures/readiness-protocols/run/valid/pass.v1.json +44 -0
  170. package/fixtures/support/invalid/leaky-support.v1.json +13 -0
  171. package/fixtures/support/valid/minimal-safe.v1.json +20 -0
  172. package/package.json +98 -0
  173. package/skills/claude/atelier-open/SKILL.md +68 -0
  174. package/skills/claude/mnstry-readiness/SKILL.md +41 -0
  175. package/skills/codex/atelier-open/SKILL.md +68 -0
  176. package/skills/codex/mnstry-readiness/SKILL.md +41 -0
  177. package/src/analysis/adapter.mjs +20 -0
  178. package/src/analysis/analysis-claim-contract.mjs +335 -0
  179. package/src/attestation/jcs.mjs +64 -0
  180. package/src/attestation/sign.mjs +305 -0
  181. package/src/boundary/content-rules.mjs +262 -0
  182. package/src/boundary/policy.mjs +806 -0
  183. package/src/check-atelier-export-contract.mjs +116 -0
  184. package/src/cli/run.mjs +283 -0
  185. package/src/collaboration/proposals.mjs +262 -0
  186. package/src/commands/analysis.mjs +8 -0
  187. package/src/commands/announcements.mjs +308 -0
  188. package/src/commands/attestation.mjs +198 -0
  189. package/src/commands/boundary.mjs +25 -0
  190. package/src/commands/config.mjs +4 -0
  191. package/src/commands/context.mjs +3 -0
  192. package/src/commands/distribution.mjs +224 -0
  193. package/src/commands/egress.mjs +11 -0
  194. package/src/commands/extension-pack.mjs +209 -0
  195. package/src/commands/feedback.mjs +3 -0
  196. package/src/commands/graph.mjs +3 -0
  197. package/src/commands/init.mjs +130 -0
  198. package/src/commands/lock.mjs +3 -0
  199. package/src/commands/project.mjs +3 -0
  200. package/src/commands/promote.mjs +4 -0
  201. package/src/commands/readiness.mjs +3 -0
  202. package/src/commands/server.mjs +6 -0
  203. package/src/commands/setup.mjs +250 -0
  204. package/src/commands/support.mjs +3 -0
  205. package/src/commands/upgrade.mjs +3 -0
  206. package/src/contracts/corpus.mjs +171 -0
  207. package/src/egress/check.mjs +45 -0
  208. package/src/egress/forbidden-egress.mjs +323 -0
  209. package/src/export/atelier-export-contract.mjs +722 -0
  210. package/src/extension-packs/loader.mjs +491 -0
  211. package/src/graph/graph.mjs +370 -0
  212. package/src/graph/knowledge-graph.mjs +887 -0
  213. package/src/harness/context-client.mjs +144 -0
  214. package/src/harness/context.mjs +27 -0
  215. package/src/index.mjs +88 -0
  216. package/src/project/config.mjs +557 -0
  217. package/src/project/file-class.mjs +113 -0
  218. package/src/project/git-ignore.mjs +31 -0
  219. package/src/project/path-match.mjs +30 -0
  220. package/src/project/repo-identity.mjs +176 -0
  221. package/src/projection/alignment-projection.mjs +169 -0
  222. package/src/projection/policy.mjs +90 -0
  223. package/src/projection/project.mjs +152 -0
  224. package/src/readiness/readiness.mjs +312 -0
  225. package/src/readiness-protocols/bundled-pack.mjs +766 -0
  226. package/src/readiness-protocols/runtime.mjs +419 -0
  227. package/src/server/local-sidecar.mjs +640 -0
  228. package/src/server/security.mjs +229 -0
  229. package/src/server/server.mjs +42 -0
  230. package/src/support/feedback-report.mjs +414 -0
  231. package/src/support/support-bundle.mjs +226 -0
  232. package/src/ui/html-primitives.mjs +104 -0
  233. package/src/upgrade/upgrade.mjs +701 -0
  234. package/src/validate-atelier-export-dry-run.mjs +75 -0
  235. package/templates/atelier.project.example.json +23 -0
  236. package/templates/distribution-workspace/.claude/launch.json +12 -0
  237. package/templates/distribution-workspace/README.md +86 -0
  238. package/templates/distribution-workspace/atelier.project.json +36 -0
  239. package/templates/distribution-workspace/boundary-policy.v1.json +61 -0
  240. package/templates/distribution-workspace/gitignore +29 -0
  241. package/templates/distribution-workspace/governance/repo-boundary-ledger.md +5 -0
  242. package/templates/distribution-workspace/project/README.md +19 -0
  243. package/templates/distribution-workspace/repo-access.v1.json +9 -0
  244. package/templates/launch.json +12 -0
  245. package/templates/private-domain-workspace/.claude/launch.json +12 -0
  246. package/templates/private-domain-workspace/README.md +50 -0
  247. package/templates/private-domain-workspace/atelier.project.json +28 -0
  248. package/templates/private-domain-workspace/boundary-policy.v1.json +54 -0
  249. package/templates/private-domain-workspace/domain/README.md +19 -0
  250. package/templates/private-domain-workspace/gitignore +29 -0
  251. package/templates/private-domain-workspace/governance/repo-boundary-ledger.md +4 -0
  252. package/templates/private-domain-workspace/repo-access.v1.json +9 -0
  253. package/templates/shared-project-workspace/.claude/launch.json +12 -0
  254. package/templates/shared-project-workspace/README.md +51 -0
  255. package/templates/shared-project-workspace/atelier.project.json +28 -0
  256. package/templates/shared-project-workspace/boundary-policy.v1.json +61 -0
  257. package/templates/shared-project-workspace/gitignore +29 -0
  258. package/templates/shared-project-workspace/governance/repo-boundary-ledger.md +5 -0
  259. package/templates/shared-project-workspace/project/README.md +19 -0
  260. package/templates/shared-project-workspace/repo-access.v1.json +9 -0
@@ -0,0 +1,766 @@
1
+ export const MNSTRY_READINESS_PACK_SCHEMA = 'mnstry-readiness-pack@v1'
2
+ export const READINESS_PROTOCOL_SCHEMA = 'atelier-readiness-protocol@v1'
3
+ export const READINESS_RUN_SCHEMA = 'atelier-readiness-run@v1'
4
+
5
+ export const READINESS_PROTOCOL_SLUGS = [
6
+ 'identity-map',
7
+ 'transformation-map',
8
+ 'offer-map',
9
+ 'space-design',
10
+ 'trackables',
11
+ 'consent-boundaries',
12
+ 'content-inventory',
13
+ 'discovery-engine',
14
+ 'journey-map',
15
+ 'operations-readiness',
16
+ 'runtime-readiness',
17
+ 'tenant-packet',
18
+ ]
19
+
20
+ export const READINESS_PROTOCOL_IDS = READINESS_PROTOCOL_SLUGS.map((slug) => `mnstry.readiness:${slug}`)
21
+
22
+ const baseSafetyPosture = {
23
+ runtimeMutation: false,
24
+ externalEgress: false,
25
+ defaultVisibility: 'private',
26
+ authority: 'proposal-only',
27
+ reviewMode: 'static-inspection',
28
+ failClosedOnMissingEvidence: true,
29
+ }
30
+
31
+ function safetyPosture(overrides = {}) {
32
+ return {
33
+ ...baseSafetyPosture,
34
+ ...overrides,
35
+ refuses: [
36
+ 'runtime writes',
37
+ 'identity inference without source evidence',
38
+ 'visibility expansion without explicit review',
39
+ ...(overrides.refuses ?? []),
40
+ ],
41
+ }
42
+ }
43
+
44
+ function namespacedProtocolId(slug) {
45
+ return slug.includes(':') ? slug : `mnstry.readiness:${slug}`
46
+ }
47
+
48
+ function outputSlug(slug, id) {
49
+ return id
50
+ .replace(`${slug}.`, '')
51
+ .replace(/[^a-z0-9:-]+/g, '-')
52
+ .replace(/^-+|-+$/g, '')
53
+ }
54
+
55
+ function namespacedTerm(protocolId, value) {
56
+ if (String(value).includes(':')) return value
57
+ return `${protocolId}.${String(value).split('.').pop()}`
58
+ }
59
+
60
+ function sourceTerm(protocolId, mapping) {
61
+ if (mapping.sourceTerm) return mapping.sourceTerm
62
+ const clean = String(mapping.sourceField || 'source')
63
+ .replace(/\[\]/g, '')
64
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
65
+ .toLowerCase()
66
+ .replace(/[^a-z0-9._-]+/gi, '-')
67
+ .replace(/^-+|-+$/g, '')
68
+ return `${protocolId}.${clean || 'source'}`
69
+ }
70
+
71
+ function protocol({
72
+ id,
73
+ stage = 'formation',
74
+ title,
75
+ purpose,
76
+ questions,
77
+ inputFields,
78
+ outputHints,
79
+ readinessRules,
80
+ claimMappings,
81
+ exportMappings,
82
+ safety,
83
+ }) {
84
+ const slug = id.includes(':') ? id.split(':').at(-1) : id
85
+ const protocolId = namespacedProtocolId(id)
86
+ const normalizedQuestions = questions.map((question) => ({
87
+ required: true,
88
+ ...question,
89
+ }))
90
+ const normalizedReadinessRules = readinessRules.map((rule) => ({
91
+ ...rule,
92
+ id: namespacedTerm(protocolId, rule.id),
93
+ }))
94
+ const normalizedClaimMappings = claimMappings.map((mapping) => ({
95
+ ...mapping,
96
+ id: namespacedTerm(protocolId, mapping.id),
97
+ }))
98
+ const normalizedExportMappings = exportMappings.map((mapping) => ({
99
+ ...mapping,
100
+ id: namespacedTerm(protocolId, mapping.id),
101
+ sourceTerm: sourceTerm(protocolId, mapping),
102
+ }))
103
+ const safetySummary = safetyPosture(safety)
104
+
105
+ return {
106
+ schema: READINESS_PROTOCOL_SCHEMA,
107
+ contractVersion: '1.0.0',
108
+ id: protocolId,
109
+ slug,
110
+ version: 'v1',
111
+ stage,
112
+ title,
113
+ purpose,
114
+ questions: normalizedQuestions,
115
+ inputFields,
116
+ outputHints,
117
+ outputs: {
118
+ runSchema: READINESS_RUN_SCHEMA,
119
+ artifacts: outputHints.map((hint) => ({
120
+ id: `${protocolId}.${outputSlug(slug, hint.id)}`,
121
+ kind: 'draft',
122
+ schema: hint.schema || 'atelier-readiness-run@v1',
123
+ description: hint.text,
124
+ })),
125
+ },
126
+ readinessRules: normalizedReadinessRules,
127
+ claimMappings: normalizedClaimMappings,
128
+ graphLenses: [{
129
+ id: `${protocolId}.lens`,
130
+ title: `${title} Lens`,
131
+ query: {
132
+ protocolId,
133
+ claimProvider: 'atelier-readiness',
134
+ },
135
+ }],
136
+ exportMappings: normalizedExportMappings,
137
+ safety: {
138
+ runtimeMutation: false,
139
+ runtimeImport: false,
140
+ canonicalWrites: false,
141
+ claimOnly: true,
142
+ telemetry: false,
143
+ egress: false,
144
+ sendPath: false,
145
+ browserApply: false,
146
+ dryRunOnly: true,
147
+ },
148
+ safetyPosture: safetySummary,
149
+ ui: {
150
+ section: 'readiness-journey',
151
+ title,
152
+ description: purpose,
153
+ agentPrompt: `Run atelier readiness run ${protocolId} --project ./atelier.project.json.`,
154
+ },
155
+ }
156
+ }
157
+
158
+ export const bundledReadinessProtocols = [
159
+ protocol({
160
+ id: 'identity-map',
161
+ title: 'Identity Map',
162
+ purpose: 'Resolve the participant, facilitator, operator, organization, and system roles that a readiness packet must describe.',
163
+ questions: [
164
+ {
165
+ id: 'identity-map.roles',
166
+ prompt: 'Which roles must be represented before this packet can be reviewed?',
167
+ inputFields: ['actors[].role', 'actors[].displayName', 'actors[].sourceRef'],
168
+ },
169
+ {
170
+ id: 'identity-map.ownership',
171
+ prompt: 'Which runtime owner would be responsible for each identity or role if promoted later?',
172
+ inputFields: ['actors[].runtimeOwner', 'actors[].ownerRationale'],
173
+ },
174
+ {
175
+ id: 'identity-map.ambiguity',
176
+ prompt: 'Which aliases, duplicate records, or unknown owners need human review?',
177
+ inputFields: ['identityQuestions[].subject', 'identityQuestions[].reason'],
178
+ },
179
+ ],
180
+ inputFields: [
181
+ { id: 'actors[].localId', type: 'string', required: true, description: 'Packet-local stable id for the role or actor.' },
182
+ { id: 'actors[].role', type: 'enum', required: true, values: ['participant', 'facilitator', 'operator', 'organization', 'system'], description: 'Neutral role category.' },
183
+ { id: 'actors[].runtimeOwner', type: 'enum', required: true, values: ['identity', 'providers', 'audit'], description: 'Runtime owner proposed for later review.' },
184
+ { id: 'identityQuestions[]', type: 'array', required: false, description: 'Open identity questions that block confident promotion.' },
185
+ ],
186
+ outputHints: [
187
+ { id: 'identity-map.table', text: 'Render a role table with local ids, source evidence, owner, and review state.' },
188
+ { id: 'identity-map.unresolved', text: 'Group unresolved aliases and duplicate candidates separately from confirmed identities.' },
189
+ ],
190
+ readinessRules: [
191
+ { id: 'identity-map.required-role-evidence', severity: 'blocker', condition: 'Every actor has a sourceRef and runtimeOwner.', remediation: 'Add source evidence or flag the actor unresolved.', failClosed: true },
192
+ { id: 'identity-map.no-contact-authority', severity: 'warning', condition: 'Contact details are not treated as authority for identity merge decisions.', remediation: 'Use reviewed source refs instead of direct-contact fields.', failClosed: true },
193
+ ],
194
+ claimMappings: [
195
+ { id: 'identity-map.actor-belongs-to-role', claimPredicate: 'belongs_to', sourceFields: ['actors[].localId', 'actors[].role'], target: 'atelier-claim@v1', evidence: 'actors[].sourceRef' },
196
+ { id: 'identity-map.alias-supports-actor', claimPredicate: 'supports', sourceFields: ['identityQuestions[].subject'], target: 'atelier-claim@v1', evidence: 'identityQuestions[].reason' },
197
+ ],
198
+ exportMappings: [
199
+ { id: 'identity-map.actor-artifact', sourceField: 'actors[]', target: 'core.artifact', runtimeOwner: 'identity', targetCollection: 'staffPrep' },
200
+ { id: 'identity-map.review-trackable', sourceField: 'identityQuestions[]', target: 'core.trackable', runtimeOwner: 'audit', targetCollection: 'trackables' },
201
+ ],
202
+ safety: {
203
+ reviewFocus: 'Verify that identity records remain role-based and evidence-backed until a runtime owner reviews them.',
204
+ },
205
+ }),
206
+ protocol({
207
+ id: 'transformation-map',
208
+ title: 'Transformation Map',
209
+ purpose: 'Describe the before, after, mechanisms, evidence, and limits of the change a project claims to support.',
210
+ questions: [
211
+ {
212
+ id: 'transformation-map.before-after',
213
+ prompt: 'What observable state is expected before and after the experience?',
214
+ inputFields: ['states.before', 'states.after', 'states.evidenceRef'],
215
+ },
216
+ {
217
+ id: 'transformation-map.mechanisms',
218
+ prompt: 'Which mechanisms are claimed to support the transformation?',
219
+ inputFields: ['mechanisms[].name', 'mechanisms[].sourceRef', 'mechanisms[].confidence'],
220
+ },
221
+ {
222
+ id: 'transformation-map.limits',
223
+ prompt: 'What outcomes are explicitly out of scope?',
224
+ inputFields: ['limits[].statement', 'limits[].reason'],
225
+ },
226
+ ],
227
+ inputFields: [
228
+ { id: 'states.before', type: 'text', required: true, description: 'Plain-language starting condition.' },
229
+ { id: 'states.after', type: 'text', required: true, description: 'Plain-language intended condition.' },
230
+ { id: 'mechanisms[].confidence', type: 'number', required: true, description: '0 to 1 proposal confidence for each mechanism.' },
231
+ { id: 'limits[]', type: 'array', required: true, description: 'Out-of-scope promises or unsupported claims.' },
232
+ ],
233
+ outputHints: [
234
+ { id: 'transformation-map.delta', text: 'Render a before-to-after delta with mechanisms and source evidence beside each claim.' },
235
+ { id: 'transformation-map.limits', text: 'Show limits as first-class packet content, not footnotes.' },
236
+ ],
237
+ readinessRules: [
238
+ { id: 'transformation-map.evidence-per-mechanism', severity: 'blocker', condition: 'Every mechanism has source evidence and confidence.', remediation: 'Attach evidence or remove the mechanism.', failClosed: true },
239
+ { id: 'transformation-map.limits-present', severity: 'warning', condition: 'At least one explicit limit or non-goal is recorded.', remediation: 'Add limits before external review.', failClosed: false },
240
+ ],
241
+ claimMappings: [
242
+ { id: 'transformation-map.mechanism-supports-outcome', claimPredicate: 'supports', sourceFields: ['mechanisms[].name', 'states.after'], target: 'atelier-claim@v1', evidence: 'mechanisms[].sourceRef' },
243
+ { id: 'transformation-map.limit-contradicts-overclaim', claimPredicate: 'contradicts', sourceFields: ['limits[].statement'], target: 'atelier-claim@v1', evidence: 'limits[].reason' },
244
+ ],
245
+ exportMappings: [
246
+ { id: 'transformation-map.material', sourceField: 'states', target: 'content.material', runtimeOwner: 'projection', targetCollection: 'surfaces' },
247
+ { id: 'transformation-map.outcome-trackable', sourceField: 'mechanisms[]', target: 'core.trackable', runtimeOwner: 'events', targetCollection: 'trackables' },
248
+ ],
249
+ safety: {
250
+ refuses: ['unsupported therapeutic or financial outcome claims'],
251
+ reviewFocus: 'Verify that outcome claims are framed as source-backed proposals with visible limits.',
252
+ },
253
+ }),
254
+ protocol({
255
+ id: 'offer-map',
256
+ title: 'Offer Map',
257
+ purpose: 'Convert service, product, session, or program ideas into reviewable offer components without creating an active sale path.',
258
+ questions: [
259
+ {
260
+ id: 'offer-map.promise',
261
+ prompt: 'What is being offered, to whom, and under what constraints?',
262
+ inputFields: ['offer.name', 'offer.audience', 'offer.constraints[]'],
263
+ },
264
+ {
265
+ id: 'offer-map.commitment',
266
+ prompt: 'What commitment path would a participant enter if this offer later became active?',
267
+ inputFields: ['commitmentPath.steps[]', 'commitmentPath.exitOptions[]'],
268
+ },
269
+ {
270
+ id: 'offer-map.status',
271
+ prompt: 'Which parts are approved, draft, blocked, or need review?',
272
+ inputFields: ['offer.components[].approvalStatus', 'offer.blockers[]'],
273
+ },
274
+ ],
275
+ inputFields: [
276
+ { id: 'offer.name', type: 'string', required: true, description: 'Neutral offer name.' },
277
+ { id: 'offer.audience', type: 'enum', required: true, values: ['public', 'team', 'operator', 'staff', 'private', 'sensitive'], description: 'Local source audience.' },
278
+ { id: 'commitmentPath.steps[]', type: 'array', required: true, description: 'Reviewable sequence before any booking or purchase path exists.' },
279
+ { id: 'offer.components[].approvalStatus', type: 'enum', required: true, values: ['approved', 'draft', 'blocked', 'needs-review'], description: 'Approval state for each offer component.' },
280
+ ],
281
+ outputHints: [
282
+ { id: 'offer-map.summary', text: 'Render the offer as promise, eligibility, commitment path, constraints, and approval status.' },
283
+ { id: 'offer-map.blockers', text: 'Keep draft or blocked components visible in a remediation section.' },
284
+ ],
285
+ readinessRules: [
286
+ { id: 'offer-map.no-active-commerce', severity: 'blocker', condition: 'The pack does not include active payment, booking, or send paths.', remediation: 'Remove active runtime actions and keep only dry-run mappings.', failClosed: true },
287
+ { id: 'offer-map.approval-known', severity: 'blocker', condition: 'Every offer component has an approvalStatus.', remediation: 'Set each component approved, draft, blocked, or needs-review.', failClosed: true },
288
+ ],
289
+ claimMappings: [
290
+ { id: 'offer-map-offer-implements-promise', claimPredicate: 'implements', sourceFields: ['offer.name', 'offer.promise'], target: 'atelier-claim@v1', evidence: 'offer.sourceRef' },
291
+ { id: 'offer-map-step-depends-on-previous', claimPredicate: 'depends_on', sourceFields: ['commitmentPath.steps[]'], target: 'atelier-claim@v1', evidence: 'commitmentPath.sourceRef' },
292
+ ],
293
+ exportMappings: [
294
+ { id: 'offer-map.offer', sourceField: 'offer', target: 'content.material', runtimeOwner: 'catalog', targetCollection: 'offers' },
295
+ { id: 'offer-map.commitment-path', sourceField: 'commitmentPath', target: 'scheduling.commitment', runtimeOwner: 'commitments', targetCollection: 'commitmentPaths' },
296
+ ],
297
+ safety: {
298
+ refuses: ['active booking flow', 'active payment flow'],
299
+ reviewFocus: 'Verify that the offer is reviewable content and dry-run mapping only.',
300
+ },
301
+ }),
302
+ protocol({
303
+ id: 'space-design',
304
+ title: 'Space Design',
305
+ purpose: 'Describe physical, virtual, or hybrid spaces as reviewable requirements before any provisioning is requested.',
306
+ questions: [
307
+ {
308
+ id: 'space-design.purpose',
309
+ prompt: 'What purpose does the space serve and which offer or journey stage depends on it?',
310
+ inputFields: ['space.purpose', 'space.relatedProtocolIds[]', 'space.sourceRef'],
311
+ },
312
+ {
313
+ id: 'space-design.constraints',
314
+ prompt: 'What capacity, access, accessibility, privacy, or equipment constraints apply?',
315
+ inputFields: ['space.constraints[]', 'space.accessModel', 'space.accessibilityNotes'],
316
+ },
317
+ {
318
+ id: 'space-design.provisioning',
319
+ prompt: 'What must be provisioned, reviewed, or refused before use?',
320
+ inputFields: ['provisioning.needs[]', 'provisioning.blockers[]'],
321
+ },
322
+ ],
323
+ inputFields: [
324
+ { id: 'space.name', type: 'string', required: true, description: 'Neutral space label.' },
325
+ { id: 'space.accessModel', type: 'enum', required: true, values: ['open', 'invited', 'staffed', 'private-review'], description: 'How access would be controlled after review.' },
326
+ { id: 'space.constraints[]', type: 'array', required: true, description: 'Capacity, accessibility, privacy, or equipment constraints.' },
327
+ { id: 'provisioning.needs[]', type: 'array', required: false, description: 'Provisioning needs that remain inactive in the bundled pack.' },
328
+ ],
329
+ outputHints: [
330
+ { id: 'space-design.matrix', text: 'Render space purpose, access model, constraints, dependencies, and provisioning status together.' },
331
+ { id: 'space-design.refusal', text: 'Call out any constraints that would prevent safe provisioning.' },
332
+ ],
333
+ readinessRules: [
334
+ { id: 'space-design.constraints-recorded', severity: 'blocker', condition: 'Space constraints are present before export mapping.', remediation: 'Add constraints or flag the space blocked.', failClosed: true },
335
+ { id: 'space-design.no-auto-provision', severity: 'blocker', condition: 'Provisioning is represented only as proposed requirements.', remediation: 'Remove any provision/apply instruction from the packet.', failClosed: true },
336
+ ],
337
+ claimMappings: [
338
+ { id: 'space-design-space-supports-offer', claimPredicate: 'supports', sourceFields: ['space.name', 'space.relatedProtocolIds[]'], target: 'atelier-claim@v1', evidence: 'space.sourceRef' },
339
+ { id: 'space-design-provision-depends-on-constraint', claimPredicate: 'depends_on', sourceFields: ['provisioning.needs[]', 'space.constraints[]'], target: 'atelier-claim@v1', evidence: 'provisioning.sourceRef' },
340
+ ],
341
+ exportMappings: [
342
+ { id: 'space-design.space', sourceField: 'space', target: 'space.space', runtimeOwner: 'projection', targetCollection: 'spaces' },
343
+ { id: 'space-design.provision', sourceField: 'provisioning', target: 'space.provision', runtimeOwner: 'providers', targetCollection: 'providerEgress' },
344
+ ],
345
+ safety: {
346
+ refuses: ['automatic provisioning', 'capacity expansion without review'],
347
+ reviewFocus: 'Verify that space requirements fail closed when access, privacy, or capacity constraints are incomplete.',
348
+ },
349
+ }),
350
+ protocol({
351
+ id: 'trackables',
352
+ title: 'Trackables',
353
+ purpose: 'Define observable states, milestones, events, and review signals without starting collection or telemetry.',
354
+ questions: [
355
+ {
356
+ id: 'trackables.signal',
357
+ prompt: 'Which signals matter for readiness, quality, safety, or progress?',
358
+ inputFields: ['trackables[].name', 'trackables[].purpose', 'trackables[].sourceRef'],
359
+ },
360
+ {
361
+ id: 'trackables.visibility',
362
+ prompt: 'Who should be allowed to see each signal after runtime review?',
363
+ inputFields: ['trackables[].localAudience', 'trackables[].proposedVisibility'],
364
+ },
365
+ {
366
+ id: 'trackables.cadence',
367
+ prompt: 'When would the signal be checked, and what decision would it support?',
368
+ inputFields: ['trackables[].cadence', 'trackables[].decisionUse'],
369
+ },
370
+ ],
371
+ inputFields: [
372
+ { id: 'trackables[].name', type: 'string', required: true, description: 'Neutral signal or milestone name.' },
373
+ { id: 'trackables[].proposedVisibility', type: 'enum', required: true, values: ['private', 'shared', 'platform', 'public'], description: 'Runtime visibility proposed for review.' },
374
+ { id: 'trackables[].cadence', type: 'string', required: true, description: 'Review cadence, not an active scheduler.' },
375
+ { id: 'trackables[].decisionUse', type: 'text', required: true, description: 'Decision this signal would inform.' },
376
+ ],
377
+ outputHints: [
378
+ { id: 'trackables.catalog', text: 'Render each signal with visibility, cadence, owner, and decision use.' },
379
+ { id: 'trackables.missing-owner', text: 'Separate signals missing an owner into a blocker list.' },
380
+ ],
381
+ readinessRules: [
382
+ { id: 'trackables.owner-and-visibility', severity: 'blocker', condition: 'Every trackable has a runtimeOwner and proposedVisibility.', remediation: 'Assign owner and visibility or remove the signal.', failClosed: true },
383
+ { id: 'trackables.no-telemetry', severity: 'blocker', condition: 'Trackables do not enable telemetry or background collection.', remediation: 'Keep signals as definitions only.', failClosed: true },
384
+ ],
385
+ claimMappings: [
386
+ { id: 'trackables-signal-evidences-outcome', claimPredicate: 'evidences', sourceFields: ['trackables[].name', 'trackables[].decisionUse'], target: 'atelier-claim@v1', evidence: 'trackables[].sourceRef' },
387
+ { id: 'trackables-signal-supports-journey', claimPredicate: 'supports', sourceFields: ['trackables[].relatedStage'], target: 'atelier-claim@v1', evidence: 'trackables[].sourceRef' },
388
+ ],
389
+ exportMappings: [
390
+ { id: 'trackables.trackable', sourceField: 'trackables[]', target: 'core.trackable', runtimeOwner: 'events', targetCollection: 'trackables' },
391
+ { id: 'trackables.audit-artifact', sourceField: 'trackables[].decisionUse', target: 'core.artifact', runtimeOwner: 'audit', targetCollection: 'staffPrep' },
392
+ ],
393
+ safety: {
394
+ refuses: ['background collection', 'implicit participant monitoring'],
395
+ reviewFocus: 'Verify that trackables are definitions and review signals, not collection jobs.',
396
+ },
397
+ }),
398
+ protocol({
399
+ id: 'consent-boundaries',
400
+ title: 'Consent Boundaries',
401
+ purpose: 'Record consent requirements, refusal paths, revocation expectations, and visibility limits for review.',
402
+ questions: [
403
+ {
404
+ id: 'consent-boundaries.scope',
405
+ prompt: 'What action, content, space, signal, or commitment requires consent?',
406
+ inputFields: ['boundaries[].subject', 'boundaries[].scope', 'boundaries[].sourceRef'],
407
+ },
408
+ {
409
+ id: 'consent-boundaries.refusal',
410
+ prompt: 'How can consent be declined, withheld, or revoked without penalty?',
411
+ inputFields: ['boundaries[].refusalPath', 'boundaries[].revocationPath'],
412
+ },
413
+ {
414
+ id: 'consent-boundaries.visibility',
415
+ prompt: 'What is the most restrictive visibility that can still support the intended workflow?',
416
+ inputFields: ['boundaries[].defaultVisibility', 'boundaries[].exceptions[]'],
417
+ },
418
+ ],
419
+ inputFields: [
420
+ { id: 'boundaries[].subject', type: 'string', required: true, description: 'Thing governed by this consent boundary.' },
421
+ { id: 'boundaries[].scope', type: 'text', required: true, description: 'Specific permission or limit under review.' },
422
+ { id: 'boundaries[].refusalPath', type: 'text', required: true, description: 'How refusal is represented.' },
423
+ { id: 'boundaries[].defaultVisibility', type: 'enum', required: true, values: ['private', 'shared'], description: 'Default to private unless review justifies shared.' },
424
+ ],
425
+ outputHints: [
426
+ { id: 'consent-boundaries.register', text: 'Render a consent register with subject, scope, refusal path, revocation path, and visibility.' },
427
+ { id: 'consent-boundaries.exceptions', text: 'Show exceptions as review items with evidence and owner.' },
428
+ ],
429
+ readinessRules: [
430
+ { id: 'consent-boundaries.refusal-required', severity: 'blocker', condition: 'Every consent boundary has refusal and revocation paths.', remediation: 'Add refusal and revocation paths before readiness.', failClosed: true },
431
+ { id: 'consent-boundaries.no-visibility-expansion', severity: 'blocker', condition: 'Visibility is private or explicitly justified as shared.', remediation: 'Downgrade visibility or add review evidence.', failClosed: true },
432
+ ],
433
+ claimMappings: [
434
+ { id: 'consent-boundaries-boundary-governs-subject', claimPredicate: 'belongs_to', sourceFields: ['boundaries[].subject', 'boundaries[].scope'], target: 'atelier-claim@v1', evidence: 'boundaries[].sourceRef' },
435
+ { id: 'consent-boundaries-refusal-supports-boundary', claimPredicate: 'supports', sourceFields: ['boundaries[].refusalPath'], target: 'atelier-claim@v1', evidence: 'boundaries[].sourceRef' },
436
+ ],
437
+ exportMappings: [
438
+ { id: 'consent-boundaries.artifact', sourceField: 'boundaries[]', target: 'core.artifact', runtimeOwner: 'consent', targetCollection: 'consentBoundaries' },
439
+ { id: 'consent-boundaries.audit-trackable', sourceField: 'boundaries[].exceptions[]', target: 'core.trackable', runtimeOwner: 'audit', targetCollection: 'trackables' },
440
+ ],
441
+ safety: {
442
+ refuses: ['assumed consent', 'silent visibility expansion'],
443
+ reviewFocus: 'Verify that consent controls refuse or fail closed when scope, refusal, or revocation is missing.',
444
+ },
445
+ }),
446
+ protocol({
447
+ id: 'content-inventory',
448
+ title: 'Content Inventory',
449
+ purpose: 'Inventory source material, packet artifacts, public surfaces, and review status without mixing private source authority into public output.',
450
+ questions: [
451
+ {
452
+ id: 'content-inventory.artifacts',
453
+ prompt: 'Which materials belong in the packet and what role does each material play?',
454
+ inputFields: ['materials[].name', 'materials[].contentRole', 'materials[].sourceRef'],
455
+ },
456
+ {
457
+ id: 'content-inventory.audience',
458
+ prompt: 'What local audience and proposed runtime visibility apply to each material?',
459
+ inputFields: ['materials[].localAudience', 'materials[].proposedVisibility'],
460
+ },
461
+ {
462
+ id: 'content-inventory.status',
463
+ prompt: 'Which materials are ready, draft, blocked, duplicated, or superseded?',
464
+ inputFields: ['materials[].approvalStatus', 'materials[].supersedes'],
465
+ },
466
+ ],
467
+ inputFields: [
468
+ { id: 'materials[].name', type: 'string', required: true, description: 'Neutral material name.' },
469
+ { id: 'materials[].contentRole', type: 'enum', required: true, values: ['source', 'summary', 'surface', 'staff-prep', 'evidence'], description: 'How this material is used in the packet.' },
470
+ { id: 'materials[].localAudience', type: 'enum', required: true, values: ['public', 'team', 'operator', 'staff', 'private', 'sensitive'], description: 'Source readership boundary.' },
471
+ { id: 'materials[].approvalStatus', type: 'enum', required: true, values: ['approved', 'draft', 'blocked', 'needs-review'], description: 'Review state.' },
472
+ ],
473
+ outputHints: [
474
+ { id: 'content-inventory.register', text: 'Render a material register with source role, audience, visibility, approval, and dependencies.' },
475
+ { id: 'content-inventory.taint', text: 'Surface private or sensitive materials as taint blockers for public projection.' },
476
+ ],
477
+ readinessRules: [
478
+ { id: 'content-inventory.audience-known', severity: 'blocker', condition: 'Every material has localAudience and approvalStatus.', remediation: 'Classify audience and status before export mapping.', failClosed: true },
479
+ { id: 'content-inventory.public-only-policy', severity: 'blocker', condition: 'Public export mappings only use public-approved source material.', remediation: 'Remove private source refs or reduce visibility.', failClosed: true },
480
+ ],
481
+ claimMappings: [
482
+ { id: 'content-inventory-material-supports-surface', claimPredicate: 'supports', sourceFields: ['materials[].sourceRef', 'materials[].contentRole'], target: 'atelier-claim@v1', evidence: 'materials[].sourceRef' },
483
+ { id: 'content-inventory-material-supersedes', claimPredicate: 'supersedes', sourceFields: ['materials[].supersedes'], target: 'atelier-claim@v1', evidence: 'materials[].sourceRef' },
484
+ ],
485
+ exportMappings: [
486
+ { id: 'content-inventory.material', sourceField: 'materials[]', target: 'content.material', runtimeOwner: 'projection', targetCollection: 'surfaces' },
487
+ { id: 'content-inventory.staff-prep', sourceField: 'materials[contentRole=staff-prep]', target: 'core.artifact', runtimeOwner: 'providers', targetCollection: 'staffPrep' },
488
+ ],
489
+ safety: {
490
+ refuses: ['public projection from private source material', 'unreviewed content promotion'],
491
+ reviewFocus: 'Verify that source audience and runtime visibility remain separate fields.',
492
+ },
493
+ }),
494
+ protocol({
495
+ id: 'discovery-engine',
496
+ title: 'Discovery Engine',
497
+ purpose: 'Define discovery prompts, intake signals, scoring notes, and next-step suggestions as local review artifacts.',
498
+ questions: [
499
+ {
500
+ id: 'discovery-engine.questions',
501
+ prompt: 'Which discovery questions gather the minimum context needed for a useful next step?',
502
+ inputFields: ['discoveryQuestions[].prompt', 'discoveryQuestions[].purpose'],
503
+ },
504
+ {
505
+ id: 'discovery-engine.signals',
506
+ prompt: 'Which answers or observations would change the recommendation?',
507
+ inputFields: ['signals[].name', 'signals[].interpretation', 'signals[].sourceRef'],
508
+ },
509
+ {
510
+ id: 'discovery-engine.next-step',
511
+ prompt: 'What next step can be suggested, and what evidence supports it?',
512
+ inputFields: ['nextSteps[].label', 'nextSteps[].evidenceRef', 'nextSteps[].confidence'],
513
+ },
514
+ ],
515
+ inputFields: [
516
+ { id: 'discoveryQuestions[].prompt', type: 'text', required: true, description: 'Neutral discovery question.' },
517
+ { id: 'signals[].interpretation', type: 'text', required: true, description: 'How a signal changes the local recommendation.' },
518
+ { id: 'nextSteps[].confidence', type: 'number', required: true, description: '0 to 1 proposal confidence.' },
519
+ { id: 'nextSteps[].requiresReview', type: 'boolean', required: true, description: 'Whether a human review is required before showing the suggestion.' },
520
+ ],
521
+ outputHints: [
522
+ { id: 'discovery-engine.flow', text: 'Render discovery questions, expected signals, recommendation logic, and review gates.' },
523
+ { id: 'discovery-engine.low-confidence', text: 'Separate low-confidence next steps from ready suggestions.' },
524
+ ],
525
+ readinessRules: [
526
+ { id: 'discovery-engine.no-model-provider', severity: 'blocker', condition: 'Discovery definitions do not require a model provider or external egress.', remediation: 'Represent discovery as local prompts and static rules only.', failClosed: true },
527
+ { id: 'discovery-engine.review-required', severity: 'warning', condition: 'Any next step with confidence below threshold requires review.', remediation: 'Set requiresReview true or remove the next step.', failClosed: true },
528
+ ],
529
+ claimMappings: [
530
+ { id: 'discovery-engine-signal-evidences-next-step', claimPredicate: 'evidences', sourceFields: ['signals[].name', 'nextSteps[].label'], target: 'atelier-claim@v1', evidence: 'nextSteps[].evidenceRef' },
531
+ { id: 'discovery-engine-question-supports-signal', claimPredicate: 'supports', sourceFields: ['discoveryQuestions[].prompt', 'signals[].name'], target: 'atelier-claim@v1', evidence: 'signals[].sourceRef' },
532
+ ],
533
+ exportMappings: [
534
+ { id: 'discovery-engine.surface', sourceField: 'discoveryQuestions[]', target: 'content.material', runtimeOwner: 'projection', targetCollection: 'sdui' },
535
+ { id: 'discovery-engine.signal-trackable', sourceField: 'signals[]', target: 'core.trackable', runtimeOwner: 'events', targetCollection: 'trackables' },
536
+ ],
537
+ safety: {
538
+ refuses: ['external analysis execution', 'automatic recommendation promotion'],
539
+ reviewFocus: 'Verify that discovery suggestions are local proposals with confidence and review gates.',
540
+ },
541
+ }),
542
+ protocol({
543
+ id: 'journey-map',
544
+ title: 'Journey Map',
545
+ purpose: 'Represent stages, transitions, commitments, handoffs, and exit paths across an experience.',
546
+ questions: [
547
+ {
548
+ id: 'journey-map.stages',
549
+ prompt: 'What stages does a participant or operator move through?',
550
+ inputFields: ['stages[].name', 'stages[].entryCriteria', 'stages[].exitCriteria'],
551
+ },
552
+ {
553
+ id: 'journey-map.handoffs',
554
+ prompt: 'Where do responsibilities, visibility, or ownership change?',
555
+ inputFields: ['handoffs[].fromOwner', 'handoffs[].toOwner', 'handoffs[].consentBoundaryRef'],
556
+ },
557
+ {
558
+ id: 'journey-map.exits',
559
+ prompt: 'How can a participant pause, decline, complete, or leave the journey?',
560
+ inputFields: ['exits[].stageRef', 'exits[].path', 'exits[].supportNeed'],
561
+ },
562
+ ],
563
+ inputFields: [
564
+ { id: 'stages[].name', type: 'string', required: true, description: 'Neutral journey stage name.' },
565
+ { id: 'stages[].entryCriteria', type: 'text', required: true, description: 'Reviewed entry condition.' },
566
+ { id: 'handoffs[].toOwner', type: 'enum', required: true, values: ['identity', 'catalog', 'commitments', 'providers', 'messaging', 'audit'], description: 'Owner proposed for review.' },
567
+ { id: 'exits[].path', type: 'text', required: true, description: 'Pause, decline, complete, or leave path.' },
568
+ ],
569
+ outputHints: [
570
+ { id: 'journey-map.timeline', text: 'Render a stage timeline with entry, exit, owner, consent, and trackable references.' },
571
+ { id: 'journey-map.handoffs', text: 'Highlight handoffs as readiness checks, not as automatic routing.' },
572
+ ],
573
+ readinessRules: [
574
+ { id: 'journey-map.entry-exit-present', severity: 'blocker', condition: 'Every stage has entry and exit criteria.', remediation: 'Add criteria or flag the stage blocked.', failClosed: true },
575
+ { id: 'journey-map.exit-path-present', severity: 'blocker', condition: 'At least one non-punitive exit path is present.', remediation: 'Add pause, decline, complete, or leave path.', failClosed: true },
576
+ ],
577
+ claimMappings: [
578
+ { id: 'journey-map-stage-depends-on-previous', claimPredicate: 'depends_on', sourceFields: ['stages[]'], target: 'atelier-claim@v1', evidence: 'stages[].sourceRef' },
579
+ { id: 'journey-map-exit-supports-consent', claimPredicate: 'supports', sourceFields: ['exits[].path', 'handoffs[].consentBoundaryRef'], target: 'atelier-claim@v1', evidence: 'exits[].sourceRef' },
580
+ ],
581
+ exportMappings: [
582
+ { id: 'journey-map.commitment-path', sourceField: 'stages[]', target: 'scheduling.commitment', runtimeOwner: 'commitments', targetCollection: 'commitmentPaths' },
583
+ { id: 'journey-map.surface', sourceField: 'stages[].participantCopy', target: 'content.material', runtimeOwner: 'projection', targetCollection: 'surfaces' },
584
+ ],
585
+ safety: {
586
+ refuses: ['automatic routing', 'exit path omission'],
587
+ reviewFocus: 'Verify that stage transitions and handoffs fail closed when consent, owner, or exit criteria are incomplete.',
588
+ },
589
+ }),
590
+ protocol({
591
+ id: 'operations-readiness',
592
+ title: 'Operations Readiness',
593
+ purpose: 'Check staff prep, ownership, support boundaries, escalation paths, and manual runbooks before launch review.',
594
+ questions: [
595
+ {
596
+ id: 'operations-readiness.owners',
597
+ prompt: 'Who owns each operational responsibility?',
598
+ inputFields: ['responsibilities[].name', 'responsibilities[].ownerRole', 'responsibilities[].backupRole'],
599
+ },
600
+ {
601
+ id: 'operations-readiness.runbooks',
602
+ prompt: 'Which runbooks or checklists are required before use?',
603
+ inputFields: ['runbooks[].name', 'runbooks[].sourceRef', 'runbooks[].approvalStatus'],
604
+ },
605
+ {
606
+ id: 'operations-readiness.escalation',
607
+ prompt: 'What support or escalation path exists when something is blocked?',
608
+ inputFields: ['escalations[].condition', 'escalations[].response', 'escalations[].ownerRole'],
609
+ },
610
+ ],
611
+ inputFields: [
612
+ { id: 'responsibilities[].ownerRole', type: 'string', required: true, description: 'Role responsible for the operational area.' },
613
+ { id: 'responsibilities[].backupRole', type: 'string', required: true, description: 'Backup role for continuity.' },
614
+ { id: 'runbooks[].approvalStatus', type: 'enum', required: true, values: ['approved', 'draft', 'blocked', 'needs-review'], description: 'Runbook review state.' },
615
+ { id: 'escalations[].condition', type: 'text', required: true, description: 'Condition that triggers manual review or support.' },
616
+ ],
617
+ outputHints: [
618
+ { id: 'operations-readiness.matrix', text: 'Render owners, backups, runbooks, escalation, and unresolved blockers in one matrix.' },
619
+ { id: 'operations-readiness.launch-gates', text: 'Call out launch gates separately from nice-to-have cleanup.' },
620
+ ],
621
+ readinessRules: [
622
+ { id: 'operations-readiness.owner-backup', severity: 'blocker', condition: 'Every responsibility has ownerRole and backupRole.', remediation: 'Assign owner and backup before launch review.', failClosed: true },
623
+ { id: 'operations-readiness.runbooks-approved', severity: 'warning', condition: 'Required runbooks are approved or explicitly set needs-review.', remediation: 'Update approvalStatus and blockers.', failClosed: true },
624
+ ],
625
+ claimMappings: [
626
+ { id: 'operations-readiness-runbook-supports-responsibility', claimPredicate: 'supports', sourceFields: ['runbooks[].name', 'responsibilities[].name'], target: 'atelier-claim@v1', evidence: 'runbooks[].sourceRef' },
627
+ { id: 'operations-readiness-escalation-depends-on-owner', claimPredicate: 'depends_on', sourceFields: ['escalations[].condition', 'escalations[].ownerRole'], target: 'atelier-claim@v1', evidence: 'escalations[].sourceRef' },
628
+ ],
629
+ exportMappings: [
630
+ { id: 'operations-readiness.staff-prep', sourceField: 'runbooks[]', target: 'core.artifact', runtimeOwner: 'providers', targetCollection: 'staffPrep' },
631
+ { id: 'operations-readiness.escalation-trackable', sourceField: 'escalations[]', target: 'core.trackable', runtimeOwner: 'audit', targetCollection: 'trackables' },
632
+ ],
633
+ safety: {
634
+ refuses: ['unowned operational responsibility', 'silent launch with blocked runbooks'],
635
+ reviewFocus: 'Verify that support and escalation controls block launch when ownership or runbooks are incomplete.',
636
+ },
637
+ }),
638
+ protocol({
639
+ id: 'runtime-readiness',
640
+ title: 'Runtime Readiness',
641
+ purpose: 'Validate dry-run import posture, runtime owner boundaries, export mapping completeness, and fail-closed controls.',
642
+ questions: [
643
+ {
644
+ id: 'runtime-readiness.owners',
645
+ prompt: 'Which runtime owners are touched by the proposed packet?',
646
+ inputFields: ['runtimeOwners[].name', 'runtimeOwners[].reason', 'runtimeOwners[].sourceRef'],
647
+ },
648
+ {
649
+ id: 'runtime-readiness.import-plan',
650
+ prompt: 'What would the dry-run import plan contain and what must remain blocked?',
651
+ inputFields: ['importPlan.mode', 'importPlan.operations[]', 'importPlan.blockers[]'],
652
+ },
653
+ {
654
+ id: 'runtime-readiness.controls',
655
+ prompt: 'Which controls must refuse, block, or fail closed before promotion?',
656
+ inputFields: ['controls[].name', 'controls[].expectedRefusal', 'controls[].evidenceRef'],
657
+ },
658
+ ],
659
+ inputFields: [
660
+ { id: 'runtimeOwners[].name', type: 'enum', required: true, values: ['identity', 'catalog', 'commitments', 'events', 'projection', 'consent', 'messaging', 'providers', 'audit'], description: 'Runtime owner proposed by the packet.' },
661
+ { id: 'importPlan.mode', type: 'enum', required: true, values: ['dry-run'], description: 'Bundled pack only supports dry-run import planning.' },
662
+ { id: 'importPlan.operations[]', type: 'array', required: true, description: 'Reviewable operations, not executable writes.' },
663
+ { id: 'controls[].expectedRefusal', type: 'text', required: true, description: 'Boundary validation expectation for fail-closed behavior.' },
664
+ ],
665
+ outputHints: [
666
+ { id: 'runtime-readiness.control-table', text: 'Render controls with expected refusal, observed evidence, owner, and remediation order.' },
667
+ { id: 'runtime-readiness.blockers', text: 'Show blockers as the authoritative reason the packet is not importable.' },
668
+ ],
669
+ readinessRules: [
670
+ { id: 'runtime-readiness.dry-run-only', severity: 'blocker', condition: 'importPlan.mode is dry-run and every operation is reviewable only.', remediation: 'Remove apply intent or runtime mutation fields.', failClosed: true },
671
+ { id: 'runtime-readiness.controls-have-evidence', severity: 'blocker', condition: 'Every control has expectedRefusal and evidenceRef.', remediation: 'Add static inspection evidence or existing defensive test evidence.', failClosed: true },
672
+ ],
673
+ claimMappings: [
674
+ { id: 'runtime-readiness-control-evidences-boundary', claimPredicate: 'evidences', sourceFields: ['controls[].name', 'controls[].expectedRefusal'], target: 'atelier-claim@v1', evidence: 'controls[].evidenceRef' },
675
+ { id: 'runtime-readiness-operation-depends-on-owner', claimPredicate: 'depends_on', sourceFields: ['importPlan.operations[]', 'runtimeOwners[].name'], target: 'atelier-claim@v1', evidence: 'runtimeOwners[].sourceRef' },
676
+ ],
677
+ exportMappings: [
678
+ { id: 'runtime-readiness.report', sourceField: 'controls[]', target: 'core.artifact', runtimeOwner: 'audit', targetCollection: 'staffPrep' },
679
+ { id: 'runtime-readiness.import-trackable', sourceField: 'importPlan.blockers[]', target: 'core.trackable', runtimeOwner: 'audit', targetCollection: 'trackables' },
680
+ ],
681
+ safety: {
682
+ refuses: ['apply mode', 'runtime mutation', 'unverified control pass'],
683
+ reviewFocus: 'Prefer static inspection and existing defensive tests; verify that each control refuses, blocks, or fails closed.',
684
+ },
685
+ }),
686
+ protocol({
687
+ id: 'tenant-packet',
688
+ title: 'Tenant Packet',
689
+ purpose: 'Assemble tenant-level launch evidence, ownership, configuration, boundary decisions, and acceptance state.',
690
+ questions: [
691
+ {
692
+ id: 'tenant-packet.scope',
693
+ prompt: 'What tenant, workspace, or project scope does this packet cover?',
694
+ inputFields: ['tenant.scopeName', 'tenant.scopeType', 'tenant.sourceRef'],
695
+ },
696
+ {
697
+ id: 'tenant-packet.acceptance',
698
+ prompt: 'Who accepts readiness and what evidence supports acceptance?',
699
+ inputFields: ['acceptance.ownerRole', 'acceptance.evidenceRefs[]', 'acceptance.conditions[]'],
700
+ },
701
+ {
702
+ id: 'tenant-packet.package',
703
+ prompt: 'Which protocol outputs are included, blocked, or deferred?',
704
+ inputFields: ['protocolStates[].protocolId', 'protocolStates[].state', 'protocolStates[].blockers[]'],
705
+ },
706
+ ],
707
+ inputFields: [
708
+ { id: 'tenant.scopeName', type: 'string', required: true, description: 'Neutral tenant or workspace scope label.' },
709
+ { id: 'tenant.scopeType', type: 'enum', required: true, values: ['project', 'workspace', 'organization', 'sandbox'], description: 'Scope category.' },
710
+ { id: 'acceptance.ownerRole', type: 'string', required: true, description: 'Role accountable for acceptance.' },
711
+ { id: 'protocolStates[].state', type: 'enum', required: true, values: ['included', 'blocked', 'deferred', 'not-applicable'], description: 'Protocol inclusion state.' },
712
+ ],
713
+ outputHints: [
714
+ { id: 'tenant-packet.cover', text: 'Render scope, acceptance owner, included protocols, blockers, and deferred work as a single cover sheet.' },
715
+ { id: 'tenant-packet.delta', text: 'Show done, blocked, and deferred protocol states separately.' },
716
+ ],
717
+ readinessRules: [
718
+ { id: 'tenant-packet.all-protocols-accounted', severity: 'blocker', condition: 'All bundled protocol ids have a protocolStates entry.', remediation: 'Add included, blocked, deferred, or not-applicable state for every protocol.', failClosed: true },
719
+ { id: 'tenant-packet.acceptance-evidence', severity: 'blocker', condition: 'Acceptance has ownerRole, evidenceRefs, and conditions.', remediation: 'Add acceptance evidence or flag packet blocked.', failClosed: true },
720
+ ],
721
+ claimMappings: [
722
+ { id: 'tenant-packet-protocol-belongs-to-scope', claimPredicate: 'belongs_to', sourceFields: ['protocolStates[].protocolId', 'tenant.scopeName'], target: 'atelier-claim@v1', evidence: 'tenant.sourceRef' },
723
+ { id: 'tenant-packet-acceptance-evidences-readiness', claimPredicate: 'evidences', sourceFields: ['acceptance.ownerRole', 'acceptance.conditions[]'], target: 'atelier-claim@v1', evidence: 'acceptance.evidenceRefs[]' },
724
+ ],
725
+ exportMappings: [
726
+ { id: 'tenant-packet.cover-artifact', sourceField: 'tenant', target: 'core.artifact', runtimeOwner: 'audit', targetCollection: 'staffPrep' },
727
+ { id: 'tenant-packet.provision-review', sourceField: 'protocolStates[]', target: 'space.provision', runtimeOwner: 'providers', targetCollection: 'providerEgress' },
728
+ ],
729
+ safety: {
730
+ refuses: ['unaccounted protocol state', 'acceptance without evidence'],
731
+ reviewFocus: 'Verify that the tenant packet reports done, blocked, and deferred states without overstating readiness.',
732
+ },
733
+ }),
734
+ ]
735
+
736
+ export const bundledMnstryReadinessPackV1 = {
737
+ schema: MNSTRY_READINESS_PACK_SCHEMA,
738
+ id: 'mnstry-readiness-pack',
739
+ version: 'v1',
740
+ title: 'MNSTRY Readiness Pack V1',
741
+ description: 'Neutral bundled readiness protocol definitions for package-safe Atelier preparation.',
742
+ packageSafe: true,
743
+ protocolSlugs: READINESS_PROTOCOL_SLUGS,
744
+ protocolIds: READINESS_PROTOCOL_IDS,
745
+ safetyPosture: {
746
+ ...baseSafetyPosture,
747
+ packageSpecificContent: false,
748
+ projectSpecificContent: false,
749
+ reviewerGuidance: 'Prefer static inspection, existing defensive tests, concrete evidence, observed behavior, impact, confidence, and remediation order.',
750
+ },
751
+ protocols: bundledReadinessProtocols,
752
+ }
753
+
754
+ export function getBundledReadinessProtocol(id) {
755
+ return bundledReadinessProtocols.find((protocolDefinition) => (
756
+ protocolDefinition.id === id ||
757
+ protocolDefinition.slug === id ||
758
+ protocolDefinition.id === namespacedProtocolId(id)
759
+ )) ?? null
760
+ }
761
+
762
+ export const bundledReadinessPack = bundledMnstryReadinessPackV1
763
+
764
+ export function protocolById(id) {
765
+ return getBundledReadinessProtocol(id)
766
+ }