atdd 0.3.3__py3-none-any.whl → 0.4.1__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 (70) hide show
  1. atdd/cli.py +223 -76
  2. atdd/coach/commands/add_persistence_metadata.py +3 -1
  3. atdd/coach/commands/infer_governance_status.py +3 -1
  4. atdd/coach/commands/interface.py +3 -1
  5. atdd/coach/commands/inventory.py +2 -2
  6. atdd/coach/commands/migration.py +11 -6
  7. atdd/coach/commands/test_runner.py +66 -27
  8. atdd/coach/commands/traceability.py +3 -1
  9. atdd/coach/conventions/session.convention.yaml +26 -26
  10. atdd/coach/templates/ATDD.md +15 -15
  11. atdd/coach/templates/SESSION-TEMPLATE.md +12 -12
  12. atdd/coach/utils/repo.py +24 -8
  13. atdd/coach/validators/shared_fixtures.py +27 -14
  14. atdd/coach/validators/test_session_validation.py +4 -4
  15. atdd/coder/conventions/commons.convention.yaml +1 -1
  16. atdd/coder/conventions/tests/test_component_taxonomy.py +4 -3
  17. atdd/coder/conventions/tests/test_component_urn_naming.py +9 -3
  18. atdd/coder/validators/test_commons_structure.py +9 -2
  19. atdd/coder/validators/test_complexity.py +3 -1
  20. atdd/coder/validators/test_cross_language_consistency.py +3 -1
  21. atdd/coder/validators/test_design_system_compliance.py +3 -1
  22. atdd/coder/validators/test_dto_testing_patterns.py +10 -3
  23. atdd/coder/validators/test_green_cross_stack_layers.py +9 -3
  24. atdd/coder/validators/test_green_layer_dependencies.py +9 -3
  25. atdd/coder/validators/test_green_python_layer_structure.py +8 -2
  26. atdd/coder/validators/test_green_supabase_layer_structure.py +8 -3
  27. atdd/coder/validators/test_import_boundaries.py +3 -1
  28. atdd/coder/validators/test_init_file_urns.py +3 -1
  29. atdd/coder/validators/test_preact_layer_boundaries.py +3 -1
  30. atdd/coder/validators/test_presentation_convention.py +3 -1
  31. atdd/coder/validators/test_python_architecture.py +9 -2
  32. atdd/coder/validators/test_quality_metrics.py +2 -1
  33. atdd/coder/validators/test_station_master_pattern.py +4 -2
  34. atdd/coder/validators/test_train_infrastructure.py +9 -2
  35. atdd/coder/validators/test_train_urns.py +9 -2
  36. atdd/coder/validators/test_typescript_architecture.py +10 -3
  37. atdd/coder/validators/test_usecase_structure.py +3 -1
  38. atdd/coder/validators/test_wagon_boundaries.py +8 -2
  39. atdd/planner/validators/test_plan_urn_resolution.py +3 -1
  40. atdd/planner/validators/test_wagon_urn_chain.py +3 -1
  41. atdd/planner/validators/test_wmbt_consistency.py +3 -1
  42. atdd/planner/validators/test_wmbt_vocabulary.py +8 -2
  43. atdd/tester/conventions/contract.convention.yaml +1 -1
  44. atdd/tester/conventions/migration.convention.yaml +5 -5
  45. atdd/tester/validators/cleanup_duplicate_headers.py +3 -1
  46. atdd/tester/validators/cleanup_duplicate_headers_v2.py +3 -1
  47. atdd/tester/validators/coverage_gap_report.py +3 -1
  48. atdd/tester/validators/fix_dual_ac_references.py +3 -1
  49. atdd/tester/validators/remove_duplicate_lines.py +3 -1
  50. atdd/tester/validators/test_acceptance_urn_filename_mapping.py +9 -3
  51. atdd/tester/validators/test_acceptance_urn_separator.py +9 -3
  52. atdd/tester/validators/test_contract_schema_compliance.py +9 -2
  53. atdd/tester/validators/test_contracts_structure.py +3 -1
  54. atdd/tester/validators/test_coverage_adequacy.py +3 -1
  55. atdd/tester/validators/test_dual_ac_reference.py +6 -2
  56. atdd/tester/validators/test_fixture_validity.py +2 -1
  57. atdd/tester/validators/test_isolation.py +9 -2
  58. atdd/tester/validators/test_migration_coverage.py +4 -2
  59. atdd/tester/validators/test_migration_generation.py +3 -1
  60. atdd/tester/validators/test_python_test_naming.py +3 -1
  61. atdd/tester/validators/test_red_layer_validation.py +7 -2
  62. atdd/tester/validators/test_red_python_layer_structure.py +7 -2
  63. atdd/tester/validators/test_red_supabase_layer_structure.py +8 -2
  64. atdd/tester/validators/test_telemetry_structure.py +9 -2
  65. {atdd-0.3.3.dist-info → atdd-0.4.1.dist-info}/METADATA +41 -12
  66. {atdd-0.3.3.dist-info → atdd-0.4.1.dist-info}/RECORD +70 -70
  67. {atdd-0.3.3.dist-info → atdd-0.4.1.dist-info}/WHEEL +0 -0
  68. {atdd-0.3.3.dist-info → atdd-0.4.1.dist-info}/entry_points.txt +0 -0
  69. {atdd-0.3.3.dist-info → atdd-0.4.1.dist-info}/licenses/LICENSE +0 -0
  70. {atdd-0.3.3.dist-info → atdd-0.4.1.dist-info}/top_level.txt +0 -0
