Coalesce four finalize hooks into mpl-finalize-gate (#257)#260
Merged
Conversation
The four finalize_done=true validators (mpl-require-e2e, mpl-require-e2e-authenticity, mpl-require-finalize-artifacts, mpl-require-whole-goal-closure) were registered as separate PreToolUse hooks on Edit|Write|MultiEdit. Each blocked on its own violation, so resolving them required a fix → retry → next-block → retry treadmill. mpl-finalize-gate runs the four as delegated subprocesses, captures every violation, and emits a single block envelope with retry_context.failures[] preserving each originating validator's hookId, code, reason, and per-finding retry_context. Per-validator ENFORCEMENT_DEFAULTS (warn/block/off) are honored because each child resolves its own rule action independently. The four hook files remain on disk and unchanged; only their hooks.json registration is removed. A new ENFORCEMENT_DEFAULTS entry (finalize_gate_failures: 'block') wires the gate through the standard enforcement resolver so workspaces can opt the whole gate off via .mpl/config.json without touching the delegate config. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Updates the discoverability layer so the new coalesced gate appears wherever the registry-aware tooling expects it: - hook-trace PURPOSES: label for mpl-finalize-gate. - hook-trace STATE_FOCUS: include the gate because it reads state.json (via its delegates) and rewrites the blocked_hook envelope. - docs/design.md Hook System table: one row replacing the four individual finalize-validator rows, plus the registered-hook count (41 → 38). - hook-trace tests: state-category and file-category D3 tests now assert the gate replaces mpl-require-e2e and mpl-require-e2e-authenticity in traces. - issue-251 runtime test: assert the new 38 count in design.md. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds an inspectRecovery handler for the new finalize_gate_failures block code emitted by mpl-finalize-gate. The handler returns requires_user_action with the structured retry_context.failures[] list — each entry carries the originating validator's hookId, code, and reason, so the orchestrator can present every failure at once without re-parsing block_reason. There is no auto-fix path: the four delegate concerns (E2E execution, E2E authenticity, declared artifacts, AC/AX closure) are independent and the user must resolve each one before retrying the finalize_done=true write. The gate re-runs every delegate on the next write, so partial fixes surface as a smaller failures[] list on the next block envelope. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Owner
Author
Scheduled Hermes PR ReviewScope: lightweight diff review of PR #260 at Findings
Notes / Caveats
Automated periodic review by Hermes Agent. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #257.
Replaces four separately-registered PreToolUse hooks on
finalize_done=truewrites —mpl-require-e2e,mpl-require-e2e-authenticity,mpl-require-finalize-artifacts,mpl-require-whole-goal-closure— with one coalesced gatempl-finalize-gate. The four delegates' files remain on disk and unchanged; only their hooks.json registration is removed.What
hooks/mpl-finalize-gate.mjs(new): detectsfinalize_done=truewrites, spawns each delegate as a subprocess, captures every block, clears the per-child envelopes that recorded along the way, and emits one envelope withretry_context.failures[]listing each originating validator'shookId,code,reason,resume_instruction, andretry_context. Per-validatorENFORCEMENT_DEFAULTS(warn/block/off) are honored — each child resolves its own rule action.hooks/hooks.json: drop the four individual registrations, register the gate with a 15s timeout to cover four sequential children.hooks/lib/mpl-config.mjs: newfinalize_gate_failures: 'block'default; lets workspaces opt the whole gate off via.mpl/config.jsonwithout touching delegate config.hooks/lib/mpl-recover.mjs: newinspectRecoveryroute forfinalize_gate_failures— returnsrequires_user_actionwith the structuredfailures[]list. No auto-fix; user must resolve each entry before retrying.skills/mpl-recover/SKILL.md: handler doc.hooks/lib/mpl-hook-trace.mjs: PURPOSES + STATE_FOCUS entries for the gate.docs/design.md: one row replacing the four, count updated 41 → 38.mpl-finalize-gate.test.mjscovers detection, summarization, multi-finding aggregation, child-envelope leak prevention, and the recover handler. Two existing hook-trace tests + one count-assertion test updated to reflect the registry change.Why
Per
docs/findings/2026-05-29-over-enforcement-audit.mdand harness-evaluation follow-up: each of the four hooks individually verified a distinct property (scenario execution, scenario authenticity, declared-artifact presence, AC/AX coverage), but registering them separately produced a cascading-block UX — fix one, retry, hit the next. Same pattern PR #233 endorses for the relaxation work: wire to existing policy + surface better, don't add new constraint surface. No new check, just one envelope instead of four sequential ones.Test plan
node --test hooks/__tests__/*.test.mjs→ 1556/1556 pass≥2entries inretry_context.failures[]failures[]entry preserves originatinghookId+code+reasonstate.blocked_by_hook === 'mpl-finalize-gate'after delegation — no leaked child envelopeinspectRecoveryroutesfinalize_gate_failures→requires_user_actionwithfailures[]🤖 Generated with Claude Code