fix(setup): canonical-only hook registration, heal-first, PT_EXPLICIT consent provenance

Three root causes of the phantom-AskUserQuestion-hooks class, all in the
registration path:

- Bug A: the Conductor auto-opt-in upgraded PT_DECISION "prompt" -> "yes"
  even when "prompt" was dev-setup's EXPLICIT --plan-tune-hooks=prompt pin,
  so every new Conductor workspace installed hooks. PT_EXPLICIT (flag/env/
  config-key-presence via `gstack-config has`) now gates the auto-opt-in to
  the true silent fall-through.
- Bug B: hook commands were baked from $SOURCE_GSTACK_DIR (`pwd -P` of the
  running tree — ephemeral for worktrees). Registration is now CANONICAL-ONLY
  via _hook_command_path (${CLAUDE_CONFIG_DIR:-$HOME/.claude}/skills/gstack);
  missing canonical hook = skip + log, never a baked tree path. SessionStart
  moves to schema-aware add-event under its identity source; whitespace paths
  are quoted.
- Bug C: nothing ever pruned, and dead tagged entries blocked the
  "already installed" guards forever. Setup now heals FIRST on every run
  (prune-stale --repoint at the stable install), surfaces a one-line summary
  only when something changed, surfaces the plan_tune_hooks:no-vs-live-hooks
  contradiction, and --no-team tears down all three sources plus an identity
  sweep for untagged strays.

dev-setup's no-mutation guarantee gains its stated repair exception (prune
dead / re-point existing, never ADD).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-17 12:42:01 -07:00
co-authored by Claude Fable 5
parent cec156c9f1
commit c988cb7ae6
2 changed files with 133 additions and 23 deletions
+11 -4
View File
@@ -68,10 +68,17 @@ fi
# GSTACK_PLAN_TUNE_HOOKS=yes would still resolve to "install" and rewrite the
# user's global ~/.claude/settings.json to point at THIS ephemeral worktree —
# which breaks once the workspace is deleted. The flag has highest precedence,
# so it pins resolution to "prompt", and closed stdin then makes prompt-mode a
# no-op skip (no install, no decline marker). A dev workspace must never mutate
# global settings.json. To install the hooks, run `./setup --plan-tune-hooks`
# directly (outside dev-setup). Saved prefix/other config preferences still apply.
# so it pins resolution to "prompt" (setup's PT_EXPLICIT provenance keeps the
# Conductor auto-opt-in from overriding an explicit flag), and closed stdin
# then makes prompt-mode a no-op skip (no install, no decline marker).
#
# A dev workspace never ADDS hooks to global settings.json. One stated repair
# exception: setup's heal-first pass may PRUNE dead gstack hook entries and
# RE-POINT existing ones at the stable ~/.claude/skills/gstack install —
# strictly convergent repair, never a new registration, and hook registration
# itself is canonical-only (an ephemeral tree path can never be baked in).
# To install the hooks, run `./setup --plan-tune-hooks` directly (outside
# dev-setup). Saved prefix/other config preferences still apply.
#
# GSTACK_SKIP_GBRAIN_REGEN=1 is passed INLINE (not exported) so it scopes to
# exactly this nested setup call and can't leak into any other setup path. It