@@ -2,6 +2,14 @@
2
2
  Shared fixtures for platform tests.
3
3
 
4
4
  Provides schemas, file discovery, and validation utilities for E2E platform tests.
5
+
6
+ Path resolution strategy:
7
+ - REPO_ROOT (via find_repo_root()) = consumer repository artifacts (plan/, contracts/, etc.)
8
+ - ATDD_PKG_DIR (via atdd.__file__) = installed package resources (schemas, conventions)
9
+
10
+ Validators should use:
11
+ - REPO_ROOT for consumer repo artifacts (plan/, contracts/, telemetry/, web/, python/)
12
+ - ATDD_PKG_DIR for package-bundled resources (schemas, conventions, templates)
5
13
  """
6
14
  import json
7
15
  import yaml
@@ -9,51 +17,56 @@ from pathlib import Path
9
17
  from typing import Dict, Any, List, Tuple
10
18
  import pytest
11
19
 
20
+ import atdd
21
+ from atdd.coach.utils.repo import find_repo_root
22
+
12
23
 
13
24
  # Path constants
14
- # File is at atdd/coach/audits/shared_fixtures.py, so go up 3 levels to reach repo root
15
- REPO_ROOT = Path(__file__).resolve().parents[4]
25
+ # Consumer repo artifacts - use find_repo_root() to locate consumer repository
26
+ REPO_ROOT = find_repo_root()
16
27
  PLAN_DIR = REPO_ROOT / "plan"
17
- ATDD_DIR = REPO_ROOT / "atdd"
18
28
  CONTRACTS_DIR = REPO_ROOT / "contracts"
19
29
  TELEMETRY_DIR = REPO_ROOT / "telemetry"
20
30
  WEB_DIR = REPO_ROOT / "web"
21
31
 
32
+ # Package resources - use atdd.__file__ to locate installed package
33
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
34
+
22
35
 
23
- # Schema fixtures - Planner schemas
36
+ # Schema fixtures - Planner schemas (loaded from installed package)
24
37
  @pytest.fixture(scope="module")
25
38
  def wagon_schema() -> Dict[str, Any]:
26
39
  """Load wagon.schema.json for validation."""
27
- with open(ATDD_DIR / "planner/schemas/wagon.schema.json") as f:
40
+ with open(ATDD_PKG_DIR / "planner/schemas/wagon.schema.json") as f:
28
41
  return json.load(f)
29
42
 
30
43
 
31
44
  @pytest.fixture(scope="module")
32
45
  def wmbt_schema() -> Dict[str, Any]:
33
46
  """Load wmbt.schema.json for validation."""
34
- with open(ATDD_DIR / "planner/schemas/wmbt.schema.json") as f:
47
+ with open(ATDD_PKG_DIR / "planner/schemas/wmbt.schema.json") as f:
35
48
  return json.load(f)
36
49
 
37
50
 
38
51
  @pytest.fixture(scope="module")
39
52
  def feature_schema() -> Dict[str, Any]:
40
53
  """Load feature.schema.json for validation."""
41
- with open(ATDD_DIR / "planner/schemas/feature.schema.json") as f:
54
+ with open(ATDD_PKG_DIR / "planner/schemas/feature.schema.json") as f:
42
55
  return json.load(f)
43
56
 
44
57
 
45
58
  @pytest.fixture(scope="module")
46
59
  def acceptance_schema() -> Dict[str, Any]:
47
60
  """Load acceptance.schema.json for validation."""
48
- with open(ATDD_DIR / "planner/schemas/acceptance.schema.json") as f:
61
+ with open(ATDD_PKG_DIR / "planner/schemas/acceptance.schema.json") as f:
49
62
  return json.load(f)
50
63
 
51
64
 
52
- # Schema fixtures - Tester schemas
65
+ # Schema fixtures - Tester schemas (loaded from installed package)
53
66
  @pytest.fixture(scope="module")
54
67
  def telemetry_signal_schema() -> Dict[str, Any]:
55
68
  """Load telemetry_signal.schema.json for validation."""
56
- schema_path = ATDD_DIR / "tester/schemas/telemetry_signal.schema.json"
69
+ schema_path = ATDD_PKG_DIR / "tester/schemas/telemetry_signal.schema.json"
57
70
  if schema_path.exists():
58
71
  with open(schema_path) as f:
59
72
  return json.load(f)
@@ -63,20 +76,20 @@ def telemetry_signal_schema() -> Dict[str, Any]:
63
76
  @pytest.fixture(scope="module")
64
77
  def telemetry_tracking_manifest_schema() -> Dict[str, Any]:
65
78
  """Load telemetry_tracking_manifest.schema.json for validation."""
66
- schema_path = ATDD_DIR / "tester/schemas/telemetry_tracking_manifest.schema.json"
79
+ schema_path = ATDD_PKG_DIR / "tester/schemas/telemetry_tracking_manifest.schema.json"
67
80
  if schema_path.exists():
68
81
  with open(schema_path) as f:
69
82
  return json.load(f)
70
83
  return {}
71
84
 
72
85
 
73
- # Generic schema loader
86
+ # Generic schema loader (loads from installed package)
74
87
  @pytest.fixture(scope="module")
75
88
  def load_schema():
76
89
  """Factory fixture to load any schema by path."""
77
90
  def _loader(agent: str, schema_name: str) -> Dict[str, Any]:
78
91
  """
