mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-02 17:40:02 +02:00
* feat: add surface-aware exploratory QA and ship documentation gates * test: preserve delegated QA setup authority after main integration * fix(qa): clarify exploration order and preserve report artifacts * test(qa): follow the shared setup reference directly * refactor(ship): make verification and recovery routes explicit * test(ship): align evidence and review guards with explicit routes * fix(workflows): clarify ship recovery and functional QA evidence * fix(workflows): clarify approval recovery and full QA coverage * refactor(workflows): order review transactions and clarify ship state * fix(ship): clarify final verification and fail closed at publication * fix(evals): attribute native atomic documentation writes * fix(ship): clarify recovery and documentation lifecycle guidance * fix(test): preserve observed native placeholder styling in CI * fix(codex): report watchdog timeouts without a process-exit race * Checkpoint functional QA implementation and workflow validation repairs * Fix documentation and shared-review fixture contracts * docs: clarify judge reuse and evaluation supervision * test: align review evidence and selected case contracts * test: verify append-only documentation checkpoints and recovery * fix: qualify QA workflows and CI validation repairs * fix: launch shared-libs fixture scripts on Windows * fix: qualify QA deadlines, fixture isolation, and shard cleanup * fix: preserve qualified QA and cancellation repairs * fix: enforce functional fixture authority and share strict event decoding * fix: retain free-test evidence and explain recovery * fix: reject malformed native evidence after decoder consolidation * test: use reliable capture for telemetry privacy filters * test: refresh measured quick coverage and document validation costs * Fix native fixture receipts and preserve VM validation evidence * Align negative judge controls with upstream clarity policy * Fix report-only QA preparation and public evidence handling * Clarify QA-only preparation and current-report preservation * Stream Ship quality judgments with an explicit 64k response contract * Validate compact judge reasoning locally with supported wire schema * Align functional QA fixture instructions with evidence acceptance * Bind native browser diagnostics to execution evidence and align review verdicts * Preserve native diagnostic line boundaries * Serialize functional QA evidence from native captures * Keep large QA evidence fixture payload out of Windows argv
60 lines
3.7 KiB
TypeScript
60 lines
3.7 KiB
TypeScript
import { expect, test } from 'bun:test';
|
|
import * as fs from 'node:fs';
|
|
import * as os from 'node:os';
|
|
import * as path from 'node:path';
|
|
import { E2E_TOUCHFILES, selectTests } from './helpers/touchfiles';
|
|
|
|
const ROOT = path.resolve(import.meta.dir, '..');
|
|
const source = fs.readFileSync(path.join(ROOT, 'test/skill-e2e-qa-bugs.test.ts'), 'utf8');
|
|
const setup = source.match(/^function browserSetupSection\(\): string \{[\s\S]*?^\}/m)?.[0];
|
|
const runner = source.match(/^ async function runPlantedBugEval\([\s\S]*?^ \}/m)?.[0];
|
|
const registrations = [...source.matchAll(/^ testConcurrentIfSelected\('qa-b[678]-[^']+', async \(\) => \{[\s\S]*?^ \}, CAPTURE_LONG_MS\);/gm)].map(match => match[0]);
|
|
if (!setup || !runner || registrations.length !== 3) throw new Error('Missing actual planted-browser fixture functions or registrations');
|
|
const script = new Bun.Transpiler({ loader: 'ts' }).transformSync([setup, runner, ...registrations].join('\n'));
|
|
const asset = fs.readFileSync(path.join(ROOT, 'qa/sections/browser-setup.md'), 'utf8');
|
|
const ids = ['qa-b6-static', 'qa-b7-spa', 'qa-b8-checkout'];
|
|
|
|
test('planted-browser fixture regression selects its three actual consumers', () => {
|
|
expect(selectTests(['test/qa-bugs-fixture.test.ts'], E2E_TOUCHFILES).selected?.sort()).toEqual(ids);
|
|
});
|
|
|
|
for (const id of ids) test.each(['complete section', 'additional trailing policy', 'missing section'])(`${id} retains the carved browser setup: %s`, async scenario => {
|
|
const owned = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'qa-bugs-fixture-')));
|
|
const section = scenario === 'additional trailing policy' ? asset + '\n## Additional policy\nPreserve this final policy.\n' : asset;
|
|
const calls: unknown[] = [];
|
|
const callbacks = new Map<string, () => Promise<void>>();
|
|
const stopped = new Error('Stopped at the offline actor boundary');
|
|
try {
|
|
fs.mkdirSync(path.join(owned, 'qa/sections'), { recursive: true });
|
|
fs.writeFileSync(path.join(owned, 'qa/SKILL.md'), '# QA entrypoint\nRead the carved sections.\n');
|
|
if (scenario !== 'missing section') fs.writeFileSync(path.join(owned, 'qa/sections/browser-setup.md'), section);
|
|
new Function('fs', 'path', 'os', 'ROOT', 'setupBrowseShims', 'testServer', 'browseBin',
|
|
'runSkillTest', 'runId', 'CAPTURE_MS', 'CAPTURE_LONG_MS', 'testConcurrentIfSelected', script)(
|
|
fs, path, { ...os, tmpdir: () => owned }, owned, () => {}, { url: 'http://fixture.invalid' }, '/unused/browse',
|
|
async (options: { workingDirectory: string; prompt: string; testName: string }) => {
|
|
calls.push(options);
|
|
const actual = fs.readFileSync(path.join(options.workingDirectory, 'BROWSER-SETUP.md'), 'utf8');
|
|
expect(actual).toBe(section);
|
|
expect(actual.indexOf('## Browser access decision')).toBeLessThan(actual.indexOf('## BROWSER SETUP'));
|
|
expect(actual).toContain('Unknown caller: use report-only authority');
|
|
expect(actual).toContain('## Browser fallback');
|
|
expect(actual).toContain('Invocation does not authorize external mutations');
|
|
expect(options.testName).toBe(id);
|
|
expect(options.prompt).toContain('read BROWSER-SETUP.md in this directory and follow it exactly');
|
|
throw stopped;
|
|
}, 'offline-fixture', 300000, 600000,
|
|
(name: string, callback: () => Promise<void>) => callbacks.set(name, callback),
|
|
);
|
|
expect([...callbacks.keys()]).toEqual(ids);
|
|
if (scenario === 'missing section') {
|
|
await expect(callbacks.get(id)!()).rejects.toThrow('ENOENT');
|
|
expect(calls).toHaveLength(0);
|
|
} else {
|
|
await expect(callbacks.get(id)!()).rejects.toBe(stopped);
|
|
expect(calls).toHaveLength(1);
|
|
}
|
|
} finally {
|
|
fs.rmSync(owned, { recursive: true, force: true });
|
|
}
|
|
});
|