mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 22:26:38 +03:00
Export portable Live evidence bundles
AI-assisted implementation under maintainer direction.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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: [
|
||||
|
||||
Reference in New Issue
Block a user