Files
ECC/commands/quality-gate.md
JongHyeok ParkandGitHub 0071fa5c3c refactor(hooks): consolidate PostToolUse hooks into sync/async dispatchers (#2494)
* refactor(hooks): consolidate PostToolUse hooks into sync/async dispatchers

Replace 10 individual PostToolUse entries in hooks.json with two
consolidated dispatcher entries (post:dispatcher:sync /
post:dispatcher:async). The dispatcher's internal registry preserves
every hook ID, matcher, and profile, so ECC_DISABLED_HOOKS and
ECC_HOOK_PROFILE gating behave exactly as before.

Performance (Edit event, actual hooks.json commands spawned in
parallel like the harness does, median of 7 runs):
- Blocking hook latency: 81ms -> 49ms (~40% faster; 7 blocking
  processes -> 1 sync dispatcher)
- Node processes per tool call: 10 -> 2 (7 blocking + 3 async
  -> 1 sync + 1 async)
- observe-runner now runs in-process (~370ms) inside the async
  dispatcher, which stays backgrounded (async: true, timeout 45s),
  so it adds no user-facing latency.

Also:
- dashboard-web lists dispatcher-managed child hooks so the hook
  inventory stays complete
- post-edit-console-warn refactored to export run() for in-process
  dispatch while keeping standalone stdin behavior
- dispatcher stdin reading is multi-byte safe (StringDecoder) and
  child hook exit codes propagate to the dispatcher exit code

* test(hooks): replace emoji literal with unicode escape for CI unicode safety check

* fix(hooks): adopt explicit cli() entrypoint and merge multi-hook stdout

Address Greptile review on #2494:

- Replace the non-standard 'require.main === undefined' guard with an
  explicit exported cli(). The hooks.json bootstraps now call
  require(s).cli(), so merely requiring the module (dashboard-web,
  test runners, Jest, worker threads) can never trigger dispatch,
  attach stdin listeners, or set process.exitCode.
- Replace last-writer-wins stdout with mergeHookStdout(): when several
  hooks emit additionalContext envelopes they merge into a single
  PostToolUse envelope; non-mergeable raw stdout keeps the last hook's
  output and emits a stderr warning naming the dropped hook IDs, so
  nothing is lost silently.

Also includes local formatter reformatting of the dispatcher and its
test file (no behavioral changes beyond the above).

* fix(hooks): keep post:bash:dispatcher phase reachable in minimal profile

The Greptile P1 premise was partially incorrect: sub-hooks without
explicit profiles default to standard,strict via parseProfiles()
(scripts/lib/hook-flags.js), so audit/cost logs never ran under the
minimal profile on main either — there is no user-visible regression.

However, main did spawn the bash dispatcher phase unconditionally and
let each sub-hook gate itself. Restore that semantic by opening the
outer registry gate to minimal,standard,strict so a future sub-hook
that opts into minimal is not silently blocked at the phase level.
Adds the previously missing minimal-profile async dry-run test.

* test(hooks): assert failing hook exit code propagates to real process status

Spawns the actual dispatcher subprocess with an injected failing hook
and asserts the OS-level exit status, stderr diagnostic, and suppressed
pass-through — closing the E2E gap CodeRabbit flagged on #2494.

* chore: retrigger CI (flaky windows powershell bootstrap test)
2026-07-19 15:47:10 -04:00

53 lines
1.9 KiB
Markdown

---
description: Run the ECC formatter quality gate for a single file and report remediation steps.
---
# Quality Gate Command
Operator entry point for the formatter quality gate that normally runs as the
`post:quality-gate` PostToolUse hook (`scripts/hooks/quality-gate.js`).
## How it actually works
The gate is a single-file formatter check driven by hook input, not CLI flags:
- The script reads the target from the hook's stdin JSON
(`tool_input.file_path`); it does not take a path argument.
- Behavior toggles are environment variables:
- `ECC_QUALITY_GATE_FIX=true` - apply formatting fixes instead of check-only
- `ECC_QUALITY_GATE_STRICT=true` - log formatter failures as gate failures
- Coverage by file type:
- `.ts/.tsx/.js/.jsx/.json/.md` - Biome `check` or Prettier `--check`,
whichever the project ships (JS/TS under Biome is skipped here because
`post-edit-format` already runs `biome check --write`)
- `.go` - `gofmt`
- `.py` - `ruff format`
- Lint and type checks are not part of this gate. Use the `verification-loop`
skill or the language verification skills for lint/type/test pipelines.
## Usage
To run the gate manually against one file, pipe hook-style JSON into the
script (set the env toggles first if you want fix or strict behavior):
```bash
echo '{"tool_input":{"file_path":"src/example.ts"}}' \
| ECC_QUALITY_GATE_FIX=true node scripts/hooks/quality-gate.js
```
Then report formatter findings and concrete remediation steps.
## Notes
Hook wiring enters through the async PostToolUse dispatcher in
`hooks/hooks.json`. Its internal registry preserves the `post:quality-gate`
ID and the `standard`/`strict` profiles.
## Arguments
$ARGUMENTS:
- `[path]` optional file to check. The script itself takes no CLI
arguments - when a path is given, substitute it as `tool_input.file_path`
in the stdin JSON shown above before running the command