79
- Load a schema from atdd/{agent}/schemas/{schema_name}.
92
+ Load a schema from the installed atdd package.
80
93
 
81
94
  Args:
82
95
  agent: Agent name (planner, tester, coach, coder)
@@ -85,7 +98,7 @@ def load_schema():
85
98
  Returns:
86
99
  Parsed JSON schema
87
100
  """
88
- schema_path = ATDD_DIR / agent / "schemas" / schema_name
101
+ schema_path = ATDD_PKG_DIR / agent / "schemas" / schema_name
89
102
  if not schema_path.exists():
90
103
  raise FileNotFoundError(f"Schema not found: {schema_path}")
91
104
  with open(schema_path) as f:
@@ -12,7 +12,7 @@ Supports two formats:
12
12
  1. Hybrid (new): YAML frontmatter + Markdown body
13
13
  2. Legacy: Pure Markdown with **Field:** patterns
14
14
 
15
- Run: python3 -m pytest src/atdd/coach/validators/test_session_validation.py -v
15
+ Run: atdd validate coach
16
16
  """
17
17
  import pytest
18
18
  import re
@@ -20,19 +20,19 @@ from pathlib import Path
20
20
  from typing import List, Dict, Optional, Set, Tuple, Any
21
21
  import yaml
22
22
 
23
+ from atdd.coach.utils.repo import find_repo_root
23
24
 
24
25
  # ============================================================================
25
26
  # Configuration
26
27
  # ============================================================================
27
28
 
28
- # Package paths (relative to this file)
29
+ # Package paths (relative to this file) - for loading package resources
29
30
  ATDD_PKG_ROOT = Path(__file__).parent.parent.parent # src/atdd
30
31
  CONVENTION_FILE = ATDD_PKG_ROOT / "coach" / "conventions" / "session.convention.yaml"
31
32
  TEMPLATE_FILE = ATDD_PKG_ROOT / "coach" / "templates" / "SESSION-TEMPLATE.md"
32
33
 
33
34
  # Consumer repo paths (where sessions are created via `atdd init`)
34
- # Default to current working directory, can be overridden
35
- REPO_ROOT = Path.cwd()
35
+ REPO_ROOT = find_repo_root()
36
36
  SESSIONS_DIR = REPO_ROOT / "atdd-sessions"
