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
@@ -1,213 +0,0 @@
1
- """
2
- elspais.trace_view.scanning - Implementation file scanning.
3
-
4
- Provides functions to scan implementation files for requirement references
5
- and associate them with requirements.
6
- """
7
-
8
- import re
9
- from pathlib import Path
10
- from typing import Dict, List, Optional, Set
11
-
12
- from elspais.trace_view.models import TraceViewRequirement
13
-
14
-
15
- def scan_implementation_files(
16
- requirements: Dict[str, TraceViewRequirement],
17
- impl_dirs: List[Path],
18
- repo_root: Path,
19
- mode: str = "core",
20
- sponsor: Optional[str] = None,
21
- quiet: bool = False,
22
- ) -> None:
23
- """Scan implementation files for requirement references.
24
-
25
- This function modifies the requirements dict in-place, adding
26
- implementation file references to each requirement.
27
-
28
- Args:
29
- requirements: Dict mapping requirement ID to TraceViewRequirement
30
- impl_dirs: List of directories to scan for implementations
31
- repo_root: Repository root for calculating relative paths
32
- mode: Scanning mode ('core', 'sponsor', 'combined')
33
- sponsor: Sponsor name for sponsor mode
34
- quiet: If True, suppress progress messages
35
- """
36
- # Pattern to match requirement references in code comments
37
- # Matches: REQ-p00001, REQ-o00042, REQ-d00156, REQ-CAL-d00001
38
- req_ref_pattern = re.compile(r"REQ-(?:([A-Z]+)-)?([pod]\d{5})")
39
-
40
- total_files_scanned = 0
41
- total_refs_found = 0
42
-
43
- for impl_dir in impl_dirs:
44
- if not impl_dir.exists():
45
- if not quiet:
46
- print(f" Warning: Implementation directory not found: {impl_dir}")
47
- continue
48
-
49
- # Apply mode-based filtering
50
- if _should_skip_directory(impl_dir, mode, sponsor):
51
- continue
52
-
53
- # Determine file patterns based on directory
54
- if impl_dir.name == "database":
55
- patterns = ["*.sql"]
56
- elif impl_dir.name in ["diary_app", "portal_app"]:
57
- patterns = ["**/*.dart"]
58
- else:
59
- # Default: scan common code file types
60
- patterns = ["**/*.dart", "**/*.sql", "**/*.py", "**/*.js", "**/*.ts"]
61
-
62
- for pattern in patterns:
63
- for file_path in impl_dir.glob(pattern):
64
- if file_path.is_file():
65
- # Skip files in sponsor directories if not in the right mode
66
- if _should_skip_file(file_path, mode, sponsor):
67
- continue
68
-
69
- total_files_scanned += 1
70
- refs = _scan_file_for_requirements(
71
- file_path, req_ref_pattern, requirements, repo_root
72
- )
73
- total_refs_found += len(refs)
74
-
75
- if not quiet:
76
- print(f" Scanned {total_files_scanned} implementation files")
77
- print(f" Found {total_refs_found} requirement references")
78
-
79
-
80
- def _scan_file_for_requirements(
81
- file_path: Path,
82
- pattern: re.Pattern,
83
- requirements: Dict[str, TraceViewRequirement],
84
- repo_root: Path,
85
- ) -> Set[str]:
86
- """Scan a single implementation file for requirement references.
87
-
88
- Args:
89
- file_path: Path to the file to scan
90
- pattern: Compiled regex pattern for matching REQ references
91
- requirements: Dict mapping requirement ID to TraceViewRequirement
92
- repo_root: Repository root for calculating relative paths
93
-
94
- Returns:
95
- Set of requirement IDs found in the file
96
- """
97
- try:
98
- content = file_path.read_text(encoding="utf-8")
99
- except (UnicodeDecodeError, PermissionError):
100
- # Skip files that can't be read
101
- return set()
102
-
103
- # Find all requirement IDs referenced in this file with their line numbers
104
- referenced_reqs: Set[str] = set()
105
-
106
- # Calculate relative path - handle external repos gracefully
107
- try:
108
- rel_path = file_path.relative_to(repo_root)
109
- except ValueError:
110
- # File is in external repo (not under repo_root)
111
- try:
112
- # Find the repo root of the external file (look for .git)
113
- external_root = file_path
114
- while external_root.parent != external_root:
115
- if (external_root / ".git").exists():
116
- break
117
- external_root = external_root.parent
118
-
119
- if (external_root / ".git").exists():
120
- # Use repo name + relative path within that repo
121
- rel_path = Path(external_root.name) / file_path.relative_to(external_root)
122
- else:
123
- # Fallback: use just the filename
124
- rel_path = Path(file_path.name)
125
- except Exception:
126
- # Ultimate fallback
127
- rel_path = Path(file_path.name)
128
-
129
- for match in pattern.finditer(content):
130
- sponsor_prefix = match.group(1) # May be None for core requirements
131
- req_id_core = match.group(2) # The core part (e.g., 'd00027')
132
-
133
- # Build full requirement ID (with sponsor prefix if present)
134
- if sponsor_prefix:
135
- req_id = f"{sponsor_prefix}-{req_id_core}"
136
- else:
137
- req_id = req_id_core
138
-
139
- referenced_reqs.add(req_id)
140
-
141
- # Calculate line number from match position
142
- line_num = content[: match.start()].count("\n") + 1
143
-
144
- # Add (file_path, line_number) tuple to requirement's implementation_files
145
- if req_id in requirements:
146
- impl_entry = (str(rel_path), line_num)
147
- # Avoid duplicates (same file, same line)
148
- if impl_entry not in requirements[req_id].implementation_files:
149
- requirements[req_id].implementation_files.append(impl_entry)
150
-
151
- return referenced_reqs
152
-
153
-
154
- def _should_skip_directory(dir_path: Path, mode: str, sponsor: Optional[str]) -> bool:
155
- """Check if a directory should be skipped based on mode.
156
-
157
- Args:
158
- dir_path: Path to the directory
159
- mode: Scanning mode ('core', 'sponsor', 'combined')
160
- sponsor: Sponsor name for sponsor mode
161
-
162
- Returns:
163
- True if the directory should be skipped
164
- """
165
- try:
166
- parts = dir_path.parts
167
- if "sponsor" in parts:
168
- sponsor_idx = parts.index("sponsor")
169
- if sponsor_idx + 1 < len(parts):
170
- dir_sponsor = parts[sponsor_idx + 1]
171
-
172
- # In core mode, skip all sponsor directories
173
- if mode == "core":
174
- return True
175
-
176
- # In sponsor mode, skip sponsor directories that don't match our sponsor
177
- if mode == "sponsor" and sponsor and dir_sponsor != sponsor:
178
- return True
179
-
180
- return False
181
- except (ValueError, IndexError):
182
- return False
183
-
184
-
185
- def _should_skip_file(file_path: Path, mode: str, sponsor: Optional[str]) -> bool:
186
- """Check if a file should be skipped based on mode.
187
-
188
- Args:
189
- file_path: Path to the file
190
- mode: Scanning mode ('core', 'sponsor', 'combined')
191
- sponsor: Sponsor name for sponsor mode
192
-
193
- Returns:
194
- True if the file should be skipped
195
- """
196
- try:
197
- parts = file_path.parts
198
- if "sponsor" in parts:
199
- sponsor_idx = parts.index("sponsor")
200
- if sponsor_idx + 1 < len(parts):
201
- file_sponsor = parts[sponsor_idx + 1]
202
-
203
- # In core mode, skip all sponsor files
204
- if mode == "core":
205
- return True
206
-
207
- # In sponsor mode, skip sponsor files that don't match our sponsor
208
- if mode == "sponsor" and sponsor and file_sponsor != sponsor:
209
- return True
210
-
211
- return False
212
- except (ValueError, IndexError):
213
- return False
@@ -1,84 +0,0 @@
1
- # trace_view Specifications
2
-
3
- This directory contains formal requirements for the trace_view HTML generator refactoring and collaborative review system.
4
-
5
- ## Scope
6
-
7
- These specifications define the requirements for:
8
- 1. Refactoring `trace_view/html/generator.py` from a 3,420-line monolithic class to a maintainable Jinja2-based template architecture
9
- 2. Adding a collaborative requirement review system with threaded comments, status workflows, and multi-user git-based synchronization
10
-
11
- ## ID Convention
12
-
13
- Requirements in this directory use a **local scope prefix** to distinguish them from main `spec/` requirements:
14
-
15
- - **Format**: `REQ-tv-{p|d|o}{number}[-{assertion}]`
16
- - **Prefix**: `tv-` (trace_view local scope)
17
- - **Types**:
18
- - `p` = PRD (Product Requirements)
19
- - `d` = Dev (Development Specifications)
20
- - `o` = Ops (Operations Documentation)
21
-
22
- **Examples**:
23
- - `REQ-tv-p00001` - Product requirement for HTML generator
24
- - `REQ-tv-d00003-B` - Assertion B of dev spec for JS extraction
25
-
26
- ## Specification Files
27
-
28
- ### HTML Generator (tv-p00001)
29
-
30
- | File | Type | Description |
31
- | ---- | ---- | ----------- |
32
- | `tv-p00001-html-generator.md` | PRD | High-level HTML generation requirements |
33
- | `tv-d00001-template-architecture.md` | Dev | Jinja2 template architecture |
34
- | `tv-d00002-css-extraction.md` | Dev | CSS extraction and embedding |
35
- | `tv-d00003-js-extraction.md` | Dev | JavaScript extraction and embedding |
36
- | `tv-d00004-build-embedding.md` | Dev | Build-time asset embedding |
37
- | `tv-d00005-test-format.md` | Dev | Test output format for elspais |
38
-
39
- ### Review System (tv-p00002)
40
-
41
- | File | Type | Description |
42
- | ---- | ---- | ----------- |
43
- | `tv-p00002-review-system.md` | PRD | Collaborative requirement review system |
44
- | `tv-d00010-review-data-models.md` | Dev | Thread, Comment, Position data models |
45
- | `tv-d00011-review-storage.md` | Dev | Atomic JSON CRUD operations |
46
- | `tv-d00012-position-resolution.md` | Dev | Position anchoring with drift handling |
47
- | `tv-d00013-git-branches.md` | Dev | reviews/{package}/{user} branch management |
48
- | `tv-d00014-review-api-server.md` | Dev | Flask API endpoints |
49
- | `tv-d00015-status-modifier.md` | Dev | REQ status changes in spec files |
50
- | `tv-d00016-js-integration.md` | Dev | JavaScript modules integration |
51
-
52
- ## Traceability
53
-
54
- ```
55
- REQ-tv-p00001 (PRD: HTML Generator)
56
- ├── REQ-tv-d00001 (Template Architecture)
57
- ├── REQ-tv-d00002 (CSS Extraction)
58
- ├── REQ-tv-d00003 (JS Extraction)
59
- ├── REQ-tv-d00004 (Build Embedding)
60
- └── REQ-tv-d00005 (Test Format)
61
-
62
- REQ-tv-p00002 (PRD: Review System)
63
- ├── REQ-tv-d00010 (Data Models)
64
- ├── REQ-tv-d00011 (Storage Operations)
65
- ├── REQ-tv-d00012 (Position Resolution)
66
- ├── REQ-tv-d00013 (Git Branches)
67
- ├── REQ-tv-d00014 (API Server)
68
- ├── REQ-tv-d00015 (Status Modifier)
69
- └── REQ-tv-d00016 (JS Integration)
70
- ```
71
-
72
- ## Standard Compliance
73
-
74
- All specifications follow the `spec/requirements-spec.md` standard:
75
-
76
- - Normative content uses **SHALL** language
77
- - Assertions are labeled A-Z
78
- - Each requirement has a content hash footer
79
- - Rationale sections are non-normative
80
-
81
- ## Related Documents
82
-
83
- - `/home/metagamer/.claude/plans/polymorphic-toasting-tiger.md` - Implementation plan
84
- - `spec/requirements-spec.md` - Requirements specification standard
@@ -1,36 +0,0 @@
1
- # REQ-tv-d00001: Jinja2 Template Architecture
2
-
3
- **Level**: Dev | **Status**: Draft | **Implements**: REQ-tv-p00001
4
-
5
- ## Assertions
6
-
7
- A. The HTMLGenerator class SHALL use a Jinja2 Environment for template rendering.
8
-
9
- B. Templates SHALL be loaded from a `templates/` subdirectory relative to the `html/` module.
10
-
11
- C. The template loader SHALL use FileSystemLoader with the templates directory path.
12
-
13
- D. The generator SHALL pass a context dictionary to template rendering containing: requirements data, coverage data, and configuration flags.
14
-
15
- E. The base template SHALL define the complete HTML document structure including DOCTYPE, html, head, and body elements.
16
-
17
- F. Template rendering SHALL support the `embed_content` flag to control data embedding mode.
18
-
19
- G. Template rendering SHALL support the `edit_mode` flag to control edit UI visibility.
20
-
21
- H. The generator class SHALL expose a `generate()` method with the same signature as the current implementation: `generate(embed_content: bool = False, edit_mode: bool = False) -> str`.
22
-
23
- I. Template errors SHALL be reported with meaningful error messages including template name and line number.
24
-
25
- ## Rationale
26
-
27
- Jinja2 is the industry-standard Python templating engine, used by Flask, Ansible, and many other projects. It provides:
28
- - Clear separation of logic and presentation
29
- - Template inheritance and includes for code reuse
30
- - Excellent IDE support (syntax highlighting, autocomplete)
31
- - Compiled templates for performance
32
- - Well-documented and actively maintained
33
-
34
- The FileSystemLoader approach allows templates to be edited as standalone files with proper syntax highlighting, while the `generate()` method signature ensures backward compatibility.
35
-
36
- *End* *Jinja2 Template Architecture* | **Hash**: 0141b0f8
@@ -1,37 +0,0 @@
1
- # REQ-tv-d00002: CSS Extraction
2
-
3
- **Level**: Dev | **Status**: Draft | **Implements**: REQ-tv-p00001
4
-
5
- ## Assertions
6
-
7
- A. All CSS rules SHALL be extracted from Python string literals to a standalone `styles.css` file located at `templates/partials/styles.css`.
8
-
9
- B. The CSS file SHALL contain all styling currently generated by the following methods: `_generate_side_panel_css()`, `_generate_code_viewer_css()`, `_generate_legend_modal_css()`, and `_generate_file_picker_modal_css()`.
10
-
11
- C. The CSS file SHALL be a valid CSS document that can be parsed by standard CSS tools and linters.
12
-
13
- D. The CSS file SHALL be readable by IDEs with proper syntax highlighting and autocomplete support.
14
-
15
- E. CSS content SHALL be loaded from the file at template render time.
16
-
17
- F. The extracted CSS SHALL produce visually identical output to the current inline CSS generation.
18
-
19
- G. CSS selectors and rules SHALL NOT be duplicated between the extracted file and any remaining inline styles.
20
-
21
- H. The CSS file SHALL use consistent formatting: 4-space indentation, one property per line, and blank lines between rule blocks.
22
-
23
- ## Rationale
24
-
25
- The current implementation embeds 629 lines of CSS across 4 Python methods as string literals. This approach:
26
- - Prevents IDE CSS support (linting, autoprefixer, minification)
27
- - Makes it difficult to detect duplicate selectors
28
- - Couples styling changes to Python code changes
29
- - Prevents use of CSS tooling
30
-
31
- Extracting CSS to a standalone file enables:
32
- - Proper IDE support for CSS editing
33
- - Use of CSS linters and formatters
34
- - Independent modification of styles
35
- - Easier review of styling changes
36
-
37
- *End* *CSS Extraction* | **Hash**: f31a509b
@@ -1,43 +0,0 @@
1
- # REQ-tv-d00003: JavaScript Extraction
2
-
3
- **Level**: Dev | **Status**: Draft | **Implements**: REQ-tv-p00001
4
-
5
- ## Assertions
6
-
7
- A. All JavaScript code SHALL be extracted from Python string literals to a standalone `scripts.js` file located at `templates/partials/scripts.js`.
8
-
9
- B. The JavaScript file SHALL contain all functionality currently generated by `_generate_side_panel_js()` and any other JavaScript-generating methods.
10
-
11
- C. The JavaScript file SHALL be a valid JavaScript document that can be parsed by standard JavaScript tools and linters.
12
-
13
- D. The JavaScript file SHALL be readable by IDEs with proper syntax highlighting, autocomplete, and error detection.
14
-
15
- E. JavaScript code SHALL be organized using a module pattern with a single namespace object (e.g., `TraceView`).
16
-
17
- F. The module pattern SHALL group related functions into logical sub-objects: `panel`, `codeViewer`, `editMode`, `state`.
18
-
19
- G. JavaScript content SHALL be loaded from the file at template render time.
20
-
21
- H. The extracted JavaScript SHALL produce functionally identical behavior to the current inline JavaScript generation.
22
-
23
- I. Global state variables (e.g., `reqCardStack`, `pendingMoves`) SHALL be encapsulated within the module namespace.
24
-
25
- J. Event handlers for dynamically created elements SHALL be bound using `addEventListener` rather than inline `onclick` attributes.
26
-
27
- K. The JavaScript file SHALL include JSDoc comments for all public functions.
28
-
29
- ## Rationale
30
-
31
- The current implementation embeds 736 lines of JavaScript in `_generate_side_panel_js()` as a Python string literal containing 28 functions. This approach:
32
- - Prevents IDE JavaScript support (linting, type checking, error detection)
33
- - Makes debugging difficult (errors reference Python line numbers, not JS)
34
- - Couples behavior changes to Python code changes
35
- - Uses global variables without encapsulation
36
-
37
- The module pattern provides:
38
- - Clear namespace to avoid global pollution
39
- - Logical grouping of related functionality
40
- - Encapsulated state management
41
- - Better testability
42
-
43
- *End* *JavaScript Extraction* | **Hash**: 297cf4c0
@@ -1,40 +0,0 @@
1
- # REQ-tv-d00004: Build-time Asset Embedding
2
-
3
- **Level**: Dev | **Status**: Draft | **Implements**: REQ-tv-p00001
4
-
5
- ## Assertions
6
-
7
- A. The generator SHALL embed CSS content inline within `<style>` tags in the generated HTML.
8
-
9
- B. The generator SHALL embed JavaScript content inline within `<script>` tags in the generated HTML.
10
-
11
- C. Asset files SHALL be read from disk at template render time, not at module import time.
12
-
13
- D. The generator SHALL provide a helper method `_load_css()` that reads and returns the CSS file content.
14
-
15
- E. The generator SHALL provide a helper method `_load_js()` that reads and returns the JavaScript file content.
16
-
17
- F. File reading errors SHALL raise informative exceptions including the expected file path.
18
-
19
- G. The generated HTML document SHALL be completely self-contained with no external file dependencies (except for CDN libraries in embedded mode).
20
-
21
- H. The embedding approach SHALL support Jinja2 template variables within embedded CSS and JavaScript content for dynamic values such as `base_path` and `repo_root`.
22
-
23
- I. The generator SHALL cache file content during a single render operation to avoid redundant disk reads.
24
-
25
- J. The embedded content SHALL be properly escaped to prevent HTML injection from file content (e.g., `</script>` within JavaScript).
26
-
27
- ## Rationale
28
-
29
- The goal is to develop with separate files for IDE support while producing a single self-contained HTML file for portability. This "develop separate, embed at build time" approach provides:
30
- - IDE support during development
31
- - Single-file distribution for end users
32
- - No web server required to view reports
33
- - Works offline after generation
34
-
35
- The caching and lazy loading approach ensures:
36
- - Files are read only when needed
37
- - Multiple templates can share the same CSS/JS without re-reading
38
- - Fresh content on each render (no stale module-level cache)
39
-
40
- *End* *Build-time Asset Embedding* | **Hash**: 177c0fd7
@@ -1,78 +0,0 @@
1
- # REQ-tv-d00005: Elspais Test Output Format
2
-
3
- **Level**: Dev | **Status**: Draft | **Implements**: REQ-tv-p00001
4
-
5
- ## Assertions
6
-
7
- A. Test runs SHALL produce a JSON output file at `tests/results/trace_results.json`.
8
-
9
- B. The JSON output SHALL conform to format version "1.0" as specified in this requirement.
10
-
11
- C. Each test result entry SHALL include: `requirement_id`, `assertion_id`, `full_id`, `test_name`, `test_file`, `test_line`, `status`, `duration_ms`, `error_message`, and `timestamp`.
12
-
13
- D. The `requirement_id` field SHALL contain the base requirement ID without assertion suffix (e.g., `REQ-tv-d00001`).
14
-
15
- E. The `assertion_id` field SHALL contain only the assertion letter (e.g., `A`) or null if the test covers the entire requirement.
16
-
17
- F. The `full_id` field SHALL contain the complete reference including assertion suffix if applicable (e.g., `REQ-tv-d00001-A`).
18
-
19
- G. The `status` field SHALL be one of: `passed`, `failed`, or `skipped`.
20
-
21
- H. The output SHALL include a `summary` object with: `total`, `passed`, `failed`, `skipped`, and `coverage_percentage` fields.
22
-
23
- I. Test functions SHALL include the requirement ID in their docstring for extraction by the reporter.
24
-
25
- J. A pytest plugin SHALL be implemented in `conftest.py` to generate the output automatically.
26
-
27
- K. The reporter SHALL extract requirement IDs from test docstrings using the pattern `REQ-tv-[pdo]\d{5}(?:-[A-Z])?`.
28
-
29
- L. The output file SHALL be generated at the end of the pytest session via `pytest_sessionfinish` hook.
30
-
31
- M. The `generated_at` field SHALL contain an ISO 8601 formatted timestamp.
32
-
33
- ## Rationale
34
-
35
- Elspais requires structured test results to incorporate into the traceability matrix. The JSON format enables:
36
- - Automated parsing and integration
37
- - Bidirectional traceability (requirements to tests, tests to requirements)
38
- - Coverage reporting at the assertion level
39
- - Historical tracking of test results
40
-
41
- The pytest plugin approach ensures:
42
- - Automatic generation without manual steps
43
- - Consistent format across all test runs
44
- - Integration with existing pytest workflows
45
- - No changes required to test execution commands
46
-
47
- ## Format Example
48
-
49
- ```json
50
- {
51
- "format_version": "1.0",
52
- "generated_at": "2026-01-03T12:34:56Z",
53
- "test_run_id": "abc123",
54
- "results": [
55
- {
56
- "requirement_id": "REQ-tv-d00001",
57
- "assertion_id": "A",
58
- "full_id": "REQ-tv-d00001-A",
59
- "test_name": "test_jinja2_environment_used",
60
- "test_file": "test_template_architecture.py",
61
- "test_line": 15,
62
- "status": "passed",
63
- "duration_ms": 12,
64
- "error_message": null,
65
- "timestamp": "2026-01-03T12:34:56.123Z"
66
- }
67
- ],
68
- "summary": {
69
- "total": 26,
70
- "passed": 24,
71
- "failed": 2,
72
- "skipped": 0,
73
- "coverage_percentage": 92.3
74
- }
75
- }
76
- ```
77
-
78
- *End* *Elspais Test Output Format* | **Hash**: 5219f9e0
@@ -1,33 +0,0 @@
1
- # REQ-tv-d00010: Review Data Models
2
-
3
- **Level**: Dev | **Status**: Draft | **Implements**: REQ-tv-p00002
4
-
5
- ## Assertions
6
-
7
- A. CommentPosition, Comment, Thread, ReviewFlag, StatusRequest, Approval, ReviewSession, ReviewConfig, and ReviewPackage SHALL be implemented as dataclasses.
8
-
9
- B. PositionType, RequestState, and ApprovalDecision SHALL be implemented as string enums for JSON compatibility.
10
-
11
- C. Each dataclass SHALL implement a `to_dict()` method returning a JSON-serializable dictionary.
12
-
13
- D. Each dataclass SHALL implement a `from_dict(data)` class method for deserialization from dictionaries.
14
-
15
- E. Each dataclass SHALL implement a `validate()` method returning a tuple of `(is_valid: bool, errors: List[str])`.
16
-
17
- F. Thread, Comment, StatusRequest, and ReviewPackage SHALL implement factory methods (`create()`) that auto-generate IDs and timestamps.
18
-
19
- G. ThreadsFile, StatusFile, and PackagesFile container classes SHALL manage file-level JSON structure with version tracking.
20
-
21
- H. CommentPosition SHALL support four anchor types: LINE (specific line), BLOCK (line range), WORD (keyword occurrence), and GENERAL (whole requirement).
22
-
23
- I. StatusRequest SHALL automatically calculate its state based on approval votes and configured approval rules.
24
-
25
- J. All dataclasses SHALL use UTC timestamps in ISO 8601 format.
26
-
27
- ## Rationale
28
-
29
- Dataclasses provide immutable-by-default data structures with auto-generated `__init__`, `__repr__`, and comparison methods. The `to_dict`/`from_dict` pattern enables clean JSON serialization without requiring JSON encoder customization. The `validate()` method enables explicit validation at boundaries rather than relying on exceptions during construction.
30
-
31
- The factory methods hide ID generation and timestamp creation from callers, ensuring consistent data creation patterns across the codebase.
32
-
33
- *End* *Review Data Models* | **Hash**: 00000000
@@ -1,33 +0,0 @@
1
- # REQ-tv-d00011: Review Storage Operations
2
-
3
- **Level**: Dev | **Status**: Draft | **Implements**: REQ-tv-p00002
4
-
5
- ## Assertions
6
-
7
- A. All JSON file writes SHALL use atomic write operations via temporary file creation followed by rename.
8
-
9
- B. Thread storage operations SHALL support: `load_threads()`, `save_threads()`, `add_thread()`, `add_comment_to_thread()`, `resolve_thread()`, and `unresolve_thread()`.
10
-
11
- C. Status request storage operations SHALL support: `load_status_requests()`, `save_status_requests()`, `create_status_request()`, `add_approval()`, and `mark_request_applied()`.
12
-
13
- D. Review flag storage operations SHALL support: `load_review_flag()` and `save_review_flag()`.
14
-
15
- E. Package storage operations SHALL support: `load_packages()`, `save_packages()`, `create_package()`, `update_package()`, `delete_package()`, `add_req_to_package()`, and `remove_req_from_package()`.
16
-
17
- F. Config storage operations SHALL support: `load_config()` and `save_config()` for system-wide settings.
18
-
19
- G. Merge operations SHALL support: `merge_threads()`, `merge_status_files()`, and `merge_review_flags()` for combining data from multiple user branches.
20
-
21
- H. Storage paths SHALL follow the convention: `.reviews/reqs/{normalized-req-id}/threads.json`, `.reviews/reqs/{normalized-req-id}/status.json`, `.reviews/packages.json`, and `.reviews/config.json`.
22
-
23
- I. Requirement IDs in paths SHALL be normalized by replacing colons and slashes with underscores.
24
-
25
- J. The merge strategy SHALL deduplicate by ID (threadId, requestId) and use timestamp-based conflict resolution for divergent edits.
26
-
27
- ## Rationale
28
-
29
- Atomic writes via temp+rename prevent data corruption from interrupted writes or concurrent access. The normalized path convention ensures filesystem compatibility across operating systems while maintaining readable directory structures.
30
-
31
- The merge operations enable the multi-user review workflow where each user works on their own branch and merges are performed when viewing consolidated package data.
32
-
33
- *End* *Review Storage Operations* | **Hash**: 00000000
@@ -1,33 +0,0 @@
1
- # REQ-tv-d00012: Position Resolution
2
-
3
- **Level**: Dev | **Status**: Draft | **Implements**: REQ-tv-p00002
4
-
5
- ## Assertions
6
-
7
- A. The position resolution system SHALL resolve CommentPosition anchors to current document coordinates.
8
-
9
- B. ResolvedPosition SHALL indicate confidence level: EXACT (hash matches), APPROXIMATE (fallback matched), or UNANCHORED (no match found).
10
-
11
- C. When the document hash matches the position's `hashWhenCreated`, the position SHALL resolve with EXACT confidence using stored coordinates.
12
-
13
- D. When the document hash differs, the system SHALL attempt fallback resolution using the `fallbackContext` field.
14
-
15
- E. For LINE positions, fallback resolution SHALL search for the context string and return the matching line number.
16
-
17
- F. For BLOCK positions, fallback resolution SHALL search for the context and expand to include the original block size.
18
-
19
- G. For WORD positions, fallback resolution SHALL search for the keyword and return the Nth occurrence based on `keywordOccurrence`.
20
-
21
- H. GENERAL positions SHALL always resolve with EXACT confidence since they apply to the entire requirement.
22
-
23
- I. ResolvedPosition SHALL include a `resolutionPath` field describing which fallback strategy was used.
24
-
25
- J. When no fallback succeeds, the position SHALL resolve as UNANCHORED with the original position preserved for manual re-anchoring.
26
-
27
- ## Rationale
28
-
29
- Position resolution enables comments to "survive" requirement edits. When a requirement is modified, its content hash changes, invalidating stored positions. The fallback strategies attempt to find where the commented content moved to, maintaining the spatial relationship between comments and content.
30
-
31
- The confidence levels allow the UI to display visual indicators (e.g., yellow warning for approximate, red for unanchored) so users know when manual review may be needed.
32
-
33
- *End* *Position Resolution* | **Hash**: 00000000
@@ -1,31 +0,0 @@
1
- # REQ-tv-d00013: Git Branch Management
2
-
3
- **Level**: Dev | **Status**: Draft | **Implements**: REQ-tv-p00002
4
-
5
- ## Assertions
6
-
7
- A. Review branches SHALL follow the naming convention `reviews/{package_id}/{username}`.
8
-
9
- B. `get_review_branch_name(package_id, user)` SHALL return the formatted branch name.
10
-
11
- C. `parse_review_branch_name(branch_name)` SHALL extract and return a tuple of `(package_id, username)` from a valid branch name.
12
-
13
- D. `is_review_branch(branch_name)` SHALL return True only for branches matching the `reviews/{package}/{user}` pattern.
14
-
15
- E. `list_package_branches(repo_root, package_id)` SHALL return all branch names for a given package across all users.
16
-
17
- F. `get_current_package_context(repo_root)` SHALL return `(package_id, username)` when on a review branch, or `(None, None)` otherwise.
18
-
19
- G. `commit_and_push_reviews(repo_root, message)` SHALL commit all changes in `.reviews/` and push to the remote tracking branch.
20
-
21
- H. Branch operations SHALL detect and report conflicts without causing data loss.
22
-
23
- I. `fetch_package_branches(repo_root, package_id)` SHALL fetch all remote branches for a package to enable merge operations.
24
-
25
- ## Rationale
26
-
27
- The branch-per-user-per-package model enables isolated work with eventual consistency. Each reviewer can work offline on their own branch, and data is consolidated when viewing the package by merging from all contributor branches.
28
-
29
- The naming convention makes it easy to discover all contributors to a package review and to filter branches by package.
30
-
31
- *End* *Git Branch Management* | **Hash**: 00000000