quality_gate 0.2.2 → 0.3.0

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/README.md +292 -21
  4. data/docs/codex.md +37 -9
  5. data/docs/releasing.md +16 -4
  6. data/lib/generators/quality_gate/install/install_generator.rb +18 -3
  7. data/lib/generators/quality_gate/install/templates/agents_section.md.tt +13 -2
  8. data/lib/generators/quality_gate/install/templates/codex_fast.rb.tt +36 -0
  9. data/lib/generators/quality_gate/install/templates/codex_hooks.json.tt +1 -0
  10. data/lib/generators/quality_gate/install/templates/codex_verify_stop.rb.tt +28 -0
  11. data/lib/generators/quality_gate/install/templates/quality_gate.yml.tt +6 -0
  12. data/lib/generators/quality_gate/install/templates/quality_gate_fast.rb.tt +16 -3
  13. data/lib/generators/quality_gate/install/templates/quality_gate_workflow.yml.tt +28 -0
  14. data/lib/generators/quality_gate/install/templates/rails_quality_gate.yml.tt +45 -0
  15. data/lib/generators/quality_gate/install/templates/ruby_agents_section.md.tt +13 -2
  16. data/lib/generators/quality_gate/install/templates/ruby_quality_gate.yml.tt +5 -0
  17. data/lib/generators/quality_gate/install/templates/simplecov.rb.tt +1 -0
  18. data/lib/quality_gate/adapters/bundler_audit.rb +28 -3
  19. data/lib/quality_gate/adapters/database_consistency.rb +51 -0
  20. data/lib/quality_gate/adapters/database_consistency_report.rb +61 -0
  21. data/lib/quality_gate/adapters/database_consistency_report_item.rb +122 -0
  22. data/lib/quality_gate/adapters/debride.rb +67 -0
  23. data/lib/quality_gate/adapters/debride_report.rb +80 -0
  24. data/lib/quality_gate/adapters/herb.rb +303 -0
  25. data/lib/quality_gate/adapters/reek.rb +21 -2
  26. data/lib/quality_gate/adapters/rubocop.rb +23 -9
  27. data/lib/quality_gate/adapters/rubycritic.rb +74 -0
  28. data/lib/quality_gate/adapters/rubycritic_report.rb +112 -0
  29. data/lib/quality_gate/adapters/test_suite.rb +12 -1
  30. data/lib/quality_gate/baseline.rb +269 -0
  31. data/lib/quality_gate/baseline_run.rb +80 -0
  32. data/lib/quality_gate/cli.rb +129 -6
  33. data/lib/quality_gate/codex_fast_hook.rb +163 -0
  34. data/lib/quality_gate/codex_patch_files.rb +95 -0
  35. data/lib/quality_gate/codex_stop_hook.rb +102 -0
  36. data/lib/quality_gate/config.rb +20 -6
  37. data/lib/quality_gate/database_consistency_runner.rb +124 -0
  38. data/lib/quality_gate/doctor.rb +217 -0
  39. data/lib/quality_gate/doctor_bounded_file.rb +74 -0
  40. data/lib/quality_gate/doctor_command.rb +130 -0
  41. data/lib/quality_gate/doctor_coverage.rb +113 -0
  42. data/lib/quality_gate/doctor_git.rb +121 -0
  43. data/lib/quality_gate/doctor_hooks.rb +99 -0
  44. data/lib/quality_gate/doctor_launchers.rb +300 -0
  45. data/lib/quality_gate/doctor_path_lookup.rb +52 -0
  46. data/lib/quality_gate/doctor_report.rb +38 -0
  47. data/lib/quality_gate/init_command.rb +3 -1
  48. data/lib/quality_gate/installation.rb +72 -17
  49. data/lib/quality_gate/installer.rb +3 -0
  50. data/lib/quality_gate/reporters/doctor.rb +57 -0
  51. data/lib/quality_gate/reporters/json.rb +18 -1
  52. data/lib/quality_gate/reporters/markdown.rb +11 -1
  53. data/lib/quality_gate/reporters/text.rb +14 -6
  54. data/lib/quality_gate/ruby_profile.rb +121 -2
  55. data/lib/quality_gate/runner.rb +15 -17
  56. data/lib/quality_gate/version.rb +1 -1
  57. data/lib/quality_gate.rb +15 -0
  58. data/sig/quality_gate.rbs +117 -2
  59. metadata +30 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75a0ad2a06f284a1e9985f522e837a43cb584a86c29640c7399f68cbf176a31c
4
- data.tar.gz: 06101f90ff3e9f1b5221a682b35b1b6470be9eecad34a2fdb8f68fa0faeaacfa
3
+ metadata.gz: e438f281cbb59bb4c7abd81290d1281e5ded80d8f6840c3268e0392a72307488
4
+ data.tar.gz: 6d0d56e91fa33fe72753dceb7e0a51f43c082639adc23f19eb2b6c8a7a003d11
5
5
  SHA512:
6
- metadata.gz: d89d8d0f2ec100c0f452d13ce6c6e14d8c38b6356f7475bc85978c3968e8575caf44848ad24c5eb550efdc7b29bcade260d9e75a04021ef2d9cdea37bd3faa7d
7
- data.tar.gz: ecffaac50b0271211ba3cfadc132c3970d55be7c8355c582a41e42dbaf3584f64cdd0969b18338bda1e9eff87517b2711a435725769db68c1997976824afd384
6
+ metadata.gz: 1d36248ffca64a9908d3dbb7ec1c835a005c0491431c5dba2fa6bb7b83d0f510762835b0cf6234abf925370eb04285d373d82b1a162db45d9caaacab5bdddca3
7
+ data.tar.gz: 356a4eeeecfb0ca945efa3f8f6af080b10adae9f75d04747d152c1c27209d574223b8de71ccdc6ca1ca7bfe7f95a036b1003560456b08fd144c7ffee4302c98e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.3.0] - 2026-10-04
4
+
5
+ - Add `quality_gate doctor` for read-only setup preflight checks with text or JSON output.
6
+ - Add an optional, explicitly invoked RubyCritic-backed `deep` gate for project-wide design analysis. RubyCritic remains a host-project dependency; the gate does not add a score budget or generated hooks/workflows.
7
+ - Add optional Debride support to the manual, project-wide `deep` gate for potentially unused method candidates. Debride remains a host-project dependency; the existing RubyCritic default and generated hooks/workflows are unchanged.
8
+ - Add an optional, project-wide `audit` adapter for database consistency using the host project's `database_consistency ~> 3.0.14`; analyzer scan failures are reported as tool failures.
9
+ - Add opt-in fast/verify warning baselines with comparison, create, and shrink-only ratchet modes; protected findings and tool failures remain enforced.
10
+ - Treat RuboCop process errors and Reek source-processing diagnostics as tool failures even when their JSON output is valid and empty.
11
+ - Add opt-in Codex patch feedback after native `apply_patch` calls while retaining full Stop verification.
12
+ - Add an opt-in native Codex Stop verification hook for plain Ruby and Rails installs.
13
+
14
+ ## [0.2.3] - 2026-10-02
15
+
16
+ - Reek scans the project when a bare gate invocation has no selected paths.
17
+ - When SimpleCov is enabled in verify, its aggregate summary must come from the current test run.
18
+ - bundler-audit treats abnormal process exits and status/report conflicts as tool failures.
19
+ - Rails setup can select Minitest or RSpec, a helper, and a test command.
20
+ - The optional Herb adapter adds ERB checks without changing fast-gate defaults.
21
+ - Ruby and Rails setup can opt in to a full-history GitHub Actions workflow with separate gate steps.
22
+
1
23
  ## [0.2.2] - 2026-09-28
