claude-dev-env 8.10.0 → 8.11.1

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 (81) hide show
  1. package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_regression.py +85 -3
  2. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_regression.py +34 -0
  3. package/_shared/pr-loop/scripts/fix_pr_test_proof.py +233 -0
  4. package/_shared/pr-loop/scripts/pr_loop_shared_constants/fix_pr_test_proof_constants.py +47 -0
  5. package/_shared/pr-loop/scripts/test_fix_pr_test_proof.py +186 -0
  6. package/bin/codex-skill-load-block.mjs +93 -0
  7. package/bin/codex-skill-load-block.test.mjs +134 -0
  8. package/bin/install.agents-home.test.mjs +76 -1
  9. package/bin/install.mjs +55 -31
  10. package/bin/install.test.mjs +57 -0
  11. package/bin/install.transaction.test.mjs +29 -7
  12. package/bin/seed-codex-pstack-models.mjs +27 -0
  13. package/bin/seed-codex-pstack-models.test.mjs +72 -0
  14. package/docs/CODE_RULES.md +5 -1
  15. package/hooks/blocking/code_rules_enforcer.py +1 -3
  16. package/hooks/blocking/code_rules_magic_values.py +1 -3
  17. package/hooks/blocking/code_rules_paired_test.py +5 -6
  18. package/hooks/blocking/pii_prevention_blocker_parts/repository_exemption.py +3 -3
  19. package/hooks/blocking/tdd_enforcer_parts/__init__.py +1 -1
  20. package/hooks/blocking/test_code_rules_enforcer_ephemeral.py +1 -46
  21. package/hooks/blocking/test_pre_tool_use_dispatcher.py +2 -40
  22. package/hooks/blocking/tests/test_repository_exemption.py +7 -0
  23. package/hooks/followup_ledger.py +8 -1
  24. package/hooks/git-hooks/test_installed_policy_lint.py +4 -2
  25. package/hooks/hooks.json +15 -0
  26. package/hooks/hooks_constants/followup_ledger_constants.py +4 -0
  27. package/hooks/hooks_constants/messages.py +0 -1
  28. package/hooks/hooks_constants/nested_project_hooks_constants.py +37 -0
  29. package/hooks/hooks_constants/test_messages.py +1 -7
  30. package/hooks/lifecycle/nested_project_hooks.py +395 -0
  31. package/hooks/lifecycle/test_nested_project_hooks.py +251 -0
  32. package/hooks/test_followup_ledger.py +18 -0
  33. package/package.json +2 -1
  34. package/pstack-codex-models.md +37 -0
  35. package/rules/bdd.md +1 -1
  36. package/rules/build-needs-a-user.md +53 -0
  37. package/rules/code-standards.md +1 -1
  38. package/rules/flag-non-breaking-findings.md +7 -0
  39. package/rules/paired-test-coverage.md +4 -2
  40. package/rules/testing.md +5 -1
  41. package/scripts/cde_lint.py +47 -1
  42. package/scripts/policy_lint/adapter_callers.py +124 -0
  43. package/scripts/policy_lint/adapter_pairing.py +4 -2
  44. package/scripts/policy_lint/adapter_support.py +4 -3
  45. package/scripts/policy_lint/adapters.py +15 -0
  46. package/scripts/policy_lint/check_catalog.py +24 -0
  47. package/scripts/policy_lint/config/approved_test_pairs.py +3 -2
  48. package/scripts/policy_lint/config/check_catalog_constants.py +13 -0
  49. package/scripts/policy_lint/config/constants.py +18 -0
  50. package/scripts/policy_lint/engine.py +9 -3
  51. package/scripts/policy_lint/model.py +6 -2
  52. package/scripts/policy_lint/registry.py +6 -0
  53. package/scripts/policy_lint/selection.py +2 -0
  54. package/scripts/repository_checks/tracked_private_terms.py +15 -1
  55. package/scripts/tests/test_cde_lint.py +50 -0
  56. package/scripts/tests/test_policy_lint_rules_archive.py +16 -0
  57. package/scripts/tests/test_policy_lint_rules_callers.py +140 -0
  58. package/scripts/tests/test_policy_lint_rules_check_catalog.py +25 -1
  59. package/scripts/tests/test_policy_lint_rules_pairing.py +31 -2
  60. package/scripts/tests/test_policy_lint_selection.py +35 -0
  61. package/scripts/tests/test_tracked_private_terms.py +35 -0
  62. package/hooks/blocking/tdd_enforcer.py +0 -195
  63. package/hooks/blocking/tdd_enforcer_parts/candidate_paths.py +0 -142
  64. package/hooks/blocking/tdd_enforcer_parts/config/__init__.py +0 -1
  65. package/hooks/blocking/tdd_enforcer_parts/config/tdd_enforcer_constants.py +0 -49
  66. package/hooks/blocking/tdd_enforcer_parts/content_hash_store.py +0 -298
  67. package/hooks/blocking/tdd_enforcer_parts/decisions.py +0 -96
  68. package/hooks/blocking/tdd_enforcer_parts/freshness.py +0 -95
  69. package/hooks/blocking/tdd_enforcer_parts/git_tracking.py +0 -132
  70. package/hooks/blocking/tdd_enforcer_parts/path_classification.py +0 -119
  71. package/hooks/blocking/tdd_enforcer_parts/tests/test_candidate_paths.py +0 -31
  72. package/hooks/blocking/tdd_enforcer_parts/tests/test_content_hash_store.py +0 -256
  73. package/hooks/blocking/tdd_enforcer_parts/tests/test_decisions.py +0 -46
  74. package/hooks/blocking/tdd_enforcer_parts/tests/test_freshness.py +0 -28
  75. package/hooks/blocking/tdd_enforcer_parts/tests/test_git_tracking.py +0 -111
  76. package/hooks/blocking/tdd_enforcer_parts/tests/test_path_classification.py +0 -36
  77. package/hooks/blocking/test_tdd_enforcer.py +0 -1506
  78. package/hooks/blocking/test_tdd_enforcer_restore.py +0 -108
  79. package/hooks/blocking/test_tdd_enforcer_scratchpad.py +0 -105
  80. package/scripts/codex_compat_watcher.py +0 -502
  81. package/scripts/tests/test_codex_compat_watcher.py +0 -599
