mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-05 16:34:00 +01:00
fix(captain): review pass 1: 'do it' parses as rec, READY template matches the tool's lines, slot-2 and freeze wording, mergeChangelogs named, parameter lists and doc numbers aligned
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
30caa1fd71
commit
02ac865411
16 files changed
+79
-46
No files matched your search
+2
-2
@@ -5,14 +5,14 @@
|
||||
**`/captain` (also `/crew`): the crew operating model that keeps many agents merging into one base branch without turning it red, as a gstack skill with templates and a team guide.** Teams running a controller agent over worker threads had the model only in one crew's private notes. It now ships generic: one controller merges and lanes never merge; a READY block (full head SHA, base, CI counts, pregate, gate evidence, `SHIP_RECEIPT` at the pin, screen choice with justification, receipt path, logged flaky cases) is the only merge trigger, and a green PR page or a cheap test tier never is; merge trains (build, verdict, per-slot stamp on call, verify, merge with the expected head, verify again, prune), the red-train rules (in-run flaky rerun once, bisect on the red cases, exactly one unchanged rebuild, one infra re-dispatch), the tree rule, the backstop and the freeze, and the post-merge babysit; the digest shape (Needs you / New / In progress with ages); the three approval shapes (the per-thread record, the plan ask with before → after and a "do it" reply, the merge ask with captioned before/after images); and the daily flaky-fix pass (ledger format, the gate runs' flake records and the free suites' retries as sources, red-before-green fix PRs, one named infra rerun allowance, never thresholds, trials or kinds). Where crews that run this model disagree (squash or merge, lane or controller stamps, gate-ahead, the severe race, a gate run id in the READY) the skill ships both as options for the crew rules file. Every repo-specific name is a parameter (`REPO`, `BASE`, `REQUIRED_CHECKS`, `FULL_GATE_CHECK`, `MERGE_METHOD`, `STAMP_FILES`, `KNOWN_INFRA_FLAKES`).
|
||||
|
||||
### Added
|
||||
- **`captain/SKILL.md.tmpl`**: the skill, tier 2, routed from the root router on "captain", "crew", "merge train", "call the slot", "validate this ready", "write the digest" and "flaky pass".
|
||||
- **`captain/SKILL.md.tmpl`**: the skill, tier 2, routed from the root router on "captain", "crew", a merge train, a slot call, a READY block or the crew digest; its own triggers add "validate this ready" and "flaky pass".
|
||||
- **`captain/templates/`**: `CREW.md` (the 22 lane rules, parametrized), `AGENTS.md` (the controller's standing rules with the owner's dated words), `NOTES.md` (the append-only timestamped log), `DIGEST.md`, `flaky-ledger.md`, `report.md` (Outcome, PR, Needs, Cost, Lesson, Approvals), `READY.md` (the block, the optional lines, the refusal list), `slot-call.md`, `plan-ask.md`, `merge-ask.md` and `automation-flaky-pass.md` (the schedule, what it reads, what it starts).
|
||||
- **`docs/captain.md`**: how a team sets up a Captain crew on Capy with gstack: the roles, the drive layout, the crew rules file, the READY contract, the lane's /ship sequence before READY, trains with the slot-2 recipe, approvals, the digest, the flaky pass, the owner's device, the lessons loop, and the setup steps; linked from the README docs table, `docs/skills.md`, `docs/capy-install.md` and the skill.
|
||||
- **`test/captain-skill.test.ts`**: pins the contract the skill teaches, the template set, the generic wording (no crew codes, names or repository literals) and the registration points.
|
||||
|
||||
### Changed
|
||||
- **`gstack-owner-brief render --captain`** closes "What we need from you" with the **do it** reply (every recommendation at full scope, the plan's follow-ons included, carried through with no further ask) and invites `rec` or `do it`; `capy/skill/gstack/captain.md` documents it as step 6 and points at the controller's side.
|
||||
- `README.md` (power tools), `AGENTS.md`, `docs/skills.md`, `docs/PROJECT_STRUCTURE.md`, the root router and the doctor component table register the skill; `test/fixtures/context-budget.json` gains the `captain` ceiling and the router's, grown by its one new rule; `test/catalog-budget.test.ts` and `CLAUDE.md` carry the catalog ceiling the new skill ratchets to.
|
||||
- `README.md` (power tools), `AGENTS.md`, `docs/skills.md`, `docs/PROJECT_STRUCTURE.md`, the root router and the doctor component table register the skill; `test/fixtures/context-budget.json` gains the `captain` ceiling and the router's, grown by its one new rule; `test/catalog-budget.test.ts`, `CLAUDE.md`, `CONTRIBUTING.md` and `docs/CONTRIBUTOR_REFERENCE.md` carry the catalog ceiling the new skill ratchets to; `gstack-autoplan answer` accepts `do it` as a `rec` alias.
|
||||
|
||||
## [1.91.248.0] - 2026-10-26
|
||||
|
||||
|
||||
+1
-1
@@ -427,7 +427,7 @@ eval files, and misses the strict classifier. No API keys needed.
|
||||
- **Generator tests** (`test/gen-skill-docs.test.ts`) — Tests the template system: verifies placeholders resolve correctly, output includes value hints for flags (e.g. `-d <N>` not just `-d`), enriched descriptions for key commands (e.g. `is` lists valid states, `press` lists key examples).
|
||||
- **Design detector, catalog, and DESIGN.md** (`test/gstack-design-detect.test.ts`, `test/design-detect-contract.test.ts`, `test/design-catalog.test.ts`, `test/design-checklist-sync.test.ts`, `test/design-md.test.ts`, `test/frontend-scope.test.ts`, `test/impeccable-fixtures.test.ts`) — Drive `bin/gstack-design-detect.ts` through the fake engine in `test/fixtures/fake-impeccable.ts` (probe order, the never-execute-a-repository-file rule, the `--changed` target allow-list, `design_detector: off`, analytics lines, output sanitizing), pin the catalog invariants and the generated `review/design-checklist.md`, round-trip the open DESIGN.md reader/writer, and check the real engine captures (`test/fixtures/impeccable-*.json`, engine 0.1.3) against the contract. `test/dom-dump-hygiene.test.ts` runs `lib/dom-dump.js` in a real Chromium page through the built browse binary; it self-skips without the binary and is opt-in outside CI (`GSTACK_DOM_DUMP_HYGIENE=1`).
|
||||
- **Tier-alignment invariant** (`test/e2e-tier-alignment.test.ts`) — For every self-gated `test/skill-e2e-*.test.ts` named in a touchfiles dep list, the file's `EVALS_TIER` self-gate must match its declared tier in `E2E_TIERS`. Kills the "inert demotion" class where a test is re-tiered in `touchfiles.ts` but the file still gates on the old tier and keeps running in the wrong lane. Unmapped or mixed-tier files are reported, never silently skipped.
|
||||
- **Catalog budget** (`test/catalog-budget.test.ts`) — Caps the aggregate discovery surface: the sum of every skill's frontmatter `name` + `description` (what every host loads at discovery, every session) must stay under 1,171 token-equivalents, with a 260-byte per-skill cap. Counting goes through the shared census in `test/helpers/skill-census.ts` (physical files vs authored skills vs registry entries — three deliberately different counts). Adding a skill? The failure message carries the re-measure + ratchet protocol.
|
||||
- **Catalog budget** (`test/catalog-budget.test.ts`) — Caps the aggregate discovery surface: the sum of every skill's frontmatter `name` + `description` (what every host loads at discovery, every session) must stay under 1,251 token-equivalents, with a 260-byte per-skill cap. Counting goes through the shared census in `test/helpers/skill-census.ts` (physical files vs authored skills vs registry entries — three deliberately different counts). Adding a skill? The failure message carries the re-measure + ratchet protocol.
|
||||
- **Context-budget ratchet** (`test/context-budget-ratchet.test.ts`) — CI ceilings on the two token ledgers the catalog budget doesn't cover: the always-on full-frontmatter aggregate and each skill's per-invocation eager tokens (SKILL.md + forced-read references), graded against `test/fixtures/context-budget.json` via `lib/context-bill.ts`. New skills fail until they have a ceiling; ceilings for removed skills must be pruned. Legitimate growth or a landed reduction: re-run `bun test/helpers/capture-context-budget.ts` and commit the refreshed fixture in the same commit, so the change is a visible decision in the diff.
|
||||
- **Dependency security regressions** (`test/dependency-security.test.ts`) — Run `bun test test/dependency-security.test.ts` to check the resolved `sharp` and `adm-zip` version floors, load Sharp, verify ordinary ZIP extraction, and reject extraction through destination-file and destination-directory symlinks. The symlink cases skip Windows. These checks complement the OSV scan; they do not change its existing exceptions.
|
||||
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ RESULT FORMAT (required by gstack-autoplan; the parent binds your file by this c
|
||||
|
||||
A reply binds to the `gate_rev` you read (`--gate-rev`). Bare `yes`/`no` is unparsed, never guessed.
|
||||
|
||||
- `rec`: every item takes its recommendation, plan changes included (each prints APPLY:); `all` is an alias.
|
||||
- `rec`: every item takes its recommendation, plan changes included (each prints APPLY:); `all` and `do it` are aliases.
|
||||
- `as-is`: keep every direction; no plan change.
|
||||
- `d3b uc1a`: one <id><option> token per item you set; unanswered auto items take their default.
|
||||
- `rec except d3b`: recommendations, with the listed overrides.
|
||||
|
||||
+11
-6
@@ -396,6 +396,7 @@ Everything repo-specific is a parameter. Fill them once in the crew rules file
|
||||
| `STAMP_FILES` | the files a version stamp may touch | `VERSION`, `package.json`, `CHANGELOG.md` |
|
||||
| `KNOWN_INFRA_FLAKES` | the named infra failures a lane may rerun once | a job that times out on one runner image |
|
||||
| `SPEND` | standing paid-eval spend and its cap per rerun | gates, screens, focused cases; cap per rerun |
|
||||
| `CONTROLLER` | the thread or name every ask and READY goes to | the Captain's thread code |
|
||||
|
||||
The repo's `.gstack/ship-policy.json` carries the `train` block (`gate_workflow`,
|
||||
`free_workflow`, `full_gate_check`, `max_size`, `fill_hours`), so the queue tool and the
|
||||
@@ -464,8 +465,9 @@ rest in READY order. Fewer than `TRAIN_MAX` PRs wait until the oldest READY is
|
||||
`FILL_HOURS` old; one urgent PR goes alone with `--urgent`. Announce `ORDER` to the lanes.
|
||||
Refusals happen before any spend and each names its PR: a moved head (get a new READY),
|
||||
no receipt at that head, a fork head, a real-code conflict (rebuild without that PR and
|
||||
send it back to merge `BASE`; this is the only time a lane merges `BASE`), and free tests
|
||||
red on the train branch (treat as a red train with no paid spend).
|
||||
send it back to merge `BASE`; apart from the slot's stamp commit below, this is the only
|
||||
time a lane merges `BASE` into a READY branch), and free tests red on the train branch
|
||||
(treat as a red train with no paid spend).
|
||||
|
||||
### 2. Verdict
|
||||
|
||||
@@ -517,9 +519,11 @@ i's head, stamped with its future version (`gstack-restamp --after`): if slot i
|
||||
expected, the real merge is the same tree and the gate is reused. Use it when slots are
|
||||
long and the queue is deep.
|
||||
|
||||
**Severe race (option).** When several severe fixes are close, call the slot for all of
|
||||
them; the first complete READY takes it and the rest restamp to the next version at
|
||||
their own call. Never hold a slot for a PR that has not sent a READY.
|
||||
**Severe race (option).** When several severe fixes are close and the next train will be
|
||||
urgent, tell all their lanes at once; the first complete READY takes that train and the
|
||||
rest join the following one at their own call. Inside a built train the order is fixed
|
||||
(the stamp and verify refuse a reorder), so the race is for a train, never for a slot.
|
||||
Never hold a train for a PR that has not sent a READY.
|
||||
|
||||
### 4. A red train: flaky rule, bisect, rebuild once
|
||||
|
||||
@@ -532,7 +536,8 @@ A `RED` case already failed twice in-run, so it is real; never rerun the whole g
|
||||
|
||||
The bisect runs only the red cases on every prefix. `ATTRIBUTED #<pr>`: rebuild without
|
||||
it and send that lane the case and both runs. Red on every prefix including T0: `BASE`
|
||||
is broken; fix forward through an urgent one-PR train first. Every prefix green: the
|
||||
is broken; fix forward first, through an urgent one-PR train, or through
|
||||
`train build --repair` when the queue is frozen (a freeze refuses `--urgent`). Every prefix green: the
|
||||
bisect earns exactly one unchanged `train rebuild`; report both runs, and a second red
|
||||
goes to a repair lane. Any other pattern: no rebuild, a repair lane. An infra-only or
|
||||
incomplete census earns one re-dispatch (`train rebuild --infra`). Bisect results never
|
||||
|
||||
+11
-6
@@ -74,6 +74,7 @@ Everything repo-specific is a parameter. Fill them once in the crew rules file
|
||||
| `STAMP_FILES` | the files a version stamp may touch | `VERSION`, `package.json`, `CHANGELOG.md` |
|
||||
| `KNOWN_INFRA_FLAKES` | the named infra failures a lane may rerun once | a job that times out on one runner image |
|
||||
| `SPEND` | standing paid-eval spend and its cap per rerun | gates, screens, focused cases; cap per rerun |
|
||||
| `CONTROLLER` | the thread or name every ask and READY goes to | the Captain's thread code |
|
||||
|
||||
The repo's `.gstack/ship-policy.json` carries the `train` block (`gate_workflow`,
|
||||
`free_workflow`, `full_gate_check`, `max_size`, `fill_hours`), so the queue tool and the
|
||||
@@ -142,8 +143,9 @@ rest in READY order. Fewer than `TRAIN_MAX` PRs wait until the oldest READY is
|
||||
`FILL_HOURS` old; one urgent PR goes alone with `--urgent`. Announce `ORDER` to the lanes.
|
||||
Refusals happen before any spend and each names its PR: a moved head (get a new READY),
|
||||
no receipt at that head, a fork head, a real-code conflict (rebuild without that PR and
|
||||
send it back to merge `BASE`; this is the only time a lane merges `BASE`), and free tests
|
||||
red on the train branch (treat as a red train with no paid spend).
|
||||
send it back to merge `BASE`; apart from the slot's stamp commit below, this is the only
|
||||
time a lane merges `BASE` into a READY branch), and free tests red on the train branch
|
||||
(treat as a red train with no paid spend).
|
||||
|
||||
### 2. Verdict
|
||||
|
||||
@@ -195,9 +197,11 @@ i's head, stamped with its future version (`gstack-restamp --after`): if slot i
|
||||
expected, the real merge is the same tree and the gate is reused. Use it when slots are
|
||||
long and the queue is deep.
|
||||
|
||||
**Severe race (option).** When several severe fixes are close, call the slot for all of
|
||||
them; the first complete READY takes it and the rest restamp to the next version at
|
||||
their own call. Never hold a slot for a PR that has not sent a READY.
|
||||
**Severe race (option).** When several severe fixes are close and the next train will be
|
||||
urgent, tell all their lanes at once; the first complete READY takes that train and the
|
||||
rest join the following one at their own call. Inside a built train the order is fixed
|
||||
(the stamp and verify refuse a reorder), so the race is for a train, never for a slot.
|
||||
Never hold a train for a PR that has not sent a READY.
|
||||
|
||||
### 4. A red train: flaky rule, bisect, rebuild once
|
||||
|
||||
@@ -210,7 +214,8 @@ A `RED` case already failed twice in-run, so it is real; never rerun the whole g
|
||||
|
||||
The bisect runs only the red cases on every prefix. `ATTRIBUTED #<pr>`: rebuild without
|
||||
it and send that lane the case and both runs. Red on every prefix including T0: `BASE`
|
||||
is broken; fix forward through an urgent one-PR train first. Every prefix green: the
|
||||
is broken; fix forward first, through an urgent one-PR train, or through
|
||||
`train build --repair` when the queue is frozen (a freeze refuses `--urgent`). Every prefix green: the
|
||||
bisect earns exactly one unchanged `train rebuild`; report both runs, and a second red
|
||||
goes to a repair lane. Any other pattern: no rebuild, a repair lane. An infra-only or
|
||||
incomplete census earns one re-dispatch (`train rebuild --infra`). Bisect results never
|
||||
|
||||
@@ -7,7 +7,8 @@ date and the words. Add rules at the end; never renumber.
|
||||
Parameters: `REPO=<owner/name>` · `BASE=<main>` · `REQUIRED_CHECKS=<check names>` ·
|
||||
`FULL_GATE_CHECK=<check the train gate publishes>` · `TRAIN_MAX=<5>` · `FILL_HOURS=<3>` ·
|
||||
`MERGE_METHOD=<squash|merge>` · `STAMP_FILES=<VERSION, package.json, CHANGELOG.md, …>` ·
|
||||
`KNOWN_INFRA_FLAKES=<named jobs, or none>` · `CONTROLLER=<thread code or name>`.
|
||||
`KNOWN_INFRA_FLAKES=<named jobs, or none>` · `SPEND=<pre-approved paid runs; cap per rerun>` ·
|
||||
`CONTROLLER=<thread code or name>`.
|
||||
|
||||
1. **Session start.** Load the gstack skill and run its install check (`--check`). Put
|
||||
the `gstack:` trailer line in your first report. Run no gstack workflow without a
|
||||
|
||||
+27
-15
@@ -1,19 +1,32 @@
|
||||
# READY block
|
||||
|
||||
Sent by the lane, as printed by `gstack-ship-queue ready --pr <n> --no-screen|--screen`,
|
||||
then the lane's own lines. The controller validates every field before the pin enters
|
||||
`train build`. A missing or wrong field goes back to the lane, never into a train.
|
||||
Sent by the lane: first the block exactly as `gstack-ship-queue ready --pr <n> --no-screen|--screen`
|
||||
prints it, then the lane's own lines. The controller validates every field before the pin
|
||||
enters `train build`. A missing or wrong field goes back to the lane, never into a train.
|
||||
|
||||
The tool's lines (shapes as printed; `screen:` is inserted as the second line under a train policy):
|
||||
|
||||
```text
|
||||
READY #<n> <sha40> STAMP_VERSION=unstamped
|
||||
base: <BASE> @ <base sha12>
|
||||
ci: passed=<k> failed=0 pending=0 (<REQUIRED_CHECKS names>)
|
||||
PREGATE: pass tree=<tree12> (remote lanes cleared: <run urls>)
|
||||
gate: <skill's own cases: <case ids> passed | screen requested>
|
||||
SHIP_RECEIPT: pr=<n> head=<sha40>
|
||||
screen: <--no-screen (cases above passed focused) | --screen (reason)>
|
||||
READY_RECEIPT: <path written by the tool>
|
||||
screen: <screen|no-screen> policy=<selection> nonce=<nonce> run=<run id or ->
|
||||
pr: <PR url>
|
||||
head: <sha40>
|
||||
version: unstamped
|
||||
base: origin/<BASE>@<base sha40>
|
||||
ci: green at <sha12> (passed=<k> failed=0 pending=0 skipped=<s>)
|
||||
PREGATE: pass tree=<tree12> head=<sha12> checks=<c>
|
||||
gate: command=<"…"|none> full_e2e=<yes|no> gate-ahead=<…>
|
||||
SHIP_RECEIPT: pr=<n> head=<sha12> version=- base=<BASE> tree=<tree> session_kind=unattended …
|
||||
READY_RECEIPT: <path the tool wrote> (<local and notes-ref detail>)
|
||||
```
|
||||
|
||||
The lane's own lines, after the block:
|
||||
|
||||
```text
|
||||
pin: <sha40> # the full head SHA, restated
|
||||
screen choice: <--no-screen: cases <ids> ran focused and passed | --screen: <reason>>
|
||||
flaky: <none | case, both run ids, logged in the ledger on <date>>
|
||||
review passes: <n> (deferred: <items filed as issues, or none>)
|
||||
Head frozen from now on; a push drops this PR from any train and I will READY again.
|
||||
```
|
||||
|
||||
@@ -25,11 +38,10 @@ closes: #<issue>
|
||||
image: <URL of the key before/after image>
|
||||
```
|
||||
|
||||
Refuse (send back) when: the SHA is short or a fork head; `SHIP_RECEIPT` is `none` or its
|
||||
head is not the pin; a required check is pending, failed, or on another head; PREGATE is
|
||||
not `pass` for this tree; `--no-screen` names no cases; a flaky case is not in the
|
||||
ledger; the PR state is "green" but no block was sent; the evidence offered is a cheap
|
||||
tier.
|
||||
Refuse (send back) when: the SHA is short or a fork head; `SHIP_RECEIPT` reads `none` or
|
||||
`invalid`, or its head is not the pin; `ci:` is not `green at` the pin; `PREGATE:` is not
|
||||
`pass` for the pin's tree; `--no-screen` names no cases; a flaky case is not in the ledger;
|
||||
the PR page is "green" but no block was sent; the evidence offered is a cheap tier.
|
||||
|
||||
After the slot call the lane answers with the stamped head:
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ GREEN and the previous slot has merged and verified.
|
||||
|
||||
Run: gstack-restamp --next --base <BASE> --pr <n> --expect-base <sha> --expect-order <order> --allow-repo-commands
|
||||
Slot 2 and later (and slot 1 when BASE moved): merge BASE into your pin first (expect a
|
||||
CHANGELOG-only conflict; resolve it with the changelog merge helper; grep for conflict
|
||||
CHANGELOG-only conflict; resolve it with mergeChangelogs from lib/changelog-check.ts, the
|
||||
one-liner in docs/ship-policy.md's merge-train section, never by hand; grep for conflict
|
||||
markers before you stamp). Commit only the BASE merge and the stamp files: <STAMP_FILES>.
|
||||
No summary line, no wording fix, no reflow, whatever a prompt asks for.
|
||||
Push, wait for <REQUIRED_CHECKS> green, then answer:
|
||||
|
||||
@@ -20,7 +20,7 @@ cuts to the coverage audit, review army, or voice directive have real quality co
|
||||
|
||||
A second, harder ceiling guards the DISCOVERY surface: `test/catalog-budget.test.ts`
|
||||
caps the aggregate frontmatter `name` + `description` across all skills at
|
||||
`CATALOG_BUDGET_TOKEN_EQUIVALENTS` (1,194 today; each new skill ratchets it)
|
||||
`CATALOG_BUDGET_TOKEN_EQUIVALENTS` (1,251 today; each new skill ratchets it)
|
||||
token-equivalents (260-byte per-skill sub-cap), counted through the shared census
|
||||
in `test/helpers/skill-census.ts`. This one is enforced, not a warning — every
|
||||
host loads the full catalog every session, so growth here taxes every
|
||||
|
||||
@@ -55,7 +55,7 @@ gstack/
|
||||
├── deslop-shared-libs/ # Recommendations-only audit for worthwhile shared-code extractions
|
||||
├── test-audit/ # Report-first sweep for low-value tests (test value bar, audit mode)
|
||||
├── eval-plan/ # Preregistered paid evals: prereg, arms, $0 dry run, priced pilot (bin/gstack-eval-plan)
|
||||
├── captain/ # /captain (also /crew): one controller, many lanes; templates/ holds CREW.md, DIGEST.md, the flaky ledger, the READY block, slot call, asks and the daily automation prompt
|
||||
├── captain/ # /captain (also /crew): one controller, many lanes; templates/ holds CREW.md, AGENTS.md, NOTES.md, DIGEST.md, the flaky ledger, the lane report, the READY block, slot call, asks and the daily automation prompt
|
||||
├── plan-ceo-review/ # /plan-ceo-review skill
|
||||
├── plan-eng-review/ # /plan-eng-review skill
|
||||
├── autoplan/ # /autoplan skill (auto-review pipeline: CEO → design → DX → eng, eng always last)
|
||||
|
||||
+6
-4
@@ -79,7 +79,8 @@ can be changed by the controller.
|
||||
|
||||
## The READY contract
|
||||
|
||||
The full field table and the refusal list are in the [READY template](../captain/templates/READY.md).
|
||||
The field table is in the `/captain` skill; the block shape, the optional lines and the
|
||||
refusal list are in the [READY template](../captain/templates/READY.md).
|
||||
The short version: the pin is the full 40-character head SHA; every required check is
|
||||
green at that head; pregate passed for that tree; `SHIP_RECEIPT: pr=<n> head=<pin>` was
|
||||
written by /ship at the pin; the screen choice is stated with its justification; flaky
|
||||
@@ -139,9 +140,10 @@ a tree no green train covered; one repair PR at its exact head clears the freeze
|
||||
|
||||
**Slot 2 and later.** The base branch already carries the earlier slots' stamps, so a
|
||||
stamp on the bare pin leaves the PR conflicting on the CHANGELOG. The lane merges the base
|
||||
into its pin first (expect a CHANGELOG-only conflict; resolve it with the changelog merge
|
||||
helper, grep for conflict markers before stamping), then restamps, then commits only the
|
||||
merge and the stamp files. In practice slot 1 needs the same merge whenever the base moved
|
||||
into its pin first (expect a CHANGELOG-only conflict; resolve it with `mergeChangelogs`
|
||||
from `lib/changelog-check.ts`, the `bun -e` one-liner in
|
||||
[ship-policy.md](ship-policy.md#run-a-merge-train), never by hand, and grep for conflict
|
||||
markers before stamping), then restamps, then commits only the merge and the stamp files. In practice slot 1 needs the same merge whenever the base moved
|
||||
after the pin was taken. A stamp commit with one extra byte freezes the queue for every
|
||||
lane behind it.
|
||||
|
||||
|
||||
+3
-3
@@ -1321,9 +1321,9 @@ suites' retries into a ledger and fixes causes, never thresholds. Where crews th
|
||||
this model disagree (squash or merge, who stamps, gate-ahead, the severe race, a gate run
|
||||
id in the READY), the skill ships both as options for the crew rules file.
|
||||
|
||||
Templates (CREW.md, DIGEST.md, the flaky ledger, the lane report, the READY block, the
|
||||
slot call, the plan and merge asks, the daily automation prompt) live in
|
||||
`captain/templates/`; the team setup guide for Capy is [docs/captain.md](captain.md).
|
||||
Templates (CREW.md, AGENTS.md, NOTES.md, DIGEST.md, the flaky ledger, the lane report,
|
||||
the READY block, the slot call, the plan and merge asks, the daily automation prompt)
|
||||
live in `captain/templates/`; the team setup guide for Capy is [docs/captain.md](captain.md).
|
||||
|
||||
## `/gstack-upgrade`
|
||||
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ export interface ParsedReply {
|
||||
|
||||
export const PAGE_SIZE = 7;
|
||||
/** Reply openers that take every recommendation: `rec` and its silent aliases. */
|
||||
const REC_ALIASES: string[][] = [['rec'], ['all'], ['approve', 'all'], ['accept', 'all'], ['take', 'all', 'recommendations']];
|
||||
const REC_ALIASES: string[][] = [['rec'], ['all'], ['approve', 'all'], ['accept', 'all'], ['take', 'all', 'recommendations'], ['do', 'it']];
|
||||
const ID_RE = /^[a-z]*[0-9]+$/;
|
||||
|
||||
export function validateGateList(list: unknown): string[] {
|
||||
|
||||
@@ -38,7 +38,7 @@ export const AUTOPLAN_DRIVER_COMMANDS: Array<{ cmd: string; does: string }> = [
|
||||
|
||||
/** The reply grammar `gstack-gate` parses, one form per line. */
|
||||
export const GATE_REPLY_FORMS: Array<{ reply: string; means: string }> = [
|
||||
{ reply: 'rec', means: 'every item takes its recommendation, plan changes included (each prints APPLY:); `all` is an alias' },
|
||||
{ reply: 'rec', means: 'every item takes its recommendation, plan changes included (each prints APPLY:); `all` and `do it` are aliases' },
|
||||
{ reply: 'as-is', means: 'keep every direction; no plan change' },
|
||||
{ reply: 'd3b uc1a', means: 'one <id><option> token per item you set; unanswered auto items take their default' },
|
||||
{ reply: 'rec except d3b', means: 'recommendations, with the listed overrides' },
|
||||
|
||||
@@ -10,7 +10,7 @@ import * as fs from 'node:fs';
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import { capyRelayLine, renderCaptainBrief } from '../lib/captain-brief';
|
||||
import { recHash, type GateList } from '../lib/gate-list';
|
||||
import { parseReply, recHash, type GateList } from '../lib/gate-list';
|
||||
import { findSection, headings } from '../lib/markdown-sections';
|
||||
import { loadBriefInputs } from '../lib/owner-brief';
|
||||
|
||||
@@ -108,6 +108,13 @@ describe('renderCaptainBrief', () => {
|
||||
expect(b.text).toContain('_Not written for this plan yet._');
|
||||
});
|
||||
|
||||
test('"do it", the advertised closing reply, parses as rec', () => {
|
||||
const gate = JSON.parse(fs.readFileSync(path.join(run(FULL_PLAN), 'gate.json'), 'utf8')) as GateList;
|
||||
const parsed = parseReply('do it', gate, gate.gate_rev);
|
||||
expect(parsed.valid).toBe(true);
|
||||
expect(parsed.mode).toBe('rec');
|
||||
});
|
||||
|
||||
test('an answered gate says nothing is pending; urgent findings come first', () => {
|
||||
expect(brief(run(FULL_PLAN, { answered: true })).text).toStartWith('**Nothing pending.** Already decided on 2026-10-20: approved with the recommended plan changes (“rec”).');
|
||||
expect(brief(run(FULL_PLAN, { urgent: true })).text).toStartWith('## URGENT, outside this plan');
|
||||
|
||||
@@ -55,7 +55,7 @@ describe('/captain skill', () => {
|
||||
for (const h of ['## Needs you', '## New', '## In progress']) expect(digest).toContain(h);
|
||||
const report = read('captain/templates/report.md');
|
||||
for (const h of ['## Outcome', '## PR', '## Needs', '## Cost', '## Lesson', '## Approvals']) expect(report).toContain(h);
|
||||
expect(read('captain/templates/READY.md')).toContain('SHIP_RECEIPT: pr=<n> head=<sha40>');
|
||||
expect(read('captain/templates/READY.md')).toContain('SHIP_RECEIPT: pr=<n> head=<sha12>');
|
||||
expect(read('captain/templates/slot-call.md')).toContain('STAMP_VERSION=<X>');
|
||||
expect(read('captain/templates/flaky-ledger.md')).toMatch(/## Open[\s\S]*## Fixed[\s\S]*## Won't fix/);
|
||||
expect(read('captain/templates/CREW.md')).toMatch(/^22\. /m);
|
||||
|
||||
Reference in new issue
Block a user