2
24
 
3
25
  - Fiddle is now a runtime dependency, so the installer loads it with a plain `require` on Ruby 4.x under Bundler. This removes the runtime `Kernel#require` patch and the hand-built extension path that missed on hosts where RbConfig and RubyGems spell the platform differently (for example `arm64-darwin25` vs `arm64-darwin-25`).
data/README.md CHANGED
@@ -2,7 +2,13 @@
2
2
 
3
3
  QualityGate gives Ruby projects one workflow for checking changes: quick feedback while editing, verification before finishing, and a separate security audit. Set up a plain Ruby project with `quality_gate init`, or a Rails application with the Rails generator.
4
4
 
5
- The `fast` gate runs RuboCop. `verify` runs Reek, the test suite, and Undercover in order. For `audit`, Rails defaults run Brakeman followed by bundler-audit; the Ruby setup uses bundler-audit alone.
5
+ The `fast` gate runs RuboCop, with optional adapters such as Herb. `verify` runs Reek, the test suite, and Undercover in order. For `audit`, Rails defaults run Brakeman followed by bundler-audit; the Ruby setup uses bundler-audit alone.
6
+
7
+ Database consistency checks are not enabled by generated configuration. They are an optional addition to `audit`; generated hooks use other gates, while a CI workflow that invokes `audit` will run this adapter after it is explicitly configured and the application provides its boot and database prerequisites.
8
+
9
+ This source prepares the unpublished 0.3.0 release candidate. It includes Doctor preflight checks, optional RubyCritic and Debride deep analysis, warning-baseline ratchets, Codex patch feedback and Stop verification hooks, stricter analyzer tool-error reporting, and an optional database consistency audit adapter. The latest RubyGems release is 0.2.2; the latest GitHub release is v0.2.3.
10
+
11
+ The optional `deep` gate is introduced in 0.3.0. Its default adapter is RubyCritic; Debride can be enabled explicitly for project-wide potentially unused method candidates. The gate runs only when requested, and `--files` does not narrow either analyzer.
6
12
 
7
13
  ## Quick start
8
14
 
@@ -17,7 +23,9 @@ bundle exec quality_gate verify
17
23
 
18
24
  For Rails, replace the init command with `bin/rails generate quality_gate:install`.
19
25
 