@@ -1,111 +0,0 @@
1
- """Behavioral tests for the git_tracking parts module."""
2
-
3
- import os
4
- import subprocess
5
- from pathlib import Path
6
-
7
- from tdd_enforcer_parts import git_tracking
8
-
9
-
10
- def _git(repository_root: Path, *arguments: str) -> None:
11
- subprocess.run(
12
- ["git", *arguments],
13
- cwd=str(repository_root),
14
- check=True,
15
- capture_output=True,
16
- env={**os.environ, "GIT_CONFIG_GLOBAL": os.devnull, "GIT_CONFIG_SYSTEM": os.devnull},
17
- )
18
-
19
-
20
- def _init_repository(repository_root: Path) -> None:
21
- _git(repository_root, "init", "-q")
22
- _git(repository_root, "config", "user.email", "test@example.com")
23
- _git(repository_root, "config", "user.name", "Test")
24
- _git(repository_root, "config", "commit.gpgsign", "false")
25
-
26
-
27
- def test_absent_but_tracked_true_after_committed_file_removed(tmp_path: Path) -> None:
28
- _init_repository(tmp_path)
29
- tracked = tmp_path / "service.py"
30
- tracked.write_text("def serve(): return 1\n")
31
- _git(tmp_path, "add", "-A")
32
- _git(tmp_path, "commit", "-q", "-m", "init")
33
- tracked.unlink()
34
- assert git_tracking.is_absent_but_tracked(tracked) is True
35
-
36
-
37
- def test_absent_but_tracked_false_for_untracked_absent_file(tmp_path: Path) -> None:
38
- _init_repository(tmp_path)
39
- assert git_tracking.is_absent_but_tracked(tmp_path / "ghost.py") is False
40
-
41
-
42
- def test_absent_but_tracked_false_when_file_present(tmp_path: Path) -> None:
43
- _init_repository(tmp_path)
44
- present = tmp_path / "present.py"
45
- present.write_text("def here(): return 1\n")
46
- _git(tmp_path, "add", "-A")
47
- _git(tmp_path, "commit", "-q", "-m", "init")
48
- assert git_tracking.is_absent_but_tracked(present) is False
49
-
50
-
51
- def test_has_uncommitted_change_from_head_true_for_untracked_file(tmp_path: Path) -> None:
52
- _init_repository(tmp_path)
53
- untracked = tmp_path / "test_orders.py"
54
- untracked.write_text("def test_fulfill(): pass\n")
55
- assert git_tracking.has_uncommitted_change_from_head(untracked) is True
56
-
57
-
58
- def test_has_uncommitted_change_from_head_true_for_tracked_modified_file(tmp_path: Path) -> None:
59
- _init_repository(tmp_path)
60
- tracked = tmp_path / "test_orders.py"
61
- tracked.write_text("def test_fulfill(): pass\n")
62
- _git(tmp_path, "add", "-A")
63
- _git(tmp_path, "commit", "-q", "-m", "init")
64
- tracked.write_text("def test_fulfill(): assert True\n")
65
- assert git_tracking.has_uncommitted_change_from_head(tracked) is True
66
-
67
-
68
- def test_has_uncommitted_change_from_head_false_for_tracked_clean_file(tmp_path: Path) -> None:
69
- _init_repository(tmp_path)
70
- tracked = tmp_path / "test_orders.py"
71
- tracked.write_text("def test_fulfill(): pass\n")
72
- _git(tmp_path, "add", "-A")
73
- _git(tmp_path, "commit", "-q", "-m", "init")
74
- tracked.touch()
75
- assert git_tracking.has_uncommitted_change_from_head(tracked) is False
76
-
77
-
78
- def test_has_uncommitted_change_from_head_true_outside_a_git_repository(tmp_path: Path) -> None:
79
- stray = tmp_path / "test_orders.py"
80
- stray.write_text("def test_fulfill(): pass\n")
81
- assert git_tracking.has_uncommitted_change_from_head(stray) is True
82
-
83
-
84
- def test_has_uncommitted_change_from_head_true_for_staged_new_file_never_committed(
85
- tmp_path: Path,
86
- ) -> None:
87
- """A brand-new file only ``git add``-ed carries content HEAD never had.
88
-
89
- Regression guard: comparing the working tree to the index (rather than to
90
- HEAD) reads a freshly staged file as unchanged, since staging makes the
91
- index match the working tree exactly. That misses every staged-but-never-
92
- committed file, which is exactly how a RED-step test file is staged.
93
- """
94
- _init_repository(tmp_path)
95
- _git(tmp_path, "commit", "--allow-empty", "-q", "-m", "baseline")
96
- staged_new_test = tmp_path / "test_orders.py"
97
- staged_new_test.write_text("def test_fulfill(): pass\n")
98
- _git(tmp_path, "add", "-A")
99
- assert git_tracking.has_uncommitted_change_from_head(staged_new_test) is True
100
-
101
-
102
- def test_has_uncommitted_change_from_head_true_for_staged_modification(tmp_path: Path) -> None:
103
- """A tracked test's staged edit still differs from HEAD, not only the index."""
104
- _init_repository(tmp_path)
105
- tracked = tmp_path / "test_orders.py"
106
- tracked.write_text("def test_fulfill(): pass\n")
107
- _git(tmp_path, "add", "-A")
108
- _git(tmp_path, "commit", "-q", "-m", "init")
109
- tracked.write_text("def test_fulfill(): assert True\n")
110
- _git(tmp_path, "add", "-A")
111
- assert git_tracking.has_uncommitted_change_from_head(tracked) is True
@@ -1,36 +0,0 @@
1
- """Behavioral tests for the path_classification parts module."""
2
-
3
- from tdd_enforcer_parts import path_classification
4
-
5
-
6
- def test_production_extensions_includes_python_and_typescript() -> None:
7
- extensions = path_classification.production_extensions()
8
- assert ".py" in extensions
9
- assert ".tsx" in extensions
10
-
11
-
12
- def test_skip_extensions_includes_markdown_and_json() -> None:
13
- extensions = path_classification.skip_extensions()
14
- assert ".md" in extensions
15
- assert ".json" in extensions
16
-
17
-
18
- def test_is_inside_dotclaude_segment_matches_exact_segment_only() -> None:
19
- assert path_classification._is_inside_dotclaude_segment("/home/user/.claude/agent.py") is True
20
- assert path_classification._is_inside_dotclaude_segment("/src/my.claude.helpers.py") is False
21
-
22
-
23
- def test_matches_any_skip_pattern_flags_test_file_names() -> None:
24
- assert (
25
- path_classification._matches_any_skip_pattern("test_orders.py", "pkg/test_orders.py")
26
- is True
27
- )
28
- assert path_classification._matches_any_skip_pattern("orders.py", "pkg/orders.py") is False
29
-
30
-
31
- def test_extract_written_content_reads_write_and_multiedit() -> None:
32
- assert path_classification._extract_written_content("Write", {"content": "x"}) == "x"
33
- joined = path_classification._extract_written_content(
34
- "MultiEdit", {"edits": [{"new_string": "a"}, {"new_string": "b"}]}
35
- )
36
- assert joined == "a\nb"