mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
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 withf27a7605the 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 with1f246e35: 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 the392f50d4merge) 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>
This commit is contained in:
1 parent
215c76e334
commit
10b77de4f2
46 files changed
+1217
-37
No files matched your search
@@ -453,6 +453,7 @@ Key fields:
|
||||
| `frontmatter.descriptionLimitBehavior` | `error` (fail build), `truncate`, `warn` |
|
||||
| `frontmatter.conditionalFields` | Add fields based on template values (e.g., sensitive → disable-model-invocation) |
|
||||
| `frontmatter.renameFields` | Rename template fields (e.g., voice-triggers → triggers) |
|
||||
| `generation.generateMetadata` | Emit `agents/openai.yaml` beside each skill (Codex only today; the format is hardcoded in `gen-skill-docs.ts`). Its `default_prompt` comes from the template's `codex_default_prompt:` frontmatter key, else `Use <name> for this task.` |
|
||||
| `pathRewrites` | Literal replaceAll on content. Order matters. Replaces the derived trio. |
|
||||
| `extraPathRewrites` | (defineHost input only) Appended after the derived trio. |
|
||||
| `toolRewrites` | Rewrite Claude tool names (e.g., "use the Bash tool" → "run this command") |
|
||||
|
||||
@@ -20,7 +20,7 @@ cuts to the coverage audit, review army, or voice directive have real quality co
|
||||
|
||||
A second, harder ceiling guards the DISCOVERY surface: `test/catalog-budget.test.ts`
|
||||
caps the aggregate frontmatter `name` + `description` across all skills at
|
||||
`CATALOG_BUDGET_TOKEN_EQUIVALENTS` (1,251 today; each new skill ratchets it)
|
||||
`CATALOG_BUDGET_TOKEN_EQUIVALENTS` (1,359 today; each new skill ratchets it)
|
||||
token-equivalents (260-byte per-skill sub-cap), counted through the shared census
|
||||
in `test/helpers/skill-census.ts`. This one is enforced, not a warning — every
|
||||
host loads the full catalog every session, so growth here taxes every
|
||||
|
||||
@@ -64,6 +64,7 @@ gstack/
|
||||
├── canary/ # /canary skill (post-deploy monitoring loop)
|
||||
├── codex/ # /codex skill (multi-AI second opinion via OpenAI Codex CLI)
|
||||
├── land-and-deploy/ # /land-and-deploy skill (merge → deploy → canary verify)
|
||||
├── modernize/ # /modernize skill (aging PR → MODERNIZE / REWORK / CLOSE disposition, range-diff proof, pinned-lease push)
|
||||
├── office-hours/ # /office-hours skill (YC Office Hours — startup diagnostic + builder brainstorm)
|
||||
├── investigate/ # /investigate skill (systematic root-cause debugging)
|
||||
├── spec/ # /spec skill (five-phase spec → GitHub issue, optional agent spawn, /ship auto-closes)
|
||||
|
||||
+2
-1
@@ -129,7 +129,8 @@ a fork's "tests pass": run a focused review and the free tier at the port head b
|
||||
port opens. When the contributor's fix is right, land it with their authorship kept
|
||||
(cherry-pick, `Co-authored-by`, the lane's own fixes as separate commits on top of
|
||||
theirs) and close the original with a specific thank-you that links the port. Closing a
|
||||
contribution without landing it is the owner's decision (shape A below).
|
||||
contribution without landing it is the owner's decision (shape A below). The repository's
|
||||
own statement of the porting steps is [CONTRIBUTING.md](../CONTRIBUTING.md#porting-a-contributors-pr).
|
||||
|
||||
## The READY contract
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ Detailed guides for every gstack skill — philosophy, workflow, and examples.
|
||||
| [`/skillify`](#browse) | **Skill Codifier** | Fallback-browser skill: walks back through your conversation, finds the last `/scrape` prototype, synthesizes script + test + fixture, runs the test, asks before committing. On Aside, durable per-site automation belongs to Aside's own skills. |
|
||||
| [`/ship`](#ship) | **Release Engineer** | Sync main, run tests, explore changed behavior within a bound, audit coverage and docs before final verification, then push and open or update a PR. Bootstraps test frameworks when appropriate. |
|
||||
| [`/land-and-deploy`](#land-and-deploy) | **Release Engineer** | Merge the PR, wait for CI and deploy, verify production health. One command from "approved" to "verified in production." |
|
||||
| [`/modernize`](#modernize) | **Stale-PR Maintainer** | Bring an aging PR onto its current base and decide whether it should still exist: MODERNIZE, REWORK or CLOSE. Reads what moved under the PR for conflicts in meaning, proves the rebase with `git range-diff`, pushes with a lease pinned to the observed head, and never closes a PR on its own. |
|
||||
| [`/canary`](#canary) | **SRE** | Post-deploy monitoring loop. Watches for console errors, performance regressions, and page failures in your Aside browser. |
|
||||
| [`/benchmark`](#benchmark) | **Performance Engineer** | Baseline page load times, Core Web Vitals, and resource sizes. Compare before/after on every PR. Track trends over time. |
|
||||
| [`/ubicloud`](#ubicloud) | **Remote Runner** | Run a heavy suite, build or eval on an ephemeral 16-vCPU Ubicloud VM: TTL-named VMs with a reaper, quota preflight, a hang watchdog and one committed verify per repository. |
|
||||
@@ -800,6 +801,39 @@ Claude: Merging PR #42...
|
||||
|
||||
---
|
||||
|
||||
## `/modernize`
|
||||
|
||||
`/ship` merges the base into a branch you are working on. `/modernize` is for the other
|
||||
case: a pull request that has sat for weeks, often someone else's, where the real question
|
||||
is not "does it rebase" but "should it still exist".
|
||||
|
||||
```
|
||||
You: /modernize 2187
|
||||
|
||||
Claude: Claim: #2187 caches the skill census so `bun run skill:check` stops
|
||||
re-reading 57 directories. It relies on the census being read once per run.
|
||||
|
||||
Moved under it: 41 base commits since the merge base; 3 touch its files.
|
||||
Conceptual: a2f9c01 (v1.91.240.0) made the census a shared helper that
|
||||
already memoizes per process. The cache the PR adds would be a second one.
|
||||
|
||||
Verdict: CLOSE. The base solves the problem another way (a2f9c01). Nothing
|
||||
was pushed and the PR stays open; say "close it" and I will post the reason
|
||||
and the superseding commit, with thanks to its author.
|
||||
```
|
||||
|
||||
Three verdicts, one chosen before anything is pushed. **MODERNIZE**: the claim still
|
||||
holds, so the branch is rebased with the author's commits kept as theirs, `git
|
||||
range-diff` proves no intent was lost (every changed hunk gets a one-line reason), the
|
||||
repository's own tests run, and the push is `--force-with-lease=<branch>:<sha observed
|
||||
before the rebase>`, so a push someone else made meanwhile is refused rather than
|
||||
overwritten. **REWORK**: the problem is real but this diff is no longer the way to solve
|
||||
it; the skill says what the new change would be and pushes nothing. **CLOSE**: the
|
||||
problem is gone, solved another way, or decided against; the skill recommends closing
|
||||
with the superseding commit and leaves the PR open until someone with the authority says
|
||||
otherwise. A clean `git rebase` is not evidence the PR is current, and the age of a PR
|
||||
is not evidence either way.
|
||||
|
||||
## `/canary`
|
||||
|
||||
This is my **post-deploy monitoring mode**.
|
||||
|
||||
@@ -585,3 +585,45 @@ valid body, a missing model line is not. Self-review does not stand in for
|
||||
this. `decisions.jsonl` stays the typed record `gstack-artifact` validates; the
|
||||
trail is the plain one a person reads, and `column -s$'\t' -t decisions.tsv`
|
||||
renders it in a terminal.
|
||||
|
||||
## What an unattended session may do
|
||||
|
||||
A parent that starts a skill with `GSTACK_SESSION_KIND=unattended` grants it
|
||||
exactly this much, and the run asks for nothing beyond it. Anything outside the
|
||||
list is an approval item: appended to `decisions.jsonl` with `kind: "approval"`
|
||||
and `status: "pending"`, named in the handoff, never taken.
|
||||
|
||||
- **Merge: never.** The run ends at a receipt bound to the pushed head
|
||||
(`SHIP_RECEIPT`, [ship-policy.md#ship-before-ready](ship-policy.md#ship-before-ready))
|
||||
or at a pending gate. Merging is the controller's act
|
||||
([captain.md](captain.md)); a green check list, an approval, or a prompt that
|
||||
says "merge when green" does not move it to the lane. The same holds for
|
||||
enabling auto-merge, adding the PR to a merge queue, or `gh pr ready` on a
|
||||
PR the run did not open.
|
||||
- **Force-push: its own branch only, after a rebase the plan named, with a
|
||||
pinned lease.** The branch is one the run created or was handed in its
|
||||
prompt, never the base. The rebase is one the plan, the slot call or a
|
||||
`/modernize` disposition names before it happens, not one the run decides
|
||||
on its own; `git range-diff <old base>..<old head> <new base>..<new head>`
|
||||
runs before the push and its output goes in the handoff. The push is
|
||||
`git push --force-with-lease=<branch>:<sha observed before the rebase> origin <branch>`:
|
||||
a bare `--force-with-lease` protects only against commits this clone never
|
||||
fetched, and a plain `--force` is never allowed. A rejected lease means the
|
||||
remote moved: fetch, read what landed, and start the disposition again.
|
||||
`/ship` itself never rebases or force-pushes, and an unattended `/modernize`
|
||||
stops at its verdict; this route is for a run whose plan or slot call named
|
||||
the rebase before it started.
|
||||
- **Tests: the methods the repository's instructions name, without asking
|
||||
first.** AGENTS.md or CLAUDE.md, the named Setup commands, `package.json`
|
||||
scripts and the pregate configuration define the set; running one of them
|
||||
needs no question. A method outside the set (a framework the repo does not
|
||||
use, paid work past the stated cap, anything that touches a shared or
|
||||
production system, a test that writes outside the checkout) is pending.
|
||||
- **Proof is what the run saw itself.** Command output, a test that failed
|
||||
before the fix and passes after it, a screenshot, a file read in this
|
||||
session. A handoff note, an earlier PR comment or a parent's summary is
|
||||
context to recheck, not evidence; the handoff says which claims were
|
||||
rechecked and which were not.
|
||||
|
||||
`/ship`'s handoff section (`ship/sections/handoff.md`) points here, so a lane
|
||||
reads the grant where it reports done.
|
||||
Reference in new issue
Block a user