mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-12 19:44:48 +01:00
fix: pre-landing review fixes
Red team (/ship Step 9): a Drive copy at a bootstrapper revision below GSTACK_CAPY_MIN_WRAPPER is a WARN with the owner action in a direct (no-provenance) run too; only a pre-bootstrapper copy fails. A --for none session never self-upgrades. Stale fail-behind comment in gstack-capy-session; SKILL.md says ok not-needed is not an install verdict. Tests: UPGRADE_SKIPPED collapse, silent in-place message, direct-run WARN, wrapper-2 --for none handover. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
6a0f9e47bb
commit
fc69d3ff0b
10 files changed
+72
-14
No files matched your search
@@ -393,6 +393,18 @@ describe('capy skill: the session hands the installer GSTACK_CAPY_BEHIND', () =>
|
||||
}
|
||||
});
|
||||
|
||||
test('an older bootstrapper handing --for none to the session in install mode: the session certifies nothing and moves nothing (no self-upgrade, HEAD unchanged), and reports behind like --check', () => {
|
||||
const f = fixture({ cloneAt: 'B' });
|
||||
write(path.join(f.root, 'bin/gstack-capy-install'), ENV_INSTALLER, 0o755);
|
||||
f.git(['update-index', '--assume-unchanged', 'bin/gstack-capy-install']);
|
||||
f.git(['fetch', '-q', 'origin', 'main']);
|
||||
const r = spawnSync('bash', [path.join(f.root, 'bin/gstack-capy-session'), '--root', f.root, '--for', 'none'], { cwd: f.host.home, encoding: 'utf8', env: { ...f.host.env, GSTACK_CAPY_REMOTE_MIN: '1.0.1', GSTACK_CAPY_WRAPPER_REV: '2', GSTACK_CAPY_WRAPPER_PATH: BOOT }, timeout: 120_000 });
|
||||
expect(r.status, r.stdout + r.stderr).toBe(0);
|
||||
expect(r.stdout).not.toMatch(/^SELF_UPGRADE:/m);
|
||||
expect(r.stdout.trim().split('\n').at(-1)).toBe(`gstack: ok 1.0.1 for=autoplan behind=1 to=1.0.2 fix=bash ${BOOT} --for none`);
|
||||
expect(f.git(['rev-parse', 'HEAD'])).toBe(f.b);
|
||||
});
|
||||
|
||||
test('current, or the fetch failed: nothing is exported, and values inherited from a parent session are dropped', () => {
|
||||
const f = fixture({ cloneAt: 'B' });
|
||||
f.git(['fetch', '-q', 'origin', 'main']);
|
||||
|
||||
@@ -293,6 +293,11 @@ describe('gstack-capy-install', () => {
|
||||
const bare = run(f, [], { ...busy, GSTACK_CAPY_BEHIND_BLOCKED: 'gstack-upgrade exit 9' });
|
||||
expect(bare.status).toBe(0);
|
||||
expect(lastLine(bare.stdout)).toBe(`gstack: ok 1.2.3 for=autoplan (behind=3 (latest: 1.2.6); upgrade skipped: gstack-upgrade exit 9 (UPGRADE_REFUSED); fix: ${f.root}/bin/gstack-upgrade)`);
|
||||
// A code the installer does not know collapses to UPGRADE_SKIPPED, whose anchor exists; the reason and fix are kept.
|
||||
const other = run(f, [], { ...busy, GSTACK_CAPY_BEHIND_BLOCKED: 'origin unreachable; fix: retry when online (UPGRADE_FETCH_FAILED)' });
|
||||
expect(other.status).toBe(0);
|
||||
expect(lastLine(other.stdout)).toBe('gstack: ok 1.2.3 for=autoplan (behind=3 (latest: 1.2.6); upgrade skipped: origin unreachable (UPGRADE_SKIPPED); fix: retry when online)');
|
||||
expect(other.stdout).toMatch(/^WARN behind — .*; fix: retry when online \(UPGRADE_SKIPPED; .*#upgrade-skipped\)$/m);
|
||||
expect(lastLine(run(f, [], { ...busy, STUB_DOCTOR_FAIL: '1' }).stdout)).toBe('gstack: fail codex');
|
||||
});
|
||||
|
||||
@@ -338,6 +343,11 @@ describe('gstack-capy-install', () => {
|
||||
const verdict = full.stdout.match(/GSTACK_INSTALL_VERDICT=(\S+)/)![1]!;
|
||||
expect(JSON.parse(fs.readFileSync(verdict, 'utf8'))).toMatchObject({ for: 'autoplan', ok: true });
|
||||
expect(lastLine(full.stdout)).toBe('gstack: ok 1.2.3 for=autoplan');
|
||||
// The message is for the review-voice -> workflow step only: a rerun of the same profile, a --check and a second review-voice install stay silent.
|
||||
const upgrading = /upgrading the review-voice install in place/;
|
||||
expect(run(f, ['--for', 'autoplan', '--project', project]).stdout).not.toMatch(upgrading);
|
||||
expect(run(f, ['--check', '--for', 'autoplan', '--project', project]).stdout).not.toMatch(upgrading);
|
||||
expect(run(f, ['--for', 'review-voice', '--project', project]).stdout).not.toMatch(upgrading);
|
||||
});
|
||||
|
||||
test('--root clones when the directory is absent and refuses a non-gstack directory', () => {
|
||||
|
||||
@@ -885,6 +885,22 @@ describe('gstack-doctor --check: wrapper and runtime drift', () => {
|
||||
expect(fresh.status, fresh.out).toBe(0);
|
||||
});
|
||||
|
||||
posixPathTest('direct doctor run: a bootstrapper Drive copy below the minimum still works, so it is an owner-action WARN with an ok trailer (only a pre-bootstrapper copy fails)', () => {
|
||||
const f = makeFixture();
|
||||
withSupport(f, Number(currentRev) + 1);
|
||||
const old = drive(f, 'user-garry-tan', current);
|
||||
const r = parse(f, []);
|
||||
expect(r.status, r.out).toBe(0);
|
||||
expect(r.trailer).toMatch(/^gstack: ok /);
|
||||
expect(r.line('wrapper')).toBe(`WARN wrapper — every Capy skill copy is below the minimum wrapper ${Number(currentRev) + 1} (it still works): ${old} (wrapper ${currentRev}); owner action: copy ${f.root}/capy/skill/gstack/ over the Drive skill folder, or have Capy re-sync it; this recurs every session until the Drive copy changes (CAPY_WRAPPER_STALE; https://github.com/garrytan/gstack/blob/main/docs/troubleshooting.md#capy-wrapper-stale)`);
|
||||
const json = JSON.parse(doctor(f, ['--check', '--json']).out);
|
||||
expect(json.ok).toBe(true);
|
||||
expect(json.rows.find((x: { id: string }) => x.id === 'wrapper')).toMatchObject({ status: 'WARN', code: 'CAPY_WRAPPER_STALE' });
|
||||
// A pre-bootstrapper copy beside it keeps the FAIL: that copy cannot hand over at all.
|
||||
drive(f, 'org', PRE_BOOTSTRAPPER);
|
||||
expect(parse(f, []).trailer).toBe('gstack: fail wrapper');
|
||||
});
|
||||
|
||||
posixPathTest('two Drive copies, one current: PASS naming the stale one; GSTACK_CAPY_WRAPPER_PATH alone decides when set without a revision', () => {
|
||||
const f = makeFixture();
|
||||
withSupport(f);
|
||||
|
||||
Reference in new issue
Block a user