chore: sync local alignment guidance and managed hooks #5

Merged
jercik merged 1 commit from chore/align-local-forge into main 2026-10-24 06:36:39 +00:00
Owner

Updates declaration-check guidance for Align's local command and regenerates managed hooks and review configuration from Align #809. Interrupted hooks clean up their snapshots, and the updated review wrapper retains the zero-failed-unit gate.

Merge after Align 13 is published and verified.

Updates declaration-check guidance for Align's local command and regenerates managed hooks and review configuration from [Align #809](https://code.j4k.dev/j4k/align/pulls/809). Interrupted hooks clean up their snapshots, and the updated review wrapper retains the zero-failed-unit gate. Merge after Align 13 is published and verified.
chore: sync local alignment guidance and managed hooks
All checks were successful
Checks / pr-flow-canary (pull_request) Has been skipped
Checks / reuse (pull_request) Successful in 5s
commit-msg / commitlint (pull_request) Successful in 11s
Checks / quality-checks (24.15.0) (pull_request) Successful in 29s
Checks / quality-checks (26.5.0) (pull_request) Successful in 31s
Review / Review (pull_request_target) Successful in 5m5s
d0037ddd9c

Review 01M5N1PJ9DX7YQ64F5TWAR52QH — head d0037ddd9cf7508244f75fd1cf3d58182ac84faf

Review — j4k-oss/worktree-remove @ 764528f24f

Scope: diff against base tree d12ab16f3acf
Review finished: 10 succeeded, 0 failed
Triage: settled
Facts: current review-wide projection

Computed under:

{
  "abandonment": "abandonment-v1",
  "anchor_recipe": 1,
  "batch_policy": "batch-v1",
  "coverage": "coverage-v3",
  "dispatch_policy": "dispatch-v2",
  "grounder_version": 1,
  "grounding_read_rule": "grounding-read-v1",
  "promotion_policy": "promotion-v1",
  "report": "report-v5",
  "tally": "tally-v1",
  "triage_settle": "triage-settle-v2"
}

Findings (1)

medium — The snapshot watcher leaves checkout processes running when the hook is killed

  • claim: 01M5N1W1TQ8ZYFJCMDFFZMRARZ
  • anchor: .githooks/commit-msg (snippet)
git --git-dir="$git_common_dir" -c worktree.useRelativePaths=false -c core.hooksPath=/dev/null worktree add --quiet --detach "$snapshot_dir" "$snapshot_commit" 6>&-
  • lens: unix-cli · arm: default
  • verdicts: 1 valid / 0 invalid / 0 uncertain
    • pass 01M5N1XM47ZRX3ZKWEEQZNY73T · valid: The exact-grounded command closes descriptor 6 during worktree creation. The reviewer supplies a coherent static trace: only run_step reports a process group, so hook-only SIGKILL during this direct checkout gives the watcher EOF with no group to terminate, and cleanup deletes files still used by checkout. The reported Linux/Bash reproduction specifically observes surviving Git, filter shell and sleep processes after snapshot removal. This establishes surviving owned work and unsafe cleanup ordering under ERR4, rather than merely demanding a signal handler. Normal completion and install cleanup do not cover this checkout path; killing the entire process group is a different condition. Medium severity is supported. Supervise checkout and stop its owned processes before deleting the snapshot. The helper behavior and reproduction are reviewer-reported evidence, not independently inspected or rerun here.
  • duplicates: 01M5N1X1V699YY0Q77ZCMDMV1P (aposd-plain)
  • disposition: none

Killing the hook during snapshot checkout leaves its Git process and any active smudge filter running after the watcher deletes their worktree. A slow or hung checkout filter therefore continues consuming resources after cancellation, despite the new watcher’s stated cleanup behavior. This affects killing the hook PID itself; killing its entire process group can also kill those checkout processes.

The worktree-add command closes fd 6, so killing the hook immediately gives the watcher EOF. However, only run_step sends a process-group ID through tell_watcher. During worktree creation the watcher has no recorded process group, skips its kill, and removes the snapshot while Git and the filter are still using it. Track and terminate the checkout subprocesses before removing their files, as the watcher already does for checks.

I traced run_step, watch_snapshot, and remove_snapshot_files in .githooks/commit-msg, together with package.json’s hook installation. On Linux with Bash 5.2, I ran node /app/probe-checkout.cjs: a disposable Git repository used the unmodified subject hook and scripts/check-msg.sh, a pnpm stub for the store-path prerequisite, and a real Git smudge filter blocked in sleep. The harness sent SIGKILL to the hook after the filter started. After the hook exited and the watcher removed the snapshot and worktree registration, /proc still showed the worktree-add Git process, filter shell, and sleep alive. The harness then killed their disposable process group. The separate normal-completion and kill-during-install probes cleaned up successfully.

