diff --git a/CHANGELOG.md b/CHANGELOG.md index 791343b5b..b15f74248 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,83 @@ # Changelog +## [1.91.34.0] - 2026-10-07 + +**/autoplan works again on current Claude Code, including long sessions and `claude --bg`.** +**The pre-push scan and the artifacts sync stop raising false alarms, and neither got weaker.** + +On Claude Code 2.1.29x, /autoplan refused every reviewer it dispatched and said "retry", which never helped. Two Claude Code changes caused it. In interactive sessions the fork-subagent setting drops `run_in_background` from the copy of the reviewer dispatch that hooks see, while the session journal keeps it, so the guard decided the call had been tampered with. Claude Code also often writes a tool call to the journal only after the hook has returned, so the guard waited two seconds for a record that never came. Sessions with a journal over 32 MiB were refused outright. The pre-push scan flagged your own email and emails already in the repo's history. One flagged file stopped the artifacts sync entirely, without telling you: one contributor's machine went 18 days without a push. + +### The numbers that matter + +All measured on Claude Code 2.1.292 unless marked otherwise. The paid runs are single trials. + +| Check | Before | After | +|---|---|---| +| Reviewer dispatches allowed in a default interactive session | 0 (each denied, "retry") | all; the live PTY case logs 3 verified allows | +| Same, through `claude --bg` + `claude attach` | 0 | 3 verified allows | +| Largest session journal the guard accepts | 32 MiB | any size; only a single record over 32 MiB counts as too large | +| One guarded read of a 120 MiB journal (4 vCPU Linux, appending during the read) | refused | 0.43-0.87 s, 170-235 MiB peak memory | +| Resumed 102 MiB session entering Phase 1 | refused | allowed, in 70 s | +| Replay fixtures shaped like the reported timelines | 3 of 28 pass (the controls) | 28 of 28 | +| Codex reviews listing 7 and 8 High/Medium findings | reported `VERDICT: clean` | reported as findings | +| Artifacts sync with one flagged file | nothing pushes, no notice | that file waits, the rest pushes, and every skill start says so | + +### What this means for you + +Run `/gstack-upgrade`. No restart is needed. An /autoplan run already in progress may get one denial asking you to publish the phase report in its own message; do that and continue. You no longer need `CLAUDE_CODE_FORK_SUBAGENT=false` (keeping it is harmless). Then try `~/.claude/skills/gstack/bin/gstack-doctor` to see what's ready before you start a skill. + +#### If /autoplan denied every reviewer on Claude Code 2.1.29x + +The guard now ignores only the one key Claude Code drops. When the current call isn't in the journal yet, it checks the call Claude Code handed to the hook against everything already written. A phase report counts once something later in the journal follows it, so each phase now publishes its report in its own message, whose only tool call is `true autoplan-published ` (no output, no permission prompt). + +When Claude Code itself leaves a call impossible to check, /autoplan continues and prints a visible warning instead of blocking. That covers an unknown journal shape, a journal that never catches up, a rewritten journal, an oversized record, or a newer Claude Code that drops another key. A changed reviewer prompt, a model override, a skipped report or any other integrity problem is still refused. Every message names a code with its own section in `docs/autoplan-guard-troubleshooting.md`. If a denial still appears, the fallback is `/plan-ceo-review`, then `/plan-devex-review`, then `/plan-eng-review`; or `/context-save`, a new session, `/context-restore`, then `/autoplan `. + +#### If the pre-push hook warned on your own email + +The scan no longer reports your own address (`git config user.email`) or addresses already in the destination's history: authors and committers of the commits you push, of the remote branch you replace, and, for a new branch, of that remote's other branches. Mailmapped addresses count too. Each MEDIUM finding now names its rule, file and line, never the value. Addresses that only some other remote knows still report, and HIGH secrets still block. To allow a team or support address in one repo, run `git config --add gstack.redact.allowEmail support@yourco.com`. If the hook says "existing-email suppression was limited for this push", it couldn't read the history within 5 seconds, so known authors may be listed that one time. + +#### If artifacts sync stopped pushing + +Run `~/.claude/skills/gstack/bin/gstack-brain-sync --status`. Each held file is listed with the scanner rule that matched and two fixes. Edit the file and the next skill run syncs it. If you never want it synced, run `~/.claude/skills/gstack/bin/gstack-brain-sync --skip-file `; undo that with `--unskip-file `. A git index lock left behind by a killed sync is now cleared once it is 10 minutes old. + +### Behavior changes you may notice + +- **/ship opens the PR early in repos that use Greptile.** That means a `.greptile/` folder, a `greptile.json`, or Greptile comments on PRs in the last 90 days. /ship pushes and opens a draft as soon as its tests pass, Greptile reviews while /ship runs its own checks, and /ship waits up to 10 minutes for that review, then folds the comments into the same pass. On a public repo it asks once first, and remembers your answer for that repo. If /ship stops partway, the draft stays open with a comment saying why. To keep the old order, run `~/.claude/skills/gstack/bin/gstack-config set ship_greptile_early false`. +- **Outside reviews that list findings without a tag, a severity label or a "no issues" statement show `unverified`, never `clean`.** Severity labels such as `High:` or `Severity: Medium` now count the same as `[P1]`-style tags. +- **Skills run the Codex probe as a command.** Skills rendered before this release still source it. That keeps working, but prints one line saying it is deprecated; sourcing stops working in a release on or after 2026-10-21. `/gstack-upgrade` re-renders them. +- **Browser skills offer a tab you're already signed in to** (title and origin only, for the site you named). They attach only after you confirm it once, instead of looping on "sign in again" for apps that keep the session in the tab or URL. +- **/context-restore no longer hands you an older checkpoint without saying so.** When another branch's worktree saved a newer checkpoint for the same task, restore shows both and proposes the newer one. Generic titles like "wip" need a matching ticket number. Restoring from a folder above a repo also offers saves made in that repo. + +### Itemized changes + +#### Added +- `bin/gstack-doctor`: one row each for install, state root, Bun, hooks, Codex (with the last cached model check and its age), artifacts sync, the browse bundle, the Claude Code version, your largest session journal, and the last five /autoplan guard codes. Each row reads ok, warn, not configured or fail, and only fail makes the exit code non-zero. Every fix line is a full path you can paste. It spends nothing unless you add `--live`. `./setup --status` gains a Codex row and ends with the doctor's path, and a new bug-report issue template asks for the doctor's output. +- `bin/gstack-post`: posts PR and issue comments, replies, titles, bodies and new PRs or issues. Every value goes to `gh` or `glab` as an argument, never through a shell string, so a title like `--repo evil/x` is posted as text. It scans exactly the bytes it sends: a credential is refused, and a MEDIUM finding needs a confirmation token tied to those exact bytes. /ship, /spec and Greptile replies post through it. +- `gstack-codex-probe` subcommands: `select-model`, `check-auth`, `show-sandbox`, `check-sandbox`, `probe-model`, `check-version`, `show-first-use-notice`, `run-with-timeout`, `log-event`, `log-hang` and `help`. +- `gstack-brain-sync --unskip-file ` and `--attention`. The `--status` JSON gains `held` (path, rule and fixes for each held file), `held_count`, `drainable`, `last_drain_at` and `last_push_at`. +- Every /autoplan guard decision, allow or deny, is logged without content to `~/.gstack/analytics/autoplan-guard.jsonl` (the last 1,000 lines are kept). +- `ship_greptile_early` config key (default `true`). + +#### Changed +- CI runs Claude Code 2.1.292 (was 2.1.284). A daily `autoplan-schema-canary` installs the newest Claude Code release and fails when its hook payload and journal record disagree in a new way. +- Question tuning, /plan-tune and brain saves pass your words through a file. /plan-tune once again records what you said when you tune a question. +- Phase reports in /autoplan are published in their own message, before the next phase starts in a later one. + +#### Fixed +- /autoplan's publication guard on Claude Code 2.1.29x, in the foreground and with `--bg`: the dropped `run_in_background` key, a current call not yet in the journal, journals over 32 MiB, and a background reviewer that finishes after the turn ended. (#3062, #3050) +- The pre-push scan's false alarms on your own email and on emails already in the repo history. MEDIUM findings now name rule, file and line. (#3060) +- Artifacts sync: one flagged file no longer blocks every push. Decision logs and their active snapshots are held together, so the remote never gets half of a pair. Every gstack writer to the sync repo shares one lock. A failed commit keeps the queue. Undecodable bytes can no longer pass the scanner as clean. The pre-commit hooks written by init and restore now catch `Bearer`/`Basic`/`Token`-prefixed JSON auth headers, like the drain does. (#3055) +- The outside-review classifier reported reviews with severity words and no `[Pn]` tags as clean. +- /context-restore picked an older checkpoint from a nested repo or a task worktree. (#3065) +- Browse cookbook: the script mistakes that look like page bugs (non-serializable `evaluate` results, a top-level `return`, `pg.press`, empty DOM reads). (#3063, #3064) +- Credits in the v1.64.0.0 entry: the extension token fix (#1822) goes to @Mike-E-Log, and the polyfill `exited` promise (#1743) to @habassa5. (#3054) + +#### For contributors +- The guard's reason codes, dispositions and anchors live in `autoplan/bin/guard-reasons.ts`. The journal reader is `lib/claude-owned-journal.ts` (two-pass, append-tolerant) over the shared extractor `lib/claude-journal-records.ts`, and `autoplan/bin/guard-journal.ts` holds the invocation window. A free test fails on any denial that advises a retry without naming what to do first. +- New paid cases: `autoplan-guard-pty` (gate, haiku) and `autoplan-long-session` (periodic). `autoplan-schema-canary` runs daily from `evals-periodic.yml`, or on dispatch with `schema_canary_only: true`. `scripts/measure-journal-read.ts` and the dispatch-only `measure-journal-read.yml` record read latency and memory. +- `gstack-post`, the probe subcommands and `gstack-greptile-early` are not supported on native Windows yet; their CLI tests are excluded from the curated Windows subset, and the in-process tests for `gstack-post`, Greptile detection and the doctor run there. +- Thanks to @yolo-jared and @crblabs (#3062), @akmandhania (#3060), @v639dragoon (#3055), @tomg65 (#3063, #3064, #3065), @Mike-E-Log (#3054) and @dgrant (#3020). + ## [1.91.33.0] - 2026-10-06 **A red eval case now gets one clear verdict from its measurement: meets, qualified, extend once, or fix.** diff --git a/TODOS.md b/TODOS.md index a4b4b809d..114d40036 100644 --- a/TODOS.md +++ b/TODOS.md @@ -2,44 +2,48 @@ ## NEXT PRIORITY -### P1–P3: Oct 6 fix-wave follow-ups (filed 2026-10-06) +### P2/P3: Oct 7 fix-wave follow-ups (filed 2026-10-07) -Deferred from the approved plan (docs/designs/FIX_WAVE_2026_10_06.md), each with its reason. +Left open by the Oct 7 wave (docs/designs/FOLLOWUP_WAVE_2026_10_07.md), each with its reason. -- **Bounded or incremental owned-journal read (P1, next wave)** — /autoplan's - guard reads the whole parent journal and refuses at 32 MiB (`too_large`, - #3050); long sessions reach 50-70 MiB. Read incrementally while keeping every - ownership and ancestry check. Acceptance: /autoplan completes in a session - whose journal is over 100 MiB, with phase-entry latency and peak memory - measured on macOS and Linux. **Effort:** L. **Priority:** P1. -- **Greptile in parallel during /ship (#3020, full version)** — push early so - Greptile reviews while /ship runs its other passes, then merge its findings - into the review. This wave only skips triage when no PR exists. +- **/autoplan permission cards after a background reviewer finishes (Claude Code + 2.1.292)** — once a background reviewer's completion notice starts a new turn, + Claude Code stops applying the skill's allowed tools, so Reads outside the + project (the close packet, the next phase's section file) show permission + cards. Seen in both foreground and `--bg` PTY runs. Options: keep those + artifacts readable without a card, or detect it and explain it once. **Effort:** M. **Priority:** P2. -- **Executed-subcommand Codex probe** — turn `bin/gstack-codex-probe` into an - executed command (`gstack-codex-probe select-model exec` printing its status - lines) so skills stop depending on the calling shell. The zsh fix (#3024) - keeps sourcing because skills call its functions across a block. - **Effort:** M. **Priority:** P2. -- **Argument-array posting helper** — one gstack helper that posts PR and issue - text by passing arguments as an array, never through a shell string (the - stronger form of the free-text file rule). **Effort:** M. **Priority:** P2. -- **Free text the lint cannot see yet** — question tuning's inline - `printf '%s' "" | … --summary-stdin`, /ship's `NEW_TITLE` - restore and Step 18's `""` prose, and the heredoc template in - `docs/gbrain-write-surfaces.md` should use the agent-written file too. - **Effort:** S. **Priority:** P2. -- **/plan-tune free-text tune events** — preference writes from skills no - longer pass the user's own words (`free_text`), because they travelled - inside a single-quoted JSON argument. Pass them through the agent-written - file. **Effort:** S. **Priority:** P2. +- **macOS numbers for the bounded journal read** — the guard's 120 MiB read + meets the Linux budget (0.43-0.87 s, at most 235 MiB peak RSS on 4 vCPU) and a + resumed 102 MiB session entered Phase 1 end to end. The macOS run is recorded + by dispatching `.github/workflows/measure-journal-read.yml`, which GitHub only + allows once the workflow is on main. **Effort:** S. **Priority:** P3. +- **Every-transition manual /autoplan session on 2.1.292** — the replay + fixtures and the scripted live boundary (foreground and `--bg`) cover the + guard; one full recorded run through every phase transition is still to do. + **Effort:** S. **Priority:** P3. +- **Remove the sourced Codex probe (on or after 2026-10-21)** — delete the + sourcing path of `bin/gstack-codex-probe`, its deprecation line, the zsh + self-locate block, the probe's entry in the zsh sourced-helper test and + `test/helpers/codex-probe-sourcing.ts`. **Effort:** S. **Priority:** P3. +- **Move the remaining PR and issue writers to gstack-post** — /document-release's + PR body and title edit (with its own scan) and the test-failure triage issue + (`--assignee`) still call gh/glab directly. **Effort:** S. **Priority:** P3. +- **`gstack-doctor --json`** — machine-readable rows for CI and bug-report + bots. Deferred as DX polish. **Effort:** S. **Priority:** P3. +- **Doctor guard check against a named session journal** — run the guard's + reader on a given journal from `gstack-doctor`. Deferred: doctor runs outside + a session and the design is unclear. **Effort:** M. **Priority:** P3. +- **One secret scanner for artifacts sync** — replace `bin/gstack-brain-sync`'s + Python scanner (and the hook copies written by init and restore) with + `lib/redact-engine.ts`. Deferred: a cross-language rewrite outside the + per-file hold. **Effort:** L. **Priority:** P3. +- **Timed novice install journey** — measure a fresh install to a first skill + run, end to end. Deferred: outside a fix wave. **Effort:** M. **Priority:** P3. - **Native Windows Docker transport for /cso (#3028)** — `lib/cso/docker.ts` accepts only `unix:///` endpoints, so /cso on Windows reports "static assessment only" even with a trusted `docker.exe`. Add named-pipe transport with the same trust checks. **Effort:** L. **Priority:** P2. -- **Readiness command** — a `gstack doctor` (or a Codex row in - `./setup --status`) that shows CODEX_MODE, the self-locate result and the - hook check without starting a skill. **Effort:** S. **Priority:** P3. ### P2/P3: reliability follow-ups deferrals (filed 2026-10-04, v1.91.30.0) diff --git a/VERSION b/VERSION index 8438d0e22..4101e586d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.33.0 +1.91.34.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index 0ff5675e6..b8eaa0b15 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.33.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.34.0 — regenerate/re-copy after upgrading gstack Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed for agent hosts without a full skill install. The full skills add workflows, diff --git a/package.json b/package.json index 4334cbfe3..61274078b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.33", + "version": "1.91.34", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", diff --git a/scripts/harness-version.json b/scripts/harness-version.json index 097171867..532284af0 100644 --- a/scripts/harness-version.json +++ b/scripts/harness-version.json @@ -16,7 +16,7 @@ "scripts/lib/published-text.ts": {"blob":"3f2e4d616b5dd0204035710c66b64d49055c5714","since":2}, "scripts/lib/shard-engine.ts": {"blob":"3cd0b1aaa84018b00bf9ea0ce48093f3c8492f66","since":2}, "scripts/test-paid-shards.ts": {"blob":"8ddee5f11ed7856876135520dd8025ab989e2db9","since":2}, - "scripts/test-pr-profile.ts": {"blob":"667ade7a76044bc20f7c183d0d4f23900c0423b3","since":2,"nonBehavioral":"FREE_ONLY_PR_FILES gains eval-sweep.yml, the sweep CLI and .github/actionlint.yaml: it changes which PR-gate cases a diff selects, never how a selected case runs or is judged"}, + "scripts/test-pr-profile.ts": {"blob":"88ecbce2b71c1e388c4dbca3f7013c71013bf8d3","since":2,"nonBehavioral":"test-pr-profile classifies the dispatch-only measure-journal-read workflow as a free-lane path; selection of paid cases and every verdict are unchanged"}, "scripts/test-strict-output.ts": {"blob":"01185d20dc9761b04b9b2f751ec98664fe0eaf93","since":2}, "test/helpers/agent-sdk-runner.ts": {"blob":"210bba92d241a90df578b2c7fc943ac5755d0025","since":2}, "test/helpers/auq-substance-panel.ts": {"blob":"4881260ef793668e4963a062db6d06a5e1f7a40f","since":2}, diff --git a/test/ship-version-sync.test.ts b/test/ship-version-sync.test.ts index ec9d9f3c6..be519ac22 100644 --- a/test/ship-version-sync.test.ts +++ b/test/ship-version-sync.test.ts @@ -262,7 +262,9 @@ test("rendered /ship handles every version-source outcome the classifier emits", const ship = readFileSync(join(import.meta.dir, "../ship/SKILL.md"), "utf8"); const changelog = readFileSync(join(import.meta.dir, "../ship/sections/changelog.md"), "utf8"); const step12 = ship.slice(ship.indexOf("## Step 12:"), ship.indexOf("## Step 14:")).replace(/\s+/g, " "); - const step18 = ship.slice(ship.indexOf("Prepare the title from that result"), ship.indexOf("## Step 20:")).replace(/\s+/g, " "); + const prBody = readFileSync(join(import.meta.dir, "../ship/sections/pr-body.md"), "utf8"); + const step18 = prBody.slice(prBody.indexOf("### Prepare the title (Step 18)"), prBody.indexOf("## Step 19:")).replace(/\s+/g, " "); + expect(step18.length).toBeGreaterThan(0); const classifyCmd = step12.match(/bun run \S+gstack-version-bump classify --base /); expect(classifyCmd).not.toBeNull(); const bin = join(import.meta.dir, "../bin/gstack-version-bump");