You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .spec-driver/deltas/DE-114-god_file_structural_splits_list_py_common_py_requirements_registry_py_creation_py_workflow_metadata_py/DE-114.md
- Draft and approve POL-003 to formalize coupling constraints (a layer may only import from itself or layers below it).
68
68
- Re-home and rename the obfuscatory `supekku/scripts/lib` paths into an explicit, layer-aligned package structure (e.g., `spec_driver/core/`, `spec_driver/domain/`).
69
+
- Separate fast unit tests (sitting alongside their target code) from slow integration tests (re-homed to `tests/integration/` and invoked via a separate command).
69
70
- **Operational Constraints**:
70
71
- The refactoring must be mechanically verifiable (e.g., via `import-linter` or explicit CI checks).
71
72
- Must not change the external CLI behaviour or workflow artifact schemas.
@@ -81,7 +82,7 @@ Before executing symptomatic refactorings, we must define the structural bluepri
81
82
## 5. Approach Overview
82
83
83
84
- **Phase 1: Blueprint & Policy**: Thrash out the layer definitions in DR-125 and ratify POL-003.
84
-
- **Phase 2: Establish API Shell & Boundaries**: Create the `spec_driver/__init__.py` and `spec_driver/workflow/__init__.py` public APIs. Re-import necessary types/functions from `supekku` to immediately unblock `autobahn` (DE-124). Establish explicit `__all__` exports in `spec_driver` internal layers.
85
+
- **Phase 2: Establish API Shell & Boundaries**: Create the `spec_driver/__init__.py` and `spec_driver/orchestration/__init__.py` public APIs. Re-import necessary types/functions from `supekku` to immediately unblock `autobahn` (DE-124). Establish explicit `__all__` exports in `spec_driver` internal layers.
85
86
- **Phase 3: Enforcement**: Configure `import-linter` in `pyproject.toml` to rigidly enforce the layers for `spec_driver/`. Set `pylint` to aggressively fail for `spec_driver/` while remaining lenient on `supekku/`.
86
87
- **Phase 4: The Strangler Fig Move**: Move individual files from `supekku/` to `spec_driver/` one by one. Fix their import graphs as they move, utilizing the strict internal boundaries.
87
88
- **Phase 5: Cleanup**: Eradicate `supekku/` once empty. This naturally resolves the god-init problem (DE-114).
***Responsibility:** The "verbs" of the system. Coordinating multi-step state transitions, executing syncs across the registry, evaluating operational readiness.
105
105
***Coupling Rules:** May import from all layers below. Must **not** import from the presentation layer. This layer represents the boundary for the Public API Facade (DE-124).
***Responsibility:** Argument parsing, user interaction, formatting terminal output, rendering UIs.
111
111
***Coupling Rules:** May import from any layer below. Must **never** contain inline business logic or state transitions (enforces the Skinny CLI pattern).
112
112
113
+
### Intra-Layer Coupling (Isolation & Sub-layers)
114
+
115
+
To prevent large layers (like the 5,000+ LOC TUI) from becoming internal hairballs, we apply secondary constraints within the layers:
116
+
117
+
1.**Independence Contracts (Isolation):** Sibling packages that have no reason to talk to each other must be explicitly isolated. For example, `spec_driver.presentation.cli` and `spec_driver.presentation.tui` must be declared independent (neither may import the other).
118
+
2.**Sub-layering:** Large packages get their own internal `layers` contract. The TUI, for example, will be structured as:
A secondary goal of this refactoring is to dramatically improve the feedback loop by separating fast unit tests from slow integration tests.
127
+
128
+
***Unit Tests:** Must sit alongside the code they test (e.g., `spec_driver/core/file_ops_test.py`). They must be fast, isolated, and free of slow I/O or full-system initialization. **Import Constraint:** Unit tests are strictly bound by the same layer constraints as their target code. A test in `spec_driver.domain` may mock an orchestration component, but it may not import it.
129
+
***Integration Tests:** Must be re-homed to a dedicated `tests/integration/` directory at the repository root. These tests exercise the composed layers (e.g., CLI-to-disk workflows) and can be executed via a separate runner command (e.g., `just test-integration`), keeping the primary `just test` suite lightning fast. **Import Constraint:** Because they reside outside the `spec_driver` namespace, integration tests are exempt from the internal layer constraints and act as top-level consumers.
130
+
113
131
## 4. Re-homing & Renaming Strategy
114
132
115
133
The `supekku` package name and `scripts/lib` path prefix are legacy cruft. The new package root will be `spec_driver/`.
When moving files, use the following heuristics to resolve ambiguity, especially for modules that currently conflate multiple responsibilities:
138
+
139
+
***Heuristic 1: Does it enforce a domain rule or execute a multi-step process?**
140
+
**Example:*`validation/validator.py` cross-checks multiple registries to ensure relations are valid. Because it coordinates across registries but does not mutate disk state or perform side-effects, it belongs in `spec_driver/domain/validation/`.
141
+
**Example:*`sync/` adapters pull external states (like code comments) and create requirements. Because this involves I/O, network (potentially), and mutation of the workspace, it belongs in `spec_driver/orchestration/sync/`.
142
+
***Heuristic 2: Is it the definition of a state, or the act of transitioning?**
143
+
**Example:*`workflow/state_machine.py` defines the valid states and the matrix of allowed transitions. This is a pure domain rule. It belongs in `spec_driver/domain/workflow/state_machine.py` (or even `spec_driver/models/workflow.py` if reduced to pure Enums).
144
+
**Example:*`workflow/review_io.py` and the execution of `prime_review` perform I/O, evaluate staleness, and mutate the artifact's state. This belongs in `spec_driver/orchestration/review.py`.
145
+
***Heuristic 3: Does it represent the physical constraints of the repo, or the domain concepts?**
146
+
**Example:*`workspace.py` knows about `.spec-driver/registry/` and the repo root. It is foundational I/O context. It belongs in `spec_driver/core/workspace.py`.
This contract explicitly bans upward imports, causing the CI pipeline to fail if an orchestration module accidentally imports a CLI formatter, or if a model imports a registry.
146
199
147
200
## 6. Rollout & Sequence
148
201
149
202
1.**Blueprint & Policy**: Finalize and ratify **DR-125** and **POL-003**.
150
203
2.**Setup Enforcer**: Add `import-linter` to `pyproject.toml` and configure the initial contracts. Tune the linter and `pylint` for aggressive failure for the new `spec_driver/` package (while maintaining the existing threshold for `supekku/`).
151
-
3.**Establish API Shell**: Create the `spec_driver/__init__.py` and `spec_driver/workflow/__init__.py` skeleton. Temporarily re-import the necessary functions/types from `supekku/*` to fulfill the Public API Facade (DE-124) without moving the underlying code yet.
204
+
3.**Establish API Shell**: Create the `spec_driver/__init__.py` and `spec_driver/orchestration/__init__.py` skeleton. Temporarily re-import the necessary functions/types from `supekku/*` to fulfill the Public API Facade (DE-124) without moving the underlying code yet.
152
205
4.**Establish Internal Boundaries**: Create internal boundary APIs within `spec_driver/` (e.g. `spec_driver.domain`) that strictly re-export a reduced set of functions and types.
153
206
5.**The Strangler Fig Move**: Move individual files from `supekku/scripts/lib/` to `spec_driver/` one at a time. As each file is moved, fix its import graph so it strictly relies on the new `spec_driver` boundary APIs. The aggressive linter rules will validate each moved file.
154
207
6.**Decouple & Cleanup**: Eradicate `supekku/scripts/lib` entirely once the strangler fig migration is complete. This will naturally resolve the god-init problem (DE-114).
155
208
156
-
## 7. Open Questions
209
+
## 7. Open Questions / Decisions
157
210
158
-
-**OQ-125-001**: Should `autobahn` remain a separate top-level Python package alongside `spec_driver`, or be pulled inside the `spec_driver` namespace (e.g. `spec_driver.autobahn`)?
159
-
-**OQ-125-002**: Are there specific modules in `supekku/scripts/lib` whose layer assignment is ambiguous (e.g., formatters)?
160
-
_Proposed Answer: Formatters belong in the Presentation layer, or a dedicated `spec_driver/presentation/formatters/` package if shared between CLI and TUI._
211
+
-**DEC-125-005 (autobahn):**`autobahn` will remain a separate top-level Python package (and repository, currently). This strictly enforces the architectural boundary: `autobahn` is a downstream consumer of `spec_driver.orchestration` and cannot accidentally bypass the facade to import internal models or domain logic. Dogfooding the public API via a completely separate package proves the API's completeness (DE-124).
212
+
-**DEC-125-006 (formatters):** Formatters will be split based on their purity and dependencies. Pure string manipulation or data-to-string formatters that do not depend on presentation libraries (like `rich` or `textual`) or orchestration logic belong in `spec_driver/core/formatters/` or `spec_driver/models/formatters/`. Formatters that are inherently tied to terminal presentation (e.g., rendering `rich` Tables or `textual` widgets) belong in `spec_driver/presentation/formatters/`. This ensures pure formatting logic is reusable across the entire stack while keeping presentation dependencies isolated at the top.
***Responsibility**: Argument parsing, formatting, terminal interaction, and user interface.
46
46
***Constraint**: Must follow the "Skinny CLI" pattern. May import from any layer below. Must **never** contain domain logic or state transitions.
47
47
@@ -51,7 +51,12 @@ Without explicit boundaries, internal dependencies become cyclic and untraceable
51
51
52
52
## Scope
53
53
54
-
Applies to all production Python code in the `spec-driver` repository. Existing legacy code in `supekku/` must be migrated to the `spec_driver/` package structure and aligned with these layers via DE-125.
54
+
Applies to all production Python code in the `spec-driver` repository, including unit tests.
55
+
56
+
***Unit Tests:** Must reside within the `spec_driver/` package alongside the code they test (e.g., `spec_driver/core/file_ops_test.py`) and are strictly bound by the identical layer constraints as their targets. For instance, a domain test may not import orchestration modules to set up its fixtures.
57
+
***Integration Tests:** Must be located in a top-level `tests/integration/` directory outside the `spec_driver/` package. Because they sit outside the enforced package, they act as top-level consumers and are exempt from internal layer constraints.
58
+
59
+
Existing legacy code in `supekku/` must be migrated to the `spec_driver/` package structure and aligned with these layers via DE-125.
0 commit comments