A checkout-interruption regression exercising the real hook would refute this finding if killing the hook PID also terminated Git and its filter before cleanup finished. No real pnpm installation is required to reach the reproduced checkout path.

Other claims

  • grounding-pending (0)
  • ungrounded (0)
  • rejected (0)
  • duplicate-of (1)
    • 01M5N1X1V699YY0Q77ZCMDMV1P medium — The watcher removes the snapshot while checkout can still be running → 01M5N1W1TQ8ZYFJCMDFFZMRARZ
  • unadjudicated (1)
    • 01M5N1V9PZGRXZERGG6N1Z4J57 medium — The recursion comment duplicates the wrapper's write inventory

Coverage

Coverage pass: 01M5N1PWSDQEEDC3PSVBF9WH54
Accounting: complete (all slots terminal; see slot results for failures)
Slot health: healthy

lens part arm unit status runs loss
general-bug whole default no-claims 1 no
writing-quality whole default claims-emitted 1 no
test-trimming whole default no-claims 1 no
restated-sets whole default no-claims 1 no
project-docs whole default no-claims 1 no
unix-cli whole default claims-emitted 1 no
use-effect whole default no-claims 1 no
module-design whole default no-claims 1 no
aposd-plain whole default claims-emitted 1 no
react whole default no-claims 1 no
<!-- review:summary --> **Review** `01M5N1PJ9DX7YQ64F5TWAR52QH` — head `d0037ddd9cf7508244f75fd1cf3d58182ac84faf` # Review — j4k-oss/worktree-remove @ 764528f24f96 Scope: diff against base tree `d12ab16f3acf` Review finished: 10 succeeded, 0 failed Triage: settled Facts: current review-wide projection Computed under: ```json { "abandonment": "abandonment-v1", "anchor_recipe": 1, "batch_policy": "batch-v1", "coverage": "coverage-v3", "dispatch_policy": "dispatch-v2", "grounder_version": 1, "grounding_read_rule": "grounding-read-v1", "promotion_policy": "promotion-v1", "report": "report-v5", "tally": "tally-v1", "triage_settle": "triage-settle-v2" } ``` ## Findings (1) ### medium — The snapshot watcher leaves checkout processes running when the hook is killed - claim: `01M5N1W1TQ8ZYFJCMDFFZMRARZ` - anchor: `.githooks/commit-msg` (snippet) ``` git --git-dir="$git_common_dir" -c worktree.useRelativePaths=false -c core.hooksPath=/dev/null worktree add --quiet --detach "$snapshot_dir" "$snapshot_commit" 6>&- ``` - lens: unix-cli · arm: default - verdicts: 1 valid / 0 invalid / 0 uncertain - pass `01M5N1XM47ZRX3ZKWEEQZNY73T` · valid: The exact-grounded command closes descriptor 6 during worktree creation. The reviewer supplies a coherent static trace: only run_step reports a process group, so hook-only SIGKILL during this direct checkout gives the watcher EOF with no group to terminate, and cleanup deletes files still used by checkout. The reported Linux/Bash reproduction specifically observes surviving Git, filter shell and sleep processes after snapshot removal. This establishes surviving owned work and unsafe cleanup ordering under ERR4, rather than merely demanding a signal handler. Normal completion and install cleanup do not cover this checkout path; killing the entire process group is a different condition. Medium severity is supported. Supervise checkout and stop its owned processes before deleting the snapshot. The helper behavior and reproduction are reviewer-reported evidence, not independently inspected or rerun here. - duplicates: `01M5N1X1V699YY0Q77ZCMDMV1P` (aposd-plain) - disposition: none > Killing the hook during snapshot checkout leaves its Git process and any active smudge filter running after the watcher deletes their worktree. A slow or hung checkout filter therefore continues consuming resources after cancellation, despite the new watcher’s stated cleanup behavior. This affects killing the hook PID itself; killing its entire process group can also kill those checkout processes. > > The worktree-add command closes fd 6, so killing the hook immediately gives the watcher EOF. However, only run_step sends a process-group ID through tell_watcher. During worktree creation the watcher has no recorded process group, skips its kill, and removes the snapshot while Git and the filter are still using it. Track and terminate the checkout subprocesses before removing their files, as the watcher already does for checks. > > I traced run_step, watch_snapshot, and remove_snapshot_files in .githooks/commit-msg, together with package.json’s hook installation. On Linux with Bash 5.2, I ran `node /app/probe-checkout.cjs`: a disposable Git repository used the unmodified subject hook and scripts/check-msg.sh, a pnpm stub for the store-path prerequisite, and a real Git smudge filter blocked in sleep. The harness sent SIGKILL to the hook after the filter started. After the hook exited and the watcher removed the snapshot and worktree registration, /proc still showed the worktree-add Git process, filter shell, and sleep alive. The harness then killed their disposable process group. The separate normal-completion and kill-during-install probes cleaned up successfully. > > A checkout-interruption regression exercising the real hook would refute this finding if killing the hook PID also terminated Git and its filter before cleanup finished. No real pnpm installation is required to reach the reproduced checkout path. ## Other claims - grounding-pending (0) - ungrounded (0) - rejected (0) - duplicate-of (1) - `01M5N1X1V699YY0Q77ZCMDMV1P` medium — The watcher removes the snapshot while checkout can still be running → `01M5N1W1TQ8ZYFJCMDFFZMRARZ` - unadjudicated (1) - `01M5N1V9PZGRXZERGG6N1Z4J57` medium — The recursion comment duplicates the wrapper's write inventory ## Coverage Coverage pass: 01M5N1PWSDQEEDC3PSVBF9WH54 Accounting: complete (all slots terminal; see slot results for failures) Slot health: healthy | lens | part | arm | unit status | runs | loss | | --- | --- | --- | --- | --- | --- | | general-bug | whole | default | no-claims | 1 | no | | writing-quality | whole | default | claims-emitted | 1 | no | | test-trimming | whole | default | no-claims | 1 | no | | restated-sets | whole | default | no-claims | 1 | no | | project-docs | whole | default | no-claims | 1 | no | | unix-cli | whole | default | claims-emitted | 1 | no | | use-effect | whole | default | no-claims | 1 | no | | module-design | whole | default | no-claims | 1 | no | | aposd-plain | whole | default | claims-emitted | 1 | no | | react | whole | default | no-claims | 1 | no |
@ -146,2 +205,3 @@
exec 6> >(set -m; watch_snapshot <&0 > /dev/null &)
# Relative worktree paths would upgrade the repository format; post-checkout hooks must not run here.
git --git-dir="$git_common_dir" -c worktree.useRelativePaths=false -c core.hooksPath=/dev/null worktree add --quiet --detach "$snapshot_dir" "$snapshot_commit"
git --git-dir="$git_common_dir" -c worktree.useRelativePaths=false -c core.hooksPath=/dev/null worktree add --quiet --detach "$snapshot_dir" "$snapshot_commit" 6>&-

