elspais 0.11.1__py3-none-any.whl → 0.43.5__py3-none-any.whl

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 (148) hide show
  1. elspais/__init__.py +2 -11
  2. elspais/{sponsors/__init__.py → associates.py} +102 -58
  3. elspais/cli.py +395 -79
  4. elspais/commands/__init__.py +9 -3
  5. elspais/commands/analyze.py +121 -173
  6. elspais/commands/changed.py +15 -30
  7. elspais/commands/config_cmd.py +13 -16
  8. elspais/commands/edit.py +60 -44
  9. elspais/commands/example_cmd.py +319 -0
  10. elspais/commands/hash_cmd.py +167 -183
  11. elspais/commands/health.py +1177 -0
  12. elspais/commands/index.py +98 -114
  13. elspais/commands/init.py +103 -26
  14. elspais/commands/reformat_cmd.py +41 -444
  15. elspais/commands/rules_cmd.py +7 -3
  16. elspais/commands/trace.py +444 -321
  17. elspais/commands/validate.py +195 -415
  18. elspais/config/__init__.py +799 -5
  19. elspais/{core/content_rules.py → content_rules.py} +20 -3
  20. elspais/docs/cli/assertions.md +67 -0
  21. elspais/docs/cli/commands.md +304 -0
  22. elspais/docs/cli/config.md +262 -0
  23. elspais/docs/cli/format.md +66 -0
  24. elspais/docs/cli/git.md +45 -0
  25. elspais/docs/cli/health.md +190 -0
  26. elspais/docs/cli/hierarchy.md +60 -0
  27. elspais/docs/cli/ignore.md +72 -0
  28. elspais/docs/cli/mcp.md +245 -0
  29. elspais/docs/cli/quickstart.md +58 -0
  30. elspais/docs/cli/traceability.md +89 -0
  31. elspais/docs/cli/validation.md +96 -0
  32. elspais/graph/GraphNode.py +383 -0
  33. elspais/graph/__init__.py +40 -0
  34. elspais/graph/annotators.py +927 -0
  35. elspais/graph/builder.py +1886 -0
  36. elspais/graph/deserializer.py +248 -0
  37. elspais/graph/factory.py +284 -0
  38. elspais/graph/metrics.py +127 -0
  39. elspais/graph/mutations.py +161 -0
  40. elspais/graph/parsers/__init__.py +156 -0
  41. elspais/graph/parsers/code.py +213 -0
  42. elspais/graph/parsers/comments.py +112 -0
  43. elspais/graph/parsers/config_helpers.py +29 -0
  44. elspais/graph/parsers/heredocs.py +225 -0
  45. elspais/graph/parsers/journey.py +131 -0
  46. elspais/graph/parsers/remainder.py +79 -0
  47. elspais/graph/parsers/requirement.py +347 -0
  48. elspais/graph/parsers/results/__init__.py +6 -0
  49. elspais/graph/parsers/results/junit_xml.py +229 -0
  50. elspais/graph/parsers/results/pytest_json.py +313 -0
  51. elspais/graph/parsers/test.py +305 -0
  52. elspais/graph/relations.py +78 -0
  53. elspais/graph/serialize.py +216 -0
  54. elspais/html/__init__.py +8 -0
  55. elspais/html/generator.py +731 -0
  56. elspais/html/templates/trace_view.html.j2 +2151 -0
  57. elspais/mcp/__init__.py +47 -29
  58. elspais/mcp/__main__.py +5 -1
  59. elspais/mcp/file_mutations.py +138 -0
  60. elspais/mcp/server.py +2016 -247
  61. elspais/testing/__init__.py +4 -4
  62. elspais/testing/config.py +3 -0
  63. elspais/testing/mapper.py +1 -1
  64. elspais/testing/result_parser.py +25 -21
  65. elspais/testing/scanner.py +301 -12
  66. elspais/utilities/__init__.py +1 -0
  67. elspais/utilities/docs_loader.py +115 -0
  68. elspais/utilities/git.py +607 -0
  69. elspais/{core → utilities}/hasher.py +8 -22
  70. elspais/utilities/md_renderer.py +189 -0
  71. elspais/{core → utilities}/patterns.py +58 -57
  72. elspais/utilities/reference_config.py +626 -0
  73. elspais/validation/__init__.py +19 -0
  74. elspais/validation/format.py +264 -0
  75. {elspais-0.11.1.dist-info → elspais-0.43.5.dist-info}/METADATA +7 -4
  76. elspais-0.43.5.dist-info/RECORD +80 -0
  77. elspais/config/defaults.py +0 -173
  78. elspais/config/loader.py +0 -494
  79. elspais/core/__init__.py +0 -21
  80. elspais/core/git.py +0 -352
  81. elspais/core/models.py +0 -320
  82. elspais/core/parser.py +0 -640
  83. elspais/core/rules.py +0 -514
  84. elspais/mcp/context.py +0 -171
  85. elspais/mcp/serializers.py +0 -112
  86. elspais/reformat/__init__.py +0 -50
  87. elspais/reformat/detector.py +0 -119
  88. elspais/reformat/hierarchy.py +0 -246
  89. elspais/reformat/line_breaks.py +0 -220
  90. elspais/reformat/prompts.py +0 -123
  91. elspais/reformat/transformer.py +0 -264
  92. elspais/trace_view/__init__.py +0 -54
  93. elspais/trace_view/coverage.py +0 -183
  94. elspais/trace_view/generators/__init__.py +0 -12
  95. elspais/trace_view/generators/base.py +0 -329
  96. elspais/trace_view/generators/csv.py +0 -122
  97. elspais/trace_view/generators/markdown.py +0 -175
  98. elspais/trace_view/html/__init__.py +0 -31
  99. elspais/trace_view/html/generator.py +0 -1006
  100. elspais/trace_view/html/templates/base.html +0 -283
  101. elspais/trace_view/html/templates/components/code_viewer_modal.html +0 -14
  102. elspais/trace_view/html/templates/components/file_picker_modal.html +0 -20
  103. elspais/trace_view/html/templates/components/legend_modal.html +0 -69
  104. elspais/trace_view/html/templates/components/review_panel.html +0 -118
  105. elspais/trace_view/html/templates/partials/review/help/help-panel.json +0 -244
  106. elspais/trace_view/html/templates/partials/review/help/onboarding.json +0 -77
  107. elspais/trace_view/html/templates/partials/review/help/tooltips.json +0 -237
  108. elspais/trace_view/html/templates/partials/review/review-comments.js +0 -928
  109. elspais/trace_view/html/templates/partials/review/review-data.js +0 -961
  110. elspais/trace_view/html/templates/partials/review/review-help.js +0 -679
  111. elspais/trace_view/html/templates/partials/review/review-init.js +0 -177
  112. elspais/trace_view/html/templates/partials/review/review-line-numbers.js +0 -429
  113. elspais/trace_view/html/templates/partials/review/review-packages.js +0 -1029
  114. elspais/trace_view/html/templates/partials/review/review-position.js +0 -540
  115. elspais/trace_view/html/templates/partials/review/review-resize.js +0 -115
  116. elspais/trace_view/html/templates/partials/review/review-status.js +0 -659
  117. elspais/trace_view/html/templates/partials/review/review-sync.js +0 -992
  118. elspais/trace_view/html/templates/partials/review-styles.css +0 -2238
  119. elspais/trace_view/html/templates/partials/scripts.js +0 -1741
  120. elspais/trace_view/html/templates/partials/styles.css +0 -1756
  121. elspais/trace_view/models.py +0 -353
  122. elspais/trace_view/review/__init__.py +0 -60
  123. elspais/trace_view/review/branches.py +0 -1149
  124. elspais/trace_view/review/models.py +0 -1205
  125. elspais/trace_view/review/position.py +0 -609
  126. elspais/trace_view/review/server.py +0 -1056
  127. elspais/trace_view/review/status.py +0 -470
  128. elspais/trace_view/review/storage.py +0 -1367
  129. elspais/trace_view/scanning.py +0 -213
  130. elspais/trace_view/specs/README.md +0 -84
  131. elspais/trace_view/specs/tv-d00001-template-architecture.md +0 -36
  132. elspais/trace_view/specs/tv-d00002-css-extraction.md +0 -37
  133. elspais/trace_view/specs/tv-d00003-js-extraction.md +0 -43
  134. elspais/trace_view/specs/tv-d00004-build-embedding.md +0 -40
  135. elspais/trace_view/specs/tv-d00005-test-format.md +0 -78
  136. elspais/trace_view/specs/tv-d00010-review-data-models.md +0 -33
  137. elspais/trace_view/specs/tv-d00011-review-storage.md +0 -33
  138. elspais/trace_view/specs/tv-d00012-position-resolution.md +0 -33
  139. elspais/trace_view/specs/tv-d00013-git-branches.md +0 -31
  140. elspais/trace_view/specs/tv-d00014-review-api-server.md +0 -31
  141. elspais/trace_view/specs/tv-d00015-status-modifier.md +0 -27
  142. elspais/trace_view/specs/tv-d00016-js-integration.md +0 -33
  143. elspais/trace_view/specs/tv-p00001-html-generator.md +0 -33
  144. elspais/trace_view/specs/tv-p00002-review-system.md +0 -29
  145. elspais-0.11.1.dist-info/RECORD +0 -101
  146. {elspais-0.11.1.dist-info → elspais-0.43.5.dist-info}/WHEEL +0 -0
  147. {elspais-0.11.1.dist-info → elspais-0.43.5.dist-info}/entry_points.txt +0 -0
  148. {elspais-0.11.1.dist-info → elspais-0.43.5.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,264 @@
1
+ """Format validation - Validate requirement format against configurable rules.
2
+
3
+ Validates requirements against rules defined in [rules.format] config section:
4
+ - require_hash: Check hash exists in footer
5
+ - require_assertions: Check at least one assertion exists
6
+ - require_rationale: Check rationale section exists
7
+ - require_shall: Check "shall" keyword in assertion text
8
+ - require_status: Check status field in metadata
9
+ - allowed_statuses: List of valid status values
10
+ - labels_sequential: Check assertion labels are sequential (A,B,C not A,C,E)
11
+ - labels_unique: Check no duplicate assertion labels
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from dataclasses import dataclass, field
17
+ from typing import TYPE_CHECKING, Any
18
+
19
+ if TYPE_CHECKING:
20
+ from elspais.graph import GraphNode
21
+
22
+
23
+ @dataclass
24
+ class FormatRulesConfig:
25
+ """Configuration for format validation rules.
26
+
27
+ All rules default to False (disabled) for backwards compatibility.
28
+ Enable rules explicitly in [rules.format] config section.
29
+ """
30
+
31
+ require_hash: bool = False
32
+ require_assertions: bool = False
33
+ require_rationale: bool = False
34
+ require_shall: bool = False
35
+ require_status: bool = False
36
+ allowed_statuses: list[str] = field(default_factory=list)
37
+ labels_sequential: bool = False
38
+ labels_unique: bool = True # Default True - duplicates are usually errors
39
+
40
+ @classmethod
41
+ def from_dict(cls, data: dict[str, Any]) -> FormatRulesConfig:
42
+ """Create FormatRulesConfig from configuration dictionary.
43
+
44
+ Args:
45
+ data: Dictionary from [rules.format] config section
46
+
47
+ Returns:
48
+ FormatRulesConfig instance
49
+ """
50
+ return cls(
51
+ require_hash=data.get("require_hash", False),
52
+ require_assertions=data.get("require_assertions", False),
53
+ require_rationale=data.get("require_rationale", False),
54
+ require_shall=data.get("require_shall", False),
55
+ require_status=data.get("require_status", False),
56
+ allowed_statuses=data.get("allowed_statuses", []),
57
+ labels_sequential=data.get("labels_sequential", False),
58
+ labels_unique=data.get("labels_unique", True),
59
+ )
60
+
61
+
62
+ @dataclass
63
+ class FormatViolation:
64
+ """A format rule violation found during validation.
65
+
66
+ Attributes:
67
+ rule: The rule that was violated
68
+ message: Human-readable description of the violation
69
+ severity: "error" or "warning"
70
+ node_id: ID of the requirement node with the violation
71
+ details: Additional context about the violation
72
+ """
73
+
74
+ rule: str
75
+ message: str
76
+ severity: str = "error"
77
+ node_id: str = ""
78
+ details: dict[str, Any] = field(default_factory=dict)
79
+
80
+
81
+ def validate_requirement_format(
82
+ node: GraphNode,
83
+ rules: FormatRulesConfig,
84
+ ) -> list[FormatViolation]:
85
+ """Validate a requirement node against format rules.
86
+
87
+ Args:
88
+ node: The requirement GraphNode to validate
89
+ rules: Format rules configuration
90
+
91
+ Returns:
92
+ List of FormatViolation objects (empty if valid)
93
+ """
94
+ from elspais.graph import NodeKind
95
+
96
+ violations: list[FormatViolation] = []
97
+
98
+ # Only validate requirement nodes
99
+ if node.kind != NodeKind.REQUIREMENT:
100
+ return violations
101
+
102
+ node_id = node.id
103
+
104
+ # Rule: require_hash
105
+ if rules.require_hash:
106
+ hash_value = node.hash # Use convenience property
107
+ if not hash_value or hash_value == "00000000":
108
+ violations.append(
109
+ FormatViolation(
110
+ rule="require_hash",
111
+ message=f"{node_id}: Missing or placeholder hash value",
112
+ node_id=node_id,
113
+ details={"current_hash": hash_value},
114
+ )
115
+ )
116
+
117
+ # Rule: require_assertions
118
+ if rules.require_assertions:
119
+ # Count assertion children
120
+ assertion_count = sum(
121
+ 1 for child in node.iter_children() if child.kind == NodeKind.ASSERTION
122
+ )
123
+ if assertion_count == 0:
124
+ violations.append(
125
+ FormatViolation(
126
+ rule="require_assertions",
127
+ message=f"{node_id}: No assertions defined",
128
+ node_id=node_id,
129
+ )
130
+ )
131
+
132
+ # Rule: require_rationale
133
+ if rules.require_rationale:
134
+ rationale = node.get_field("rationale", "")
135
+ if not rationale or not rationale.strip():
136
+ violations.append(
137
+ FormatViolation(
138
+ rule="require_rationale",
139
+ message=f"{node_id}: Missing rationale section",
140
+ node_id=node_id,
141
+ )
142
+ )
143
+
144
+ # Rule: require_shall
145
+ if rules.require_shall:
146
+ # Check assertions for SHALL keyword
147
+ assertions_without_shall = []
148
+ for child in node.iter_children():
149
+ if child.kind == NodeKind.ASSERTION:
150
+ assertion_text = child.get_field("text", "") or child.get_label()
151
+ if "shall" not in assertion_text.lower():
152
+ assertions_without_shall.append(child.get_label())
153
+
154
+ if assertions_without_shall:
155
+ violations.append(
156
+ FormatViolation(
157
+ rule="require_shall",
158
+ message=(
159
+ f"{node_id}: Assertions missing 'SHALL' keyword: "
160
+ f"{', '.join(assertions_without_shall)}"
161
+ ),
162
+ node_id=node_id,
163
+ details={"assertions": assertions_without_shall},
164
+ )
165
+ )
166
+
167
+ # Rule: require_status
168
+ if rules.require_status:
169
+ status = node.status # Use convenience property
170
+ if not status:
171
+ violations.append(
172
+ FormatViolation(
173
+ rule="require_status",
174
+ message=f"{node_id}: Missing status field",
175
+ node_id=node_id,
176
+ )
177
+ )
178
+
179
+ # Rule: allowed_statuses
180
+ if rules.allowed_statuses:
181
+ status = node.status # Use convenience property
182
+ if status and status not in rules.allowed_statuses:
183
+ violations.append(
184
+ FormatViolation(
185
+ rule="allowed_statuses",
186
+ message=(
187
+ f"{node_id}: Invalid status '{status}' "
188
+ f"(allowed: {', '.join(rules.allowed_statuses)})"
189
+ ),
190
+ node_id=node_id,
191
+ details={"current": status, "allowed": rules.allowed_statuses},
192
+ )
193
+ )
194
+
195
+ # Collect assertion labels for sequential and unique checks
196
+ assertion_labels: list[str] = []
197
+ for child in node.iter_children():
198
+ if child.kind == NodeKind.ASSERTION:
199
+ # Extract label from assertion ID (e.g., "REQ-p00001-A" -> "A")
200
+ label = child.get_field("label")
201
+ if not label and "-" in child.id:
202
+ label = child.id.split("-")[-1]
203
+ if label:
204
+ assertion_labels.append(label)
205
+
206
+ # Rule: labels_unique
207
+ if rules.labels_unique and assertion_labels:
208
+ seen = set()
209
+ duplicates = []
210
+ for label in assertion_labels:
211
+ if label in seen:
212
+ duplicates.append(label)
213
+ seen.add(label)
214
+
215
+ if duplicates:
216
+ violations.append(
217
+ FormatViolation(
218
+ rule="labels_unique",
219
+ message=f"{node_id}: Duplicate assertion labels: {', '.join(set(duplicates))}",
220
+ node_id=node_id,
221
+ details={"duplicates": list(set(duplicates))},
222
+ )
223
+ )
224
+
225
+ # Rule: labels_sequential
226
+ if rules.labels_sequential and assertion_labels:
227
+ # Check if uppercase letter labels are sequential
228
+ uppercase_labels = [lbl for lbl in assertion_labels if len(lbl) == 1 and lbl.isupper()]
229
+ if uppercase_labels:
230
+ sorted_labels = sorted(set(uppercase_labels))
231
+ expected_next = "A"
232
+ gaps = []
233
+
234
+ for label in sorted_labels:
235
+ if label != expected_next:
236
+ gaps.append(f"expected {expected_next}, found {label}")
237
+ break
238
+ expected_next = chr(ord(expected_next) + 1)
239
+
240
+ if gaps:
241
+ violations.append(
242
+ FormatViolation(
243
+ rule="labels_sequential",
244
+ message=f"{node_id}: Non-sequential assertion labels ({gaps[0]})",
245
+ node_id=node_id,
246
+ severity="warning", # Less severe - sometimes intentional
247
+ details={"labels": uppercase_labels, "gaps": gaps},
248
+ )
249
+ )
250
+
251
+ return violations
252
+
253
+
254
+ def get_format_rules_config(config: dict[str, Any]) -> FormatRulesConfig:
255
+ """Get FormatRulesConfig from configuration dictionary.
256
+
257
+ Args:
258
+ config: Full configuration dictionary from get_config()
259
+
260
+ Returns:
261
+ FormatRulesConfig instance from [rules.format] section
262
+ """
263
+ rules_data = config.get("rules", {}).get("format", {})
264
+ return FormatRulesConfig.from_dict(rules_data)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: elspais
3
- Version: 0.11.1
3
+ Version: 0.43.5
4
4
  Summary: Requirements validation and traceability tools - L-Space connects all libraries
5
5
  Project-URL: Homepage, https://github.com/anspar/elspais
6
6
  Project-URL: Documentation, https://github.com/anspar/elspais#readme
@@ -25,12 +25,15 @@ Classifier: Topic :: Software Development :: Quality Assurance
25
25
  Classifier: Typing :: Typed
26
26
  Requires-Python: >=3.9
27
27
  Provides-Extra: all
28
+ Requires-Dist: argcomplete>=3.0; extra == 'all'
28
29
  Requires-Dist: flask-cors>=4.0; extra == 'all'
29
30
  Requires-Dist: flask>=2.0; extra == 'all'
30
31
  Requires-Dist: jinja2>=3.0; extra == 'all'
31
32
  Requires-Dist: mcp>=1.0; extra == 'all'
32
33
  Provides-Extra: binary
33
34
  Requires-Dist: pyinstaller>=6.0; extra == 'binary'
35
+ Provides-Extra: completion
36
+ Requires-Dist: argcomplete>=3.0; extra == 'completion'
34
37
  Provides-Extra: dev
35
38
  Requires-Dist: black>=23.0; extra == 'dev'
36
39
  Requires-Dist: mypy>=1.0; extra == 'dev'
@@ -97,7 +100,7 @@ FROM python:3.11-slim
97
100
  COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
98
101
 
99
102
  # Install elspais (10-100x faster than pip)
100
- RUN uv pip install --system --no-cache elspais==0.9.3
103
+ RUN uv pip install --system --no-cache elspais==0.24.3
101
104
  ```
102
105
 
103
106
  ```yaml
@@ -106,7 +109,7 @@ RUN uv pip install --system --no-cache elspais==0.9.3
106
109
  uses: astral-sh/setup-uv@v2
107
110
 
108
111
  - name: Install elspais
109
- run: uv pip install --system elspais==0.9.3
112
+ run: uv pip install --system elspais==0.24.3
110
113
  ```
111
114
 
112
115
  **Note:** For regulated/medical software projects, always pin the exact version for reproducibility.
@@ -424,7 +427,7 @@ For reproducible builds, pin the version in your project:
424
427
 
425
428
  ```bash
426
429
  # .github/versions.env
427
- ELSPAIS_VERSION=0.1.0
430
+ ELSPAIS_VERSION=0.24.3
428
431
  ```
429
432
 
430
433
  ```yaml
@@ -0,0 +1,80 @@
1
+ elspais/__init__.py,sha256=ddJTTPg5aTpGZSeriPjIiSW5fxnYWQ33Lquah3HLw6g,730
2
+ elspais/__main__.py,sha256=rCMaObqJeT_6dhyfND7S4dh_lv30j7Ww3Z7992YYwaE,130
3
+ elspais/associates.py,sha256=Wtue2cn60VkLGoIMQDAZeOJtuOdfJjVbXsIc7EKuun0,14221
4
+ elspais/cli.py,sha256=ccIvB7JseseSXDCLXv8euyIfK4BrEV-ttTSFj3VgLd0,29369
5
+ elspais/content_rules.py,sha256=YEjsMB07gjcWymlRRf2z1E39-RvZMHXAwVxypo7ylog,4829
6
+ elspais/commands/__init__.py,sha256=E8otW6goXASgd0cDvG3SiuqXxC-U6rfyRCnN8ZI3tcQ,256
7
+ elspais/commands/analyze.py,sha256=t4THSyUytRjoECMToDSELj6OKJu_BTiEuCQsmRt18EY,5197
8
+ elspais/commands/changed.py,sha256=DmZ8taBHOKrckiqm5RNA0zUJKMYAoWNCPzVZSUD2ugM,4524
9
+ elspais/commands/config_cmd.py,sha256=r1BATGOVYOuFNd1gl2AnktMj4LOSc1O7KuzykPExTpo,13995
10
+ elspais/commands/edit.py,sha256=_ok7MWUhtYviCFSf6ZR_ol6Ab0HPn4NTMIuZFTEBejc,16784
11
+ elspais/commands/example_cmd.py,sha256=DGByHbTwj0iyeabtJCD7o3Vx5crj9IpgsZ01ZnmmI98,8804
12
+ elspais/commands/hash_cmd.py,sha256=dNvH0dzBpyshvpe6Dz9iFODLb-k9UA_qPyVQfyz4h2E,6010
13
+ elspais/commands/health.py,sha256=ihE_pPPFySI3opNPRTShhY9Mr4PH7g8qb7W297oS7vo,37801
14
+ elspais/commands/index.py,sha256=JbNyGjaS3GqElIkAV1_fKyLuIcna1Kko6fPaetZ3DuY,4569
15
+ elspais/commands/init.py,sha256=fvGjuN6rDe_7bZvwwEW3Lqr7r4xgYXcsn1wlDOWVvPA,6939
16
+ elspais/commands/reformat_cmd.py,sha256=AFFGWX-OVx__xdMVvdbahLYK8G7d5Kdsm7oSHOAVX5E,1950
17
+ elspais/commands/rules_cmd.py,sha256=UwFzDoAXKzSpzjJ1LIJK1bfAkosnGwtS9k_CsPhUrH4,3451
18
+ elspais/commands/trace.py,sha256=iq-gF_M_OIC7_2kxYC3zT-V8RYJqOX-nmRsuujUMtbY,16432
19
+ elspais/commands/validate.py,sha256=iTrN9v6ZQM-HoNacVOzS1B1sp5JUi4FlOPtINZCCa9I,7456
20
+ elspais/config/__init__.py,sha256=LlfrMXtUd_E0bQIDBgSh29EpYAUqXMuGrPyp1qGUwE8,23272
21
+ elspais/graph/GraphNode.py,sha256=UuqcXPLzwdC2JyZhDaIHc2rGeZ9fACmPdsdzMGKjkmw,12327
22
+ elspais/graph/__init__.py,sha256=rifZItDPBLJRqsn1lDKLtfxzSF9kbJ-3Vl0byxlniRs,1196
23
+ elspais/graph/annotators.py,sha256=WGhR6gXXzQqYl8SxliECRpluUDnIwIM2kwt30JqyPfI,28464
24
+ elspais/graph/builder.py,sha256=Ro1VYBnN4sVfRUsPnUo2qA4ov9BxrNUkhLnk3H_yRnQ,70544
25
+ elspais/graph/deserializer.py,sha256=4jiGe3agIYDwrTNCShS-jKzdKK0ndZIvU__rX9c6xkU,7906
26
+ elspais/graph/factory.py,sha256=1VirAq1YO0nqPpa-Z8EvnlC1F3AuM_hZ-NE2uTGAMgI,11812
27
+ elspais/graph/metrics.py,sha256=Z5-rfm5DeEcwmdx4LltrWxCM104O2Cmw8uFZU8zCb4I,4811
28
+ elspais/graph/mutations.py,sha256=Nd0_S2CEMllYHYjwDdmKkMvnBvah7pSSquMniq47F5E,4882
29
+ elspais/graph/relations.py,sha256=O8Wbht2J3OuHx2Ah18FWUXhRA47Kc2xgeutQ7VAjnlU,2538
30
+ elspais/graph/serialize.py,sha256=U_WQKCbAAygg59Ocvjr8_f4--UdGtK534Ys4WDR2fOE,5571
31
+ elspais/graph/parsers/__init__.py,sha256=jqD4N5Z3qRzmCcz8jpSpo-NdBCvPZrcgSOAFt5ZH0gQ,4538
32
+ elspais/graph/parsers/code.py,sha256=9txDvj6umxHkP_t07HfNayMre1pNhUP1cScBEeBj_Qk,7422
33
+ elspais/graph/parsers/comments.py,sha256=JxB79XSg0wDhEkOgGhivk6evrft7IkcCBhdur82ZC4M,3469
34
+ elspais/graph/parsers/config_helpers.py,sha256=Vz3xitKnNgZbCSYKnBSeDCW1TKVyHlB9UbEzq-q21zg,995
35
+ elspais/graph/parsers/heredocs.py,sha256=kEyIZrGXOUWu-JJkfM56OD1uDYYBYOtzY1qoslhkGZQ,7219
36
+ elspais/graph/parsers/journey.py,sha256=Amj40qEq_zE7maz8ewR-djlSy5SiWQB6JeEIa_Q5Fic,3928
37
+ elspais/graph/parsers/remainder.py,sha256=u004gg9twwN_oW9hfqyDt_6MSEvxRrFNIeoAMVic7j4,2308
38
+ elspais/graph/parsers/requirement.py,sha256=HcSL5gFUpOmWHBoI1EOazvOszkVuEnSPIKhWR-k8DzI,12002
39
+ elspais/graph/parsers/test.py,sha256=EfM1eySf2bUYrPknfPGW1hOu_98_HA2V1K5ral5UQSg,11244
40
+ elspais/graph/parsers/results/__init__.py,sha256=QRo0_DIh4xar2kv4HKnqV2IRg7Rjbku9AGO8vJtolsA,254
41
+ elspais/graph/parsers/results/junit_xml.py,sha256=k_wRG_sblQMBdlVmoaMxDcHHqW30XQqHKhEhAY-UmNg,7821
42
+ elspais/graph/parsers/results/pytest_json.py,sha256=eZf3tXCm4Tv8oDdLsrCnbPShSaIrG55CoIegGxQs-nw,10395
43
+ elspais/html/__init__.py,sha256=csyyiBoU_WKkFyP5c4zTnx1uHwQ4sZlbA66OvFgpAis,212
44
+ elspais/html/generator.py,sha256=RJMEwzgrNLzmIPEomkGfJRogcyqQQj24sjpRJsdYOlg,27927
45
+ elspais/html/templates/trace_view.html.j2,sha256=6tUx9BgiQqjnThUZ4NG6sSKXH1F1pXGhaSM6n3CRDJc,76871
46
+ elspais/mcp/__init__.py,sha256=Sr-YJtQgYO2gKDD4vHwJ9si3PeAnoqX6DntUXM-qekI,1450
47
+ elspais/mcp/__main__.py,sha256=QgFm_G-BkqjW0cULzUfdLAeGeam5R4qneBCs5k2pUTc,182
48
+ elspais/mcp/file_mutations.py,sha256=ts2-m7-mupe96rkkQe6nS_u_K3JPf_rH02pANw8RhCA,4457
49
+ elspais/mcp/server.py,sha256=OEmUzpMLf_gront2E5MmFNnhSfoPaR_VFU_lXvNu2uI,77388
50
+ elspais/testing/__init__.py,sha256=RIGednU6uRUcYHNT5nbLTrDPY-SCh3HCYj0A-iEWCHg,916
51
+ elspais/testing/config.py,sha256=iobz9r6CHEcfx4r2QTWlGN6S8XWj3OJ0DEW7GyxmpLw,1813
52
+ elspais/testing/mapper.py,sha256=itcatI7vaVn7RkW6SSTb4bj0R8hZXINWVN8KtBf24iI,5657
53
+ elspais/testing/result_parser.py,sha256=YgSNQa3mlT-ovo3PzjoUypN2urR1dIunPcfdB2IMAH8,9415
54
+ elspais/testing/scanner.py,sha256=9YttAeHA1uNuyMMHaVVhotbAqVQQN5U2J5HVK7c6gC8,17724
55
+ elspais/utilities/__init__.py,sha256=_HN7tawOZdaopnl3ISEWqDp2L_3fzkWsx4iKu0kYohs,55
56
+ elspais/utilities/docs_loader.py,sha256=NiXOU-NAP97JMDR8w_H0xq6eMP7Gbq4NeDeoNgq-6h4,2693
57
+ elspais/utilities/git.py,sha256=yEw-ARaVjQIC8Fu5evAgmvi77mDLFesXdX1bd4v8yKU,19887
58
+ elspais/utilities/hasher.py,sha256=2gwHgdMYf6r87Rd1R2YEfIfz3KqymESu_DD1SgYFkXk,3782
59
+ elspais/utilities/md_renderer.py,sha256=nKKO4RxechfayduCC-jr2YmyzxPTfd5JY8W5kvsLOXs,6378
60
+ elspais/utilities/patterns.py,sha256=jCILSUsk9rBI18sVp9StBxw7lImnI1kBtEU7Bajlm1s,13050
61
+ elspais/utilities/reference_config.py,sha256=i0bA0NMplip2TY2XQvRPN1TvDoqafnuPv9PtsPMABdw,21461
62
+ elspais/validation/__init__.py,sha256=pgP-4_gkmkaBX1uRGiwzZf0n3kSJpYKCAQppIq65fpQ,441
63
+ elspais/validation/format.py,sha256=nlYF5WVPbygo2jlscDg4Bk3R4J7fyYVf362nfGvvPsY,9219
64
+ elspais/docs/cli/assertions.md,sha256=Rp8KM7s-2JU9A2QA0GtsaL12BTf5gGU_rbOfvMW1gaU,1538
65
+ elspais/docs/cli/commands.md,sha256=41luTLMrl3qvhl_OcEEuAou7BFQpC3--i6D-I8Uut10,8789
66
+ elspais/docs/cli/config.md,sha256=ckRwF2ImcxYeXku-oVomnQrp0xqlvsG7FADdOQMEjfw,6075
67
+ elspais/docs/cli/format.md,sha256=ygsfxdIYvWMGoO-8DzlY8ELATlaUJhGNxfLe77ehljM,1633
68
+ elspais/docs/cli/git.md,sha256=kXW5WaVu9XkzgQ0ryBl4H-Vav2sVGThH_DifdvBqQFs,1284
69
+ elspais/docs/cli/health.md,sha256=mFLUEOhcSfZ6aHMrzYjqUbcDhMmaieMIaEQaVD4DqUo,5146
70
+ elspais/docs/cli/hierarchy.md,sha256=_hqxQVu-sp_BhJnLznKljiTDZDMNXKYqMh-uDyjVuB0,1677
71
+ elspais/docs/cli/ignore.md,sha256=THa2hdt05Hq4Bi3eKdt4prDUntU1xV3rySldY2DLhNw,2097
72
+ elspais/docs/cli/mcp.md,sha256=4UrxT6QSC-qgtz_pkWcWarpnDVRBb8hemK9jBnYFi6o,6564
73
+ elspais/docs/cli/quickstart.md,sha256=y7rpVjN3lcL32517rEpNF0b2Nw8IAH5xMCFh02wRK74,1412
74
+ elspais/docs/cli/traceability.md,sha256=CtZfFUqyWNqtAgL3yQYGT8OUpsof0tkzTturRk4vzJ0,2573
75
+ elspais/docs/cli/validation.md,sha256=LYnL3YaSOhdx-kBGOUYUxD9yYDUasX41RhuO7BolnWs,2535
76
+ elspais-0.43.5.dist-info/METADATA,sha256=HBl9hNKnkh9Q-xRm1JP6m5U6ZKMm9bRHWwh9bPmSSJE,11767
77
+ elspais-0.43.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
78
+ elspais-0.43.5.dist-info/entry_points.txt,sha256=yWZZEfn2fBSKSzGoS-fMQ9YoTkyeu6-i7Oht6NsdKpk,45
79
+ elspais-0.43.5.dist-info/licenses/LICENSE,sha256=x_dNMsy_askp2MmKXZFL2bKW_tDiJHcRTyAg0TY1RMI,1063
80
+ elspais-0.43.5.dist-info/RECORD,,
@@ -1,173 +0,0 @@
1
- """
2
- elspais.config.defaults - Default configuration values.
3
-
4
- Provides built-in defaults matching the HHT-diary repository structure.
5
- """
6
-
7
- DEFAULT_CONFIG = {
8
- "project": {
9
- "name": "",
10
- "type": "core",
11
- },
12
- "directories": {
13
- "spec": "spec",
14
- "docs": "docs",
15
- "database": "database",
16
- "code": ["apps", "packages", "server", "tools"],
17
- "ignore": [
18
- "node_modules",
19
- ".git",
20
- "build",
21
- "dist",
22
- ".dart_tool",
23
- "__pycache__",
24
- ".venv",
25
- "venv",
26
- ],
27
- },
28
- "patterns": {
29
- "id_template": "{prefix}-{associated}{type}{id}",
30
- "prefix": "REQ",
31
- "types": {
32
- "prd": {"id": "p", "name": "Product Requirement", "level": 1},
33
- "ops": {"id": "o", "name": "Operations Requirement", "level": 2},
34
- "dev": {"id": "d", "name": "Development Requirement", "level": 3},
35
- },
36
- "id_format": {
37
- "style": "numeric",
38
- "digits": 5,
39
- "leading_zeros": True,
40
- },
41
- "associated": {
42
- "enabled": True,
43
- "position": "after_prefix",
44
- "format": "uppercase",
45
- "length": 3,
46
- "separator": "-",
47
- },
48
- "assertions": {
49
- "label_style": "uppercase", # uppercase | numeric | alphanumeric | numeric_1based
50
- "max_count": 26,
51
- "zero_pad": False,
52
- },
53
- },
54
- "spec": {
55
- "index_file": "INDEX.md",
56
- "readme_file": "README.md",
57
- "format_guide": "requirements-format.md",
58
- "skip_files": ["README.md", "requirements-format.md", "INDEX.md"],
59
- "file_patterns": {
60
- "prd-*.md": "prd",
61
- "ops-*.md": "ops",
62
- "dev-*.md": "dev",
63
- },
64
- # Values in Implements field that mean "no references"
65
- "no_reference_values": ["-", "null", "none", "x", "X", "N/A", "n/a"],
66
- },
67
- "core": {
68
- "path": None,
69
- "remote": None,
70
- },
71
- "associated": {
72
- "prefix": None,
73
- "id_range": [1, 99999],
74
- },
75
- "rules": {
76
- "hierarchy": {
77
- "allowed_implements": [
78
- "dev -> ops, prd",
79
- "ops -> prd",
80
- "prd -> prd",
81
- ],
82
- "allow_circular": False,
83
- "allow_orphans": False,
84
- "max_depth": 5,
85
- "cross_repo_implements": True,
86
- },
87
- "format": {
88
- "require_hash": True,
89
- "require_rationale": False,
90
- "require_status": True,
91
- "allowed_statuses": ["Active", "Draft", "Deprecated", "Superseded"],
92
- # Assertion format rules
93
- "require_assertions": True,
94
- "acceptance_criteria": "warn", # allow | warn | error
95
- "require_shall": True,
96
- "labels_sequential": True,
97
- "labels_unique": True,
98
- "placeholder_values": [
99
- "obsolete", "removed", "deprecated", "N/A", "n/a", "-", "reserved"
100
- ],
101
- },
102
- "traceability": {
103
- "require_code_link": False,
104
- "scan_for_orphans": True,
105
- },
106
- "naming": {
107
- "title_min_length": 10,
108
- "title_max_length": 100,
109
- "title_pattern": "^[A-Z].*",
110
- },
111
- "content_rules": [], # List of content rule markdown file paths
112
- },
113
- "validation": {
114
- "strict_hierarchy": True,
115
- "hash_algorithm": "sha256",
116
- "hash_length": 8,
117
- "normalize_whitespace": False, # If True, normalize whitespace before hashing
118
- },
119
- "traceability": {
120
- "output_formats": ["markdown", "html"],
121
- "output_dir": ".",
122
- "scan_patterns": [
123
- "database/**/*.sql",
124
- "apps/**/*.dart",
125
- "packages/**/*.dart",
126
- "server/**/*.dart",
127
- "tools/**/*.py",
128
- ".github/workflows/**/*.yml",
129
- ],
130
- "impl_patterns": [
131
- r"IMPLEMENTS.*REQ-",
132
- r"Implements:\s*REQ-",
133
- r"Fixes:\s*REQ-",
134
- ],
135
- },
136
- "index": {
137
- "auto_regenerate": False,
138
- },
139
- "testing": {
140
- "enabled": False,
141
- "test_dirs": [
142
- "apps/**/test",
143
- "apps/**/tests",
144
- "packages/**/test",
145
- "packages/**/tests",
146
- "tools/**/tests",
147
- "tests",
148
- ],
149
- "patterns": [
150
- "*_test.dart",
151
- "test_*.dart",
152
- "test_*.py",
153
- "*_test.py",
154
- "*_test.sql",
155
- ],
156
- "result_files": [
157
- "build-reports/**/TEST-*.xml",
158
- "build-reports/pytest-results.json",
159
- ],
160
- "reference_patterns": [
161
- # Test function names containing requirement IDs
162
- r"test_.*(?:REQ[-_])?([pod]\d{5})(?:_[A-Z])?",
163
- # Comment/docstring patterns
164
- r"(?:IMPLEMENTS|Implements|implements)[:\s]+(?:REQ[-_])?([pod]\d{5})(?:-[A-Z])?",
165
- # Direct requirement ID mentions
166
- r"\bREQ[-_]([pod]\d{5})(?:-[A-Z])?\b",
167
- ],
168
- },
169
- "hooks": {
170
- "pre_commit": True,
171
- "commit_msg": True,
172
- },
173
- }