aw-spec-cli 0.1.8 → 0.1.9

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 (257) hide show
  1. package/assets/.appweaver/DESIGN-FORMAT.md +200 -0
  2. package/assets/.appweaver/ORCH-DIALECT.md +156 -0
  3. package/assets/.appweaver/RULE-PARTITION.md +175 -0
  4. package/assets/.appweaver/STACK-PROFILES.md +461 -0
  5. package/assets/.appweaver/ai-rules.md +180 -0
  6. package/assets/.appweaver/domain.json +1 -0
  7. package/assets/.appweaver/extensions/.registry +19 -0
  8. package/assets/.appweaver/extensions/agent-context/README.md +57 -0
  9. package/assets/.appweaver/extensions/agent-context/agent-context-config.yml +4 -0
  10. package/assets/.appweaver/extensions/agent-context/commands/aw-spec.agent-context.update.md +26 -0
  11. package/assets/.appweaver/extensions/agent-context/extension.yml +37 -0
  12. package/assets/.appweaver/extensions/agent-context/scripts/bash/update-agent-context.sh +201 -0
  13. package/assets/.appweaver/extensions/agent-context/scripts/powershell/update-agent-context.ps1 +237 -0
  14. package/assets/.appweaver/extensions.yml +16 -0
  15. package/assets/.appweaver/feature.json +3 -0
  16. package/assets/.appweaver/init-options.json +9 -0
  17. package/assets/.appweaver/integration.json +15 -0
  18. package/assets/.appweaver/integrations/aw-spec.manifest.json +9 -0
  19. package/assets/.appweaver/interpreter/run-skill.py +1176 -0
  20. package/assets/.appweaver/memory/constitution.md +50 -0
  21. package/assets/.appweaver/orchestrator/.smoke-out/smoke.md +6 -0
  22. package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +94 -0
  23. package/assets/.appweaver/orchestrator/README.md +300 -0
  24. package/assets/.appweaver/orchestrator/adapters/claude_agent_sdk.py +74 -0
  25. package/assets/.appweaver/orchestrator/adapters/google_antigravity.py +74 -0
  26. package/assets/.appweaver/orchestrator/modules/delta-design.orch.yaml +105 -0
  27. package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +101 -0
  28. package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +90 -0
  29. package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +126 -0
  30. package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +123 -0
  31. package/assets/.appweaver/orchestrator/orchestrator.py +1721 -0
  32. package/assets/.appweaver/orchestrator/rev-templates/ai-rules.reference.md +40 -0
  33. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +101 -0
  34. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +245 -0
  35. package/assets/.appweaver/orchestrator/rev-templates/domain-constitution.skeleton.md +63 -0
  36. package/assets/.appweaver/orchestrator/rev-templates/domain-requirements.skeleton.md +48 -0
  37. package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +59 -0
  38. package/assets/.appweaver/orchestrator/rev-templates/domain-rule-file.skeleton.md +39 -0
  39. package/assets/.appweaver/orchestrator/rev-templates/frontend-rule-file.skeleton.md +63 -0
  40. package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +116 -0
  41. package/assets/.appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md +106 -0
  42. package/assets/.appweaver/orchestrator/rev-templates/technical-rule-file.skeleton.md +54 -0
  43. package/assets/.appweaver/orchestrator/rev-templates/ui-constitution.skeleton.md +125 -0
  44. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +123 -0
  45. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +294 -0
  46. package/assets/.appweaver/orchestrator/workflows/_smoke.orch.yaml +160 -0
  47. package/assets/.appweaver/orchestrator/workflows/aw-spec-add-component.orch.yaml +270 -0
  48. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +934 -0
  49. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-delta-design.orch.yaml +251 -0
  50. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-design.orch.yaml +265 -0
  51. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +437 -0
  52. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +197 -0
  53. package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +475 -0
  54. package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +181 -0
  55. package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +727 -0
  56. package/assets/.appweaver/orchestrator/workflows/aw-spec-demo.orch.yaml +100 -0
  57. package/assets/.appweaver/orchestrator/workflows/aw-spec-dependency-tree.orch.yaml +69 -0
  58. package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +85 -0
  59. package/assets/.appweaver/orchestrator/workflows/aw-spec-design-ui.orch.yaml +386 -0
  60. package/assets/.appweaver/orchestrator/workflows/aw-spec-design.orch.yaml +382 -0
  61. package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +462 -0
  62. package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +265 -0
  63. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-delta.orch.yaml +253 -0
  64. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-ui.orch.yaml +267 -0
  65. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +287 -0
  66. package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +238 -0
  67. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +1822 -0
  68. package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +293 -0
  69. package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +194 -0
  70. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +83 -0
  71. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +128 -0
  72. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +296 -0
  73. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +439 -0
  74. package/assets/.appweaver/scripts/bash/aw-inventory.sh +17 -0
  75. package/assets/.appweaver/scripts/bash/aw-parity.sh +13 -0
  76. package/assets/.appweaver/scripts/bash/aw-rev-constitution.sh +13 -0
  77. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +2626 -0
  78. package/assets/.appweaver/scripts/bash/aw-xref.sh +15 -0
  79. package/assets/.appweaver/scripts/bash/common.sh +533 -0
  80. package/assets/.appweaver/scripts/powershell/aw-inventory.ps1 +17 -0
  81. package/assets/.appweaver/scripts/powershell/aw-parity.ps1 +13 -0
  82. package/assets/.appweaver/scripts/powershell/aw-rev-constitution.ps1 +13 -0
  83. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +2232 -0
  84. package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +15 -0
  85. package/assets/.appweaver/scripts/python/aw-component-catalog.py +121 -0
  86. package/assets/.appweaver/scripts/python/aw-inventory.py +1180 -0
  87. package/assets/.appweaver/scripts/python/aw-parity.py +380 -0
  88. package/assets/.appweaver/scripts/python/aw-rev-constitution.py +329 -0
  89. package/assets/.appweaver/scripts/python/aw-stack.py +1251 -0
  90. package/assets/.appweaver/scripts/python/aw-xref.py +1330 -0
  91. package/assets/.appweaver/scripts/python/validate_okf.py +352 -0
  92. package/assets/.appweaver/stack-profiles/angular.json +16 -0
  93. package/assets/.appweaver/stack-profiles/blazor-wasm.json +17 -0
  94. package/assets/.appweaver/stack-profiles/dotnet-webapi.json +15 -0
  95. package/assets/.appweaver/stack-profiles/go-chi.json +14 -0
  96. package/assets/.appweaver/stack-profiles/java-spring.json +16 -0
  97. package/assets/.appweaver/stack-profiles/nextjs.json +16 -0
  98. package/assets/.appweaver/stack-profiles/node-express.json +15 -0
  99. package/assets/.appweaver/stack-profiles/python-fastapi.json +16 -0
  100. package/assets/.appweaver/stack-profiles/react-vite.json +17 -0
  101. package/assets/.appweaver/stack-profiles/sveltekit.json +16 -0
  102. package/assets/.appweaver/stack-profiles/vue-vite.json +17 -0
  103. package/assets/.appweaver/stacks.json +3 -0
  104. package/assets/.appweaver/templates/constitution-domain-template.md +116 -0
  105. package/assets/.appweaver/templates/constitution-technical-template.md +108 -0
  106. package/assets/.appweaver/templates/constitution-ui-template.md +116 -0
  107. package/assets/.appweaver/templates/delta-design-template.md +69 -0
  108. package/assets/.appweaver/templates/delta-spec-template.md +63 -0
  109. package/assets/.appweaver/templates/design-template.md +383 -0
  110. package/assets/.appweaver/templates/okf-concept-template.md +114 -0
  111. package/assets/.appweaver/templates/parity-manifest-template.json +49 -0
  112. package/assets/.appweaver/templates/source-map-template.md +85 -0
  113. package/assets/.appweaver/templates/spec-template.md +309 -0
  114. package/assets/.appweaver/templates/ui-design-template.md +273 -0
  115. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.Reference.pack.txt +25248 -0
  116. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +5726 -0
  117. package/assets/foundations/dotnet/ModularMonolith/pack-foundation.ps1 +145 -0
  118. package/assets/foundations/dotnet/ModularMonolith/pack-foundation.sh +196 -0
  119. package/assets/foundations/dotnet/ModularMonolith/pack-reference-foundation.ps1 +157 -0
  120. package/assets/foundations/dotnet/ModularMonolith/pack-reference-foundation.sh +209 -0
  121. package/assets/foundations/dotnet/ModularMonolith/unpack-foundation.ps1 +126 -0
  122. package/assets/foundations/dotnet/ModularMonolith/unpack-foundation.sh +217 -0
  123. package/assets/foundations/dotnet/ModularMonolith/unpack-reference-foundation.ps1 +129 -0
  124. package/assets/foundations/dotnet/ModularMonolith/unpack-reference-foundation.sh +218 -0
  125. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.Reference.pack.txt +19318 -0
  126. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +2833 -0
  127. package/assets/foundations/dotnet/VerticalSlice/pack-foundation.ps1 +145 -0
  128. package/assets/foundations/dotnet/VerticalSlice/pack-foundation.sh +196 -0
  129. package/assets/foundations/dotnet/VerticalSlice/pack-reference-foundation.ps1 +157 -0
  130. package/assets/foundations/dotnet/VerticalSlice/pack-reference-foundation.sh +209 -0
  131. package/assets/foundations/dotnet/VerticalSlice/unpack-foundation.ps1 +126 -0
  132. package/assets/foundations/dotnet/VerticalSlice/unpack-foundation.sh +217 -0
  133. package/assets/foundations/dotnet/VerticalSlice/unpack-reference-foundation.ps1 +129 -0
  134. package/assets/foundations/dotnet/VerticalSlice/unpack-reference-foundation.sh +218 -0
  135. package/assets/foundations/dotnet/components/Email/README.md +119 -0
  136. package/assets/foundations/dotnet/components/Email/ReferenceEndpoints/SendEmailEndpoint.cs +84 -0
  137. package/assets/foundations/dotnet/components/Email/integration.md +300 -0
  138. package/assets/foundations/dotnet/components/Jobs/README.md +113 -0
  139. package/assets/foundations/dotnet/components/Jobs/integration.md +259 -0
  140. package/assets/foundations/dotnet/components/QrGenerator/README.md +85 -0
  141. package/assets/foundations/dotnet/components/QrGenerator/ReferenceEndpoints/GenerateQrEndpoint.cs +57 -0
  142. package/assets/foundations/dotnet/components/QrGenerator/integration.md +230 -0
  143. package/assets/foundations/dotnet/components/README.md +74 -0
  144. package/assets/guardrails/README.md +222 -0
  145. package/assets/guardrails/domain/healthcare/ai-rules.domain.md +34 -0
  146. package/assets/guardrails/domain/healthcare/api-versioning.domain.md +17 -0
  147. package/assets/guardrails/domain/healthcare/auditing.domain.md +97 -0
  148. package/assets/guardrails/domain/healthcare/authorization.domain.md +26 -0
  149. package/assets/guardrails/domain/healthcare/clinical-terms.md +20 -0
  150. package/assets/guardrails/domain/healthcare/coding-standards.domain.md +26 -0
  151. package/assets/guardrails/domain/healthcare/consent.md +19 -0
  152. package/assets/guardrails/domain/healthcare/cqrs.domain.md +12 -0
  153. package/assets/guardrails/domain/healthcare/data-classification.domain.md +28 -0
  154. package/assets/guardrails/domain/healthcare/dependency-policy.domain.md +11 -0
  155. package/assets/guardrails/domain/healthcare/dicom.md +15 -0
  156. package/assets/guardrails/domain/healthcare/domain-constitution.md +119 -0
  157. package/assets/guardrails/domain/healthcare/domain-driven-design.domain.md +28 -0
  158. package/assets/guardrails/domain/healthcare/eventing.domain.md +18 -0
  159. package/assets/guardrails/domain/healthcare/fhir.md +36 -0
  160. package/assets/guardrails/domain/healthcare/folder-structure.domain.md +25 -0
  161. package/assets/guardrails/domain/healthcare/hipaa.md +34 -0
  162. package/assets/guardrails/domain/healthcare/hl7.md +15 -0
  163. package/assets/guardrails/domain/healthcare/ihe-conformance.md +31 -0
  164. package/assets/guardrails/domain/healthcare/integration-terms.md +21 -0
  165. package/assets/guardrails/domain/healthcare/persistence.domain.md +20 -0
  166. package/assets/guardrails/domain/healthcare/terminology.md +30 -0
  167. package/assets/guardrails/domain/healthcare/testing.domain.md +15 -0
  168. package/assets/guardrails/domain/healthcare/ux/accessibility-standards.md +36 -0
  169. package/assets/guardrails/domain/healthcare/ux/content-design.md +32 -0
  170. package/assets/guardrails/domain/healthcare/ux/interaction-states.md +44 -0
  171. package/assets/guardrails/domain/healthcare/ux/journey-mapping.md +40 -0
  172. package/assets/guardrails/domain/healthcare/vertical-slices.domain.md +18 -0
  173. package/assets/guardrails/domain/healthcare/zero-trust.domain.md +12 -0
  174. package/assets/guardrails/domain/pharma/ai-rules.domain.md +32 -0
  175. package/assets/guardrails/domain/pharma/api-versioning.domain.md +20 -0
  176. package/assets/guardrails/domain/pharma/atc.md +22 -0
  177. package/assets/guardrails/domain/pharma/auditing.domain.md +90 -0
  178. package/assets/guardrails/domain/pharma/authorization.domain.md +25 -0
  179. package/assets/guardrails/domain/pharma/coding-standards.domain.md +28 -0
  180. package/assets/guardrails/domain/pharma/cqrs.domain.md +16 -0
  181. package/assets/guardrails/domain/pharma/data-classification.domain.md +24 -0
  182. package/assets/guardrails/domain/pharma/data-provenance.md +21 -0
  183. package/assets/guardrails/domain/pharma/dependency-policy.domain.md +11 -0
  184. package/assets/guardrails/domain/pharma/domain-constitution.md +113 -0
  185. package/assets/guardrails/domain/pharma/domain-driven-design.domain.md +36 -0
  186. package/assets/guardrails/domain/pharma/domain-requirements.sample.md +103 -0
  187. package/assets/guardrails/domain/pharma/eventing.domain.md +18 -0
  188. package/assets/guardrails/domain/pharma/fhir.md +31 -0
  189. package/assets/guardrails/domain/pharma/folder-structure.domain.md +26 -0
  190. package/assets/guardrails/domain/pharma/hl7.md +17 -0
  191. package/assets/guardrails/domain/pharma/idmp.md +26 -0
  192. package/assets/guardrails/domain/pharma/integration-terms.md +21 -0
  193. package/assets/guardrails/domain/pharma/ndc.md +28 -0
  194. package/assets/guardrails/domain/pharma/persistence.domain.md +23 -0
  195. package/assets/guardrails/domain/pharma/pharma-terms.md +27 -0
  196. package/assets/guardrails/domain/pharma/product-lifecycle.domain.md +30 -0
  197. package/assets/guardrails/domain/pharma/regulatory-compliance.md +19 -0
  198. package/assets/guardrails/domain/pharma/terminology.md +32 -0
  199. package/assets/guardrails/domain/pharma/testing.domain.md +19 -0
  200. package/assets/guardrails/domain/pharma/vertical-slices.domain.md +17 -0
  201. package/assets/guardrails/domain/pharma/zero-trust.domain.md +12 -0
  202. package/assets/guardrails/projects/dotnet-default-project/domain/domain-requirements.md +58 -0
  203. package/assets/guardrails/projects/dotnet-default-project/domain-rule-bindings.md +113 -0
  204. package/assets/guardrails/projects/dotnet-default-project/frontend/ui-requirements.md +43 -0
  205. package/assets/guardrails/projects/dotnet-default-project/service/technical-requirements.md +40 -0
  206. package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +263 -0
  207. package/assets/guardrails/requirement-spec.txt +27 -0
  208. package/assets/guardrails/technology/dotnet-webapi/PACKAGING.md +184 -0
  209. package/assets/guardrails/technology/dotnet-webapi/api-versioning.md +44 -0
  210. package/assets/guardrails/technology/dotnet-webapi/auditing.md +96 -0
  211. package/assets/guardrails/technology/dotnet-webapi/authorization-matrix.md +14 -0
  212. package/assets/guardrails/technology/dotnet-webapi/authorization.md +39 -0
  213. package/assets/guardrails/technology/dotnet-webapi/clean-architecture.md +54 -0
  214. package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +87 -0
  215. package/assets/guardrails/technology/dotnet-webapi/cqrs.md +63 -0
  216. package/assets/guardrails/technology/dotnet-webapi/data-classification.md +38 -0
  217. package/assets/guardrails/technology/dotnet-webapi/dependency-policy.md +40 -0
  218. package/assets/guardrails/technology/dotnet-webapi/domain-driven-design.md +91 -0
  219. package/assets/guardrails/technology/dotnet-webapi/eventing.md +57 -0
  220. package/assets/guardrails/technology/dotnet-webapi/examples/api-versioning.md +75 -0
  221. package/assets/guardrails/technology/dotnet-webapi/examples/auditing.md +84 -0
  222. package/assets/guardrails/technology/dotnet-webapi/examples/authorization.md +68 -0
  223. package/assets/guardrails/technology/dotnet-webapi/examples/clean-architecture.md +37 -0
  224. package/assets/guardrails/technology/dotnet-webapi/examples/cqrs.md +97 -0
  225. package/assets/guardrails/technology/dotnet-webapi/examples/domain-driven-design.md +141 -0
  226. package/assets/guardrails/technology/dotnet-webapi/examples/eventing.md +46 -0
  227. package/assets/guardrails/technology/dotnet-webapi/examples/persistence.md +207 -0
  228. package/assets/guardrails/technology/dotnet-webapi/examples/vertical-slices.md +151 -0
  229. package/assets/guardrails/technology/dotnet-webapi/examples/zero-trust.md +48 -0
  230. package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +61 -0
  231. package/assets/guardrails/technology/dotnet-webapi/modular-monolith.md +47 -0
  232. package/assets/guardrails/technology/dotnet-webapi/persistence.md +82 -0
  233. package/assets/guardrails/technology/dotnet-webapi/technology-constitution.md +162 -0
  234. package/assets/guardrails/technology/dotnet-webapi/testing.md +55 -0
  235. package/assets/guardrails/technology/dotnet-webapi/vertical-slices.md +70 -0
  236. package/assets/guardrails/technology/dotnet-webapi/zero-trust.md +48 -0
  237. package/assets/guardrails/technology/java-spring/README.md +62 -0
  238. package/assets/guardrails/technology/nextjs/accessibility-implementation.md +56 -0
  239. package/assets/guardrails/technology/nextjs/api-client.md +56 -0
  240. package/assets/guardrails/technology/nextjs/api-integration.dotnet-webapi.md +174 -0
  241. package/assets/guardrails/technology/nextjs/api-integration.java-spring.md +203 -0
  242. package/assets/guardrails/technology/nextjs/auth-session.md +68 -0
  243. package/assets/guardrails/technology/nextjs/client-security.md +69 -0
  244. package/assets/guardrails/technology/nextjs/component-architecture.md +60 -0
  245. package/assets/guardrails/technology/nextjs/component-conventions.md +58 -0
  246. package/assets/guardrails/technology/nextjs/design-system.md +60 -0
  247. package/assets/guardrails/technology/nextjs/error-handling.md +72 -0
  248. package/assets/guardrails/technology/nextjs/forms-and-validation.md +75 -0
  249. package/assets/guardrails/technology/nextjs/frontend-testing.md +94 -0
  250. package/assets/guardrails/technology/nextjs/i18n.md +57 -0
  251. package/assets/guardrails/technology/nextjs/observability.md +67 -0
  252. package/assets/guardrails/technology/nextjs/performance-budgets.md +66 -0
  253. package/assets/guardrails/technology/nextjs/routing-navigation.md +52 -0
  254. package/assets/guardrails/technology/nextjs/state-management.md +70 -0
  255. package/assets/guardrails/technology/nextjs/ui-constitution.md +166 -0
  256. package/package.json +1 -1
  257. package/assets/docs/pharma-constitution.my-ref.md +0 -86
