aw-spec-cli 0.1.5 → 0.1.7

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 (205) hide show
  1. package/assets/.agents/agent.json +1 -1
  2. package/assets/.agents/skills/{aw-spec-orch → appweaver}/SKILL.md +10 -10
  3. package/assets/.agents/skills/{aw-spec-orch-demo → appweaver-demo}/SKILL.md +9 -9
  4. package/assets/.claude/agent.json +1 -1
  5. package/assets/.claude/skills/{aw-spec-orch → appweaver}/SKILL.md +10 -10
  6. package/assets/.claude/skills/{aw-spec-orch-demo → appweaver-demo}/SKILL.md +9 -9
  7. package/assets/.kilocode/agent.json +1 -1
  8. package/assets/.kilocode/workflows/{aw-spec-orch-demo.md → appweaver-demo.md} +9 -9
  9. package/assets/.kilocode/workflows/{aw-spec-orch.md → appweaver.md} +10 -10
  10. package/assets/docs/pharma-constitution.my-ref.md +86 -0
  11. package/dist/utils/paths.js +1 -1
  12. package/dist/utils/paths.js.map +1 -1
  13. package/package.json +1 -1
  14. package/assets/.aw-spec/DESIGN-FORMAT.md +0 -151
  15. package/assets/.aw-spec/ORCH-DIALECT.md +0 -156
  16. package/assets/.aw-spec/RULE-PARTITION.md +0 -126
  17. package/assets/.aw-spec/domain.json +0 -3
  18. package/assets/.aw-spec/extensions/.registry +0 -19
  19. package/assets/.aw-spec/extensions/agent-context/README.md +0 -57
  20. package/assets/.aw-spec/extensions/agent-context/agent-context-config.yml +0 -4
  21. package/assets/.aw-spec/extensions/agent-context/commands/aw-spec.agent-context.update.md +0 -26
  22. package/assets/.aw-spec/extensions/agent-context/extension.yml +0 -37
  23. package/assets/.aw-spec/extensions/agent-context/scripts/bash/update-agent-context.sh +0 -201
  24. package/assets/.aw-spec/extensions/agent-context/scripts/powershell/update-agent-context.ps1 +0 -237
  25. package/assets/.aw-spec/extensions.yml +0 -16
  26. package/assets/.aw-spec/feature.json +0 -3
  27. package/assets/.aw-spec/init-options.json +0 -9
  28. package/assets/.aw-spec/integration.json +0 -15
  29. package/assets/.aw-spec/integrations/aw-spec.manifest.json +0 -9
  30. package/assets/.aw-spec/interpreter/run-skill.py +0 -1158
  31. package/assets/.aw-spec/memory/constitution.md +0 -50
  32. package/assets/.aw-spec/orchestrator/AGENT-PROFILE.md +0 -94
  33. package/assets/.aw-spec/orchestrator/README.md +0 -300
  34. package/assets/.aw-spec/orchestrator/adapters/claude_agent_sdk.py +0 -74
  35. package/assets/.aw-spec/orchestrator/adapters/google_antigravity.py +0 -74
  36. package/assets/.aw-spec/orchestrator/modules/delta-design.orch.yaml +0 -105
  37. package/assets/.aw-spec/orchestrator/modules/delta-spec.orch.yaml +0 -79
  38. package/assets/.aw-spec/orchestrator/modules/domain-select.orch.yaml +0 -81
  39. package/assets/.aw-spec/orchestrator/modules/tech-select.orch.yaml +0 -75
  40. package/assets/.aw-spec/orchestrator/orchestrator.py +0 -1721
  41. package/assets/.aw-spec/orchestrator/rev-templates/ai-rules.reference.md +0 -40
  42. package/assets/.aw-spec/orchestrator/rev-templates/comandrulemap.skeleton.md +0 -59
  43. package/assets/.aw-spec/orchestrator/rev-templates/commandtechrulemap.skeleton.md +0 -97
  44. package/assets/.aw-spec/orchestrator/rev-templates/domain-constitution.skeleton.md +0 -61
  45. package/assets/.aw-spec/orchestrator/rev-templates/domain-requirements.skeleton.md +0 -48
  46. package/assets/.aw-spec/orchestrator/rev-templates/domain-rule-file.skeleton.md +0 -39
  47. package/assets/.aw-spec/orchestrator/rev-templates/technical-constitution.skeleton.md +0 -106
  48. package/assets/.aw-spec/orchestrator/rev-templates/technical-rule-file.skeleton.md +0 -54
  49. package/assets/.aw-spec/orchestrator/workflows/_smoke.orch.yaml +0 -160
  50. package/assets/.aw-spec/orchestrator/workflows/aw-spec-add-component.orch.yaml +0 -244
  51. package/assets/.aw-spec/orchestrator/workflows/aw-spec-adopt.orch.yaml +0 -775
  52. package/assets/.aw-spec/orchestrator/workflows/aw-spec-analyze-delta-design.orch.yaml +0 -248
  53. package/assets/.aw-spec/orchestrator/workflows/aw-spec-analyze-design.orch.yaml +0 -261
  54. package/assets/.aw-spec/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +0 -425
  55. package/assets/.aw-spec/orchestrator/workflows/aw-spec-build.orch.yaml +0 -188
  56. package/assets/.aw-spec/orchestrator/workflows/aw-spec-characterize.orch.yaml +0 -474
  57. package/assets/.aw-spec/orchestrator/workflows/aw-spec-close-delta.orch.yaml +0 -181
  58. package/assets/.aw-spec/orchestrator/workflows/aw-spec-constitution.orch.yaml +0 -284
  59. package/assets/.aw-spec/orchestrator/workflows/aw-spec-demo.orch.yaml +0 -103
  60. package/assets/.aw-spec/orchestrator/workflows/aw-spec-dependency-tree.orch.yaml +0 -69
  61. package/assets/.aw-spec/orchestrator/workflows/aw-spec-deploy.orch.yaml +0 -85
  62. package/assets/.aw-spec/orchestrator/workflows/aw-spec-design.orch.yaml +0 -382
  63. package/assets/.aw-spec/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +0 -382
  64. package/assets/.aw-spec/orchestrator/workflows/aw-spec-foundation.orch.yaml +0 -246
  65. package/assets/.aw-spec/orchestrator/workflows/aw-spec-implement-delta.orch.yaml +0 -231
  66. package/assets/.aw-spec/orchestrator/workflows/aw-spec-implement.orch.yaml +0 -258
  67. package/assets/.aw-spec/orchestrator/workflows/aw-spec-inventory.orch.yaml +0 -236
  68. package/assets/.aw-spec/orchestrator/workflows/aw-spec-onboard.orch.yaml +0 -949
  69. package/assets/.aw-spec/orchestrator/workflows/aw-spec-parity.orch.yaml +0 -293
  70. package/assets/.aw-spec/orchestrator/workflows/aw-spec-run.orch.yaml +0 -177
  71. package/assets/.aw-spec/orchestrator/workflows/aw-spec-select-domain.orch.yaml +0 -79
  72. package/assets/.aw-spec/orchestrator/workflows/aw-spec-select-feature.orch.yaml +0 -128
  73. package/assets/.aw-spec/orchestrator/workflows/aw-spec-specify.orch.yaml +0 -412
  74. package/assets/.aw-spec/scripts/bash/aw-inventory.sh +0 -14
  75. package/assets/.aw-spec/scripts/bash/aw-parity.sh +0 -13
  76. package/assets/.aw-spec/scripts/bash/aw-rev-constitution.sh +0 -13
  77. package/assets/.aw-spec/scripts/bash/aw-spec-actions.sh +0 -1899
  78. package/assets/.aw-spec/scripts/bash/aw-xref.sh +0 -15
  79. package/assets/.aw-spec/scripts/bash/common.sh +0 -533
  80. package/assets/.aw-spec/scripts/powershell/aw-inventory.ps1 +0 -14
  81. package/assets/.aw-spec/scripts/powershell/aw-parity.ps1 +0 -13
  82. package/assets/.aw-spec/scripts/powershell/aw-rev-constitution.ps1 +0 -13
  83. package/assets/.aw-spec/scripts/powershell/aw-spec-actions.ps1 +0 -1563
  84. package/assets/.aw-spec/scripts/powershell/aw-xref.ps1 +0 -15
  85. package/assets/.aw-spec/scripts/python/aw-inventory.py +0 -683
  86. package/assets/.aw-spec/scripts/python/aw-parity.py +0 -380
  87. package/assets/.aw-spec/scripts/python/aw-rev-constitution.py +0 -312
  88. package/assets/.aw-spec/scripts/python/aw-xref.py +0 -1330
  89. package/assets/.aw-spec/scripts/python/validate_okf.py +0 -349
  90. package/assets/.aw-spec/templates/constitution-domain-template.md +0 -75
  91. package/assets/.aw-spec/templates/constitution-technical-template.md +0 -70
  92. package/assets/.aw-spec/templates/delta-design-template.md +0 -69
  93. package/assets/.aw-spec/templates/delta-spec-template.md +0 -60
  94. package/assets/.aw-spec/templates/design-template.md +0 -383
  95. package/assets/.aw-spec/templates/okf-concept-template.md +0 -103
  96. package/assets/.aw-spec/templates/parity-manifest-template.json +0 -49
  97. package/assets/.aw-spec/templates/source-map-template.md +0 -85
  98. package/assets/.aw-spec/templates/spec-template.md +0 -252
  99. package/assets/docs/ModularMonolith/ModularMonolith.Reference.pack.txt +0 -25248
  100. package/assets/docs/ModularMonolith/ModularMonolith.pack.txt +0 -5726
  101. package/assets/docs/ModularMonolith/pack-foundation.ps1 +0 -145
  102. package/assets/docs/ModularMonolith/pack-foundation.sh +0 -196
  103. package/assets/docs/ModularMonolith/pack-reference-foundation.ps1 +0 -157
  104. package/assets/docs/ModularMonolith/pack-reference-foundation.sh +0 -209
  105. package/assets/docs/ModularMonolith/unpack-foundation.ps1 +0 -126
  106. package/assets/docs/ModularMonolith/unpack-foundation.sh +0 -217
  107. package/assets/docs/ModularMonolith/unpack-reference-foundation.ps1 +0 -129
  108. package/assets/docs/ModularMonolith/unpack-reference-foundation.sh +0 -218
  109. package/assets/docs/README.md +0 -106
  110. package/assets/docs/VerticalSlice/PACKAGING.md +0 -185
  111. package/assets/docs/VerticalSlice/VerticalSlice.Reference.pack.txt +0 -19318
  112. package/assets/docs/VerticalSlice/VerticalSlice.pack.txt +0 -2833
  113. package/assets/docs/VerticalSlice/pack-foundation.ps1 +0 -145
  114. package/assets/docs/VerticalSlice/pack-foundation.sh +0 -196
  115. package/assets/docs/VerticalSlice/pack-reference-foundation.ps1 +0 -157
  116. package/assets/docs/VerticalSlice/pack-reference-foundation.sh +0 -209
  117. package/assets/docs/VerticalSlice/unpack-foundation.ps1 +0 -126
  118. package/assets/docs/VerticalSlice/unpack-foundation.sh +0 -217
  119. package/assets/docs/VerticalSlice/unpack-reference-foundation.ps1 +0 -129
  120. package/assets/docs/VerticalSlice/unpack-reference-foundation.sh +0 -218
  121. package/assets/docs/architecture/clean-architecture.md +0 -71
  122. package/assets/docs/architecture/cqrs.md +0 -141
  123. package/assets/docs/architecture/eventing.md +0 -83
  124. package/assets/docs/architecture/folder-structure.md +0 -61
  125. package/assets/docs/architecture/modular-monolith.md +0 -47
  126. package/assets/docs/architecture/persistence.md +0 -269
  127. package/assets/docs/architecture/testing.md +0 -55
  128. package/assets/docs/architecture/vertical-slices.md +0 -201
  129. package/assets/docs/components/Email/README.md +0 -119
  130. package/assets/docs/components/Email/ReferenceEndpoints/SendEmailEndpoint.cs +0 -84
  131. package/assets/docs/components/Email/integration.md +0 -300
  132. package/assets/docs/components/Jobs/README.md +0 -113
  133. package/assets/docs/components/Jobs/integration.md +0 -259
  134. package/assets/docs/components/QrGenerator/README.md +0 -85
  135. package/assets/docs/components/QrGenerator/ReferenceEndpoints/GenerateQrEndpoint.cs +0 -57
  136. package/assets/docs/components/QrGenerator/integration.md +0 -230
  137. package/assets/docs/components/README.md +0 -74
  138. package/assets/docs/domain/domain-driven-design.md +0 -212
  139. package/assets/docs/domainspecs/healthcare/ai-rules.domain.md +0 -34
  140. package/assets/docs/domainspecs/healthcare/api-versioning.domain.md +0 -17
  141. package/assets/docs/domainspecs/healthcare/auditing.domain.md +0 -97
  142. package/assets/docs/domainspecs/healthcare/authorization.domain.md +0 -26
  143. package/assets/docs/domainspecs/healthcare/clinical-terms.md +0 -20
  144. package/assets/docs/domainspecs/healthcare/coding-standards.domain.md +0 -26
  145. package/assets/docs/domainspecs/healthcare/comandrulemap.md +0 -100
  146. package/assets/docs/domainspecs/healthcare/commandtechrulemap.md +0 -119
  147. package/assets/docs/domainspecs/healthcare/consent.md +0 -19
  148. package/assets/docs/domainspecs/healthcare/cqrs.domain.md +0 -12
  149. package/assets/docs/domainspecs/healthcare/data-classification.domain.md +0 -28
  150. package/assets/docs/domainspecs/healthcare/dependency-policy.domain.md +0 -11
  151. package/assets/docs/domainspecs/healthcare/dicom.md +0 -15
  152. package/assets/docs/domainspecs/healthcare/domain-driven-design.domain.md +0 -28
  153. package/assets/docs/domainspecs/healthcare/domain-requirements.md +0 -55
  154. package/assets/docs/domainspecs/healthcare/eventing.domain.md +0 -18
  155. package/assets/docs/domainspecs/healthcare/fhir.md +0 -36
  156. package/assets/docs/domainspecs/healthcare/folder-structure.domain.md +0 -23
  157. package/assets/docs/domainspecs/healthcare/hipaa.md +0 -34
  158. package/assets/docs/domainspecs/healthcare/hl7.md +0 -15
  159. package/assets/docs/domainspecs/healthcare/integration-terms.md +0 -21
  160. package/assets/docs/domainspecs/healthcare/persistence.domain.md +0 -20
  161. package/assets/docs/domainspecs/healthcare/terminology.md +0 -30
  162. package/assets/docs/domainspecs/healthcare/testing.domain.md +0 -15
  163. package/assets/docs/domainspecs/healthcare/vertical-slices.domain.md +0 -18
  164. package/assets/docs/domainspecs/healthcare/zero-trust.domain.md +0 -12
  165. package/assets/docs/domainspecs/pharma/ai-rules.domain.md +0 -32
  166. package/assets/docs/domainspecs/pharma/api-versioning.domain.md +0 -20
  167. package/assets/docs/domainspecs/pharma/atc.md +0 -22
  168. package/assets/docs/domainspecs/pharma/auditing.domain.md +0 -90
  169. package/assets/docs/domainspecs/pharma/authorization.domain.md +0 -25
  170. package/assets/docs/domainspecs/pharma/coding-standards.domain.md +0 -28
  171. package/assets/docs/domainspecs/pharma/comandrulemap.md +0 -108
  172. package/assets/docs/domainspecs/pharma/commandtechrulemap.md +0 -119
  173. package/assets/docs/domainspecs/pharma/cqrs.domain.md +0 -16
  174. package/assets/docs/domainspecs/pharma/data-classification.domain.md +0 -24
  175. package/assets/docs/domainspecs/pharma/data-provenance.md +0 -21
  176. package/assets/docs/domainspecs/pharma/dependency-policy.domain.md +0 -11
  177. package/assets/docs/domainspecs/pharma/domain-driven-design.domain.md +0 -36
  178. package/assets/docs/domainspecs/pharma/domain-requirements.md +0 -99
  179. package/assets/docs/domainspecs/pharma/eventing.domain.md +0 -18
  180. package/assets/docs/domainspecs/pharma/fhir.md +0 -31
  181. package/assets/docs/domainspecs/pharma/folder-structure.domain.md +0 -24
  182. package/assets/docs/domainspecs/pharma/hl7.md +0 -17
  183. package/assets/docs/domainspecs/pharma/idmp.md +0 -26
  184. package/assets/docs/domainspecs/pharma/integration-terms.md +0 -21
  185. package/assets/docs/domainspecs/pharma/ndc.md +0 -28
  186. package/assets/docs/domainspecs/pharma/persistence.domain.md +0 -23
  187. package/assets/docs/domainspecs/pharma/pharma-terms.md +0 -27
  188. package/assets/docs/domainspecs/pharma/product-lifecycle.domain.md +0 -30
  189. package/assets/docs/domainspecs/pharma/regulatory-compliance.md +0 -19
  190. package/assets/docs/domainspecs/pharma/terminology.md +0 -32
  191. package/assets/docs/domainspecs/pharma/testing.domain.md +0 -19
  192. package/assets/docs/domainspecs/pharma/vertical-slices.domain.md +0 -17
  193. package/assets/docs/domainspecs/pharma/zero-trust.domain.md +0 -12
  194. package/assets/docs/glossary/ai-rules.md +0 -59
  195. package/assets/docs/governance/api-versioning.md +0 -99
  196. package/assets/docs/governance/coding-standards.md +0 -87
  197. package/assets/docs/governance/dependency-policy.md +0 -40
  198. package/assets/docs/interop/ihe-conformance.md +0 -31
  199. package/assets/docs/requirement-spec.txt +0 -27
  200. package/assets/docs/security/auditing.md +0 -160
  201. package/assets/docs/security/authorization-matrix.md +0 -14
  202. package/assets/docs/security/authorization.md +0 -87
  203. package/assets/docs/security/data-classification.md +0 -38
  204. package/assets/docs/security/zero-trust.md +0 -76
  205. package/assets/docs/technology-constitution.md +0 -172
