mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-04 15:57:33 +01:00
v1.93.20.0 docs: version flow under changelog fragments; scorecard pass cap of 2 (GST-1003) (#3882)
* docs: version flow under changelog fragments; scorecard pass cap matches the two-round review cap (GST-1003) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: CHANGELOG_STYLE.md describes the fragment flow; pin the train land link to #train-land (GST-1003, #3885) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * changelog: GST-1003 fragment 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
cb72cc13b1
commit
16e4d2f4f0
11 files changed
+91
-65
No files matched your search
@@ -1,5 +1,17 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [1.93.20.0] - 2026-11-02
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- `gstack-factory-scorecard` now counts a PR as "at the cap" once it reaches 2 review passes, the two-round cap the review policy sets, instead of 3. The default `--pass-cap` is 2, and the "Review passes per PR" benchmark reads "median 1 pass, few at the cap". Pass `--pass-cap 3` to get the old count. Rows from earlier weeks in `trend.csv` were counted at the old cap, and each row names the cap it used.
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
|
||||||
|
- CLAUDE.md now describes how gstack versions its own PRs today: a branch writes its entry as `changelog.d/<branch-slug>.md` and never edits VERSION, package.json or CHANGELOG.md, and the merge train's stamp assigns the version (`bump: minor` or `bump: major` front matter asks for more than a patch). The old text said to claim a version slot with `bin/gstack-next-version`.
|
||||||
|
- docs/CHANGELOG_STYLE.md, which CLAUDE.md says to read before writing an entry, now describes the same fragment flow: what goes in the fragment, when to add `bump:` front matter, and what to check after merging main. It no longer tells a branch to bump VERSION or claim a slot with `bin/gstack-next-version`.
|
||||||
|
- docs/ship-policy.md marks the queue-side procedure as being for repos on `stamp-at-merge` without changelog fragments, and points gstack's own PRs to the fragment flow and `train land`. The old link to that section still works.
|
||||||
|
|
||||||
## [1.93.19.0] - 2026-11-02
|
## [1.93.19.0] - 2026-11-02
|
||||||
|
|
||||||
**`gstack-ship-receipt read --check-prose` no longer reads the Documentation exception line or code fences as counter claims (GST-983, GST-984).** `write --docs` with an owner exception requires the PR body to carry the whole `Documentation exception: …` line word for word, but the prose check read the owner's reason in it as prose, so a reason like "sections 1 and 2 skip the audit" was a `2 skip` claim and no body could pass both checks. That is the deadlock GST-977 fixed for the Review-loop exception line. Separately, on gstack-evals #142, test output pasted in a fenced block ("113 passed, 0 failed") and a quoted code comment ("the first 35 fail") were read as receipt counts and refused.
|
**`gstack-ship-receipt read --check-prose` no longer reads the Documentation exception line or code fences as counter claims (GST-983, GST-984).** `write --docs` with an owner exception requires the PR body to carry the whole `Documentation exception: …` line word for word, but the prose check read the owner's reason in it as prose, so a reason like "sections 1 and 2 skip the audit" was a `2 skip` claim and no body could pass both checks. That is the deadlock GST-977 fixed for the Review-loop exception line. Separately, on gstack-evals #142, test output pasted in a fenced block ("113 passed, 0 failed") and a quoted code comment ("the first 35 fail") were read as receipt counts and refused.
|
||||||
|
|||||||
@@ -374,18 +374,22 @@ is not a reason to choose MINOR. Choose **MINOR (X.Y+1.0.0)** or **MAJOR
|
|||||||
("ridiculous"), such as an incompatible public-interface change or a genuinely
|
("ridiculous"), such as an incompatible public-interface change or a genuinely
|
||||||
new product-scale release. Make that judgment without another approval question.
|
new product-scale release. Make that judgment without another approval question.
|
||||||
|
|
||||||
Use `bin/gstack-next-version` to check the live release queue before publishing.
|
gstack's policy sets `changelog_fragments` (#3654), so a branch never writes a
|
||||||
If a slot is claimed, advance to the next available version at the chosen bump
|
version and never checks `bin/gstack-next-version` for a slot. The merge
|
||||||
level and use `bin/gstack-version-bump` to synchronize release metadata. A higher
|
train's stamp (`train land`) assigns base + PATCH at merge. To ask for more,
|
||||||
base version does not itself require a MINOR bump. Keep the PR ready for Garry to
|
open the branch's fragment with `bump: minor` (or `major`) front matter. A
|
||||||
merge; autonomous version decisions do not authorize merging, deploying or
|
higher base version does not itself require a MINOR bump. Keep the PR READY for
|
||||||
skipping required validation.
|
the merge train; autonomous version decisions do not authorize merging,
|
||||||
|
deploying or skipping required validation.
|
||||||
|
|
||||||
**VERSION and CHANGELOG are branch-scoped.** Each shipping branch gets its own
|
**The CHANGELOG entry is a branch fragment.** Each shipping branch writes one
|
||||||
bump and one entry, written at `/ship` time, that describes what THIS branch
|
entry at `/ship` time as `changelog.d/<branch-slug>.md` (entry text only, no
|
||||||
adds versus main, for users, with no branch-internal versions or development
|
`## [x]` heading) that describes what THIS branch adds versus main, for users,
|
||||||
narrative. VERSION stays 4-digit; package.json carries the 3-digit npm
|
with no branch-internal versions or development narrative. A branch never edits
|
||||||
translation owned by `bin/gstack-version-bump`, so never hand-edit it. Read
|
VERSION, package.json or a released CHANGELOG.md section: the merge stamp folds
|
||||||
|
the fragment into CHANGELOG.md under its version, keeps VERSION 4-digit and
|
||||||
|
writes package.json's 3-digit npm translation through `bin/gstack-version-bump`
|
||||||
|
([changelog fragments](docs/ship-policy.md#changelog-fragments)). Read
|
||||||
[docs/CHANGELOG_STYLE.md](docs/CHANGELOG_STYLE.md) BEFORE writing an entry: it
|
[docs/CHANGELOG_STYLE.md](docs/CHANGELOG_STYLE.md) BEFORE writing an entry: it
|
||||||
holds the versioning invariant, the merge-main checks, what stays out and the
|
holds the versioning invariant, the merge-main checks, what stays out and the
|
||||||
entry format. Always credit community contributions with
|
entry format. Always credit community contributions with
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# gstack digest v1.93.19.0 — regenerate/re-copy after upgrading gstack
|
# gstack digest v1.93.20.0 — regenerate/re-copy after upgrading gstack
|
||||||
|
|
||||||
Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed
|
Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed
|
||||||
for agent hosts without a full skill install. The full skills add workflows,
|
for agent hosts without a full skill install. The full skills add workflows,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
* gstack-factory-scorecard [--repo owner/name] [--base main] [--since-days 7]
|
* gstack-factory-scorecard [--repo owner/name] [--base main] [--since-days 7]
|
||||||
* [--crew login,login] [--gate-workflow evals.yml] [--gate-event workflow_dispatch|any]
|
* [--crew login,login] [--gate-workflow evals.yml] [--gate-event workflow_dispatch|any]
|
||||||
* [--free-workflow free-tests.yml] [--train-prefix train/] [--ready-marker <regex>]
|
* [--free-workflow free-tests.yml] [--train-prefix train/] [--ready-marker <regex>]
|
||||||
* [--pass-marker <regex>] [--pass-cap 3] [--max-artifact-runs 60]
|
* [--pass-marker <regex>] [--pass-cap 2] [--max-artifact-runs 60]
|
||||||
* [--out-dir <dir>] [--csv <file>] [--json] [--cache-dir <dir>]
|
* [--out-dir <dir>] [--csv <file>] [--json] [--cache-dir <dir>]
|
||||||
* [--fixtures <recorded gh responses.json>] [--now <iso>]
|
* [--fixtures <recorded gh responses.json>] [--now <iso>]
|
||||||
*
|
*
|
||||||
|
|||||||
+46
-42
@@ -1,7 +1,9 @@
|
|||||||
# CHANGELOG + VERSION style
|
# CHANGELOG + VERSION style
|
||||||
|
|
||||||
Moved verbatim from CLAUDE.md (token-load reduction). Read this BEFORE
|
Moved verbatim from CLAUDE.md (token-load reduction). Read this BEFORE
|
||||||
writing any `## [X.Y.Z]` CHANGELOG entry.
|
writing a CHANGELOG entry. In gstack the entry is a fragment,
|
||||||
|
`changelog.d/<branch-slug>.md`, and the merge step gives it its `## [X.Y.Z.W]`
|
||||||
|
heading ([changelog fragments](ship-policy.md#changelog-fragments)).
|
||||||
|
|
||||||
## Versioning and branch-scoped entries
|
## Versioning and branch-scoped entries
|
||||||
|
|
||||||
@@ -9,15 +11,15 @@ Moved verbatim from CLAUDE.md (#2096 size limit). The autonomous version
|
|||||||
policy (choose versions without asking; default to PATCH) stays in CLAUDE.md
|
policy (choose versions without asking; default to PATCH) stays in CLAUDE.md
|
||||||
as the single source.
|
as the single source.
|
||||||
|
|
||||||
**Versioning invariant (workspace-aware ship).** VERSION is a monotonic ordered
|
**Versioning invariant.** VERSION is a monotonic ordered release identifier,
|
||||||
release identifier, not a strict semver commitment. The bump level
|
not a strict semver commitment. The bump level (major/minor/patch/micro)
|
||||||
(major/minor/patch/micro) expresses intent at ship time. Queue-advancing past a
|
expresses intent. Versions are assigned at merge, in merge order: each stamp
|
||||||
claimed version within the same bump level is explicitly permitted — if branch A
|
takes the version before it plus the effective bump, which is the policy's
|
||||||
claims v1.7.0.0 as a MINOR and branch B is also a MINOR, B lands at v1.8.0.0
|
PATCH raised by any folded fragment's `bump:` front matter. If PR A and PR B
|
||||||
(still a MINOR relative to main). Downstream consumers must NOT rely on
|
both ask for MINOR and land back to back on v1.6.0.0, A lands at v1.7.0.0 and
|
||||||
"MINOR = feature-only, PATCH = fix-only" as a strict contract. This is why
|
B at v1.8.0.0 (still a MINOR relative to the version before it). Downstream
|
||||||
`bin/gstack-next-version` advances within the chosen bump level rather than
|
consumers must NOT rely on "MINOR = feature-only, PATCH = fix-only" as a
|
||||||
repicking the level when collisions happen.
|
strict contract.
|
||||||
|
|
||||||
**package.json carries the npm-valid translation, not VERSION verbatim.**
|
**package.json carries the npm-valid translation, not VERSION verbatim.**
|
||||||
VERSION stays the 4-digit source of truth (e.g. `1.67.0.0`); package.json and
|
VERSION stays the 4-digit source of truth (e.g. `1.67.0.0`); package.json and
|
||||||
@@ -26,18 +28,25 @@ translation (`1.67.0`), and lockfile `version` fields sync only when the
|
|||||||
lockfile already exists. `bin/gstack-version-bump` (via `lib/version-source.ts`)
|
lockfile already exists. `bin/gstack-version-bump` (via `lib/version-source.ts`)
|
||||||
owns the translation and judges drift on translated forms — do NOT "fix" the
|
owns the translation and judges drift on translated forms — do NOT "fix" the
|
||||||
apparent mismatch by hand, and do not write a 4-digit version into
|
apparent mismatch by hand, and do not write a 4-digit version into
|
||||||
package.json (npm rejects it). Rationale and translation rules live in the
|
package.json (npm rejects it). A branch never writes either one: the merge
|
||||||
|
stamp does, through `bin/gstack-version-bump`. Rationale and translation rules live in the
|
||||||
`lib/version-source.ts` header; `test/gstack-version-bump.test.ts` pins the
|
`lib/version-source.ts` header; `test/gstack-version-bump.test.ts` pins the
|
||||||
contract.
|
contract.
|
||||||
|
|
||||||
**VERSION and CHANGELOG are branch-scoped.** Every feature branch that ships gets its
|
**The CHANGELOG entry is branch-scoped; the version is not.** Every feature
|
||||||
own version bump and CHANGELOG entry. The entry describes what THIS branch adds —
|
branch that ships writes one entry as `changelog.d/<branch-slug>.md`: the entry
|
||||||
not what was already on main.
|
text only, with no `## [x]` heading, and `bump: minor` or `bump: major` front
|
||||||
|
matter only when the change warrants more than a PATCH. A branch never edits
|
||||||
|
VERSION, package.json's version or a released CHANGELOG.md section. At merge,
|
||||||
|
`train land` (or `gstack-ship-queue land`) assigns the version, folds the
|
||||||
|
fragment into one `## [<version>] - <date>` section at the top of CHANGELOG.md
|
||||||
|
and deletes the file. The entry describes what THIS branch adds — not what was
|
||||||
|
already on main.
|
||||||
|
|
||||||
**The CHANGELOG entry is the diff between main and the shipping branch — what users
|
**The CHANGELOG entry is the diff between main and the shipping branch — what users
|
||||||
get when they upgrade. NOT how the branch got there.** A reader landing on the entry
|
get when they upgrade. NOT how the branch got there.** A reader landing on the entry
|
||||||
should learn what they can do now that they couldn't before; they should not learn
|
should learn what they can do now that they couldn't before; they should not learn
|
||||||
about the branch's internal version bumps, the bugs we caught and fixed mid-branch,
|
about versions the branch carried during development, the bugs we caught and fixed mid-branch,
|
||||||
the plan reviews we ran, or the commits we squashed. That is branch development
|
the plan reviews we ran, or the commits we squashed. That is branch development
|
||||||
narrative. It belongs in PR descriptions and commit messages, not CHANGELOG.
|
narrative. It belongs in PR descriptions and commit messages, not CHANGELOG.
|
||||||
|
|
||||||
@@ -62,29 +71,28 @@ the user gets; the path to that system is invisible to them.
|
|||||||
**When to write the CHANGELOG entry:**
|
**When to write the CHANGELOG entry:**
|
||||||
- At `/ship` time (Step 13), not during development or mid-branch.
|
- At `/ship` time (Step 13), not during development or mid-branch.
|
||||||
- The entry covers ALL commits on this branch vs the base branch.
|
- The entry covers ALL commits on this branch vs the base branch.
|
||||||
- `/ship` lints the lines the branch added with `bin/gstack-prose-lint CHANGELOG.md --base origin/<base> --gate`,
|
- `/ship` lints the fragment with `bin/gstack-prose-lint changelog.d/<branch-slug>.md --gate`.
|
||||||
and the Quality gate workflow gates the `## [Unreleased]` block the same way. Rewrite each `PROSE:` line
|
Rewrite each `PROSE:` line it names ([docs/troubleshooting.md](troubleshooting.md#prose-lint-found)).
|
||||||
it names ([docs/troubleshooting.md](troubleshooting.md#prose-lint-found)).
|
- Never fold new work into a CHANGELOG.md section that already landed on main.
|
||||||
- Never fold new work into an existing CHANGELOG entry from a prior version that
|
New work goes in this branch's fragment, and the merge stamp gives it its own
|
||||||
already landed on main. If main has v0.10.0.0 and your branch adds features,
|
section at the next version.
|
||||||
bump to v0.10.1.0 with a new entry — don't edit the v0.10.0.0 entry.
|
|
||||||
|
|
||||||
**Key questions before writing:**
|
**Key questions before writing:**
|
||||||
1. What branch am I on? What did THIS branch change?
|
1. What branch am I on? What did THIS branch change?
|
||||||
2. Is the base branch version already released? (If yes, bump and create new entry.)
|
2. Does this change warrant more than a PATCH? (If yes, open the fragment with
|
||||||
3. Does an existing entry on this branch already cover earlier work? (If yes, replace
|
`bump: minor` or `bump: major` front matter; otherwise add none.)
|
||||||
it with one unified entry for the final version.)
|
3. Does this branch's fragment already cover earlier work? (If yes, rewrite it as
|
||||||
|
one unified entry.)
|
||||||
|
|
||||||
**Merging main does NOT mean adopting main's version.** When you merge origin/main into
|
**Merging main never gives your branch a version.** When you merge origin/main into
|
||||||
a feature branch, main may bring new CHANGELOG entries and a higher VERSION. Your branch
|
a feature branch, main may bring new CHANGELOG sections and a higher VERSION. Take them
|
||||||
still needs its OWN version bump on top. If main is at v0.13.8.0 and your branch adds
|
exactly as main has them. Your branch still carries only its fragment, and never jams its
|
||||||
features, bump to v0.13.9.0 with a new entry. Never jam your changes into an entry that
|
changes into a section that already landed on main; the merge stamp puts its section on top.
|
||||||
already landed on main. Your entry goes on top because your branch lands next.
|
|
||||||
|
|
||||||
**After merging main, always check:**
|
**After merging main, always check:**
|
||||||
- Does CHANGELOG have your branch's own entry separate from main's entries?
|
- Is your fragment still in `changelog.d/`, with its own text, separate from main's sections?
|
||||||
- Is VERSION higher than main's VERSION?
|
- Are VERSION, package.json's version and every released CHANGELOG.md section exactly
|
||||||
- Is your entry the topmost entry in CHANGELOG (above main's latest)?
|
main's? (The Version Gate check requires this of a head the merge step did not stamp.)
|
||||||
If any answer is no, fix it before continuing.
|
If any answer is no, fix it before continuing.
|
||||||
|
|
||||||
**After any CHANGELOG edit that moves, adds, or removes entries,** immediately run
|
**After any CHANGELOG edit that moves, adds, or removes entries,** immediately run
|
||||||
@@ -93,13 +101,9 @@ order. Gaps between version numbers are fine. A branch that ships at v1.6.4.0 wi
|
|||||||
a prior v1.5.2.0 or v1.5.3.0 entry on main is correct — those were branch-internal
|
a prior v1.5.2.0 or v1.5.3.0 entry on main is correct — those were branch-internal
|
||||||
version numbers that never landed. Do not back-fill gaps with placeholder entries.
|
version numbers that never landed. Do not back-fill gaps with placeholder entries.
|
||||||
|
|
||||||
**Never orphan branch-internal versions.** If your branch bumped VERSION several times
|
**Keep one entry per branch.** When the branch's work grows after its fragment was
|
||||||
during development (v1.5.1.0 → v1.5.2.0 → v1.6.4.0, say) and those earlier entries were
|
written, rewrite that fragment as one unified entry instead of adding a second file
|
||||||
never released to main, the final ship consolidates ALL of them into a single entry at
|
beside it. Readers see one release, not a branch diary.
|
||||||
the final version (v1.6.4.0). Collapse them — delete the old entries and move their
|
|
||||||
content into the final entry, re-version table columns accordingly. Readers see one
|
|
||||||
release, not a branch diary. Gaps are fine (v1.6.3.0 → v1.6.4.0 with no v1.5.x
|
|
||||||
in between on main is correct).
|
|
||||||
|
|
||||||
CHANGELOG.md is **for users**, not contributors. Write it like product release notes:
|
CHANGELOG.md is **for users**, not contributors. Write it like product release notes:
|
||||||
|
|
||||||
@@ -122,9 +126,9 @@ we got here. Keep out of the CHANGELOG, always:
|
|||||||
documents what DID ship, not what MIGHT ship.
|
documents what DID ship, not what MIGHT ship.
|
||||||
- Version-bump housekeeping when no user-facing work actually landed.
|
- Version-bump housekeeping when no user-facing work actually landed.
|
||||||
|
|
||||||
If the diff between the base branch version and this version has no user-facing change
|
If the diff between the base branch and this branch has no user-facing change
|
||||||
(only merges, only CHANGELOG edits, only placeholder work), the honest entry is one
|
(only merges, only CHANGELOG edits, only placeholder work), the honest fragment is one
|
||||||
sentence: "Version bump for branch-ahead discipline. No user-facing changes yet." Stop
|
sentence: "No user-facing changes yet." Stop
|
||||||
there. Do not pad. Do not explain the plan that will ship eventually. Do not narrate
|
there. Do not pad. Do not explain the plan that will ship eventually. Do not narrate
|
||||||
the branch's history. When real work lands, the entry will replace this at /ship time.
|
the branch's history. When real work lands, the entry will replace this at /ship time.
|
||||||
|
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ line whose input could not be read says `unavailable (<reason>)` rather than 0.
|
|||||||
gstack-factory-scorecard --repo owner/name --since-days 7 \
|
gstack-factory-scorecard --repo owner/name --since-days 7 \
|
||||||
[--crew login,login] [--gate-workflow evals.yml] [--free-workflow free-tests.yml] \
|
[--crew login,login] [--gate-workflow evals.yml] [--free-workflow free-tests.yml] \
|
||||||
[--train-prefix train/] [--ready-marker 'READY #\d+|SHIP_RECEIPT:'] [--pass-marker '"passes": (\d+)|passes=(\d+)'] \
|
[--train-prefix train/] [--ready-marker 'READY #\d+|SHIP_RECEIPT:'] [--pass-marker '"passes": (\d+)|passes=(\d+)'] \
|
||||||
[--pass-cap 3] [--out-dir .context/factory-scorecard] [--now <iso>]
|
[--pass-cap 2] [--out-dir .context/factory-scorecard] [--now <iso>]
|
||||||
```
|
```
|
||||||
|
|
||||||
`--repo` defaults to the origin remote's owner/name on github.com (or
|
`--repo` defaults to the origin remote's owner/name on github.com (or
|
||||||
@@ -280,7 +280,7 @@ measured later does not count anything that happened after that week.
|
|||||||
| Merged PRs | `merged_at` in the window, base = default branch; crew by `--crew` logins, else author association OWNER/MEMBER/COLLABORATOR | several merges a day, every day; outside contributions land in the same week |
|
| Merged PRs | `merged_at` in the window, base = default branch; crew by `--crew` logins, else author association OWNER/MEMBER/COLLABORATOR | several merges a day, every day; outside contributions land in the same week |
|
||||||
| Lead time, created → merged | PR `created_at` to `merged_at`, median and p90 | median under 24h, p90 under 3 days (DORA "elite" change lead time is under a day) |
|
| Lead time, created → merged | PR `created_at` to `merged_at`, median and p90 | median under 24h, p90 under 3 days (DORA "elite" change lead time is under a day) |
|
||||||
| Lead time, READY → merged | first PR comment matching `--ready-marker` at or before `merged_at`; PRs with no such comment are left out and counted | under 2h; every merged PR carries a READY comment |
|
| Lead time, READY → merged | first PR comment matching `--ready-marker` at or before `merged_at`; PRs with no such comment are left out and counted | under 2h; every merged PR carries a READY comment |
|
||||||
| Review passes per PR | the largest count `--pass-marker` captures in the PR body (the ship receipt's `"passes": N` once /ship writes it) or a PR comment (`passes=N`, `REVIEW_PASSES: N`), median and p90, plus how many PRs sat at `--pass-cap` (3: pass 1 reviews the whole diff, later passes only the delta, a pass that finds nothing new is the exit) | median 2 passes; none at the cap |
|
| Review passes per PR | the largest count `--pass-marker` captures in the PR body (the ship receipt's `"passes": N` once /ship writes it) or a PR comment (`passes=N`, `REVIEW_PASSES: N`), median and p90, plus how many PRs reached `--pass-cap` (2, the [review policy](review-policy.md)'s cap of two rounds, a fix-check included: pass 1 reviews the whole diff, pass 2 only the range since, and a pass that finds nothing blocking is the exit) | median 1 pass; few at the cap |
|
||||||
| Gate runs green / red / cancelled | completed runs of the gate workflow (`workflow_dispatch` by default; `--gate-event any`); cost from the run's `report-verdict-a*` artifact (`collector-outcomes.json` `.verdict.costUsd`), else the `**$N** rule/judge cost` or `cost=$N` line of the PR's verdict comment | green on 95%+ of runs, cancelled near 0, cost known for every run |
|
| Gate runs green / red / cancelled | completed runs of the gate workflow (`workflow_dispatch` by default; `--gate-event any`); cost from the run's `report-verdict-a*` artifact (`collector-outcomes.json` `.verdict.costUsd`), else the `**$N** rule/judge cost` or `cost=$N` line of the PR's verdict comment | green on 95%+ of runs, cancelled near 0, cost known for every run |
|
||||||
| Known gate cost per merged PR | known cost / merged PRs; unknown-cost runs make it a floor | known, stable or falling week over week |
|
| Known gate cost per merged PR | known cost / merged PRs; unknown-cost runs make it a floor | known, stable or falling week over week |
|
||||||
| Red-train rate | runs whose head branch starts with `--train-prefix`, cancelled excluded; red = conclusion other than success; red backstops and screens shown beside it | under 5% (each red train is a bisect plus a rebuild, about two gates) |
|
| Red-train rate | runs whose head branch starts with `--train-prefix`, cancelled excluded; red = conclusion other than success; red backstops and screens shown beside it | under 5% (each red train is a bisect plus a rebuild, about two gates) |
|
||||||
|
|||||||
+9
-3
@@ -112,10 +112,16 @@ refuses the file by name (`POLICY_GSTACK_TOO_OLD`).
|
|||||||
`.gstack/ship-policy.example.json` shows every key set the way a serial-merge
|
`.gstack/ship-policy.example.json` shows every key set the way a serial-merge
|
||||||
repo with a release script, docs mentions and a mirror would set them.
|
repo with a release script, docs mentions and a mirror would set them.
|
||||||
|
|
||||||
### Queue-side procedure for gstack
|
<a id="queue-side-procedure-for-gstack"></a>
|
||||||
|
### Queue-side procedure under `stamp-at-merge` without fragments
|
||||||
|
|
||||||
Who does what under `stamp-at-merge`, for the PR author and for the thread
|
gstack itself no longer follows these steps. Since #3654 (v1.91.342.0) its
|
||||||
running the merge queue:
|
policy sets [`changelog_fragments`](#changelog-fragments), so a gstack PR adds
|
||||||
|
a fragment and never a version, and trains merge through
|
||||||
|
[`train land`](#train-land). The steps
|
||||||
|
below are for a repo on `stamp-at-merge` whose policy has no
|
||||||
|
`changelog_fragments`. Who does what there, for the PR author and for the
|
||||||
|
thread running the merge queue:
|
||||||
|
|
||||||
1. **Open.** The branch carries a tentative stamp of the base's version plus
|
1. **Open.** The branch carries a tentative stamp of the base's version plus
|
||||||
PATCH (`gstack-version-bump write --version <base+patch> --regen-digest`)
|
PATCH (`gstack-version-bump write --version <base+patch> --regen-digest`)
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export interface ScorecardOptions {
|
|||||||
export const DEFAULTS = {
|
export const DEFAULTS = {
|
||||||
base: 'main', sinceDays: 7, gateWorkflow: 'evals.yml', gateEvent: 'workflow_dispatch', freeWorkflow: 'free-tests.yml',
|
base: 'main', sinceDays: 7, gateWorkflow: 'evals.yml', gateEvent: 'workflow_dispatch', freeWorkflow: 'free-tests.yml',
|
||||||
trainPrefix: 'train/', readyMarker: 'READY #\\d+|SHIP_RECEIPT:|gstack-ship-receipt',
|
trainPrefix: 'train/', readyMarker: 'READY #\\d+|SHIP_RECEIPT:|gstack-ship-receipt',
|
||||||
passMarker: '"passes"\\s*:\\s*(\\d+)|\\bpasses=(\\d+)|\\bREVIEW_PASS(?:ES)?[:= ]\\s*(\\d+)', passCap: 3, maxArtifactRuns: 60,
|
passMarker: '"passes"\\s*:\\s*(\\d+)|\\bpasses=(\\d+)|\\bREVIEW_PASS(?:ES)?[:= ]\\s*(\\d+)', passCap: 2, maxArtifactRuns: 60,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const CREW_ASSOCIATIONS = new Set(['OWNER', 'MEMBER', 'COLLABORATOR']);
|
export const CREW_ASSOCIATIONS = new Set(['OWNER', 'MEMBER', 'COLLABORATOR']);
|
||||||
@@ -399,7 +399,7 @@ export const BENCHMARKS: Record<string, string> = {
|
|||||||
merged: 'several merges a day, every day; outside contributions land in the same week',
|
merged: 'several merges a day, every day; outside contributions land in the same week',
|
||||||
lead_time: 'median under 24h, p90 under 3 days (DORA elite: change lead time under a day)',
|
lead_time: 'median under 24h, p90 under 3 days (DORA elite: change lead time under a day)',
|
||||||
ready_to_merge: 'under 2h from READY to merge; every merged PR carries a READY comment',
|
ready_to_merge: 'under 2h from READY to merge; every merged PR carries a READY comment',
|
||||||
review_passes: 'median 2 passes, none at the cap (a pass that finds nothing new is the exit; what is left at the cap is named in the PR body)',
|
review_passes: 'median 1 pass, few at the cap (a pass that finds nothing blocking is the exit; a PR at the cap ships with what is left named in the PR body)',
|
||||||
gates: 'green on 95%+ of runs, cancelled near 0, cost known for every run',
|
gates: 'green on 95%+ of runs, cancelled near 0, cost known for every run',
|
||||||
cost_per_merge: 'known, stable or falling week over week',
|
cost_per_merge: 'known, stable or falling week over week',
|
||||||
red_train: 'under 5% of trains red (each red train costs a bisect and a rebuild)',
|
red_train: 'under 5% of trains red (each red train costs a bisect and a rebuild)',
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gstack",
|
"name": "gstack",
|
||||||
"version": "1.93.19",
|
"version": "1.93.20",
|
||||||
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
|
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ describe('factory-scorecard: recorded window', () => {
|
|||||||
expect(values.merged).toBe('3 (crew 2, outside 1)');
|
expect(values.merged).toBe('3 (crew 2, outside 1)');
|
||||||
expect(values.lead_time).toBe('median 8.0h, p90 5.0d');
|
expect(values.lead_time).toBe('median 8.0h, p90 5.0d');
|
||||||
expect(values.ready_to_merge).toBe('median 1.0h, p90 2.0h (2 of 3 PRs with a READY comment)');
|
expect(values.ready_to_merge).toBe('median 1.0h, p90 2.0h (2 of 3 PRs with a READY comment)');
|
||||||
expect(values.review_passes).toBe('median 2, p90 3 (2 of 3 PRs report a pass count; 1 at the cap of 3)');
|
expect(values.review_passes).toBe('median 2, p90 3 (2 of 3 PRs report a pass count; 2 at the cap of 2)');
|
||||||
expect(values.gates).toBe('2 / 1 / 1; known cost $43.00 on 2 of 4 runs');
|
expect(values.gates).toBe('2 / 1 / 1; known cost $43.00 on 2 of 4 runs');
|
||||||
expect(values.cost_per_merge).toBe('$14.33 (2 runs without a known cost)');
|
expect(values.cost_per_merge).toBe('$14.33 (2 runs without a known cost)');
|
||||||
expect(values.red_train).toBe('50% (1 red of 2 trains; 0 red backstop, 0 red screens)');
|
expect(values.red_train).toBe('50% (1 red of 2 trains; 0 red backstop, 0 red screens)');
|
||||||
|
|||||||
Reference in new issue
Block a user