mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-26 22:51:47 +02:00
* feat: bind shared-code review advice to source and branch * feat: add shared-code extraction audit and scoped review checks * test: recognize complete source reads and explicit coverage legends * chore: bump version and changelog (v1.88.0.0) Co-Authored-By: OpenAI Codex <noreply@openai.com> * test: capture native review questions and retain public evidence Capture the actual first public native question with strict ownership and display matching. Preserve terminal failures and raw evidence, and retain SDK completion checks. * test: recognize verified review evidence and complete fixtures Recognize complete source and diagram evidence, concrete design and developer-experience decisions, and the complete planted scenario contracts. Preserve negative controls and grading thresholds. * fix: preserve decision brief structure in native questions Keep the required pros-and-cons heading and final Net field in native question text. Regenerate host outputs and document the release and evaluation repairs. Co-Authored-By: OpenAI Codex <noreply@openai.com> * docs: update project documentation for v1.88.0.0 Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix: correct eval retry accounting and ship workflow gates * fix: capture native eval evidence and stabilize CI fixtures * fix: keep shared-code eval skips read-only Choose explicit no-change answers instead of mixed fix/preservation options. Reuse the bounded revalidation prompt for path fixtures so required review metadata is available without repeated discovery. Preserve source checks, retry limits, and failed native terminal outcomes. Add captured-question and callback regressions, plus evaluation selection coverage for the affected fixtures. --------- Co-authored-by: OpenAI Codex <noreply@openai.com>
110 lines
6.8 KiB
TypeScript
110 lines
6.8 KiB
TypeScript
import { describe, expect, test } from 'bun:test';
|
|
import * as fs from 'node:fs';
|
|
import * as os from 'node:os';
|
|
import * as path from 'node:path';
|
|
import { createPlanCountSnapshotWriter, persistPlanCountSnapshot } from './helpers/plan-count-artifacts';
|
|
|
|
const input = {
|
|
skillName: 'plan-design-review', observation: { outcome: 'timeout', reviewCount: 3 },
|
|
raw: '\x1b[2JSTART\r' + 'raw-frame\r'.repeat(2000) + '\x1b[31mEND',
|
|
visible: 'START\r' + 'visible-frame\r'.repeat(2000) + 'END',
|
|
cwd: '/temporary/count-fixture', claudeConfigDir: '/temporary/claude-config',
|
|
};
|
|
|
|
describe('plan-count diagnostic artifacts', () => {
|
|
test('refreshes one in-progress attempt through final outcome without keeping old copies', () => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'plan-count-artifacts-'));
|
|
try {
|
|
const save = createPlanCountSnapshotWriter({ EVALS_RUN_ID: 'checkpoint', GSTACK_EVAL_DIR: root });
|
|
const progress = save({ ...input, observation: { state: 'in_progress', reviewCount: 1 } });
|
|
const recordPath = path.join(progress.artifactDir!, 'observation.json');
|
|
expect(JSON.parse(fs.readFileSync(recordPath, 'utf8'))).toMatchObject({ state: 'in_progress', reviewCount: 1 });
|
|
const final = save({ ...input, raw: input.raw + '\nlast question', observation: { outcome: 'completion_summary', reviewCount: 5 } });
|
|
expect(final.artifactDir).toBe(progress.artifactDir);
|
|
const record = JSON.parse(fs.readFileSync(recordPath, 'utf8'));
|
|
expect(record).toMatchObject({ outcome: 'completion_summary', reviewCount: 5 });
|
|
expect(record.state).toBeUndefined();
|
|
expect(fs.readdirSync(final.artifactDir!).sort()).toEqual(['observation.json', 'terminal.raw.log', 'terminal.visible.log']);
|
|
expect(fs.readFileSync(path.join(final.artifactDir!, 'terminal.raw.log'), 'utf8')).toBe(input.raw + '\nlast question');
|
|
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
|
});
|
|
test('keeps complete output and distinct retry records in the configured eval directory', () => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'plan-count-artifacts-'));
|
|
try {
|
|
const env = { EVALS_RUN_ID: 'same-run', GSTACK_EVAL_DIR: root };
|
|
const first = persistPlanCountSnapshot(input, env);
|
|
const second = persistPlanCountSnapshot({ ...input, raw: 'retry' }, env);
|
|
expect(first.artifactError).toBeUndefined();
|
|
expect(second.artifactError).toBeUndefined();
|
|
expect(first.artifactDir).not.toBe(second.artifactDir);
|
|
expect(path.relative(root, first.artifactDir!)).toStartWith(path.join('pty-count', 'same-run'));
|
|
expect(fs.readFileSync(path.join(first.artifactDir!, 'terminal.raw.log'), 'utf8')).toBe(input.raw);
|
|
expect(fs.readFileSync(path.join(first.artifactDir!, 'terminal.visible.log'), 'utf8')).toBe(input.visible);
|
|
const record = JSON.parse(fs.readFileSync(path.join(first.artifactDir!, 'observation.json'), 'utf8'));
|
|
expect(record).toMatchObject({ ...input.observation, artifactDir: first.artifactDir,
|
|
capture: { skill: input.skillName, cwd: input.cwd, claudeConfigDir: input.claudeConfigDir } });
|
|
expect(fs.readFileSync(path.join(second.artifactDir!, 'terminal.raw.log'), 'utf8')).toBe('retry');
|
|
if (process.platform !== 'win32') {
|
|
expect(fs.statSync(path.join(first.artifactDir!, 'terminal.raw.log')).mode & 0o777).toBe(0o600);
|
|
}
|
|
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('retains explicitly requested captures without a run ID and isolates invocation fallbacks', () => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'plan-count-artifacts-'));
|
|
try {
|
|
// The paid shard launcher sets GSTACK_EVAL_DIR without EVALS_RUN_ID.
|
|
const env = { GSTACK_EVAL_DIR: root };
|
|
const save = createPlanCountSnapshotWriter(env);
|
|
const progress = save({ ...input, observation: { state: 'in_progress', reviewCount: 1 } });
|
|
expect(progress.artifactError).toBeUndefined();
|
|
expect(progress.artifactDir).toBeDefined();
|
|
const first = JSON.parse(fs.readFileSync(path.join(progress.artifactDir!, 'observation.json'), 'utf8'));
|
|
expect(first.capture.runId).toMatch(/^local-[0-9a-f-]{36}$/);
|
|
expect(path.relative(root, progress.artifactDir!)).toStartWith(path.join('pty-count', first.capture.runId));
|
|
|
|
const final = save({ ...input, raw: 'final output', observation: { outcome: 'plan_ready', reviewCount: 5 } });
|
|
expect(final.artifactDir).toBe(progress.artifactDir);
|
|
const record = JSON.parse(fs.readFileSync(path.join(final.artifactDir!, 'observation.json'), 'utf8'));
|
|
expect(record).toMatchObject({ outcome: 'plan_ready', capture: { runId: first.capture.runId } });
|
|
expect(record.state).toBeUndefined();
|
|
expect(fs.readFileSync(path.join(final.artifactDir!, 'terminal.raw.log'), 'utf8')).toBe('final output');
|
|
expect(fs.readFileSync(path.join(final.artifactDir!, 'terminal.visible.log'), 'utf8')).toBe(input.visible);
|
|
|
|
const retry = persistPlanCountSnapshot(input, env);
|
|
const retried = JSON.parse(fs.readFileSync(path.join(retry.artifactDir!, 'observation.json'), 'utf8'));
|
|
expect(retry.artifactDir).not.toBe(final.artifactDir);
|
|
expect(retried.capture.runId).not.toBe(first.capture.runId);
|
|
expect(path.dirname(retry.artifactDir!)).not.toBe(path.dirname(final.artifactDir!));
|
|
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('does not persist ordinary free runs without either capture setting', () => {
|
|
expect(persistPlanCountSnapshot(input, {})).toEqual({});
|
|
expect(persistPlanCountSnapshot(input, { EVALS_RUN_ID: '', GSTACK_EVAL_DIR: '' })).toEqual({});
|
|
});
|
|
|
|
test('keeps run and skill identifiers within the owned artifact directory', () => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'plan-count-artifacts-'));
|
|
try {
|
|
const saved = persistPlanCountSnapshot({ ...input, skillName: '../../other' }, {
|
|
EVALS_RUN_ID: '../outside', GSTACK_EVAL_DIR: root,
|
|
});
|
|
expect(saved.artifactError).toBeUndefined();
|
|
expect(path.relative(root, saved.artifactDir!)).not.toStartWith('..');
|
|
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('reports a diagnostic write failure without replacing the original observation', () => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'plan-count-artifacts-'));
|
|
const file = path.join(root, 'file');
|
|
fs.writeFileSync(file, 'unchanged');
|
|
try {
|
|
const result = persistPlanCountSnapshot(input, { EVALS_RUN_ID: 'run', GSTACK_EVAL_DIR: file });
|
|
expect(result.artifactError).toBeDefined();
|
|
expect(input.observation).toEqual({ outcome: 'timeout', reviewCount: 3 });
|
|
expect(fs.readFileSync(file, 'utf8')).toBe('unchanged');
|
|
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
|
});
|
|
});
|