Export portable Live evidence bundles

AI-assisted implementation under maintainer direction.
This commit is contained in:
Paul Bakaus
2026-07-13 13:56:25 -07:00
parent 7a99e1725d
commit e0c19eff28
7 changed files with 161 additions and 12 deletions
+35
View File
@@ -120,3 +120,38 @@ When `preActions` is omitted, steer smoke inherits `runtime.preActions` to revea
| `nuxt-csp/` | Nuxt `routeRules` with literal CSP header in `nuxt.config.ts`. CSP shape `append-string`. |
Add new fixtures by cloning a directory, swapping files, and updating `fixture.json`.
## External quality-eval fixtures
The public Live benchmark can execute a fixture owned by another repository
without copying its task corpus or rubric into Impeccable:
```sh
bun run bench:live -- \
--fixture-dir=/absolute/path/to/private-fixture \
--agent=codex \
--action=bolder \
--iterations=1 \
--evidence-bundle=/absolute/path/to/output-bundle
```
An external fixture has the same shape as a directory in this folder:
`fixture.json`, `gitignore.txt`, and `files/`. Use the optional
`evidenceCapture` block in `fixture.json` for rubric-free capture metadata:
```json
{
"evidenceCapture": {
"captureSelector": "section.case-study",
"viewport": { "width": 1440, "height": 1080 },
"action": "bolder"
}
}
```
The bundle contains `report.json`, the original capture, each progressively
delivered variant capture, geometry/overflow facts, hashes, and timing data.
It deliberately cannot run `--judge-rendered`; comparative rubrics, private
fixtures, human calibration, and quality decisions belong in the consuming
evaluation harness. The normal public E2E suite remains responsible for Live
protocol, framework, source-commit, cleanup, and recovery correctness.
+31
View File
@@ -9,6 +9,7 @@ import {
deriveJournalGenerationMetrics,
durationBetween,
parseLiveBenchmarkArgs,
resolveLiveBenchmarkPaths,
summarizeRuns,
} from '../scripts/lib/live-benchmark.mjs';
@@ -27,6 +28,36 @@ describe('live benchmark metrics', () => {
});
});
it('resolves an external fixture into a portable rubric-free evidence bundle', () => {
const paths = resolveLiveBenchmarkPaths({
fixtureDir: '../impeccable-evals/fixtures/live/tidewater',
evidenceBundle: '/tmp/live-tidewater',
}, {
root: '/workspace/impeccable',
fixturesDir: '/workspace/impeccable/tests/framework-fixtures',
});
assert.deepEqual(paths, {
fixtureName: 'tidewater',
fixtureDir: '/workspace/impeccable-evals/fixtures/live/tidewater',
fixtureOrigin: 'external',
evidenceRoot: '/tmp/live-tidewater',
artifactRoot: '/tmp/live-tidewater',
outputPath: '/tmp/live-tidewater/report.json',
});
});
it('keeps evidence bundles atomic and unambiguous', () => {
const options = { root: '/repo', fixturesDir: '/repo/tests/framework-fixtures' };
assert.throws(
() => resolveLiveBenchmarkPaths({ evidenceBundle: 'bundle', artifacts: 'shots' }, options),
/replaces --artifacts/,
);
assert.throws(
() => resolveLiveBenchmarkPaths({ evidenceBundle: 'bundle', output: 'report.json' }, options),
/writes report.json itself/,
);
});
it('derives production worker phases from the durable session journal', () => {
const metrics = deriveJournalGenerationMetrics({
generationTimings: {
+4 -3
View File
@@ -32,8 +32,7 @@ export { SCRIPTS_DIR, FIXTURES_DIR, REPO_ROOT };
// Stage
// ---------------------------------------------------------------------------
export function stageFixture(name, fixture) {
const fixtureRoot = join(FIXTURES_DIR, name);
export function stageFixture(name, fixture, { fixtureRoot = join(FIXTURES_DIR, name) } = {}) {
const gitignore = readFileSync(join(fixtureRoot, 'gitignore.txt'), 'utf-8');
const tmp = mkdtempSync(join(tmpdir(), 'impeccable-e2e-'));
@@ -216,6 +215,7 @@ export async function stopDevServer(child) {
* @param {object} opts
* @param {string} opts.name fixture name
* @param {object} opts.fixture fixture.json contents
* @param {string=} opts.fixtureRoot fixture directory; defaults to the public framework fixture tree
* @param {import('playwright').Browser} opts.browser shared browser instance
* @param {object} opts.agent VariantAgent (defaults to fake)
* @param {object|function=} opts.wrapTarget live-wrap target or event mapper
@@ -228,6 +228,7 @@ export async function stopDevServer(child) {
export async function bootFixtureSession({
name,
fixture,
fixtureRoot,
browser,
agent,
wrapTarget,
@@ -244,7 +245,7 @@ export async function bootFixtureSession({
const runtime = fixture.runtime;
if (!runtime) throw new Error(`fixture ${name} has no runtime block`);
const tmp = stageFixture(name, fixture);
const tmp = stageFixture(name, fixture, { fixtureRoot });
let live;
let dev;
let agentAbort;
+20
View File
@@ -47,6 +47,26 @@ describe('Live rendered quality judge', () => {
assert.equal(context.safeContext.componentRoles.ActionLink, 'Quiet outlined control');
});
it('prefers rubric-free evidence capture settings for external harnesses', () => {
const context = buildRenderedReviewContext({
fixture: 'private-fixture',
fixtureConfig: {
runtime: { pickSelector: '.picked' },
evidenceCapture: {
captureSelector: '.selected-section',
action: 'bolder',
},
renderedQuality: {
captureSelector: '.public-smoke-only',
reviewFocus: 'Must not leak into the evidence contract.',
},
},
});
assert.equal(context.captureSelector, '.selected-section');
assert.equal(context.action, 'bolder');
assert.equal(context.safeContext.reviewFocus, '');
});
it('requires every expected rendered variant to pass the strict score floor', () => {
const result = parseRenderedJudgeResult(JSON.stringify({
variants: [