medium — The snapshot watcher leaves checkout processes running when the hook is killed

Killing the hook during snapshot checkout leaves its Git process and any active smudge filter running after the watcher deletes their worktree. A slow or hung checkout filter therefore continues consuming resources after cancellation, despite the new watcher’s stated cleanup behavior. This affects killing the hook PID itself; killing its entire process group can also kill those checkout processes.

The worktree-add command closes fd 6, so killing the hook immediately gives the watcher EOF. However, only run_step sends a process-group ID through tell_watcher. During worktree creation the watcher has no recorded process group, skips its kill, and removes the snapshot while Git and the filter are still using it. Track and terminate the checkout subprocesses before removing their files, as the watcher already does for checks.

I traced run_step, watch_snapshot, and remove_snapshot_files in .githooks/commit-msg, together with package.json’s hook installation. On Linux with Bash 5.2, I ran node /app/probe-checkout.cjs: a disposable Git repository used the unmodified subject hook and scripts/check-msg.sh, a pnpm stub for the store-path prerequisite, and a real Git smudge filter blocked in sleep. The harness sent SIGKILL to the hook after the filter started. After the hook exited and the watcher removed the snapshot and worktree registration, /proc still showed the worktree-add Git process, filter shell, and sleep alive. The harness then killed their disposable process group. The separate normal-completion and kill-during-install probes cleaned up successfully.

A checkout-interruption regression exercising the real hook would refute this finding if killing the hook PID also terminated Git and its filter before cleanup finished. No real pnpm installation is required to reach the reproduced checkout path.

lens unix-cli · arm default · tally 1 valid / 0 invalid / 0 uncertain
claim 01M5N1W1TQ8ZYFJCMDFFZMRARZ of review 01M5N1PJ9DX7YQ64F5TWAR52QH

