finefettle 1.0.2__tar.gz

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 (221) hide show
  1. finefettle-1.0.2/CHANGELOG.md +350 -0
  2. finefettle-1.0.2/LICENSE +21 -0
  3. finefettle-1.0.2/MANIFEST.in +9 -0
  4. finefettle-1.0.2/PKG-INFO +387 -0
  5. finefettle-1.0.2/README.md +355 -0
  6. finefettle-1.0.2/finefettle.egg-info/PKG-INFO +387 -0
  7. finefettle-1.0.2/finefettle.egg-info/SOURCES.txt +219 -0
  8. finefettle-1.0.2/finefettle.egg-info/dependency_links.txt +1 -0
  9. finefettle-1.0.2/finefettle.egg-info/entry_points.txt +2 -0
  10. finefettle-1.0.2/finefettle.egg-info/requires.txt +12 -0
  11. finefettle-1.0.2/finefettle.egg-info/top_level.txt +1 -0
  12. finefettle-1.0.2/hooks/hooks.json +51 -0
  13. finefettle-1.0.2/hooks/subagent_inject.js +85 -0
  14. finefettle-1.0.2/integrations/opencode/fettle.ts +88 -0
  15. finefettle-1.0.2/integrations/vscode/src/extension.ts +189 -0
  16. finefettle-1.0.2/pyproject.toml +67 -0
  17. finefettle-1.0.2/rules/.ruff.toml +10 -0
  18. finefettle-1.0.2/rules/go-antipatterns.yml +68 -0
  19. finefettle-1.0.2/rules/llm-antipatterns.yml +261 -0
  20. finefettle-1.0.2/rules/ts-antipatterns.yml +112 -0
  21. finefettle-1.0.2/scripts/__init__.py +3 -0
  22. finefettle-1.0.2/scripts/__main__.py +7 -0
  23. finefettle-1.0.2/scripts/_resources.py +45 -0
  24. finefettle-1.0.2/scripts/action_entrypoint.py +130 -0
  25. finefettle-1.0.2/scripts/adapters/__init__.py +74 -0
  26. finefettle-1.0.2/scripts/adapters/go_adapter.py +136 -0
  27. finefettle-1.0.2/scripts/adapters/python_adapter.py +204 -0
  28. finefettle-1.0.2/scripts/adapters/rust_adapter.py +122 -0
  29. finefettle-1.0.2/scripts/adapters/typescript_adapter.py +182 -0
  30. finefettle-1.0.2/scripts/advisory.py +136 -0
  31. finefettle-1.0.2/scripts/ai_summaries.py +38 -0
  32. finefettle-1.0.2/scripts/artifact_gate.py +174 -0
  33. finefettle-1.0.2/scripts/autofix.py +116 -0
  34. finefettle-1.0.2/scripts/baseline.py +113 -0
  35. finefettle-1.0.2/scripts/bash_audit.py +86 -0
  36. finefettle-1.0.2/scripts/bench.py +117 -0
  37. finefettle-1.0.2/scripts/blackduck_adapter.py +133 -0
  38. finefettle-1.0.2/scripts/boundary_rules.py +105 -0
  39. finefettle-1.0.2/scripts/boundary_scan.py +207 -0
  40. finefettle-1.0.2/scripts/cache.py +105 -0
  41. finefettle-1.0.2/scripts/changeset.py +141 -0
  42. finefettle-1.0.2/scripts/ci.py +212 -0
  43. finefettle-1.0.2/scripts/ci_diagnose.py +137 -0
  44. finefettle-1.0.2/scripts/ci_ingest.py +105 -0
  45. finefettle-1.0.2/scripts/cli.py +435 -0
  46. finefettle-1.0.2/scripts/commit_message.py +184 -0
  47. finefettle-1.0.2/scripts/complexity_check.py +177 -0
  48. finefettle-1.0.2/scripts/config.py +316 -0
  49. finefettle-1.0.2/scripts/config_protect.py +194 -0
  50. finefettle-1.0.2/scripts/config_v050.py +139 -0
  51. finefettle-1.0.2/scripts/coverage_gate.py +228 -0
  52. finefettle-1.0.2/scripts/cross_review.py +106 -0
  53. finefettle-1.0.2/scripts/debt_report.py +179 -0
  54. finefettle-1.0.2/scripts/dep_check.py +251 -0
  55. finefettle-1.0.2/scripts/deploy_gate.py +164 -0
  56. finefettle-1.0.2/scripts/destructive_guard.py +210 -0
  57. finefettle-1.0.2/scripts/discipline_link.py +114 -0
  58. finefettle-1.0.2/scripts/dispatcher.py +171 -0
  59. finefettle-1.0.2/scripts/dispatcher_aggregate.py +107 -0
  60. finefettle-1.0.2/scripts/dispatcher_registry.py +257 -0
  61. finefettle-1.0.2/scripts/dispatcher_types.py +128 -0
  62. finefettle-1.0.2/scripts/doctor.py +98 -0
  63. finefettle-1.0.2/scripts/entry_points.py +109 -0
  64. finefettle-1.0.2/scripts/environment.py +141 -0
  65. finefettle-1.0.2/scripts/evals_runner.py +203 -0
  66. finefettle-1.0.2/scripts/event.py +105 -0
  67. finefettle-1.0.2/scripts/explain.py +84 -0
  68. finefettle-1.0.2/scripts/finding.py +244 -0
  69. finefettle-1.0.2/scripts/fp_stamp.py +111 -0
  70. finefettle-1.0.2/scripts/health_telemetry.py +267 -0
  71. finefettle-1.0.2/scripts/import_graph.py +260 -0
  72. finefettle-1.0.2/scripts/install.py +156 -0
  73. finefettle-1.0.2/scripts/integration_base.py +63 -0
  74. finefettle-1.0.2/scripts/lean_debt.py +98 -0
  75. finefettle-1.0.2/scripts/lean_sniffers.py +647 -0
  76. finefettle-1.0.2/scripts/learn.py +220 -0
  77. finefettle-1.0.2/scripts/loop_detect.py +232 -0
  78. finefettle-1.0.2/scripts/lsp_server.py +382 -0
  79. finefettle-1.0.2/scripts/mcp_trust_gate.py +333 -0
  80. finefettle-1.0.2/scripts/migration_safety.py +44 -0
  81. finefettle-1.0.2/scripts/mutation_test.py +217 -0
  82. finefettle-1.0.2/scripts/pact_adapter.py +115 -0
  83. finefettle-1.0.2/scripts/paths.py +109 -0
  84. finefettle-1.0.2/scripts/plan_validator.py +333 -0
  85. finefettle-1.0.2/scripts/policy_layers.py +346 -0
  86. finefettle-1.0.2/scripts/post_bash_doc_check.py +185 -0
  87. finefettle-1.0.2/scripts/post_edit.py +455 -0
  88. finefettle-1.0.2/scripts/post_edit_go.py +120 -0
  89. finefettle-1.0.2/scripts/post_edit_ts.py +185 -0
  90. finefettle-1.0.2/scripts/pr_review.py +148 -0
  91. finefettle-1.0.2/scripts/profile.py +260 -0
  92. finefettle-1.0.2/scripts/project_rules.py +85 -0
  93. finefettle-1.0.2/scripts/provenance_gate.py +141 -0
  94. finefettle-1.0.2/scripts/py.typed +0 -0
  95. finefettle-1.0.2/scripts/quality_gate.py +591 -0
  96. finefettle-1.0.2/scripts/quality_scan.py +374 -0
  97. finefettle-1.0.2/scripts/ratchet.py +377 -0
  98. finefettle-1.0.2/scripts/release_gate.py +103 -0
  99. finefettle-1.0.2/scripts/report.py +161 -0
  100. finefettle-1.0.2/scripts/result.py +136 -0
  101. finefettle-1.0.2/scripts/review.py +130 -0
  102. finefettle-1.0.2/scripts/sarif.py +101 -0
  103. finefettle-1.0.2/scripts/schema_drift.py +45 -0
  104. finefettle-1.0.2/scripts/scope_creep.py +186 -0
  105. finefettle-1.0.2/scripts/secret_scan.py +123 -0
  106. finefettle-1.0.2/scripts/security_review.py +195 -0
  107. finefettle-1.0.2/scripts/semgrep_util.py +75 -0
  108. finefettle-1.0.2/scripts/sonar_adapter.py +113 -0
  109. finefettle-1.0.2/scripts/spec_audit.py +75 -0
  110. finefettle-1.0.2/scripts/stop_quality_gate.py +285 -0
  111. finefettle-1.0.2/scripts/suppressions_v3.py +343 -0
  112. finefettle-1.0.2/scripts/tdd_gate.py +192 -0
  113. finefettle-1.0.2/scripts/test_discovery.py +91 -0
  114. finefettle-1.0.2/scripts/test_runner_opts.py +61 -0
  115. finefettle-1.0.2/scripts/threat_model.py +168 -0
  116. finefettle-1.0.2/scripts/tier_routing.py +87 -0
  117. finefettle-1.0.2/scripts/tool_runner.py +101 -0
  118. finefettle-1.0.2/scripts/trace.py +81 -0
  119. finefettle-1.0.2/scripts/trace_requirements.py +207 -0
  120. finefettle-1.0.2/scripts/ux_spec_gate.py +90 -0
  121. finefettle-1.0.2/scripts/worklog.py +165 -0
  122. finefettle-1.0.2/scripts/workspace.py +234 -0
  123. finefettle-1.0.2/setup.cfg +4 -0
  124. finefettle-1.0.2/setup.py +38 -0
  125. finefettle-1.0.2/templates/ci-fettle.yml +28 -0
  126. finefettle-1.0.2/templates/claude-md-addon.md +12 -0
  127. finefettle-1.0.2/templates/ops-review.md +81 -0
  128. finefettle-1.0.2/templates/pre-commit-config.yaml +16 -0
  129. finefettle-1.0.2/templates/preflight.md +82 -0
  130. finefettle-1.0.2/tests/test_action_entrypoint.py +82 -0
  131. finefettle-1.0.2/tests/test_adapter.py +91 -0
  132. finefettle-1.0.2/tests/test_advanced.py +100 -0
  133. finefettle-1.0.2/tests/test_advisory.py +179 -0
  134. finefettle-1.0.2/tests/test_artifact_gate.py +114 -0
  135. finefettle-1.0.2/tests/test_baseline.py +56 -0
  136. finefettle-1.0.2/tests/test_bash_audit.py +128 -0
  137. finefettle-1.0.2/tests/test_bench.py +138 -0
  138. finefettle-1.0.2/tests/test_bootstrap_gate.py +101 -0
  139. finefettle-1.0.2/tests/test_boundary_rules.py +107 -0
  140. finefettle-1.0.2/tests/test_boundary_scan.py +118 -0
  141. finefettle-1.0.2/tests/test_changeset.py +97 -0
  142. finefettle-1.0.2/tests/test_ci.py +170 -0
  143. finefettle-1.0.2/tests/test_ci_diagnose.py +90 -0
  144. finefettle-1.0.2/tests/test_ci_ingest.py +85 -0
  145. finefettle-1.0.2/tests/test_cli.py +184 -0
  146. finefettle-1.0.2/tests/test_commit_message.py +204 -0
  147. finefettle-1.0.2/tests/test_complexity.py +178 -0
  148. finefettle-1.0.2/tests/test_config.py +145 -0
  149. finefettle-1.0.2/tests/test_config_protect.py +193 -0
  150. finefettle-1.0.2/tests/test_config_v050.py +100 -0
  151. finefettle-1.0.2/tests/test_coverage_gate.py +224 -0
  152. finefettle-1.0.2/tests/test_debt_report.py +71 -0
  153. finefettle-1.0.2/tests/test_debug_detect.py +139 -0
  154. finefettle-1.0.2/tests/test_dep_check.py +109 -0
  155. finefettle-1.0.2/tests/test_deploy_gate.py +98 -0
  156. finefettle-1.0.2/tests/test_destructive_guard.py +293 -0
  157. finefettle-1.0.2/tests/test_discipline_link.py +100 -0
  158. finefettle-1.0.2/tests/test_dispatcher.py +190 -0
  159. finefettle-1.0.2/tests/test_doctor.py +62 -0
  160. finefettle-1.0.2/tests/test_entry_points.py +54 -0
  161. finefettle-1.0.2/tests/test_environment.py +82 -0
  162. finefettle-1.0.2/tests/test_evals_runner.py +153 -0
  163. finefettle-1.0.2/tests/test_finding.py +225 -0
  164. finefettle-1.0.2/tests/test_health_telemetry.py +232 -0
  165. finefettle-1.0.2/tests/test_import_graph.py +332 -0
  166. finefettle-1.0.2/tests/test_integrations.py +144 -0
  167. finefettle-1.0.2/tests/test_lean_debt.py +173 -0
  168. finefettle-1.0.2/tests/test_lean_sniffers.py +525 -0
  169. finefettle-1.0.2/tests/test_lean_surface.py +178 -0
  170. finefettle-1.0.2/tests/test_learn.py +58 -0
  171. finefettle-1.0.2/tests/test_loop_detect.py +212 -0
  172. finefettle-1.0.2/tests/test_loop_discipline.py +141 -0
  173. finefettle-1.0.2/tests/test_lsp_server.py +346 -0
  174. finefettle-1.0.2/tests/test_mcp_trust_gate.py +296 -0
  175. finefettle-1.0.2/tests/test_mutation_test.py +81 -0
  176. finefettle-1.0.2/tests/test_output_schema.py +304 -0
  177. finefettle-1.0.2/tests/test_paths.py +86 -0
  178. finefettle-1.0.2/tests/test_plan_validator.py +342 -0
  179. finefettle-1.0.2/tests/test_policy_layers.py +433 -0
  180. finefettle-1.0.2/tests/test_polyglot_adapters.py +78 -0
  181. finefettle-1.0.2/tests/test_post_bash_doc_check.py +204 -0
  182. finefettle-1.0.2/tests/test_post_edit.py +382 -0
  183. finefettle-1.0.2/tests/test_post_edit_go.py +152 -0
  184. finefettle-1.0.2/tests/test_post_edit_rust.py +130 -0
  185. finefettle-1.0.2/tests/test_post_edit_shell.py +108 -0
  186. finefettle-1.0.2/tests/test_pr_review.py +55 -0
  187. finefettle-1.0.2/tests/test_profile.py +85 -0
  188. finefettle-1.0.2/tests/test_project_rules.py +116 -0
  189. finefettle-1.0.2/tests/test_provenance_gate.py +117 -0
  190. finefettle-1.0.2/tests/test_quality_gate.py +270 -0
  191. finefettle-1.0.2/tests/test_quality_scan.py +189 -0
  192. finefettle-1.0.2/tests/test_ratchet.py +468 -0
  193. finefettle-1.0.2/tests/test_release_gate.py +100 -0
  194. finefettle-1.0.2/tests/test_report.py +37 -0
  195. finefettle-1.0.2/tests/test_resources.py +14 -0
  196. finefettle-1.0.2/tests/test_result.py +88 -0
  197. finefettle-1.0.2/tests/test_rule_integrity.py +139 -0
  198. finefettle-1.0.2/tests/test_rules.py +333 -0
  199. finefettle-1.0.2/tests/test_run_sh.py +87 -0
  200. finefettle-1.0.2/tests/test_scope_creep.py +171 -0
  201. finefettle-1.0.2/tests/test_scrub_audit.py +71 -0
  202. finefettle-1.0.2/tests/test_secret_scan.py +135 -0
  203. finefettle-1.0.2/tests/test_security_review.py +110 -0
  204. finefettle-1.0.2/tests/test_semgrep_anchor.py +111 -0
  205. finefettle-1.0.2/tests/test_spec_audit.py +81 -0
  206. finefettle-1.0.2/tests/test_stop_quality_gate.py +300 -0
  207. finefettle-1.0.2/tests/test_subagent_inject.py +204 -0
  208. finefettle-1.0.2/tests/test_suppressions_v3.py +243 -0
  209. finefettle-1.0.2/tests/test_tdd_gate.py +130 -0
  210. finefettle-1.0.2/tests/test_test_discovery.py +51 -0
  211. finefettle-1.0.2/tests/test_test_runner_opts.py +72 -0
  212. finefettle-1.0.2/tests/test_threat_model.py +57 -0
  213. finefettle-1.0.2/tests/test_tier_routing.py +63 -0
  214. finefettle-1.0.2/tests/test_tool_runner.py +98 -0
  215. finefettle-1.0.2/tests/test_trace.py +37 -0
  216. finefettle-1.0.2/tests/test_trace_requirements.py +116 -0
  217. finefettle-1.0.2/tests/test_ts_rules.py +102 -0
  218. finefettle-1.0.2/tests/test_typescript_adapter.py +216 -0
  219. finefettle-1.0.2/tests/test_ux_spec_gate.py +49 -0
  220. finefettle-1.0.2/tests/test_worklog.py +126 -0
  221. finefettle-1.0.2/tests/test_workspace.py +130 -0
