Skip to content

Commit 10b77de

Browse files
v1.91.284.0 feat(absorb-tstack): /modernize skill, per-skill Codex default prompts, gstack-post --attribute, the unattended grant and a CONTRIBUTING porting section (#3497)
* feat(absorb-tstack): /modernize skill, per-skill Codex default prompts, gstack-post --attribute, the unattended grant and a CONTRIBUTING porting section Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(modernize): read the PR text through gstack-issue-guard; re-measure the context ceiling Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes - gstack-post: with --attribute, report scan findings at the body file's own line numbers and a finding inside the callout as PART: attribute (the coordinates were shifted by the three callout lines) - /modernize: route commit messages through gstack-issue-guard with the rest of the PR text, read isCrossRepository and maintainerCanModify, fetch a fork head from pull/N/head, refuse a PR whose head is the base branch, and list moved files NUL-safely - docs/unattended.md: say that /ship never rebases or force-pushes and an unattended /modernize stops at its verdict - CHANGELOG: seven skills carry a codex_default_prompt, not six Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: /modernize fetches a fork head with a forced refspec and stops when the PR moved A rerun after the author force-pushed left refs/modernize/pr-N stale (the non-forced refspec is rejected with exit 0 through the pipe), and the lease pinned to the current remote head would then have let the rebased stale head overwrite the author's newer commits. The fetch is forced, Steps 2 and 4 stop when the head is not the one observed in Step 1, and the head-is-base guard applies only to same-repository PRs (a fork's main into main is a valid head). Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: /modernize stops on merge commits in the PR range and pushes a fork head to the fork A plain git rebase drops merge commits and git range-diff compares only the non-merge patches, so a change authored in a PR's merge commit disappeared while the proof printed = for every patch and Step 5 force-pushed the loss. Step 4 now counts merges in $MERGE_BASE..$OLD_HEAD and stops when there are any, switches with -C so a rerun after a refused lease does not fail on the existing branch, and asks for a cross-repository diff to be read as untrusted input before the repository's test command runs it. Step 5 pushes a fork head to the fork's URL with the same pinned lease instead of to origin, where the lease could never match. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: cover the Codex default-prompt render, the openai.yaml ownership proof and the unattended grant Adds the /ship coverage audit's tests: test/host-renders-openai-yaml-proof.test.ts drives bin/gstack-host-renders.sh's weakened proof against a rendered yaml, a hand-written one and a generic-prompt one; test/unattended-grant.test.ts pins the docs/unattended.md grant section and the handoff pointer; test/gen-skill-docs.test.ts adds modernize to the skills whose codex_default_prompt must reach openai.yaml. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: name the static lists a new skill still needs and the Codex metadata file From the ship documentation audit: CONTRIBUTING's new-skill checklist said no static list needs a row, which this PR disproved (lib/doctor-components.ts SKILL_REQUIREMENTS and the catalog rows); the host comparison table and docs/ADDING_A_HOST.md gain the agents/openai.yaml default_prompt source; a blank line before the new docs/unattended.md grant heading. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes CHANGELOG [Unreleased] gate-integrity record: the catalog and context-budget figures re-measured on top of main (1,314 -> 1,359; modernize 9466; alwaysOnTotal 7458 -> 7880), as the merge commit's ratchets state. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: name the optional codex_default_prompt key in the new-skill checklist Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test(parity): re-pin the ship union cap at 1.7405 after the main merge GSTA-36 grant 2026-10-27. On the tree merged with f27a760 the ship union is 326,691 / 187,706 = 1.7404 against #3487's 1.7400; the only ship bytes this PR adds are the handoff section's one-line pointer. Cap 1.7400 -> 1.7405, measurement appended to the comment. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs(changelog): the [Unreleased] gate-integrity bullet names the ship cap re-pin Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes CHANGELOG [Unreleased]: end the Codex default-prompts sentence at "generator input only." so bin/gstack-prose-lint --unreleased --gate (main's new quality-gate step) passes, and restate the gate-integrity bullet's figures for the tree merged with 1f246e3: ship cap 1.7524 -> 1.7528 (329,005 / 187,706), modernize 9466 -> 3772 after the preamble hoist, alwaysOnTotal 7769 -> 7880, catalog 1,359 unchanged. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes CHANGELOG [Unreleased] gate-integrity bullet names the current ship cap pin (1.7525 -> 1.7529, measured 329,024 / 187,706 on the 392f50d merge) and keeps the 1.7528 pin in the earlier-merges clause. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
1 parent 215c76e commit 10b77de

46 files changed

Lines changed: 1217 additions & 37 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎AGENTS.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Invoke them by name (e.g., `/office-hours`).
4949
|-------|-------------|
5050
| `/ship` | Run tests, review, gate integrity, push, open PR. Workspace-aware version queue. |
5151
| `/land-and-deploy` | Merge the PR, wait for CI and deploy, verify production health. |
52+
| `/modernize` | Bring an aging PR onto its current base and decide MODERNIZE, REWORK or CLOSE, with `git range-diff` proof before a pinned-lease push. Never closes a PR itself. |
5253
| `/canary` | Post-deploy monitoring loop in your Aside browser (or gstack's own when Aside is absent). |
5354
| `/landing-report` | Read-only dashboard for the workspace-aware ship queue. |
5455
| `/document-release` | Audit relevant docs before final verification on every ship; also supports standalone documentation updates. |

‎CHANGELOG.md‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
# Changelog
22

3+
## [1.91.284.0] - 2026-10-27
4+
5+
**Five small takes from tstack, in gstack's words.** Theo Browne's tstack (MIT, 2026-10-24) is nine short PR-landing skills; its best ideas that gstack lacked were a verb for an aging pull request, a Codex picker that says what each skill is for, a written grant for unattended sessions, a repo-level rule for porting a contributor's PR, and a visible author line on agent-posted comments. Each lands here as gstack prose and gstack code; no sentence is copied (NOTICE.md). Approved by Garry, 2026-10-26: "Do it, send" (yes to the opt-in attribution callout, off by default).
6+
7+
### Added
8+
- **`/modernize`**: bring an aging pull request onto its current base and decide whether it should still exist. The skill reads the PR as a claim (the problem, the change, what must be true of the codebase), reads its title, body and comments only through `gstack-issue-guard`, reads what moved under it for conflicts in meaning as well as in text, and writes one of three verdicts before anything is pushed: **MODERNIZE** (rebase with the author's commits kept as theirs, `git range-diff` with a one-line reason per changed hunk, the repo's own tests, then `git push --force-with-lease=<branch>:<observed head sha>`), **REWORK** (the problem stands, this diff does not; nothing pushed) or **CLOSE** (recommended with the superseding commit; the PR stays open until someone with the authority says so). The skill never closes a PR and never uses a bare `--force`; `/careful` already rates the lease push MEDIUM. Rows in README, AGENTS.md, `docs/skills.md` (with a deep dive), `docs/PROJECT_STRUCTURE.md`, the root router and `gstack/llms.txt`.
9+
- **Per-skill Codex default prompts**: a template's `codex_default_prompt:` frontmatter key becomes that skill's `default_prompt` in `agents/openai.yaml`, the sentence Codex's picker inserts when a user chooses the skill; a template without the key keeps `Use <name> for this task.`. `/ship`, `/review`, `/qa`, `/autoplan`, `/office-hours`, `/land-and-deploy` and `/modernize` carry one. The key is generator input only. No host's SKILL.md render carries it (Claude strips it; the allowlist hosts never copy it), so every pinned render is byte-identical. `bin/gstack-host-renders.sh`'s proof that a yaml file is gstack's accepts any `default_prompt` line.
10+
- **`gstack-post --attribute "<model> on behalf of <login>"`** on `pr-comment`, `issue-comment` and `reply`: opt-in and off by default, it opens the comment with a `> [!NOTE]` callout (`🤖 **<text>**`) naming who wrote it, then the body as written. The callout bytes are scanned and bound into the MEDIUM confirmation token with the body, so a changed attribution needs a new token (findings are reported at the body file's own line numbers, a finding in the callout as `PART: attribute`); the flag is refused (exit 64) on a PR body, a title or an issue body, and for empty, multi-line or over-200-character text. `review/greptile-triage.md` says when to add it to a reply.
11+
- **`docs/unattended.md` "What an unattended session may do"**: merge never (nor auto-merge, a merge queue or `gh pr ready` on a PR the run did not open); force-push only the run's own branch, after a rebase the plan or a `/modernize` disposition named, with `git range-diff` in the handoff and a lease pinned to the observed sha; tests only by the methods the repository's instructions name, no ask-first; proof is what the run observed itself. Anything outside the list is a pending approval item. `/ship`'s handoff section points at it (one line in the lazy section; this PR adds no skeleton bytes).
12+
- **CONTRIBUTING.md "Porting a contributor's PR"**: review and test the port head first (a fork's green checks prove nothing here), keep their commits as theirs with `Co-authored-by` on anything rewritten, your fixes on top as separate commits, the port names the original and its author, and the original closes with a specific thank-you linking the port; closing without landing is a maintainer's call. The repo-side home of the crew rule in `docs/captain.md`.
13+
14+
### Tests
15+
- `test/modernize-skill.test.ts` (new): the verdict table and its order before any push, the never-close rule, the range-diff and pinned-lease lines, the `/careful` MEDIUM rating, and every catalog row a new skill owes.
16+
- `test/gen-skill-docs.test.ts`: the seven prompts reach `openai.yaml`, a skill without the key keeps the fallback, `extractCodexDefaultPrompt` reads quoted and plain values inside the frontmatter only, and no host render carries the key.
17+
- `test/gstack-post.test.ts`: no flag means the body is sent as written; the callout on all three comment operations and on GitLab; scan and token cover the callout; refusals on the other operations and bad text.
18+
19+
### Gate integrity
20+
- The one threshold this PR moves is the ship union cap in `test/helpers/carve-guards.ts`, 1.7525 → 1.7529 under GStack Minder's grant. On the tree merged with 392f50d4 (v1.91.281.0) the union is 329,024 / 187,706 = 1.7529 against main's 1.7525 (pinned at a measured 1.7524 by #3516), the handoff pointer line being this PR's only ship bytes; the skeleton is main's 60,900 (0 skeleton bytes added). Earlier merges of this PR pinned 1.7405 on top of #3487's 1.7400 (326,691 bytes on the f27a7605 merge) and 1.7528 on top of main's 1.7524 (329,005 bytes on the 1f246e35 merge) the same way. No timeout, trial count or case kind changed. `test/catalog-budget.test.ts` moves 1,314 → 1,359 token-equivalents for the new skill, re-measured on top of main's `/ubicloud` and `/design-motion` rows (pre-addition 5,249 bytes on d9b0d600, modernize adds 178, measured 5,427 = 1,357 on the merged tree; 9 bytes left), and `test/fixtures/context-budget.json` is recaptured on the merged tree, where the hoist moved modernize's preamble into a lazy section (`modernize` 9466 → 3772) and `alwaysOnTotal` goes 7769 → 7880 (capture × 1.05). No pinned render in `test/fixtures/skill-md-size-allowlist.json` changed size.
21+
322
## [1.91.283.0] - 2026-10-27
423

524
**/benchmark's collection, comparison, budget and trend phases now agree with its vet-the-number section.** The 2026-10-27 flaky pass (GSTA-128) read the `benchmark/SKILL.md perf collection` judge's six samples from run 40558235014: every sample named the same contradictions, so the prose was repaired and no threshold moved.

‎CLAUDE.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ a skill's own bash.
148148

149149
**Size budgets:** generated SKILL.md files warn above 160KB (~40K tokens);
150150
`test/catalog-budget.test.ts` caps the always-loaded skill catalog at
151-
`CATALOG_BUDGET_TOKEN_EQUIVALENTS` (1,314 today; each new skill ratchets it); and
151+
`CATALOG_BUDGET_TOKEN_EQUIVALENTS` (1,359 today; each new skill ratchets it); and
152152
`test/context-budget-ratchet.test.ts` pins per-skill token ceilings against
153153
`test/fixtures/context-budget.json` (for legitimate growth or a landed
154154
reduction, re-run `bun test/helpers/capture-context-budget.ts` and commit the

‎CONTRIBUTING.md‎

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -424,10 +424,10 @@ eval files, and misses the strict classifier. No API keys needed.
424424
- **Aside driver contract** (`test/aside-driver.test.ts`) — Browser behaviour in skills is written against `scripts/resolvers/aside.ts` (`{{ASIDE_SETUP}}`) and verified live against the Aside CLI on a Mac. CI cannot run Aside, so the Aside E2E tests self-skip where `aside` is not installed; the static pins (detection, fallback hand-off, consent, credential, one-flow-per-script, sentinel) are what CI proves.
425425
- **Aside render wrapper** (`test/aside-render.test.ts`) — Pins the option mapping and generated script of `lib/aside-render.ts` everywhere, and drives both engines hermetically with fake `aside` / `browse` executables (probe classification, the stdout contract, loopback-server policy, failure paths, the timeout kill, engine choice and the mid-run fallback); the live render (PDF + screenshot through a real Aside) runs only where Aside is open and self-skips elsewhere. make-pdf's render gates (`make-pdf/test/e2e/*-gate.test.ts`) and `test/skill-e2e-diagram.test.ts` are engine-agnostic: they run through whichever engine resolves (`browserAvailable()` — Aside, or the browse binary `bun run build:gates` compiles, which is what Linux CI does) and skip only when neither exists.
426426
- **Render CLI** (`test/gstack-render-cli.test.ts`) — Pins `bin/gstack-render.ts` against a fake daemon (`GSTACK_SKIP_ASIDE=1` + `GSTACK_BROWSE_BIN`): argv guards exit 1 with the usage line, `--help` exits 0, `ENGINE=` first then `OK <path>` then fenced `EVAL` / `PAGE_ERRORS`, `--serve-root` containment, the no-browser first line, and prompt exit after a successful render. `make-pdf/test/cli-exit-codes.test.ts` and `make-pdf/test/setup-smoke.test.ts` pin the `pdf` binary's error-to-exit-code map and `$P setup`'s engine report.
427-
- **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).
427+
- **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), and that a template's `codex_default_prompt:` frontmatter key reaches the Codex `agents/openai.yaml` `default_prompt` (a template without the key keeps `Use <name> for this task.`) while no host's SKILL.md render carries the key.
428428
- **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`).
429429
- **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.
430-
- **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.
430+
- **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,359 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.
431431
- **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.
432432
- **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.
433433

@@ -766,6 +766,7 @@ Each host config (`hosts/*.ts`) controls:
766766
| Hook skills | `hooks:` frontmatter vs inline safety advisory prose |
767767
| Suppressed sections | GBrain blocks vs GBrain blocks and Review Army; Codex retains outside-review sections routed to Claude Code |
768768
| Model overlay | `claude` vs `gpt` (per-host `defaultModel`; `--model` or, at setup time, the Codex `config.toml` model overrides) |
769+
| Metadata file | none vs `agents/openai.yaml` beside each skill (`generation.generateMetadata`); its `default_prompt` is the template's `codex_default_prompt:` frontmatter key, else `Use <name> for this task.` The key is generator input only and appears in no host's SKILL.md render |
769770

770771
See `scripts/host-config.ts` for the full `HostConfig` interface.
771772

@@ -802,11 +803,11 @@ install ownership rules in the guide.
802803

803804
### Adding a new skill
804805

805-
When you add a new skill template, all hosts get it automatically:
806-
1. Create `{skill}/SKILL.md.tmpl`
806+
When you add a new skill template, every host renders it; a few static lists still need a row:
807+
1. Create `{skill}/SKILL.md.tmpl` (optionally with a one-line `codex_default_prompt:` frontmatter key, the sentence Codex's picker inserts for the skill; without it the picker gets `Use <name> for this task.`)
807808
2. Run `bun run gen:skill-docs --host all`
808-
3. The dynamic template discovery picks it up, no static list to update
809-
4. Budget it: run `bun test/helpers/capture-context-budget.ts` and commit the refreshed `test/fixtures/context-budget.json` — the context-budget ratchet fails any skill without a ceiling
809+
3. The dynamic template discovery picks it up for every host render and for `gstack/llms.txt`. Two things it does not fill in: a row in `SKILL_REQUIREMENTS` in `lib/doctor-components.ts` (the doctor's `--for <skill>` table; `test/doctor-components.test.ts` fails on a skill directory without one, and the same gen run rerenders `bin/gstack-doctor-components.sh`), and the catalog rows readers find the skill through (README.md, AGENTS.md, `docs/skills.md`, `docs/PROJECT_STRUCTURE.md`, the root `SKILL.md.tmpl` router)
810+
4. Budget it: run `bun test/helpers/capture-context-budget.ts` and commit the refreshed `test/fixtures/context-budget.json` — the context-budget ratchet fails any skill without a ceiling; the catalog budget (`test/catalog-budget.test.ts`) fails until its cap is ratcheted by the protocol in its failure message, and the number is quoted in CLAUDE.md, this file and `docs/CONTRIBUTOR_REFERENCE.md`
810811
5. Commit `{skill}/SKILL.md` (and the generated `{skill}/sections/preamble.md` when the template's `preamble-tier` is 2 or higher), external host output is generated at setup time and gitignored
811812

812813
## Conductor workspaces
@@ -934,6 +935,48 @@ When community PRs accumulate, batch them into themed waves:
934935

935936
See [PR #205](../../pull/205) (v0.8.3) for the first wave as an example.
936937

938+
## Porting a contributor's PR
939+
940+
Sometimes the right way to land an outside PR is to port it: the diff is right
941+
but it sits on an old base, its tests need our fixtures, or the repo's gates
942+
(generated renders, size pins, the CHANGELOG entry) are things only a maintainer
943+
can finish. The port keeps the contributor's credit and gives them a clear
944+
answer; the steps below are the repo's version of the rule a maintainer crew
945+
follows ([docs/captain.md](docs/captain.md#contributions-from-outside-the-crew)).
946+
947+
1. **Treat the diff as untrusted input before anything runs it.** Read it for
948+
scope, network egress, credentials, new dependencies, CI permission changes
949+
and weakened or deleted tests. A fork's green checks prove nothing about this
950+
checkout: the port head gets its own focused review and the free tier
951+
(`bun run test:quick` while iterating, `bun run test` once on the final tree)
952+
before a PR opens.
953+
2. **Keep their commits as theirs.** Cherry-pick or rebase the contributor's
954+
commits onto the current base with authorship intact (`git cherry-pick -x`
955+
keeps the source SHA in the message). A commit you have to rewrite keeps
956+
their name as author and gains a `Co-authored-by:` trailer for whoever
957+
edited it. Never fold their work into a commit under your own name, and
958+
never guess an email: use the identity on their commits.
959+
3. **Your fixes go on top, as separate commits.** Base merges, generated files,
960+
test repairs, the CHANGELOG entry and the version stamp are your commits,
961+
after theirs, so `git log` and the PR's commit list show who did what. A
962+
squash merge keeps the credit when the squash message carries their
963+
`Co-authored-by:` lines; check the merge commit before you call it landed.
964+
4. **Say so in the port.** The PR body names the original PR and its author in
965+
the first paragraph and lists what you changed on top of their diff. The
966+
port's `## Approvals` section (when the repo uses one) records who asked for
967+
the port.
968+
5. **Close the original with a specific thank-you.** After the port lands,
969+
comment on their PR with what landed (the port's number and version), what
970+
you changed and why, and thank them by name for the specific thing they
971+
fixed. Then close it. Closing a contribution without landing it is a
972+
maintainer's call, never a lane's: ask first, and when the answer is no,
973+
say why in the same comment.
974+
975+
A port is not a rewrite. If the contributor's approach is one you would not
976+
land, say that on their PR and close or park it under
977+
[Issue triage](#issue-triage) instead of shipping a different change under
978+
their name.
979+
937980
## Upgrade migrations
938981

939982
When a release changes on-disk state (directory structure, config format, stale

‎NOTICE.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ grew the diff cuts first; the end of the budget is not approval) in
104104
`ship/sections/review-army.md.tmpl`, `review/checklist.md` and `docs/review-policy.md`
105105
are written in gstack's words and mapped onto gstack's blocking floor. No sentence is copied,
106106
so no license text is carried; this entry is a courtesy.
107+
Also ideas, not text (`skills/modernize`, `skills/leaving-pr-comments`, `skills/full-send`,
108+
`agents/openai.yaml`, at 7de017b3): the MODERNIZE / REWORK / CLOSE verdict names in
109+
`modernize/SKILL.md.tmpl`, the `> [!NOTE]` author callout behind `gstack-post --attribute`, the
110+
three-bullet unattended grant in `docs/unattended.md`, and a per-skill Codex `default_prompt`;
111+
all written fresh in gstack's words.
107112

108113
Design port (`skills/babysit-pr/scripts/pr-wait`, at 7de017b3; license text:
109114
`licenses/MIT-tstack.txt`): `bin/gstack-pr-wait`, `lib/pr-wait.ts` and

0 commit comments

Comments
 (0)