elspais 0.11.2__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 (147) hide show
  1. elspais/__init__.py +1 -10
  2. elspais/{sponsors/__init__.py → associates.py} +102 -56
  3. elspais/cli.py +366 -69
  4. elspais/commands/__init__.py +9 -3
  5. elspais/commands/analyze.py +118 -169
  6. elspais/commands/changed.py +12 -23
  7. elspais/commands/config_cmd.py +10 -13
  8. elspais/commands/edit.py +33 -13
  9. elspais/commands/example_cmd.py +319 -0
  10. elspais/commands/hash_cmd.py +161 -183
  11. elspais/commands/health.py +1177 -0
  12. elspais/commands/index.py +98 -115
  13. elspais/commands/init.py +99 -22
  14. elspais/commands/reformat_cmd.py +41 -433
  15. elspais/commands/rules_cmd.py +2 -2
  16. elspais/commands/trace.py +443 -324
  17. elspais/commands/validate.py +193 -411
  18. elspais/config/__init__.py +799 -5
  19. elspais/{core/content_rules.py → content_rules.py} +20 -2
  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 +45 -29
  58. elspais/mcp/__main__.py +5 -1
  59. elspais/mcp/file_mutations.py +138 -0
  60. elspais/mcp/server.py +1998 -244
  61. elspais/testing/__init__.py +3 -3
  62. elspais/testing/config.py +3 -0
  63. elspais/testing/mapper.py +1 -1
  64. elspais/testing/scanner.py +301 -12
  65. elspais/utilities/__init__.py +1 -0
  66. elspais/utilities/docs_loader.py +115 -0
  67. elspais/utilities/git.py +607 -0
  68. elspais/{core → utilities}/hasher.py +8 -22
  69. elspais/utilities/md_renderer.py +189 -0
  70. elspais/{core → utilities}/patterns.py +56 -51
  71. elspais/utilities/reference_config.py +626 -0
  72. elspais/validation/__init__.py +19 -0
  73. elspais/validation/format.py +264 -0
  74. {elspais-0.11.2.dist-info → elspais-0.43.5.dist-info}/METADATA +7 -4
  75. elspais-0.43.5.dist-info/RECORD +80 -0
  76. elspais/config/defaults.py +0 -179
  77. elspais/config/loader.py +0 -494
  78. elspais/core/__init__.py +0 -21
  79. elspais/core/git.py +0 -346
  80. elspais/core/models.py +0 -320
  81. elspais/core/parser.py +0 -639
  82. elspais/core/rules.py +0 -509
  83. elspais/mcp/context.py +0 -172
  84. elspais/mcp/serializers.py +0 -112
  85. elspais/reformat/__init__.py +0 -50
  86. elspais/reformat/detector.py +0 -112
  87. elspais/reformat/hierarchy.py +0 -247
  88. elspais/reformat/line_breaks.py +0 -218
  89. elspais/reformat/prompts.py +0 -133
  90. elspais/reformat/transformer.py +0 -266
  91. elspais/trace_view/__init__.py +0 -55
  92. elspais/trace_view/coverage.py +0 -183
  93. elspais/trace_view/generators/__init__.py +0 -12
  94. elspais/trace_view/generators/base.py +0 -334
  95. elspais/trace_view/generators/csv.py +0 -118
  96. elspais/trace_view/generators/markdown.py +0 -170
  97. elspais/trace_view/html/__init__.py +0 -33
  98. elspais/trace_view/html/generator.py +0 -1140
  99. elspais/trace_view/html/templates/base.html +0 -283
  100. elspais/trace_view/html/templates/components/code_viewer_modal.html +0 -14
  101. elspais/trace_view/html/templates/components/file_picker_modal.html +0 -20
  102. elspais/trace_view/html/templates/components/legend_modal.html +0 -69
  103. elspais/trace_view/html/templates/components/review_panel.html +0 -118
  104. elspais/trace_view/html/templates/partials/review/help/help-panel.json +0 -244
  105. elspais/trace_view/html/templates/partials/review/help/onboarding.json +0 -77
  106. elspais/trace_view/html/templates/partials/review/help/tooltips.json +0 -237
  107. elspais/trace_view/html/templates/partials/review/review-comments.js +0 -928
  108. elspais/trace_view/html/templates/partials/review/review-data.js +0 -961
  109. elspais/trace_view/html/templates/partials/review/review-help.js +0 -679
  110. elspais/trace_view/html/templates/partials/review/review-init.js +0 -177
  111. elspais/trace_view/html/templates/partials/review/review-line-numbers.js +0 -429
  112. elspais/trace_view/html/templates/partials/review/review-packages.js +0 -1029
  113. elspais/trace_view/html/templates/partials/review/review-position.js +0 -540
  114. elspais/trace_view/html/templates/partials/review/review-resize.js +0 -115
  115. elspais/trace_view/html/templates/partials/review/review-status.js +0 -659
  116. elspais/trace_view/html/templates/partials/review/review-sync.js +0 -992
  117. elspais/trace_view/html/templates/partials/review-styles.css +0 -2238
  118. elspais/trace_view/html/templates/partials/scripts.js +0 -1741
  119. elspais/trace_view/html/templates/partials/styles.css +0 -1756
  120. elspais/trace_view/models.py +0 -378
  121. elspais/trace_view/review/__init__.py +0 -63
  122. elspais/trace_view/review/branches.py +0 -1142
  123. elspais/trace_view/review/models.py +0 -1200
  124. elspais/trace_view/review/position.py +0 -591
  125. elspais/trace_view/review/server.py +0 -1032
  126. elspais/trace_view/review/status.py +0 -455
  127. elspais/trace_view/review/storage.py +0 -1343
  128. elspais/trace_view/scanning.py +0 -213
  129. elspais/trace_view/specs/README.md +0 -84
  130. elspais/trace_view/specs/tv-d00001-template-architecture.md +0 -36
  131. elspais/trace_view/specs/tv-d00002-css-extraction.md +0 -37
  132. elspais/trace_view/specs/tv-d00003-js-extraction.md +0 -43
  133. elspais/trace_view/specs/tv-d00004-build-embedding.md +0 -40
  134. elspais/trace_view/specs/tv-d00005-test-format.md +0 -78
  135. elspais/trace_view/specs/tv-d00010-review-data-models.md +0 -33
  136. elspais/trace_view/specs/tv-d00011-review-storage.md +0 -33
  137. elspais/trace_view/specs/tv-d00012-position-resolution.md +0 -33
  138. elspais/trace_view/specs/tv-d00013-git-branches.md +0 -31
  139. elspais/trace_view/specs/tv-d00014-review-api-server.md +0 -31
  140. elspais/trace_view/specs/tv-d00015-status-modifier.md +0 -27
  141. elspais/trace_view/specs/tv-d00016-js-integration.md +0 -33
  142. elspais/trace_view/specs/tv-p00001-html-generator.md +0 -33
  143. elspais/trace_view/specs/tv-p00002-review-system.md +0 -29
  144. elspais-0.11.2.dist-info/RECORD +0 -101
  145. {elspais-0.11.2.dist-info → elspais-0.43.5.dist-info}/WHEEL +0 -0
  146. {elspais-0.11.2.dist-info → elspais-0.43.5.dist-info}/entry_points.txt +0 -0
  147. {elspais-0.11.2.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.2
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,179 +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",
100
- "removed",
101
- "deprecated",
102
- "N/A",
103
- "n/a",
104
- "-",
105
- "reserved",
106
- ],
107
- },
108
- "traceability": {
109
- "require_code_link": False,
110
- "scan_for_orphans": True,
111
- },
112
- "naming": {
113
- "title_min_length": 10,
114
- "title_max_length": 100,
115
- "title_pattern": "^[A-Z].*",
116
- },
117
- "content_rules": [], # List of content rule markdown file paths
118
- },
119
- "validation": {
120
- "strict_hierarchy": True,
121
- "hash_algorithm": "sha256",
122
- "hash_length": 8,
123
- "normalize_whitespace": False, # If True, normalize whitespace before hashing
124
- },
125
- "traceability": {
126
- "output_formats": ["markdown", "html"],
127
- "output_dir": ".",
128
- "scan_patterns": [
129
- "database/**/*.sql",
130
- "apps/**/*.dart",
131
- "packages/**/*.dart",
132
- "server/**/*.dart",
133
- "tools/**/*.py",
134
- ".github/workflows/**/*.yml",
135
- ],
136
- "impl_patterns": [
137
- r"IMPLEMENTS.*REQ-",
138
- r"Implements:\s*REQ-",
139
- r"Fixes:\s*REQ-",
140
- ],
141
- },
142
- "index": {
143
- "auto_regenerate": False,
144
- },
145
- "testing": {
146
- "enabled": False,
147
- "test_dirs": [
148
- "apps/**/test",
149
- "apps/**/tests",
150
- "packages/**/test",
151
- "packages/**/tests",
152
- "tools/**/tests",
153
- "tests",
154
- ],
155
- "patterns": [
156
- "*_test.dart",
157
- "test_*.dart",
158
- "test_*.py",
159
- "*_test.py",
160
- "*_test.sql",
161
- ],
162
- "result_files": [
163
- "build-reports/**/TEST-*.xml",
164
- "build-reports/pytest-results.json",
165
- ],
166
- "reference_patterns": [
167
- # Test function names containing requirement IDs
168
- r"test_.*(?:REQ[-_])?([pod]\d{5})(?:_[A-Z])?",
169
- # Comment/docstring patterns
170
- r"(?:IMPLEMENTS|Implements|implements)[:\s]+(?:REQ[-_])?([pod]\d{5})(?:-[A-Z])?",
171
- # Direct requirement ID mentions
172
- r"\bREQ[-_]([pod]\d{5})(?:-[A-Z])?\b",
173
- ],
174
- },
175
- "hooks": {
176
- "pre_commit": True,
177
- "commit_msg": True,
178
- },
179
- }