@skill-harness/core 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/dist/adapters/types.d.ts +0 -12
- package/dist/capture-trace-types.d.ts +0 -96
- package/dist/capture-trace-types.js +0 -4
- package/dist/command-cost.d.ts +1 -1
- package/dist/command-cost.js +0 -5
- package/dist/execution-trace.js +1 -1
- package/dist/index.d.ts +3 -23
- package/dist/index.js +3 -23
- package/dist/instruction-coverage.d.ts +0 -7
- package/dist/instruction-coverage.js +5 -7
- package/dist/journal.d.ts +0 -8
- package/dist/metrics.d.ts +18 -0
- package/dist/metrics.js +28 -0
- package/dist/redaction.d.ts +6 -0
- package/dist/redaction.js +55 -0
- package/dist/regate.js +6 -71
- package/dist/regrade.d.ts +1 -3
- package/dist/regrade.js +1 -21
- package/dist/report.d.ts +1 -15
- package/dist/report.js +1 -13
- package/dist/reps.d.ts +1 -2
- package/dist/reps.js +0 -2
- package/dist/results.d.ts +0 -9
- package/dist/results.js +2 -19
- package/dist/run.js +11 -72
- package/dist/seeded.d.ts +1 -7
- package/dist/seeded.js +5 -11
- package/dist/sources.js +4 -9
- package/dist/spec.d.ts +0 -13
- package/dist/spec.js +6 -48
- package/dist/trajectory-events.d.ts +58 -0
- package/dist/trajectory-events.js +119 -0
- package/package.json +1 -1
- package/schemas/results-v2.schema.json +376 -75
- package/schemas/specification-v1.schema.json +128 -174
- package/dist/adjudication.d.ts +0 -219
- package/dist/adjudication.js +0 -422
- package/dist/adoption.d.ts +0 -128
- package/dist/adoption.js +0 -102
- package/dist/affected.d.ts +0 -88
- package/dist/affected.js +0 -222
- package/dist/capture.d.ts +0 -193
- package/dist/capture.js +0 -344
- package/dist/comparison.d.ts +0 -97
- package/dist/comparison.js +0 -189
- package/dist/factory-calibration.d.ts +0 -63
- package/dist/factory-calibration.js +0 -115
- package/dist/intervention-results.d.ts +0 -6
- package/dist/intervention-results.js +0 -52
- package/dist/intervention.d.ts +0 -123
- package/dist/intervention.js +0 -218
- package/dist/investigation.d.ts +0 -94
- package/dist/investigation.js +0 -148
- package/dist/judge-agreement.d.ts +0 -19
- package/dist/judge-agreement.js +0 -31
- package/dist/qualification-capture.d.ts +0 -44
- package/dist/qualification-capture.js +0 -163
- package/dist/qualification-config.d.ts +0 -233
- package/dist/qualification-config.js +0 -694
- package/dist/qualification-lock.d.ts +0 -15
- package/dist/qualification-lock.js +0 -87
- package/dist/qualification-oauth-directory.d.ts +0 -79
- package/dist/qualification-oauth-directory.js +0 -444
- package/dist/qualification-panel-store.d.ts +0 -14
- package/dist/qualification-panel-store.js +0 -188
- package/dist/qualification-panels.d.ts +0 -99
- package/dist/qualification-panels.js +0 -91
- package/dist/qualification-process.d.ts +0 -13
- package/dist/qualification-process.js +0 -190
- package/dist/qualification-runner.d.ts +0 -203
- package/dist/qualification-runner.js +0 -2037
- package/dist/qualification-store.d.ts +0 -187
- package/dist/qualification-store.js +0 -833
- package/dist/qualification-validation.d.ts +0 -12
- package/dist/qualification-validation.js +0 -8
- package/dist/screen.d.ts +0 -31
- package/dist/screen.js +0 -105
- package/dist/trajectory-gates.d.ts +0 -137
- package/dist/trajectory-gates.js +0 -576
- package/dist/trusted-host-supervision.d.ts +0 -25
- package/dist/trusted-host-supervision.js +0 -94
- package/dist/work-capture-schema.d.ts +0 -38
- package/dist/work-capture-schema.js +0 -33
- package/dist/work-capture.d.ts +0 -43
- package/dist/work-capture.js +0 -81
- package/dist/work-signals.d.ts +0 -55
- package/dist/work-signals.js +0 -71
- package/schemas/qualification-cell-result-v1.schema.json +0 -32
- package/schemas/qualification-config-v1.schema.json +0 -244
- package/schemas/qualification-invocation-request-v1.schema.json +0 -59
- package/schemas/qualification-judge-panel-result-v1.schema.json +0 -42
- package/schemas/trajectory-event-v1.schema.json +0 -80
package/dist/regrade.js
CHANGED
|
@@ -113,22 +113,6 @@ export async function regradeScenario(opts) {
|
|
|
113
113
|
* results.yaml, emits the `score` journal event, and returns the new
|
|
114
114
|
* ResultsFile. Shared by `cmdGrade` and the pi-extension's `judge` command.
|
|
115
115
|
*/
|
|
116
|
-
/** Preserve prior panel votes and append a full-cell grade without writing invalid one-vote history. */
|
|
117
|
-
export function appendJudgeHistory(prior, priorJudge, fresh) {
|
|
118
|
-
const history = prior?.judge_history ?? prior?.adjudication?.judgments ?? (prior && priorJudge ? [{
|
|
119
|
-
ordinal: 1,
|
|
120
|
-
judge: priorJudge,
|
|
121
|
-
verdict: prior.judge_verdict ?? "JUDGE-AMBIGUOUS",
|
|
122
|
-
reason: prior.judge_reason ?? "prior grade",
|
|
123
|
-
suspect: prior.suspect ?? true,
|
|
124
|
-
criteria: prior.rep_judgments?.find(panel => panel.repetition === 0)?.judgments[0]?.criteria ?? [],
|
|
125
|
-
}] : []);
|
|
126
|
-
const next = [
|
|
127
|
-
...history,
|
|
128
|
-
{ ...fresh, criteria: fresh.criteria ?? [], ordinal: history.length + 1 },
|
|
129
|
-
].slice(-3).map((judgment, index) => ({ ...judgment, ordinal: index + 1 }));
|
|
130
|
-
return next.length >= 2 ? next : undefined;
|
|
131
|
-
}
|
|
132
116
|
export async function regradeRun(opts) {
|
|
133
117
|
const { runDir, spec, adapter, judge, specDir } = opts;
|
|
134
118
|
const now = opts.now ?? (() => new Date().toISOString());
|
|
@@ -140,7 +124,7 @@ export async function regradeRun(opts) {
|
|
|
140
124
|
// silently downgraded a gated scenario to "no assertions declared".
|
|
141
125
|
// `adjudication` is deliberately NOT carried: it describes the judgments this
|
|
142
126
|
// re-grade just replaced, and a stale panel beside a fresh verdict is worse
|
|
143
|
-
// than none.
|
|
127
|
+
// than none.
|
|
144
128
|
// The whole prior result per id — `rebuildScenarioResult` decides, field by
|
|
145
129
|
// field, what survives. Passing a hand-picked subset here is how fields got
|
|
146
130
|
// dropped before.
|
|
@@ -209,10 +193,6 @@ export async function regradeRun(opts) {
|
|
|
209
193
|
rr.criterion_count = scenario.checklist.length;
|
|
210
194
|
rr.metrics = mergeScenarioMetrics(carry?.metrics, rr.metrics);
|
|
211
195
|
rr.rep_judgments = carryRepObjectives(rr.rep_judgments, carry?.rep_judgments);
|
|
212
|
-
rr.judge_history = appendJudgeHistory(carry, prev?.judge, {
|
|
213
|
-
judge, verdict: rr.judge_verdict, reason: rr.judge_reason, suspect: rr.suspect,
|
|
214
|
-
criteria: rr.rep_judgments?.find(panel => panel.repetition === 0)?.judgments[0]?.criteria,
|
|
215
|
-
});
|
|
216
196
|
// `grade` re-judges the saved transcript. It does not re-evaluate trace gates
|
|
217
197
|
// (that is `regate`), so `objective` still describes this run; and it replaced
|
|
218
198
|
// the judgments a prior adjudication described, so that panel must go.
|
package/dist/report.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ShipBar } from "./spec.js";
|
|
2
2
|
import { type ResultsFile } from "./results.js";
|
|
3
3
|
import { type Lift } from "./lift.js";
|
|
4
|
-
import { type AggregateMetrics } from "./
|
|
4
|
+
import { type AggregateMetrics } from "./metrics.js";
|
|
5
5
|
export interface RunColumn {
|
|
6
6
|
index: number;
|
|
7
7
|
label: string;
|
|
@@ -22,13 +22,6 @@ export interface RunColumn {
|
|
|
22
22
|
status: string;
|
|
23
23
|
detail: string;
|
|
24
24
|
};
|
|
25
|
-
/** Adjudication outcome, when the cell was re-judged. */
|
|
26
|
-
adjudication?: {
|
|
27
|
-
state: string;
|
|
28
|
-
trigger: string;
|
|
29
|
-
count: number;
|
|
30
|
-
detail: string;
|
|
31
|
-
};
|
|
32
25
|
reps?: number;
|
|
33
26
|
passes?: number;
|
|
34
27
|
clean?: number;
|
|
@@ -112,13 +105,6 @@ export declare function publicView(data: ReportData): {
|
|
|
112
105
|
status: string;
|
|
113
106
|
detail: string;
|
|
114
107
|
};
|
|
115
|
-
/** Adjudication outcome, when the cell was re-judged. */
|
|
116
|
-
adjudication?: {
|
|
117
|
-
state: string;
|
|
118
|
-
trigger: string;
|
|
119
|
-
count: number;
|
|
120
|
-
detail: string;
|
|
121
|
-
};
|
|
122
108
|
reps?: number;
|
|
123
109
|
passes?: number;
|
|
124
110
|
clean?: number;
|
package/dist/report.js
CHANGED
|
@@ -4,7 +4,7 @@ import { loadSpec } from "./spec.js";
|
|
|
4
4
|
import { readResults } from "./results.js";
|
|
5
5
|
import { collectLift, liftHeadline } from "./lift.js";
|
|
6
6
|
import { boundaryCells, collectStability, stabilityNote } from "./stability.js";
|
|
7
|
-
import { aggregateMetrics } from "./
|
|
7
|
+
import { aggregateMetrics } from "./metrics.js";
|
|
8
8
|
/** Most-recent run dir (by name, which is an ISO-ish slug) under a model-tag dir. */
|
|
9
9
|
function latestRunDir(tagDir) {
|
|
10
10
|
if (!statSync(tagDir).isDirectory())
|
|
@@ -65,18 +65,6 @@ export function collectReport(skillDir) {
|
|
|
65
65
|
},
|
|
66
66
|
}
|
|
67
67
|
: {}),
|
|
68
|
-
...(s.adjudication
|
|
69
|
-
? {
|
|
70
|
-
adjudication: {
|
|
71
|
-
state: s.adjudication.state,
|
|
72
|
-
trigger: s.adjudication.trigger,
|
|
73
|
-
count: s.adjudication.judgments.length,
|
|
74
|
-
detail: s.adjudication.judgments
|
|
75
|
-
.map((j) => `#${j.ordinal} ${j.judge.provider}:${j.judge.model} ${j.verdict}${j.suspect ? " (misfired, not counted)" : ""}`)
|
|
76
|
-
.join(" · "),
|
|
77
|
-
},
|
|
78
|
-
}
|
|
79
|
-
: {}),
|
|
80
68
|
judge_verdict: s.judge_verdict,
|
|
81
69
|
judge_reason: s.judge_reason,
|
|
82
70
|
suspect: s.suspect ?? false, // suspect defaults false for older results that predate the field
|
package/dist/reps.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Verdict } from "./score.js";
|
|
2
|
-
import type { ScenarioResult, ObjectiveResult, Judgment
|
|
2
|
+
import type { ScenarioResult, ObjectiveResult, Judgment } from "./results.js";
|
|
3
3
|
import type { TraceMetrics } from "./capture-trace-types.js";
|
|
4
4
|
/** One rep's outcome (subject run + judge). */
|
|
5
5
|
export interface RepOutcome {
|
|
@@ -9,7 +9,6 @@ export interface RepOutcome {
|
|
|
9
9
|
/** Present only when the scenario declared structured objective assertions. */
|
|
10
10
|
objective?: ObjectiveResult;
|
|
11
11
|
judgment?: Judgment;
|
|
12
|
-
subject_invocations?: SubjectInvocationObservation[];
|
|
13
12
|
metrics?: {
|
|
14
13
|
wall_time_ms: number;
|
|
15
14
|
judge_calls: number;
|
package/dist/reps.js
CHANGED
|
@@ -15,11 +15,9 @@ export function aggregateObjective(outcomes) {
|
|
|
15
15
|
const picked = present.find((o) => o.status === "ERROR") ?? present.find((o) => o.status === "NOT-MEASURED") ?? present.find((o) => o.status === "FAIL") ?? present[0];
|
|
16
16
|
if (present.length === 1)
|
|
17
17
|
return picked;
|
|
18
|
-
const eventHashes = present.map((objective) => objective.events_sha256);
|
|
19
18
|
const traceHashes = present.map((objective) => objective.trace_sha256);
|
|
20
19
|
return {
|
|
21
20
|
...picked,
|
|
22
|
-
...(eventHashes.every((hash) => typeof hash === "string") ? { rep_events_sha256: eventHashes } : {}),
|
|
23
21
|
...(traceHashes.every((hash) => typeof hash === "string") ? { rep_trace_sha256: traceHashes } : {}),
|
|
24
22
|
};
|
|
25
23
|
}
|
package/dist/results.d.ts
CHANGED
|
@@ -72,8 +72,6 @@ export interface ScenarioResult {
|
|
|
72
72
|
* actually blocks SHIP; this field is the audit trail behind that flag.
|
|
73
73
|
*/
|
|
74
74
|
adjudication?: AdjudicationResult;
|
|
75
|
-
/** Latest three full-cell grades; enables offline agreement reports with distinct judges. */
|
|
76
|
-
judge_history?: Judgment[];
|
|
77
75
|
/** Initial and panel judge members, by repetition, sufficient to recompute the recorded verdict. */
|
|
78
76
|
rep_judgments?: RepJudgmentPanel[];
|
|
79
77
|
}
|
|
@@ -109,10 +107,7 @@ export interface ObjectiveResult {
|
|
|
109
107
|
status: "PASS" | "FAIL" | "ERROR" | "NOT-MEASURED";
|
|
110
108
|
trace_version?: number;
|
|
111
109
|
trace_sha256?: string;
|
|
112
|
-
trajectory_version?: string;
|
|
113
|
-
events_sha256?: string;
|
|
114
110
|
/** Per-repetition hashes retained when an aggregate has more than one rep. */
|
|
115
|
-
rep_events_sha256?: string[];
|
|
116
111
|
rep_trace_sha256?: string[];
|
|
117
112
|
assertions: {
|
|
118
113
|
kind: string;
|
|
@@ -443,10 +438,6 @@ export declare function rebuildScenarioResult(fresh: ScenarioResult, prior: Scen
|
|
|
443
438
|
* traces append without a wrapper.
|
|
444
439
|
*/
|
|
445
440
|
export declare function tracePath(runDir: string, scenarioId: string, mode: string, rep?: number): string;
|
|
446
|
-
/** Saved adapter-neutral workflow events for one scenario rep. */
|
|
447
|
-
export declare function trajectoryPath(runDir: string, scenarioId: string, mode: string, rep?: number): string;
|
|
448
|
-
/** A scenario's normalized-event files, sorted (plain first, then numeric rep). */
|
|
449
|
-
export declare function findTrajectoryFiles(runDir: string, scenarioId: string, mode?: string): string[];
|
|
450
441
|
/** A scenario's staged-diff files, sorted (plain first, then numeric rep). Mode-scoped when given. */
|
|
451
442
|
export declare function findDiffFiles(runDir: string, scenarioId: string, mode?: string): string[];
|
|
452
443
|
/** A scenario's execution-trace files, sorted (plain first, then numeric rep). Mode-scoped when given. */
|
package/dist/results.js
CHANGED
|
@@ -409,7 +409,7 @@ export function validateResults(raw) {
|
|
|
409
409
|
const aggregateObjectiveStatus = objectiveStatuses.includes("ERROR") ? "ERROR" : objectiveStatuses.includes("NOT-MEASURED") ? "NOT-MEASURED" : objectiveStatuses.includes("FAIL") ? "FAIL" : "PASS";
|
|
410
410
|
if (!scenario.objective || scenario.objective.status !== aggregateObjectiveStatus)
|
|
411
411
|
throw new Error(`scenario objective diverges from per-repetition objectives for ${scenario.id}`);
|
|
412
|
-
for (const judgment of
|
|
412
|
+
for (const judgment of scenario.adjudication?.judgments ?? [])
|
|
413
413
|
assertCriteria(judgment);
|
|
414
414
|
let adjudicatedVerdict;
|
|
415
415
|
if (scenario.adjudication) {
|
|
@@ -599,7 +599,7 @@ export function diffPath(runDir, scenarioId, mode, rep) {
|
|
|
599
599
|
export function rebuildScenarioResult(fresh, prior, policy) {
|
|
600
600
|
// Exhaustive destructure. Do not replace with a spread: the spread is what
|
|
601
601
|
// allowed a new field to pass through unconsidered in the first place.
|
|
602
|
-
const { id, criterion_count: freshCriterionCount, judge_verdict, judge_reason, suspect, override: _freshOverride, note: _freshNote, reps, passes, clean, flakiness, pass_threshold, metrics: freshMetrics, objective: freshObjective, adjudication: freshAdjudication,
|
|
602
|
+
const { id, criterion_count: freshCriterionCount, judge_verdict, judge_reason, suspect, override: _freshOverride, note: _freshNote, reps, passes, clean, flakiness, pass_threshold, metrics: freshMetrics, objective: freshObjective, adjudication: freshAdjudication, rep_judgments: freshRepJudgments, ...rest } = fresh;
|
|
603
603
|
const _exhaustive = rest;
|
|
604
604
|
void _exhaustive;
|
|
605
605
|
void _freshOverride;
|
|
@@ -660,7 +660,6 @@ export function rebuildScenarioResult(fresh, prior, policy) {
|
|
|
660
660
|
// existed.
|
|
661
661
|
...(objective ? { objective } : {}),
|
|
662
662
|
...(adjudication ? { adjudication } : {}),
|
|
663
|
-
...((freshJudgeHistory ?? prior?.judge_history) ? { judge_history: freshJudgeHistory ?? prior.judge_history } : {}),
|
|
664
663
|
...((freshRepJudgments ?? prior?.rep_judgments) ? { rep_judgments: freshRepJudgments ?? prior.rep_judgments } : {}),
|
|
665
664
|
};
|
|
666
665
|
}
|
|
@@ -675,21 +674,6 @@ export function tracePath(runDir, scenarioId, mode, rep) {
|
|
|
675
674
|
const base = rep === undefined ? `${scenarioId}.${mode}` : `${scenarioId}.${mode}.rep${rep}`;
|
|
676
675
|
return join(runDir, `${base}.trace.jsonl`);
|
|
677
676
|
}
|
|
678
|
-
/** Saved adapter-neutral workflow events for one scenario rep. */
|
|
679
|
-
export function trajectoryPath(runDir, scenarioId, mode, rep) {
|
|
680
|
-
const base = rep === undefined ? `${scenarioId}.${mode}` : `${scenarioId}.${mode}.rep${rep}`;
|
|
681
|
-
return join(runDir, `${base}.events.jsonl`);
|
|
682
|
-
}
|
|
683
|
-
/** A scenario's normalized-event files, sorted (plain first, then numeric rep). */
|
|
684
|
-
export function findTrajectoryFiles(runDir, scenarioId, mode) {
|
|
685
|
-
if (!existsSync(runDir))
|
|
686
|
-
return [];
|
|
687
|
-
const esc = scenarioId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
688
|
-
const re = mode === undefined
|
|
689
|
-
? new RegExp(`^${esc}\\..*\\.events\\.jsonl$`)
|
|
690
|
-
: new RegExp(`^${esc}\\.${mode}(\\.rep\\d+)?\\.events\\.jsonl$`);
|
|
691
|
-
return sortByRep(readdirSync(runDir).filter((f) => re.test(f)));
|
|
692
|
-
}
|
|
693
677
|
/** A scenario's staged-diff files, sorted (plain first, then numeric rep). Mode-scoped when given. */
|
|
694
678
|
export function findDiffFiles(runDir, scenarioId, mode) {
|
|
695
679
|
if (!existsSync(runDir))
|
|
@@ -738,7 +722,6 @@ export function preserveTranscript(resultsRoot, runDir, scenarioId) {
|
|
|
738
722
|
// override whose justification was gitignored, and left `regate` with nothing
|
|
739
723
|
// to re-evaluate on the one cell a human had disputed.
|
|
740
724
|
...findTraceFiles(runDir, scenarioId),
|
|
741
|
-
...findTrajectoryFiles(runDir, scenarioId),
|
|
742
725
|
];
|
|
743
726
|
if (files.length === 0)
|
|
744
727
|
return;
|
package/dist/run.js
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync, readFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
|
-
import { sourceHashes
|
|
3
|
+
import { sourceHashes } from "./sources.js";
|
|
4
4
|
import { judgeResemblesSubject } from "./grade.js";
|
|
5
5
|
import { NONE_ARM, seedArmDefinitions } from "./arms.js";
|
|
6
|
-
import { runDirFor, transcriptPath, diffPath, tracePath,
|
|
6
|
+
import { runDirFor, transcriptPath, diffPath, tracePath, writeResults, ensureResultsGitignore, scoreContextFor, effectiveThreshold, isScoredMode, } from "./results.js";
|
|
7
7
|
import { appendJournal } from "./journal.js";
|
|
8
8
|
import { liftHeadline } from "./lift.js";
|
|
9
9
|
import { runSeeded } from "./seeded.js";
|
|
10
10
|
import { serializeTrace, mergeTraces, traceSha256 } from "./execution-trace.js";
|
|
11
11
|
import { evaluateTraceGates } from "./trace-gates.js";
|
|
12
|
-
import { evaluateTrajectoryGates, serializeTrajectoryEvents, } from "./trajectory-gates.js";
|
|
13
12
|
import { snapshotPaths, diffSnapshots, createWorkspace } from "./workspace.js";
|
|
14
13
|
import { runPool } from "./scheduler.js";
|
|
15
14
|
import { outcomesToResult } from "./reps.js";
|
|
16
15
|
import { judgeOneRep } from "./regrade.js";
|
|
17
16
|
import { runDeliveryCanary, canaryFailure } from "./canary.js";
|
|
18
17
|
import { boundaryCells, stabilityNote } from "./stability.js";
|
|
19
|
-
import { aggregateMetrics } from "./
|
|
18
|
+
import { aggregateMetrics } from "./metrics.js";
|
|
20
19
|
import { providerFailureFromTranscript } from "./provider-failure.js";
|
|
21
20
|
/**
|
|
22
21
|
* The pi-daddy arm's delivery proof, by convention: `arms.yaml` points
|
|
@@ -139,20 +138,13 @@ export async function runSkillModel(opts) {
|
|
|
139
138
|
}
|
|
140
139
|
});
|
|
141
140
|
const flat = await runPool(tasks, opts.concurrency ?? 1);
|
|
142
|
-
const subjectInvocations = flat.flatMap(outcome => outcome.subject_invocations ?? []);
|
|
143
141
|
const grouped = scenarios.map(() => []);
|
|
144
142
|
flat.forEach((outcome, i) => grouped[owners[i]].push(outcome));
|
|
145
143
|
const scenarioResults = scenarios.map((scenario, si) => {
|
|
146
144
|
const threshold = scenario.critical
|
|
147
145
|
? effectiveThreshold(undefined, scenario)
|
|
148
146
|
: scenario.passThreshold ?? opts.passThreshold ?? 0.5;
|
|
149
|
-
|
|
150
|
-
if (adapter.observesPrompts)
|
|
151
|
-
result.criterion_count = scenario.checklist.length;
|
|
152
|
-
if (adapter.observesPrompts && !result.rep_judgments) {
|
|
153
|
-
result.rep_judgments = grouped[si].map((outcome, repetition) => ({ repetition, judgments: [], recorded_verdict: outcome.verdict, ...(outcome.objective ? { objective: outcome.objective } : {}) }));
|
|
154
|
-
}
|
|
155
|
-
return result;
|
|
147
|
+
return outcomesToResult(scenario.id, grouped[si], repCounts[si], threshold);
|
|
156
148
|
});
|
|
157
149
|
const ctx = scoreContextFor({ mode, partial }, spec);
|
|
158
150
|
const results = writeResults(runDir, {
|
|
@@ -168,12 +160,8 @@ export async function runSkillModel(opts) {
|
|
|
168
160
|
...(partial ? { partial: true } : {}),
|
|
169
161
|
// Only the scenarios this run actually measured: a --only run must not claim
|
|
170
162
|
// coverage of scenarios it skipped.
|
|
171
|
-
source_hashes: {
|
|
172
|
-
...sourceHashes({ skillDir, specDir: dirname(opts.specPath), scenarios, judgePersona: spec.judge_persona }),
|
|
173
|
-
...(adapter.observesPrompts ? { [PROMPT_NORMALIZATION_SOURCE_KEY]: PROMPT_NORMALIZATION_SOURCE_DIGEST } : {}),
|
|
174
|
-
},
|
|
163
|
+
source_hashes: sourceHashes({ skillDir, specDir: dirname(opts.specPath), scenarios, judgePersona: spec.judge_persona }),
|
|
175
164
|
scenarios: scenarioResults,
|
|
176
|
-
...(adapter.observesPrompts ? { schema: 3, subject_invocations: subjectInvocations } : {}),
|
|
177
165
|
...(arm.name === NONE_ARM.name ? {} : {
|
|
178
166
|
arm: {
|
|
179
167
|
name: arm.name,
|
|
@@ -240,7 +228,6 @@ async function runRep(scenario, rep, repCount, ctx) {
|
|
|
240
228
|
// produces no diff, and writing an empty artifact there would misreport "the
|
|
241
229
|
// model changed nothing" for a rep that never ran.
|
|
242
230
|
let stagedDiff = null;
|
|
243
|
-
const subjectInvocations = [];
|
|
244
231
|
try {
|
|
245
232
|
try {
|
|
246
233
|
ws = createWorkspace(scenario.workspace, { specDir: dirname(ctx.specPath), remote: scenario.remote });
|
|
@@ -254,8 +241,6 @@ async function runRep(scenario, rep, repCount, ctx) {
|
|
|
254
241
|
}
|
|
255
242
|
let noResponse = false;
|
|
256
243
|
let traces = [];
|
|
257
|
-
let events = [];
|
|
258
|
-
let eventErrors = [];
|
|
259
244
|
let unobservablePaths = false;
|
|
260
245
|
// The pre-run state, captured AFTER `createWorkspace` has applied the
|
|
261
246
|
// fixture's `_staged/` and `_uncommitted/` trees. Those land after the
|
|
@@ -286,10 +271,10 @@ async function runRep(scenario, rep, repCount, ctx) {
|
|
|
286
271
|
// used to pass `trace: {...}` unconditionally and let `runSeeded` throw
|
|
287
272
|
// ``scenario `X` declares `assert.trace`…`` at a scenario that declares no
|
|
288
273
|
// such thing.
|
|
289
|
-
const needsStructuredEvidence = Boolean(scenario.traceAssert
|
|
274
|
+
const needsStructuredEvidence = Boolean(scenario.traceAssert);
|
|
290
275
|
if (needsStructuredEvidence && !ctx.adapter.runStructured) {
|
|
291
276
|
throw new Error(`scenario \`${scenario.id}\` declares structured objective assertions, but the \`${ctx.adapter.name}\` adapter` +
|
|
292
|
-
` cannot produce execution traces
|
|
277
|
+
` cannot produce execution traces — the gate would have no evidence to read.`);
|
|
293
278
|
}
|
|
294
279
|
const useStructured = (Boolean(ctx.structured) || needsStructuredEvidence) && Boolean(ctx.adapter.runStructured);
|
|
295
280
|
// A blank assistant turn is a harness timeout, not model behavior: retry ONCE in a
|
|
@@ -297,7 +282,6 @@ async function runRep(scenario, rep, repCount, ctx) {
|
|
|
297
282
|
// it happens again the verdict is ERROR — never a judged FAIL on an empty reply.
|
|
298
283
|
// An adapter that THREW is the same class of event and takes the same retry.
|
|
299
284
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
300
|
-
const observe = (prompt) => subjectInvocations.push({ scenario_id: scenario.id, repetition: rep, attempt, prompt });
|
|
301
285
|
if (attempt > 0) {
|
|
302
286
|
const why = adapterFailure ? `adapter failed (${adapterFailure})` : "empty response";
|
|
303
287
|
appendJournal(runDir, { event: "empty-response-retry", ts: now(), id: scenario.id, attempt, reason: why, ...repField });
|
|
@@ -337,15 +321,12 @@ async function runRep(scenario, rep, repCount, ctx) {
|
|
|
337
321
|
// already substituted) both must reach pi.
|
|
338
322
|
armExtensions: arm.extensions,
|
|
339
323
|
...(armEnvFor(ws.cwd) ? { armEnv: armEnvFor(ws.cwd) } : {}),
|
|
340
|
-
...(ctx.adapter.observesPrompts ? { onPromptObservation: observe } : {}),
|
|
341
324
|
});
|
|
342
325
|
transcript = r.transcript;
|
|
343
326
|
gatePrefix = r.gateFailure;
|
|
344
327
|
infrastructureFailure = r.gateError;
|
|
345
328
|
stagedDiff = r.diff; // a retry replaces the aborted attempt's diff, as it should
|
|
346
329
|
traces = r.traces;
|
|
347
|
-
events = r.events;
|
|
348
|
-
eventErrors = r.eventErrors;
|
|
349
330
|
}
|
|
350
331
|
else {
|
|
351
332
|
const req = {
|
|
@@ -361,16 +342,12 @@ async function runRep(scenario, rep, repCount, ctx) {
|
|
|
361
342
|
...(scenario.extensions?.map((e) => resolve(dirname(ctx.specPath), e)) ?? []),
|
|
362
343
|
...arm.extensions,
|
|
363
344
|
],
|
|
364
|
-
eventSources: scenario.eventSources,
|
|
365
345
|
...(armEnvFor(ws.cwd) ? { armEnv: armEnvFor(ws.cwd) } : {}),
|
|
366
|
-
...(ctx.adapter.observesPrompts ? { onPromptObservation: observe } : {}),
|
|
367
346
|
};
|
|
368
347
|
if (useStructured) {
|
|
369
348
|
const structured = await ctx.adapter.runStructured({ ...req, scenarioId: scenario.id, rep });
|
|
370
349
|
transcript = structured.transcript;
|
|
371
350
|
traces = structured.traces;
|
|
372
|
-
events = structured.events ?? [];
|
|
373
|
-
eventErrors = structured.eventErrors ?? [];
|
|
374
351
|
if (structured.providerFailure)
|
|
375
352
|
infrastructureFailure = `provider failure — ${structured.providerFailure}`;
|
|
376
353
|
}
|
|
@@ -399,8 +376,6 @@ async function runRep(scenario, rep, repCount, ctx) {
|
|
|
399
376
|
gatePrefix = null;
|
|
400
377
|
stagedDiff = null;
|
|
401
378
|
traces = [];
|
|
402
|
-
events = [];
|
|
403
|
-
eventErrors = [];
|
|
404
379
|
}
|
|
405
380
|
// A provider outage is infrastructure, never a model verdict. Checked on
|
|
406
381
|
// every path: the text path carries the marker in the transcript, the
|
|
@@ -457,16 +432,6 @@ async function runRep(scenario, rep, repCount, ctx) {
|
|
|
457
432
|
});
|
|
458
433
|
}
|
|
459
434
|
}
|
|
460
|
-
// Delivery is an objective gate on every Pi subject invocation. It is derived
|
|
461
|
-
// from captured provider payload bytes, never from mode/argv supplied by a caller.
|
|
462
|
-
let deliveryObjective;
|
|
463
|
-
if (ctx.adapter.observesPrompts) {
|
|
464
|
-
const statuses = subjectInvocations.map(observation => observation.prompt.status);
|
|
465
|
-
const status = deliveryStatusForObservations(subjectInvocations);
|
|
466
|
-
deliveryObjective = { status, assertions: [{ kind: "skill_delivered", status, detail: statuses.length === 0 ? "no model-visible prompt observation was retained" : `${statuses.length} provider request(s): ${statuses.join(", ")}` }] };
|
|
467
|
-
if (status !== "PASS")
|
|
468
|
-
gatePrefix = `objective: skill_delivered ${status.toLowerCase()} — ${deliveryObjective.assertions[0].detail}`;
|
|
469
|
-
}
|
|
470
435
|
// Objective evidence is persisted for every rep, pass or fail — a failing gate
|
|
471
436
|
// is exactly when someone wants to read what the model actually did.
|
|
472
437
|
// `!adapterFailure`: a rep whose adapter threw never ran, so there is nothing
|
|
@@ -474,12 +439,11 @@ async function runRep(scenario, rep, repCount, ctx) {
|
|
|
474
439
|
// which is the symptom — it names the missing artifact instead of the crash or
|
|
475
440
|
// timeout that caused it, and it is that text, not the real reason, that would
|
|
476
441
|
// reach the results record. The verdict is ERROR either way.
|
|
477
|
-
let objective
|
|
478
|
-
if (
|
|
442
|
+
let objective;
|
|
443
|
+
if (scenario.traceAssert && !adapterFailure) {
|
|
479
444
|
const assertionResults = [];
|
|
480
445
|
let status = "PASS";
|
|
481
446
|
let traceMeta = {};
|
|
482
|
-
let trajectoryMeta = {};
|
|
483
447
|
if (scenario.traceAssert) {
|
|
484
448
|
if (traces.length > 0) {
|
|
485
449
|
writeFileSync(tracePath(runDir, scenario.id, mode, repSuffix), traces.map(serializeTrace).join(""), "utf8");
|
|
@@ -500,32 +464,7 @@ async function runRep(scenario, rep, repCount, ctx) {
|
|
|
500
464
|
traceMeta = { trace_version: merged.trace_version, trace_sha256: merged.trace_sha256 };
|
|
501
465
|
}
|
|
502
466
|
}
|
|
503
|
-
|
|
504
|
-
if (events.length > 0) {
|
|
505
|
-
writeFileSync(trajectoryPath(runDir, scenario.id, mode, repSuffix), serializeTrajectoryEvents(events), "utf8");
|
|
506
|
-
}
|
|
507
|
-
if (eventErrors.length > 0) {
|
|
508
|
-
status = "ERROR";
|
|
509
|
-
assertionResults.push(...eventErrors.map((detail) => ({ kind: "trajectory_evidence", status: "ERROR", detail })));
|
|
510
|
-
}
|
|
511
|
-
else if (events.length === 0) {
|
|
512
|
-
status = "ERROR";
|
|
513
|
-
assertionResults.push({ kind: "trajectory_evidence", status: "ERROR", detail: "no normalized workflow events were produced" });
|
|
514
|
-
}
|
|
515
|
-
else {
|
|
516
|
-
const gate = evaluateTrajectoryGates(scenario.trajectoryAssert, events);
|
|
517
|
-
if (gate.status === "ERROR" || (gate.status === "FAIL" && status === "PASS"))
|
|
518
|
-
status = gate.status;
|
|
519
|
-
assertionResults.push(...gate.assertions);
|
|
520
|
-
trajectoryMeta = { trajectory_version: gate.event_version, events_sha256: gate.events_sha256 };
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
if (deliveryObjective) {
|
|
524
|
-
if (deliveryObjective.status === "ERROR" || (deliveryObjective.status === "NOT-MEASURED" && status !== "ERROR") || (deliveryObjective.status === "FAIL" && status === "PASS"))
|
|
525
|
-
status = deliveryObjective.status;
|
|
526
|
-
assertionResults.unshift(...deliveryObjective.assertions);
|
|
527
|
-
}
|
|
528
|
-
objective = { status, ...traceMeta, ...trajectoryMeta, assertions: assertionResults };
|
|
467
|
+
objective = { status, ...traceMeta, assertions: assertionResults };
|
|
529
468
|
if (status !== "PASS") {
|
|
530
469
|
const details = assertionResults.filter((result) => result.status === status).map((result) => result.detail);
|
|
531
470
|
gatePrefix = `objective: ${details.join("; ") || "structured evidence could not be evaluated"}`;
|
|
@@ -580,7 +519,7 @@ async function runRep(scenario, rep, repCount, ctx) {
|
|
|
580
519
|
log(` → ${scenario.id}${repCount > 1 ? `#${rep}` : ""} ${verdict}${reason ? `: ${reason}` : ""}${suspect ? " ⚠ suspect" : ""}`);
|
|
581
520
|
const subject = mergeTraces(traces)?.metrics;
|
|
582
521
|
return {
|
|
583
|
-
verdict, reason, suspect, objective, judgment,
|
|
522
|
+
verdict, reason, suspect, objective, judgment,
|
|
584
523
|
metrics: {
|
|
585
524
|
wall_time_ms: Math.max(0, Math.round(performance.now() - startedAt)),
|
|
586
525
|
judge_calls: judgeCalls,
|
package/dist/seeded.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { Scenario } from "./spec.js";
|
|
2
2
|
import type { ExecutionTraceV1 } from "./capture-trace-types.js";
|
|
3
|
-
import type {
|
|
4
|
-
import type { HarnessAdapter, ModelRef, RunMode, PromptProvenance } from "./adapters/types.js";
|
|
3
|
+
import type { HarnessAdapter, ModelRef, RunMode } from "./adapters/types.js";
|
|
5
4
|
import { type ExecResult } from "./util/exec.js";
|
|
6
5
|
interface SeededOpts {
|
|
7
6
|
skillDir: string;
|
|
@@ -37,7 +36,6 @@ interface SeededOpts {
|
|
|
37
36
|
armExtensions?: string[];
|
|
38
37
|
/** The arm's env for the subject process; `<run-dir>` already substituted by the caller. */
|
|
39
38
|
armEnv?: Record<string, string>;
|
|
40
|
-
onPromptObservation?: (observation: PromptProvenance) => void;
|
|
41
39
|
}
|
|
42
40
|
/**
|
|
43
41
|
* Result of one vitest invocation — deliberately `ExecResult`, not a narrower
|
|
@@ -58,10 +56,6 @@ export interface SeededOutcome {
|
|
|
58
56
|
diff: string;
|
|
59
57
|
/** One per turn; empty unless structured execution was requested. */
|
|
60
58
|
traces: ExecutionTraceV1[];
|
|
61
|
-
/** Adapter-neutral workflow/tool events for assert.trajectory. */
|
|
62
|
-
events: TrajectoryEventV1[];
|
|
63
|
-
/** Required native sources that could not be read or normalized. */
|
|
64
|
-
eventErrors: string[];
|
|
65
59
|
}
|
|
66
60
|
/**
|
|
67
61
|
* The added/removed lines of a unified diff — what the model actually *changed*,
|
package/dist/seeded.js
CHANGED
|
@@ -173,17 +173,13 @@ export async function runSeeded(scenario, opts) {
|
|
|
173
173
|
...(scenario.extensions?.map((e) => resolve(opts.specDir, e)) ?? []),
|
|
174
174
|
...(opts.armExtensions ?? []),
|
|
175
175
|
],
|
|
176
|
-
eventSources: scenario.eventSources,
|
|
177
176
|
...(opts.armEnv ? { armEnv: opts.armEnv } : {}),
|
|
178
|
-
...(opts.onPromptObservation ? { onPromptObservation: opts.onPromptObservation } : {}),
|
|
179
177
|
};
|
|
180
178
|
// A trace-gated seeded scenario runs through the structured path so the tool
|
|
181
179
|
// calls are recorded; everything downstream (gates, diff, transcript) is
|
|
182
180
|
// identical, because the rebuilt transcript is what print mode would have
|
|
183
181
|
// emitted anyway.
|
|
184
182
|
let traces = [];
|
|
185
|
-
let events = [];
|
|
186
|
-
let eventErrors = [];
|
|
187
183
|
let harnessOut;
|
|
188
184
|
if (opts.trace) {
|
|
189
185
|
if (!opts.adapter.runStructured) {
|
|
@@ -197,8 +193,6 @@ export async function runSeeded(scenario, opts) {
|
|
|
197
193
|
});
|
|
198
194
|
harnessOut = structured.transcript;
|
|
199
195
|
traces = structured.traces;
|
|
200
|
-
events = structured.events ?? [];
|
|
201
|
-
eventErrors = structured.eventErrors ?? [];
|
|
202
196
|
}
|
|
203
197
|
else {
|
|
204
198
|
harnessOut = await opts.adapter.run(req);
|
|
@@ -227,7 +221,7 @@ export async function runSeeded(scenario, opts) {
|
|
|
227
221
|
parts.push(` staged diff: ERROR (${msg})`);
|
|
228
222
|
gateFailure = msg;
|
|
229
223
|
gateError = msg;
|
|
230
|
-
return finish(parts, gateFailure, gateError, diff, traces
|
|
224
|
+
return finish(parts, gateFailure, gateError, diff, traces);
|
|
231
225
|
}
|
|
232
226
|
// BOTH needle gates read the changed lines only, never context. A unified diff
|
|
233
227
|
// carries three lines of context per hunk, so an untouched symbol near the edit
|
|
@@ -301,7 +295,7 @@ export async function runSeeded(scenario, opts) {
|
|
|
301
295
|
if (!gateFailure)
|
|
302
296
|
gateFailure = msg;
|
|
303
297
|
gateError = msg;
|
|
304
|
-
return finish(parts, gateFailure, gateError, diff, traces
|
|
298
|
+
return finish(parts, gateFailure, gateError, diff, traces);
|
|
305
299
|
}
|
|
306
300
|
const v = await runVitest([POST_TEST_BASE], repo);
|
|
307
301
|
const out = `${v.stdout}\n${v.stderr}`;
|
|
@@ -358,7 +352,7 @@ export async function runSeeded(scenario, opts) {
|
|
|
358
352
|
gateError = problem;
|
|
359
353
|
}
|
|
360
354
|
}
|
|
361
|
-
return finish(parts, gateFailure, gateError, diff, traces
|
|
355
|
+
return finish(parts, gateFailure, gateError, diff, traces);
|
|
362
356
|
}
|
|
363
357
|
function git(cwd, args) {
|
|
364
358
|
return exec("git", args, { cwd, timeoutMs: 30_000 });
|
|
@@ -392,13 +386,13 @@ function bothStreams(v) {
|
|
|
392
386
|
return o || e;
|
|
393
387
|
}
|
|
394
388
|
/** Append the staged diff and return the outcome. Every exit path goes through here, so the judge always sees the same sections in the same order. */
|
|
395
|
-
function finish(parts, gateFailure, gateError, diff, traces = []
|
|
389
|
+
function finish(parts, gateFailure, gateError, diff, traces = []) {
|
|
396
390
|
// The code itself, last — the gates above only prove that keywords appeared.
|
|
397
391
|
// Without this section a seeded checklist item about what the code *does* is
|
|
398
392
|
// graded from the model's own description of its work.
|
|
399
393
|
parts.push("", "=== STAGED DIFF ===");
|
|
400
394
|
parts.push(diff.trim() === "" ? " (empty — the model left no staged changes)" : capDiff(diff));
|
|
401
|
-
return { transcript: parts.join("\n"), gateFailure, gateError, diff, traces
|
|
395
|
+
return { transcript: parts.join("\n"), gateFailure, gateError, diff, traces };
|
|
402
396
|
}
|
|
403
397
|
/**
|
|
404
398
|
* Parse vitest's `Tests N passed | M skipped (T)` summary line.
|
package/dist/sources.js
CHANGED
|
@@ -170,13 +170,13 @@ function walk(dir, prefix = "") {
|
|
|
170
170
|
* transcripts are actually invalid.
|
|
171
171
|
*/
|
|
172
172
|
function facets(s) {
|
|
173
|
-
const { id, title, critical, mode, turns, checklist, fixture, assert, traceAssert,
|
|
173
|
+
const { id, title, critical, mode, turns, checklist, fixture, assert, traceAssert, workspace, remote, systemPromptFile, extensions, reps, passThreshold, covers: _coversIsMetadata, ...restScenario } = s;
|
|
174
174
|
const _scenarioExhaustive = restScenario;
|
|
175
175
|
void _scenarioExhaustive;
|
|
176
176
|
// `covers` is destructured into a discard on purpose, and this comment is the
|
|
177
177
|
// decision the guard demanded: it belongs to NO digest. It records which
|
|
178
|
-
// instruction sections a scenario is declared to exercise
|
|
179
|
-
//
|
|
178
|
+
// instruction sections a scenario is declared to exercise; it does not change
|
|
179
|
+
// what any past run measured. Bucketing it
|
|
180
180
|
// anywhere would charge a re-run (or at best a re-score) for editing a label,
|
|
181
181
|
// which is the exact trap the facet split was built to remove.
|
|
182
182
|
void _coversIsMetadata;
|
|
@@ -187,7 +187,7 @@ function facets(s) {
|
|
|
187
187
|
// already saved, so `regate` can re-answer it without re-running the subject model.
|
|
188
188
|
// Note the asymmetry with `env.extensions` in Phase 3, which IS stimulus — one
|
|
189
189
|
// changes what gets executed, the other only what we conclude from it.
|
|
190
|
-
const hasGates = diff_contains !== undefined || diff_excludes !== undefined || traceAssert !== undefined
|
|
190
|
+
const hasGates = diff_contains !== undefined || diff_excludes !== undefined || traceAssert !== undefined;
|
|
191
191
|
return {
|
|
192
192
|
// `vitest` and the `post_test` PATH are stimulus, not gates: both change what the
|
|
193
193
|
// run executes in the workspace, and neither can be re-evaluated from a saved
|
|
@@ -206,10 +206,6 @@ function facets(s) {
|
|
|
206
206
|
id, mode, turns, workspace, remote, systemPromptFile ?? null,
|
|
207
207
|
fixture ?? null, vitest ?? null, post_test ?? null,
|
|
208
208
|
...(extensions ? [extensions] : []),
|
|
209
|
-
// Event-source paths choose which native ledgers are captured. A saved
|
|
210
|
-
// normalized artifact cannot answer for a source that was never collected,
|
|
211
|
-
// so changing this is stimulus and needs a re-run.
|
|
212
|
-
...(eventSources ? [eventSources] : []),
|
|
213
209
|
]),
|
|
214
210
|
rubric: JSON.stringify([id, title, checklist]),
|
|
215
211
|
policy: JSON.stringify([id, critical, reps ?? null, passThreshold ?? null]),
|
|
@@ -219,7 +215,6 @@ function facets(s) {
|
|
|
219
215
|
? JSON.stringify([
|
|
220
216
|
id, diff_contains ?? null, diff_excludes ?? null,
|
|
221
217
|
...(traceAssert ? [traceAssert] : []),
|
|
222
|
-
...(trajectoryAssert ? [trajectoryAssert] : []),
|
|
223
218
|
])
|
|
224
219
|
: null,
|
|
225
220
|
};
|
package/dist/spec.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { WorkspaceKind } from "./workspace.js";
|
|
2
2
|
import { type TraceAssert } from "./trace-gates.js";
|
|
3
|
-
import { type TrajectoryAssert } from "./trajectory-gates.js";
|
|
4
3
|
export type ScenarioMode = "inline" | "seeded";
|
|
5
4
|
export interface SeededAssert {
|
|
6
5
|
vitest?: boolean;
|
|
@@ -21,14 +20,6 @@ export interface SeededAssert {
|
|
|
21
20
|
*/
|
|
22
21
|
post_test?: string;
|
|
23
22
|
}
|
|
24
|
-
export interface TrajectoryEventSource {
|
|
25
|
-
/** Native format adapter registered by the harness adapter. */
|
|
26
|
-
adapter: "normalized-v1" | "principal-assurance-v1" | "pi-daddy-v1" | "pi-daddy-ledger-v3";
|
|
27
|
-
/** Workspace-relative file/glob. Never an absolute path or traversal. */
|
|
28
|
-
path: string;
|
|
29
|
-
/** Missing evidence is an error by default; false is for optional supplemental ledgers. */
|
|
30
|
-
required: boolean;
|
|
31
|
-
}
|
|
32
23
|
export interface Scenario {
|
|
33
24
|
id: string;
|
|
34
25
|
title: string;
|
|
@@ -46,10 +37,6 @@ export interface Scenario {
|
|
|
46
37
|
* Declaring it opts the scenario into structured (`--mode json`) execution.
|
|
47
38
|
*/
|
|
48
39
|
traceAssert?: TraceAssert;
|
|
49
|
-
/** Objective assertions over adapter-neutral, versioned workflow events. */
|
|
50
|
-
trajectoryAssert?: TrajectoryAssert;
|
|
51
|
-
/** Native event/ledger files the harness normalizes after execution. */
|
|
52
|
-
eventSources?: TrajectoryEventSource[];
|
|
53
40
|
workspace: WorkspaceKind;
|
|
54
41
|
remote: boolean;
|
|
55
42
|
systemPromptFile?: string;
|