mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
* feat(ship-queue): the ship size cap composes across a merge train; verify refuses a stale all-merged train (#3519 b, c) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes (runnable clear-time NEXT, stale exit only on a fetched main, open-slot freeze control, LF size-ledger fixture) - verify's clear-time NEXT names gh pr view <n> --json state,headRefOid per unreadable slot instead of a pasteable #n@sha that views the current branch's PR - QUEUE_TRAIN_STALE needs a fetched main (never under --no-fetch) and reports a freeze restored from the notes ref instead of saying the queue is not frozen - freezeQueue docstring matches the unreadable field - new test: a train with a slot still OPEN freezes even when another train verified main's sha - test/size-ledger.test.ts fixture repo sets core.autocrlf false (Windows Free Tests shard 4 counted CRLF bytes) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: CHANGELOG [Unreleased] entry for the ship size ledger and QUEUE_TRAIN_STALE Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: run scripts/size-ledger.ts (check on this tree, refusals write nothing) The remote pregate refused82f160cwith PREGATE_NO_LANE: no test named scripts/size-ledger.ts. The new case runs the CLI itself. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: spawn scripts/size-ledger.ts with bunIsolationArgs() so native Windows Bun starts it The CLI test passed --config=/dev/null, which native Bun on Windows cannot open (#3415); Windows Free Tests shard 6 failed at4143373with exit 1 and empty stdout. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * FILES: CHANGELOG.md VERSION agents-digest/gstack-AGENTS.md package.json MERGE_CONDITION: sha=1b7c8b3af32a093924205f4894cba6c5d224630a next: NEW_VERSION=1.91.286.0; commit and push only the stamp diff above (FILES), with no edit of your own: the train's verify accepts the CHANGELOG only as the base's plus this PR's entry re-headed; merge with the expected head1b7c8b3af3and recompute on a stale queue. GSTACK_RESULT: skill=restamp status=complete run=/workspace/gstack/.gstack/tmp/restamp-journal.json 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>
70 lines
3.6 KiB
TypeScript
Executable File
70 lines
3.6 KiB
TypeScript
Executable File
#!/usr/bin/env -S bun --no-env-file --config=/dev/null
|
|
/**
|
|
* Size ledger for a carved skill's union bytes (GSTA-132; format in
|
|
* test/helpers/size-ledger.ts).
|
|
*
|
|
* size-ledger.ts record <skill> --why <text> [--branch <name>]
|
|
* set this branch's entry to what this tree's union bytes differ from the
|
|
* base plus every other entry; a zero difference deletes the entry
|
|
* size-ledger.ts check <skill>
|
|
* print measured, expected and each entry; exit 1 on a mismatch
|
|
* size-ledger.ts fold <skill> --measured-at <text>
|
|
* move the entries' sum into base.json and delete them (a tidy-up PR,
|
|
* never a stamp commit); refuses on a mismatch
|
|
*/
|
|
import { spawnSync } from 'child_process';
|
|
import { CARVE_GUARDS } from '../test/helpers/carve-guards';
|
|
import { readSkillForParity } from '../test/helpers/parity-harness';
|
|
import { foldLedger, ledgerExpected, ledgerFailure, readSizeLedger, recordEntry } from '../test/helpers/size-ledger';
|
|
|
|
const USAGE = 'usage: size-ledger.ts record <skill> --why <text> [--branch <name>] | check <skill> | fold <skill> --measured-at <text>';
|
|
|
|
function fail(msg: string, code = 2): never {
|
|
console.error(`size-ledger: ${msg}`);
|
|
process.exit(code);
|
|
}
|
|
|
|
function flag(args: string[], name: string): string | undefined {
|
|
const i = args.indexOf(name);
|
|
if (i < 0) return undefined;
|
|
const v = args[i + 1];
|
|
if (!v || v.startsWith('--')) fail(`${name} needs a value`);
|
|
return v;
|
|
}
|
|
|
|
const [cmd, skill, ...rest] = process.argv.slice(2);
|
|
if (!cmd || !skill || !['record', 'check', 'fold'].includes(cmd)) fail(USAGE);
|
|
const root = spawnSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf-8', timeout: 10_000 }).stdout?.trim() || process.cwd();
|
|
const dir = CARVE_GUARDS[skill]?.sizeLedger;
|
|
if (!dir) fail(`${skill} has no sizeLedger in test/helpers/carve-guards.ts`);
|
|
const measured = readSkillForParity(root, skill, true).unionBytes;
|
|
const ledger = readSizeLedger(root, dir);
|
|
if ('error' in ledger) fail(ledger.error, 1);
|
|
|
|
if (cmd === 'check') {
|
|
console.log(`base ${ledger.base.union_bytes} (${ledger.base.measured_at})`);
|
|
for (const e of ledger.entries) console.log(`${e.bytes > 0 ? '+' : ''}${e.bytes} ${e.file}: ${e.why}`);
|
|
console.log(`expected ${ledgerExpected(ledger)} measured ${measured}`);
|
|
const failure = ledgerFailure(skill, measured, ledger);
|
|
if (failure) fail(failure, 1);
|
|
console.log('SIZE_LEDGER: ok');
|
|
} else if (cmd === 'record') {
|
|
const why = flag(rest, '--why');
|
|
if (!why?.trim()) fail('record needs --why "<what changed>"');
|
|
const branch = flag(rest, '--branch') ?? spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: root, encoding: 'utf-8', timeout: 10_000 }).stdout?.trim();
|
|
if (!branch || branch === 'HEAD') fail('detached HEAD: pass --branch <name>');
|
|
if (branch === 'main' || branch === 'master') fail(`refusing to record on ${branch}; record on the branch that made the change`);
|
|
let r: { file: string; bytes: number };
|
|
try { r = recordEntry(root, ledger, measured, branch, why); } catch (err) { fail((err as Error).message); }
|
|
console.log(r.bytes === 0
|
|
? `SIZE_LEDGER: ${dir}/${r.file} not needed (this tree matches the ledger without it); expected ${measured}`
|
|
: `SIZE_LEDGER: ${dir}/${r.file} ${r.bytes > 0 ? '+' : ''}${r.bytes}; expected ${measured}`);
|
|
} else {
|
|
const at = flag(rest, '--measured-at');
|
|
if (!at?.trim()) fail('fold needs --measured-at "<tree it was measured on>"');
|
|
const failure = ledgerFailure(skill, measured, ledger);
|
|
if (failure) fail(`fold refused: ${failure}`, 1);
|
|
foldLedger(root, ledger, at);
|
|
console.log(`SIZE_LEDGER: folded ${ledger.entries.length} entries into ${dir}/base.json = ${measured}`);
|
|
}
|