@@ -0,0 +1,350 @@
1
+ # Changelog
2
+
3
+ ## v1.0.2 — finefettle on PyPI
4
+
5
+ - **Package renamed to `finefettle` on PyPI** (“in fine fettle”) — the
6
+ `fettle` name belongs to an unrelated project. Console script and import
7
+ name remain `fettle`.
8
+ - **Trusted Publishing release workflow**: pushing a `v*` tag builds,
9
+ tests, smoke-tests the wheel, and publishes to PyPI via GitHub OIDC —
10
+ no long-lived tokens. Tag must match pyproject version (enforced).
11
+ - **Commit-time guards**: repo now runs scrub-audit + fettle-check +
12
+ rules-validate as pre-commit hooks (`pre-commit install`); the CI
13
+ scrub-audit failure of 2026-07-24 (leaked local path in a plan doc)
14
+ is caught before a commit exists.
15
+
16
+ ## v1.0.1 — Trustworthy Core (Phase 0 hotfix arc)
17
+
18
+ Correctness fixes from the 2026-07 full-repo audit (D1–D4). See
19
+ [docs/fettle-enterprise-product-plan.md](docs/fettle-enterprise-product-plan.md)
20
+ for the full enterprise arc (WP-133..WP-153).
21
+
22
+ ### Fixed
23
+ - **CLI exit-code contract (D1)**: `fettle check` now exits `0` (clean),
24
+ `1` (error-severity findings), `2` (usage/environment error) — identically
25
+ in text and `--json` modes. Previously `--json` always exited 0, silently
26
+ passing CI gates.
27
+ - **`fettle check` flags wired (D2)**: `--changed` scans only git-changed
28
+ Python files (via changeset detection), `--fix` applies safe ruff autofixes
29
+ before scanning, `--baseline` reports only findings absent from
30
+ `.fettle-baseline.json` (accepts both wrapper-dict and legacy list formats).
31
+ `--all` and `--changed` together is now a usage error. All four flags were
32
+ previously accepted but ignored.
33
+ - **MCP trust gate allowlist path (D3)**: the default
34
+ `~/.config/fettle/mcp-allowlist.json` path is now `expanduser`-resolved —
35
+ the literal `~` was never expanded, so the default allowlist never loaded.
36
+ Protected-path checks also resolve paths, blocking writes to the allowlist
37
+ via its absolute path, not just the literal `~` form.
38
+ - **LR012 duplicate-helper sniffer (D4)**: replaced per-function `git grep`
39
+ calls with a 40 ms timeout by one batched grep with a 0.5 s timeout —
40
+ detection was nondeterministic under load (and its test flaky).
41
+ - **Hook launcher no longer auto-installs tools (D6)**: `run.sh` ran an
42
+ unpinned `uv tool install ruff/semgrep` inside the hook path on every
43
+ invocation where a tool was missing — a supply-chain and latency risk.
44
+ Missing tools are now reported by `fettle doctor` and skipped with a
45
+ warning by the individual checks.
46
+ - **Destructive-guard allowlist matching (D7)**: `allow_commands` entries
47
+ now match a whole command segment exactly (whitespace-normalized).
48
+ Substring matching let one allowed entry forgive an entire chained
49
+ command (`rm -rf node_modules; rm -rf ~`).
50
+ - **Hook timeouts corrected to seconds (D8)**: `hooks.json` declared
51
+ 10000/15000/60000 — Claude Code interprets hook timeouts in seconds, so a
52
+ hung hook could block a session for hours. Now 10/15/60 s (5 s SubagentStart).
53
+
54
+ ### Added
55
+ - `fettle --version` — reads pyproject.toml in clone mode, package metadata
56
+ when pip-installed.
57
+ - Release-gate test asserting pyproject, `__version__`, CHANGELOG, and README
58
+ versions all agree.
59
+ - Ruff self-lint config in pyproject.toml and a `.fettle-ignore` excluding
60
+ `tests/fixtures` (intentional-violation corpora) from self-scans (D9);
61
+ repo is now self-check clean.
62
+
63
+ ### Internal
64
+ - `quality_scan.scan_project()` accepts a `files=` parameter for targeted
65
+ scans; `run_ruff`/`run_semgrep` accept target lists.
66
+ - 12 new regression tests pin the exit-code contract and allowlist resolution.
67
+ - Version metadata aligned (pyproject said 0.7.0 while docs said v1.0.0).
68
+
69
+ ## v1.0.0 — Enterprise Integration + SWEBOK Coverage
70
+
71
+ ### Enterprise Features (v1.0 plan)
72
+ - **WP-L — Extended secret scanner**: Azure Storage, Azure AD, GCP Service Account,
73
+ GCP API Key, Bearer Token patterns. Config: `boundary.extra_secret_patterns`.
74
+ - **WP-N — Provenance policy gate**: 4 modes (none/manifest/marker/commit) for
75
+ AI-generated code disclosure. PostToolUse(Write), new files only.
76
+ - **WP-O — Artifact verification gate**: PreToolUse(Bash) blocks publish without
77
+ signed/scanned evidence. Evidence bound to exact artifact identity + exit code.
78
+ - **WP-P — Security review command**: `/fettle:security-review` orchestrating ruff
79
+ S-rules + semgrep p/owasp-top-ten with CWE references.
80
+ - **WP-Q — Threat model command**: `/fettle:threat-model` STRIDE template with
81
+ auto-detected entry points, data stores, and auth mechanisms.
82
+ - **WP-R — PR review orchestration**: `/fettle:pr-review` aggregates quality scan +
83
+ coverage + complexity + breaking-change detection.
84
+ - **WP-S — SonarQube adapter**: IntegrationAdapter protocol, quality gate + issues API.
85
+ - **WP-T — Black Duck/Polaris adapter**: CLI invocation, SARIF parsing, subprocess security.
86
+ - **WP-U — Pact adapter**: Broker API for contract verification status.
87
+ - **WP-V — Architecture boundary rules**: import direction enforcement from .fettle.toml rules.
88
+ - **WP-W — ADR + Architecture discipline skills** in Disciplines plugin.
89
+
90
+ ### SWEBOK v4 Gap Coverage
91
+ - **WP-X1 — Technical debt dashboard**: TODO/suppression count, complexity trend, A-E rating.
92
+ - **WP-X2 — Deployment safety gate**: PreToolUse(Bash) verifies tests ran, health endpoint
93
+ exists, no debug flags before deploy commands.
94
+ - **WP-X3 — Release gate**: CHANGELOG/semver enforcement on `git tag`.
95
+ - **WP-X4 — Mutation testing command**: wraps mutmut, changed files only, configurable threshold.
96
+ - **WP-X5 — Requirements traceability**: links spec files to tests via naming + markers.
97
+
98
+ ### Infrastructure
99
+ - **IntegrationAdapter protocol**: shared 5-state result model (pass/fail/unavailable/
100
+ misconfigured/not_enabled) with configurable fail-open/fail-closed.
101
+ - **Codebase rationalization**: deleted 11 dead modules + 6 orphaned tests (-1,585 lines).
102
+ - **JSON schema contract tests**: 16 tests validating dispatcher output against Claude Code schema.
103
+ - **TypeScript adapter tests**: 21 dedicated integration tests.
104
+ - **Worklog gate**: daily worklog enforcement at Stop hook.
105
+ - **CI fix**: resolved semgrep false positive on f-strings.
106
+
107
+ ## v0.9.0 — Engineering Discipline Enforcement
108
+
109
+ - **WP-K — Branch coverage gate**: extends coverage_gate.py to check
110
+ missing_branches from coverage.json. Only flags branches originating from
111
+ edited lines. Config: `gates.coverage.minimum_branch_percent`.
112
+ - **WP-H — Function complexity limits**: new complexity_check.py with
113
+ cyclomatic and cognitive complexity per modified function (stdlib ast only).
114
+ Config: `gates.complexity.max_cyclomatic`, `max_cognitive`.
115
+ - **WP-J — Enhanced plan thresholds**: risk paths (auth/security/migration
116
+ globs), module count, and line estimation independently trigger plan gate.
117
+ Config: `gates.plan.risk_paths`, `module_threshold`, `line_threshold`.
118
+ - **WP-I — TDD phase enforcement**: detects test-before-implementation ordering.
119
+ Advisory mode only in v0.9. Config: `gates.tdd`.
120
+ - **VS Code extension**: new `integrations/vscode/` launches LSP server for
121
+ inline diagnostics in VS Code.
122
+
123
+ ## v0.8.0 — Discipline Integration
124
+
125
+ - **WP-A — Surface lean findings**: lean_sniffers returns advisory (not just
126
+ silent JSONL) when `gates.lean_review.mode = "advisory"`.
127
+ - **WP-B — Normalized advisory contract**: Advisory dataclass, persisted
128
+ AdvisoryDeduplicator, format_advisories renderer, aggregator cross-check cap.
129
+ Config: `gates.advisory`.
130
+ - **WP-B2 — Migrate lean_sniffers onto AdvisoryDeduplicator**: single dedup
131
+ mechanism across all advisory output.
132
+ - **WP-C — Discipline link pilot**: loop_detect injects 2-sentence debugging
133
+ reminder from discipline-debugging (or fallback). Config: `gates.discipline_link`.
134
+ - **WP-D — Cooperative budget enforcement**: per-check deadline in HookContext,
135
+ overrun logging, lean_sniffers honors dispatcher deadline.
136
+ - **WP-E — Bash structured audit**: privacy-first event logging (hash only by
137
+ default, opt-in redacted capture). Config: `gates.bash_audit`.
138
+ - **WP-F — Diff coverage gate**: reads pre-existing coverage.json, staleness
139
+ guard, advisory/enforce per mode. Config: `gates.coverage`.
140
+ - **WP-G — Shared discipline_link helper**: trigger-to-skill mappings ready for
141
+ expansion after pilot metric passes.
142
+ - **hookEventName fix**: dispatcher now includes hookEventName in all output
143
+ (fixes Claude Code Stop hook validation error).
144
+ - **bench/doctor PATH fix**: tools at ~/.local/bin found via _which() fallback.
145
+
146
+ ## v0.7.0
147
+
148
+ - **WP-122 (partial) — Git-installable Python package**: console entry points,
149
+ bundled rule resources, and `python -m fettle`. PyPI publication is deferred
150
+ because that project name belongs to an unrelated package.
151
+ - **WP-123 — GitHub Action and reusable workflow**: advisory/enforce modes,
152
+ SARIF output, and pull-request annotations.
153
+ - **WP-125 — LSP diagnostics**: `fettle lsp` publishes ruff and semgrep findings
154
+ to editors over stdio JSON-RPC.
155
+ - **WP-126 (partial) — policy layering**: defaults, organization, team,
156
+ repository, and directory-scoped configuration with `fettle config --explain`.
157
+ Cryptographic bundle signing remains open.
158
+ - **OpenCode integration**: translates OpenCode tool/session lifecycle events
159
+ into the existing dispatcher protocol while preserving Claude Code support.
160
+
161
+ ## v0.6.0 arc
162
+
163
+ - **WP-124 (pulled forward) — pre-commit integration**: published
164
+ `.pre-commit-hooks.yaml` with `fettle-check` (changed-files quality scan)
165
+ and `fettle-rules-validate` (project rule packs must pass `--validate`);
166
+ consumer snippet in `templates/pre-commit-config.yaml`. Same policy at the
167
+ commit chokepoint regardless of editor/agent.
168
+ - **WP-133 (scaffold) — behavioral eval lab** (`evals/`,
169
+ `scripts/evals_runner.py`): quorum-inspired, slimmed. Scenario dirs with
170
+ prompt/setup_files/checks; three-valued verdicts; static side CI-safe
171
+ (`evals_runner.py validate` + fake-runner unit tests), live side
172
+ (`claude -p`) trusted-operator only. Two seed scenarios: hook-catches-debug-statement,
173
+ plan-gate-nudges-multifile.
174
+ - **WP-116 — Rule-pack integrity gates** (`tests/test_rule_integrity.py`):
175
+ every rule in every pack must have a `fire/` and a `silent/` fixture under
176
+ `tests/fixtures/rulepacks/<pack>/<rule-id>/` — fixture-less rules fail the
177
+ suite. Mutation check proves `--validate` catches the duplicate-key defect
178
+ class that shipped in v0.4.0; generated project rules must validate too.
179
+ 46 fixtures added (23 rules × fire/silent). **Immediately caught a dead
180
+ rule**: `string-built-sql-ts` never fired — semgrep's ellipsis does not
181
+ match inside template literals; rewritten as `pattern-regex` (also covers
182
+ SQL templates assigned to variables).
183
+ - **WP-117 — Tool-version canary CI leg**: ubuntu job against newest semgrep
184
+ (`continue-on-error`, non-blocking) to surface upstream behavior changes
185
+ early; pinned legs stay authoritative.
186
+ - **WP-119 — Ratchet workflow** (`scripts/ratchet.py`): evidence-based
187
+ rule promotion/demotion. `fettle ratchet status` shows per-rule mode,
188
+ fire count, FP rate, and promotion eligibility. `promote` only succeeds
189
+ when a rule has ≥5 fires and ≤20% FP rate (aggregated from trace JSONL
190
+ and false-positive stamps). `demote` requires a reason. `sync`
191
+ re-aggregates without changing modes. Makes advisory-first a measured
192
+ product feature instead of a convention. (21 tests)
193
+ - **WP-120 — Suppressions with expiry and owner**
194
+ (`scripts/suppressions_v3.py`): structured suppression model with
195
+ `# fettle:ignore[rule-id] reason=... owner=@handle until=YYYY-MM-DD`
196
+ inline comments and `.fettle/suppressions.json` file-level entries.
197
+ Expired suppressions become findings themselves; ownerless suppressions
198
+ flagged in reports. CLI: `fettle suppressions {list|add|remove|report|expired}`.
199
+ (28 tests)
200
+ - **WP-121 — Loaded-rules health telemetry**
201
+ (`scripts/health_telemetry.py`): every hook run can log rules
202
+ loaded/skipped per config source into trace (`record_loaded_rules`);
203
+ `check_health` detects zero-rule packs and drops; `doctor_check()`
204
+ discovers expected packs from `rules/*.yml` and asserts health.
205
+ Standalone CLI for debugging. (16 tests)
206
+
207
+ ## v0.4.2 — Go post-edit check (2026-07-16)
208
+
209
+ - **Go route** (`scripts/post_edit_go.py`, registered in the dispatcher for
210
+ `.go` edits): semgrep runs the new built-in `rules/go-antipatterns.yml`
211
+ (empty-error-swallow, debug-print, sql-string-concat, http-client-no-timeout)
212
+ plus project rules from `.fettle/rules/`; golangci-lint runs when the anchor
213
+ root has a `go.mod`. Enforce mode blocks on ERROR findings.
214
+ End-to-end test proves a project-local Go rule (e.g. DVA3's
215
+ `no-direct-kafka-produce`) fires through the hook (`tests/test_post_edit_go.py`).
216
+
217
+ ## v0.4.1 — Rule config fixes + anchored semgrep scans (2026-07-16)
218
+
219
+ - **Fix: `ts-antipatterns.yml` was invalid** — duplicate `pattern-not-inside` keys
220
+ (`unawaited-promise`) and `patterns` + sibling `pattern-not-inside`
221
+ (`fetch-without-timeout`) made semgrep reject the whole config, silently
222
+ disabling **all** TS/JS checks. Also fixed AND-vs-OR misuse: `empty-catch-block`,
223
+ `string-built-sql-ts`, `regex-llm-output-ts` used `patterns:` (AND) where
224
+ `pattern-either:` (OR) was intended and could never fire.
225
+ - **Fix: TS rule precision** — the resurrected rules measured ~9,000 findings on a
226
+ 23-file UI5 app. `unawaited-promise` now targets known promise-returning APIs
227
+ (fetch/axios) instead of every statement-level call (semgrep OSS has no type
228
+ inference), and ignores `.then()`/`.catch()` chains. `regex-llm-output-ts` is
229
+ path-scoped to `agents/`, `pipeline/`, `llm/` like its Python counterpart.
230
+ Same app now: 2 findings, both true positives (`tests/test_ts_rules.py`).
231
+ - **Project-local rules** (`scripts/project_rules.py`): projects extend the
232
+ built-in rule packs via `.fettle.toml` — `[rules] extra_dirs` adds project
233
+ semgrep rule files (default `.fettle/rules/`), `promise_apis` extends
234
+ `unawaited-promise` with project-specific promise-returning APIs (validated
235
+ identifiers only; rule generated and cached under `.fettle/generated/`).
236
+ Both post-edit hooks pass the extra configs to semgrep.
237
+ - **Noise audit** of `llm-antipatterns.yml` on three real codebases: rules
238
+ confirmed precise when scans are correctly anchored (mis-anchored scans
239
+ defeated `paths.exclude` — same class of bug as the hook anchoring fix).
240
+ - **Fix: path-filter anchoring** (`scripts/semgrep_util.py`): semgrep ≥ 1.136
241
+ resolves `paths.include`/`exclude` against the git project root; files outside a
242
+ git repo silently escaped path-scoped rules and exclusions. Both hooks
243
+ (`post_edit.py`, `post_edit_ts.py`) now scan via `anchored_semgrep_args()` —
244
+ git root, else session cwd, else file dir — with `--project-root .`.
245
+ - **Tests** (`tests/test_semgrep_anchor.py`): every file under `rules/` must pass
246
+ `semgrep --validate` (catches dead-config regressions), plus anchoring contract
247
+ tests. Test harnesses in `test_rules.py`/`test_debug_detect.py` pin
248
+ `--project-root` for non-git tmpdirs.
249
+
250
+ ## v0.4.0 — Intelligence + Extensibility (2026-07-07)
251
+
252
+ - **TypeScript/JS rules** (`rules/ts-antipatterns.yml`): 5 semgrep rules for TS/JS
253
+ - **Cross-review** (`review.py`): provider-agnostic LLM code review
254
+ - **SARIF output** (`sarif.py`): GitHub code scanning format
255
+ - **Result caching** (`cache.py`): skip re-scanning unchanged files
256
+ - **Autofix** (`autofix.py`): safe ruff fixes with trace logging
257
+ - **Checker protocol** (`checker.py`): formal ABC for tool plugins (Ruff, Semgrep built-in)
258
+ - **Policy engine** (`policy.py`): central decision point for hook behavior
259
+ - **Event model** (`event.py`): typed FettleEvent replaces raw JSON
260
+ - **Install UX** (`install.py`): `fettle install config|hooks|ignore|all|status`
261
+ - **TS hook** (`post_edit_ts.py`): wired in hooks.json for TS/JS files
262
+
263
+ ## v0.3.0 — Foundation for v0.3/v0.4 roadmap
264
+
265
+ ### New modules
266
+ - **Result taxonomy** (`scripts/result.py`): PASS, VIOLATION, TOOL_ERROR, CONFIG_ERROR, SKIPPED. Finding dataclass with tool/severity/path/line/code/message/fixable.
267
+ - **Path resolver** (`scripts/paths.py`): centralized resolution, traversal protection, repo boundary checks, symlink safety.
268
+ - **CLI** (`scripts/cli.py`): `fettle check`, `fettle config --print-effective`, `fettle explain`, `fettle baseline`, `fettle doctor`.
269
+ - **Trace** (`scripts/trace.py`): persistent JSONL logging of all hook decisions.
270
+ - **Explain** (`scripts/explain.py`): human-readable explanation of last hook decision.
271
+ - **Baseline** (`scripts/baseline.py`): snapshot violations for incremental enforcement.
272
+ - **Learn** (`scripts/learn.py`): LLM-generated semgrep rules from incident descriptions.
273
+ - `pyproject.toml`: package metadata + console script `fettle`.
274
+ - 3 new slash commands: `/fettle:learn`, `/fettle:explain`, `/fettle:baseline`.
275
+ - `rules/learned/` directory for incident-derived rules.
276
+ - 33 new tests (test_result, test_paths, test_trace, test_baseline, test_learn, test_cli).
277
+
278
+ ### GPT 5.5 audit
279
+ - `docs/AUDIT-GPT55.md`: independent code audit with prioritized TODO.
280
+
281
+ ## Unreleased
282
+
283
+ - Stop-hook import checks understand src-layout packages (`src/<pkg>/`)
284
+ and skip dependencies declared in pyproject/requirements even when no
285
+ .venv exists to probe (ephemeral `uv run --with` envs) — a second
286
+ round of import false positives on real-world project layouts.
287
+ - Stop-hook cross-file checks no longer flood real projects with false
288
+ positives:
289
+ `stop_quality_gate.py` discovers the project root by walking up to
290
+ `pyproject.toml`/`setup.py`/`.git` instead of using the edited file's own
291
+ directory; `check_imports` recognizes packages installed in the project's
292
+ `.venv` (the hook's interpreter can't import them); `check_contracts`
293
+ accepts `from pkg import submodule` without an `__init__` re-export.
294
+
295
+ - Removed `effectiveness_report.py`: it depended on a private logging tool
296
+ no public install has; the tool's name joined the scrub-audit pattern.
297
+ The effectiveness loop returns in v0.4.0 built on Fettle's own trace files.
298
+ - Rust/shell gate tests now run on ubuntu CI (cargo + shellcheck installed);
299
+ cargo is resolved from PATH instead of a hardcoded Linux toolchain path.
300
+ - README documents the seven plugin slash commands.
301
+
302
+ ## v0.2.1 (2026-07-04)
303
+
304
+ Fixes surfaced by dogfooding the project scan on a real multi-package repo:
305
+
306
+ - `quality_scan.py` findings and baselines now use root-relative paths, so a
307
+ committed baseline matches on CI and other machines. Legacy absolute-path
308
+ baselines are normalized on load and keep working.
309
+ - `.fettle-ignore` patterns now actually filter project-scan findings (they
310
+ were only applied to the file count).
311
+ - File discovery prunes hidden dirs, `node_modules`, `venv`, `build`, `dist`
312
+ (a `.venv` inflated the scanned-file count 40x).
313
+ - The project scan reads `[severity]` from `.fettle.toml` instead of
314
+ hardcoded rule sets — CONFIG.md's "single source" claim is now true.
315
+ - New test suite for `quality_scan.py` (10 tests: baselines, portability,
316
+ ignores, severity config, exit codes).
317
+
318
+ ## v0.2.0 (2026-07-04)
319
+
320
+ First public release. Fettle began as a private quality-enforcement plugin;
321
+ this release makes it portable, configurable, and installable.
322
+
323
+ ### Added
324
+ - `.fettle.toml` per-repo configuration: per-gate enables, severity single
325
+ source, paths, review provider (docs/CONFIG.md).
326
+ - Session-scoped state under `$XDG_STATE_HOME/fettle/<session_id>/` — no
327
+ cross-session interference.
328
+ - Portable interpreter launcher (`scripts/run.sh`) and `scripts/doctor.py`
329
+ environment self-check.
330
+ - Authoritative plugin hook wiring (`hooks/hooks.json`) across PreToolUse /
331
+ PostToolUse / Stop — enforcement installs with the plugin.
332
+ - Rule metadata (`origin`, `citation`) on every semgrep rule.
333
+ - CI (ubuntu + macos), permanent private-string scrub audit.
334
+
335
+ ### Changed
336
+ - Opinionated process gates (plan, UX-spec, UI colors, doc-before-push,
337
+ tests, MCP trust) are now **opt-in** and default off; the core lint gate
338
+ defaults to advisory. Every block message names the config key that
339
+ disables it.
340
+ - The legacy `QUALITY_GATE_MODE` env var is gone; mode lives in
341
+ `.fettle.toml` (`[gates.lint].mode`, `[gates.docs].mode`) with
342
+ `FETTLE_GATE_MODE` as the emergency override (`off` disables all gates).
343
+ - Fail-visible policy: missing or failing analysis tools emit warnings and
344
+ `gate_error` trace events instead of silently passing.
345
+ - Python floor: 3.11 (stdlib tomllib).
346
+
347
+ ### Fixed
348
+ - Baseline save crash on bare filenames.
349
+ - Test suite: 163 passed / 0 failed (was 53 failures against
350
+ pre-consolidation script paths).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Milind Gaharwar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ include LICENSE
2
+ include README.md
3
+ include CHANGELOG.md
4
+
5
+ recursive-include rules *.yml
6
+ recursive-include rules *.toml
7
+ recursive-include hooks *.json *.js
8
+ recursive-include integrations *.ts
9
+ recursive-include templates *.yml *.yaml *.md