chore(fanout): bump to v1.60.0.0 + CHANGELOG entry

Queue-aware claim: main at 1.57.7.0, 1.58/1.59 claimed by open PRs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
sohmn 2026-06-09 15:06:10 -07:00
parent bcfa57273b
commit 9dcc34a218
4 changed files with 87 additions and 5 deletions

View File

@ -1,5 +1,45 @@
# Changelog
## [1.61.0.0] - 2026-07-10
**New skill: `/fanout` decomposes a finished design doc into 2-3 parallel agent tasks.**
**Per-slab prompt files plus a worktree dispatch script. v0 produces the plan and stops.**
After `/office-hours` + eng-review + `/design-consultation` produces a design doc, the bottleneck is execution: one agent works through the whole doc serially. `/fanout docs/designs/MY_FEATURE.md` reads the doc, identifies independent slabs of work via a 4-layer heuristic (numbered phases, implementation subsections, file-reference tables, natural seams), promotes shared groundwork to a synchronous Slab 0, builds a slab matrix with verification gates, and writes a `## Parallel Execution Plan` section back to the doc. Alongside it: one editable `<topic>-slab-<k>.prompt.md` per slab and a `worktree-dispatch.sh` with Slab 0 ready to run and Slabs 1-N commented out, uncommented manually after Slab 0 lands on main.
### The shape of the win
No production benchmarks yet, this is a v0 release. The structural argument:
- Serial implementation of a 3-subsystem design doc waits on one agent finishing each subsystem in sequence.
- Parallel implementation runs three agents concurrently after a brief Slab 0 (shared groundwork) lands. Wall-clock collapses to Slab 0 time plus the slowest slab, instead of the sum.
- The slab matrix plus explicit Slab 0 promotion is the structural defense against three parallel agents tripping over the same shared type file. The skill also names the coordination tax it can't remove: every slab's /ship queues a CHANGELOG/VERSION entry, and each slab after the first rebases over the earlier ones.
Real numbers land in v1 with the first production runs and a paid E2E eval. Until then the win is qualitative: it turns "wait for one agent" into "wait for the slowest of three."
### What this means for builders
If you're sitting on a finished design doc that touches 3+ subsystems, `/fanout` turns it into 2-3 worktrees you can dispatch in parallel, each with an editable prompt file. Read the appended section, tweak the prompts if you want, run the script, let Slab 0 land before uncommenting the rest. Caps at 3 slabs by default because more is usually false parallelism. Pure prompt-based skill, no new binaries, no eval cost.
### Itemized changes
#### Added
- `/fanout` skill at `fanout/SKILL.md.tmpl` and generated `fanout/SKILL.md`.
- Free `bun test` fixture at `test/fanout.test.ts` validates frontmatter, section structure, and the hardening guardrails below.
- `/fanout` routing line in `CLAUDE.md`, rows in `README.md`, `AGENTS.md`, `docs/skills.md`, and a `test/skill-coverage-matrix.ts` entry.
#### Hardening (from the first PR's adversarial review, all six prior limitations closed)
- Worktree dirs and branch names carry a doc-path hash suffix, so two design docs with the same filename stem can't collide.
- CHANGELOG/VERSION are named expected-conflict files in the Merge order, the per-slab prompts, and the wall-clock report, so the coordination tax of parallel /ship is visible up front.
- Slab 0 promotion keeps contract ownership with the owning slab (Slab 0 lands skeletons only).
- An over-decomposition guard stops the skill when more than a third of slabs end up chained, and the natural-seams heuristic refuses docs whose shared contracts are marked draft.
- Table cells escape `|` and collapse newlines so odd file paths can't corrupt the slab matrix.
- Per-slab prompt files replace heredocs in the dispatch script, eliminating the EOF-breakout class and making each slab's marching orders user-editable before dispatch.
#### For contributors
- Design doc at [`docs/designs/FANOUT.md`](docs/designs/FANOUT.md) documents the slab detection heuristic, Slab 0 promotion logic, conflict resolution rules, edge cases, and the v0.1 hardening section.
- No new infrastructure: skill is auto-discovered by `setup` via the existing top-level-directory glob.
## [1.60.1.0] - 2026-07-09
## **The /autoplan dual-voice eval is back on the board, catching real regressions.**

View File

@ -1 +1 @@
1.60.1.0
1.61.0.0

View File