20
- Review the installer summary: existing configuration is preserved, and conflicts require manual integration. Agent hooks are optional; add `--agents` to the setup command to install them. Use `--pretend` to preview filesystem changes. See [Ruby setup](#plain-ruby-and-other-test-runners) for test-runner selection and command overrides.
26
+ Review the installer summary: existing configuration is preserved, and conflicts require manual integration. Claude hooks are optional; add `--agents` to install them. Add `--codex` to install Codex patch feedback, native Stop verification, and the owned `AGENTS.md` contract. Codex activation requires a trusted project and review of both hook commands in `/hooks`; see the [Codex integration guide](docs/codex.md). Use `--pretend` to preview filesystem changes. See [Ruby setup](#plain-ruby-and-other-test-runners) for test-runner selection and command overrides.
27
+
28
+ Claude Code's fast hook responds to native `Edit` and `Write` calls; Codex's equivalent patch feedback responds to native `apply_patch` calls.
21
29
 
22
30
  The same commands work from your terminal and CI. QualityGate runs existing tools, collects their findings, and distinguishes code findings from tools that could not complete. A clean result only describes the configured checks and their scope.
23
31
 
@@ -39,6 +47,96 @@ bundle exec quality_gate verify
39
47
  bundle exec quality_gate audit
40
48
  ```
41
49
 
50
+ ### Database consistency (optional audit adapter)
51
+
52
+ QualityGate does not install the analyzer. Add it to the host application's development bundle and explicitly append it to the existing audit adapters:
53
+
54
+ ```ruby
55
+ gem 'database_consistency', '~> 3.0.14', group: :development, require: false
56
+ ```
57
+
58
+ ```yaml
59
+ adapters:
60
+ audit:
61
+ - brakeman
62
+ - bundler_audit
63
+ - database_consistency
64
+ timeouts:
65
+ database_consistency: 120
66
+ ```
67
+
68
+ The adapter scans the project as a whole; `--files` validates input paths but does not narrow its checks. The default launcher is the current Ruby interpreter and QualityGate's packaged bridge. An optional `commands.audit.database_consistency` array replaces the Ruby launcher prefix, with the bridge path appended. The bridge loads the current Bundler context, `config/boot.rb`, and `config/environment.rb`, then eager-loads the Rails application. Run `quality_gate audit` manually from the application root after installing the bundle. Doctor can inspect the configured launcher without booting Rails and does not establish that the analyzer or database is available.
69
+
70
+ The bridge uses the analyzer's internal configuration and processor APIs from version 3.0.14 (`~> 3.0.14`, which allows patch releases below 3.1). It requests reports only; it never calls the analyzer's autofix or todo writers. The upstream processor can write a diagnostic file in the project root when it rescues a checker exception; QualityGate detects that condition and reports a tool failure instead of presenting a clean result. Application boot and schema/database access can still have project-specific effects.
71
+
72
+ Findings use the regular text, JSON, and Markdown reports, with fail reports mapped to errors and warnings mapped to warnings. A completed clean scan exits `0`, findings exit `1`, and boot, dependency, malformed-output, and execution failures exit `2`.
73
+
74
+ ### Deep analysis (introduced in 0.3.0)
75
+
76
+ The `deep` gate is invoked explicitly and supports the usual output formats:
77
+
78
+ ```sh
79
+ bundle exec quality_gate deep --format text
80
+ bundle exec quality_gate deep --format json
81
+ bundle exec quality_gate deep --format markdown
82
+ ```
83
+
84
+ RubyCritic is optional and is not installed by QualityGate. Add it to the host project's Gemfile (for example, `gem "rubycritic", "~> 5", require: false`) and run `bundle install` before invoking the gate. The default is `deep: [rubycritic]`; `commands.deep.rubycritic` overrides the launcher argv prefix, with the adapter supplying RubyCritic's analysis flags and managing its output directory. Its timeout can be set with `timeouts.rubycritic` (otherwise the existing 120-second default applies).
85
+
86
+ ```yaml
87
+ adapters:
88
+ deep:
89
+ - rubycritic
90
+ commands:
91
+ deep:
92
+ rubycritic:
93
+ - bundle
94
+ - exec
95
+ - rubycritic
96
+ timeouts:
97
+ rubycritic: 120
98
+ ```
99
+
100
+ RubyCritic analyzes the project as a whole; `--files` does not narrow this gate. Its findings complement tests and security checks and may overlap Reek. QualityGate does not add a score budget or minimum; RubyCritic owns its score. A completed analysis with no smells exits `0`, reported smells exit `1`, and missing input, configuration, or tool failures exit `2`. A report containing no analyzed Ruby modules is a tool failure, not a clean result. The JSON report is captured through a temporary file that QualityGate removes on success or failure; the adapter does not request HTML output or project-local report artifacts.
101
+
102
+ #### Debride: potentially unused methods
103
+
104
+ Debride is an optional host-project dependency; QualityGate does not install it. Add it to the project's Gemfile and install the bundle before enabling the adapter:
105
+
106
+ ```ruby
107
+ gem "debride", "~> 1.15", require: false
108
+ ```
109
+
110
+ Select Debride alone or alongside RubyCritic in `.quality_gate.yml`:
111
+
112
+ ```yaml
113
+ adapters:
114
+ deep:
115
+ - debride
116
+ timeouts:
117
+ debride: 120
118
+ ```
119
+
120
+ To run both analyzers, add `- rubycritic` before `- debride`. The default remains `deep: [rubycritic]`. The Debride command defaults to the `debride` executable; `commands.deep.debride` overrides its launcher argv prefix, and QualityGate appends `--json` and `.`. For Rails conventions with Bundler, for example:
121
+
122
+ ```yaml
123
+ commands:
124
+ deep:
125
+ debride:
126
+ - bundle
127
+ - exec
128
+ - debride
129
+ - --rails
130
+ ```
131
+
132
+ QualityGate adds `--json` and `.` after this prefix. It does not select framework options automatically. Leave `--verbose` off: Debride stderr diagnostics, including launcher chatter, make the result a tool failure. `timeouts.debride` uses the existing 120-second default when omitted.
133
+
134
+ Debride examines the whole project even when `--files` is supplied. Its candidates can be false positives when code is reached through dynamic dispatch, external APIs, metaprogramming, or Rails callbacks. Treat them as review leads: QualityGate does not delete code or prove that a method is dead. Debride does not report how many Ruby files it analyzed, so an empty report can be clean while providing no guarantee that files were present or fully understood.
135
+
136
+ Debride returns `0` for a clean report or candidates; QualityGate maps these to gate exits `0` and `1`, respectively. Missing tools, timeouts, malformed output, and any stderr diagnostics are tool failures and make the gate exit `2`. This strict check matters because Debride can skip invalid Ruby files, print a warning, and still exit successfully. Keep custom launchers quiet and emit only Debride's JSON on stdout. Like the other adapters, the result uses the standard text, JSON, and Markdown reporters.
137
+
138
+ This gate is a manual command only. It does not add generated hooks or workflow steps.
139
+
42
140
  The built-in fast path is meant for changed files:
43
141
 
44
142
  ```sh
@@ -56,6 +154,18 @@ undercover clean git_diff 619ms
56
154
 
57
155
  (Durations above are illustrative, not measured figures.) These tool lines make a clean run visible: you see every tool that ran, not just an absence of findings.
58
156
 
157
+ Run a read-only setup preflight with `bundle exec quality_gate doctor`. It prints text by default; `--format json` emits a machine-readable report, regardless of the gate format in the project configuration. `--help` works without loading that configuration. Doctor rejects positional arguments, `--files`, Markdown output, and unknown options.
158
+
159
+ Doctor is introduced in 0.3.0.
160
+
161
+ Doctor checks configuration, runtime and bundle context, whether supported launch paths are available, Undercover's comparison point, required coverage evidence, and recent optional hook history. It does not execute analyzers, test suites, or application boot code; install or repair anything; fetch from Git; or establish that the application is clean or works. A ready launcher check means only that the inspected executable or explicit script was found. Custom wrappers and nested bare commands that cannot be resolved safely remain `unchecked`.
162
+
163
+ The report has scope `preflight`, checks with `id`, `status`, and `message`, and summary counts for every status. Each message describes what was observed and gives a next step when needed. Statuses are `ready`, `warning`, `blocked`, `unchecked`, and `not_applicable`. Exit `0` means applicable preflight checks are ready; `1` means a warning or unchecked observation remains; `2` means a blocker, invalid input, or report failure. `not_applicable` is neutral. These results describe preflight observations, not gate findings or proof of application health.
164
+
165
+ Coverage artifacts are inspected only when an enabled adapter needs them. Before the first suite run, missing coverage is `unchecked`; run `bundle exec quality_gate verify` to create the evidence. Doctor reads at most 1 MiB from each artifact and does not check freshness, coverage wiring, or budget compliance. Hook history is advisory: absent optional hooks are `not_applicable`; installed hooks without valid history are `unchecked`; and valid history does not verify that hooks are currently installed. The Git comparison probe has a shared five-second budget and never fetches history.
166
+
167
+ If Bundler prevents the `quality_gate` command from starting, Doctor cannot run. Check Ruby and Bundler outside QualityGate with `ruby -v`, `command -v ruby`, `bundle --version`, and `bundle check`; these are manual troubleshooting commands, not Doctor checks.
168
+
59
169
  Use `--files` to select paths for RuboCop and Reek; the first path follows the option and further paths follow it as separate arguments:
60
170
 
61
171
  ```sh
@@ -74,6 +184,7 @@ rubocop clean project 842ms
74
184
  | Adapter | Scope with `--files` |
75
185
  | --- | --- |
76
186
  | RuboCop, Reek | Selected files/directories, subject to the tool's exclusions |
187
+ | Herb | Project scan, or selected ERB files/directories; unrelated files are omitted |
77
188
  | Test suite | Full configured suite |
78
189
  | Undercover | Git changes against the comparison point |
79
190
  | SimpleCov | Aggregate coverage summary |
@@ -93,10 +204,43 @@ The shorter form `quality_gate version` works when the installed executable is a
93
204
 
94
205
  The repository config must also use exactly `text`, `json`, or `markdown` for `format`; any other configured value is rejected as a configuration error before a gate runs.
95
206
 
207
+ ## Warning baselines
208
+
209
+ Fast and verify can compare their current results with an explicitly created warning baseline. The feature is disabled by default. Create a snapshot, then compare it on later runs:
210
+
211
+ ```sh
212
+ bundle exec quality_gate fast --create-baseline config/fast-baseline.json
213
+ bundle exec quality_gate fast --baseline config/fast-baseline.json
214
+ # After resolving findings, shrink the accepted set.
215
+ bundle exec quality_gate fast --ratchet-baseline config/fast-baseline.json
216
+ ```
217
+
218
+ `--baseline PATH` accepts existing entries while reporting new or protected findings normally. `--create-baseline PATH` writes only when every finding is eligible for the snapshot. `--ratchet-baseline PATH` compares first and shrinks the snapshot only when the run has no new or protected findings; a blocked ratchet keeps the original bytes and exits with the ordinary findings or tool-failure status. All three options work only with `fast` and `verify`, are mutually exclusive, and use the command's `--format` reporter. Creation and ratcheting require a full scan: they reject `--files` and non-empty configured `files` before running tools. Comparison can use `--files` and never writes the snapshot.
219
+
220
+ Baselines store only warning and info findings from RuboCop, Reek, and Herb. Errors, tool failures, test and security results, coverage results, and other analyzers remain enforced. Matching uses tool, normalized project-relative file, rule, severity, and message plus a bounded duplicate count; line numbers do not participate, so moving a finding within its file does not make it new. Identical findings in one file are interchangeable up to their stored count, and the snapshot does not prove semantic identity or source provenance. Review analyzer configuration whenever using ratchet, and review manual baseline JSON edits in Git.
221
+
222
+ Analyzer process status also remains part of the result contract: RuboCop accepts exits `0` and `1`, while Reek accepts `0` and `2`. Other statuses and process signals fail the tool. Reek's explicit “cannot be processed” source diagnostic also fails the tool even if its JSON is empty and the process exits successfully.
223
+
224
+ The versioned JSON snapshot records its gate, configured adapter order, and finding entries. It must match the gate and current adapter list exactly. The parent directory must already exist. A successful create or ratchet writes before report output; an output-stream failure does not undo that completed file write. This is a reviewed warning policy for QualityGate results, not a replacement for RuboCop's `.rubocop_todo.yml` mechanism.
225
+
226
+ Snapshots contain analyzer messages and project-relative paths, so treat them as belonging to the host project. Keep baseline files in the project that owns the findings; do not ship them with QualityGate.
227
+
228
+ To enable comparison from `.quality_gate.yml`, add a gate-to-path mapping. It remains disabled for gates not listed:
229
+
230
+ ```yaml
231
+ baseline:
232
+ fast: config/fast-baseline.json
233
+ verify: config/verify-baseline.json
234
+ ```
235
+
236
+ An explicit `--baseline PATH` takes precedence for that invocation. `quality_gate <gate> --help` documents the command-line options without loading configuration.
237
+
96
238
  ## Output contract
97
239
 
98
240
  Gate text output prints, in order: one line per tool that ran, then findings, then the tally.
99
241
 
242
+ When a baseline is active, checks keep each adapter's raw status while the finding list and JSON summary describe enforced findings after comparison. The JSON `baseline` object reports the mode, accepted finding records, counts, and whether a create or ratchet write completed. Without a baseline, JSON retains the existing `checks`, `findings`, and `summary` shape.
243
+
100
244
  When at least one tool ran, each gets a line naming the tool, its status, what it inspected, and how long it took:
101
245
 
102
246
  ```text
@@ -221,6 +365,7 @@ timeouts:
221
365
  undercover: 120
222
366
  compare_point:
223
367
  rubocop_config:
368
+ # baseline: {}
224
369
  ```
225
370
 
226
371
  Default adapters when no project configuration overrides them (the Rails setup uses these; Ruby init writes its own test command and omits Brakeman):
@@ -228,6 +373,7 @@ Default adapters when no project configuration overrides them (the Rails setup u
228
373
  - `fast` => `rubocop`
229
374
  - `verify` => `reek`, then `test_suite`, then `undercover`
230
375
  - `audit` => `brakeman`, then `bundler_audit`
376
+ - `deep` => `rubycritic` (introduced in 0.3.0; manual invocation only)
231
377
 
232
378
  Default timeouts:
233
379
 
@@ -236,7 +382,7 @@ Default timeouts:
236
382
  - `test_suite` => `120`
237
383
  - `undercover` => `120`
238
384
 
239
- `adapters` lists adapter names per gate. The built-in registry knows `rubocop`, `reek`, `test_suite`, `undercover`, `simplecov`, `brakeman`, and `bundler_audit`. SimpleCov is registry-known but not a default adapter: the default verify adapters are Reek, the test suite, and Undercover, in that order. Unknown adapter names still become reported tool failures instead of being ignored.
385
+ `adapters` lists adapter names per gate. The built-in registry knows `rubocop`, `reek`, `test_suite`, `undercover`, `simplecov`, `brakeman`, `bundler_audit`, `database_consistency`, `herb`, `rubycritic`, and `debride`. SimpleCov, Herb, Debride, and database_consistency are registry-known optional adapters, not defaults. RubyCritic is the `deep` default; Debride can be selected alongside it or by itself. The default verify adapters are Reek, the test suite, and Undercover, in that order. Unknown adapter names still become reported tool failures instead of being ignored.
240
386
 
241
387
  ### Aggregate coverage budgets
242
388
 
@@ -255,9 +401,9 @@ coverage:
255
401
 
256
402
  `coverage.minimum_line` and `coverage.minimum_branch` are independent numeric percentage budgets in the inclusive range `0..100`. At least one is required when the `simplecov` adapter is enabled, and equality with the configured minimum passes. A valid `coverage` mapping alone is inert without `simplecov` in `adapters.verify`.
257
403
 
258
- After the test suite runs, the adapter reads SimpleCov's `coverage/.last_run.json` summary without rerunning tests. A missing or unusable record is a tool failure. A branch budget without usable branch data is also a tool failure and names `enable_coverage :branch` as the required SimpleCov setup. Coverage below a configured budget produces a stable error finding: `line_coverage_below_minimum` for the line budget and `branch_coverage_below_minimum` for the branch budget.
404
+ After the test suite runs, the adapter reads SimpleCov's `coverage/.last_run.json` summary without rerunning tests. When SimpleCov is configured in `verify`, QualityGate removes only that aggregate summary before the test command. A command that produces no fresh summary cannot pass using stale coverage. A missing or unusable record is a tool failure. A branch budget without usable branch data is also a tool failure and names `enable_coverage :branch` as the required SimpleCov setup. Coverage below a configured budget produces a stable error finding: `line_coverage_below_minimum` for the line budget and `branch_coverage_below_minimum` for the branch budget.
259
405
 
260
- `timeouts` sets the default adapter timeout in seconds and allows per-tool entries. The shipped RuboCop timeout is 10 seconds, while the test suite and Undercover each have an explicit 120-second timeout. Brakeman and bundler-audit inherit the 120-second default.
406
+ `timeouts` sets the default adapter timeout in seconds and allows per-tool entries. The shipped RuboCop timeout is 10 seconds, while the test suite and Undercover each have an explicit 120-second timeout. Brakeman and bundler-audit inherit the 120-second default; database_consistency also inherits it unless configured separately.
261
407
 
262
408
  ### Projects with longer test suites
263
409
 
@@ -298,9 +444,9 @@ can write a log record. Check `log/quality_gate_hooks.jsonl` and run
298
444
 
299
445
  ### Configuration validation
300
446
 
301
- `adapters` must be a mapping whose only permitted keys are `fast`, `verify`, and `audit`, and each layer value must be an array of non-empty strings. The mapping may specify any subset of those gates; unspecified gates keep the shipped defaults. A misspelled layer key such as `fasst` is rejected as a configuration error instead of silently falling back to a clean run.
447
+ `adapters` must be a mapping whose only permitted keys are `fast`, `verify`, `audit`, and `deep`, and each layer value must be an array of non-empty strings. The mapping may specify any subset of those gates; unspecified gates keep the shipped defaults. A misspelled layer key such as `fasst` is rejected as a configuration error instead of silently falling back to a clean run.
302
448
 
303
- `commands` follows the same three gate layers. Every command is an argv array of non-empty strings, never a shell command string. `commands.verify.test_suite` defaults to `["bin/rails", "test"]`.
449
+ `commands` follows the same four gate layers. Every command is an argv array of non-empty strings, never a shell command string. `commands.verify.test_suite` defaults to `["bin/rails", "test"]`; deep analyzer commands default to their executable names.
304
450
 
305
451
  `compare_point` may be `nil` or a non-empty String. Set it to a Git ref or commit when CI has too little history to find a common ancestor automatically.
306
452
 
@@ -400,13 +546,13 @@ Each uncovered region is a warning that names its file, first line, full line ra
400
546
 
401
547
  The security adapters deliberately ignore `--files`. Brakeman scans the whole application because its data-flow analysis crosses file boundaries. bundler-audit always checks `Gemfile.lock`, and dependency advisories use that file with line `0` rather than inventing a source location.
402
548
 
403
- bundler-audit tries to update its advisory database first. If that update fails and a real, usable local database exists, QualityGate scans the cached database and writes exactly one fallback warning to standard error. If no usable advisory database exists, bundler-audit returns a tool failure and exit code `2`; an unchecked dependency audit is never reported as clean.
549
+ bundler-audit tries to update its advisory database first. A clean report must exit `0`; vulnerability findings must exit `1`. Abnormal exits or conflicting statuses and reports become tool failures. If the update fails and a real, usable local database exists, QualityGate scans the cached database and writes exactly one fallback warning to standard error. If no usable advisory database exists, bundler-audit returns a tool failure and exit code `2`; an unchecked dependency audit is never reported as clean.
404
550
 
405
551
  ### Coverage template
406
552
 
407
- QualityGate packages coverage templates for Rails/Minitest and plain Ruby. Both setup paths render coverage into a marked block after the Ruby source prologue and before host application code is required.
553
+ QualityGate packages coverage templates for Rails Minitest, Rails RSpec, and plain Ruby. Both setup paths render coverage into a marked block after the Ruby source prologue and before host application code is required.
408
554
 
409
- The host-facing coverage templates are Undercover-only. They activate only when `ENV["COVERAGE"] == "1"`, load SimpleCov and the Undercover formatter, start branch coverage, and write `coverage/coverage.json`. The Rails template filters `test`; the Ruby template filters both `test` and `spec`. HTML output is only part of this gem's self-dogfood setup and is not configured for generated hosts.
555
+ The host-facing coverage templates are Undercover-only. They activate only when `ENV["COVERAGE"] == "1"`, load SimpleCov and the Undercover formatter, start branch coverage, and write `coverage/coverage.json`. Generated Rails and Ruby templates filter both `test` and `spec`. HTML output is only part of this gem's self-dogfood setup and is not configured for generated hosts.
410
556
 
411
557
  ## Exit codes
412
558
 
@@ -484,17 +630,48 @@ bundle exec quality_gate init --help
484
630
 
485
631
  Setup reports written, unchanged, skipped, and conflicting files. It never replaces custom configuration automatically; merge the displayed template where needed. Repeating setup with unchanged inputs is idempotent. Init uses a text summary; `--format json` applies to gate commands.
486
632
 
487
- Coverage starts only with `COVERAGE=1`, which the test-suite adapter supplies, and filters both `test` and `spec`. Undercover requires a Git comparison point; set `compare_point` in shallow CI checkouts or fetch the base branch/history. Agent hooks and contracts are installed only with `--agents`.
633
+ Coverage starts only with `COVERAGE=1`, which the test-suite adapter supplies, and filters both `test` and `spec`. Undercover requires a Git comparison point; set `compare_point` in shallow CI checkouts or fetch the base branch/history. Claude hooks require `--agents`; the separate native Codex hook requires `--codex`.
488
634
 
489
635
  ## Installation
490
636
 
491
- QualityGate has not been published to RubyGems yet. Until it is released, install it from GitHub with Bundler:
637
+ Install the published gem as a development and test dependency. The executable is
638
+ used through Bundler, so the Gemfile entry does not require the library:
639
+
640
+ ```ruby
641
+ group :development, :test do
642
+ gem "quality_gate", "~> 0.2", require: false
643
+ end
644
+ ```
645
+
646
+ The Rails/RSpec options, `--ci`, and Herb support were introduced in the v0.2.3 GitHub release and are included in this candidate. They are not in the current RubyGems release, 0.2.2.
647
+ The `~> 0.2` version constraint will accept 0.3.x once published.
648
+
649
+ Bundler installs the gem's runtime dependencies automatically. The published
650
+ gemspec currently declares:
651
+
652
+ | Runtime dependency | Version requirement |
653
+ | --- | --- |
654
+ | brakeman | `~> 8.0` |
655
+ | bullet | `~> 8.2.0` |
656
+ | bundler-audit | `~> 0.9.3` |
657
+ | fiddle | `~> 1.1` |
658
+ | reek | `~> 6.5` |
659
+ | rubocop | `~> 1.90` |
660
+ | rubocop-minitest | `~> 0.40` |
661
+ | rubocop-performance | `~> 1.27` |
662
+ | rubocop-rails | `~> 2.37` |
663
+ | simplecov | `~> 1.1.1` |
664
+ | strong_migrations | `~> 2.5.2` |
665
+ | undercover | `~> 0.8.5` |
666
+
667
+ If you need to install directly from the repository instead, Bundler also
668
+ supports this Gemfile entry:
492
669
 
493
670
  ```ruby
494
- gem "quality_gate", github: "lucianghinda/quality_gate"
671
+ gem "quality_gate", github: "lucianghinda/quality_gate", require: false
495
672
  ```
496
673
 
497
- Then install for Ruby or Rails:
674
+ Then install and set up for Ruby or Rails:
498
675
 
499
676
  ```sh
500
677
  bundle install
@@ -505,13 +682,39 @@ bundle exec quality_gate init --profile ruby
505
682
  bin/rails generate quality_gate:install
506
683
  ```
507
684
 
685
+ ### Rails test setup
686
+
687
+ The Rails generator detects one existing test helper. If both helpers exist,
688
+ choose Minitest or RSpec explicitly:
689
+
690
+ ```sh
691
+ bin/rails generate quality_gate:install --test-framework rspec
692
+ ```
693
+
694
+ Rails defaults to `test/test_helper.rb` and `bin/rails test`. RSpec uses
695
+ `spec/rails_helper.rb` and `bundle exec rspec`. A custom helper under `spec/`
696
+ selects RSpec; other custom helpers select Minitest unless specified.
697
+
698
+ Pass a project-relative helper and command when needed:
699
+
700
+ ```sh
701
+ bin/rails generate quality_gate:install --test-helper spec/rails_helper.rb --test-command 'bundle exec rspec'
702
+ ```
703
+
704
+ An explicit custom helper must exist when coverage wiring is enabled. Use
705
+ `--skip-coverage` to omit coverage wiring. With no detected helper, Rails keeps
706
+ Minitest, warns, and installs the remaining artifacts.
707
+
708
+ The generated `.quality_gate.yml` activates the selected test command as an
709
+ argv array. The generator renders each argument as a safe YAML scalar.
710
+
508
711
  The Rails generator manages these host artifacts:
509
712
 
510
713
  - `.quality_gate.yml`
511
714
  - `.rubocop.yml`
512
715
  - `config/initializers/bullet.rb`
513
716
  - `config/initializers/strong_migrations.rb`
514
- - a marked coverage block in `test/test_helper.rb`, before executable host code
717
+ - a marked coverage block in the selected helper, before executable host code
515
718
 
516
719
  With `--agents`, it additionally manages:
517
720
 
@@ -521,11 +724,20 @@ With `--agents`, it additionally manages:
521
724
  - one marker-owned Quality Gate contract section in `CLAUDE.md`
522
725
  - one marker-owned Quality Gate contract section in `AGENTS.md`
523
726
 
524
- Installation is idempotent. A missing file is written, while a byte-identical file is left untouched. For wholly owned files such as `.quality_gate.yml`, `.rubocop.yml`, both files under `.claude/hooks/`, and `.claude/settings.json`, if an existing file has different content the generator never overwrites or merges it unless it is the exact known settings snapshot described next: otherwise, the installer prints the current template for manual use, marks the conflict as needing a person, and continues with the remaining artifacts. The sole upgrade exception is `.claude/settings.json` whose bytes exactly match the previously shipped PostToolUse-only template; rerunning the installer safely replaces that known snapshot with the current PostToolUse-and-Stop template. Any customized settings file remains a manual conflict and is not overwritten.
727
+ With `--codex`, it additionally manages `.codex/hooks.json`, executable
728
+ `.codex/hooks/quality_gate_fast.rb` and `.codex/hooks/quality_gate_verify_stop.rb`
729
+ scripts, and one marker-owned contract section in `AGENTS.md`. Codex activation
730
+ requires a trusted project and explicit review of both hook commands in `/hooks`;
731
+ the installer does not change trust. A custom Codex hook configuration is left
732
+ untouched for manual integration. See the
733
+ [Codex integration guide](docs/codex.md) for runtime limits, project discovery,
734
+ conflict handling, and removal.
735
+
736
+ Installation is idempotent. A missing file is written, while a byte-identical file is left untouched. For wholly owned files such as `.quality_gate.yml`, `.rubocop.yml`, hook scripts, and hook configuration, if an existing file has different content the generator never overwrites or merges it except when it exactly matches one narrowly defined prior snapshot. `.claude/settings.json` must match the previously shipped PostToolUse-only template; `.codex/hooks.json` must match the previously shipped Stop-only template generated for this same project root. The installer safely replaces those snapshots with current configuration while preserving file mode. Customized configuration, a Codex snapshot generated for another project root, and symlinks remain manual conflicts; other conflicts print the current template for manual use.
525
737
 
526
738
  The generated Strong Migrations initializer begins with the exact provenance line `# Generated by Quality Gate.`. On its first install, QualityGate records the newest existing migration as the baseline, or records that no migration exists yet. On later runs, that provenance makes the recorded baseline take precedence, so newer migrations leave the generated initializer unchanged. An unmarked initializer is always developer-owned and therefore follows the conflict/manual policy; when it already contains `StrongMigrations.start_after`, the printed marked template preserves that established baseline instead of advancing it.
527
739
 
528
- Use `--skip-initializers` when the host does not use Bullet or Strong Migrations. Use `--skip-coverage` to leave the Minitest helper alone. Use `--pretend` to preview the run without changing the filesystem; pending writes are reported as skipped.
740
+ Use `--skip-initializers` when the host does not use Bullet or Strong Migrations. Use `--skip-coverage` to leave the selected test helper alone. Use `--pretend` to preview the run without changing the filesystem; pending writes are reported as skipped.
529
741
 
530
742
  ```sh
531
743
  bin/rails generate quality_gate:install --skip-initializers
@@ -533,7 +745,66 @@ bin/rails generate quality_gate:install --skip-coverage
533
745
  bin/rails generate quality_gate:install --pretend
534
746
  ```
535
747
 
536
- For coverage, the generator preserves a UTF-8 BOM and shebang, then leading blank lines, ordinary comments, all Ruby and Emacs directives, and complete `=begin`/`=end` comment blocks before the marked block. It inserts coverage immediately before the first executable host code. Inserted lines use the helper's existing LF or CRLF convention.
748
+ For coverage, the generator preserves a UTF-8 BOM and shebang, then leading blank lines, ordinary comments, all Ruby and Emacs directives, and complete `=begin`/`=end` comment blocks before the marked block. It inserts coverage immediately before the first executable host code. Inserted lines use the helper's existing LF or CRLF convention. Generated Rails and Ruby coverage blocks exclude both `test` and `spec`.
749
+
750
+ ### Optional GitHub Actions workflow
751
+
752
+ Pass `--ci` to either setup command to create
753
+ `.github/workflows/quality_gate.yml`:
754
+
755
+ ```sh
756
+ bundle exec quality_gate init --ci
757
+ ```
758
+
759
+ ```sh
760
+ bin/rails generate quality_gate:install --ci
761
+ ```
762
+
763
+ The workflow is opt-in. `--pretend` previews it without writing files. An
764
+ existing customized `.github/workflows/quality_gate.yml` is preserved and
765
+ reported for manual integration. Later setup without `--ci` leaves an installed
766
+ workflow alone.
767
+
768
+ The generated workflow runs on pushes and pull requests. It grants `contents: read`
769
+ and uses `actions/checkout@v7` with `fetch-depth: 0` and
770
+ `persist-credentials: false`. It uses `ruby/setup-ruby@v1` with Bundler caching.
771
+ Its Ruby selector uses the installing runtime's exact `RUBY_VERSION`. Separate
772
+ direct `fast`, `verify`, and `audit` steps enforce each gate's exit status.
773
+
774
+ Customize the workflow for your supported Ruby matrix, services, and environment.
775
+ The generator cannot infer application database services or secrets.
776
+
777
+ ### Optional Herb checks
778
+
779
+ Herb adds ERB linting to the fast gate without changing its defaults. Install the
780
+ official CLI separately, then configure its local executable when needed:
781
+
782
+ ```sh
783
+ npm install --save-dev @herb-tools/linter@0.11.0
784
+ ```
785
+
786
+ ```yaml
787
+ adapters:
788
+ fast:
789
+ - rubocop
790
+ - herb
791
+ commands:
792
+ fast:
793
+ herb:
794
+ - node_modules/.bin/herb-lint
795
+ ```
796
+
797
+ Generated CI installs Ruby and Bundler dependencies only. If Herb is enabled,
798
+ customize the workflow to set up Node and install locked npm dependencies before
799
+ the fast step.
800
+
801
+ QualityGate appends JSON output flags and eligible selected paths to the command.
802
+ The default launcher is `herb-lint`. Bundler does not add npm's local binaries
803
+ to `PATH`. With no selected paths, Herb scans the project. With
804
+ selected paths, it receives ERB files and directories; unrelated files are
805
+ omitted. Herb applies its own `.herb.yml` exclusions. The generated fast hook
806
+ keeps Ruby checks unchanged. It checks ERB only when Herb is enabled. Hook
807
+ feedback may fail open; CI enforces direct gate exit codes.
537
808
 
538
809
  ### Claude Code agent hooks
539
810
 
@@ -543,13 +814,13 @@ Plain Ruby projects use `bundle exec quality_gate init --profile ruby --agents`
543
814
 
544
815
  For agent integration, run `bin/rails generate quality_gate:install --agents`. The generator writes `.claude/hooks/quality_gate_fast.rb` and `.claude/hooks/quality_gate_verify_stop.rb`, installs the exact Claude Code `PostToolUse` and `Stop` entries in `.claude/settings.json`, and manages one marker-owned Quality Gate contract block inside `CLAUDE.md` and `AGENTS.md`. The Stop command has a 300-second Claude Code timeout. The marker-owned contract sections are narrower than the wholly owned files: a single stale Quality Gate block is replaced in place, the surrounding bytes are preserved, and any unmatched or multiple marker cases fall back to manual installation. If a hook file is byte-identical but has lost its executable mode, reinstalling repairs the mode without rewriting the file. After `bundle install` or a gem upgrade, rerun `bin/rails generate quality_gate:install --agents` to reinstall the generated hooks and contract files.
545
816
 
546
- The `PostToolUse` hook runs file-scoped `quality_gate fast` after Ruby edits. Findings exit 2 and return the gate's JSON report to Claude as feedback. If an attempted fast run is unavailable, the first attempt in that unavailable streak exits 2 with one stderr line naming `bundle exec quality_gate fast` and `log/quality_gate_hooks.jsonl`; the already-applied edit stands and is not rolled back. Repeated unavailable attempts exit 0 silently. Non-Ruby paths and deleted files remain cheap skips.
817
+ The `PostToolUse` hook runs file-scoped `quality_gate fast` after Ruby edits. It also checks ERB edits when Herb is configured in the fast gate. Findings exit 2 and return the gate's JSON report to Claude as feedback. If an attempted fast run is unavailable, the first attempt in that unavailable streak exits 2 with one stderr line naming `bundle exec quality_gate fast` and `log/quality_gate_hooks.jsonl`; the already-applied edit stands and is not rolled back. Repeated unavailable attempts exit 0 silently. Other non-Ruby paths and deleted files remain cheap skips.
547
818
 
548
819
  The `Stop` hook checks for Ruby working-tree edits and automatically runs `quality_gate verify` before Claude finishes. With no Ruby edits it skips without starting the verifier. A clean result from the same `session_id` is debounced when no Ruby edit was logged at or after that result. Findings exit 2 with the machine-readable JSON report only after the matching `verify_blocked` record is safely appended, so Claude receives the feedback and continues working. If prior hook history cannot be read safely or that record cannot be written, the hook suppresses the feedback and fails open so the retry cap cannot deadlock. Invalid verifier output, a tool failure, a verifier timeout, or a command exception also fails open as unavailable. After three consecutive blocked finish attempts in one session, the next attempt is capped and exits 0.
549
820
 
550
821
  Hook activity is appended to `log/quality_gate_hooks.jsonl`. Stop records include `session_id` and use the outcomes `verify_skipped`, `verify_debounced`, `verify_clean`, `verify_blocked`, `verify_unavailable`, and `verify_cap`. The CLI warns on stderr when the last 20 valid records include either fast-hook `unavailable` or Stop-hook `verify_unavailable` outcomes. The warning does not change the gate's JSON output or exit code.
551
822
 
552
- Codex does not consume the Claude Code hook automatically. Use the manual Codex workflow in `docs/codex.md` to run the same `fast`, `verify`, and `audit` commands yourself.
823
+ Codex uses its native patch and Stop hooks only when you install them with `--codex`, start Codex in the installed project or one of its descendants, and explicitly review and trust both commands. Patch feedback runs only after native `apply_patch` calls; shell writes still reach final Stop verification. It is advisory and does not roll back edits. The 30-second native patch-hook timeout can be exceeded by a project fast budget longer than the shipped 10-second RuboCop timeout, in which case run fast manually. The full activation and removal instructions are in `docs/codex.md`.
553
824
 
554
825
  For the Rails generator, when `test/test_helper.rb` is missing, it warns that Minitest coverage wiring was skipped, installs the other files, and exits successfully. Plain Ruby init instead requires an existing helper or `--skip-coverage`. Every successful install or preview run ends by naming the next command:
555
826
 
@@ -559,7 +830,7 @@ bundle exec quality_gate fast
559
830
 
560
831
  `bin/rails destroy quality_gate:install` is intentionally read-only. Automatic removal is not supported because coverage is embedded in a developer-owned helper and the agent contract files may contain developer-owned text around the managed markers; the command changes nothing and directs you to the manual removal steps below instead of printing an install summary or next command.
561
832
 
562
- To undo a clean installation, delete the files that the generator wrote (`.quality_gate.yml`, `.rubocop.yml`, `config/initializers/bullet.rb`, `config/initializers/strong_migrations.rb`, `.claude/hooks/quality_gate_fast.rb`, `.claude/hooks/quality_gate_verify_stop.rb`, and `.claude/settings.json`). Then remove the complete block in `test/test_helper.rb` from `# quality_gate coverage — start` through `# quality_gate coverage — end`, including both marker lines, and remove the complete Quality Gate block from `CLAUDE.md` and `AGENTS.md` from `<!-- quality_gate agent contract — start -->` through `<!-- quality_gate agent contract — end -->`. Do not delete a file that predated the generator or contains developer changes outside the managed markers.
833
+ To undo a clean installation, delete the files that the generator wrote (`.quality_gate.yml`, `.rubocop.yml`, `config/initializers/bullet.rb`, `config/initializers/strong_migrations.rb`, the installed Claude and Codex hook scripts, `.claude/settings.json`, and `.codex/hooks.json` only when it contains solely generated Quality Gate configuration). Then remove the complete block in `test/test_helper.rb` from `# quality_gate coverage — start` through `# quality_gate coverage — end`, including both marker lines, and remove the complete Quality Gate block from `CLAUDE.md` and `AGENTS.md` from `<!-- quality_gate agent contract — start -->` through `<!-- quality_gate agent contract — end -->`. Do not delete a file that predated the generator or contains developer changes outside the managed markers.
563
834
 
564
835
  ## Acceptance evidence
565
836
 
data/docs/codex.md CHANGED
@@ -1,14 +1,42 @@
1
- # Codex and QualityGate
1
+ # Codex and Quality Gate
2
2
 
3
- Codex does not consume Claude Code `PostToolUse` or `Stop` hooks. The optional `.claude/settings.json`, `.claude/hooks/quality_gate_fast.rb`, and `.claude/hooks/quality_gate_verify_stop.rb` files are for Claude Code sessions and are installed only with `--agents`. In Codex, run the same gates manually or have the agent invoke them explicitly:
3
+ Quality Gate offers two optional native Codex hooks. The `PostToolUse` hook gives file-scoped fast feedback after patches; the `Stop` hook runs the full verification gate. Install both explicitly in a plain Ruby project:
4
+
5
+ ```sh
6
+ bundle exec quality_gate init --codex
7
+ ```
8
+
9
+ Claude Code's existing fast feedback is triggered by native `Edit` and `Write` calls. Codex uses its native `apply_patch` tool event for the equivalent patch feedback; the hook matcher does not include shell writes or other tools.
10
+
11
+ For Rails:
12
+
13
+ ```sh
14
+ bin/rails generate quality_gate:install --codex
15
+ ```
16
+
17
+ `--codex` installs `.codex/hooks.json`, executable `.codex/hooks/quality_gate_fast.rb` and `.codex/hooks/quality_gate_verify_stop.rb` scripts, and the Quality Gate section in `AGENTS.md`. It does not install Claude Code files. Use `--agents --codex` to install both clients; the shared `AGENTS.md` section is still installed once. `--pretend` previews filesystem changes. Reinstalling repairs either script's executable mode and leaves matching files unchanged.
18
+
19
+ The patch hook runs `quality_gate fast` after completed native `apply_patch` calls only. It selects changed Ruby files and, when Herb is configured in the fast gate, ERB files. A mixed patch gets one file-scoped run. Other tools, including shell writes, do not trigger this feedback hook; those changes are still checked by the final Stop hook. The patch has already been applied before this hook runs, so findings are advisory context for Codex and never roll the edit back.
20
+
21
+ A clean run returns no extra context. Findings provide Codex with file and rule details to guide a repair. When input, configuration, or a tool is unavailable, the hook reports that fact to Codex and asks it to tell you and run `bundle exec quality_gate fast` manually. A missing fast check never claims the files are clean. Run the manual gate and use CI exit status as enforcement evidence.
22
+
23
+ Codex gives the patch hook a 30-second native timeout. The shipped RuboCop fast timeout is 10 seconds, but a longer project-specific fast budget or slow analyzer can exceed Codex's hook timeout. In that case, use the manual fast command. The full Stop hook remains synchronous on every Stop and uses its existing 600-second hook timeout. It runs the full `verify` gate, can add substantial latency, and asks for one repair continuation when it finds issues. Codex verifies again on the resumed Stop; if findings remain, it reports the cap and allows the turn to finish. Runtime, input, and tool failures report unavailable and also allow the turn to finish. Hooks provide feedback; an agent session ending is not proof that checks passed.
24
+
25
+ This integration requires a Codex CLI version with native hooks; it was verified with CLI 0.160.0. Check the [official Codex hooks documentation](https://developers.openai.com/codex/hooks) for current requirements and behavior. [Project configuration layers](https://developers.openai.com/codex/config-basic) load from the project root down to the session working directory, so start Codex in the installed project or one of its descendants for its `.codex` configuration to apply. In a monorepo, a session started at the repository root does not load a nested subproject's hook configuration.
26
+
27
+ Codex project hooks require a trusted project and explicit hook review. In Codex, open `/hooks`, inspect both scripts and both generated command definitions in `.codex/hooks.json`, then decide whether to trust them. Review both commands again after hook configuration changes or a Quality Gate upgrade. Quality Gate never writes Codex trust state, user-home files, or `.codex/config.toml`. Doctor can recognize installed files, but cannot establish trust, activation, or execution; Codex supplies no Quality Gate hook-history source, so Doctor leaves execution history unchecked.
28
+
29
+ The generated commands contain absolute paths to the installed Ruby scripts, so they work when Codex starts in a nested working directory. If the project moves, update both command paths and review them in `/hooks` again. Existing customized `.codex/hooks.json` is left unchanged and needs manual integration using the proposal printed by the installer. The only upgrade exception is the exact previously shipped Stop-only JSON generated for this same project root; changed-root snapshots, formatting changes, extra hooks, and customized bytes need manual integration. Symlink destinations are never followed.
30
+
31
+ The launchers use the installed project's `Gemfile`; install the project's bundle with `bundle install` before trusting the hooks. Ruby and Bundler must be available to the Codex process. To remove the integration, remove both Quality Gate hook entries and scripts, and remove `.codex/hooks.json` only when it contains solely generated Quality Gate configuration. Remove only the Codex instructions from `AGENTS.md` when it also contains Claude guidance, or remove the Quality Gate section when Codex is its only client.
32
+
33
+ Run the gates directly as well:
4
34
 
5
35
  - Run `bundle exec quality_gate fast` after Ruby edits.
6
36
  - Run `bundle exec quality_gate verify` before you finish a change.
7
37
  - Run `bundle exec quality_gate audit` before you merge security-sensitive work.
8
38
 
9
- Fix findings before you continue editing. Use `--format json` for structured results, and inspect `checks` alongside findings to see each tool's status and scope. Explicit selected paths must exist; a missing path is an input failure. A clean gate describes only its configured checks, not overall application correctness.
10
-
11
- Automatic Claude hooks can fail open or cap retries. An agent session ending is not proof of verification. CI should run the gate commands directly and enforce their exit status.
39
+ Fix findings before you continue editing. Use `--format json` for structured results and inspect `checks` with findings to see each tool's status and scope. Explicit selected paths must exist; a missing path is an input failure. A clean gate describes only its configured checks, not overall application correctness.
12
40
 
13
41
  Exit meanings stay the same in Codex and Claude Code:
14
42
 
@@ -16,16 +44,16 @@ Exit meanings stay the same in Codex and Claude Code:
16
44
  - Exit 1 means the gate reported findings and no tool failures.
17
45
  - Exit 2 means the gate could not complete cleanly because of invalid input, configuration, or another tool failure.
18
46
 
19
- If the automatic Claude Code hook becomes unavailable, inspect `log/quality_gate_hooks.jsonl`, run `bundle install`, and reinstall the generated integration with the setup command for your project.
47
+ If the automatic Claude Code hook becomes unavailable, inspect `log/quality_gate_hooks.jsonl`, run `bundle install`, and reinstall the generated integration with the setup command for your project. Codex does not provide this Claude hook history log.
20
48
 
21
- For a plain Ruby project, install or refresh the generated contract files with:
49
+ For a plain Ruby project, install or refresh both Claude Code and Codex integration with:
22
50
 
23
51
  ```sh
24
- bundle exec quality_gate init --profile ruby --agents
52
+ bundle exec quality_gate init --profile ruby --agents --codex
25
53
  ```
26
54
 
27
55
  For Rails:
28
56
 
29
57
  ```sh
30
- bin/rails generate quality_gate:install --agents
58
+ bin/rails generate quality_gate:install --agents --codex
31
59
  ```