mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-12 03:30:28 +01:00
fix(ship-policy): DOCS_CAPS_KEY_VERSION is 1.91.270.0; key versions move through stamp_paths at the slot stamp
#3487 was written naming 1.91.258.0 for docs.caps and main stamped that number for another PR first; the slot call cannot edit anything beyond the four stamp files, so the constant shipped stale. lib/ship-policy.ts now sits in .gstack/ship-policy.json stamp_paths with the _KEY_VERSION = '{version}' template, so a new key written as a tentative future version is moved by gstack-restamp's stamp_paths stage at the slot (read from the base policy, so live from the next PR on). test/gstack-ship-policy.test.ts gains the check the incident lacked: a released key's version must be a heading whose entry names the key. Dry-run proof: a tentative 1.91.272.0 on a branch line moved to the allocated 1.91.271.0 with --policy-from head. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
f27a7605d4
commit
9f1a6b3899
4 files changed
+40
-5
No files matched your search
@@ -4,7 +4,8 @@
|
||||
"queue_mode": "stamp-at-merge",
|
||||
"release_tool": "bun scripts/gen-agents-digest.ts",
|
||||
"release_outputs": ["agents-digest/gstack-AGENTS.md"],
|
||||
"stamp_paths": [],
|
||||
"stamp_paths": ["lib/ship-policy.ts"],
|
||||
"stamp_patterns": ["_KEY_VERSION = '{version}'"],
|
||||
"changelog": "CHANGELOG.md",
|
||||
"mirror": null,
|
||||
"history": "squash-ok",
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
- **Policy key versions are stamped, not hand-moved** (`lib/ship-policy.ts`, `.gstack/ship-policy.json`): `DOCS_CAPS_KEY_VERSION` is 1.91.270.0, the release that shipped `docs.caps` (#3487 was written naming 1.91.258.0, which main stamped for another PR; a slot call never permits an edit beyond the four stamp files, so the constant could not move at the slot). gstack's own policy now lists `lib/ship-policy.ts` under `stamp_paths` with the `_KEY_VERSION = '{version}'` template in `stamp_patterns`: a new key's constant is written as a tentative future version (the next patch above the fork point) and `gstack-restamp`'s stamp_paths stage moves it to the allocated version at the slot stamp, reading the base branch's policy, so the stage is live for the PRs after this one. `test/gstack-ship-policy.test.ts` adds the check the incident lacked: a released key's version must be a CHANGELOG heading whose entry names the key, so a tentative value no stamp moved fails (keys from before `review_scope` are exempt).
|
||||
|
||||
## [1.91.270.0] - 2026-10-27
|
||||
|
||||
### Added
|
||||
|
||||
+10
-4
@@ -161,11 +161,17 @@ export const SHIP_QUEUE_KEYS_VERSION = '1.91.108.0';
|
||||
export const TRAIN_KEYS_VERSION = '1.91.146.0';
|
||||
// Each constant is the release that first reads its key: a policy declaring the key must name at least
|
||||
// that version as min_gstack_version, so an older gstack refuses the policy by name instead of failing on
|
||||
// an unknown key. review_scope shipped in 1.91.256.0 (#3481). docs.caps is unreleased: its constant names the
|
||||
// release expected to stamp it (test/gstack-ship-policy.test.ts holds it newer than every CHANGELOG heading the
|
||||
// checkout sees); whoever stamps that release under another number moves the constant to the stamped version.
|
||||
// an unknown key. review_scope shipped in 1.91.256.0 (#3481), docs.caps in 1.91.270.0 (#3487). A new key's
|
||||
// constant is written as a tentative future version (the next patch after the fork point, in this exact
|
||||
// `_KEY_VERSION = '<version>'` form): this file is in .gstack/ship-policy.json stamp_paths with that form as a
|
||||
// stamp_patterns template, so the slot stamp's gstack-restamp stamp_paths stage moves the tentative value to the
|
||||
// allocated version. The stage reads lines the branch added: a tentative value newer than the fork version moves,
|
||||
// an untouched released constant stays, and a branch-added line naming the base's own version is re-read as a
|
||||
// stale stamp and moves too, so never rewrite a released constant's line. test/gstack-ship-policy.test.ts holds an
|
||||
// unreleased constant newer than every CHANGELOG heading and a released one on a heading whose entry names its
|
||||
// key, so a value a stamp did not move fails there.
|
||||
export const REVIEW_SCOPE_KEY_VERSION = '1.91.256.0';
|
||||
export const DOCS_CAPS_KEY_VERSION = '1.91.258.0';
|
||||
export const DOCS_CAPS_KEY_VERSION = '1.91.270.0';
|
||||
export const POLICY_KEY_INTRODUCED: Record<PolicyKey, string> = {
|
||||
bump: '1.91.73.0', queue_mode: '1.91.73.0', release_tool: '1.91.73.0', release_outputs: '1.91.73.0', stamp_paths: '1.91.73.0',
|
||||
changelog: '1.91.73.0', mirror: '1.91.73.0', history: '1.91.73.0', preregistration_shas: '1.91.73.0', stamp_sensitive_gates: '1.91.73.0',
|
||||
|
||||
@@ -91,6 +91,29 @@ describe('policy key versions against the CHANGELOG', () => {
|
||||
expect(cmp(parse(version), newest), `${key} is introduced in ${version}, which has no CHANGELOG heading and is not newer than the newest heading ${newest.join('.')}; an unreleased key names the release that will stamp it`).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
test('a released key names the heading whose entry introduces it, so a tentative version no stamp moved fails', () => {
|
||||
// #3487 was written naming the next version and main stamped that number for another PR first, so the constant
|
||||
// pointed at a release that never read `docs` while the heading existed and the test above skipped it. A key version that is
|
||||
// a heading must be the one whose entry names the key (`\`<key>` at a word boundary in the section body, so `\`docs/` paths do not count); lib/ship-policy.ts sits in
|
||||
// stamp_paths so the slot stamp moves a tentative value there itself. Keys from before the convention are exempt.
|
||||
const root = path.join(import.meta.dir, '..');
|
||||
const base = spawnSync('git', ['show', 'origin/main:CHANGELOG.md'], { cwd: root, encoding: 'utf8', timeout: 30_000 });
|
||||
const text = fs.readFileSync(path.join(root, 'CHANGELOG.md'), 'utf8') + (base.status === 0 ? base.stdout : '');
|
||||
const sections = new Map<string, string>();
|
||||
for (const part of text.split(/^(?=## \[)/m)) {
|
||||
const heading = /^## \[(\d+\.\d+\.\d+\.\d+)\]/.exec(part);
|
||||
if (heading && !sections.has(heading[1]!)) sections.set(heading[1]!, part);
|
||||
}
|
||||
const parse = (v: string) => v.split('.').map(Number);
|
||||
const cmp = (a: number[], b: number[]) => a[0]! - b[0]! || a[1]! - b[1]! || a[2]! - b[2]! || a[3]! - b[3]!;
|
||||
for (const [key, version] of Object.entries(POLICY_KEY_INTRODUCED)) {
|
||||
if (cmp(parse(version), parse(REVIEW_SCOPE_KEY_VERSION)) < 0) continue;
|
||||
const section = sections.get(version);
|
||||
if (section === undefined) continue;
|
||||
expect(new RegExp('`' + key + '(?![A-Za-z0-9_/-])').test(section), `${key} is introduced in ${version}, but that release's CHANGELOG entry never names \`${key}: the constant still holds the tentative version the branch was written with; the slot stamp moves it through stamp_paths, or move it to the release that shipped the key`).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("gstack's own .gstack/ship-policy.json", () => {
|
||||
|
||||
Reference in new issue
Block a user