37
37
 
38
38
  # Valid values from convention
@@ -457,4 +457,4 @@ migration:
457
457
  commands:
458
458
  - "cd web && npx tsc --noEmit"
459
459
  - "cd web && npm test"
460
- - "./atdd/atdd.py --test coder -k commons"
460
+ - "atdd validate coder -k commons"
@@ -9,6 +9,8 @@ import yaml
9
9
  from pathlib import Path
10
10
  from typing import Dict, Any, List
11
11
 
12
+ from atdd.coach.utils.repo import find_repo_root
13
+
12
14
 
13
15
  # Utility functions for loading YAML files
14
16
  def load_yaml(file_path: Path) -> Dict[str, Any]:
@@ -18,9 +20,8 @@ def load_yaml(file_path: Path) -> Dict[str, Any]:
18
20
 
19
21
 
20
22
  def get_project_root() -> Path:
21
- """Get the project root directory."""
22
- # From tests/ directory, go up 4 levels: tests -> conventions -> coder -> atdd -> root
23
- return Path(__file__).parent.parent.parent.parent.parent
23
+ """Get the consumer project root directory."""
24
+ return find_repo_root()
24
25
 
25
26
 
26
27
  def load_convention_backend() -> Dict[str, Any]:
@@ -7,9 +7,15 @@ import pytest
7
7
  import yaml
8
8
  from pathlib import Path
9
9
 
10
- REPO_ROOT = Path(__file__).resolve().parents[5]
11
- COMPONENT_NAMING_PATH = REPO_ROOT / "atdd/coder/conventions/component-naming.convention.yaml"
12
- GREEN_CONV_PATH = REPO_ROOT / "atdd/coder/conventions/green.convention.yaml"
10
+ import atdd
11
+ from atdd.coach.utils.repo import find_repo_root
12
+
13
+ REPO_ROOT = find_repo_root()
14
+
15
+ # Package resources (conventions, schemas)
16
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
17
+ COMPONENT_NAMING_PATH = ATDD_PKG_DIR / "coder/conventions/component-naming.convention.yaml"
18
+ GREEN_CONV_PATH = ATDD_PKG_DIR / "coder/conventions/green.convention.yaml"
13
19
 
14
20
 
15
21
  def test_coder_convention_uses_colon_hierarchy():
@@ -18,12 +18,19 @@ import re
18
18
  from pathlib import Path
19
19
  from typing import List
20
20
 
21
+ import atdd
22
+ from atdd.coach.utils.repo import find_repo_root
21
23
 
22
- REPO_ROOT = Path(__file__).resolve().parents[4]
24
+
25
+ # Consumer repo artifacts
26
+ REPO_ROOT = find_repo_root()
23
27
  PYTHON_COMMONS = REPO_ROOT / "python" / "commons"
24
28
  WEB_COMMONS = REPO_ROOT / "web" / "src" / "commons"
25
29
  WEB_SRC = REPO_ROOT / "web" / "src"
26
30
 
31
+ # Package resources (conventions, schemas)
32
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
33
+
27
34
 
28
35
  # ============================================================================
29
36
  # CROSS-STACK VALIDATION
@@ -457,7 +464,7 @@ def test_structural_patterns_documented():
457
464
 
458
465
  Validates: Convention documents intentional divergence