<!-- review:claim:01M5N1W1TQ8ZYFJCMDFFZMRARZ --> **medium** — The snapshot watcher leaves checkout processes running when the hook is killed > Killing the hook during snapshot checkout leaves its Git process and any active smudge filter running after the watcher deletes their worktree. A slow or hung checkout filter therefore continues consuming resources after cancellation, despite the new watcher’s stated cleanup behavior. This affects killing the hook PID itself; killing its entire process group can also kill those checkout processes. > > The worktree-add command closes fd 6, so killing the hook immediately gives the watcher EOF. However, only run_step sends a process-group ID through tell_watcher. During worktree creation the watcher has no recorded process group, skips its kill, and removes the snapshot while Git and the filter are still using it. Track and terminate the checkout subprocesses before removing their files, as the watcher already does for checks. > > I traced run_step, watch_snapshot, and remove_snapshot_files in .githooks/commit-msg, together with package.json’s hook installation. On Linux with Bash 5.2, I ran `node /app/probe-checkout.cjs`: a disposable Git repository used the unmodified subject hook and scripts/check-msg.sh, a pnpm stub for the store-path prerequisite, and a real Git smudge filter blocked in sleep. The harness sent SIGKILL to the hook after the filter started. After the hook exited and the watcher removed the snapshot and worktree registration, /proc still showed the worktree-add Git process, filter shell, and sleep alive. The harness then killed their disposable process group. The separate normal-completion and kill-during-install probes cleaned up successfully. > > A checkout-interruption regression exercising the real hook would refute this finding if killing the hook PID also terminated Git and its filter before cleanup finished. No real pnpm installation is required to reach the reproduced checkout path. lens `unix-cli` · arm `default` · tally 1 valid / 0 invalid / 0 uncertain claim `01M5N1W1TQ8ZYFJCMDFFZMRARZ` of review `01M5N1PJ9DX7YQ64F5TWAR52QH`
Author
Owner

Declining this hardening change for the owned-repository migration at d0037ddd9c. I traced the direct worktree-add call and the watcher: checkout does not register a process group, so the reported hook-only SIGKILL ordering is a plausible cleanup gap. I am not claiming it is fixed or disproved. The reported experiment adds a blocking smudge filter that these tracked files do not use. Git attribute inspection found no assigned filter on any of this repository’s 79 tracked paths. The user explicitly limited this migration to our actual repositories and asked us to avoid expanding tooling for unusual edge cases. We retain that scope and accept this limitation; no follow-up PR or broader cleanup guarantee is claimed.

<!-- gh-feedback:reply-to:182215 --> Declining this hardening change for the owned-repository migration at d0037ddd9cf7508244f75fd1cf3d58182ac84faf. I traced the direct worktree-add call and the watcher: checkout does not register a process group, so the reported hook-only SIGKILL ordering is a plausible cleanup gap. I am not claiming it is fixed or disproved. The reported experiment adds a blocking smudge filter that these tracked files do not use. Git attribute inspection found no assigned filter on any of this repository’s 79 tracked paths. The user explicitly limited this migration to our actual repositories and asked us to avoid expanding tooling for unusual edge cases. We retain that scope and accept this limitation; no follow-up PR or broader cleanup guarantee is claimed.
jercik marked this conversation as resolved
Author
Owner

Review 01M5N1PJ9DX7YQ64F5TWAR52QH, head d0037ddd9c: I inspected unadjudicated claim 01M5N1V9PZGRXZERGG6N1Z4J57, “The recursion comment duplicates the wrapper's write inventory.” The generated workflow explains why its event triggers cannot recurse and warns that widening them needs another check. This is explanatory text beside the trigger declaration, not another executable inventory. The report identifies duplication rather than an incorrect command or behavior. I am declining this optional prose consolidation under the requested bounded migration scope. No source change or follow-up PR is claimed.

Review 01M5N1PJ9DX7YQ64F5TWAR52QH, head d0037ddd9cf7508244f75fd1cf3d58182ac84faf: I inspected unadjudicated claim 01M5N1V9PZGRXZERGG6N1Z4J57, “The recursion comment duplicates the wrapper's write inventory.” The generated workflow explains why its event triggers cannot recurse and warns that widening them needs another check. This is explanatory text beside the trigger declaration, not another executable inventory. The report identifies duplication rather than an incorrect command or behavior. I am declining this optional prose consolidation under the requested bounded migration scope. No source change or follow-up PR is claimed.
jercik merged commit ac277dacc1 into main 2026-10-24 06:36:39 +00:00
jercik deleted branch chore/align-local-forge 2026-10-24 06:36:39 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
j4k-oss/worktree-remove!5
No description provided.