v1.89.1.0 fix: remove continuous checkpoint commits (#2970)

* v1.89.1.0 fix: remove continuous checkpoint commits and repair validation blockers

* fix: clarify shipping and engineering review recovery

* fix: interpret native no-change review descriptions

* test: separate descendant readiness from timeout delivery
This commit is contained in:
Garry Tan
2026-09-24 17:27:14 -04:00
committed by GitHub
parent 06ed920a97
commit 730a1017d1
103 changed files with 1819 additions and 2279 deletions
+19 -98
View File
@@ -295,31 +295,6 @@ For high-stakes ambiguity (architecture, data model, destructive scope, missing
A claimed limitation or requirement ("the API can't do this", "X requires a credential", "that's impossible on this platform") is a material claim. State one only with the verbatim error, the documented statement, or a live probe in hand — pattern-matching a failure to a familiar story is not evidence. When a cheap probe settles the question, run it BEFORE asking the user anything or declaring a step blocked.
## Continuous Checkpoint Mode
If `CHECKPOINT_MODE` is `"continuous"`: auto-commit completed logical units with `WIP:` prefix.
Commit after new intentional files, completed functions/modules, verified bug fixes, and before long-running install/build/test commands.
Commit format:
```
WIP: <concise description of what changed>
[gstack-context]
Decisions: <key choices made this step>
Remaining: <what's left in the logical unit>
Tried: <failed approaches worth recording> (omit if none)
Skill: </skill-name-if-running>
[/gstack-context]
```
Rules: stage only intentional files, NEVER `git add -A`, do not commit broken tests or mid-edit state, and push only if `CHECKPOINT_PUSH` is `"true"`. Do not announce each WIP commit.
`/context-restore` reads `[gstack-context]`; `/ship` squashes WIP commits into clean commits.
If `CHECKPOINT_MODE` is `"explicit"`: ignore this section unless a skill or user asks to commit.
## Context Health (soft directive)
During long-running skill sessions, periodically write a brief `[PROGRESS]` summary: done, next, surprises.
@@ -670,14 +645,15 @@ service with existing deployment — verify that a distribution pipeline exists.
- B) Defer — add a P1 distribution TODO in Step 14
- C) Not needed — this is internal/web-only, existing deployment covers it
4. **If release pipeline exists:** Continue silently.
5. **If no new artifact detected:** Skip silently.
4. **If the user chooses A:** Add packaging and publish configuration using this repository's CI conventions. Ask for the intended distribution target if it is unknown; do not invent a registry or credentials. Include the new workflow in the tests and review below. Do not publish a release during `/ship`.
5. **If release pipeline exists:** Continue silently.
6. **If no new artifact detected:** Skip silently.
---
## Step 3: Merge the base branch (BEFORE tests)
Merge the base ref fetched in Step 1 so tests cover the same state used by Step 2:
Merge the base ref fetched in Step 1 so tests and reviews cover the integrated code:
```bash
git merge origin/<base> --no-edit
@@ -718,7 +694,7 @@ for slot selection. Bump level and queue collisions remain agent decisions.
```
Save the JSON `baseVersion` as `BASE_VERSION`, then read `state` and dispatch:
- **FRESH** → do the bump (steps 2-4).
- **ALREADY_BUMPED** → keep `NEW_VERSION` at `currentVersion`; recover the prior `BUMP_LEVEL` from the release decision (or base/current version difference), then run step 3's queue check. Do not bump again without approval.
- **ALREADY_BUMPED** → keep `NEW_VERSION` at `currentVersion`. Use the recorded level for this release; if absent, compare `baseVersion` and `currentVersion` left to right: the first changed major/minor/patch/micro component supplies `BUMP_LEVEL` (a missing fourth component is zero). Then run step 3's queue check. This recovers the level, not permission to bump again.
- **DRIFT_STALE_PKG** → run `gstack-version-bump repair`, then reclassify. On success, follow **ALREADY_BUMPED**, including its queue check; on failure, STOP. Repair alone never re-bumps.
- **DRIFT_UNEXPECTED** → **STOP**. package.json disagrees with VERSION while VERSION matches base — a manual edit bypassed /ship. Reconcile manually, then re-run.
@@ -776,25 +752,7 @@ Never turn dropped scope into TODOs or invent unapproved follow-ups. Reuse match
## Step 15: Commit (bisectable chunks)
### Step 15.0: Preserve checkpoint context
Run `~/.claude/skills/gstack/bin/gstack-config get checkpoint_mode`. `continuous` means automatic `WIP:`
checkpoint commits; any other value skips WIP consolidation. In continuous mode,
count `WIP:` commits in `origin/<base>..HEAD`. If none exist, skip Step 15.2.
Otherwise preserve their context before committing or rewriting history:
```bash
mkdir -p "$(git rev-parse --show-toplevel)/.gstack"
git log origin/<base>..HEAD --grep="^WIP:" --format="%H%n%B%n---END---" > \
"$(git rev-parse --show-toplevel)/.gstack/wip-context-before-squash.md"
```
If export fails, do not rewrite history. Step 13 already read these bodies for
CHANGELOG; retain this PR context locally, outside commits.
### Step 15.1: Bisectable Commits
Create small, logical commits for `git bisect`. If all changes are already committed, continue to Step 15.2; never create an empty commit.
Create small, logical commits for `git bisect`. If all changes are already committed, continue to Step 16; never create an empty commit.
1. Group by coherent change. Keep each model/service/controller with its tests;
keep controller views together. Migrations may stand alone or accompany their
@@ -815,48 +773,6 @@ EOF
)"
```
### Step 15.2: Consolidate WIP commits when safe
After Step 15.1, run only for continuous-mode WIP commits. Require a clean working
tree except the context export. Run `git fetch origin`; failure means STOP.
Inspect `WIP_BASE..HEAD`, where `WIP_BASE` is `git merge-base HEAD origin/<base>`:
- **merge commits:** do not replay or flatten Step 3's integration merge.
- **published commits** (`git branch -r --contains <sha>` returns a ref): never rewrite.
- For either, ask to preserve WIP history and continue to Step 16 (recommended),
or stop for manual consolidation. Never rebase or force-push these paths.
For a linear, unpublished range, prepare and inspect an oldest-first todo.
Keep non-WIP commits as `pick` in relative order; put each WIP after its verified
logical target as `fixup`. Include every commit exactly once. An ambiguous or
out-of-range target needs a preserve-history/stop decision. First entry stays
`pick` or `reword`; all-WIP ranges retain a logical `reword` anchor. Rewording
requires a noninteractive `WIP_EDITOR` script that writes descriptive messages;
picks/fixups alone use `true`. Set the reviewed todo's absolute path below:
```bash
export WIP_TODO="<absolute path to prepared todo>"
test -s "$WIP_TODO" || exit 1
WIP_BASE=$(git merge-base HEAD origin/<base>) || exit 1
test -z "$(git status --porcelain -- . ':(exclude).gstack/wip-context-before-squash.md')" || exit 1
test -z "$(git rev-list --merges "$WIP_BASE"..HEAD)" || exit 1
for sha in $(git rev-list "$WIP_BASE"..HEAD); do
test -z "$(git branch -r --contains "$sha")" || exit 1
done
ORIGINAL_TREE=$(git rev-parse 'HEAD^{tree}')
GIT_EDITOR="${WIP_EDITOR:-true}" GIT_SEQUENCE_EDITOR='cp "$WIP_TODO"' git rebase -i "$WIP_BASE" || {
git rebase --abort
echo "STATUS: BLOCKED — WIP consolidation conflicted; original history restored"
exit 1
}
test "$ORIGINAL_TREE" = "$(git rev-parse 'HEAD^{tree}')" || {
echo "STATUS: BLOCKED — consolidation changed contents; inspect before continuing"
exit 1
}
```
Only an unchanged tree after successful consolidation may proceed to Step 16.
---
## Step 16: Verification Gate
@@ -885,14 +801,19 @@ Step 7 tests, review fixes, and Step 14 TODO edits intentionally make evidence S
- **Every line FRESH (exit 0):** recorded runs passed on identical content except
the listed release files. Cite label, exit, timestamp, and log path; continue.
- **Any STALE/MISSING (exit non-zero):** rerun the stale/missing lanes on final
content, wrapped as `~/.claude/skills/gstack/bin/gstack-evidence run --label <lane> -- '<command>'`.
Read results and recheck once. A content, command, or age mismatch requires
relevant fresh verification. If the ledger alone cannot record or verify a
successful live run, confirm unchanged final content and cite the exact command,
exit, and log; report ledger unavailable and continue, but never label the ledger FRESH.
If unchanged content cannot be confirmed, STOP. Do not rerun green suites solely for bookkeeping.
A failed CHECK selects live verification: a failed CHECK never blocks; a failed RUN does, except for the explicit triage waiver below.
- **Any STALE/MISSING (exit non-zero):** inspect the reason before choosing recovery:
- **Content, command or age mismatch, or no passing live evidence:** rerun the
affected lanes on final content, wrapped as `~/.claude/skills/gstack/bin/gstack-evidence run --label <lane> -- '<command>'`.
Read results and recheck once. TODO edits and generated tests are content
changes, not ledger-only bookkeeping.
- **Ledger read/write failure only:** if a successful live run already covers
the unchanged final content, exact command and permitted age, cite its exit,
timestamp and log directly. Report ledger unavailable and continue, never
ledger FRESH. Do not rerun green suites solely because the ledger cannot save
or read its record. If unchanged content cannot be confirmed, STOP.
A failed CHECK identifies evidence to repair; it is not a test failure. The
required live RUN must pass, except for the explicit triage waiver below.
Paste build and rerun results. Later code, test, or build-input changes return
through this gate before pushing. Step 18 owns validation of its post-push
+36 -116
View File
@@ -303,31 +303,6 @@ For high-stakes ambiguity (architecture, data model, destructive scope, missing
A claimed limitation or requirement ("the API can't do this", "X requires a credential", "that's impossible on this platform") is a material claim. State one only with the verbatim error, the documented statement, or a live probe in hand — pattern-matching a failure to a familiar story is not evidence. When a cheap probe settles the question, run it BEFORE asking the user anything or declaring a step blocked.
## Continuous Checkpoint Mode
If `CHECKPOINT_MODE` is `"continuous"`: auto-commit completed logical units with `WIP:` prefix.
Commit after new intentional files, completed functions/modules, verified bug fixes, and before long-running install/build/test commands.
Commit format:
```
WIP: <concise description of what changed>
[gstack-context]
Decisions: <key choices made this step>
Remaining: <what's left in the logical unit>
Tried: <failed approaches worth recording> (omit if none)
Skill: </skill-name-if-running>
[/gstack-context]
```
Rules: stage only intentional files, NEVER `git add -A`, do not commit broken tests or mid-edit state, and push only if `CHECKPOINT_PUSH` is `"true"`. Do not announce each WIP commit.
`/context-restore` reads `[gstack-context]`; `/ship` squashes WIP commits into clean commits.
If `CHECKPOINT_MODE` is `"explicit"`: ignore this section unless a skill or user asks to commit.
## Context Health (soft directive)
During long-running skill sessions, periodically write a brief `[PROGRESS]` summary: done, next, surprises.
@@ -663,14 +638,15 @@ service with existing deployment — verify that a distribution pipeline exists.
- B) Defer — add a P1 distribution TODO in Step 14
- C) Not needed — this is internal/web-only, existing deployment covers it
4. **If release pipeline exists:** Continue silently.
5. **If no new artifact detected:** Skip silently.
4. **If the user chooses A:** Add packaging and publish configuration using this repository's CI conventions. Ask for the intended distribution target if it is unknown; do not invent a registry or credentials. Include the new workflow in the tests and review below. Do not publish a release during `/ship`.
5. **If release pipeline exists:** Continue silently.
6. **If no new artifact detected:** Skip silently.
---
## Step 3: Merge the base branch (BEFORE tests)
Merge the base ref fetched in Step 1 so tests cover the same state used by Step 2:
Merge the base ref fetched in Step 1 so tests and reviews cover the integrated code:
```bash
git merge origin/<base> --no-edit
@@ -2031,20 +2007,22 @@ or missing-reviewer rules.
- Overall RECOMMENDATION
- If 3 or fewer ASK items, you may use individual AskUserQuestion calls instead
4. **After all fixes (auto + user-approved):**
- If fixes were applied, commit named fixed files (`git add <fixed-files> && git commit -m "fix: pre-landing review fixes"`), then **stay in this invocation and loop**: re-run the test suite (Step 5), then re-run the whole Step 9 cycle from a new pass's start-token capture, including design, specialists, Red Team, and dedup. Repeat until a complete pass applies ZERO fixes with tests green or the same explicit Step 5 waiver. NEVER tell the user to run `/ship` again just for this cycle.
4. **After all fixes (auto + user-approved), take the first matching branch:**
- If a dispatched specialist or Red Team failed, emit items 5–6 with `status:"unavailable"`, `completed:false` and `converged:false`. Then **STOP before Step 10**, naming the missing reviewer and retaining applied fixes. When coverage is available, rerun Step 5 and affected Steps 6–8 if code changed, then resume with a new Step 9 pass. Intentionally gated or host-unsupported reviewers were not dispatched and do not trigger this stop.
- If fixes were applied, commit named fixed files (`git add <fixed-files> && git commit -m "fix: pre-landing review fixes"`), then **stay in this invocation and loop**: re-run the test suite (Step 5) and affected Steps 6–8, then re-run the whole Step 9 cycle from a new pass's start-token capture, including design, specialists, Red Team, and dedup. Repeat until a complete pass applies ZERO fixes with tests green or the same explicit Step 5 waiver. NEVER tell the user to run `/ship` again just for this cycle.
- **Bound: 3 fix cycles.** If cycle 3 still fixes code, persist item 6 below with `converged:false` and that pass's original REVIEW_START, then STOP and report which findings keep reappearing.
- A zero-fix pass (including explicit skips) proceeds to summary and persistence below; missing dispatched coverage still prevents completion.
- A zero-fix pass (including explicit skips) proceeds to summary and persistence below.
5. Output summary: `Pre-Landing Review: N issues — M auto-fixed, K asked (J fixed, L skipped)`
If no issues found: `Pre-Landing Review: No issues found.`
If coverage is incomplete: `Pre-Landing Review: INCOMPLETE — <missing reviewers>`.
Otherwise, if no issues found: `Pre-Landing Review: No issues found.`
6. Persist the review result to the review log:
```bash
$GSTACK_ROOT/bin/gstack-review-log '{"skill":"review","timestamp":"TIMESTAMP","status":"STATUS","issues_found":N,"critical":N,"informational":N,"quality_score":SCORE,"specialists":SPECIALISTS_JSON,"findings":FINDINGS_JSON,"commit":"'"$(git rev-parse --short HEAD)"'","via":"ship","completed":COMPLETED,"converged":CONVERGED,"cycles":CYCLES}' --finish REVIEW_START
```
Substitute TIMESTAMP (ISO 8601), STATUS ("clean" if no issues, "issues_found" otherwise),
Substitute TIMESTAMP (ISO 8601), STATUS ("unavailable" for missing dispatched coverage, otherwise "issues_found" for unresolved defects or "clean" for none),
and N values from the remaining unresolved findings, not the original pre-fix totals. The `via:"ship"` distinguishes from standalone `/review` runs.
- `REVIEW_START` = the token captured at the start of Step 9 before this pass read the diff. `COMPLETED` = true only if the checklist and dispatched specialists completed; failed or missing dispatched coverage is false, never clean. A host-unsupported or intentionally gated specialist was not dispatched and does not block completion; retain the skip/unavailable label. `CONVERGED` = true only for a completed pass that applied zero fixes. `CYCLES` = fix cycles performed (0 for a first-pass completion). Never recapture at persistence to certify fixes that have not been reviewed.
- `quality_score` = the PR Quality Score computed in Step 9.2 (e.g., 7.5). If specialists were skipped or unsupported by this host, use `10.0`
@@ -2105,7 +2083,7 @@ For each comment in `comments`:
**SUPPRESSED:** Skip silently — these are known false positives from previous triage.
**After all comments are resolved:** If any fixes were applied, the tests from Step 5 are now stale. **Re-run tests** (Step 5) before continuing to Step 11. If no fixes were applied, continue to Step 11.
**After all comments are resolved:** If fixes were applied, run Step 5 and any affected checks from Steps 6–8, then repeat Step 9 on the changed tree before continuing to Step 11. Keep the replies already sent; do not repeat unchanged comment decisions. If no fixes were applied, continue to Step 11.
---
@@ -2183,7 +2161,7 @@ Read the diff for this branch. First list changed files: `DIFF_BASE=$(git merge-
Think like an attacker and a chaos engineer. Your job is to find ways this code will fail in production. Look for: edge cases, race conditions, security holes, resource leaks, failure modes, silent data corruption, logic errors that produce wrong results silently, error handling that swallows failures, and trust boundary violations. Be adversarial. Be thorough. No compliments — just the problems. For each finding, classify as FIXABLE (you know how to fix it) or INVESTIGATE (needs human judgment). After listing findings, end your output with ONE line in the canonical format `Recommendation: <action> because <one-line reason naming the most exploitable finding>` — examples: `Recommendation: Fix the unbounded retry at queue.ts:78 because it'll DoS the worker pool under sustained 429s` or `Recommendation: Ship as-is because the strongest finding is a theoretical race that requires conditions we can't trigger in production`. The reason must point to a specific finding (or no-fix rationale). Generic reasons like 'because it's safer' do not qualify."
Present findings under an `ADVERSARIAL REVIEW (Codex (in-host) subagent):` header. **FIXABLE findings** flow into the same Fix-First pipeline as the structured review. **INVESTIGATE findings** are presented as informational.
Present findings under an `ADVERSARIAL REVIEW (Codex (in-host) subagent):` header. **FIXABLE findings:** collect them for the Step 11 completion procedure below; it uses Step 9.4's classification and approval rules. **INVESTIGATE findings** are presented as informational.
If the subagent fails or times out: "Codex (in-host) adversarial subagent unavailable. Continuing."
@@ -2339,7 +2317,7 @@ A) Investigate and fix now (recommended)
B) Continue — review will still complete
```
If A: address the findings. After fixing, re-run tests (Step 5) since code has changed. Re-run the same shared structured invocation and diff scope to verify.
If A: record approval to fix these findings in the Step 11 completion procedure below. If B: retain the acknowledged findings and failed gate; do not report a clean review.
Read stderr for errors (same error handling as Claude Code adversarial above).
@@ -2379,6 +2357,13 @@ ADVERSARIAL REVIEW SYNTHESIS (always-on, N lines):
High-confidence findings (agreed on by multiple sources) should be prioritized for fixes.
### Step 11 completion and late-fix loop
1. Finish all available passes and persist each source/phase's actual result above. Missing or failed passes remain unavailable, never clean.
2. Triage the collected FIXABLE findings using Step 9.4 items 1–3: AUTO-FIX or ASK, apply automatic and approved fixes, and retain explicit skips. Do not ask again for a Step 11 P1 fix already approved.
3. If anything changed, commit only the fixed files. Run Step 5 and affected Steps 6–8, then repeat Step 9 from a fresh start token. After Step 9 converges, return directly to Step 11 and repeat its passes on the changed tree. Prior responses do not certify the fixes; do not repeat unchanged Step 10 comment decisions.
4. Bound this late-fix loop to three fix cycles. If the third cycle still changes code, record non-convergence and STOP with the recurring findings. A zero-fix cycle continues to Step 12 with actual coverage and any explicit acknowledgments; unavailable or waived coverage is never reported as a clean completed pass.
---
## Capture Learnings
@@ -2433,7 +2418,7 @@ for slot selection. Bump level and queue collisions remain agent decisions.
```
Save the JSON `baseVersion` as `BASE_VERSION`, then read `state` and dispatch:
- **FRESH** → do the bump (steps 2-4).
- **ALREADY_BUMPED** → keep `NEW_VERSION` at `currentVersion`; recover the prior `BUMP_LEVEL` from the release decision (or base/current version difference), then run step 3's queue check. Do not bump again without approval.
- **ALREADY_BUMPED** → keep `NEW_VERSION` at `currentVersion`. Use the recorded level for this release; if absent, compare `baseVersion` and `currentVersion` left to right: the first changed major/minor/patch/micro component supplies `BUMP_LEVEL` (a missing fourth component is zero). Then run step 3's queue check. This recovers the level, not permission to bump again.
- **DRIFT_STALE_PKG** → run `gstack-version-bump repair`, then reclassify. On success, follow **ALREADY_BUMPED**, including its queue check; on failure, STOP. Repair alone never re-bumps.
- **DRIFT_UNEXPECTED** → **STOP**. package.json disagrees with VERSION while VERSION matches base — a manual edit bypassed /ship. Reconcile manually, then re-run.
@@ -2464,16 +2449,6 @@ for slot selection. Bump level and queue collisions remain agent decisions.
```
Substitute `NEW_VERSION`, `BUMP_LEVEL`, and one-line `WHY` (scope or breaking-change signal). Best-effort, non-interactive, non-blocking.
**Before drafting:** In continuous checkpoint mode, read the WIP commit bodies
while they still exist (no WIP commits means no extra context):
```bash
git log origin/<base>..HEAD --grep="^WIP:" --format="%H%n%B"
```
Use their `[gstack-context]` notes only where supported by the diff. Step 15.0
later preserves these bodies for PR context before squashing them.
## Step 13: CHANGELOG (auto-generate)
1. Read `CHANGELOG.md` header to know the format.
@@ -2542,25 +2517,7 @@ Never turn dropped scope into TODOs or invent unapproved follow-ups. Reuse match
## Step 15: Commit (bisectable chunks)
### Step 15.0: Preserve checkpoint context
Run `$GSTACK_ROOT/bin/gstack-config get checkpoint_mode`. `continuous` means automatic `WIP:`
checkpoint commits; any other value skips WIP consolidation. In continuous mode,
count `WIP:` commits in `origin/<base>..HEAD`. If none exist, skip Step 15.2.
Otherwise preserve their context before committing or rewriting history:
```bash
mkdir -p "$(git rev-parse --show-toplevel)/.gstack"
git log origin/<base>..HEAD --grep="^WIP:" --format="%H%n%B%n---END---" > \
"$(git rev-parse --show-toplevel)/.gstack/wip-context-before-squash.md"
```
If export fails, do not rewrite history. Step 13 already read these bodies for
CHANGELOG; retain this PR context locally, outside commits.
### Step 15.1: Bisectable Commits
Create small, logical commits for `git bisect`. If all changes are already committed, continue to Step 15.2; never create an empty commit.
Create small, logical commits for `git bisect`. If all changes are already committed, continue to Step 16; never create an empty commit.
1. Group by coherent change. Keep each model/service/controller with its tests;
keep controller views together. Migrations may stand alone or accompany their
@@ -2581,48 +2538,6 @@ EOF
)"
```
### Step 15.2: Consolidate WIP commits when safe
After Step 15.1, run only for continuous-mode WIP commits. Require a clean working
tree except the context export. Run `git fetch origin`; failure means STOP.
Inspect `WIP_BASE..HEAD`, where `WIP_BASE` is `git merge-base HEAD origin/<base>`:
- **merge commits:** do not replay or flatten Step 3's integration merge.
- **published commits** (`git branch -r --contains <sha>` returns a ref): never rewrite.
- For either, ask to preserve WIP history and continue to Step 16 (recommended),
or stop for manual consolidation. Never rebase or force-push these paths.
For a linear, unpublished range, prepare and inspect an oldest-first todo.
Keep non-WIP commits as `pick` in relative order; put each WIP after its verified
logical target as `fixup`. Include every commit exactly once. An ambiguous or
out-of-range target needs a preserve-history/stop decision. First entry stays
`pick` or `reword`; all-WIP ranges retain a logical `reword` anchor. Rewording
requires a noninteractive `WIP_EDITOR` script that writes descriptive messages;
picks/fixups alone use `true`. Set the reviewed todo's absolute path below:
```bash
export WIP_TODO="<absolute path to prepared todo>"
test -s "$WIP_TODO" || exit 1
WIP_BASE=$(git merge-base HEAD origin/<base>) || exit 1
test -z "$(git status --porcelain -- . ':(exclude).gstack/wip-context-before-squash.md')" || exit 1
test -z "$(git rev-list --merges "$WIP_BASE"..HEAD)" || exit 1
for sha in $(git rev-list "$WIP_BASE"..HEAD); do
test -z "$(git branch -r --contains "$sha")" || exit 1
done
ORIGINAL_TREE=$(git rev-parse 'HEAD^{tree}')
GIT_EDITOR="${WIP_EDITOR:-true}" GIT_SEQUENCE_EDITOR='cp "$WIP_TODO"' git rebase -i "$WIP_BASE" || {
git rebase --abort
echo "STATUS: BLOCKED — WIP consolidation conflicted; original history restored"
exit 1
}
test "$ORIGINAL_TREE" = "$(git rev-parse 'HEAD^{tree}')" || {
echo "STATUS: BLOCKED — consolidation changed contents; inspect before continuing"
exit 1
}
```
Only an unchanged tree after successful consolidation may proceed to Step 16.
---
## Step 16: Verification Gate
@@ -2651,14 +2566,19 @@ Step 7 tests, review fixes, and Step 14 TODO edits intentionally make evidence S
- **Every line FRESH (exit 0):** recorded runs passed on identical content except
the listed release files. Cite label, exit, timestamp, and log path; continue.
- **Any STALE/MISSING (exit non-zero):** rerun the stale/missing lanes on final
content, wrapped as `$GSTACK_ROOT/bin/gstack-evidence run --label <lane> -- '<command>'`.
Read results and recheck once. A content, command, or age mismatch requires
relevant fresh verification. If the ledger alone cannot record or verify a
successful live run, confirm unchanged final content and cite the exact command,
exit, and log; report ledger unavailable and continue, but never label the ledger FRESH.
If unchanged content cannot be confirmed, STOP. Do not rerun green suites solely for bookkeeping.
A failed CHECK selects live verification: a failed CHECK never blocks; a failed RUN does, except for the explicit triage waiver below.
- **Any STALE/MISSING (exit non-zero):** inspect the reason before choosing recovery:
- **Content, command or age mismatch, or no passing live evidence:** rerun the
affected lanes on final content, wrapped as `$GSTACK_ROOT/bin/gstack-evidence run --label <lane> -- '<command>'`.
Read results and recheck once. TODO edits and generated tests are content
changes, not ledger-only bookkeeping.
- **Ledger read/write failure only:** if a successful live run already covers
the unchanged final content, exact command and permitted age, cite its exit,
timestamp and log directly. Report ledger unavailable and continue, never
ledger FRESH. Do not rerun green suites solely because the ledger cannot save
or read its record. If unchanged content cannot be confirmed, STOP.
A failed CHECK identifies evidence to repair; it is not a test failure. The
required live RUN must pass, except for the explicit triage waiver below.
Paste build and rerun results. Later code, test, or build-input changes return
through this gate before pushing. Step 18 owns validation of its post-push
+36 -116
View File
@@ -283,31 +283,6 @@ For high-stakes ambiguity (architecture, data model, destructive scope, missing
A claimed limitation or requirement ("the API can't do this", "X requires a credential", "that's impossible on this platform") is a material claim. State one only with the verbatim error, the documented statement, or a live probe in hand — pattern-matching a failure to a familiar story is not evidence. When a cheap probe settles the question, run it BEFORE asking the user anything or declaring a step blocked.
## Continuous Checkpoint Mode
If `CHECKPOINT_MODE` is `"continuous"`: auto-commit completed logical units with `WIP:` prefix.
Commit after new intentional files, completed functions/modules, verified bug fixes, and before long-running install/build/test commands.
Commit format:
```
WIP: <concise description of what changed>
[gstack-context]
Decisions: <key choices made this step>
Remaining: <what's left in the logical unit>
Tried: <failed approaches worth recording> (omit if none)
Skill: </skill-name-if-running>
[/gstack-context]
```
Rules: stage only intentional files, NEVER `git add -A`, do not commit broken tests or mid-edit state, and push only if `CHECKPOINT_PUSH` is `"true"`. Do not announce each WIP commit.
`/context-restore` reads `[gstack-context]`; `/ship` squashes WIP commits into clean commits.
If `CHECKPOINT_MODE` is `"explicit"`: ignore this section unless a skill or user asks to commit.
## Context Health (soft directive)
During long-running skill sessions, periodically write a brief `[PROGRESS]` summary: done, next, surprises.
@@ -643,14 +618,15 @@ service with existing deployment — verify that a distribution pipeline exists.
- B) Defer — add a P1 distribution TODO in Step 14
- C) Not needed — this is internal/web-only, existing deployment covers it
4. **If release pipeline exists:** Continue silently.
5. **If no new artifact detected:** Skip silently.
4. **If the user chooses A:** Add packaging and publish configuration using this repository's CI conventions. Ask for the intended distribution target if it is unknown; do not invent a registry or credentials. Include the new workflow in the tests and review below. Do not publish a release during `/ship`.
5. **If release pipeline exists:** Continue silently.
6. **If no new artifact detected:** Skip silently.
---
## Step 3: Merge the base branch (BEFORE tests)
Merge the base ref fetched in Step 1 so tests cover the same state used by Step 2:
Merge the base ref fetched in Step 1 so tests and reviews cover the integrated code:
```bash
git merge origin/<base> --no-edit
@@ -2270,20 +2246,22 @@ or missing-reviewer rules.
- Overall RECOMMENDATION
- If 3 or fewer ASK items, you may use individual AskUserQuestion calls instead
4. **After all fixes (auto + user-approved):**
- If fixes were applied, commit named fixed files (`git add <fixed-files> && git commit -m "fix: pre-landing review fixes"`), then **stay in this invocation and loop**: re-run the test suite (Step 5), then re-run the whole Step 9 cycle from a new pass's start-token capture, including design, specialists, Red Team, and dedup. Repeat until a complete pass applies ZERO fixes with tests green or the same explicit Step 5 waiver. NEVER tell the user to run `/ship` again just for this cycle.
4. **After all fixes (auto + user-approved), take the first matching branch:**
- If a dispatched specialist or Red Team failed, emit items 5–6 with `status:"unavailable"`, `completed:false` and `converged:false`. Then **STOP before Step 10**, naming the missing reviewer and retaining applied fixes. When coverage is available, rerun Step 5 and affected Steps 6–8 if code changed, then resume with a new Step 9 pass. Intentionally gated or host-unsupported reviewers were not dispatched and do not trigger this stop.
- If fixes were applied, commit named fixed files (`git add <fixed-files> && git commit -m "fix: pre-landing review fixes"`), then **stay in this invocation and loop**: re-run the test suite (Step 5) and affected Steps 6–8, then re-run the whole Step 9 cycle from a new pass's start-token capture, including design, specialists, Red Team, and dedup. Repeat until a complete pass applies ZERO fixes with tests green or the same explicit Step 5 waiver. NEVER tell the user to run `/ship` again just for this cycle.
- **Bound: 3 fix cycles.** If cycle 3 still fixes code, persist item 6 below with `converged:false` and that pass's original REVIEW_START, then STOP and report which findings keep reappearing.
- A zero-fix pass (including explicit skips) proceeds to summary and persistence below; missing dispatched coverage still prevents completion.
- A zero-fix pass (including explicit skips) proceeds to summary and persistence below.
5. Output summary: `Pre-Landing Review: N issues — M auto-fixed, K asked (J fixed, L skipped)`
If no issues found: `Pre-Landing Review: No issues found.`
If coverage is incomplete: `Pre-Landing Review: INCOMPLETE — <missing reviewers>`.
Otherwise, if no issues found: `Pre-Landing Review: No issues found.`
6. Persist the review result to the review log:
```bash
$GSTACK_ROOT/bin/gstack-review-log '{"skill":"review","timestamp":"TIMESTAMP","status":"STATUS","issues_found":N,"critical":N,"informational":N,"quality_score":SCORE,"specialists":SPECIALISTS_JSON,"findings":FINDINGS_JSON,"commit":"'"$(git rev-parse --short HEAD)"'","via":"ship","completed":COMPLETED,"converged":CONVERGED,"cycles":CYCLES}' --finish REVIEW_START
```
Substitute TIMESTAMP (ISO 8601), STATUS ("clean" if no issues, "issues_found" otherwise),
Substitute TIMESTAMP (ISO 8601), STATUS ("unavailable" for missing dispatched coverage, otherwise "issues_found" for unresolved defects or "clean" for none),
and N values from the remaining unresolved findings, not the original pre-fix totals. The `via:"ship"` distinguishes from standalone `/review` runs.
- `REVIEW_START` = the token captured at the start of Step 9 before this pass read the diff. `COMPLETED` = true only if the checklist and dispatched specialists completed; failed or missing dispatched coverage is false, never clean. A host-unsupported or intentionally gated specialist was not dispatched and does not block completion; retain the skip/unavailable label. `CONVERGED` = true only for a completed pass that applied zero fixes. `CYCLES` = fix cycles performed (0 for a first-pass completion). Never recapture at persistence to certify fixes that have not been reviewed.
- `quality_score` = the PR Quality Score computed in Step 9.2 (e.g., 7.5). If specialists were skipped or unsupported by this host, use `10.0`
@@ -2344,7 +2322,7 @@ For each comment in `comments`:
**SUPPRESSED:** Skip silently — these are known false positives from previous triage.
**After all comments are resolved:** If any fixes were applied, the tests from Step 5 are now stale. **Re-run tests** (Step 5) before continuing to Step 11. If no fixes were applied, continue to Step 11.
**After all comments are resolved:** If fixes were applied, run Step 5 and any affected checks from Steps 6–8, then repeat Step 9 on the changed tree before continuing to Step 11. Keep the replies already sent; do not repeat unchanged comment decisions. If no fixes were applied, continue to Step 11.
---
@@ -2441,7 +2419,7 @@ Read the diff for this branch. First list changed files: `DIFF_BASE=$(git merge-
Think like an attacker and a chaos engineer. Your job is to find ways this code will fail in production. Look for: edge cases, race conditions, security holes, resource leaks, failure modes, silent data corruption, logic errors that produce wrong results silently, error handling that swallows failures, and trust boundary violations. Be adversarial. Be thorough. No compliments — just the problems. For each finding, classify as FIXABLE (you know how to fix it) or INVESTIGATE (needs human judgment). After listing findings, end your output with ONE line in the canonical format `Recommendation: <action> because <one-line reason naming the most exploitable finding>` — examples: `Recommendation: Fix the unbounded retry at queue.ts:78 because it'll DoS the worker pool under sustained 429s` or `Recommendation: Ship as-is because the strongest finding is a theoretical race that requires conditions we can't trigger in production`. The reason must point to a specific finding (or no-fix rationale). Generic reasons like 'because it's safer' do not qualify."
Present findings under an `ADVERSARIAL REVIEW (factory (in-host) subagent):` header. **FIXABLE findings** flow into the same Fix-First pipeline as the structured review. **INVESTIGATE findings** are presented as informational.
Present findings under an `ADVERSARIAL REVIEW (factory (in-host) subagent):` header. **FIXABLE findings:** collect them for the Step 11 completion procedure below; it uses Step 9.4's classification and approval rules. **INVESTIGATE findings** are presented as informational.
If the subagent fails or times out: "factory (in-host) adversarial subagent unavailable. Continuing."
@@ -2590,7 +2568,7 @@ A) Investigate and fix now (recommended)
B) Continue — review will still complete
```
If A: address the findings. After fixing, re-run tests (Step 5) since code has changed. Re-run the same shared structured invocation and diff scope to verify.
If A: record approval to fix these findings in the Step 11 completion procedure below. If B: retain the acknowledged findings and failed gate; do not report a clean review.
Read stderr for errors (same error handling as Codex adversarial above).
@@ -2630,6 +2608,13 @@ ADVERSARIAL REVIEW SYNTHESIS (always-on, N lines):
High-confidence findings (agreed on by multiple sources) should be prioritized for fixes.
### Step 11 completion and late-fix loop
1. Finish all available passes and persist each source/phase's actual result above. Missing or failed passes remain unavailable, never clean.
2. Triage the collected FIXABLE findings using Step 9.4 items 1–3: AUTO-FIX or ASK, apply automatic and approved fixes, and retain explicit skips. Do not ask again for a Step 11 P1 fix already approved.
3. If anything changed, commit only the fixed files. Run Step 5 and affected Steps 6–8, then repeat Step 9 from a fresh start token. After Step 9 converges, return directly to Step 11 and repeat its passes on the changed tree. Prior responses do not certify the fixes; do not repeat unchanged Step 10 comment decisions.
4. Bound this late-fix loop to three fix cycles. If the third cycle still changes code, record non-convergence and STOP with the recurring findings. A zero-fix cycle continues to Step 12 with actual coverage and any explicit acknowledgments; unavailable or waived coverage is never reported as a clean completed pass.
---
## Capture Learnings
@@ -2684,7 +2669,7 @@ for slot selection. Bump level and queue collisions remain agent decisions.
```
Save the JSON `baseVersion` as `BASE_VERSION`, then read `state` and dispatch:
- **FRESH** → do the bump (steps 2-4).
- **ALREADY_BUMPED** → keep `NEW_VERSION` at `currentVersion`; recover the prior `BUMP_LEVEL` from the release decision (or base/current version difference), then run step 3's queue check. Do not bump again without approval.
- **ALREADY_BUMPED** → keep `NEW_VERSION` at `currentVersion`. Use the recorded level for this release; if absent, compare `baseVersion` and `currentVersion` left to right: the first changed major/minor/patch/micro component supplies `BUMP_LEVEL` (a missing fourth component is zero). Then run step 3's queue check. This recovers the level, not permission to bump again.
- **DRIFT_STALE_PKG** → run `gstack-version-bump repair`, then reclassify. On success, follow **ALREADY_BUMPED**, including its queue check; on failure, STOP. Repair alone never re-bumps.
- **DRIFT_UNEXPECTED** → **STOP**. package.json disagrees with VERSION while VERSION matches base — a manual edit bypassed /ship. Reconcile manually, then re-run.
@@ -2715,16 +2700,6 @@ for slot selection. Bump level and queue collisions remain agent decisions.
```
Substitute `NEW_VERSION`, `BUMP_LEVEL`, and one-line `WHY` (scope or breaking-change signal). Best-effort, non-interactive, non-blocking.
**Before drafting:** In continuous checkpoint mode, read the WIP commit bodies
while they still exist (no WIP commits means no extra context):
```bash
git log origin/<base>..HEAD --grep="^WIP:" --format="%H%n%B"
```
Use their `[gstack-context]` notes only where supported by the diff. Step 15.0
later preserves these bodies for PR context before squashing them.
## Step 13: CHANGELOG (auto-generate)
1. Read `CHANGELOG.md` header to know the format.
@@ -2793,25 +2768,7 @@ Never turn dropped scope into TODOs or invent unapproved follow-ups. Reuse match
## Step 15: Commit (bisectable chunks)
### Step 15.0: Preserve checkpoint context
Run `$GSTACK_ROOT/bin/gstack-config get checkpoint_mode`. `continuous` means automatic `WIP:`
checkpoint commits; any other value skips WIP consolidation. In continuous mode,
count `WIP:` commits in `origin/<base>..HEAD`. If none exist, skip Step 15.2.
Otherwise preserve their context before committing or rewriting history:
```bash
mkdir -p "$(git rev-parse --show-toplevel)/.gstack"
git log origin/<base>..HEAD --grep="^WIP:" --format="%H%n%B%n---END---" > \
"$(git rev-parse --show-toplevel)/.gstack/wip-context-before-squash.md"
```
If export fails, do not rewrite history. Step 13 already read these bodies for
CHANGELOG; retain this PR context locally, outside commits.
### Step 15.1: Bisectable Commits
Create small, logical commits for `git bisect`. If all changes are already committed, continue to Step 15.2; never create an empty commit.
Create small, logical commits for `git bisect`. If all changes are already committed, continue to Step 16; never create an empty commit.
1. Group by coherent change. Keep each model/service/controller with its tests;
keep controller views together. Migrations may stand alone or accompany their
@@ -2832,48 +2789,6 @@ EOF
)"
```
### Step 15.2: Consolidate WIP commits when safe
After Step 15.1, run only for continuous-mode WIP commits. Require a clean working
tree except the context export. Run `git fetch origin`; failure means STOP.
Inspect `WIP_BASE..HEAD`, where `WIP_BASE` is `git merge-base HEAD origin/<base>`:
- **merge commits:** do not replay or flatten Step 3's integration merge.
- **published commits** (`git branch -r --contains <sha>` returns a ref): never rewrite.
- For either, ask to preserve WIP history and continue to Step 16 (recommended),
or stop for manual consolidation. Never rebase or force-push these paths.
For a linear, unpublished range, prepare and inspect an oldest-first todo.
Keep non-WIP commits as `pick` in relative order; put each WIP after its verified
logical target as `fixup`. Include every commit exactly once. An ambiguous or
out-of-range target needs a preserve-history/stop decision. First entry stays
`pick` or `reword`; all-WIP ranges retain a logical `reword` anchor. Rewording
requires a noninteractive `WIP_EDITOR` script that writes descriptive messages;
picks/fixups alone use `true`. Set the reviewed todo's absolute path below:
```bash
export WIP_TODO="<absolute path to prepared todo>"
test -s "$WIP_TODO" || exit 1
WIP_BASE=$(git merge-base HEAD origin/<base>) || exit 1
test -z "$(git status --porcelain -- . ':(exclude).gstack/wip-context-before-squash.md')" || exit 1
test -z "$(git rev-list --merges "$WIP_BASE"..HEAD)" || exit 1
for sha in $(git rev-list "$WIP_BASE"..HEAD); do
test -z "$(git branch -r --contains "$sha")" || exit 1
done
ORIGINAL_TREE=$(git rev-parse 'HEAD^{tree}')
GIT_EDITOR="${WIP_EDITOR:-true}" GIT_SEQUENCE_EDITOR='cp "$WIP_TODO"' git rebase -i "$WIP_BASE" || {
git rebase --abort
echo "STATUS: BLOCKED — WIP consolidation conflicted; original history restored"
exit 1
}
test "$ORIGINAL_TREE" = "$(git rev-parse 'HEAD^{tree}')" || {
echo "STATUS: BLOCKED — consolidation changed contents; inspect before continuing"
exit 1
}
```
Only an unchanged tree after successful consolidation may proceed to Step 16.
---
## Step 16: Verification Gate
@@ -2902,14 +2817,19 @@ Step 7 tests, review fixes, and Step 14 TODO edits intentionally make evidence S
- **Every line FRESH (exit 0):** recorded runs passed on identical content except
the listed release files. Cite label, exit, timestamp, and log path; continue.
- **Any STALE/MISSING (exit non-zero):** rerun the stale/missing lanes on final
content, wrapped as `$GSTACK_ROOT/bin/gstack-evidence run --label <lane> -- '<command>'`.
Read results and recheck once. A content, command, or age mismatch requires
relevant fresh verification. If the ledger alone cannot record or verify a
successful live run, confirm unchanged final content and cite the exact command,
exit, and log; report ledger unavailable and continue, but never label the ledger FRESH.
If unchanged content cannot be confirmed, STOP. Do not rerun green suites solely for bookkeeping.
A failed CHECK selects live verification: a failed CHECK never blocks; a failed RUN does, except for the explicit triage waiver below.
- **Any STALE/MISSING (exit non-zero):** inspect the reason before choosing recovery:
- **Content, command or age mismatch, or no passing live evidence:** rerun the
affected lanes on final content, wrapped as `$GSTACK_ROOT/bin/gstack-evidence run --label <lane> -- '<command>'`.
Read results and recheck once. TODO edits and generated tests are content
changes, not ledger-only bookkeeping.
- **Ledger read/write failure only:** if a successful live run already covers
the unchanged final content, exact command and permitted age, cite its exit,
timestamp and log directly. Report ledger unavailable and continue, never
ledger FRESH. Do not rerun green suites solely because the ledger cannot save
or read its record. If unchanged content cannot be confirmed, STOP.
A failed CHECK identifies evidence to repair; it is not a test failure. The
required live RUN must pass, except for the explicit triage waiver below.
Paste build and rerun results. Later code, test, or build-input changes return
through this gate before pushing. Step 18 owns validation of its post-push
File diff suppressed because one or more lines are too long
@@ -0,0 +1,87 @@
{
"source": "CI run 36048177576, shared-libs-review-index-flags, merge ref 1215f799 (head b1dc44e7)",
"cases": [
{
"attempt": 1,
"input": {
"questions": [
{
"question": "1 advisory needs your input (no defects were found).\n\n1. [ADVISORY] src/retry-worker.ts:2 — The diff replaces `export { retrySeconds } from '../lib/retry-after'` with a byte-identical inline copy of the helper. src/retry-route.ts:2 (raw file; hidden from `git diff` by its assume-unchanged flag) carries the same copy. lib/retry-after.ts:2 is the proven helper, already used by src/scheduler.ts:1 and covered by test/retry-after.test.ts (`retry parser contract`).\n Fix: restore the one-line re-export in the worker and replace the route's copy with the same re-export. Est. implementation: −32 / +2 lines (≈30 saved); no new tests needed; shared-failure blast radius = scheduler + worker + route, all same TS package, no runtime/deployment boundary crossed.\n\nRECOMMENDATION: Fix both callers — the helper already exists and is tested, and the copies preserve no differences.\n\nHow do you want to handle this?",
"header": "Advisory",
"options": [
{
"label": "Fix both callers (Recommended)",
"description": "Restore `export { retrySeconds } from '../lib/retry-after'` in src/retry-worker.ts and src/retry-route.ts."
},
{
"label": "Fix worker only",
"description": "Only revert src/retry-worker.ts (the file in the diff); leave src/retry-route.ts as-is."
},
{
"label": "Skip",
"description": "Keep the duplicated copies. Recorded as an explicit skip for this snapshot."
}
],
"multiSelect": false
},
{
"question": "src/retry-route.ts has the Git assume-unchanged index bit set (`git ls-files -v` shows `h`). This hides real edits to that file from `git diff`, `git status`, and the review fingerprint — which is exactly why the prior skipped decision could not be trusted. Should I clear it?",
"header": "Index flag",
"options": [
{
"label": "Clear the flag (Recommended)",
"description": "Run `git update-index --no-assume-unchanged src/retry-route.ts` so the file's changes become visible to Git and future reviews."
},
{
"label": "Leave it",
"description": "Do not touch the index. I will note it in the summary; the path stays excluded from reusable coverage."
}
],
"multiSelect": false
}
]
}
},
{
"attempt": 2,
"input": {
"questions": [
{
"question": "Pre-Landing Review: 0 issues (0 critical, 0 informational). 1 advisory needs your input:\n\n1. [ADVISORY] src/retry-worker.ts:2 — This diff replaces the worker's re-export of lib/retry-after.ts with a byte-identical inline copy of `retrySeconds`; src/retry-route.ts:2 carries a third identical copy. lib/retry-after.ts is already used by src/scheduler.ts and tested by test/retry-after.test.ts ('retry parser contract').\n Fix: restore `export { retrySeconds } from '../lib/retry-after';` in retry-worker.ts and apply the same one-line re-export in retry-route.ts. Impl: −30/+2 = 28 lines saved; no new tests needed (existing contract test covers the helper); shared-failure blast radius = scheduler + worker + route (scheduler already depends on it).\n\nRECOMMENDATION: Fix both — the worker change is a regression of existing reuse, and the route copy is the same contract. (Prior skip on this branch could not be reused: src/retry-route.ts is assume-unchanged and its raw bytes differ from the snapshot.)\n\nHow should I handle the advisory?",
"header": "Advisory",
"multiSelect": false,
"options": [
{
"label": "Fix both files (Recommended)",
"description": "Re-export retrySeconds from lib/retry-after.ts in both src/retry-worker.ts and src/retry-route.ts (−28 lines)."
},
{
"label": "Fix worker only",
"description": "Restore the re-export in src/retry-worker.ts (revert this diff); leave src/retry-route.ts's copy in place."
},
{
"label": "Skip",
"description": "Keep the inline copies as-is; record the advisory as skipped."
}
]
},
{
"question": "src/retry-route.ts is flagged assume-unchanged in the Git index (`git ls-files -v` shows `h`), so its on-disk edit (an appended comment) is invisible to `git status`/`git diff` and to the review snapshot. Should I clear that flag?",
"header": "Index flag",
"multiSelect": false,
"options": [
{
"label": "Clear the flag (Recommended)",
"description": "Run `git update-index --no-assume-unchanged src/retry-route.ts` so Git and future reviews see the file's real contents."
},
{
"label": "Leave it",
"description": "Don't touch the index flag; I'll note it in the review summary and exclude the path from reusable coverage."
}
]
}
]
}
}
]
}