mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-11 03:00:26 +01:00
fix: pre-landing review of the pstack ports
bin/gstack-worktree-audit: a worktree path with a space is read whole (sed on the porcelain 'worktree ' line, not awk's second field); a registered worktree whose directory is gone prints a 'prunable' row instead of being skipped; 'safe' now requires a clean tree and either merged into the base or a closed/merged PR with every commit pushed, so unpushed commits or untracked files on a merged branch read 'review' (the port's rule called them safe); fork PRs are dropped and an open PR wins over an older closed one on a reused branch name; GIT_TERMINAL_PROMPT=0 on the base fetch. bin/gstack-decision-trail: only a leading -h/--help is help, so a '-h' cell is appended as data; a trail without a final newline, with CRLF rows or with a repeated header line is appended to correctly; a run id is limited to [A-Za-z0-9._:@/-] (exit 2) so a tab or quote cannot break the start-row idempotence check. Tests cover each case; the 'without gh' test resolves git from 'git --exec-path' instead of a PATH rebuilt from a tool list. Docs, CHANGELOG and --help text describe the stricter buckets. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
e012748959
commit
c9ae990209
8 files changed
+161
-50
No files matched your search
@@ -182,10 +182,15 @@ beside the main one, largest first: size, age of the last commit, whether its
|
||||
head is merged into the base, `clean` / `wip:<n>` (tracked edits) /
|
||||
`scratch:<n>` (untracked only), `pushed` / `ahead<n>` / `no-remote` /
|
||||
`detached`, the PR on its branch through `gh` (`#n/open|merged|closed`, or
|
||||
`-`), the date of the newest Claude Code chat that ran in it, and a bucket:
|
||||
`hold-wip`, then `hold-open-pr`, then `verify-recent-chat` (a chat in the last
|
||||
four days), then `safe` (merged, or its PR is closed or merged), else
|
||||
`review`. A squash-merged branch is never an ancestor of the base, so read
|
||||
`MERGED` together with `PR`. The audit only reads; removing a worktree
|
||||
(`git worktree remove <path>`) stays your call after the table. `/landing-report`
|
||||
points at it when the sibling table shows stale worktrees.
|
||||
`-`; a fork's PR on a same-named branch is ignored, and an open PR wins over
|
||||
an older closed one on a reused branch name), the date of the newest Claude
|
||||
Code chat that ran in it, and a bucket: `prunable` (registered, directory
|
||||
gone), then `hold-wip`, then `hold-open-pr`, then `verify-recent-chat` (a chat
|
||||
in the last four days), then `safe`, else `review`. `safe` means nothing
|
||||
exists only in that worktree: a clean tree whose head is merged into the base,
|
||||
or whose PR is closed or merged with every commit pushed; an unpushed commit or
|
||||
an untracked file on a merged branch is `review`. A squash-merged branch is
|
||||
never an ancestor of the base, so read `MERGED` together with `PR`. The audit
|
||||
only reads; removing a worktree (`git worktree remove <path>`) stays your call
|
||||
after the table. `/landing-report` points at it when the sibling table shows
|
||||
stale worktrees.
|
||||
@@ -13,7 +13,7 @@ Beyond the slash-command skills, gstack ships standalone CLIs for workflows that
|
||||
| `gstack-verify-gate` | **Verification stop hook (opt-in)** — blocks a Claude Code turn from ending until the project's declared verify command passes (after 3 blocked re-entries it yields with a loud still-RED warning instead of looping forever). Declare it on one line in CLAUDE.md: `<!-- gstack:verify: bun test -->`. Hooks bypass the permission system, so a declared command never runs until you trust it once per repo (`gstack-verify-gate --trust`); editing the command invalidates trust until re-granted, and every grant is audit-logged. `./setup` never registers it for you — opt in with `gstack-settings-hook add-event --event Stop --command ~/.claude/skills/gstack/bin/gstack-verify-gate --source verify-gate`, remove with `gstack-settings-hook remove-source --source verify-gate`. |
|
||||
| `gstack-memorable` | **Memorable recall bridge (opt-in, third party, Claude Code only)** — connects Claude Code to the external [Memorable](https://memorable.sh) CLI *through gstack* instead of the vendor's own installer, so the hook gets gstack's guarantees: an explicit consent key (`memorable_recall`, off by default, listed by `gstack-egress grants`), a fail-closed egress receipt for every prompt handed over (`gstack-egress list --sink memorable-recall`), a HIGH-tier secret pre-scan, a trust envelope and 8 KiB cap on whatever comes back, an allowlisted environment and process-group containment for the vendor process, and clean removal. `enable` registers the hook at the stable install with a 5 s timeout and never runs the vendor's own consent command; `disable` revokes the gate first and removes the entry by identity even after Claude Code strips the tag; `status` is read-only. gstack never installs Memorable, and what its binary sends is the vendor's claim, not gstack's. Not available on Windows yet. [Full guide](memorable-workflow-memory.md). |
|
||||
| `gstack-decision-trail` | **Decision trail** — append one row (ts, phase, decision, why, evidence, result) to a run's TSV trail so a reviewer reads what was chosen and why without the transcript. Header once, append-only, cells flattened to one line, and a cell starting with `=`, `+`, `-` or `@` quoted so a spreadsheet cannot run it. `start <file> <run-id>` opens a run's stretch of a shared trail (idempotent), and `--run <id>` refuses an append until that start row is the newest. Ported from pstack's `log.sh` (MIT, NOTICE.md). [Rule](unattended.md#the-decision-trail). |
|
||||
| `gstack-worktree-audit` | **Worktree audit** — read-only table of every git worktree beside the main one, largest first: size, age, merged into the base or not, `clean`/`wip:<n>`/`scratch:<n>`, `pushed`/`ahead<n>`/`no-remote`/`detached`, the PR on its branch through `gh`, the newest Claude Code chat in it, and a bucket (`hold-wip`, `hold-open-pr`, `verify-recent-chat`, `safe`, `review`). `-b origin/<branch>` sets the base, `--no-fetch` skips the base fetch. Never deletes. Ported from pstack's `worktree-audit.sh` (MIT, NOTICE.md). [Guide](CONTRIBUTOR_REFERENCE.md#auditing-conductor-worktrees). |
|
||||
| `gstack-worktree-audit` | **Worktree audit** — read-only table of every git worktree beside the main one, largest first: size, age, merged into the base or not, `clean`/`wip:<n>`/`scratch:<n>`, `pushed`/`ahead<n>`/`no-remote`/`detached`, the PR on its branch through `gh` (fork PRs ignored), the newest Claude Code chat in it, and a bucket (`prunable` for a registered worktree whose directory is gone, `hold-wip`, `hold-open-pr`, `verify-recent-chat`, `safe` only for a clean tree with nothing unpushed, else `review`). `-b origin/<branch>` sets the base, `--no-fetch` skips the base fetch. Never deletes. Ported from pstack's `worktree-audit.sh` (MIT, NOTICE.md). [Guide](CONTRIBUTOR_REFERENCE.md#auditing-conductor-worktrees). |
|
||||
| `gstack-wtree` | **Working-tree fingerprint** — prints a content hash of what's actually on disk (temp index seeded from the stat cache, ~40x cheaper than a full re-hash; untracked source counts, gitignored scratch doesn't). Identical content fingerprints identically through commits, rebases, amends, and squashes — it's what binds reviews and test evidence to content instead of commit SHAs. |
|
||||
| `gstack-review-log` | **Review-pass receipts** — `--start <skill>` captures the working-tree fingerprint before a diff review; `'<JSON>' --finish <token>` consumes that single-use, repository/branch/skill-scoped receipt. Binding requires matching start/end content and reviewer-reported `completed:true` and `converged:true`; it is not independent proof that a model read the source. `--check-shared-libs <token>` reads a current finding as JSON on stdin and checks prior Skip decisions against the actual branch, capture and eligible raw source blobs. It returns `reusable:false` when proof is missing or unsafe, including older records without logger-versioned coverage. Final review logging computes shared-code fingerprints and coverage rather than trusting supplied proof. |
|
||||
| `gstack-review-read` | **Review freshness** — emits review records with computed `review_freshness.status` and `reason`: CURRENT, STALE, or UNVERIFIED for diff reviews. `/ship` and `/land-and-deploy` use the same grade; a matching commit alone never certifies a diff review. [Dashboard rules](skills.md#review-readiness-dashboard). |
|
||||
|
||||
@@ -4552,5 +4552,8 @@ Without `-b` the audit compares each worktree's head against the remote's
|
||||
default branch (then `origin/main`, then `origin/master`), which is not
|
||||
always the branch PRs merge into; pass `-b origin/<branch>`. A squash-merged
|
||||
branch is never an ancestor of the base, so `MERGED no` beside `PR #n/merged`
|
||||
is normal and the bucket is still `safe`. The audit only reads; a worktree it
|
||||
calls `safe` is still yours to remove.
|
||||
is normal and the bucket is still `safe` while the tree is clean and every
|
||||
commit is pushed; an unpushed commit or an untracked file on that branch makes
|
||||
it `review`, because deleting the worktree would lose it. The audit only reads;
|
||||
a worktree it calls `safe` is still yours to remove, and a `prunable` row names
|
||||
a registered worktree whose directory is already gone (`git worktree prune`).
|
||||
Reference in new issue
Block a user