459
466
  """
460
- convention_file = REPO_ROOT / "atdd" / "coder" / "conventions" / "commons.convention.yaml"
467
+ convention_file = ATDD_PKG_DIR / "coder" / "conventions" / "commons.convention.yaml"
461
468
 
462
469
  if not convention_file.exists():
463
470
  pytest.fail(
@@ -16,9 +16,11 @@ import re
16
16
  from pathlib import Path
17
17
  from typing import List, Tuple
18
18
 
19
+ from atdd.coach.utils.repo import find_repo_root
20
+
19
21
 
20
22
  # Path constants
21
- REPO_ROOT = Path(__file__).resolve().parents[3]
23
+ REPO_ROOT = find_repo_root()
22
24
  PYTHON_DIR = REPO_ROOT / "python"
23
25
 
24
26
 
@@ -17,9 +17,11 @@ import json
17
17
  from pathlib import Path
18
18
  from typing import Dict, List, Set
19
19
 
20
+ from atdd.coach.utils.repo import find_repo_root
21
+
20
22
 
21
23
  # Path constants
22
- REPO_ROOT = Path(__file__).resolve().parents[3]
24
+ REPO_ROOT = find_repo_root()
23
25
  PYTHON_DIR = REPO_ROOT / "python"
24
26
  LIB_DIR = REPO_ROOT / "lib"
25
27
  SUPABASE_DIR = REPO_ROOT / "supabase"
@@ -15,9 +15,11 @@ import re
15
15
  from pathlib import Path
16
16
  from typing import List, Set, Dict, Tuple
17
17
 
18
+ from atdd.coach.utils.repo import find_repo_root
19
+
18
20
 
19
21
  # Path constants
20
- REPO_ROOT = Path(__file__).resolve().parents[4]
22
+ REPO_ROOT = find_repo_root()
21
23
  WEB_SRC = REPO_ROOT / "web" / "src"
22
24
  MAINTAIN_UX = WEB_SRC / "maintain-ux"
23
25
  PRIMITIVES_DIR = MAINTAIN_UX / "primitives"
@@ -25,11 +25,18 @@ import ast
25
25
  from pathlib import Path
26
26
  from typing import List, Tuple, Set
27
27
 
28
+ import atdd
29
+ from atdd.coach.utils.repo import find_repo_root
30
+
28
31
 
29
32
  # Path constants
30
- REPO_ROOT = Path(__file__).resolve().parents[4]
33
+ # Consumer repo artifacts
34
+ REPO_ROOT = find_repo_root()
31
35
  PYTHON_DIR = REPO_ROOT / "python"
32
- DTO_CONVENTION = REPO_ROOT / "atdd" / "coder" / "conventions" / "dto.convention.yaml"
36
+
37
+ # Package resources (conventions, schemas)
38
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
39
+ DTO_CONVENTION = ATDD_PKG_DIR / "coder" / "conventions" / "dto.convention.yaml"
33
40
 
34
41
 
35
42
  def find_integration_test_files() -> List[Path]:
@@ -264,5 +271,5 @@ class TestDTOTestingPatterns:
264
271
 
265
272
 
266
273
  if __name__ == '__main__':
267
- # Run with: pytest atdd/coder/test_dto_testing_patterns.py -v
274
+ # Run with: atdd validate coder
268
275
  pytest.main([__file__, '-v'])
@@ -8,10 +8,16 @@ import pytest
8
8
  from pathlib import Path
9
9
  import yaml
10
10
 
11
+ import atdd
12
+ from atdd.coach.utils.repo import find_repo_root
11
13
 
12
- REPO_ROOT = Path(__file__).resolve().parents[4]
13
- BACKEND_CONVENTION = REPO_ROOT / "atdd" / "coder" / "conventions" / "backend.convention.yaml"
14
- FRONTEND_CONVENTION = REPO_ROOT / "atdd" / "coder" / "conventions" / "frontend.convention.yaml"
14
+
15
+ REPO_ROOT = find_repo_root()
16
+
17
+ # Package resources (conventions, schemas)
18
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
19
+ BACKEND_CONVENTION = ATDD_PKG_DIR / "coder" / "conventions" / "backend.convention.yaml"
20
+ FRONTEND_CONVENTION = ATDD_PKG_DIR / "coder" / "conventions" / "frontend.convention.yaml"
15
21
 
16
22
 
17
23
  @pytest.mark.coder
@@ -8,10 +8,16 @@ import pytest
8
8
  from pathlib import Path
9
9
  import yaml
10
10
 
11
+ import atdd
12
+ from atdd.coach.utils.repo import find_repo_root
11
13
 
12
- REPO_ROOT = Path(__file__).resolve().parents[4]
13
- BACKEND_CONVENTION = REPO_ROOT / "atdd" / "coder" / "conventions" / "backend.convention.yaml"
14
- FRONTEND_CONVENTION = REPO_ROOT / "atdd" / "coder" / "conventions" / "frontend.convention.yaml"
14
+
15
+ REPO_ROOT = find_repo_root()
16
+
17
+ # Package resources (conventions, schemas)
18
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
19
+ BACKEND_CONVENTION = ATDD_PKG_DIR / "coder" / "conventions" / "backend.convention.yaml"
20
+ FRONTEND_CONVENTION = ATDD_PKG_DIR / "coder" / "conventions" / "frontend.convention.yaml"
15
21
 
16
22
 
17
23
  @pytest.mark.coder
@@ -8,9 +8,15 @@ import pytest
8
8
  from pathlib import Path
9
9
  import yaml
10
10
 
11
+ import atdd
12
+ from atdd.coach.utils.repo import find_repo_root
11
13
 
12
- REPO_ROOT = Path(__file__).resolve().parents[4]
13
- BACKEND_CONVENTION = REPO_ROOT / "atdd" / "coder" / "conventions" / "backend.convention.yaml"
14
+
15
+ REPO_ROOT = find_repo_root()
16
+
17
+ # Package resources (conventions, schemas)
18
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
19
+ BACKEND_CONVENTION = ATDD_PKG_DIR / "coder" / "conventions" / "backend.convention.yaml"
14
20
 
15
21
 
16
22
  @pytest.mark.coder
@@ -8,10 +8,15 @@ import pytest
8
8
  from pathlib import Path
9
9
  import yaml
10
10
 
11
+ import atdd
12
+ from atdd.coach.utils.repo import find_repo_root
11
13
 
12
- REPO_ROOT = Path(__file__).resolve().parents[4]
13
- BACKEND_CONVENTION = REPO_ROOT / "atdd" / "coder" / "conventions" / "backend.convention.yaml"
14
- FRONTEND_CONVENTION = REPO_ROOT / "atdd" / "coder" / "conventions" / "frontend.convention.yaml"
14
+ REPO_ROOT = find_repo_root()
15
+
16
+ # Package resources (conventions, schemas)
17
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
18
+ BACKEND_CONVENTION = ATDD_PKG_DIR / "coder" / "conventions" / "backend.convention.yaml"
19
+ FRONTEND_CONVENTION = ATDD_PKG_DIR / "coder" / "conventions" / "frontend.convention.yaml"
15
20
 
16
21
 
17
22
  @pytest.mark.coder
@@ -15,9 +15,11 @@ import re
15
15
  from pathlib import Path
16
16
  from typing import Dict, List, Set
17
17
 
18
+ from atdd.coach.utils.repo import find_repo_root
19
+
18
20
 
19
21
  # Path constants
20
- REPO_ROOT = Path(__file__).resolve().parents[3]
22
+ REPO_ROOT = find_repo_root()
21
23
  PYTHON_DIR = REPO_ROOT / "python"
22
24
 
23
25
 
@@ -23,9 +23,11 @@ import re
23
23
  from pathlib import Path
24
24
  from typing import List, Tuple, Optional
25
25
 
26
+ from atdd.coach.utils.repo import find_repo_root
27
+
26
28
 
27
29
  # Path constants
28
- REPO_ROOT = Path(__file__).resolve().parents[3]
30
+ REPO_ROOT = find_repo_root()
29
31
  PYTHON_DIR = REPO_ROOT / "python"
30
32
  DART_DIR = REPO_ROOT / "lib"
31
33
  TS_DIR = REPO_ROOT / "typescript"
@@ -18,9 +18,11 @@ import re
18
18
  from pathlib import Path
19
19
  from typing import List
20
20
 
21
+ from atdd.coach.utils.repo import find_repo_root
22
+
21
23
 
22
24
  # Path constants
23
- REPO_ROOT = Path(__file__).resolve().parents[4] # Go up 3 levels: file -> audits -> coder -> atdd -> repo
25
+ REPO_ROOT = find_repo_root()
24
26
  WEB_SRC = REPO_ROOT / "web" / "src"
25
27
  WEB_TESTS = REPO_ROOT / "web" / "tests"
26
28
 
@@ -16,8 +16,10 @@ from pathlib import Path
16
16
  from typing import List, Tuple, Optional
17
17
  import re
18
18
 
19
+ from atdd.coach.utils.repo import find_repo_root
20
+
19
21
  # Project root constant (pytest pythonpath handles imports)
20
- REPO_ROOT = Path(__file__).resolve().parents[4]
22
+ REPO_ROOT = find_repo_root()
21
23
 
22
24
 
23
25
  class PresentationValidator:
@@ -22,11 +22,18 @@ import yaml
22
22
  from pathlib import Path
23
23
  from typing import Dict, List, Tuple
24
24
 
25
+ import atdd
26
+ from atdd.coach.utils.repo import find_repo_root
27
+
25
28
 
26
29
  # Path constants
27
- REPO_ROOT = Path(__file__).resolve().parents[4]
30
+ # Consumer repo artifacts
31
+ REPO_ROOT = find_repo_root()
28
32
  PYTHON_DIR = REPO_ROOT / "python"
29
- BACKEND_CONVENTION = REPO_ROOT / "atdd" / "coder" / "conventions" / "backend.convention.yaml"
33
+
34
+ # Package resources (conventions, schemas)
35
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
36
+ BACKEND_CONVENTION = ATDD_PKG_DIR / "coder" / "conventions" / "backend.convention.yaml"
30
37
 
31
38
 
32
39
  def determine_layer_from_path(file_path: Path) -> str:
@@ -16,9 +16,10 @@ import re
16
16
  from pathlib import Path
17
17
  from typing import List, Tuple
18
18
 
19
+ from atdd.coach.utils.repo import find_repo_root
19
20
 
20
21
  # Path constants
21
- REPO_ROOT = Path(__file__).resolve().parents[3]
22
+ REPO_ROOT = find_repo_root()
22
23
  PYTHON_DIR = REPO_ROOT / "python"
23
24
 
24
25
 
@@ -14,10 +14,12 @@ import os
14
14
  from pathlib import Path
15
15
  from typing import List, Dict, Any, Tuple
16
16
 
17
+ from atdd.coach.utils.repo import find_repo_root
18
+
17
19
 
18
20
  def get_python_dir() -> Path:
19
- """Get the python directory path."""
20
- return Path(__file__).parent.parent.parent.parent / "python"
21
+ """Get the python directory path in the consumer repo."""
22
+ return find_repo_root() / "python"
21
23
 
22
24
 
23
25
  def test_composition_accepts_shared_dependencies():
@@ -24,15 +24,22 @@ import re
24
24
  from pathlib import Path
25
25
  from typing import List, Dict, Set, Tuple
26
26
 
27
+ import atdd
28
+ from atdd.coach.utils.repo import find_repo_root
29
+
27
30
 
28
31
  # Path constants
29
- REPO_ROOT = Path(__file__).resolve().parents[4]
32
+ # Consumer repo artifacts
33
+ REPO_ROOT = find_repo_root()
30
34
  TRAINS_DIR = REPO_ROOT / "python" / "trains"
31
35
  WAGONS_DIR = REPO_ROOT / "python"
32
36
  GAME_PY = REPO_ROOT / "python" / "game.py"
33
37
  E2E_CONFTEST = REPO_ROOT / "e2e" / "conftest.py"
34
38
  CONTRACT_VALIDATOR = REPO_ROOT / "e2e" / "shared" / "fixtures" / "contract_validator.py"
35
- TRAIN_CONVENTION = REPO_ROOT / "atdd" / "coder" / "conventions" / "train.convention.yaml"
39
+
40
+ # Package resources (conventions, schemas)
41
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
42
+ TRAIN_CONVENTION = ATDD_PKG_DIR / "coder" / "conventions" / "train.convention.yaml"
36
43
 
37
44
 
38
45
  def find_wagons() -> List[Path]:
@@ -21,12 +21,19 @@ import yaml
21
21
  from pathlib import Path
22
22
  from typing import List, Dict, Set, Tuple
23
23
 
24
+ import atdd
25
+ from atdd.coach.utils.repo import find_repo_root
26
+
24
27
 
25
28
  # Path constants
26
- REPO_ROOT = Path(__file__).resolve().parents[4]
29
+ # Consumer repo artifacts
30
+ REPO_ROOT = find_repo_root()
27
31
  PYTHON_SHARED_DIR = REPO_ROOT / "python" / "shared"
28
32
  TRAINS_DIR = REPO_ROOT / "plan" / "_trains"
29
- TRAIN_CONVENTION = REPO_ROOT / "atdd" / "planner" / "conventions" / "train.convention.yaml"
33
+
34
+ # Package resources (conventions, schemas)
35
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
36
+ TRAIN_CONVENTION = ATDD_PKG_DIR / "planner" / "conventions" / "train.convention.yaml"
30
37
 
31
38
 
32
39
  def find_theme_orchestrators() -> List[Path]:
@@ -23,17 +23,24 @@ import yaml
23
23
  from pathlib import Path
24
24
  from typing import Dict, List, Set, Tuple
25
25
 
26
+ import atdd
27
+ from atdd.coach.utils.repo import find_repo_root
28
+
26
29
 
27
30
  # Path constants
28
- REPO_ROOT = Path(__file__).resolve().parents[4]
31
+ # Consumer repo artifacts
32
+ REPO_ROOT = find_repo_root()
29
33
  TS_DIRS = [
30
34
  REPO_ROOT / "supabase" / "functions",
31
35
  REPO_ROOT / "typescript",
32
36
  REPO_ROOT / "frontend",
33
37
  REPO_ROOT / "web",
34
38
  ]
35
- FRONTEND_CONVENTION = REPO_ROOT / "atdd" / "coder" / "conventions" / "frontend.convention.yaml"
36
- BACKEND_CONVENTION = REPO_ROOT / "atdd" / "coder" / "conventions" / "backend.convention.yaml"
39
+
40
+ # Package resources (conventions, schemas)
41
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
42
+ FRONTEND_CONVENTION = ATDD_PKG_DIR / "coder" / "conventions" / "frontend.convention.yaml"
43
+ BACKEND_CONVENTION = ATDD_PKG_DIR / "coder" / "conventions" / "backend.convention.yaml"
37
44
 
38
45
 
39
46
  def load_conventions() -> Tuple[Dict, Dict]:
@@ -18,9 +18,11 @@ import ast
18
18
  from pathlib import Path
19
19
  from typing import List, Tuple, Set
20
20
 
21
+ from atdd.coach.utils.repo import find_repo_root
22
+
21
23
 
22
24
  # Path constants
23
- REPO_ROOT = Path(__file__).resolve().parents[3]
25
+ REPO_ROOT = find_repo_root()
24
26
  PYTHON_DIR = REPO_ROOT / "python"
25
27
  DART_DIRS = [REPO_ROOT / "lib", REPO_ROOT / "dart"]
26
28
  TS_DIRS = [REPO_ROOT / "supabase" / "functions", REPO_ROOT / "typescript"]
@@ -27,12 +27,18 @@ from pathlib import Path
27
27
  from typing import List, Tuple, Set
28
28
  import ast
29
29
 
30
+ import atdd
31
+ from atdd.coach.utils.repo import find_repo_root
30
32
 
31
33
  # Path constants
32
- REPO_ROOT = Path(__file__).resolve().parents[4]
34
+ # Consumer repo artifacts
35
+ REPO_ROOT = find_repo_root()
33
36
  PYTHON_DIR = REPO_ROOT / "python"
34
37
  PYPROJECT_TOML = PYTHON_DIR / "pyproject.toml"
35
- BOUNDARIES_CONVENTION = REPO_ROOT / "atdd" / "coder" / "conventions" / "boundaries.convention.yaml"
38
+
39
+ # Package resources (conventions, schemas)
40
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
41
+ BOUNDARIES_CONVENTION = ATDD_PKG_DIR / "coder" / "conventions" / "boundaries.convention.yaml"
36
42
 
37
43
 
38
44
  def find_test_files() -> List[Path]:
@@ -8,8 +8,10 @@ import pytest
8
8
  from pathlib import Path
9
9
  from typing import Tuple
10
10
 
11
+ from atdd.coach.utils.repo import find_repo_root
12
+
11
13
  # Path constants
12
- REPO_ROOT = Path(__file__).resolve().parents[4]
14
+ REPO_ROOT = find_repo_root()
13
15
  CONTRACTS_DIR = REPO_ROOT / "contracts"
14
16
  TELEMETRY_DIR = REPO_ROOT / "telemetry"
15
17
 
@@ -23,8 +23,10 @@ import json
23
23
  from pathlib import Path
24
24
  from typing import Dict, Any, List, Set
25
25
 
26
+ from atdd.coach.utils.repo import find_repo_root
27
+
26
28
  # Path constants
27
- REPO_ROOT = Path(__file__).resolve().parents[4]
29
+ REPO_ROOT = find_repo_root()
28
30
  PLAN_DIR = REPO_ROOT / "plan"
29
31
  CONTRACTS_DIR = REPO_ROOT / "contracts"
30
32
  TELEMETRY_DIR = REPO_ROOT / "telemetry"
@@ -11,8 +11,10 @@ from pathlib import Path
11
11
  from typing import Dict, Set, List, Tuple
12
12
  import yaml
13
13
 
14
+ from atdd.coach.utils.repo import find_repo_root
15
+
14
16
  # Path constants
15
- REPO_ROOT = Path(__file__).resolve().parents[4]
17
+ REPO_ROOT = find_repo_root()
16
18
  PLAN_DIR = REPO_ROOT / "plan"
17
19
 
18
20