@@ -0,0 +1,352 @@
1
+ #!/usr/bin/env python3
2
+ """validate_okf.py — conformance checker for OKF v0.1 bundles.
3
+
4
+ Implements OKF §9 conformance rules as ERRORs and the spec's soft
5
+ guidance as WARNINGs:
6
+
7
+ ERRORS (bundle is non-conformant):
8
+ E1 Non-reserved .md file has no parseable YAML frontmatter block, or
9
+ could not be read.
10
+ E2 Frontmatter lacks a non-empty `type` field.
11
+ E3 Reserved file structure violations:
12
+ - index.md with frontmatter anywhere except the bundle root
13
+ (root index.md may carry only okf_version per §11)
14
+ - log.md date headings not in ISO 8601 YYYY-MM-DD form (§7)
15
+ E4 log.md date block missing a required `Commit: \\`<sha>\\`` line, or
16
+ the line is present but not a valid hex commit SHA. This is an
17
+ ERROR because /speckit.okf.update depends on it to resume.
18
+
19
+ WARNINGS (consumers must tolerate; reported for quality):
20
+ W0 PyYAML not installed — using the lenient fallback parser.
21
+ W1 Missing recommended frontmatter (title, description).
22
+ W2 Broken bundle-internal links (may be not-yet-written knowledge).
23
+ W3 Directory containing concepts but no index.md.
24
+ W4 Concept body is empty.
25
+ W5 Possible secret-looking string in a file.
26
+ W6 A `source_files` / `ui_source_files` entry does not exist on disk (may be pending
27
+ reconciliation by /speckit.okf.update).
28
+ W7 Possible duplicate concept: another file shares the same
29
+ `type` + `title`.
30
+ W8 Concept has unresolved `open_questions` (run /speckit.okf.clarify).
31
+
32
+ Usage: validate_okf.py <bundle_dir> [--config PATH] [--exclude GLOB]...
33
+ [--repo-root PATH] [--json]
34
+ Exit code 0 if conformant (warnings allowed), 1 if non-conformant, 2 on
35
+ bad usage.
36
+
37
+ Only stdlib is required; PyYAML is used if available for stricter YAML
38
+ parsing, with a lenient fallback otherwise.
39
+ """
40
+
41
+ import argparse
42
+ import fnmatch
43
+ import json
44
+ import os
45
+ import re
46
+ import sys
47
+
48
+ try:
49
+ import yaml # type: ignore
50
+ HAVE_YAML = True
51
+ except ImportError:
52
+ HAVE_YAML = False
53
+
54
+ RESERVED = {"index.md", "log.md"}
55
+ DATE_HEADING = re.compile(r"^##\s+(\d{4}-\d{2}-\d{2})\s*$")
56
+ COMMIT_LINE = re.compile(r"^Commit:\s+`([0-9a-fA-F]{7,40})`\s*$")
57
+ LINK = re.compile(r"\[[^\]]*\]\(([^)]+)\)")
58
+ SECRET_PATTERNS = [
59
+ # key: "value" / key = 'value' (quoted)
60
+ re.compile(r"(?i)(api[_-]?key|secret|password|token)\s*[:=]\s*['\"][A-Za-z0-9+/_\-]{16,}['\"]"),
61
+ # key: value / key = value (unquoted)
62
+ re.compile(r"(?i)(api[_-]?key|secret|password|token)\s*[:=]\s*[A-Za-z0-9+/_\-]{16,}\b"),
63
+ # AWS-style access key ID
64
+ re.compile(r"\bAKIA[0-9A-Z]{16}\b"),
65
+ # PEM private key block start
66
+ re.compile(r"-----BEGIN (RSA |EC |OPENSSH |)PRIVATE KEY-----"),
67
+ ]
68
+
69
+ errors: list[str] = []
70
+ warnings: list[str] = []
71
+ concept_meta: list[tuple[str, str, str]] = [] # (rel, type, title)
72
+
73
+
74
+ def split_frontmatter(text: str):
75
+ """Return (frontmatter_str or None, body)."""
76
+ if not text.startswith("---"):
77
+ return None, text
78
+ parts = text.split("\n")
79
+ if parts[0].strip() != "---":
80
+ return None, text
81
+ for i in range(1, len(parts)):
82
+ if parts[i].strip() == "---":
83
+ return "\n".join(parts[1:i]), "\n".join(parts[i + 1:])
84
+ return None, text # unterminated block
85
+
86
+
87
+ def parse_yaml(fm: str):
88
+ """Parse frontmatter; return dict or None on failure."""
89
+ if HAVE_YAML:
90
+ try:
91
+ data = yaml.safe_load(fm)
92
+ return data if isinstance(data, dict) else None
93
+ except yaml.YAMLError:
94
+ return None
95
+ # Lenient fallback: top-level "key: value" lines only.
96
+ data = {}
97
+ for line in fm.splitlines():
98
+ if not line.strip() or line.startswith(("#", " ", "\t", "-")):
99
+ continue
100
+ if ":" not in line:
101
+ return None
102
+ k, _, v = line.partition(":")
103
+ data[k.strip()] = v.strip().strip("'\"")
104
+ return data
105
+
106
+
107
+ def read_text(path: str) -> tuple[str, None] | tuple[None, str]:
108
+ """Read a file as text; return (text, None) or (None, error_message)."""
109
+ try:
110
+ with open(path, encoding="utf-8", errors="replace") as f:
111
+ return f.read(), None
112
+ except OSError as e:
113
+ return None, str(e)
114
+
115
+
116
+ def check_concept(path: str, rel: str, bundle: str, repo_root: str):
117
+ text, err = read_text(path)
118
+ if text is None:
119
+ errors.append(f"E1 {rel}: could not read file ({err})")
120
+ return
121
+ fm, body = split_frontmatter(text)
122
+ if fm is None:
123
+ errors.append(f"E1 {rel}: missing or unterminated YAML frontmatter block")
124
+ return
125
+ data = parse_yaml(fm)
126
+ if data is None:
127
+ errors.append(f"E1 {rel}: frontmatter is not parseable YAML")
128
+ return
129
+ t = data.get("type")
130
+ if not (isinstance(t, str) and t.strip()):
131
+ errors.append(f"E2 {rel}: frontmatter has no non-empty `type` field")
132
+ for field in ("title", "description"):
133
+ if not data.get(field):
134
+ warnings.append(f"W1 {rel}: missing recommended field `{field}`")
135
+ if not body.strip():
136
+ warnings.append(f"W4 {rel}: concept body is empty")
137
+ check_links(body, rel, os.path.dirname(path), bundle)
138
+ check_source_files(data, rel, repo_root)
139
+ check_open_questions(data, rel)
140
+ if isinstance(t, str) and t.strip() and data.get("title"):
141
+ concept_meta.append((rel, t.strip(), str(data["title"]).strip()))
142
+ for pattern in SECRET_PATTERNS:
143
+ if pattern.search(text):
144
+ warnings.append(f"W5 {rel}: possible secret-looking value — review before sharing")
145
+ break
146
+
147
+
148
+ def check_source_files(data: dict, rel: str, repo_root: str):
149
+ # Both halves of the slice's file list get the same existence check — a stale UI
150
+ # path is exactly as misleading to a reverse step as a stale service one.
151
+ for key in ("source_files", "ui_source_files"):
152
+ sf = data.get(key)
153
+ if not isinstance(sf, list):
154
+ continue
155
+ for entry in sf:
156
+ if not isinstance(entry, str) or not entry.strip():
157
+ continue
158
+ candidate = os.path.join(repo_root, entry)
159
+ if not os.path.exists(candidate):
160
+ warnings.append(f"W6 {rel}: {key} entry '{entry}' does not exist")
161
+
162
+
163
+ def check_open_questions(data: dict, rel: str):
164
+ oq = data.get("open_questions")
165
+ if not isinstance(oq, list):
166
+ return
167
+ pending = [q for q in oq if isinstance(q, str) and q.strip()]
168
+ if pending:
169
+ n = len(pending)
170
+ warnings.append(
171
+ f"W8 {rel}: {n} unresolved open question{'s' if n != 1 else ''} "
172
+ f"— run /speckit.okf.clarify"
173
+ )
174
+
175
+
176
+ def check_links(body: str, rel: str, filedir: str, bundle: str):
177
+ for target in LINK.findall(body):
178
+ target = target.split("#")[0].strip()
179
+ if not target or "://" in target or target.startswith("mailto:"):
180
+ continue
181
+ if target.startswith("/"):
182
+ dest = os.path.join(bundle, target.lstrip("/"))
183
+ else:
184
+ dest = os.path.join(filedir, target)
185
+ # Directory links (progressive disclosure) are fine if the dir exists.
186
+ if not (os.path.exists(dest) or os.path.exists(dest.rstrip("/"))):
187
+ warnings.append(f"W2 {rel}: broken link -> {target}")
188
+
189
+
190
+ def check_index(path: str, rel: str, is_root: bool, bundle: str):
191
+ text, err = read_text(path)
192
+ if text is None:
193
+ errors.append(f"E1 {rel}: could not read file ({err})")
194
+ return
195
+ fm, body = split_frontmatter(text)
196
+ if fm is not None:
197
+ if not is_root:
198
+ errors.append(f"E3 {rel}: index.md must not contain frontmatter (only the bundle root may, per §11)")
199
+ else:
200
+ data = parse_yaml(fm) or {}
201
+ extra = set(data) - {"okf_version"}
202
+ if extra:
203
+ errors.append(f"E3 {rel}: root index.md frontmatter may only declare okf_version (found: {sorted(extra)})")
204
+ check_links(body if fm is not None else text, rel, os.path.dirname(path), bundle)
205
+
206
+
207
+ def check_log(path: str, rel: str):
208
+ text, err = read_text(path)
209
+ if text is None:
210
+ errors.append(f"E1 {rel}: could not read file ({err})")
211
+ return
212
+ lines = text.splitlines()
213
+ for i, ln in enumerate(lines):
214
+ if not ln.startswith("## "):
215
+ continue
216
+ stripped = ln.rstrip()
217
+ if not DATE_HEADING.match(stripped):
218
+ errors.append(f"E3 {rel}: log heading not ISO 8601 YYYY-MM-DD: '{stripped}'")
219
+ continue
220
+ # Look for a "Commit: `<sha>`" line before the next date heading.
221
+ found_sha = None
222
+ for j in range(i + 1, len(lines)):
223
+ if lines[j].startswith("## "):
224
+ break
225
+ m = COMMIT_LINE.match(lines[j].strip())
226
+ if m:
227
+ found_sha = m.group(1)
228
+ break
229
+ if found_sha is None:
230
+ errors.append(f"E4 {rel}: date block '{stripped}' missing required 'Commit: `<sha>`' line")
231
+
232
+
233
+ def find_repo_root(bundle: str) -> str:
234
+ p = bundle
235
+ while True:
236
+ if os.path.isdir(os.path.join(p, ".git")):
237
+ return p
238
+ parent = os.path.dirname(p)
239
+ if parent == p:
240
+ return os.path.dirname(bundle)
241
+ p = parent
242
+
243
+
244
+ def load_config_excludes(path: str) -> list[str]:
245
+ if not path or not os.path.isfile(path):
246
+ return []
247
+ text, err = read_text(path)
248
+ if err is not None or text is None:
249
+ return []
250
+ if HAVE_YAML:
251
+ try:
252
+ data = yaml.safe_load(text) or {}
253
+ except yaml.YAMLError:
254
+ return []
255
+ excl = (data.get("okf") or {}).get("exclude") or []
256
+ return [str(x) for x in excl if isinstance(x, str)]
257
+ # Lenient fallback: scan for an `exclude:` block of `- "glob"` lines.
258
+ globs = []
259
+ in_exclude = False
260
+ for line in text.splitlines():
261
+ stripped = line.strip()
262
+ if re.match(r"^exclude\s*:\s*$", stripped):
263
+ in_exclude = True
264
+ continue
265
+ if in_exclude:
266
+ m = re.match(r"^-\s*['\"]?([^'\"#]+)['\"]?\s*(#.*)?$", stripped)
267
+ if m:
268
+ globs.append(m.group(1).strip())
269
+ continue
270
+ if stripped and not stripped.startswith("#"):
271
+ in_exclude = False
272
+ return globs
273
+
274
+
275
+ def is_excluded(rel: str, patterns: list[str]) -> bool:
276
+ return any(fnmatch.fnmatch(rel, pat) for pat in patterns)
277
+
278
+
279
+ def main() -> int:
280
+ parser = argparse.ArgumentParser(
281
+ description="Conformance checker for OKF v0.1 knowledge bundles.",
282
+ )
283
+ parser.add_argument("bundle_dir", help="Path to the knowledge bundle directory")
284
+ parser.add_argument("--config", help="Path to okf-config.yml (exclude list is honored)")
285
+ parser.add_argument("--exclude", action="append", default=[], help="Glob to exclude (repeatable)")
286
+ parser.add_argument("--repo-root", help="Repo root for resolving source_files (default: nearest .git above bundle_dir)")
287
+ parser.add_argument("--json", action="store_true", help="Emit machine-readable JSON instead of text")
288
+ args = parser.parse_args()
289
+
290
+ if not os.path.isdir(args.bundle_dir):
291
+ parser.error(f"{args.bundle_dir} is not a directory")
292
+
293
+ bundle = os.path.abspath(args.bundle_dir)
294
+ repo_root = os.path.abspath(args.repo_root) if args.repo_root else find_repo_root(bundle)
295
+ exclude_patterns = load_config_excludes(args.config) + list(args.exclude)
296
+
297
+ if not HAVE_YAML:
298
+ warnings.append("W0 (global): PyYAML not installed — using lenient fallback parser, results may be less strict")
299
+
300
+ concepts = 0
301
+ for dirpath, dirnames, filenames in os.walk(bundle):
302
+ dirnames[:] = [d for d in dirnames if not d.startswith(".")]
303
+ rel_dir = os.path.relpath(dirpath, bundle)
304
+ mds = [
305
+ f for f in filenames
306
+ if f.endswith(".md") and not is_excluded(
307
+ os.path.relpath(os.path.join(dirpath, f), bundle), exclude_patterns
308
+ )
309
+ ]
310
+ if any(f not in RESERVED for f in mds) and "index.md" not in mds:
311
+ warnings.append(f"W3 {rel_dir or '.'}: directory has concepts but no index.md")
312
+ for f in mds:
313
+ path = os.path.join(dirpath, f)
314
+ rel = os.path.relpath(path, bundle)
315
+ if f == "index.md":
316
+ check_index(path, rel, dirpath == bundle, bundle)
317
+ elif f == "log.md":
318
+ check_log(path, rel)
319
+ else:
320
+ concepts += 1
321
+ check_concept(path, rel, bundle, repo_root)
322
+
323
+ # W7: duplicate (type, title) pairs across the bundle.
324
+ seen: dict[tuple[str, str], str] = {}
325
+ for rel, t, title in concept_meta:
326
+ key = (t.lower(), title.lower())
327
+ if key in seen:
328
+ warnings.append(f"W7 {rel}: possible duplicate concept — same type+title as {seen[key]}")
329
+ else:
330
+ seen[key] = rel
331
+
332
+ if args.json:
333
+ print(json.dumps({
334
+ "concepts": concepts,
335
+ "errors": errors,
336
+ "warnings": warnings,
337
+ "result": "NON-CONFORMANT" if errors else "CONFORMANT",
338
+ }, indent=2))
339
+ else:
340
+ print(f"OKF validation of {bundle}")
341
+ print(f" concepts: {concepts} errors: {len(errors)} warnings: {len(warnings)}\n")
342
+ for e in errors:
343
+ print(f" ERROR {e}")
344
+ for w in warnings:
345
+ print(f" WARNING {w}")
346
+ print("\nRESULT:", "NON-CONFORMANT" if errors else "CONFORMANT (OKF v0.1)")
347
+
348
+ return 1 if errors else 0
349
+
350
+
351
+ if __name__ == "__main__":
352
+ sys.exit(main())
@@ -0,0 +1,16 @@
1
+ {
2
+ "id": "angular",
3
+ "kind": "frontend",
4
+ "title": "Angular",
5
+ "language": "TypeScript",
6
+ "ecosystem": "node",
7
+ "root": "web/",
8
+ "run_from": "root",
9
+ "build": "npm run build",
10
+ "test": "npm test",
11
+ "run": "npm start",
12
+ "prototype_run": "npm start --prefix prototype",
13
+ "detect": [
14
+ "web/angular.json"
15
+ ]
16
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "id": "blazor-wasm",
3
+ "kind": "frontend",
4
+ "title": "Blazor WebAssembly",
5
+ "language": "C#",
6
+ "ecosystem": "dotnet",
7
+ "root": "web/",
8
+ "run_from": "root",
9
+ "build": "dotnet build",
10
+ "test": "dotnet test",
11
+ "run": "dotnet run",
12
+ "prototype_run": "dotnet run --project prototype/",
13
+ "detect": [
14
+ "web/**/*.csproj",
15
+ "web/**/wwwroot/index.html"
16
+ ]
17
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "dotnet-webapi",
3
+ "kind": "backend",
4
+ "title": "ASP.NET Core Web API",
5
+ "language": "C#",
6
+ "ecosystem": "dotnet",
7
+ "root": "src/",
8
+ "build": "dotnet build",
9
+ "test": "dotnet test",
10
+ "run": "dotnet run --project {{root}}",
11
+ "detect": [
12
+ "*.sln",
13
+ "src/**/*.csproj"
14
+ ]
15
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "id": "go-chi",
3
+ "kind": "backend",
4
+ "title": "Go + chi",
5
+ "language": "Go",
6
+ "ecosystem": "go",
7
+ "root": "internal/",
8
+ "build": "go build ./...",
9
+ "test": "go test ./...",
10
+ "run": "go run ./cmd/api",
11
+ "detect": [
12
+ "go.mod"
13
+ ]
14
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "id": "java-spring",
3
+ "kind": "backend",
4
+ "title": "Spring Boot",
5
+ "language": "Java",
6
+ "ecosystem": "java",
7
+ "root": "src/main/java/",
8
+ "run_from": "root",
9
+ "build": "./mvnw package -DskipTests",
10
+ "test": "./mvnw test",
11
+ "run": "./mvnw spring-boot:run",
12
+ "detect": [
13
+ "pom.xml",
14
+ "build.gradle"
15
+ ]
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "id": "nextjs",
3
+ "kind": "frontend",
4
+ "title": "Next.js",
5
+ "language": "TypeScript",
6
+ "ecosystem": "node",
7
+ "root": "web/",
8
+ "run_from": "root",
9
+ "build": "npm run build",
10
+ "test": "npm test",
11
+ "run": "npm run dev",
12
+ "prototype_run": "npm run dev --prefix prototype",
13
+ "detect": [
14
+ "web/next.config.*"
15
+ ]
16
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "node-express",
3
+ "kind": "backend",
4
+ "title": "Express + TypeScript",
5
+ "language": "Node.js",
6
+ "ecosystem": "node",
7
+ "root": "src/",
8
+ "build": "npm run build",
9
+ "test": "npm test",
10
+ "run": "npm run dev",
11
+ "detect": [
12
+ "package.json",
13
+ "src/**/*.ts"
14
+ ]
15
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "id": "python-fastapi",
3
+ "kind": "backend",
4
+ "title": "FastAPI",
5
+ "language": "Python",
6
+ "ecosystem": "python",
7
+ "root": "app/",
8
+ "build": "python -m compileall {{root}}",
9
+ "test": "pytest",
10
+ "run": "uvicorn app.main:app --reload",
11
+ "detect": [
12
+ "pyproject.toml",
13
+ "requirements.txt",
14
+ "app/main.py"
15
+ ]
16
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "id": "react-vite",
3
+ "kind": "frontend",
4
+ "title": "React + Vite",
5
+ "language": "TypeScript",
6
+ "ecosystem": "node",
7
+ "root": "web/",
8
+ "run_from": "root",
9
+ "build": "npm run build",
10
+ "test": "npm test",
11
+ "run": "npm run dev",
12
+ "prototype_run": "npm run dev --prefix prototype",
13
+ "detect": [
14
+ "web/package.json",
15
+ "web/vite.config.*"
16
+ ]
17
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "id": "sveltekit",
3
+ "kind": "frontend",
4
+ "title": "SvelteKit",
5
+ "language": "TypeScript",
6
+ "ecosystem": "node",
7
+ "root": "web/",
8
+ "run_from": "root",
9
+ "build": "npm run build",
10
+ "test": "npm test",
11
+ "run": "npm run dev",
12
+ "prototype_run": "npm run dev --prefix prototype",
13
+ "detect": [
14
+ "web/svelte.config.*"
15
+ ]
16
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "id": "vue-vite",
3
+ "kind": "frontend",
4
+ "title": "Vue 3 + Vite",
5
+ "language": "TypeScript",
6
+ "ecosystem": "node",
7
+ "root": "web/",
8
+ "run_from": "root",
9
+ "build": "npm run build",
10
+ "test": "npm test",
11
+ "run": "npm run dev",
12
+ "prototype_run": "npm run dev --prefix prototype",
13
+ "detect": [
14
+ "web/vite.config.*",
15
+ "web/src/App.vue"
16
+ ]
17
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "lanes": []
3
+ }
@@ -0,0 +1,116 @@
1
+ # [PROJECT_NAME] Constitution — [DOMAIN_NAME] Addenda
2
+ <!--
3
+ AppWeaver split-constitution model. This is the DOMAIN half — the domain
4
+ addenda derived from the set mapped under "## /aw-spec-constitution" in the project's
5
+ domain-rule-bindings.md: the mapped industry corpus's domain-constitution.md, the STANDARD
6
+ industry rules beside it, and the project team's own domain/domain-requirements.md. In a
7
+ project reverse-engineered by `onboard` that map points at the project's OWN generated
8
+ domain rule files and its own charter, both derived from the code — same partition, a
9
+ different corpus. It carries ONLY domain-specific material:
10
+ the domain principles, domain identifiers/terminology, regulatory regime,
11
+ interoperability surfaces, and domain governance overrides.
12
+
13
+ ══ THIS FILE IS SHAPE. THE MAPPED CORPUS IS CONTENT. ═════════════════════════════
14
+ This template is part of the kit and governs projects in any industry. It therefore
15
+ names NO industry, regulation, terminology system, identifier or modelling methodology
16
+ anywhere — deliberately. An example that named one would be a suggestion, and a
17
+ suggestion in a template becomes ratified law in a domain it does not fit.
18
+
19
+ Take the principles — their SUBJECTS, their WORDING, their ORDER and their COUNT —
20
+ from the mapped domain rule files and the charter they are headed by. The three slots
21
+ below are a scaffold, not a set.
22
+ ═══════════════════════════════════════════════════════════════════════════════════
23
+
24
+ It EXTENDS the paired constitution.technical.md — it does not restate that half's
25
+ technical principles or the base governance; it references them and adds the domain
26
+ layer on top.
27
+
28
+ Loading policy: this file is a SPECIFY-only standing input and a GATE checklist.
29
+ It is deliberately NOT loaded by design or implement — domain reaches those
30
+ phases only through the spec.
31
+
32
+ THIN AUTHORITY: each principle is ONE declarative, testable line + a pointer to its
33
+ rule doc. Do NOT restate the rule doc's detail here — this file says WHICH domain rules
34
+ are supreme/non-negotiable and adopted; the domain docs (also loaded in specify) carry
35
+ the detail. That keeps the authority/detail overlap to one line.
36
+ -->
37
+
38
+ ## Adopted Modelling Standard
39
+
40
+ [MODELLING_STANDARD_STATEMENT]
41
+ <!--
42
+ Form: ONE thin authority line naming the domain-modelling methodology this project has
43
+ ratified, the principle of the technical half that mandates it CITED BY ITS ACTUAL
44
+ NUMERAL, and the rule docs that carry the method.
45
+
46
+ READ constitution.technical.md (in context) to find that numeral. It is a property of
47
+ this project's technology base and differs between projects — never a fixed number, and
48
+ never assumed from another project's constitution. If the technical half mandates no
49
+ modelling methodology, say exactly that instead of inventing one.
50
+
51
+ This section exists because specify loads THIS file and not constitution.technical, so
52
+ this line is the only way the modelling mandate reaches specify at all. State the
53
+ mandate and point at the docs; do not restate the method itself — the rule docs are
54
+ loaded in specify alongside this file.
55
+ -->
56
+
57
+ ## Domain Principles
58
+ <!--
59
+ Numbered to CONTINUE the technical half: start at the number FOLLOWING its last
60
+ principle. Read constitution.technical.md (in context) to find that number — it is
61
+ whatever the mapped technology base ended on, not a fixed value. A base ending at XII
62
+ makes the first domain principle XIII; one ending at XXVI makes it XXVII. Numbering
63
+ runs unbroken across the two halves: no gap, no restart, no number used by both.
64
+
65
+ Where constitution.technical.md is ABSENT, the project declared no service lane and
66
+ there is no technical half: this half OPENS the sequence at I. That is a complete
67
+ constitution for a UI-only project, not a broken one — the lane that would have
68
+ ratified a technology base does not exist, and the UI half runs its own UX-* series
69
+ alongside. Say so in the Sync Impact Report so the gap is visible rather than guessed.
70
+ -->
71
+
72
+ ### [DOMAIN_PRINCIPLE_1_NAME]
73
+ <!-- Form: "<next numeral>. <the domain concern this rule governs> (NON-NEGOTIABLE)".
74
+ Title by the CONCERN, never by a feature or an aggregate name. -->
75
+ [DOMAIN_PRINCIPLE_1_DESCRIPTION]
76
+ <!-- Form: ONE declarative, testable sentence stating what the domain mandates, the
77
+ technical principle it EXTENDS (by that principle's actual numeral), and a pointer
78
+ to the rule file that carries the detail. -->
79
+
80
+ ### [DOMAIN_PRINCIPLE_2_NAME]
81
+ [DOMAIN_PRINCIPLE_2_DESCRIPTION]
82
+
83
+ ### [DOMAIN_PRINCIPLE_3_NAME]
84
+ <!-- Form: continue one '### ' block per principle the mapped domain rules actually
85
+ state, then stop. Do not import a domain rule the mapped set does not carry. -->
86
+ [DOMAIN_PRINCIPLE_3_DESCRIPTION]
87
+
88
+ ## Domain Folder Additions
89
+
90
+ [FOLDER_ADDITIONS_CONTENT]
91
+ <!-- Form: only the structural ADDITIONS this domain requires on top of the base layout
92
+ in constitution.technical.md, with a pointer to the rule file that defines them; or
93
+ "none beyond the base". -->
94
+
95
+ ## Regulatory Posture & Security Addenda
96
+
97
+ [REGULATORY_POSTURE_CONTENT]
98
+ <!-- Form: the regulatory regime this domain operates under, its data-integrity and
99
+ retention expectations, its identifier / terminology / interoperability alignment,
100
+ and its data classification — each as a thin adopted line citing the rule file that
101
+ carries it. Take every one of these from the mapped rules; a domain with no
102
+ regulatory regime says so. -->
103
+
104
+ ## Domain Governance Overrides
105
+ <!-- Extends the Governance section of constitution.technical.md with domain-specific
106
+ change authority. -->
107
+
108
+ [DOMAIN_GOVERNANCE_CONTENT]
109
+ <!-- Form: who must approve a change to a domain identifier / classification / lifecycle
110
+ rule, who owns each bounded context, the review cadence, and the exception process.
111
+ The base amendment procedure + SemVer policy in constitution.technical.md still
112
+ apply and are not restated here. -->
113
+
114
+ **Version**: [CONSTITUTION_VERSION] | **Ratified**: [RATIFICATION_DATE] | **Last Amended**: [LAST_AMENDED_DATE]
115
+ <!-- ISO YYYY-MM-DD dates. Versions INDEPENDENTLY of constitution.technical.md — a change
116
+ to the domain's rules bumps this file only. -->