@@ -1,349 +0,0 @@
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` 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
- sf = data.get("source_files")
150
- if not isinstance(sf, list):
151
- return
152
- for entry in sf:
153
- if not isinstance(entry, str) or not entry.strip():
154
- continue
155
- candidate = os.path.join(repo_root, entry)
156
- if not os.path.exists(candidate):
157
- warnings.append(f"W6 {rel}: source_files entry '{entry}' does not exist")
158
-
159
-
160
- def check_open_questions(data: dict, rel: str):
161
- oq = data.get("open_questions")
162
- if not isinstance(oq, list):
163
- return
164
- pending = [q for q in oq if isinstance(q, str) and q.strip()]
165
- if pending:
166
- n = len(pending)
167
- warnings.append(
168
- f"W8 {rel}: {n} unresolved open question{'s' if n != 1 else ''} "
169
- f"— run /speckit.okf.clarify"
170
- )
171
-
172
-
173
- def check_links(body: str, rel: str, filedir: str, bundle: str):
174
- for target in LINK.findall(body):
175
- target = target.split("#")[0].strip()
176
- if not target or "://" in target or target.startswith("mailto:"):
177
- continue
178
- if target.startswith("/"):
179
- dest = os.path.join(bundle, target.lstrip("/"))
180
- else:
181
- dest = os.path.join(filedir, target)
182
- # Directory links (progressive disclosure) are fine if the dir exists.
183
- if not (os.path.exists(dest) or os.path.exists(dest.rstrip("/"))):
184
- warnings.append(f"W2 {rel}: broken link -> {target}")
185
-
186
-
187
- def check_index(path: str, rel: str, is_root: bool, bundle: str):
188
- text, err = read_text(path)
189
- if text is None:
190
- errors.append(f"E1 {rel}: could not read file ({err})")
191
- return
192
- fm, body = split_frontmatter(text)
193
- if fm is not None:
194
- if not is_root:
195
- errors.append(f"E3 {rel}: index.md must not contain frontmatter (only the bundle root may, per §11)")
196
- else:
197
- data = parse_yaml(fm) or {}
198
- extra = set(data) - {"okf_version"}
199
- if extra:
200
- errors.append(f"E3 {rel}: root index.md frontmatter may only declare okf_version (found: {sorted(extra)})")
201
- check_links(body if fm is not None else text, rel, os.path.dirname(path), bundle)
202
-
203
-
204
- def check_log(path: str, rel: str):
205
- text, err = read_text(path)
206
- if text is None:
207
- errors.append(f"E1 {rel}: could not read file ({err})")
208
- return
209
- lines = text.splitlines()
210
- for i, ln in enumerate(lines):
211
- if not ln.startswith("## "):
212
- continue
213
- stripped = ln.rstrip()
214
- if not DATE_HEADING.match(stripped):
215
- errors.append(f"E3 {rel}: log heading not ISO 8601 YYYY-MM-DD: '{stripped}'")
216
- continue
217
- # Look for a "Commit: `<sha>`" line before the next date heading.
218
- found_sha = None
219
- for j in range(i + 1, len(lines)):
220
- if lines[j].startswith("## "):
221
- break
222
- m = COMMIT_LINE.match(lines[j].strip())
223
- if m:
224
- found_sha = m.group(1)
225
- break
226
- if found_sha is None:
227
- errors.append(f"E4 {rel}: date block '{stripped}' missing required 'Commit: `<sha>`' line")
228
-
229
-
230
- def find_repo_root(bundle: str) -> str:
231
- p = bundle
232
- while True:
233
- if os.path.isdir(os.path.join(p, ".git")):
234
- return p
235
- parent = os.path.dirname(p)
236
- if parent == p:
237
- return os.path.dirname(bundle)
238
- p = parent
239
-
240
-
241
- def load_config_excludes(path: str) -> list[str]:
242
- if not path or not os.path.isfile(path):
243
- return []
244
- text, err = read_text(path)
245
- if err is not None or text is None:
246
- return []
247
- if HAVE_YAML:
248
- try:
249
- data = yaml.safe_load(text) or {}
250
- except yaml.YAMLError:
251
- return []
252
- excl = (data.get("okf") or {}).get("exclude") or []
253
- return [str(x) for x in excl if isinstance(x, str)]
254
- # Lenient fallback: scan for an `exclude:` block of `- "glob"` lines.
255
- globs = []
256
- in_exclude = False
257
- for line in text.splitlines():
258
- stripped = line.strip()
259
- if re.match(r"^exclude\s*:\s*$", stripped):
260
- in_exclude = True
261
- continue
262
- if in_exclude:
263
- m = re.match(r"^-\s*['\"]?([^'\"#]+)['\"]?\s*(#.*)?$", stripped)
264
- if m:
265
- globs.append(m.group(1).strip())
266
- continue
267
- if stripped and not stripped.startswith("#"):
268
- in_exclude = False
269
- return globs
270
-
271
-
272
- def is_excluded(rel: str, patterns: list[str]) -> bool:
273
- return any(fnmatch.fnmatch(rel, pat) for pat in patterns)
274
-
275
-
276
- def main() -> int:
277
- parser = argparse.ArgumentParser(
278
- description="Conformance checker for OKF v0.1 knowledge bundles.",
279
- )
280
- parser.add_argument("bundle_dir", help="Path to the knowledge bundle directory")
281
- parser.add_argument("--config", help="Path to okf-config.yml (exclude list is honored)")
282
- parser.add_argument("--exclude", action="append", default=[], help="Glob to exclude (repeatable)")
283
- parser.add_argument("--repo-root", help="Repo root for resolving source_files (default: nearest .git above bundle_dir)")
284
- parser.add_argument("--json", action="store_true", help="Emit machine-readable JSON instead of text")
285
- args = parser.parse_args()
286
-
287
- if not os.path.isdir(args.bundle_dir):
288
- parser.error(f"{args.bundle_dir} is not a directory")
289
-
290
- bundle = os.path.abspath(args.bundle_dir)
291
- repo_root = os.path.abspath(args.repo_root) if args.repo_root else find_repo_root(bundle)
292
- exclude_patterns = load_config_excludes(args.config) + list(args.exclude)
293
-
294
- if not HAVE_YAML:
295
- warnings.append("W0 (global): PyYAML not installed — using lenient fallback parser, results may be less strict")
296
-
297
- concepts = 0
298
- for dirpath, dirnames, filenames in os.walk(bundle):
299
- dirnames[:] = [d for d in dirnames if not d.startswith(".")]
300
- rel_dir = os.path.relpath(dirpath, bundle)
301
- mds = [
302
- f for f in filenames
303
- if f.endswith(".md") and not is_excluded(
304
- os.path.relpath(os.path.join(dirpath, f), bundle), exclude_patterns
305
- )
306
- ]
307
- if any(f not in RESERVED for f in mds) and "index.md" not in mds:
308
- warnings.append(f"W3 {rel_dir or '.'}: directory has concepts but no index.md")
309
- for f in mds:
310
- path = os.path.join(dirpath, f)
311
- rel = os.path.relpath(path, bundle)
312
- if f == "index.md":
313
- check_index(path, rel, dirpath == bundle, bundle)
314
- elif f == "log.md":
315
- check_log(path, rel)
316
- else:
317
- concepts += 1
318
- check_concept(path, rel, bundle, repo_root)
319
-
320
- # W7: duplicate (type, title) pairs across the bundle.
321
- seen: dict[tuple[str, str], str] = {}
322
- for rel, t, title in concept_meta:
323
- key = (t.lower(), title.lower())
324
- if key in seen:
325
- warnings.append(f"W7 {rel}: possible duplicate concept — same type+title as {seen[key]}")
326
- else:
327
- seen[key] = rel
328
-
329
- if args.json:
330
- print(json.dumps({
331
- "concepts": concepts,
332
- "errors": errors,
333
- "warnings": warnings,
334
- "result": "NON-CONFORMANT" if errors else "CONFORMANT",
335
- }, indent=2))
336
- else:
337
- print(f"OKF validation of {bundle}")
338
- print(f" concepts: {concepts} errors: {len(errors)} warnings: {len(warnings)}\n")
339
- for e in errors:
340
- print(f" ERROR {e}")
341
- for w in warnings:
342
- print(f" WARNING {w}")
343
- print("\nRESULT:", "NON-CONFORMANT" if errors else "CONFORMANT (OKF v0.1)")
344
-
345
- return 1 if errors else 0
346
-
347
-
348
- if __name__ == "__main__":
349
- sys.exit(main())
@@ -1,75 +0,0 @@
1
- # [PROJECT_NAME] Constitution — [DOMAIN_NAME] Addenda
2
- <!-- Example: Medicinal Product Registry Constitution — Pharma Addenda -->
3
- <!--
4
- AppWeaver split-constitution model. This is the DOMAIN half — the domain
5
- addenda derived from docs/<domain>-constitution.md + the domain rule files
6
- (docs/domainspecs/<domain>/…). It carries ONLY domain-specific material:
7
- domain principles (XVI+), domain identifiers/terminology, regulatory regime,
8
- interoperability surfaces, and domain governance overrides.
9
-
10
- It EXTENDS the paired constitution.technical.md — it does not restate the
11
- technical principles (I–XV) or the base governance; it references them and adds
12
- the domain layer on top ("Extends technology X and XIV with …").
13
-
14
- Loading policy: this file is a SPECIFY-only standing input and a GATE checklist.
15
- It is deliberately NOT loaded by design or implement — domain reaches those
16
- phases only through the spec. Expand the principle slots to the full domain set
17
- from the domain addenda — the three shown are a scaffold, not a limit.
18
-
19
- THIN AUTHORITY: each principle is ONE declarative, testable line + a "→ [doc.md]"
20
- pointer to its rule doc. Do NOT restate the rule doc's detail here — this file says
21
- WHICH domain rules are supreme/non-negotiable and adopted; the domain docs (also
22
- loaded in specify) carry the detail. That keeps the authority/detail overlap to one line.
23
- -->
24
-
25
- ## Adopted Modelling Standard
26
- <!--
27
- DDD is the ratified domain-modelling standard, and it is the ONE technical principle
28
- that specify needs (specify loads THIS file, not constitution.technical). State it here
29
- as a thin authority line so specify carries the DDD mandate in its constitution frame —
30
- the detail lives in the rule docs (both loaded in specify), do NOT restate it.
31
- -->
32
- Domain modelling follows **Principle III — Domain-Driven Design (NON-NEGOTIABLE)** of
33
- the technical base → docs/domain/domain-driven-design.md (generic tactical patterns) +
34
- docs/domainspecs/[DOMAIN]/domain-driven-design.domain.md (this domain's canonical model).
35
- The spec expresses the model in DDD terms (ubiquitous language, aggregates + roots,
36
- entities vs value objects, aggregate-owned invariants, bounded context) as domain MODEL,
37
- never code.
38
-
39
- ## Domain Principles
40
- <!-- Numbered to CONTINUE the technical base (which ends at XV): start at XVI. -->
41
-
42
- ### [PRINCIPLE_16_NAME]
43
- <!-- Example: XVI. Pharmaceutical Product Identification (NON-NEGOTIABLE) -->
44
- [PRINCIPLE_16_DESCRIPTION]
45
- <!-- Example: NDC modeled as a Value Object with discrete Labeler/Product/Package segments; uniqueness enforced; validation rules configurable; no invented codes; model aligns with ISO IDMP concepts. Cite docs/domainspecs/<domain>/ sources. -->
46
-
47
- ### [PRINCIPLE_17_NAME]
48
- <!-- Example: XVII. Domain Terminology & Classification (NON-NEGOTIABLE) -->
49
- [PRINCIPLE_17_DESCRIPTION]
50
- <!-- Example: Coded data uses standard terminologies; every coded field is a Codeable value object; lookup/validation via the Terminology module; no invented or free-text codes. -->
51
-
52
- ### [PRINCIPLE_18_NAME]
53
- <!-- Example: Continue XVIII+ from the domain addenda (e.g. Regulatory Compliance: Audit/Provenance/Versioning; Lifecycle Integrity; Interoperability Readiness). Add one '### ' block per domain principle; state which technical principle each EXTENDS. -->
54
- [PRINCIPLE_18_DESCRIPTION]
55
- <!-- Example: Immutable append-only audit records; full version history; retirement is a logical state change, never a hard delete. Extends technology X and XIV with domain compliance controls. -->
56
-
57
- ## Domain Folder Additions
58
- <!-- Example: Pharma Folder Additions -->
59
-
60
- [FOLDER_ADDITIONS_CONTENT]
61
- <!-- Example: Interop/Fhir + Hl7v2 adapters, InteropTests, terminology seed fixtures, and provenance/version-history stores. See docs/domainspecs/<domain>/folder-structure.domain.md. These ADD to the base layout in constitution.technical.md. -->
62
-
63
- ## Regulatory Posture & Security Addenda
64
-
65
- [REGULATORY_POSTURE_CONTENT]
66
- <!-- Example: Regulatory-compliance readiness (auditability, traceability, data integrity, provenance); data-integrity expectations (e.g. ALCOA+/GxP); identifier/terminology/standard alignment; data residency. Zero-trust posture; change-authority enforcement; data classification (public vs sensitive/pre-market/externally-sourced). Cite docs/domainspecs/<domain>/ + docs/security/*.domain.md. -->
67
-
68
- ## Domain Governance Overrides
69
- <!-- Extends the Governance section of constitution.technical.md with domain-specific change authority. -->
70
-
71
- [DOMAIN_GOVERNANCE_CONTENT]
72
- <!-- Example: Mandatory approver for any identifier/classification/lifecycle-rule change (e.g. Regulatory/Compliance Officer); Domain Owners per bounded context; review cadence tied to regulatory/terminology releases; exception/waiver process. The base amendment procedure + SemVer policy in constitution.technical.md still apply. -->
73
-
74
- **Version**: [CONSTITUTION_VERSION] | **Ratified**: [RATIFICATION_DATE] | **Last Amended**: [LAST_AMENDED_DATE]
75
- <!-- Example: Version: 1.0.0 | Ratified: 2026-06-13 | Last Amended: 2026-06-13. Versions INDEPENDENTLY of constitution.technical.md — e.g. a WHO ATC annual update bumps this file only. -->
@@ -1,70 +0,0 @@
1
- # [PROJECT_NAME] Constitution — Technical Base
2
- <!-- Example: Medicinal Product Registry Constitution — Technical Base -->
3
- <!--
4
- AppWeaver split-constitution model. This is the TECHNICAL half — the
5
- domain-agnostic constitution derived from docs/technology-constitution.md
6
- (Core Principles I–XV, base governance, folder/convention pointers) + the base
7
- AI rules (docs/glossary/ai-rules.md). It carries NO domain-specific principle,
8
- identifier, terminology, or regulatory rule — those live in the paired
9
- constitution.domain.md, authored from the domain addenda.
10
-
11
- This file is the standing technical authority for the TECHNICAL authoring phases —
12
- DESIGN and IMPLEMENT (specify loads constitution.domain, not this; the gates load
13
- neither). Keeping it domain-free is what lets design author architecture from "spec
14
- + technical docs only" and lets the tech base stay swappable. Expand the principle
15
- slots to the full I–XV set from the technology base — the five shown are a scaffold,
16
- not a limit. Do NOT add domain principles here.
17
-
18
- THIN AUTHORITY: each principle is ONE declarative, testable line + a "→ [doc.md]"
19
- pointer to its rule doc. Do NOT restate the rule doc's detail here — this file says
20
- WHICH rules are supreme/non-negotiable and adopted; the docs (also loaded in the
21
- phase) carry the detail. That keeps the authority/detail overlap to one line.
22
- -->
23
-
24
- ## Core Principles
25
-
26
- ### [PRINCIPLE_1_NAME]
27
- <!-- Example: I. Modular Monolith with Vertical Slices (NON-NEGOTIABLE) -->
28
- [PRINCIPLE_1_DESCRIPTION]
29
- <!-- Example: Single deployable service partitioned into modules; each module = Domain/Features/Persistence/Shared; each feature is a self-contained vertical slice; no cross-module Domain coupling; no horizontal service layers. -->
30
-
31
- ### [PRINCIPLE_2_NAME]
32
- <!-- Example: II. Clean Architecture Dependency Rule (NON-NEGOTIABLE) -->
33
- [PRINCIPLE_2_DESCRIPTION]
34
- <!-- Example: Dependencies flow inward: API → Application → Domain ← Infrastructure; Domain is framework-agnostic; endpoints call IMediator, never repositories/DbContext. -->
35
-
36
- ### [PRINCIPLE_3_NAME]
37
- <!-- Example: III. Domain-Driven Design with Rich Aggregates (NON-NEGOTIABLE) -->
38
- [PRINCIPLE_3_DESCRIPTION]
39
- <!-- Example: Access entities through aggregate roots; strongly-typed IDs; sealed validating value objects; immutable domain events; invariants enforced in the aggregate; transaction boundary = aggregate boundary. -->
40
-
41
- ### [PRINCIPLE_4_NAME]
42
- <!-- Example: IV. CQRS via Mediator with Result Pattern (NON-NEGOTIABLE) -->
43
- [PRINCIPLE_4_DESCRIPTION]
44
- <!-- Example: All logic dispatched via the mediator; commands/queries return Result<T>; errors are Result.Failure (not exceptions); writes run in a transaction and publish domain events. -->
45
-
46
- ### [PRINCIPLE_5_NAME]
47
- <!-- Example: Continue V–XV from the technology base (Specification-Driven Persistence, Optimistic Concurrency, Multi-Provider/Multi-Tenant Persistence, Security by Default, Observability, Cloud-Native Orchestration, REST API Standards, Test-First, Data Integration / Single Source of Truth, Evolutionary Path to Microservices). Add one '### ' block per principle. STOP at the last technical principle — domain principles (XVI+) go in constitution.domain.md. -->
48
- [PRINCIPLE_5_DESCRIPTION]
49
- <!-- Example: Keep each principle declarative and testable; mark NON-NEGOTIABLE ones explicitly; the rules live in docs/ — cite the technology-constitution.md source. -->
50
-
51
- ## [SECTION_2_NAME]
52
- <!-- Example: Mandatory Folder Structure (base) -->
53
-
54
- [SECTION_2_CONTENT]
55
- <!-- Example: Module = Domain/Features/Persistence/Shared; cross-cutting files at the AppWeaver template level. See docs/architecture/folder-structure.md. Domain folder ADDITIONS are declared in constitution.domain.md, not here. -->
56
-
57
- ## [SECTION_3_NAME]
58
- <!-- Example: Conventions, Forbidden Patterns, AI Rules & Quality Gates (base) -->
59
-
60
- [SECTION_3_CONTENT]
61
- <!-- Example: Naming/coding conventions, base Forbidden Patterns, CI Quality Gates (docs/governance/coding-standards.md); package governance (docs/governance/dependency-policy.md); base AI operational rules (docs/glossary/ai-rules.md). Domain overlays are referenced from constitution.domain.md. -->
62
-
63
- ## Governance
64
- <!-- Example: Constitution supersedes README/CLAUDE.md/AGENTS.md; amendments via PR with a migration plan + SemVer bump; reviewers cite the principle number. This base governance also applies to constitution.domain.md; domain-specific approver/change-authority overrides are declared there. -->
65
-
66
- [GOVERNANCE_RULES]
67
- <!-- Example: Amendment procedure; SemVer-for-governance (MAJOR = weaken a NON-NEGOTIABLE or break the folder structure; MINOR = new principle or bounded context; PATCH = clarifications); compliance review on every PR; quarterly audit. The paired constitution.domain.md extends this section with domain change-authority. -->
68
-
69
- **Version**: [CONSTITUTION_VERSION] | **Ratified**: [RATIFICATION_DATE] | **Last Amended**: [LAST_AMENDED_DATE]
70
- <!-- Example: Version: 1.0.0 | Ratified: 2026-06-13 | Last Amended: 2026-06-13. This file versions INDEPENDENTLY of constitution.domain.md — a technical-base change need not bump the domain half, and vice-versa. -->
@@ -1,69 +0,0 @@
1
- # Delta Design — [CR-ID]: [TITLE]
2
-
3
- **Feature (aggregate)**: [Aggregate]
4
-
5
- **Base version**: [vX.Y] <!-- the current master design version; the design phase bumps the minor on close -->
6
-
7
- <!--
8
- This delta applies to the SINGLE master design at specs/[Aggregate]/design.md —
9
- never a new design doc. Classify every design change ADDED / MODIFIED / REMOVED
10
- against the current master, per LAYER section (Domain · Application · API · Infra),
11
- in the SAME technology-agnostic form as the master: behaviour as signatures +
12
- pre/post/invariant/raises, contracts as field shapes — NO code. A new command
13
- (e.g. UpdateOrder) is a new USER STORY realised as delta design elements, NOT a
14
- new feature/aggregate. After this delta is applied to design.md, `implement`
15
- regenerates the touched slice; regression re-tests the shared-element dependents.
16
- -->
17
-
18
- ## Change summary
19
-
20
- [One paragraph: what the design change is and which user story / spec delta it serves.]
21
-
22
- ## ADDED — new design elements
23
-
24
- <!-- New entities/VOs/events, use-cases/handlers, endpoints, ports, adapters, and the
25
- realisation of any new spec constraint/classification/contract. Serves = a spec id
26
- (FR-/BR-/CN-/DC-/IC-/US-); design reads the spec, never the domain rule files. -->
27
-
28
- | Layer (§) | Element | Kind | Serves |
29
- |---|---|---|---|
30
- | Application (§2) | `[Command/Query]` + handler | use-case | US-[n] · FR-[nnn] |
31
- | API (§3) | `[VERB] [/route]` | endpoint | US-[n] · FR-[nnn] |
32
- | Domain (§1) | `[Event]` / `[VO]` | event / value object | BR-[nnn] · CN-[nnn] |
33
- | Infrastructure (§4.2) | `I[External]` adapter | contract realisation | IC-[nnn] |
34
- | Cross-cutting (§5) | [audit / retention / exposure decision] | constraint realisation | CN-[nnn] · DC-[nnn] |
35
-
36
- ## MODIFIED — existing design elements
37
-
38
- <!-- Edits to elements the master already defines (add a behaviour, change a contract). -->
39
-
40
- | Layer (§) | Element | What changes | Why |
41
- |---|---|---|---|
42
- | Domain (§1) | `[Root].[Behaviour]` | add [method] + invariant | US-[n] |
43
- | Infrastructure (§4) | `I[Aggregate]Repository` | add [operation] | US-[n] |
44
-
45
- ## REMOVED
46
-
47
- - [design element removed + why] — or `None`
48
-
49
- ## Cross-layer impact
50
-
51
- [Which layer sections ripple; shared elements touched (e.g. the aggregate root);
52
- new migration needed? (yes/no); any contract change other systems couple to.]
53
-
54
- ## Regression targets
55
-
56
- [Existing user stories / behaviours to re-verify because a shared element changed —
57
- e.g. re-test CreateOrder when the Order root or its repository is MODIFIED.]
58
-
59
- ## New assumptions / workarounds (from this change)
60
-
61
- <!-- Anything this change defers — folds into the master's §7 / §8 ledgers on apply. -->
62
-
63
- - **DA-[n]**: [assumption to clarify later] — or `None`
64
- - **WA-[n]**: [structural workaround to clear later] — or `None`
65
-
66
- ## On close
67
-
68
- The design phase amends the master design.md doc-first, appends the Change History
69
- row, bumps the version (minor), and archives this record under `changes/archive/`.
@@ -1,60 +0,0 @@
1
- # Delta Spec — [CR-ID]: [TITLE]
2
-
3
- **Feature (aggregate)**: [Aggregate]
4
-
5
- **Change type**: [new-requirement | changed-requirement | defect | refactor]
6
-
7
- **Created**: [DATE]
8
-
9
- **Base version**: [vX.Y] <!-- the current master version; close-delta bumps the minor at the end of the chain -->
10
-
11
- <!--
12
- A change request is a DELTA on the feature's existing spec.md — never a new spec.
13
- Classify every item ADDED / MODIFIED / REMOVED against the current master, using
14
- the SAME vocabulary as the master spec: System Requirements in EARS, Business
15
- Rules (BR-n) as invariants, User Stories with Given/When/Then acceptance criteria,
16
- and — where the domain applies — Constraints & NFRs (CN-n), Data Classification
17
- (DC-n), and Integration Contracts (IC-n). A CR that changes a retention/audit rule,
18
- a data-exposure rule, or an interop obligation is a CN-/DC-/IC- delta, not a smuggled
19
- code change. Adding a command (e.g. UpdateOrder to the Order aggregate) is a new
20
- user story (US-n), NOT a new feature. Feature = aggregate (see spec-template.md).
21
- -->
22
-
23
- ## Change summary
24
-
25
- [One paragraph: what is changing and why.]
26
-
27
- ## ADDED
28
-
29
- <!-- New user stories, system requirements, business rules, entities, or domain-lift items (CN/DC/IC). -->
30
-
31
- - **US-[n] — [title]** (Priority: P?)
32
- - **Why this priority**: [the value and why it ranks here]
33
- - **Exercises**: [FR-nnn, BR-nnn]
34
- - **Acceptance**: Given [state], When [action], Then [outcome]
35
- - **Independent test**: [how this story is verified on its own]
36
- - **FR-[nnn]**: WHEN [trigger] THE SYSTEM SHALL [response] <!-- EARS — pick the fitting pattern -->
37
- - **BR-[nnn]**: [a new invariant that must always hold] — or `None`
38
- - **CN-[nnn]**: [new constraint / NFR — retention, immutability, audit, performance-as-a-limit; cite lifted source] — or `None`
39
- - **DC-[nnn]**: [new data-classification category or exposure rule] — or `None`
40
- - **IC-[nnn]**: [new integration contract / interop obligation] — or `None`
41
- - **Entity**: [new entity / value object + what it represents] — or `None`
42
-
43
- ## MODIFIED
44
-
45
- - **FR-[nnn]**: was [old] → now [new] <!-- keep EARS form -->
46
- - **BR-[nnn]**: was [old] → now [new]
47
- - **CN-[nnn]** / **DC-[nnn]** / **IC-[nnn]**: was [old] → now [new]
48
- - **US-[n]**: [what changes and why]
49
-
50
- ## REMOVED
51
-
52
- - [FR / BR / CN / DC / IC / US / entity removed and why] — or `None`
53
-
54
- ## Impact
55
-
56
- - **Affected FR / BR / CN / DC / IC / US / SC**: [ids]
57
- - **Regression risk**: [existing behaviour that must still hold — e.g. CreateOrder must still pass]
58
- - **On merge**: the new US-[n] is tagged `Added: (this CR)` in the master; finalize-delta
59
- merges this delta into spec.md + design.md and appends the Change History row, and
60
- close-delta (after analyze-slice) archives the change and bumps the minor version.