@ -54,6 +54,24 @@ echo "REPO_MODE: $REPO_MODE"
_SESSION_KIND=$(~/.claude/skills/gstack/bin/gstack-session-kind 2>/dev/null || echo "interactive")
case "$_SESSION_KIND" in spawned|headless|interactive) ;; *) _SESSION_KIND="interactive" ;; esac
echo "SESSION_KIND: $_SESSION_KIND"
# Conductor host: AskUserQuestion is unreliable here (native disabled, MCP
# variant flaky), so skills render decisions as prose instead of calling the
# tool. Gated on !headless so an eval/CI run INSIDE Conductor (GSTACK_HEADLESS)
# still BLOCKs rather than rendering prose to nobody.
if [ "$_SESSION_KIND" != "headless" ] && { [ -n "${CONDUCTOR_WORKSPACE_PATH:-}" ] || [ -n "${CONDUCTOR_PORT:-}" ]; }; then
echo "CONDUCTOR_SESSION: true"
fi
_ACTIVATED=$([ -f ~/.gstack/.activated ] && echo "yes" || echo "no")
_FIRST_LOOP_SHOWN=$([ -f ~/.gstack/.first-loop-tip-shown ] && echo "yes" || echo "no")
echo "ACTIVATED: $_ACTIVATED"
echo "FIRST_LOOP_SHOWN: $_FIRST_LOOP_SHOWN"
# First-run project detection: run the detector ONLY on the first-ever skill run
# (ACTIVATED=no, interactive) so it stays off the hot path for every run after.
_FIRST_TASK=""
if [ "$_ACTIVATED" = "no" ] && [ "$_SESSION_KIND" != "headless" ]; then
_FIRST_TASK=$(~/.claude/skills/gstack/bin/gstack-first-task-detect 2>/dev/null || true)
fi
echo "FIRST_TASK: $_FIRST_TASK"
_LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no")
echo "LAKE_INTRO: $_LAKE_SEEN"
_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true)
@ -223,6 +241,24 @@ touch ~/.gstack/.proactive-prompted
Skip if `PROACTIVE_PROMPTED` is `yes`.
## First-run guidance (one-time)
If `ACTIVATED` is `no` (first skill run on this machine) AND the preamble printed a non-empty `FIRST_TASK:` value that is NOT `nongit`: show ONE short, project-specific line mapped from the token, as a heads-up, then CONTINUE with whatever the user actually asked — do NOT halt their task. Map the token: `greenfield` → "Fresh repo — shape it first with `/spec` or `/office-hours`." `code_node`/`code_python`/`code_rust`/`code_go`/`code_ruby`/`code_ios` → "There's code here — `/qa` to see it work, or `/investigate` if something's off." `branch_ahead` → "Unshipped work on this branch — `/review` then `/ship`." `dirty_default` → "Uncommitted changes — `/review` before committing." `clean_default` → "Pick one: `/spec`, `/investigate`, or `/qa`." Then substitute the token you saw for TASK_TOKEN and run (best-effort), and mark activated:
```bash
~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type first_task_scaffold_shown --skill "TASK_TOKEN" --outcome shown 2>/dev/null || true
touch ~/.gstack/.activated 2>/dev/null || true
```
If `ACTIVATED` is `no` but `FIRST_TASK:` is empty or `nongit` (headless, non-git, or nothing actionable): show nothing, just run `touch ~/.gstack/.activated 2>/dev/null || true`.
Else if `ACTIVATED` is `yes` AND `FIRST_LOOP_SHOWN` is `no`: say once as a heads-up (then continue):
> Tip: gstack pays off when you complete one loop — **plan → review → ship**. A common first loop: `/office-hours` or `/spec` to shape it, `/plan-eng-review` to lock it, then `/ship`.
Then run `touch ~/.gstack/.first-loop-tip-shown 2>/dev/null || true`.
Skip this section if `ACTIVATED` and `FIRST_LOOP_SHOWN` are both `yes`.
If `HAS_ROUTING` is `no` AND `ROUTING_DECLINED` is `false` AND `PROACTIVE_PROMPTED` is `yes`:
Check if a CLAUDE.md file exists in the project root. If it does not exist, create it.
@ -303,7 +339,9 @@ AI orchestrator (e.g., OpenClaw). In spawned sessions:
"AskUserQuestion" can resolve to two tools at runtime: the **host MCP variant** (e.g. `mcp__conductor__AskUserQuestion` — appears in your tool list when the host registers it) or the **native** Claude Code tool.
**Rule:** if any `mcp__*__AskUserQuestion` variant is in your tool list, prefer it. Hosts may disable native AUQ via `--disallowedTools AskUserQuestion` (Conductor does, by default) and route through their MCP variant; calling native there silently fails. Same questions/options shape; same decision-brief format applies.
**Conductor rule (read before the MCP rule):** if `CONDUCTOR_SESSION: true` was echoed by the preamble, do NOT call AskUserQuestion at all — neither native nor any `mcp__*__AskUserQuestion` variant. Render EVERY decision brief as the **prose form** below and STOP. This is proactive, not a reaction to a failure: Conductor disables native AUQ and its MCP variant is flaky (it returns `[Tool result missing due to internal error]`), so prose is the reliable path. **Auto-decide preferences still apply first:** if a `[plan-tune auto-decide] <id> → <option>` result has already surfaced for a question, proceed with that option (no prose). Because in Conductor you go straight to prose without ever calling the tool, this auto-decide-first ordering is enforced HERE, not only by the PreToolUse hook. When you render a Conductor prose brief, also capture it with `bin/gstack-question-log` (the PostToolUse capture hook never fires on a prose path, so `/plan-tune` history/learning depends on this call).
**Rule (non-Conductor):** if any `mcp__*__AskUserQuestion` variant is in your tool list, prefer it. Hosts may disable native AUQ via `--disallowedTools AskUserQuestion` (Conductor does, by default) and route through their MCP variant; calling native there silently fails. Same questions/options shape; same decision-brief format applies.
If AskUserQuestion is unavailable (no variant in your tool list) OR a call to it fails, do NOT silently auto-decide or write the decision to the plan file as a substitute. Follow the **failure fallback** below.
@ -325,7 +363,11 @@ Tell three outcomes apart:
2. **Completeness scores per choice** — explicit `Completeness: X/10` on EACH choice (10 complete, 7 happy-path, 3 shortcut); use the kind-note when options differ in kind not coverage, but never silently drop the score.
3. **The recommendation and why** — a `Recommendation: <choice> because <reason>` line plus the `(recommended)` marker on that choice.
Layout: a `D<N>` title + a one-line note that AskUserQuestion failed and to reply with a letter; the issue ELI10; the Recommendation line; then ONE paragraph per choice carrying its `(recommended)` marker, its `Completeness: X/10`, and 2-4 sentences of reasoning — never a bare bullet list; a closing `Net:` line. Split chains / 5+ options: one prose block per per-option call, in sequence. Then STOP and wait — the user's typed answer is the decision. In plan mode this satisfies end-of-turn like a tool call.
Layout: a `D<N>` title + a one-line note to reply with a letter (in Conductor this is the normal path; elsewhere it means AskUserQuestion was unavailable or errored); the issue ELI10; the Recommendation line; then ONE paragraph per choice carrying its `(recommended)` marker, its `Completeness: X/10`, and 2-4 sentences of reasoning — never a bare bullet list; a closing `Net:` line. Split chains / 5+ options: one prose block per per-option call, in sequence. Then STOP and wait — the user's typed answer is the decision. In plan mode this satisfies end-of-turn like a tool call.
**Continuation — mapping a typed reply back to a brief.** Each brief carries a stable label (`D<N>`, or `D<N>.k` in a split chain). The user references it (e.g. "3.2: B"). A bare letter maps to the single most-recent UNANSWERED brief; if more than one is open (a split chain), do NOT guess — ask which `D<N>.k` it answers. Never apply a bare letter ambiguously across a chain.
**One-way / destructive confirmations in prose.** When the decision is a one-way door (irreversible or destructive — delete, force-push, drop, overwrite), prose is a WEAKER gate than the tool, so make it stronger: require an explicit typed confirmation (the exact option letter or word), state plainly what is irreversible, and NEVER proceed on a vague, partial, or ambiguous reply — re-ask instead. Treat silence or "ok"/"sure" without the explicit choice as not-yet-confirmed.
### Format
@ -409,7 +451,7 @@ Before calling AskUserQuestion, verify:
- [ ] (recommended) label on one option (even for neutral-posture)
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
- [ ] Net line closes the decision
- [ ] You are calling the tool, not writing prose — unless the documented failure fallback applies (then: prose with the mandatory triad — issue ELI10, per-choice Completeness, Recommendation + `(recommended)` — and a "reply with a letter" instruction, then STOP)
- [ ] You are calling the tool, not writing prose — unless `CONDUCTOR_SESSION: true` (then prose is the DEFAULT, not the tool) OR the documented failure fallback applies (then: prose with the mandatory triad — issue ELI10, per-choice Completeness, Recommendation + `(recommended)` — and a "reply with a letter" instruction, then STOP)
- [ ] Non-ASCII characters (CJK / accents) written directly, NOT \u-escaped
- [ ] If you had 5+ options, you split (or batched into ≤4-groups) — did NOT drop any
- [ ] If you split, you checked dependencies between options before firing the chain

View File

@ -1,6 +1,6 @@
{
"name": "gstack",
"version": "1.60.1.0",
"version": "1.61.0.0",
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
"license": "MIT",
"type": "module",