claude-dev-env 1.50.1 → 1.50.3
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.
- package/_shared/pr-loop/audit-contract.md +3 -3
- package/audit-rubrics/category_rubrics/category-e-dead-code.md +3 -2
- package/audit-rubrics/prompts/category-a-api-contracts.md +1 -1
- package/audit-rubrics/prompts/category-b-selector-engine-compat.md +2 -2
- package/audit-rubrics/prompts/category-c-resource-cleanup.md +2 -2
- package/audit-rubrics/prompts/category-d-scoping-and-ordering.md +2 -2
- package/audit-rubrics/prompts/category-e-dead-code.md +5 -4
- package/audit-rubrics/prompts/category-f-silent-failures.md +2 -2
- package/audit-rubrics/prompts/category-g-bounds-and-overflow.md +2 -2
- package/audit-rubrics/prompts/category-h-security-boundaries.md +2 -2
- package/audit-rubrics/prompts/category-i-concurrency.md +2 -2
- package/audit-rubrics/prompts/category-j-code-rules-compliance.md +2 -2
- package/audit-rubrics/prompts/category-k-codebase-conflicts.md +2 -2
- package/docs/CODE_RULES.md +1 -1
- package/hooks/blocking/code_rules_annotations_length.py +167 -0
- package/hooks/blocking/code_rules_banned_identifiers.py +385 -0
- package/hooks/blocking/code_rules_boolean_mustcheck.py +350 -0
- package/hooks/blocking/code_rules_comments.py +337 -0
- package/hooks/blocking/code_rules_constants_config.py +252 -0
- package/hooks/blocking/code_rules_docstrings.py +308 -0
- package/hooks/blocking/code_rules_enforcer.py +98 -5807
- package/hooks/blocking/code_rules_imports_logging.py +276 -0
- package/hooks/blocking/code_rules_magic_values.py +180 -0
- package/hooks/blocking/code_rules_mock_completeness.py +295 -0
- package/hooks/blocking/code_rules_naming_collection.py +264 -0
- package/hooks/blocking/code_rules_optional_params.py +288 -0
- package/hooks/blocking/code_rules_paths_syspath.py +186 -0
- package/hooks/blocking/code_rules_probe_chains.py +305 -0
- package/hooks/blocking/code_rules_probe_detection.py +257 -0
- package/hooks/blocking/code_rules_probe_recording.py +225 -0
- package/hooks/blocking/code_rules_scope_binding.py +151 -0
- package/hooks/blocking/code_rules_shared.py +301 -0
- package/hooks/blocking/code_rules_string_magic.py +207 -0
- package/hooks/blocking/code_rules_test_assertions.py +226 -0
- package/hooks/blocking/code_rules_test_branching_except.py +181 -0
- package/hooks/blocking/code_rules_test_isolation.py +341 -0
- package/hooks/blocking/code_rules_type_escape.py +341 -0
- package/hooks/blocking/code_rules_typeddict_stub.py +305 -0
- package/hooks/blocking/code_rules_unused_imports.py +256 -0
- package/hooks/blocking/tdd_enforcer.py +31 -0
- package/hooks/blocking/test_code_rules_constants_config.py +26 -0
- package/hooks/blocking/test_code_rules_enforcer_banned_noun_word.py +5 -2
- package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +0 -5
- package/hooks/blocking/test_code_rules_enforcer_comment_string_awareness.py +21 -15
- package/hooks/blocking/test_code_rules_enforcer_config_path.py +20 -16
- package/hooks/blocking/test_code_rules_enforcer_exempt_marker_chained.py +4 -2
- package/hooks/blocking/test_code_rules_enforcer_function_length.py +18 -13
- package/hooks/blocking/test_code_rules_enforcer_hardcoded_user_path.py +1 -2
- package/hooks/blocking/test_code_rules_enforcer_ignored_must_check_return.py +22 -12
- package/hooks/blocking/test_code_rules_enforcer_split_annotations_length.py +55 -0
- package/hooks/blocking/test_code_rules_enforcer_split_banned.py +170 -0
- package/hooks/blocking/test_code_rules_enforcer_split_comments.py +60 -0
- package/hooks/blocking/test_code_rules_enforcer_split_config_path.py +52 -0
- package/hooks/blocking/test_code_rules_enforcer_split_constants_config.py +236 -0
- package/hooks/blocking/test_code_rules_enforcer_split_entry_1.py +296 -0
- package/hooks/blocking/test_code_rules_enforcer_split_entry_2.py +238 -0
- package/hooks/blocking/test_code_rules_enforcer_split_isolation_1.py +271 -0
- package/hooks/blocking/test_code_rules_enforcer_split_isolation_2.py +283 -0
- package/hooks/blocking/test_code_rules_enforcer_split_isolation_3.py +268 -0
- package/hooks/blocking/test_code_rules_enforcer_split_isolation_4.py +85 -0
- package/hooks/blocking/test_code_rules_enforcer_split_mocks_1.py +303 -0
- package/hooks/blocking/test_code_rules_enforcer_split_mocks_2.py +111 -0
- package/hooks/blocking/test_code_rules_enforcer_split_mustcheck.py +87 -0
- package/hooks/blocking/test_code_rules_enforcer_split_naming.py +107 -0
- package/hooks/blocking/test_code_rules_enforcer_split_optional_params.py +325 -0
- package/hooks/blocking/test_code_rules_enforcer_split_paths_syspath.py +110 -0
- package/hooks/blocking/test_code_rules_enforcer_split_shared.py +44 -0
- package/hooks/blocking/test_code_rules_enforcer_split_string_magic.py +55 -0
- package/hooks/blocking/test_code_rules_enforcer_split_test_assertions.py +56 -0
- package/hooks/blocking/test_code_rules_enforcer_todo_markers.py +21 -15
- package/hooks/blocking/test_code_rules_paths_syspath.py +26 -0
- package/hooks/blocking/test_tdd_enforcer.py +116 -0
- package/hooks/hooks_constants/blocking_check_limits.py +3 -0
- package/hooks/hooks_constants/code_rules_enforcer_constants.py +8 -0
- package/hooks/hooks_constants/sys_path_insert_constants.py +1 -0
- package/package.json +1 -1
- package/skills/_shared/pr-loop/scripts/build_audit_prompt.py +13 -7
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +21 -11
- package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +92 -0
- package/skills/bugteam/CONSTRAINTS.md +1 -1
- package/skills/bugteam/PROMPTS.md +20 -48
- package/skills/bugteam/SKILL.md +5 -5
- package/skills/bugteam/reference/audit-and-teammates.md +1 -1
- package/skills/bugteam/reference/audit-contract.md +4 -4
- package/skills/bugteam/reference/design-rationale.md +1 -1
- package/skills/findbugs/SKILL.md +21 -12
- package/skills/fixbugs/SKILL.md +1 -1
- package/skills/qbug/SKILL.md +5 -5
- package/skills/qbug/test_qbug_skill_audit_schema.py +13 -23
- package/skills/refine/SKILL.md +1 -1
- package/hooks/blocking/test_code_rules_enforcer.py +0 -2669
|
@@ -21,7 +21,7 @@ Each finding an audit produces MUST be one of exactly two shapes.
|
|
|
21
21
|
"id": "loop<N>-<K>",
|
|
22
22
|
"file": "path/relative/to/repo/root.py",
|
|
23
23
|
"line": 123,
|
|
24
|
-
"category": "A | B | C | D | E | F | G | H | I | J",
|
|
24
|
+
"category": "A | B | C | D | E | F | G | H | I | J | K | L | M | N",
|
|
25
25
|
"severity": "P0 | P1 | P2",
|
|
26
26
|
"excerpt": "verbatim code snippet from the offending line(s)",
|
|
27
27
|
"failure_mode": "one sentence describing what goes wrong and when",
|
|
@@ -37,7 +37,7 @@ Used when an audit investigates a category and does NOT find a bug. Bare "verifi
|
|
|
37
37
|
|
|
38
38
|
```json
|
|
39
39
|
{
|
|
40
|
-
"category": "A | B | C | D | E | F | G | H | I | J",
|
|
40
|
+
"category": "A | B | C | D | E | F | G | H | I | J | K | L | M | N",
|
|
41
41
|
"files_opened": ["file1.py", "file2.py"],
|
|
42
42
|
"lines_quoted": [
|
|
43
43
|
{"file": "file1.py", "line": 88, "text": "verbatim line content"}
|
|
@@ -120,7 +120,7 @@ Sequence:
|
|
|
120
120
|
3. Run `py_compile` (or language-equivalent) on each modified file.
|
|
121
121
|
4. Compute `fix_diff` against pre-fix contents for the modified set.
|
|
122
122
|
5. Run `bugteam_code_rules_gate.py` with explicit paths for every modified file.
|
|
123
|
-
6. Spawn a scoped audit of `fix_diff` with full A–
|
|
123
|
+
6. Spawn a scoped audit of `fix_diff` with full A–N rigor, Shape A/B contract, adversarial pass, AND Haiku secondary in parallel (paranoid mode on post-fix).
|
|
124
124
|
7. Read the previous loop's outcome XML (`<worktree_path>/.bugteam-pr<N>-loop<L-1>.outcomes.xml`) and obtain its total finding count. If this is the first loop (L <= 1) or the file does not exist, skip this comparison. Compute the post-fix total: previous total minus bugs fixed in this round plus new violations found in the post-fix audit (step 6). If the post-fix total exceeds the previous total, flag all new findings as same-loop fix-targets and revise. An increase in total findings across loop transitions is a regression.
|
|
125
125
|
8. Any new findings become same-loop fix-targets. Internal iteration count increments by one.
|
|
126
126
|
9. After 3 internal iterations with fresh findings each time, exit `stuck: post-fix audit not converging`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Category E — Dead code and unused imports
|
|
2
2
|
|
|
3
|
-
**What this category audits:** imports the diff adds but leaves unreferenced, functions defined but never called,
|
|
3
|
+
**What this category audits:** imports the diff adds but leaves unreferenced (dead imports), functions defined but never called, code made unreachable by a prior return or raise (dead returns), conditions that are always true or always false (dead branches), parameters that are accepted but never used (dead parameters), local variables assigned but never read (dead locals), removed-but-not-deleted symbols.
|
|
4
4
|
|
|
5
5
|
**Examples of Category E findings:**
|
|
6
6
|
- A new `import` line with zero corresponding references in the file.
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
- Code after an unconditional `return` or `raise`.
|
|
9
9
|
- A condition like `if False:` or `while True: ... return` where the loop body always returns immediately.
|
|
10
10
|
- An accepted parameter that the function body never uses.
|
|
11
|
+
- A local variable assigned and never read afterward in the same function.
|
|
11
12
|
|
|
12
13
|
**Companion reference:** see `../source-material-section-types.md`.
|
|
13
14
|
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
| E2 | Functions / methods defined but never called | Internal helpers defined in this PR with no call sites in this PR or elsewhere. |
|
|
22
23
|
| E3 | Code after unconditional return / raise / exit | Statements following a top-level `return`, `raise`, `sys.exit`, `os._exit` that cannot execute. |
|
|
23
24
|
| E4 | Always-true / always-false conditions | `if True:` / `if False:` / conditions provably constant given context. |
|
|
24
|
-
| E5 | Unused parameters | Parameters declared but never read inside the function body. |
|
|
25
|
+
| E5 | Unused parameters and locals | Parameters declared but never read inside the function body; local variables assigned but never read afterward in the same scope. |
|
|
25
26
|
| E6 | Removed-but-not-deleted symbol references | Symbols renamed/removed elsewhere with stale import or call sites left behind. |
|
|
26
27
|
| E7 | Test fixtures / helpers defined but never used | Pytest fixtures, test data builders, mock factories with no callers. |
|
|
27
28
|
| E8 | Stub / placeholder code without TODO | `pass`, `...`, `raise NotImplementedError` left without explanation or tracking. |
|
|
@@ -95,7 +95,7 @@ Lead: `Total: N (P0=N, P1=N, P2=N)`. For each sub-bucket A1–A9, produce Shape
|
|
|
95
95
|
|
|
96
96
|
# Worked example: jl-cmd/claude-code-config PR #394 (May 2026 audit experiment)
|
|
97
97
|
|
|
98
|
-
Audit jl-cmd/claude-code-config PR #394 for **Category A only** (API contract verification). Skip B–
|
|
98
|
+
Audit jl-cmd/claude-code-config PR #394 for **Category A only** (API contract verification). Skip B–N. Sub-bucket forced-exhaustion mode: Category A is decomposed into 8 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
99
99
|
|
|
100
100
|
PR: feat(scripts): add sweep-empty-dirs utility and scheduled-task installer
|
|
101
101
|
Head SHA: 62c9c169ee7a44824e5da25c4cf8b74fdca08a53
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category B only** (selector / query / engine compatibility). Skip A, C–
|
|
1
|
+
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category B only** (selector / query / engine compatibility). Skip A, C–N. Sub-bucket forced-exhaustion mode: Category B is decomposed into 7 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
2
2
|
|
|
3
3
|
[ARTIFACT METADATA: repo, ref/SHA, PR or commit range, file count, language matrix, declared engine/runtime/browser/DB targets — fill before running.]
|
|
4
4
|
ID prefix: `find`.
|
|
@@ -80,7 +80,7 @@ Lead: `Total: N (P0=N, P1=N, P2=N)`. For each sub-bucket B1–B7, produce Shape
|
|
|
80
80
|
|
|
81
81
|
# Worked example: jl-cmd/claude-code-config PR #394
|
|
82
82
|
|
|
83
|
-
Audit jl-cmd/claude-code-config PR #394 for **Category B only** (selector / query / engine compatibility). Skip A, C–
|
|
83
|
+
Audit jl-cmd/claude-code-config PR #394 for **Category B only** (selector / query / engine compatibility). Skip A, C–N. Sub-bucket forced-exhaustion mode: Category B is decomposed into 7 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
84
84
|
|
|
85
85
|
PR: feat(scripts): add sweep-empty-dirs utility and scheduled-task installer
|
|
86
86
|
Head SHA: 62c9c169ee7a44824e5da25c4cf8b74fdca08a53
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category C only** (resource cleanup and lifecycle). Skip A, B, D–
|
|
1
|
+
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category C only** (resource cleanup and lifecycle). Skip A, B, D–N. Sub-bucket forced-exhaustion mode: Category C is decomposed into 8 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
2
2
|
|
|
3
3
|
[ARTIFACT METADATA]
|
|
4
4
|
- Repository / artifact: [REPO_OR_ARTIFACT_NAME]
|
|
@@ -98,7 +98,7 @@ Read-only. No edits, no commits.
|
|
|
98
98
|
|
|
99
99
|
# Worked example: jl-cmd/claude-code-config PR #394
|
|
100
100
|
|
|
101
|
-
Audit jl-cmd/claude-code-config PR #394 for **Category C only** (resource cleanup and lifecycle). Skip A, B, D–
|
|
101
|
+
Audit jl-cmd/claude-code-config PR #394 for **Category C only** (resource cleanup and lifecycle). Skip A, B, D–N. Sub-bucket forced-exhaustion mode: Category C is decomposed into 8 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
102
102
|
|
|
103
103
|
PR: feat(scripts): add sweep-empty-dirs utility and scheduled-task installer
|
|
104
104
|
Head SHA: 62c9c169ee7a44824e5da25c4cf8b74fdca08a53
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category D only** (variable scoping, ordering, and unbound references). Skip A–C, E–
|
|
1
|
+
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category D only** (variable scoping, ordering, and unbound references). Skip A–C, E–N. Sub-bucket forced-exhaustion mode: Category D is decomposed into 8 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
2
2
|
|
|
3
3
|
[ARTIFACT METADATA]
|
|
4
4
|
- Repo / artifact: [REPO_OR_ARTIFACT]
|
|
@@ -89,7 +89,7 @@ Lead: `Total: N (P0=N, P1=N, P2=N)`. For each sub-bucket D1–D8, produce Shape
|
|
|
89
89
|
|
|
90
90
|
# Worked example: jl-cmd/claude-code-config PR #394
|
|
91
91
|
|
|
92
|
-
Audit jl-cmd/claude-code-config PR #394 for **Category D only** (variable scoping, ordering, and unbound references). Skip A–C, E–
|
|
92
|
+
Audit jl-cmd/claude-code-config PR #394 for **Category D only** (variable scoping, ordering, and unbound references). Skip A–C, E–N. Sub-bucket forced-exhaustion mode: Category D is decomposed into 8 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
93
93
|
|
|
94
94
|
PR: feat(scripts): add sweep-empty-dirs utility and scheduled-task installer
|
|
95
95
|
Head SHA: 62c9c169ee7a44824e5da25c4cf8b74fdca08a53
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category E only** (dead code and unused imports). Skip A–D, F–
|
|
1
|
+
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category E only** (dead code and unused imports). Skip A–D, F–N. Sub-bucket forced-exhaustion mode: Category E is decomposed into 8 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
2
2
|
|
|
3
3
|
[ARTIFACT METADATA]
|
|
4
4
|
- Repo / artifact: [REPO_OR_ARTIFACT_NAME]
|
|
@@ -43,8 +43,9 @@ Inline the artifact under this section using the section types defined in the ch
|
|
|
43
43
|
- Runtime-bound conditions (parameter values, `os.path.isdir`, `Test-Path`, environment lookups) are not constant; state the runtime source.
|
|
44
44
|
- Adversarial probes for proof-of-absence: (a) any `if 1:` / `if 0:` / `if True:` / `if False:` literals in the diff? (b) any condition of the form `if x:` where `x` was just assigned a literal in the line above? (c) any `assert True` / `assert False` in test bodies? (d) any short-circuit like `x or DEFAULT` where `x` was just constructed and is statically truthy?
|
|
45
45
|
|
|
46
|
-
**E5. Unused parameters**
|
|
46
|
+
**E5. Unused parameters and locals**
|
|
47
47
|
- For every function or method introduced or modified by the artifact, verify each declared parameter is read at least once in the body (including in default-argument expressions for inner functions, in closures, or in type guards).
|
|
48
|
+
- For every function or method introduced or modified by the artifact, verify each local variable assigned in the body is read at least once afterward in the same scope; an assignment whose value is never read is a dead local.
|
|
48
49
|
- Tuple-unpack discards (`for path, _, _ in os.walk(...)`) are out of scope — E5 specifically scopes "function parameters never read"; state this exclusion explicitly.
|
|
49
50
|
- `*args` / `**kwargs` / TypeScript rest spreads: confirm at least one consumer (forwarded to another call, iterated, indexed) or mark the parameter unused.
|
|
50
51
|
- Cross-language parameter declarations (PowerShell `param(...)`, shell positional `$1..$N`, Bash `getopts`): confirm each named parameter has at least one body reference.
|
|
@@ -86,7 +87,7 @@ Note: most Category E findings are P2 (style / cleanup) unless the dead code mas
|
|
|
86
87
|
|
|
87
88
|
# Worked example: jl-cmd/claude-code-config PR #394
|
|
88
89
|
|
|
89
|
-
Audit jl-cmd/claude-code-config PR #394 for **Category E only** (dead code and unused imports). Skip A–D, F–
|
|
90
|
+
Audit jl-cmd/claude-code-config PR #394 for **Category E only** (dead code and unused imports). Skip A–D, F–N. Sub-bucket forced-exhaustion mode: Category E is decomposed into 8 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
90
91
|
|
|
91
92
|
PR: feat(scripts): add sweep-empty-dirs utility and scheduled-task installer
|
|
92
93
|
Head SHA: 62c9c169ee7a44824e5da25c4cf8b74fdca08a53
|
|
@@ -128,7 +129,7 @@ ID prefix: `find`.
|
|
|
128
129
|
- `test_sweep_empty_dirs.py` line 13: `if str(_SCRIPTS_DIR) not in sys.path:` — runtime membership test; not constant.
|
|
129
130
|
- Adversarial probes for proof-of-absence: (a) does the diff introduce any `if 1:` / `if 0:` / `if True:` / `if False:` literals? grep the diff text. (b) any condition of the form `if x:` where `x` was just assigned a literal in the line above? (c) any `assert True` or `assert False` in test bodies? (none — verify).
|
|
130
131
|
|
|
131
|
-
**E5. Unused parameters**
|
|
132
|
+
**E5. Unused parameters and locals**
|
|
132
133
|
- `_log_walk_error(os_error: OSError) -> None` (line 14) — parameter `os_error` is read twice in the body (`os_error.filename`, `os_error.strerror`). Used.
|
|
133
134
|
- `sweep(root: str, min_age_seconds: int) -> list[str]` (line 18) — `root` is passed to `os.walk` (line 21); `min_age_seconds` is read at line 26. Both used.
|
|
134
135
|
- `_build_parser() -> argparse.ArgumentParser` (line 39) — zero parameters; nothing to verify.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category F only** (silent failures). Skip A–E, G–
|
|
1
|
+
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category F only** (silent failures). Skip A–E, G–N. Sub-bucket forced-exhaustion mode: Category F is decomposed into 8 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
2
2
|
|
|
3
3
|
[ARTIFACT METADATA]
|
|
4
4
|
- Title / short description: [TITLE]
|
|
@@ -98,7 +98,7 @@ Lead: `Total: N (P0=N, P1=N, P2=N)`. For each sub-bucket F1-F8, produce Shape A
|
|
|
98
98
|
|
|
99
99
|
# Worked example: jl-cmd/claude-code-config PR #394
|
|
100
100
|
|
|
101
|
-
Audit jl-cmd/claude-code-config PR #394 for **Category F only** (silent failures). Skip A–E, G–
|
|
101
|
+
Audit jl-cmd/claude-code-config PR #394 for **Category F only** (silent failures). Skip A–E, G–N. Sub-bucket forced-exhaustion mode: Category F is decomposed into 8 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
102
102
|
|
|
103
103
|
PR: feat(scripts): add sweep-empty-dirs utility and scheduled-task installer
|
|
104
104
|
Head SHA: 62c9c169ee7a44824e5da25c4cf8b74fdca08a53
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category G only** (off-by-one, bounds, integer overflow). Skip A–F, H–
|
|
1
|
+
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category G only** (off-by-one, bounds, integer overflow). Skip A–F, H–N. Sub-bucket forced-exhaustion mode: Category G is decomposed into 8 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
2
2
|
|
|
3
3
|
[ARTIFACT METADATA]
|
|
4
4
|
- Repository / artifact: [REPO_OR_ARTIFACT]
|
|
@@ -61,7 +61,7 @@ Lead: `Total: N (P0=N, P1=N, P2=N)`. For each sub-bucket G1-G8, produce Shape A
|
|
|
61
61
|
|
|
62
62
|
# Worked example: jl-cmd/claude-code-config PR #394
|
|
63
63
|
|
|
64
|
-
Audit jl-cmd/claude-code-config PR #394 for **Category G only** (off-by-one, bounds, integer overflow). Skip A–F, H–
|
|
64
|
+
Audit jl-cmd/claude-code-config PR #394 for **Category G only** (off-by-one, bounds, integer overflow). Skip A–F, H–N. Sub-bucket forced-exhaustion mode: Category G is decomposed into 8 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
65
65
|
|
|
66
66
|
PR: feat(scripts): add sweep-empty-dirs utility and scheduled-task installer
|
|
67
67
|
Head SHA: 62c9c169ee7a44824e5da25c4cf8b74fdca08a53
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category H only** (security boundaries). Skip A–G, I–
|
|
1
|
+
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category H only** (security boundaries). Skip A–G, I–N. Sub-bucket forced-exhaustion mode: Category H is decomposed into 10 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
2
2
|
|
|
3
3
|
## ARTIFACT METADATA — trust model
|
|
4
4
|
|
|
@@ -83,7 +83,7 @@ Note: Category H findings tend toward P0/P1 since they're security-relevant —
|
|
|
83
83
|
|
|
84
84
|
# Worked example: jl-cmd/claude-code-config PR #394
|
|
85
85
|
|
|
86
|
-
Audit jl-cmd/claude-code-config PR #394 for **Category H only** (security boundaries). Skip A–G, I–
|
|
86
|
+
Audit jl-cmd/claude-code-config PR #394 for **Category H only** (security boundaries). Skip A–G, I–N. Sub-bucket forced-exhaustion mode: Category H is decomposed into 10 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
87
87
|
|
|
88
88
|
PR: feat(scripts): add sweep-empty-dirs utility and scheduled-task installer
|
|
89
89
|
Head SHA: 62c9c169ee7a44824e5da25c4cf8b74fdca08a53
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category I only** (concurrency hazards). Skip A–H, J–
|
|
1
|
+
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category I only** (concurrency hazards). Skip A–H, J–N. Sub-bucket forced-exhaustion mode: Category I is decomposed into [N] sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
2
2
|
|
|
3
3
|
[ARTIFACT METADATA — including: is this code single-threaded, threaded, asyncio, multiprocessing, or mixed? Name the runtime (CPython 3.x, Node, Go, JVM, .NET, PowerShell runspace, browser JS), the concurrency primitives actually present (`threading`, `asyncio`, `multiprocessing`, `concurrent.futures`, `Thread`, `goroutine`, `Promise`, `Task`, `Start-ThreadJob`, `ForEach-Object -Parallel`, etc.), and the inter-process surface (shared filesystem, shared DB, shared cache, shared queue, signals). State explicitly which primitives are absent so each sub-bucket has a Shape B basis.]
|
|
4
4
|
|
|
@@ -88,7 +88,7 @@ Lead: `Total: N (P0=N, P1=N, P2=N)`. For each sub-bucket I1–I8, produce Shape
|
|
|
88
88
|
|
|
89
89
|
# Worked example: jl-cmd/claude-code-config PR #394
|
|
90
90
|
|
|
91
|
-
Audit jl-cmd/claude-code-config PR #394 for **Category I only** (concurrency hazards). Skip A–H, J–
|
|
91
|
+
Audit jl-cmd/claude-code-config PR #394 for **Category I only** (concurrency hazards). Skip A–H, J–N. Sub-bucket forced-exhaustion mode: Category I is decomposed into 8 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
92
92
|
|
|
93
93
|
PR: feat(scripts): add sweep-empty-dirs utility and scheduled-task installer
|
|
94
94
|
Head SHA: 62c9c169ee7a44824e5da25c4cf8b74fdca08a53
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category J only** (CODE_RULES.md compliance). Skip A–I, K. Sub-bucket forced-exhaustion mode: Category J is decomposed into 12 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
1
|
+
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category J only** (CODE_RULES.md compliance). Skip A–I, K–N. Sub-bucket forced-exhaustion mode: Category J is decomposed into 12 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
2
2
|
|
|
3
3
|
[ARTIFACT METADATA]
|
|
4
4
|
- Artifact: [PR title / commit subject / file set / patch series]
|
|
@@ -100,7 +100,7 @@ Note: most Category J findings are P2 (style / cleanup) since they don't affect
|
|
|
100
100
|
|
|
101
101
|
# Worked example: jl-cmd/claude-code-config PR #394
|
|
102
102
|
|
|
103
|
-
Audit jl-cmd/claude-code-config PR #394 for **Category J only** (CODE_RULES.md compliance). Skip A–I, K. Sub-bucket forced-exhaustion mode: Category J is decomposed into 12 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
103
|
+
Audit jl-cmd/claude-code-config PR #394 for **Category J only** (CODE_RULES.md compliance). Skip A–I, K–N. Sub-bucket forced-exhaustion mode: Category J is decomposed into 12 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
104
104
|
|
|
105
105
|
PR: feat(scripts): add sweep-empty-dirs utility and scheduled-task installer
|
|
106
106
|
Head SHA: 62c9c169ee7a44824e5da25c4cf8b74fdca08a53
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category K only** (codebase conflicts — incomplete propagation). Skip A–J. Sub-bucket forced-exhaustion mode: Category K is decomposed into 9 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
1
|
+
Audit [REPO/ARTIFACT] [TARGET_ID] for **Category K only** (codebase conflicts — incomplete propagation). Skip A–J, L–N. Sub-bucket forced-exhaustion mode: Category K is decomposed into 9 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
2
2
|
|
|
3
3
|
[ARTIFACT METADATA — including the BEFORE state of changed surfaces, so the agent can compare before vs after]
|
|
4
4
|
|
|
@@ -79,7 +79,7 @@ Lead: `Total: N (P0=N, P1=N, P2=N)`. For each sub-bucket K1-K9, produce Shape A
|
|
|
79
79
|
|
|
80
80
|
Note: PR #397 is the K canonical case, NOT #394.
|
|
81
81
|
|
|
82
|
-
Audit jl-cmd/claude-code-config PR #397 for **Category K only** (codebase conflicts — incomplete propagation). Skip A–J. Sub-bucket forced-exhaustion mode: Category K is decomposed into 9 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
82
|
+
Audit jl-cmd/claude-code-config PR #397 for **Category K only** (codebase conflicts — incomplete propagation). Skip A–J, L–N. Sub-bucket forced-exhaustion mode: Category K is decomposed into 9 sub-buckets below. Each sub-bucket REQUIRES at least one Shape A finding OR exactly one Shape B proof-of-absence with **at least 3 adversarial probes** specific to that sub-bucket. A sub-bucket returning neither is a protocol gap.
|
|
83
83
|
|
|
84
84
|
PR: fix(hooks): improve hedging-language guardrail to surface user questions
|
|
85
85
|
Base SHA: 76f9c1a0048729b87c44626a3380dc840065c2fa (origin/main at PR open time)
|
package/docs/CODE_RULES.md
CHANGED
|
@@ -354,7 +354,7 @@ These principles cannot be reduced to a regex or AST visitor. They live in user-
|
|
|
354
354
|
|
|
355
355
|
### Audit-rubric reference
|
|
356
356
|
|
|
357
|
-
For multi-file architectural reviews see [`packages/claude-dev-env/audit-rubrics/`](../audit-rubrics/). Categories A–
|
|
357
|
+
For multi-file architectural reviews see [`packages/claude-dev-env/audit-rubrics/`](../audit-rubrics/). Categories A–N are maintained as agent rubrics. Category J (CODE_RULES.md compliance) mirrors the ⚡ hook-enforced rules as an audit-side rubric; the other categories stay agent rubrics because they rest on multi-file reasoning beyond a single-file hook's reach.
|
|
358
358
|
|
|
359
359
|
---
|
|
360
360
|
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""Parameter-annotation, return-annotation, and function-length checks."""
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
_blocking_directory = str(Path(__file__).resolve().parent)
|
|
8
|
+
_hooks_directory = str(Path(__file__).resolve().parent.parent)
|
|
9
|
+
if _blocking_directory not in sys.path:
|
|
10
|
+
sys.path.insert(0, _blocking_directory)
|
|
11
|
+
if _hooks_directory not in sys.path:
|
|
12
|
+
sys.path.insert(0, _hooks_directory)
|
|
13
|
+
|
|
14
|
+
from code_rules_shared import ( # noqa: E402
|
|
15
|
+
_collect_annotated_arguments,
|
|
16
|
+
_definition_docstring_line_span,
|
|
17
|
+
_function_definition_line_span,
|
|
18
|
+
_scope_violations_to_changed_lines,
|
|
19
|
+
is_hook_infrastructure,
|
|
20
|
+
is_migration_file,
|
|
21
|
+
is_test_file,
|
|
22
|
+
is_workflow_registry_file,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from hooks_constants.code_rules_enforcer_constants import ( # noqa: E402
|
|
26
|
+
ALL_SELF_AND_CLS_PARAMETER_NAMES,
|
|
27
|
+
FUNCTION_LENGTH_BLOCKING_MESSAGE_SUFFIX,
|
|
28
|
+
FUNCTION_LENGTH_BLOCKING_THRESHOLD,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def check_parameter_annotations(content: str, file_path: str) -> list[str]:
|
|
33
|
+
if is_test_file(file_path):
|
|
34
|
+
return []
|
|
35
|
+
if is_workflow_registry_file(file_path) or is_migration_file(file_path):
|
|
36
|
+
return []
|
|
37
|
+
try:
|
|
38
|
+
tree = ast.parse(content)
|
|
39
|
+
except SyntaxError:
|
|
40
|
+
return []
|
|
41
|
+
issues: list[str] = []
|
|
42
|
+
for each_node in ast.walk(tree):
|
|
43
|
+
if not isinstance(each_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
44
|
+
continue
|
|
45
|
+
for each_arg in _collect_annotated_arguments(each_node):
|
|
46
|
+
if each_arg.arg in ALL_SELF_AND_CLS_PARAMETER_NAMES:
|
|
47
|
+
continue
|
|
48
|
+
if each_arg.annotation is None:
|
|
49
|
+
issues.append(
|
|
50
|
+
f"Line {each_arg.lineno}: parameter {each_arg.arg!r} on {each_node.name!r} missing type annotation (CODE_RULES §6)"
|
|
51
|
+
)
|
|
52
|
+
return issues
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def check_return_annotations(content: str, file_path: str) -> list[str]:
|
|
56
|
+
if is_test_file(file_path):
|
|
57
|
+
return []
|
|
58
|
+
if is_workflow_registry_file(file_path) or is_migration_file(file_path):
|
|
59
|
+
return []
|
|
60
|
+
try:
|
|
61
|
+
tree = ast.parse(content)
|
|
62
|
+
except SyntaxError:
|
|
63
|
+
return []
|
|
64
|
+
issues: list[str] = []
|
|
65
|
+
for each_node in ast.walk(tree):
|
|
66
|
+
if not isinstance(each_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
67
|
+
continue
|
|
68
|
+
if each_node.returns is None:
|
|
69
|
+
issues.append(
|
|
70
|
+
f"Line {each_node.lineno}: function {each_node.name!r} missing return type annotation (CODE_RULES §6)"
|
|
71
|
+
)
|
|
72
|
+
return issues
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def check_function_length(
|
|
76
|
+
content: str,
|
|
77
|
+
file_path: str,
|
|
78
|
+
all_changed_lines: set[int] | None = None,
|
|
79
|
+
defer_scope_to_caller: bool = False,
|
|
80
|
+
) -> list[str]:
|
|
81
|
+
"""Flag functions whose executable span exceeds cognitive-load thresholds.
|
|
82
|
+
|
|
83
|
+
Function executable spans — the definition span (signature line through
|
|
84
|
+
last body statement, inclusive) minus the leading docstring lines of the
|
|
85
|
+
function and of every function or class nested within it, per
|
|
86
|
+
``_definition_docstring_line_span`` summed over the nested definitions —
|
|
87
|
+
at or above ``FUNCTION_LENGTH_BLOCKING_THRESHOLD`` appear in
|
|
88
|
+
the returned issues list and block the write at the
|
|
89
|
+
gate. The threshold rests on the small-function guidance in Robert C.
|
|
90
|
+
Martin, *Clean Code* Chapter Three ("Functions") and the Google Python Style
|
|
91
|
+
Guide's ~forty-line function review hint
|
|
92
|
+
(https://google.github.io/styleguide/pyguide.html) — a measure of
|
|
93
|
+
executable complexity, paired with the Guide's complete-docstring mandate
|
|
94
|
+
for public APIs, so documentation lines never count against the gate; this
|
|
95
|
+
gate blocks on body growth that pushes a function past that span. It does
|
|
96
|
+
not derive from CODE_RULES file-length guidance, which governs advisory
|
|
97
|
+
file-length signals and argues against hard numeric blocks.
|
|
98
|
+
|
|
99
|
+
The issue message carries ``Function NAME (defined at line X) is Y lines``
|
|
100
|
+
precisely so the gate's ``function_length_span_range`` can recover the
|
|
101
|
+
function's full declared span (lines ``X`` through ``X + Y - 1``). The
|
|
102
|
+
gate classifies the violation blocking when that span intersects the
|
|
103
|
+
diff's added lines — the body grew this diff — and advisory otherwise — a
|
|
104
|
+
pre-existing, untouched long function in a file the diff happened to
|
|
105
|
+
touch. Anchoring to the span rather than a single ``Line N:`` definition
|
|
106
|
+
line lets body growth on any interior line block correctly even when the
|
|
107
|
+
``def`` line itself is untouched.
|
|
108
|
+
|
|
109
|
+
Exempt: test files (test bodies are sometimes long by necessity), Django
|
|
110
|
+
migrations (auto-generated), workflow registries (registry entries), and
|
|
111
|
+
hook infrastructure.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
content: The Python source to analyze.
|
|
115
|
+
file_path: The path of the file being checked.
|
|
116
|
+
all_changed_lines: Post-edit line numbers the current edit touched, or
|
|
117
|
+
None to treat the whole file as in scope. When provided, a violation
|
|
118
|
+
blocks only when the function's declared span intersects the changed
|
|
119
|
+
lines.
|
|
120
|
+
defer_scope_to_caller: When True, return every violation so the
|
|
121
|
+
commit/push gate's ``split_violations_by_scope`` can scope by added
|
|
122
|
+
line and report the in-scope set.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
Blocking issues. When *defer_scope_to_caller* is True every violation is
|
|
126
|
+
returned for the gate to scope; otherwise every violation in scope is
|
|
127
|
+
returned.
|
|
128
|
+
"""
|
|
129
|
+
if is_test_file(file_path):
|
|
130
|
+
return []
|
|
131
|
+
if is_hook_infrastructure(file_path):
|
|
132
|
+
return []
|
|
133
|
+
if is_workflow_registry_file(file_path) or is_migration_file(file_path):
|
|
134
|
+
return []
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
parsed_tree = ast.parse(content)
|
|
138
|
+
except SyntaxError:
|
|
139
|
+
return []
|
|
140
|
+
|
|
141
|
+
all_violations_in_walk_order: list[tuple[range, str]] = []
|
|
142
|
+
for each_node in ast.walk(parsed_tree):
|
|
143
|
+
if not isinstance(each_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
144
|
+
continue
|
|
145
|
+
line_span = _function_definition_line_span(each_node)
|
|
146
|
+
if line_span < FUNCTION_LENGTH_BLOCKING_THRESHOLD:
|
|
147
|
+
continue
|
|
148
|
+
docstring_line_total = sum(
|
|
149
|
+
_definition_docstring_line_span(each_definition)
|
|
150
|
+
for each_definition in ast.walk(each_node)
|
|
151
|
+
if isinstance(
|
|
152
|
+
each_definition, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)
|
|
153
|
+
)
|
|
154
|
+
)
|
|
155
|
+
executable_line_span = line_span - docstring_line_total
|
|
156
|
+
if executable_line_span >= FUNCTION_LENGTH_BLOCKING_THRESHOLD:
|
|
157
|
+
span_range = range(each_node.lineno, each_node.lineno + line_span)
|
|
158
|
+
message = (
|
|
159
|
+
f"Function {each_node.name!r} (defined at line {each_node.lineno}) "
|
|
160
|
+
f"is {line_span} lines - {FUNCTION_LENGTH_BLOCKING_MESSAGE_SUFFIX}"
|
|
161
|
+
)
|
|
162
|
+
all_violations_in_walk_order.append((span_range, message))
|
|
163
|
+
return _scope_violations_to_changed_lines(
|
|
164
|
+
all_violations_in_walk_order,
|
|
165
|
+
all_changed_lines,
|
|
166
|
+
defer_scope_to_caller,
|
|
167
|
+
)
|