mirror of https://github.com/garrytan/gstack.git
docs(plan-rollout): compress PLAN_ROLLOUT_V0.md (188 → 81 lines, -57%)
Drop "What v0 got right" (self-congratulation), "What v0 proves" (redundant), and the long prose framing on each finding. Collapse findings into one-sentence-each v1.1 backlog. All concrete content preserved: problem, design, what ships, dogfood table, verdict, four findings, limit-surfaced. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9c4ab6fe6e
commit
673665d165
|
|
@ -1,188 +1,81 @@
|
|||
# PLAN_ROLLOUT_V0 — decomposition-as-artifact
|
||||
|
||||
**Status:** SHIPPED (v0.1.0)
|
||||
**Skill:** `/plan-rollout` (`plan-rollout/SKILL.md.tmpl`)
|
||||
**Skill:** `plan-rollout/SKILL.md.tmpl`
|
||||
**Schema:** `docs/SYSTEM_MD.md`
|
||||
|
||||
## The problem
|
||||
## Problem
|
||||
|
||||
LLM-assisted coding compresses implementation by 10-100x. It does not
|
||||
compress *review*. A reviewer still reads code at human speed. A
|
||||
2,000-line diff across 15 files becomes unreviewable — scope creep
|
||||
hides, reviewers skim, bugs ship.
|
||||
LLMs compress implementation 10-100x. They do not compress *review*. A
|
||||
2,000-line diff is unreviewable — scope creeps, reviewers skim, bugs
|
||||
ship. No existing skill asks of an actual diff: "one PR, or several?"
|
||||
|
||||
gstack's other planning skills scope or review the *plan*. None ask of
|
||||
the actual diff: "is this one PR, or several?"
|
||||
## Design
|
||||
|
||||
## The design
|
||||
`/plan-rollout` reads the working diff + optional `SYSTEM.md`, writes
|
||||
one artifact: `decomposition.md` (per-slice file lists, reader-time
|
||||
estimates, dependency edges, reconciliation flags). Never splits
|
||||
branches, never implements, never ships.
|
||||
|
||||
`/plan-rollout` reads the working diff (committed + staged + unstaged +
|
||||
untracked) plus `SYSTEM.md` if present, then writes one artifact:
|
||||
`decomposition.md`. The artifact contains per-slice file lists,
|
||||
reader-time estimates, dependency edges, and (when `SYSTEM.md` is
|
||||
present) contract-graph reconciliation flags. It does not split
|
||||
branches, does not implement, does not push.
|
||||
Verdict-first: if the diff is one PR, the artifact says so in one line
|
||||
and stops. False slicing is worse than no slicing.
|
||||
|
||||
The skill is verdict-first. If the diff is one PR's worth, the artifact
|
||||
says so in one line and stops. False slicing is worse than no slicing.
|
||||
|
||||
`SYSTEM.md` is optional. It declares the semantic contract graph —
|
||||
role-level relationships between components, including `breaks-if` and
|
||||
`rollout-edge` annotations. Distinct from the package/import graph,
|
||||
which is discovered at runtime. When present, it sharpens slice
|
||||
ordering and surfaces coordinated-deploy edges. When absent, the skill
|
||||
falls back to path heuristics plus light-touch import discovery.
|
||||
`SYSTEM.md` is optional input. Path heuristics + import discovery
|
||||
when absent.
|
||||
|
||||
## What v0 ships
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `plan-rollout/SKILL.md.tmpl` | The skill template (290 lines). |
|
||||
| `plan-rollout/SKILL.md` | Generated from the template. |
|
||||
| `docs/SYSTEM_MD.md` | The optional schema spec (215 lines). |
|
||||
| `docs/designs/PLAN_ROLLOUT_V0.md` | This doc — design + dogfood. |
|
||||
| `AGENTS.md`, `docs/skills.md` | One-line registry entries. |
|
||||
| File | Lines | Purpose |
|
||||
|------|------:|---------|
|
||||
| `plan-rollout/SKILL.md.tmpl` | 296 | Skill template |
|
||||
| `plan-rollout/SKILL.md` | 1011 | Generated from template |
|
||||
| `docs/SYSTEM_MD.md` | 129 | Schema spec (optional input) |
|
||||
| `docs/designs/PLAN_ROLLOUT_V0.md` | (this file) | Design + dogfood |
|
||||
| `AGENTS.md`, `docs/skills.md` | +2 | Registry |
|
||||
|
||||
Out of v0 scope (deferred):
|
||||
|
||||
- `rollout.md` (rollout/rollback strategy + inverse-rollback auto-gen)
|
||||
- A spill-check skill for in-progress diffs against the declared slice
|
||||
- Integrations into `/ship` and `/review`
|
||||
- A `SYSTEM.md` scaffolder
|
||||
|
||||
The boundary is intentional. If the primitive doesn't fit gstack,
|
||||
`git rm -r plan-rollout/ docs/SYSTEM_MD.md docs/designs/PLAN_ROLLOUT_V0.md`
|
||||
is the entire revert.
|
||||
Out of v0 (deferred): `rollout.md`, spill-check skill, `/ship` and
|
||||
`/review` integrations, `SYSTEM.md` scaffolder. Reverting v0 is
|
||||
`git rm -r plan-rollout/ docs/SYSTEM_MD.md docs/designs/PLAN_ROLLOUT_V0.md`.
|
||||
|
||||
## Dogfood: PR #1241
|
||||
|
||||
**Target:** [garrytan/gstack#1241](https://github.com/garrytan/gstack/pull/1241)
|
||||
— `fix(ask-user): keep question payloads compact`. 41 files, +661 / -282.
|
||||
**Operator:** manual walkthrough against the documented Step-by-Step flow.
|
||||
Target: [garrytan/gstack#1241](https://github.com/garrytan/gstack/pull/1241)
|
||||
— 41 files, +661/-282. Manual walkthrough.
|
||||
|
||||
41 files in one PR is the canonical "one PR or three?" surface — the
|
||||
most informative test of the verdict logic, even though (spoiler) the
|
||||
right answer turns out to be one PR.
|
||||
|
||||
### File breakdown (skill Step 2)
|
||||
|
||||
Bucketed by top-level dir (path-heuristic fallback, no `SYSTEM.md`):
|
||||
Bucketing (no SYSTEM.md):
|
||||
|
||||
| Bucket | Files | Lines |
|
||||
|--------|------:|------:|
|
||||
| `*/SKILL.md` (36 skill regenerations) | 36 | +576 / -252 |
|
||||
| `scripts/resolvers/preamble/` (the actual fix) | 1 | +16 / -7 |
|
||||
| `test/fixtures/golden/` (3 golden regenerations) | 3 | +54 / -27 |
|
||||
| `test/` (2 test files) | 2 | +31 / -3 |
|
||||
| `*/SKILL.md` regenerations | 36 | +576/-252 |
|
||||
| `scripts/resolvers/preamble/` (the fix) | 1 | +16/-7 |
|
||||
| `test/fixtures/golden/` regenerations | 3 | +54/-27 |
|
||||
| `test/` | 2 | +31/-3 |
|
||||
|
||||
### Reader-time estimate (skill Step 4)
|
||||
Reader time: `ceil(943/80) + ceil(41/5) = 21 min`. Under 30-min cap.
|
||||
|
||||
`ceil(943 / 80) + ceil(41 / 5) = 12 + 9 = 21 min`. Under the 30-min cap.
|
||||
### Verdict
|
||||
|
||||
Honest only if you treat the 36 SKILL.md regenerations as skim-time, not
|
||||
read-time. A reviewer who actually reads each one would burn far longer.
|
||||
The skill's heuristic does not currently model "mechanical regeneration"
|
||||
— see Finding 1.
|
||||
**One PR.** 39 of 41 files are deterministic regenerations of one
|
||||
source change in `scripts/resolvers/preamble/generate-ask-user-format.ts`.
|
||||
Not independently shippable — splitting them would leave dependent
|
||||
fragments.
|
||||
|
||||
### Verdict the skill should emit
|
||||
### Findings (v1.1 backlog)
|
||||
|
||||
> **This is one PR. No decomposition needed.**
|
||||
>
|
||||
> 39 of 41 files are deterministic regenerations of one source change
|
||||
> (`scripts/resolvers/preamble/generate-ask-user-format.ts`). They are
|
||||
> not independently shippable — splitting them off would leave Slice 2
|
||||
> with no standalone value and Slice 1 with broken downstream goldens
|
||||
> until Slice 2 lands. Boil it.
|
||||
>
|
||||
> **Reader guide for the single PR:**
|
||||
> 1. Read `scripts/resolvers/preamble/generate-ask-user-format.ts`
|
||||
> (+16 / -7). This is the entire substantive change.
|
||||
> 2. Spot-check 2-3 of the regenerated `*/SKILL.md` files to verify
|
||||
> the new format is applied as intended.
|
||||
> 3. Read `test/resolver-ask-user-format.test.ts` (+22 / -3) and
|
||||
> `test/gen-skill-docs.test.ts` (+9 / -0). These pin the new
|
||||
> behavior.
|
||||
> 4. Goldens (`test/fixtures/golden/*-ship-SKILL.md`) are diff-only;
|
||||
> skim if curious.
|
||||
|
||||
### Findings (v1.1 todos)
|
||||
|
||||
**Finding 1 — Path heuristics can't detect "regenerated output."**
|
||||
|
||||
Without `SYSTEM.md`, the skill buckets by top-level directory. With this
|
||||
PR it would produce roughly:
|
||||
|
||||
- Slice 0: `scripts/resolvers/preamble/...` (the fix)
|
||||
- Slice 1: `*/SKILL.md` (the regenerations)
|
||||
- Slice 2: `test/fixtures/golden/*` (also regenerations)
|
||||
- Slice 3: `test/*.test.ts` (the tests)
|
||||
|
||||
The verdict logic *should* catch this because Slice 1 and Slice 2 have
|
||||
no import edges back to anything except the build script — they can't
|
||||
ship before Slice 0. The topological-order check would collapse them.
|
||||
But the file count is high enough that a naive operator might still
|
||||
ship "Source fix" + "Regenerated outputs" as two PRs. The skill needs
|
||||
a deterministic-regeneration detector: if a slice's only diff is
|
||||
mechanical output of another slice's source change, merge them. v1
|
||||
doesn't have this.
|
||||
|
||||
**Finding 2 — Reader-time is wrong for regeneration-heavy diffs.**
|
||||
|
||||
21 minutes is the right number for "skim 36 generated files + read the
|
||||
source." It would be the wrong number if a reviewer read each
|
||||
`SKILL.md`. The heuristic treats lines uniformly. A `regen-multiplier`
|
||||
flag on slices that match build-output patterns
|
||||
(`*/SKILL.md` adjacent to a build script, `test/fixtures/golden/*`)
|
||||
would adjust this — v1.1.
|
||||
|
||||
**Finding 3 — `SYSTEM.md` wouldn't have helped here.**
|
||||
|
||||
A gstack-shaped `SYSTEM.md` with `scripts/resolvers/` marked as a
|
||||
component and `*/SKILL.md` files marked as `leaf-util` wouldn't have
|
||||
changed the verdict. The actual signal needed is "this file is a build
|
||||
output of that file," closer to a Makefile-style dependency than a
|
||||
contract graph. `SYSTEM.md` is not the right primitive for catching
|
||||
this. Don't promise it is.
|
||||
|
||||
**Finding 4 — The skill needs an `--explain` mode.**
|
||||
|
||||
A reviewer looking at the verdict "this is one PR" deserves to see why:
|
||||
how many files were classified as regeneration, which source change
|
||||
they depend on, what would happen if you tried to slice anyway. v1's
|
||||
verdict is a one-liner. v1.1 should print the rejected slicing
|
||||
alternatives and why they were rejected.
|
||||
|
||||
### What v0 got right
|
||||
|
||||
- **Verdict-first design.** The skill is structured to ALWAYS output a
|
||||
verdict line. Even when the right answer is "one PR," the artifact
|
||||
produces value: a written record of "we looked, and slicing was
|
||||
considered and rejected because of these signals."
|
||||
- **Honest about reader-time.** 21 min is the right number under
|
||||
reasonable skim assumptions. Calibrated for typical PR reading, not
|
||||
pathological "read every regenerated file."
|
||||
- **No silent slicing.** The Step 7 self-check ("If the entire diff
|
||||
fits comfortably in one slice ... say so plainly") catches the case
|
||||
where naive bucket-counting would propose 3 slices but the verdict
|
||||
logic should collapse them.
|
||||
|
||||
## v1.1 roadmap
|
||||
|
||||
1. **Deterministic-regeneration detector.** Heuristic match on filename
|
||||
patterns (`SKILL.md` adjacent to `SKILL.md.tmpl`,
|
||||
`test/fixtures/golden/*`) plus an optional `regeneration-of:` field
|
||||
in `SYSTEM.md`.
|
||||
2. **Regen-multiplier on reader-time.** Scale regenerated-output line
|
||||
counts by ~0.1 (skim-reading speed).
|
||||
1. **Regeneration detector.** Path heuristics don't know `*/SKILL.md`
|
||||
is mechanical output of `*/SKILL.md.tmpl`. Without it, a naive
|
||||
operator might still ship "source + regenerations" as two PRs. Fix:
|
||||
filename-pattern match + optional `regeneration-of:` in SYSTEM.md.
|
||||
2. **Regen-multiplier on reader-time.** Lines in regenerated files
|
||||
should count ~0.1x (skim speed). Today they count 1x.
|
||||
3. **`--explain` mode.** When the verdict is "one PR," print the
|
||||
rejected slicing alternatives and the signals that rejected them.
|
||||
rejected slicing alternatives and why each was rejected.
|
||||
4. **Calibration loop.** Log predicted vs actual reader-time on the
|
||||
first ~10 real invocations to ground v2 heuristics in data.
|
||||
first ~10 real invocations. Ground v2 heuristics in data.
|
||||
|
||||
## What v0 proves
|
||||
### Limit surfaced
|
||||
|
||||
The skill is honest about the cases where it can produce useful output
|
||||
(real multi-component diffs with clear seams) and the cases where it
|
||||
can't (regeneration-heavy diffs, single-source-fan-out patterns). One
|
||||
PR's worth of analysis on a real diff caught four real limits worth
|
||||
fixing in v1.1. That's the bar a skill should clear before shipping.
|
||||
`SYSTEM.md` is **not** the right primitive for build-output coupling.
|
||||
The signal needed is "file X is generated from file Y" — closer to a
|
||||
Makefile dependency than a contract graph. Don't promise SYSTEM.md
|
||||
solves regeneration cases.
|
||||
|
|
|
|||
Loading…
Reference in New Issue