From cd62fb662c0f41e7b28ddbbae79b181d95bf4da5 Mon Sep 17 00:00:00 2001 From: garrytan Date: Thu, 15 Oct 2026 00:11:32 +0000 Subject: [PATCH] fix(ship): link issues by intent at publish and handoff; Fixes: trailer at commit (Lane D: D1, D2, D-a) - Step 15: a commit fixing a user-named issue carries a `Fixes: #` trailer (offset by tightening Step 15 so the skeleton stays at 80,998 <= 81,000). - pr-body: an explicit "Issue links" step runs gstack-issue-links before the body is composed (previously only a placeholder inside the body template); interactive runs ask once about `(promote: fix #N)` references and add `--supersedes`/`--credit` only on the owner's confirmation; unattended runs keep Refs and list unpromoted candidates, Related lines and lookup failures in the completion message; `ISSUE_LINKS_MISSING` from the receipt write. - handoff (no-PR lanes): runs gstack-issue-links and passes --issues to the receipt; the completion message gains an `issues:` line. - Regenerated ship/SKILL.md and sections; refreshed the four ship goldens. - Parity: union 309,431 / 187,706 = 1.6485 (> 1.6450 by 655 bytes); maxSizeRatio raised to the measured 1.6485 with its justification, as previous waves did. Files: ship/SKILL.md.tmpl, ship/SKILL.md, ship/sections/pr-body.md.tmpl, ship/sections/pr-body.md, ship/sections/handoff.md.tmpl, ship/sections/handoff.md, test/fixtures/golden/{claude,codex,factory,agy}-ship-SKILL.md, test/helpers/carve-guards.ts (ship maxSizeRatio). Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- bin/gstack-issue-links | 4 ++-- docs/pregate.md | 7 ++++--- lib/issue-links.ts | 13 +++++++------ ship/SKILL.md | 13 ++++++------- ship/SKILL.md.tmpl | 13 ++++++------- ship/sections/handoff.md | 6 ++++-- ship/sections/handoff.md.tmpl | 6 ++++-- ship/sections/pr-body.md | 15 +++++++++++---- ship/sections/pr-body.md.tmpl | 15 +++++++++++---- test/fixtures/golden/agy-ship-SKILL.md | 13 ++++++------- test/fixtures/golden/claude-ship-SKILL.md | 13 ++++++------- test/fixtures/golden/codex-ship-SKILL.md | 13 ++++++------- test/fixtures/golden/factory-ship-SKILL.md | 13 ++++++------- test/helpers/carve-guards.ts | 2 +- test/ship-issue-intent.test.ts | 9 ++++++--- 15 files changed, 86 insertions(+), 69 deletions(-) diff --git a/bin/gstack-issue-links b/bin/gstack-issue-links index f0fb03145..c44b59a25 100755 --- a/bin/gstack-issue-links +++ b/bin/gstack-issue-links @@ -34,8 +34,8 @@ const HELP = `gstack-issue-links — Fixes only on explicit closure intent; ever --base base branch (default: origin/HEAD, else main); commits origin/..HEAD are read --issue explicit closure intent (repeatable); still read through gstack-issue-guard --ci-run a failing CI run id (repeatable); bot flake issues of this repo naming it and a test become Flake: #N (run ) - --supersedes owner confirmed this PR supersedes a Related PR: Supersedes #N (@author) (repeatable) - --credit owner confirmed crediting a Related PR's author: Contributed by @author (#N) (repeatable) + --supersedes owner confirmed this PR supersedes a Related PR: Supersedes #N (repeatable) + --credit owner confirmed crediting a Related PR's author: Contributed by @author (repeatable) --no-auto-links no Related lookup (open PRs by other authors closing a fixed issue) --repo repository for gh (default: the current remote) --out write the issues object (fixes, refs, flakes, related) for gstack-ship-receipt write --issues @file diff --git a/docs/pregate.md b/docs/pregate.md index 757b1d373..ca7063f21 100644 --- a/docs/pregate.md +++ b/docs/pregate.md @@ -363,9 +363,10 @@ every refused match is printed with its reason. Open PRs by other authors (not the `gh` user, not this branch) whose closing set overlaps this PR's `Fixes` are `Related: #N (@author)`, read page by page -from each issue's closing-PR references, in unattended runs too. `Supersedes #N -(@author)` replaces that line and `Contributed by @author (#N)` is added only -with `--supersedes N` / `--credit N`, after the owner confirms. +from each issue's closing-PR references, in unattended runs too. `Supersedes #N` +replaces that line and `Contributed by @author` is added (the credit lines of +`lib/contributor-mode.ts`) only with `--supersedes N` / `--credit N`, after the +owner confirms. `--no-auto-links` skips the lookup. A failed lookup prints `ISSUE_LOOKUP_FAILED` and keeps the other lines. The stderr preview names the source of each line. diff --git a/lib/issue-links.ts b/lib/issue-links.ts index 4535364fb..fa90293ca 100644 --- a/lib/issue-links.ts +++ b/lib/issue-links.ts @@ -19,8 +19,9 @@ * `Flake: ` title): `Flake: #N (run )`. Duplicate test names * keep the lowest issue number. * - Open PRs by other authors that close an issue this PR fixes are - * `Related: #N (@author)`; `Supersedes` and `Contributed by` only with the - * owner's confirmation (--supersedes / --credit). + * `Related: #N (@author)`; `Supersedes #N` and `Contributed by @author` + * (lib/contributor-mode.ts credit lines) only with the owner's + * confirmation (--supersedes / --credit). */ export type IssueIntent = 'fixes' | 'refs'; @@ -163,8 +164,8 @@ export function renderIssueLines(links: IssueLinks): string[] { for (const c of links.cross) lines.push(`Refs ${c}`); for (const f of links.flakes) lines.push(`Flake: #${f.issue} (run ${f.run})`); for (const r of links.related ?? []) { - lines.push(`${r.supersedes ? 'Supersedes' : 'Related:'} ${prId(r)} (@${r.author})`); - if (r.credit) lines.push(`Contributed by @${r.author} (${prId(r)})`); + lines.push(r.supersedes ? `Supersedes ${prId(r)}` : `Related: ${prId(r)} (@${r.author})`); + if (r.credit) lines.push(`Contributed by @${r.author}`); } return lines; } @@ -175,8 +176,8 @@ export function lineSources(links: IssueLinks): string[] { for (const f of links.flakes) out.push(`Flake: #${f.issue} (run ${f.run}) ← bot flake issue for ${f.test ?? 'an unnamed test'}`); for (const r of links.related ?? []) { const closes = `open PR closing ${r.closes.map(n => `#${n}`).join(', ')}`; - out.push(`${r.supersedes ? 'Supersedes' : 'Related:'} ${prId(r)} (@${r.author}) ← ${closes}${r.supersedes ? '; owner confirmed --supersedes' : ''}`); - if (r.credit) out.push(`Contributed by @${r.author} (${prId(r)}) ← ${closes}; owner confirmed --credit`); + out.push(r.supersedes ? `Supersedes ${prId(r)} ← ${closes} by @${r.author}; owner confirmed --supersedes` : `Related: ${prId(r)} (@${r.author}) ← ${closes}`); + if (r.credit) out.push(`Contributed by @${r.author} ← ${prId(r)}, ${closes}; owner confirmed --credit`); } return out; } diff --git a/ship/SKILL.md b/ship/SKILL.md index 39ca8aa00..fcc7d06ae 100644 --- a/ship/SKILL.md +++ b/ship/SKILL.md @@ -887,15 +887,14 @@ No edits means an executed audit, not a skip; report the section's verified outc Make bisectable commits; if already committed, continue to Step 16. Never create an empty commit. -1. Group changes with their tests, config/routes, views and Step 14.5 docs. - Migrations may stand alone or accompany their model. - Under 50 lines across fewer than 4 files may be one commit. +1. Group changes with their tests, config/routes, views and Step 14.5 docs; + migrations may stand alone. Under 50 lines across fewer than 4 files may be one commit. 2. Order dependencies first: infrastructure → models/services → controllers/views. - Each commit must work on its own, without broken imports or missing code. + Each commit works alone (no broken imports or missing code). Group VERSION + CHANGELOG + TODOS.md after the feature commits. -3. Use `: ` (feat/fix/chore/refactor/docs) and a brief body. - Only the final VERSION/CHANGELOG commit gets the release version and co-author - trailer. Do not create a Git tag: +3. Use `: ` (feat/fix/chore/refactor/docs) and a brief body; fixing a + user-named issue adds a `Fixes: #` trailer. Only the final + VERSION/CHANGELOG commit gets the release version and co-author trailer. No Git tag: ```bash git commit -m "$(cat <<'EOF' diff --git a/ship/SKILL.md.tmpl b/ship/SKILL.md.tmpl index f568b7eaa..68021885b 100644 --- a/ship/SKILL.md.tmpl +++ b/ship/SKILL.md.tmpl @@ -350,15 +350,14 @@ No edits means an executed audit, not a skip; report the section's verified outc Make bisectable commits; if already committed, continue to Step 16. Never create an empty commit. -1. Group changes with their tests, config/routes, views and Step 14.5 docs. - Migrations may stand alone or accompany their model. - Under 50 lines across fewer than 4 files may be one commit. +1. Group changes with their tests, config/routes, views and Step 14.5 docs; + migrations may stand alone. Under 50 lines across fewer than 4 files may be one commit. 2. Order dependencies first: infrastructure → models/services → controllers/views. - Each commit must work on its own, without broken imports or missing code. + Each commit works alone (no broken imports or missing code). Group VERSION + CHANGELOG + TODOS.md after the feature commits. -3. Use `: ` (feat/fix/chore/refactor/docs) and a brief body. - Only the final VERSION/CHANGELOG commit gets the release version and co-author - trailer. Do not create a Git tag: +3. Use `: ` (feat/fix/chore/refactor/docs) and a brief body; fixing a + user-named issue adds a `Fixes: #` trailer. Only the final + VERSION/CHANGELOG commit gets the release version and co-author trailer. No Git tag: ```bash git commit -m "$(cat <<'EOF' diff --git a/ship/sections/handoff.md b/ship/sections/handoff.md index b576d3172..efcc24bc6 100644 --- a/ship/sections/handoff.md +++ b/ship/sections/handoff.md @@ -7,9 +7,10 @@ automation lane, an unattended parent said so). Nothing here publishes. 1. Verify-only checks: write Step 16's per-lane pass/fail/skip counts, naming the lanes that need a remote (`requires-remote`), to `.gstack/tmp/ship-gate.json` - as the pr-body section does, then: + as the pr-body section does, then (with its Issue links flags; ask nothing): ```bash - ~/.claude/skills/gstack/bin/gstack-ship-receipt write --base --gate @.gstack/tmp/ship-gate.json + ~/.claude/skills/gstack/bin/gstack-issue-links --base --out .gstack/tmp/issues.json + ~/.claude/skills/gstack/bin/gstack-ship-receipt write --base --gate @.gstack/tmp/ship-gate.json --issues @.gstack/tmp/issues.json ``` 2. Send the completion message, identifiers first, in this order: the `SHIP_RECEIPT:` line and receipt block (`pr: none`); `branch:` and `sha:` (`git rev-parse HEAD`), @@ -17,6 +18,7 @@ automation lane, an unattended parent said so). Nothing here publishes. cap; `before/after:` one row per claimed metric, measured on base and on this SHA with the command used; `escalation:` the one condition that stops the merge (a `requires-remote` lane, an open gate finding, an unverified claim) or `none`. + `issues:` its lines, unpromoted candidates and lookup failures. Full thread ids (`jam_…`) in any cross-thread reference, never a short code. Prose may follow the identifiers; nothing may precede them. 3. Skip Steps 19 and 21. Run Step 20 with `"version":null` when NO_VERSION applied. diff --git a/ship/sections/handoff.md.tmpl b/ship/sections/handoff.md.tmpl index 015198597..66758528b 100644 --- a/ship/sections/handoff.md.tmpl +++ b/ship/sections/handoff.md.tmpl @@ -5,9 +5,10 @@ automation lane, an unattended parent said so). Nothing here publishes. 1. Verify-only checks: write Step 16's per-lane pass/fail/skip counts, naming the lanes that need a remote (`requires-remote`), to `.gstack/tmp/ship-gate.json` - as the pr-body section does, then: + as the pr-body section does, then (with its Issue links flags; ask nothing): ```bash - ~/.claude/skills/gstack/bin/gstack-ship-receipt write --base --gate @.gstack/tmp/ship-gate.json + ~/.claude/skills/gstack/bin/gstack-issue-links --base --out .gstack/tmp/issues.json + ~/.claude/skills/gstack/bin/gstack-ship-receipt write --base --gate @.gstack/tmp/ship-gate.json --issues @.gstack/tmp/issues.json ``` 2. Send the completion message, identifiers first, in this order: the `SHIP_RECEIPT:` line and receipt block (`pr: none`); `branch:` and `sha:` (`git rev-parse HEAD`), @@ -15,6 +16,7 @@ automation lane, an unattended parent said so). Nothing here publishes. cap; `before/after:` one row per claimed metric, measured on base and on this SHA with the command used; `escalation:` the one condition that stops the merge (a `requires-remote` lane, an open gate finding, an unverified claim) or `none`. + `issues:` its lines, unpromoted candidates and lookup failures. Full thread ids (`jam_…`) in any cross-thread reference, never a short code. Prose may follow the identifiers; nothing may precede them. 3. Skip Steps 19 and 21. Run Step 20 with `"version":null` when NO_VERSION applied. diff --git a/ship/sections/pr-body.md b/ship/sections/pr-body.md index 5bcfe857e..3c8a95c3d 100644 --- a/ship/sections/pr-body.md +++ b/ship/sections/pr-body.md @@ -56,6 +56,14 @@ then return here for a new lookup and a fresh body before publishing. and names the remaining work; never auto-close it. Include the archive filename and `spec_filed_at`, not a private absolute path; `gstack-post` scans them with the body. +### Issue links + +Run `~/.claude/skills/gstack/bin/gstack-issue-links --base --out .gstack/tmp/issues.json`, adding +`--issue ` per issue the user named as fixed and `--ci-run ` per failing CI run. Interactive: +ask once about its `(promote: fix #N)` references (each `fix #` reply adds `--issue `), and add +`--supersedes `/`--credit ` for a `Related:` PR only when the owner confirms; rerun after any change. +The completion message lists unpromoted candidates, `Related:` lines and any `ISSUE_LOOKUP_FAILED`. + The PR/MR body should contain these sections (never reuse a prior run's body): ``` @@ -118,9 +126,7 @@ unavailable results as passing.> Without a valid match, omit this entire section.> ## Issues - [--issue ] [--ci-run ] --out .gstack/tmp/issues.json` -prints: Fixes only from a Fixes/Closes trailer or --issue, Refs otherwise, -Flake: #N for failing run ids. Omit when it prints none.> + ## Verification Results ":{"pass":N,"fail":N,"skip":N}}`) to Add `--receipt .gstack/tmp/tree-receipt.json` only when Step 16 wrote it (gate-ahead). New PR/MR: omit `--pr`, then rerun with the number after creation and repost the body. Its `SHIP_RECEIPT:` line opens the completion message. `RECEIPT_INVALID` names the bad -field: fix that input file and rerun; nothing was written. `PREGATE_STALE` means rerun +field: fix that input file and rerun; nothing was written. `ISSUE_LINKS_MISSING`: add +the named line under `## Issues` and rerun. `PREGATE_STALE` means rerun `gstack-pregate` on the stamped tree; `PREGATE_REMOTE_UNCLEARED` needs `gstack-pregate clear` with the run URL. Both stop publication. diff --git a/ship/sections/pr-body.md.tmpl b/ship/sections/pr-body.md.tmpl index 7d4200e98..0b37b036b 100644 --- a/ship/sections/pr-body.md.tmpl +++ b/ship/sections/pr-body.md.tmpl @@ -47,6 +47,14 @@ then return here for a new lookup and a fresh body before publishing. and names the remaining work; never auto-close it. Include the archive filename and `spec_filed_at`, not a private absolute path; `gstack-post` scans them with the body. +### Issue links + +Run `~/.claude/skills/gstack/bin/gstack-issue-links --base --out .gstack/tmp/issues.json`, adding +`--issue ` per issue the user named as fixed and `--ci-run ` per failing CI run. Interactive: +ask once about its `(promote: fix #N)` references (each `fix #` reply adds `--issue `), and add +`--supersedes `/`--credit ` for a `Related:` PR only when the owner confirms; rerun after any change. +The completion message lists unpromoted candidates, `Related:` lines and any `ISSUE_LOOKUP_FAILED`. + The PR/MR body should contain these sections (never reuse a prior run's body): ``` @@ -109,9 +117,7 @@ unavailable results as passing.> Without a valid match, omit this entire section.> ## Issues - [--issue ] [--ci-run ] --out .gstack/tmp/issues.json` -prints: Fixes only from a Fixes/Closes trailer or --issue, Refs otherwise, -Flake: #N for failing run ids. Omit when it prints none.> + ## Verification Results ":{"pass":N,"fail":N,"skip":N}}`) to Add `--receipt .gstack/tmp/tree-receipt.json` only when Step 16 wrote it (gate-ahead). New PR/MR: omit `--pr`, then rerun with the number after creation and repost the body. Its `SHIP_RECEIPT:` line opens the completion message. `RECEIPT_INVALID` names the bad -field: fix that input file and rerun; nothing was written. `PREGATE_STALE` means rerun +field: fix that input file and rerun; nothing was written. `ISSUE_LINKS_MISSING`: add +the named line under `## Issues` and rerun. `PREGATE_STALE` means rerun `gstack-pregate` on the stamped tree; `PREGATE_REMOTE_UNCLEARED` needs `gstack-pregate clear` with the run URL. Both stop publication. diff --git a/test/fixtures/golden/agy-ship-SKILL.md b/test/fixtures/golden/agy-ship-SKILL.md index 6ccbd249d..2ebc23f34 100644 --- a/test/fixtures/golden/agy-ship-SKILL.md +++ b/test/fixtures/golden/agy-ship-SKILL.md @@ -882,15 +882,14 @@ No edits means an executed audit, not a skip; report the section's verified outc Make bisectable commits; if already committed, continue to Step 16. Never create an empty commit. -1. Group changes with their tests, config/routes, views and Step 14.5 docs. - Migrations may stand alone or accompany their model. - Under 50 lines across fewer than 4 files may be one commit. +1. Group changes with their tests, config/routes, views and Step 14.5 docs; + migrations may stand alone. Under 50 lines across fewer than 4 files may be one commit. 2. Order dependencies first: infrastructure → models/services → controllers/views. - Each commit must work on its own, without broken imports or missing code. + Each commit works alone (no broken imports or missing code). Group VERSION + CHANGELOG + TODOS.md after the feature commits. -3. Use `: ` (feat/fix/chore/refactor/docs) and a brief body. - Only the final VERSION/CHANGELOG commit gets the release version and co-author - trailer. Do not create a Git tag: +3. Use `: ` (feat/fix/chore/refactor/docs) and a brief body; fixing a + user-named issue adds a `Fixes: #` trailer. Only the final + VERSION/CHANGELOG commit gets the release version and co-author trailer. No Git tag: ```bash git commit -m "$(cat <<'EOF' diff --git a/test/fixtures/golden/claude-ship-SKILL.md b/test/fixtures/golden/claude-ship-SKILL.md index 39ca8aa00..fcc7d06ae 100644 --- a/test/fixtures/golden/claude-ship-SKILL.md +++ b/test/fixtures/golden/claude-ship-SKILL.md @@ -887,15 +887,14 @@ No edits means an executed audit, not a skip; report the section's verified outc Make bisectable commits; if already committed, continue to Step 16. Never create an empty commit. -1. Group changes with their tests, config/routes, views and Step 14.5 docs. - Migrations may stand alone or accompany their model. - Under 50 lines across fewer than 4 files may be one commit. +1. Group changes with their tests, config/routes, views and Step 14.5 docs; + migrations may stand alone. Under 50 lines across fewer than 4 files may be one commit. 2. Order dependencies first: infrastructure → models/services → controllers/views. - Each commit must work on its own, without broken imports or missing code. + Each commit works alone (no broken imports or missing code). Group VERSION + CHANGELOG + TODOS.md after the feature commits. -3. Use `: ` (feat/fix/chore/refactor/docs) and a brief body. - Only the final VERSION/CHANGELOG commit gets the release version and co-author - trailer. Do not create a Git tag: +3. Use `: ` (feat/fix/chore/refactor/docs) and a brief body; fixing a + user-named issue adds a `Fixes: #` trailer. Only the final + VERSION/CHANGELOG commit gets the release version and co-author trailer. No Git tag: ```bash git commit -m "$(cat <<'EOF' diff --git a/test/fixtures/golden/codex-ship-SKILL.md b/test/fixtures/golden/codex-ship-SKILL.md index 9b69f681c..a7c6621b6 100644 --- a/test/fixtures/golden/codex-ship-SKILL.md +++ b/test/fixtures/golden/codex-ship-SKILL.md @@ -907,15 +907,14 @@ No edits means an executed audit, not a skip; report the section's verified outc Make bisectable commits; if already committed, continue to Step 16. Never create an empty commit. -1. Group changes with their tests, config/routes, views and Step 14.5 docs. - Migrations may stand alone or accompany their model. - Under 50 lines across fewer than 4 files may be one commit. +1. Group changes with their tests, config/routes, views and Step 14.5 docs; + migrations may stand alone. Under 50 lines across fewer than 4 files may be one commit. 2. Order dependencies first: infrastructure → models/services → controllers/views. - Each commit must work on its own, without broken imports or missing code. + Each commit works alone (no broken imports or missing code). Group VERSION + CHANGELOG + TODOS.md after the feature commits. -3. Use `: ` (feat/fix/chore/refactor/docs) and a brief body. - Only the final VERSION/CHANGELOG commit gets the release version and co-author - trailer. Do not create a Git tag: +3. Use `: ` (feat/fix/chore/refactor/docs) and a brief body; fixing a + user-named issue adds a `Fixes: #` trailer. Only the final + VERSION/CHANGELOG commit gets the release version and co-author trailer. No Git tag: ```bash git commit -m "$(cat <<'EOF' diff --git a/test/fixtures/golden/factory-ship-SKILL.md b/test/fixtures/golden/factory-ship-SKILL.md index ec1c7ebef..7ca7cc393 100644 --- a/test/fixtures/golden/factory-ship-SKILL.md +++ b/test/fixtures/golden/factory-ship-SKILL.md @@ -888,15 +888,14 @@ No edits means an executed audit, not a skip; report the section's verified outc Make bisectable commits; if already committed, continue to Step 16. Never create an empty commit. -1. Group changes with their tests, config/routes, views and Step 14.5 docs. - Migrations may stand alone or accompany their model. - Under 50 lines across fewer than 4 files may be one commit. +1. Group changes with their tests, config/routes, views and Step 14.5 docs; + migrations may stand alone. Under 50 lines across fewer than 4 files may be one commit. 2. Order dependencies first: infrastructure → models/services → controllers/views. - Each commit must work on its own, without broken imports or missing code. + Each commit works alone (no broken imports or missing code). Group VERSION + CHANGELOG + TODOS.md after the feature commits. -3. Use `: ` (feat/fix/chore/refactor/docs) and a brief body. - Only the final VERSION/CHANGELOG commit gets the release version and co-author - trailer. Do not create a Git tag: +3. Use `: ` (feat/fix/chore/refactor/docs) and a brief body; fixing a + user-named issue adds a `Fixes: #` trailer. Only the final + VERSION/CHANGELOG commit gets the release version and co-author trailer. No Git tag: ```bash git commit -m "$(cat <<'EOF' diff --git a/test/helpers/carve-guards.ts b/test/helpers/carve-guards.ts index eab2463f8..4341826e4 100644 --- a/test/helpers/carve-guards.ts +++ b/test/helpers/carve-guards.ts @@ -168,7 +168,7 @@ export const CARVE_GUARDS: Record = { // wave's headline capability) grows the union to 1.195x. Deliberate: // the section is on-demand (loads only for Apple store targets), so // per-invocation cost for non-iOS ships is one manifest line. - maxSizeRatio: 1.6450, // Shared advisory identity/dedup + critical-severity validation: 248,065 union bytes / 187,706 baseline = 1.3216 (2026-09-17). + test value bar in the lazy Step 7 section (value cards, weak paths, gate table, base control, machine checks; ~13.6KB): measured 1.396 (2026-09-29). + W1 guarded state-root resolution (`eval gstack-paths; : "${GSTACK_STATE_ROOT:?…}"`) in the Context Recovery preamble, the eureka log and each state-writing bash block; measured 1.401 (2026-09-30). + the shared QA review step's plan-check timing rule (plan checks and their revalidation run on --timeout-ms after smoke expiry); measured 1.4022 (2026-09-30). + the shared TEST_BOOTSTRAP owned-change undo rules (s03 H1-H3, M1) and the value-bar coverage wording (s03 M2/M3); measured 1.4044 (2026-10-02). + severe fix wave ship-review lane: G1 NO_VERSION dispatch, title and CHANGELOG arms (versionless repos ship without inventing a version), F1 parent-side plan binding before the audit dispatch (binding, docs/designs candidates, exact not-run line) and D3's data-not-instructions line; +2,126 union bytes, measured 1.4135 (2026-10-03). + INV-1 consumer lines (outside review `unverified`/`unavailable` is missing coverage in the readiness note and PR body); measured 1.4148 (2026-10-03). + v1.91.19.0 severe fix wave: verdict-form outside-review callers with sandbox preflight and first-use notice (INV-1/B1/Q2), P0/P1 gate and unverified wording, bound-plan discovery (F1), visible LEARNINGS failures (B5), carved external pointers; measured 267,752 / 187,706 = 1.4264 (2026-10-03). + v1.91.18.0 (#3023) merged into the v1.91.19.0 wave; measured 267,874 / 187,706 = 1.4271 (2026-10-04). + Oct 6 fix wave: quota_exhausted preflight branch (#3051) and quoted-heredoc issue template (#3046); measured 268,199 / 187,706 = 1.4288 (2026-10-06). + Step 10's inline no-PR check before the Greptile dispatch (#3020); measured 268,655 / 187,706 = 1.4313 (2026-10-06). + Oct 6 fix wave A3/CEO-12: free text reaches commands only through agent-written mktemp files (mktemp block, write rule, path rebuild and refusal at each posting, prompt and brief site); measured 275,422 / 187,706 = 1.4673 (2026-10-06). Combined Oct 6 wave head (B free-text files + D measure loop + A rework): measured 280,363 / 187,706 = 1.4936 (2026-10-06). + gate-once push rule (no second paid gate after a CI push); measured 280,573 / 187,706 = 1.4947 (2026-10-06). + the measurement bar's decision step (exit-code branches for MEETS, MEETS-qualified, needs-classify with the qualifying and fix-round classes, EXTEND once; the measure prose was tightened to offset most of it); measured 281,058 / 187,706 = 1.4973 (2026-10-06). + Oct 7 wave B3: the Codex probe runs as a command (select-model capture lines, check-sandbox/probe-model/run-with-timeout subcommands) instead of being sourced; measured 281,438 / 187,706 = 1.4994 (2026-10-07). + Oct 7 wave CEO-28/DX-11: review prompts ask for a severity per finding and design proposals use the proposal gate; measured 281,556 / 187,706 = 1.5000 (2026-10-07). + Oct 7 wave B4: /ship publishes through gstack-post (title prepared in a file in the pr-body section, compose block plus gstack-post exit-code branches replacing the two scans); measured 281,894 / 187,706 = 1.5018 (2026-10-07). + B2 early Greptile PR (lazy Step 6.5 section: detect, public-repo consent, push, provisional title file, open; Step 10's bounded wait; the stop-leaves-the-draft rule); measured 286,626 / 187,706 = 1.5270 (2026-10-07). B3, the classifier, B4 and B2 merged: measured 287,128 / 187,706 = 1.5297 (2026-10-07). + Oct 7 wave guard (CEO-20): conditional `run_in_background` request plus the background-run recovery at each foreground dispatch site; measured 281,370 / 187,706 = 1.4990 (2026-10-07). Merged with the guard area: measured 287,440 / 187,706 = 1.5313 (2026-10-07). + Oct 8 wave: the defensive-security framing and fixture summary mode reach the security specialist and the Red Team (stated once in the dispatch, referenced by the Red Team); measured 288,783 / 187,706 = 1.5385 (2026-10-08). + gate integrity (HONEST_WORK_GATE_INTEGRITY W3): the shared GATE_SCAN_BLOCK in the core checklist (2.5) and after Step 7's child, the four-option gate question and record fields in 9.4, tests_ran states in Step 5, Gate edits and per-lane counts in the PR body with draft-while-open; measured 300,143 / 187,706 = 1.5990 (2026-10-10). + Honest Work wave merged (W2/W3 gate integrity in review/ship, W4 kernel + DONE line in every tier-2+ skill, W5/W7 in spec/ship): re-measured on the integrated tree (2026-10-10). + Oct 10 multi-agent wave PR E2 (ship/sections/handoff.md: the no-PR automation handoff, with its Section-index row and STOP pointer in the skeleton), offset by tightening Steps 1–3, 12, 14–17 and 20–21 prose so the skeleton stays under 81,000 bytes (80,997); C-pregate landed 1,123 union bytes in tests.md in between; measured 308,619 / 187,706 = 1.6442 on the integrated tree (2026-10-10). + maxSizeRatio: 1.6485, // Shared advisory identity/dedup + critical-severity validation: 248,065 union bytes / 187,706 baseline = 1.3216 (2026-09-17). + test value bar in the lazy Step 7 section (value cards, weak paths, gate table, base control, machine checks; ~13.6KB): measured 1.396 (2026-09-29). + W1 guarded state-root resolution (`eval gstack-paths; : "${GSTACK_STATE_ROOT:?…}"`) in the Context Recovery preamble, the eureka log and each state-writing bash block; measured 1.401 (2026-09-30). + the shared QA review step's plan-check timing rule (plan checks and their revalidation run on --timeout-ms after smoke expiry); measured 1.4022 (2026-09-30). + the shared TEST_BOOTSTRAP owned-change undo rules (s03 H1-H3, M1) and the value-bar coverage wording (s03 M2/M3); measured 1.4044 (2026-10-02). + severe fix wave ship-review lane: G1 NO_VERSION dispatch, title and CHANGELOG arms (versionless repos ship without inventing a version), F1 parent-side plan binding before the audit dispatch (binding, docs/designs candidates, exact not-run line) and D3's data-not-instructions line; +2,126 union bytes, measured 1.4135 (2026-10-03). + INV-1 consumer lines (outside review `unverified`/`unavailable` is missing coverage in the readiness note and PR body); measured 1.4148 (2026-10-03). + v1.91.19.0 severe fix wave: verdict-form outside-review callers with sandbox preflight and first-use notice (INV-1/B1/Q2), P0/P1 gate and unverified wording, bound-plan discovery (F1), visible LEARNINGS failures (B5), carved external pointers; measured 267,752 / 187,706 = 1.4264 (2026-10-03). + v1.91.18.0 (#3023) merged into the v1.91.19.0 wave; measured 267,874 / 187,706 = 1.4271 (2026-10-04). + Oct 6 fix wave: quota_exhausted preflight branch (#3051) and quoted-heredoc issue template (#3046); measured 268,199 / 187,706 = 1.4288 (2026-10-06). + Step 10's inline no-PR check before the Greptile dispatch (#3020); measured 268,655 / 187,706 = 1.4313 (2026-10-06). + Oct 6 fix wave A3/CEO-12: free text reaches commands only through agent-written mktemp files (mktemp block, write rule, path rebuild and refusal at each posting, prompt and brief site); measured 275,422 / 187,706 = 1.4673 (2026-10-06). Combined Oct 6 wave head (B free-text files + D measure loop + A rework): measured 280,363 / 187,706 = 1.4936 (2026-10-06). + gate-once push rule (no second paid gate after a CI push); measured 280,573 / 187,706 = 1.4947 (2026-10-06). + the measurement bar's decision step (exit-code branches for MEETS, MEETS-qualified, needs-classify with the qualifying and fix-round classes, EXTEND once; the measure prose was tightened to offset most of it); measured 281,058 / 187,706 = 1.4973 (2026-10-06). + Oct 7 wave B3: the Codex probe runs as a command (select-model capture lines, check-sandbox/probe-model/run-with-timeout subcommands) instead of being sourced; measured 281,438 / 187,706 = 1.4994 (2026-10-07). + Oct 7 wave CEO-28/DX-11: review prompts ask for a severity per finding and design proposals use the proposal gate; measured 281,556 / 187,706 = 1.5000 (2026-10-07). + Oct 7 wave B4: /ship publishes through gstack-post (title prepared in a file in the pr-body section, compose block plus gstack-post exit-code branches replacing the two scans); measured 281,894 / 187,706 = 1.5018 (2026-10-07). + B2 early Greptile PR (lazy Step 6.5 section: detect, public-repo consent, push, provisional title file, open; Step 10's bounded wait; the stop-leaves-the-draft rule); measured 286,626 / 187,706 = 1.5270 (2026-10-07). B3, the classifier, B4 and B2 merged: measured 287,128 / 187,706 = 1.5297 (2026-10-07). + Oct 7 wave guard (CEO-20): conditional `run_in_background` request plus the background-run recovery at each foreground dispatch site; measured 281,370 / 187,706 = 1.4990 (2026-10-07). Merged with the guard area: measured 287,440 / 187,706 = 1.5313 (2026-10-07). + Oct 8 wave: the defensive-security framing and fixture summary mode reach the security specialist and the Red Team (stated once in the dispatch, referenced by the Red Team); measured 288,783 / 187,706 = 1.5385 (2026-10-08). + gate integrity (HONEST_WORK_GATE_INTEGRITY W3): the shared GATE_SCAN_BLOCK in the core checklist (2.5) and after Step 7's child, the four-option gate question and record fields in 9.4, tests_ran states in Step 5, Gate edits and per-lane counts in the PR body with draft-while-open; measured 300,143 / 187,706 = 1.5990 (2026-10-10). + Honest Work wave merged (W2/W3 gate integrity in review/ship, W4 kernel + DONE line in every tier-2+ skill, W5/W7 in spec/ship): re-measured on the integrated tree (2026-10-10). + Oct 10 multi-agent wave PR E2 (ship/sections/handoff.md: the no-PR automation handoff, with its Section-index row and STOP pointer in the skeleton), offset by tightening Steps 1–3, 12, 14–17 and 20–21 prose so the skeleton stays under 81,000 bytes (80,997); C-pregate landed 1,123 union bytes in tests.md in between; measured 308,619 / 187,706 = 1.6442 on the integrated tree (2026-10-10). + next-wave Lane D (GBRA-40 item 12): the pr-body Issue links step (promotion candidates and `fix #N`, owner-confirmed Supersedes/credit, lookup failures, ISSUE_LINKS_MISSING) and the handoff's issue-links run, with the `## Issues` placeholder shortened; Step 15's `Fixes:` trailer rule offset by tightening Step 15 so the skeleton stays at 80,998; measured 309,431 / 187,706 = 1.6485 (2026-10-14). }, 'plan-ceo-review': { skill: 'plan-ceo-review', diff --git a/test/ship-issue-intent.test.ts b/test/ship-issue-intent.test.ts index ce6cbb127..ca92c734c 100644 --- a/test/ship-issue-intent.test.ts +++ b/test/ship-issue-intent.test.ts @@ -141,8 +141,11 @@ describe('related PRs (D2)', () => { expect(renderIssueLines(links)).toEqual(['Fixes #6252', 'Fixes #6275', 'Related: #6253 (@andreineacsu)', 'Related: #6299 (@ghost)', 'Related: forker/gbrain#12 (@forker)']); related[0]!.supersedes = true; related[0]!.credit = true; - expect(renderIssueLines(links).slice(2, 4)).toEqual(['Supersedes #6253 (@andreineacsu)', 'Contributed by @andreineacsu (#6253)']); - expect(lineSources(links)[0]).toBe('Supersedes #6253 (@andreineacsu) ← open PR closing #6252, #6275; owner confirmed --supersedes'); + expect(renderIssueLines(links).slice(2, 4)).toEqual(['Supersedes #6253', 'Contributed by @andreineacsu']); + expect(lineSources(links).slice(0, 2)).toEqual([ + 'Supersedes #6253 ← open PR closing #6252, #6275 by @andreineacsu; owner confirmed --supersedes', + 'Contributed by @andreineacsu ← #6253, open PR closing #6252, #6275; owner confirmed --credit', + ]); expect(resolveLinks([], [], () => true, [], [])).not.toHaveProperty('related'); }); }); @@ -166,7 +169,7 @@ describe('gstack-issue-links (bin): related PRs, flake validation, lookup failur const credited = runBin(repo, 'gstack-issue-links', ['--base', 'main', '--supersedes', '7', '--credit', '7', '--out', out, '--json'], env); expect(credited.status).toBe(EXIT.ok); const j = JSON.parse(credited.out); - expect(j.lines).toEqual(['Fixes #14', 'Refs #30', 'Supersedes #7 (@alice)', 'Contributed by @alice (#7)', 'Related: carol/repo#11 (@carol)']); + expect(j.lines).toEqual(['Fixes #14', 'Refs #30', 'Supersedes #7', 'Contributed by @alice', 'Related: carol/repo#11 (@carol)']); expect(j.candidates.map((c: { issue: number }) => c.issue)).toEqual([30]); expect(JSON.parse(fs.readFileSync(out, 'utf8'))).toEqual({ fixes: [14], refs: [30], flakes: [], related: [{ pr: 7, author: 'alice', closes: [14], supersedes: true, credit: true }, { pr: 11, repo: 'carol/repo', author: 'carol', closes: [14] }] }); expect(runBin(repo, 'gstack-issue-links', ['--base', 'main', '--supersedes', '99'], env)).toMatchObject({ status: EXIT.usage, err: expect.stringContaining('--supersedes #99 is not a Related PR (#7, carol/repo#11)') });