Skip to content

T-WC1T-lefthook-gate-ports

Status: closed/done · Impact: high · Complexity: medium

Three pre-commit gates are capabilities living as scripts — and two lefthook lines point at deleted .py files, so those gates are silently broken today. A third mechanism (check_skill_prose.ts) subprocess-spawns the very script being moved. Port the gates to ops and repoint every gate mechanism so the pre-commit surface is live again and survives the scripts/ deletion.

LocationRole today
plugin/scripts/lint_skill_prose.tsSKILL.md prose linter vs per-skill invariants.yaml
plugin/scripts/lint_task_state_commit_origin.tstask-state frontmatter commits only on main
plugin/scripts/worktree_scope_guard.tsstaged paths must stay in the active worktree scope
lefthook.yml:37runs plugin/scripts/worktree_scope_guard.py — file no longer exists (broken gate)
lefthook.yml:89runs plugin/scripts/lint_task_state_commit_origin.py — same
.claude/skills/project-check/check_skill_prose.tslefthook wrapper whose DEFAULT_LINTER spawns plugin/scripts/lint_skill_prose.ts

services/gate/ops/{skill-prose,worktree-scope}.ts and model/entities/task/ops/lint-state-origin.ts (all hidden; the task gate sits on its entity per resolved design question a). lefthook.yml runs bun run "$CLAUDE_PLUGIN_ROOT"cli/sdlc.ts gate skill-prose | gate worktree-scope | task lint-state-origin; check_skill_prose.ts is thinned to call the verb (or lefthook calls it directly); every project-check spawn target referencing plugin/scripts/ or plugin/validators/ is repointed.

  1. Goldens: violation fixtures per gate (red) + clean tree (green), capturing <path>:<line> citation format and exit codes.
  2. Port the three gate cores; render hooks preserve citation output.
  3. Repoint lefthook lines 37 and 89 (the stale .py refs) and line 58’s wrapper; audit all .claude/skills/project-check/*.ts for scripts//validators/ spawn targets and repoint each.
  4. Prove the gates fire red-on-fixture through a real git commit attempt.
LocationKindChange
plugin/lib/services/gate/ops/skill-prose.tsnewfrom lint_skill_prose.ts
plugin/lib/services/gate/ops/worktree-scope.tsnewfrom worktree_scope_guard.ts
plugin/lib/model/entities/task/ops/lint-state-origin.tsnewfrom lint_task_state_commit_origin.ts
lefthook.ymlmodifythree gate recipes → sdlc CLI; fixes the stale .py lines
.claude/skills/project-check/check_skill_prose.tsmodifyDEFAULT_LINTER → sdlc gate skill-prose (or delete the wrapper)
plugin/scripts/lint_skill_prose.tsmodifythins to forwarder until deletion
plugin/scripts/lint_task_state_commit_origin.tsmodifysame
plugin/scripts/worktree_scope_guard.tsmodifysame
  • AC-1: each gate fires red on its violation fixture through lefthook (a real pre-commit run), with citation output matching the golden.
  • AC-2: grep -n '\.py' lefthook.yml returns nothing; no lefthook recipe references plugin/scripts/ or plugin/validators/.
  • AC-3: grep -rn "plugin/scripts/\|plugin/validators/" .claude/skills/project-check/ returns zero spawn targets.
  • AC-4: the three ops are hidden (absent from default --help, present under --advanced); full bun test green.
  • T-NV49-op-path-substrate — the gate hidden noun + per-verb hidden rendering must exist before lefthook lines can point at it.
  • Planning-phase drift finding: lefthook.yml:37,89 invoke deleted .py scripts; adversarial refutation expanded scope to the 6 live .ts gate shims (check_skill_prose wrapper). docs/plans/op-substrate-full-sweep.md §Context + T8 amendment.

T-NV49-op-path-substrate


← Back to Tasks