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>
169 lines
9.5 KiB
TypeScript
169 lines
9.5 KiB
TypeScript
import { describe, expect, test } from 'bun:test';
|
|
import { canReuseSharedLibsAdvisory, sharedLibsFingerprint } from '../lib/review-evidence';
|
|
|
|
const source = {
|
|
evidence_paths: ['src/z.ts', 'src/a.ts'],
|
|
helper_target: { path: 'lib/shared.ts', symbol: 'parseResult' },
|
|
};
|
|
// Fixed independently from the specified UTF-8 JSON tuple, not another call to the helper.
|
|
const fingerprint = 'shared-libs:bb1ca4abd2783be0a39a15e40c38e670930fad23812c33df6b979047b92522da';
|
|
const branchId = '0d6e4079e36703ebd37c00722f5891d28b0e2811dc114b129215123adcce3605';
|
|
const wtree = 'a'.repeat(40);
|
|
|
|
describe('shared-library structural identity', () => {
|
|
test('matches the versioned fixed digest and ignores caller ordering, duplicate paths and report details', () => {
|
|
expect(sharedLibsFingerprint(source)).toBe(fingerprint);
|
|
expect(sharedLibsFingerprint({
|
|
...source, evidence_paths: ['src/a.ts', 'src/z.ts', 'src/a.ts'],
|
|
line: 999, summary: 'a different rendering', fingerprint: 'untrusted model text',
|
|
})).toBe(fingerprint);
|
|
expect(source.evidence_paths).toEqual(['src/z.ts', 'src/a.ts']);
|
|
});
|
|
|
|
test('each source path, target path and target symbol changes the identity', () => {
|
|
for (const changed of [
|
|
{ ...source, evidence_paths: ['src/z.ts', 'src/b.ts'] },
|
|
{ ...source, evidence_paths: ['src/z.ts', 'src/A.ts'] },
|
|
{ ...source, evidence_paths: [...source.evidence_paths, 'src/third.ts'] },
|
|
{ ...source, helper_target: { ...source.helper_target, path: 'lib/Shared.ts' } },
|
|
{ ...source, helper_target: { ...source.helper_target, symbol: 'ParseResult' } },
|
|
]) expect(sharedLibsFingerprint(changed)).not.toBe(fingerprint);
|
|
});
|
|
|
|
test('preserves Unicode and spaces without path normalization or locale-dependent sorting', () => {
|
|
const unicode = { ...source, evidence_paths: ['src/é.ts', 'src/Z file.ts', 'src/a.ts'] };
|
|
expect(sharedLibsFingerprint(unicode)).toBe(sharedLibsFingerprint({
|
|
...unicode, evidence_paths: ['src/a.ts', 'src/é.ts', 'src/Z file.ts'],
|
|
}));
|
|
expect(sharedLibsFingerprint(unicode)).not.toBe(sharedLibsFingerprint({
|
|
...unicode, evidence_paths: ['src/é.ts', 'src/Z file.ts', 'src/a.ts'],
|
|
}));
|
|
expect(sharedLibsFingerprint({ ...source, evidence_paths: ['src/ leading.ts'] })).toBeDefined();
|
|
// Emoji's UTF-16 leading surrogate sorts before U+E000, unlike code-point sorting.
|
|
expect(sharedLibsFingerprint({
|
|
...source, evidence_paths: ['src/\ue000.ts', 'src/é.ts', 'src/😀.ts', 'src/a.ts', 'src/Z file.ts'],
|
|
})).toBe('shared-libs:e48c488d014da5440e9922a6500f91b33605650b93222247d1c29b89d6638255');
|
|
});
|
|
|
|
test('rejects missing and malformed structures, including sparse path arrays', () => {
|
|
const malformed: unknown[] = [
|
|
undefined, null, false, 1, '', [], {}, { evidence_paths: source.evidence_paths },
|
|
{ ...source, evidence_paths: [] }, { ...source, evidence_paths: 'src/a.ts' },
|
|
{ ...source, evidence_paths: [null] }, { ...source, evidence_paths: [1] },
|
|
{ ...source, evidence_paths: Array(1) },
|
|
{ ...source, helper_target: null }, { ...source, helper_target: [] },
|
|
{ ...source, helper_target: { path: 'lib/shared.ts' } },
|
|
{ ...source, helper_target: { path: 'lib/shared.ts', symbol: '' } },
|
|
{ ...source, helper_target: { path: 'lib/shared.ts', symbol: ' ' } },
|
|
{ ...source, helper_target: { path: 'lib/shared.ts', symbol: 42 } },
|
|
{ ...source, helper_target: { path: 'lib/shared.ts', symbol: 'parse\nResult' } },
|
|
];
|
|
for (const value of malformed) expect(sharedLibsFingerprint(value)).toBeUndefined();
|
|
});
|
|
|
|
test('rejects paths that cannot be reused as unambiguous Git-relative source locations', () => {
|
|
for (const path of [
|
|
'', ' ', '/src/a.ts', 'C:/src/a.ts', 'C:src/a.ts', '\\src\\a.ts', 'src\\a.ts',
|
|
'./src/a.ts', '../src/a.ts', 'src/../a.ts', 'src/./a.ts', 'src//a.ts', 'src/',
|
|
'.git/config', 'nested/.git/config', 'src/a\0.ts', 'src/a\n.ts', 'src/a\t.ts',
|
|
]) {
|
|
expect(sharedLibsFingerprint({ ...source, evidence_paths: [path] })).toBeUndefined();
|
|
expect(sharedLibsFingerprint({ ...source, helper_target: { path, symbol: 'parseResult' } })).toBeUndefined();
|
|
}
|
|
});
|
|
});
|
|
|
|
function evidence() {
|
|
return {
|
|
prior: {
|
|
...source, fingerprint, advisory: true, severity: 'INFORMATIONAL', action: 'skipped',
|
|
snapshot_covered_paths: [...source.evidence_paths],
|
|
},
|
|
current: { ...source, advisory: true, severity: 'INFORMATIONAL' },
|
|
review: {
|
|
skill: 'review', completed: true, converged: true, status: 'clean', wtree,
|
|
review_binding: { state: 'verified', start_wtree: wtree, end_wtree: wtree, branch_id: branchId },
|
|
},
|
|
snapshot: { wtree, branch_id: branchId, covered_paths: [...source.evidence_paths] },
|
|
};
|
|
}
|
|
|
|
describe('shared-library advisory skip reuse', () => {
|
|
test('requires identity, trusted unchanged binding and coverage, independently of unrelated defects', () => {
|
|
const { prior, current, review, snapshot } = evidence();
|
|
expect(canReuseSharedLibsAdvisory(prior, current, review, snapshot)).toBe(true);
|
|
expect(canReuseSharedLibsAdvisory(prior, current, {
|
|
...review, status: 'issues_found', issues_found: 1, critical: 1,
|
|
}, snapshot)).toBe(true);
|
|
});
|
|
|
|
test('advisories cannot suppress defects, fixed findings, malformed identities or forged saved hashes', () => {
|
|
const { prior, current, review, snapshot } = evidence();
|
|
for (const changed of [
|
|
{ ...prior, advisory: false }, { ...prior, advisory: undefined },
|
|
{ ...prior, severity: 'CRITICAL' }, { ...prior, severity: undefined },
|
|
{ ...prior, action: 'fixed' }, { ...prior, action: 'auto-fixed' }, { ...prior, action: undefined },
|
|
{ ...prior, fingerprint: 'shared-libs:invented' }, { ...prior, fingerprint: undefined },
|
|
{ ...prior, evidence_paths: undefined }, { ...prior, helper_target: undefined },
|
|
{ ...prior, helper_target: { ...source.helper_target, symbol: 'otherHelper' } },
|
|
]) expect(canReuseSharedLibsAdvisory(changed, current, review, snapshot)).toBe(false);
|
|
for (const changed of [
|
|
{ ...current, advisory: false }, { ...current, advisory: undefined },
|
|
{ ...current, severity: 'CRITICAL' }, { ...current, fingerprint: 'shared-libs:invented' },
|
|
]) expect(canReuseSharedLibsAdvisory(prior, changed, review, snapshot)).toBe(false);
|
|
});
|
|
|
|
test('rejects legacy, mismatched, incomplete and non-review binding evidence', () => {
|
|
const { prior, current, review, snapshot } = evidence();
|
|
for (const changed of [
|
|
{}, { ...review, skill: 'ship' }, { ...review, skill: 'plan-eng-review' },
|
|
{ ...review, completed: false }, { ...review, completed: undefined },
|
|
{ ...review, converged: false }, { ...review, converged: undefined },
|
|
{ ...review, wtree: undefined }, { ...review, review_binding: undefined },
|
|
...['uncaptured', 'changed', 'incomplete'].map(state => ({
|
|
...review, review_binding: { ...review.review_binding, state },
|
|
})),
|
|
{ ...review, review_binding: { ...review.review_binding, start_wtree: 'b'.repeat(40) } },
|
|
{ ...review, review_binding: { ...review.review_binding, end_wtree: 'b'.repeat(40) } },
|
|
{ ...review, review_binding: { ...review.review_binding, branch_id: undefined } },
|
|
]) expect(canReuseSharedLibsAdvisory(prior, current, changed, snapshot)).toBe(false);
|
|
for (const changed of [
|
|
{}, { ...snapshot, wtree: 'unknown' }, { ...snapshot, wtree: 'b'.repeat(40) },
|
|
{ ...snapshot, branch_id: 'b'.repeat(64) }, { ...snapshot, branch_id: 'unknown' },
|
|
]) expect(canReuseSharedLibsAdvisory(prior, current, review, changed)).toBe(false);
|
|
});
|
|
|
|
test('every secondary caller must be positively covered, even when the Git tree is unchanged', () => {
|
|
const { prior, current, review, snapshot } = evidence();
|
|
// Callers exclude symlinks, dirty submodules, transformed files, assume-unchanged
|
|
// and skip-worktree index entries from covered_paths.
|
|
// The canonical Git tree can remain unchanged while that raw source changes.
|
|
for (const covered_paths of [undefined, [], ['src/a.ts'], ['src/z.ts'], Array(2), ['../outside.ts']]) {
|
|
expect(canReuseSharedLibsAdvisory(prior, current, review, { ...snapshot, covered_paths })).toBe(false);
|
|
}
|
|
expect(canReuseSharedLibsAdvisory(null, current, review, snapshot)).toBe(false);
|
|
expect(canReuseSharedLibsAdvisory(prior, null, review, snapshot)).toBe(false);
|
|
expect(canReuseSharedLibsAdvisory(prior, current, null, snapshot)).toBe(false);
|
|
expect(canReuseSharedLibsAdvisory(prior, current, review, null)).toBe(false);
|
|
});
|
|
|
|
test('prior coverage must be complete and valid; legacy records require revalidation', () => {
|
|
const { prior, current, review, snapshot } = evidence();
|
|
for (const snapshot_covered_paths of [
|
|
undefined, null, 'src/a.ts', [], ['src/a.ts'], ['src/z.ts'],
|
|
Array(2), ['../outside.ts'], ['src/a.ts', 1],
|
|
]) {
|
|
expect(canReuseSharedLibsAdvisory({ ...prior, snapshot_covered_paths }, current, review, snapshot)).toBe(false);
|
|
}
|
|
});
|
|
|
|
test('removing a prior transformation cannot reuse different raw source under the same tree hash', () => {
|
|
const { prior, current, review, snapshot } = evidence();
|
|
// A prior clean filter normalized different raw caller bytes to this same tree.
|
|
// It is now removed and current raw bytes match the tree, so current coverage
|
|
// is complete. The original decision still lacks prior raw-to-blob coverage.
|
|
expect(canReuseSharedLibsAdvisory({ ...prior, snapshot_covered_paths: [] }, current, review, snapshot)).toBe(false);
|
|
expect(canReuseSharedLibsAdvisory(prior, current, review, snapshot)).toBe(true);
|
|
});
|
|
});
|