humanish 0.109.1 → 0.110.1
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/ARCHITECTURE.md +14 -11
- package/CHANGELOG.md +24 -0
- package/CONTEXT.md +8 -6
- package/README.md +97 -48
- package/dist/actors/computer-use/loop/ending.js +4 -4
- package/dist/actors/local-agent/claude-participant.d.ts +74 -0
- package/dist/actors/local-agent/claude-participant.js +243 -0
- package/dist/actors/local-agent/claude-session.d.ts +16 -3
- package/dist/actors/local-agent/claude-session.js +64 -23
- package/dist/actors/local-agent/cli.d.ts +11 -0
- package/dist/actors/local-agent/cli.js +103 -24
- package/dist/actors/local-agent/readiness.d.ts +2 -2
- package/dist/actors/local-agent/readiness.js +18 -11
- package/dist/cli/commands/analyze.js +21 -5
- package/dist/cli/commands/comms.js +25 -7
- package/dist/cli/commands/observe.js +4 -2
- package/dist/cli/commands/run-command.js +4 -3
- package/dist/cli/commands/run-signals.d.ts +2 -0
- package/dist/cli/commands/run-signals.js +96 -44
- package/dist/cli/commands/runs.d.ts +5 -0
- package/dist/cli/commands/runs.js +89 -67
- package/dist/cli/commands/setup.js +19 -5
- package/dist/cli/commands/study-format.js +29 -2
- package/dist/cli/commands/study-route-computer-use.js +2 -0
- package/dist/cli/commands/study-route-scripted.js +2 -0
- package/dist/cli/commands/study-route-shared-world.js +2 -0
- package/dist/cli/commands/study-route-terminal.js +2 -0
- package/dist/cli/commands/study.js +4 -3
- package/dist/cli/commands/tui.js +4 -3
- package/dist/cli/commands/watch.js +2 -2
- package/dist/cli/doctor.d.ts +7 -2
- package/dist/cli/doctor.js +47 -8
- package/dist/cli/findings.d.ts +103 -0
- package/dist/cli/findings.js +316 -0
- package/dist/cli/first-run-path.d.ts +5 -4
- package/dist/cli/first-run-path.js +14 -7
- package/dist/cli/io.d.ts +17 -3
- package/dist/cli/io.js +22 -4
- package/dist/cli/product-sentence.d.ts +3 -3
- package/dist/cli/product-sentence.js +3 -3
- package/dist/comms/receiving-runtime.js +1 -1
- package/dist/comms/setup.js +1 -1
- package/dist/evidence/redaction.d.ts +7 -3
- package/dist/evidence/redaction.js +68 -24
- package/dist/feedback/export-bundle.js +6 -1
- package/dist/feedback/export.js +3 -0
- package/dist/keys/env-file.d.ts +4 -0
- package/dist/keys/env-file.js +17 -0
- package/dist/keys/key-resolution.d.ts +7 -0
- package/dist/keys/key-resolution.js +10 -8
- package/dist/observer/data.d.ts +14 -1
- package/dist/observer/data.js +19 -9
- package/dist/observer/library.d.ts +4 -0
- package/dist/observer/library.js +18 -15
- package/dist/observer/render.js +8 -2
- package/dist/observer/run-routes.d.ts +2 -0
- package/dist/observer/run-routes.js +43 -34
- package/dist/observer-app.html +3 -3
- package/dist/routes/computer-use/bundle.js +3 -1
- package/dist/routes/computer-use/fanout-records.js +1 -1
- package/dist/routes/computer-use/live-phase.d.ts +1 -0
- package/dist/routes/computer-use/participant-execution.js +3 -1
- package/dist/routes/computer-use/participant-model.js +5 -2
- package/dist/routes/computer-use/plan.js +4 -4
- package/dist/routes/computer-use/preflight.js +2 -2
- package/dist/routes/computer-use/result.js +17 -28
- package/dist/routes/computer-use/single-bundle.js +7 -1
- package/dist/routes/computer-use/types.d.ts +6 -0
- package/dist/routes/scripted/bundle.js +4 -2
- package/dist/routes/scripted/plan.js +2 -2
- package/dist/routes/scripted/result.d.ts +3 -5
- package/dist/routes/scripted/result.js +16 -22
- package/dist/routes/scripted/scenario.js +4 -4
- package/dist/routes/scripted/types.d.ts +1 -0
- package/dist/routes/shared-world/bundle-records.js +6 -1
- package/dist/routes/shared-world/bundle.js +2 -0
- package/dist/routes/shared-world/plan.js +1 -1
- package/dist/routes/shared-world/result.js +22 -22
- package/dist/routes/shared-world/route.js +1 -1
- package/dist/routes/shared-world/types.d.ts +2 -0
- package/dist/routes/terminal/bundle.js +4 -2
- package/dist/routes/terminal/credentials.js +1 -1
- package/dist/routes/terminal/dry-run.js +8 -12
- package/dist/routes/terminal/ledger.d.ts +3 -3
- package/dist/routes/terminal/ledger.js +6 -6
- package/dist/routes/terminal/live-finish.js +23 -17
- package/dist/routes/terminal/plan.js +4 -4
- package/dist/routes/terminal/result.d.ts +6 -7
- package/dist/routes/terminal/result.js +6 -22
- package/dist/routes/terminal/session.js +1 -1
- package/dist/routes/terminal/types.d.ts +3 -0
- package/dist/run/bundle-shape.d.ts +3 -1
- package/dist/run/bundle-shape.js +26 -1
- package/dist/run/bundle.d.ts +30 -0
- package/dist/run/display.d.ts +59 -0
- package/dist/run/display.js +106 -0
- package/dist/run/dry-run.js +11 -7
- package/dist/run/judge.d.ts +3 -2
- package/dist/run/judge.js +10 -0
- package/dist/run/pricing.js +1 -1
- package/dist/run/projection.d.ts +0 -2
- package/dist/run/projection.js +0 -11
- package/dist/run/reclaim-outcomes.d.ts +89 -0
- package/dist/run/reclaim-outcomes.js +213 -0
- package/dist/run/reclaim.d.ts +18 -14
- package/dist/run/reclaim.js +179 -105
- package/dist/run/results.d.ts +11 -18
- package/dist/run/results.js +2 -2
- package/dist/run/run-index.d.ts +11 -1
- package/dist/run/run-index.js +11 -0
- package/dist/run/run.d.ts +34 -18
- package/dist/run/run.js +177 -72
- package/dist/run/sandbox-creates.d.ts +59 -0
- package/dist/run/sandbox-creates.js +138 -0
- package/dist/run/sandbox-ids.d.ts +53 -0
- package/dist/run/sandbox-ids.js +198 -0
- package/dist/run/sandbox-receipts.d.ts +16 -0
- package/dist/run/sandbox-receipts.js +70 -0
- package/dist/run/stats.d.ts +5 -0
- package/dist/run/stats.js +8 -4
- package/dist/run/status.d.ts +6 -9
- package/dist/run/status.js +7 -20
- package/dist/run/stored-runs.d.ts +5 -14
- package/dist/run/stored-runs.js +31 -137
- package/dist/run/streams.d.ts +3 -2
- package/dist/run-study.js +6 -1
- package/dist/study/doctor.d.ts +1 -1
- package/dist/study/doctor.js +7 -4
- package/dist/study/init-templates.js +2 -2
- package/dist/study/init.js +14 -3
- package/dist/study/keys.d.ts +12 -0
- package/dist/study/keys.js +32 -0
- package/dist/study/persona.d.ts +4 -0
- package/dist/study/persona.js +4 -2
- package/dist/study/types.d.ts +1 -1
- package/dist/substrates/e2b/peer-install.d.ts +51 -0
- package/dist/substrates/e2b/peer-install.js +161 -0
- package/dist/substrates/e2b/sandbox.d.ts +34 -6
- package/dist/substrates/e2b/sandbox.js +128 -35
- package/dist/substrates/e2b/sdk.d.ts +33 -0
- package/dist/substrates/e2b/sdk.js +21 -21
- package/dist/substrates/shell.d.ts +2 -0
- package/dist/substrates/shell.js +4 -0
- package/dist/tui-app.js +133 -133
- package/dist/verify/artifacts.d.ts +4 -0
- package/dist/verify/artifacts.js +8 -0
- package/dist/verify/liveness.d.ts +19 -3
- package/dist/verify/liveness.js +53 -28
- package/dist/verify/verify.d.ts +4 -1
- package/dist/verify/verify.js +27 -3
- package/docs/architecture/actor-contract.md +2 -1
- package/docs/architecture/observer.md +22 -7
- package/docs/architecture/restricted-codex-analysis.md +1 -1
- package/docs/architecture/task-protocol-support.md +13 -13
- package/docs/architecture/terminal-product-route.md +1 -1
- package/docs/contracts/run-bundle.md +90 -7
- package/docs/contracts/schemas.md +39 -22
- package/docs/contracts/study-analysis.md +45 -0
- package/docs/contracts/study-costs.md +8 -0
- package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +3 -0
- package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +9 -3
- package/docs/principles/invariants-and-defaults.md +11 -8
- package/package.json +5 -3
- package/skills/humanish/SKILL.md +18 -4
|
@@ -95,6 +95,7 @@ export interface ConcurrentSharedWorldParticipantResult {
|
|
|
95
95
|
/** The actor sandbox lifecycle proof (the getHost/key value is never surfaced here). */
|
|
96
96
|
sandbox?: {
|
|
97
97
|
sandboxId: string;
|
|
98
|
+
sandboxIdDigest?: string;
|
|
98
99
|
killed: boolean;
|
|
99
100
|
};
|
|
100
101
|
error?: {
|
|
@@ -119,6 +120,7 @@ export interface ConcurrentSharedWorldStudyResult extends AutomaticAnalysisResul
|
|
|
119
120
|
/** The one subject sandbox lifecycle proof. */
|
|
120
121
|
subjectSandbox?: {
|
|
121
122
|
sandboxId: string;
|
|
123
|
+
sandboxIdDigest?: string;
|
|
122
124
|
killed: boolean;
|
|
123
125
|
};
|
|
124
126
|
/** Whether ≥2 actor windows overlapped in time (proven concurrency; live only). */
|
|
@@ -2,6 +2,7 @@ import { redactText } from "../../evidence/redaction.js";
|
|
|
2
2
|
import { participantAssignment } from "../../study/participant-assignment.js";
|
|
3
3
|
import { REVIEW_SCHEMA, bundleArtifacts, bundleHead, } from "../../run/bundle.js";
|
|
4
4
|
import { verdictText } from "../../run/judge.js";
|
|
5
|
+
import { reviewOutcome } from "../../run/display.js";
|
|
5
6
|
import {} from "../../run/streams.js";
|
|
6
7
|
import { participantEvent, participantIds, participantRecord, participantStream, } from "../../run/participant-records.js";
|
|
7
8
|
import { TERMINAL_EVENTS_ARTIFACT, TERMINAL_LEDGERS_ARTIFACT, TERMINAL_TRANSCRIPT_ARTIFACT, } from "../../run/terminal-contract.js";
|
|
@@ -72,7 +73,7 @@ export function buildTerminalProductBundle(args) {
|
|
|
72
73
|
at: args.run.createdAt,
|
|
73
74
|
level: "info",
|
|
74
75
|
type: "terminal-lab.contract.ready",
|
|
75
|
-
message: "Dry-run bundle ready. Switch
|
|
76
|
+
message: "Dry-run bundle ready. Switch mode to live with the required runtime auth and caps to exercise the in-sandbox agent route, captured exec stream, and declared runtime-auth placement.",
|
|
76
77
|
}),
|
|
77
78
|
];
|
|
78
79
|
const review = {
|
|
@@ -172,7 +173,7 @@ export function buildLiveTerminalProductBundle(args) {
|
|
|
172
173
|
// so a green run never silently over-claims a fully-proven $0.
|
|
173
174
|
...(noSpend.unmeasuredLines.length > 0
|
|
174
175
|
? [
|
|
175
|
-
`${noSpendLineMeasured(noSpend) ? noSpendNotEstablished(noSpend.maxUsd ?? 0) : "No-spend proof is partial."} ${describeMeasuredSpend(args.ledgers.cost, args.trace.tokenUsage)}
|
|
176
|
+
`${noSpendLineMeasured(noSpend) ? noSpendNotEstablished(noSpend.maxUsd ?? 0) : "No-spend proof is partial."} ${describeMeasuredSpend(args.ledgers.cost, args.trace.tokenUsage)} humanish has no source for the missing lines, and a study cannot supply one.`,
|
|
176
177
|
]
|
|
177
178
|
: []),
|
|
178
179
|
],
|
|
@@ -283,6 +284,7 @@ export function renderTerminalReviewMarkdown(bundle) {
|
|
|
283
284
|
`- run: ${bundle.runId}`,
|
|
284
285
|
`- mode: ${bundle.mode}`,
|
|
285
286
|
`- verdict: ${verdictText(bundle.review.verdict, bundle.mode)}`,
|
|
287
|
+
`- outcome: ${reviewOutcome(bundle)}`,
|
|
286
288
|
`- summary: ${bundle.review.summary}`,
|
|
287
289
|
`- mission: ${bundle.scenario.goal}`,
|
|
288
290
|
...(subject ? [`- subject: ${subject.message}`] : []),
|
|
@@ -38,7 +38,7 @@ export function buildRuntimeAuth(args) {
|
|
|
38
38
|
return {
|
|
39
39
|
ok: false,
|
|
40
40
|
code: "HUMANISH_TERMINAL_RUNTIME_AUTH_MISSING",
|
|
41
|
-
message: `Live terminal-product studies declare runtimeAuth "${String(args.runtimeAuth)}" and need ${ALLOWED_RUNTIME_KEY_NAMES.join(" or ")} in the environment (pass via --
|
|
41
|
+
message: `Live terminal-product studies declare runtimeAuth "${String(args.runtimeAuth)}" and need ${ALLOWED_RUNTIME_KEY_NAMES.join(" or ")} in the environment (pass via --dotenv; the selected auth mode places the value in command-scoped env or an external E2B header transform; the value is never persisted).`,
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
const keyValue = args.env[keyName];
|
|
@@ -68,20 +68,16 @@ export async function runDryTerminalStudy(args) {
|
|
|
68
68
|
verdict: judgment.verdict,
|
|
69
69
|
});
|
|
70
70
|
bundle.events.push(runtimeDeclaredEvent(plan.runtime, createdAt));
|
|
71
|
-
const
|
|
71
|
+
const policy = OUTCOME_POLICIES.terminal;
|
|
72
|
+
const execution = judgeExecution([], policy);
|
|
73
|
+
const finished = await run.finish(bundle, {
|
|
74
|
+
ok: resultOk({ judgment, execution, scorerFailures: [], policy }),
|
|
75
|
+
execution,
|
|
76
|
+
policy,
|
|
77
|
+
});
|
|
72
78
|
const observer = await finished.renderObserver();
|
|
73
79
|
await validatePreparedRunArtifactPaths(finished.paths);
|
|
74
|
-
const
|
|
75
|
-
const execution = judgeExecution(observer.ok
|
|
76
|
-
? []
|
|
77
|
-
: [
|
|
78
|
-
{
|
|
79
|
-
kind: "evidence",
|
|
80
|
-
message: observer.error?.message ?? "Observer failed for the terminal-product run.",
|
|
81
|
-
},
|
|
82
|
-
], policy);
|
|
83
|
-
const ok = resultOk({ judgment, execution, scorerFailures: [], policy });
|
|
84
|
-
await finished.recordOutcome({ ok, execution });
|
|
80
|
+
const { ok } = finished.outcome;
|
|
85
81
|
return {
|
|
86
82
|
...studyResultIdentity("terminal", plan.studyId),
|
|
87
83
|
ok,
|
|
@@ -7,9 +7,9 @@ import type { CostLine, NoSpendProof, TerminalCostLedger } from "./types.js";
|
|
|
7
7
|
* - The `provider` line is populated from the actor trace's tokenUsage.costUsd when the trace
|
|
8
8
|
* carries it (a measured value, incl. a measured 0). When the trace carries no costUsd, the
|
|
9
9
|
* provider line is `null` = not measured (never guessed to 0 just because no-spend was intended).
|
|
10
|
-
* - product/media/payment are `null` by default: core has no signal for those categories
|
|
11
|
-
*
|
|
12
|
-
* `injectedLines` lets a test
|
|
10
|
+
* - product/media/payment are `null` by default: core has no signal for those categories, and
|
|
11
|
+
* only a test can supply one, through `StudyDeps.costProbe`.
|
|
12
|
+
* `injectedLines` lets a test supply known spend for a category,
|
|
13
13
|
* exercising the fail-closed cap enforcement deterministically without a real billable run.
|
|
14
14
|
*/
|
|
15
15
|
export declare function buildCostLedger(args: {
|
|
@@ -6,9 +6,9 @@ import { COST_CATEGORIES } from "../../run/terminal-contract.js";
|
|
|
6
6
|
* - The `provider` line is populated from the actor trace's tokenUsage.costUsd when the trace
|
|
7
7
|
* carries it (a measured value, incl. a measured 0). When the trace carries no costUsd, the
|
|
8
8
|
* provider line is `null` = not measured (never guessed to 0 just because no-spend was intended).
|
|
9
|
-
* - product/media/payment are `null` by default: core has no signal for those categories
|
|
10
|
-
*
|
|
11
|
-
* `injectedLines` lets a test
|
|
9
|
+
* - product/media/payment are `null` by default: core has no signal for those categories, and
|
|
10
|
+
* only a test can supply one, through `StudyDeps.costProbe`.
|
|
11
|
+
* `injectedLines` lets a test supply known spend for a category,
|
|
12
12
|
* exercising the fail-closed cap enforcement deterministically without a real billable run.
|
|
13
13
|
*/
|
|
14
14
|
export function buildCostLedger(args) {
|
|
@@ -39,7 +39,7 @@ export function buildCostLedger(args) {
|
|
|
39
39
|
usd: null,
|
|
40
40
|
count: null,
|
|
41
41
|
source: "unmeasured",
|
|
42
|
-
note: `${category} spend not measured: humanish has no ${category} spend signal
|
|
42
|
+
note: `${category} spend not measured: humanish has no ${category} spend signal, and a study cannot supply one. Recorded as null, never guessed as 0.`,
|
|
43
43
|
});
|
|
44
44
|
const lines = {
|
|
45
45
|
product: args.injectedLines?.product ?? unmeasured("product"),
|
|
@@ -149,7 +149,7 @@ export function evaluateCapsAgainstLedger(ledger, caps) {
|
|
|
149
149
|
const overLines = COST_CATEGORIES.filter((c) => ledger.lines[c].usd !== null && ledger.lines[c].usd > 0);
|
|
150
150
|
return {
|
|
151
151
|
ok: false,
|
|
152
|
-
message: `Stopped: measured spend ${ledger.knownTotalUsd} USD passed
|
|
152
|
+
message: `Stopped: measured spend ${ledger.knownTotalUsd} USD passed caps.maxUsd=${caps.maxUsd}${overLines.length > 0 ? ` (non-zero lines: ${overLines.join(", ")})` : ""}. The cap stops the run; it is not a warning.`,
|
|
153
153
|
};
|
|
154
154
|
}
|
|
155
155
|
if (caps.maxJobs !== undefined) {
|
|
@@ -162,7 +162,7 @@ export function evaluateCapsAgainstLedger(ledger, caps) {
|
|
|
162
162
|
if (knownJobs > caps.maxJobs) {
|
|
163
163
|
return {
|
|
164
164
|
ok: false,
|
|
165
|
-
message: `Stopped: ${knownJobs} measured billable jobs passed
|
|
165
|
+
message: `Stopped: ${knownJobs} measured billable jobs passed caps.maxJobs=${caps.maxJobs}.`,
|
|
166
166
|
};
|
|
167
167
|
}
|
|
168
168
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Finishing a live terminal session: the actor trace from the captured stream, the spend ledger
|
|
2
2
|
// and its caps check, the evidence files, the bundle, and the study result.
|
|
3
|
+
import { publicSandboxView, readRunSandboxIds, scrubSandboxIds } from "../../run/sandbox-ids.js";
|
|
3
4
|
import { buildRunCostSummary } from "../../run/cost-summary.js";
|
|
4
5
|
import { writeContainedOutputFile } from "../../run/contained-output.js";
|
|
5
6
|
import { validatePreparedRunArtifactPaths, } from "../../run/paths.js";
|
|
@@ -8,7 +9,7 @@ import { normalizeLocalActorTranscript, TERMINAL_EVENTS_ARTIFACT, TERMINAL_LEDGE
|
|
|
8
9
|
import { applyAdapterExtensionSeam } from "./adapter.js";
|
|
9
10
|
import { buildLiveTerminalProductBundle } from "./bundle.js";
|
|
10
11
|
import { buildCostLedger, buildNoSpendProof, describeMeasuredSpend, evaluateCapsAgainstLedger, noSpendLineMeasured, noSpendNotEstablished, } from "./ledger.js";
|
|
11
|
-
import { foldScorerFailures, judgeExecution, judgeTerminal, OUTCOME_POLICIES, } from "../../run/judge.js";
|
|
12
|
+
import { foldScorerFailures, judgeExecution, judgeTerminal, OUTCOME_POLICIES, resultOk, } from "../../run/judge.js";
|
|
12
13
|
import { terminalExecutionFailures, terminalStudyResult, terminalParticipantFacts, } from "./result.js";
|
|
13
14
|
import { parseTerminalTokenUsage } from "./token-usage.js";
|
|
14
15
|
import { buildTerminalActorTrace, scrubSplitKnownValues, tailOf } from "./trace.js";
|
|
@@ -59,7 +60,7 @@ async function settleLiveLedgers(inputs, trace, normalizedTranscript) {
|
|
|
59
60
|
// --- Spend ledger + no-spend proof + full caps enforcement (fail-closed). ---
|
|
60
61
|
// The cost ledger is derived, with the null discipline: provider spend from the trace's
|
|
61
62
|
// tokenUsage.costUsd when present (else null = not measured), product/media/payment null by
|
|
62
|
-
// default (core has no signal). The costProbe hook lets tests
|
|
63
|
+
// default (core has no signal). The costProbe hook lets tests inject known
|
|
63
64
|
// spend to exercise the fail-closed cap without a real billable run.
|
|
64
65
|
const injectedLines = costProbe?.(trace.tokenUsage?.costUsd === undefined ? {} : { tokenCostUsd: trace.tokenUsage.costUsd });
|
|
65
66
|
if (costProbe)
|
|
@@ -170,19 +171,24 @@ export async function finishLiveTerminalSession(inputs) {
|
|
|
170
171
|
// The one final verdict fold: scoring can only make the judged verdict stricter.
|
|
171
172
|
bundle.review = foldScorerFailures(bundle.review, scorer.failures);
|
|
172
173
|
await validatePreparedRunArtifactPaths(runPaths);
|
|
173
|
-
const finished = await run.finish(bundle);
|
|
174
|
-
const observer = await finished.renderObserver();
|
|
175
|
-
await validatePreparedRunArtifactPaths(runPaths);
|
|
176
174
|
// A failing agent is captured evidence on this route: only the execution and a declared scorer
|
|
177
|
-
// fail ok.
|
|
175
|
+
// fail ok. A declared scorer that did not render a pass (status:"fail", malformed or thrown) is a
|
|
176
|
+
// gate, so it fails ok as well as the persisted verdict.
|
|
177
|
+
const policy = OUTCOME_POLICIES.terminal;
|
|
178
178
|
const execution = judgeExecution(terminalExecutionFailures({
|
|
179
179
|
participant,
|
|
180
180
|
capFailure,
|
|
181
181
|
sessionReason: sanitize(session.reason),
|
|
182
182
|
cleanup: session.cleanup,
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
}), policy);
|
|
184
|
+
const finished = await run.finish(bundle, {
|
|
185
|
+
ok: resultOk({ judgment, execution, scorerFailures: scorer.failures, policy }),
|
|
186
|
+
execution,
|
|
187
|
+
policy,
|
|
188
|
+
});
|
|
189
|
+
const observer = await finished.renderObserver();
|
|
190
|
+
await validatePreparedRunArtifactPaths(runPaths);
|
|
191
|
+
return terminalStudyResult({
|
|
186
192
|
cwd,
|
|
187
193
|
studyId: plan.studyId,
|
|
188
194
|
actorId: plan.actor,
|
|
@@ -198,19 +204,19 @@ export async function finishLiveTerminalSession(inputs) {
|
|
|
198
204
|
noSpendProof,
|
|
199
205
|
capFailure,
|
|
200
206
|
declaredScorerFailure: scorer.failures[0],
|
|
201
|
-
|
|
202
|
-
execution,
|
|
207
|
+
ok: finished.outcome.ok,
|
|
203
208
|
observer,
|
|
204
209
|
warnings,
|
|
205
210
|
});
|
|
206
|
-
await finished.recordOutcome({ ok: result.ok, execution });
|
|
207
|
-
return result;
|
|
208
211
|
}
|
|
209
212
|
/** Persist the terminal evidence: redacted events, normalized transcript, ledgers, actor trace. */
|
|
210
213
|
async function writeTerminalEvidence(runPaths, evidence) {
|
|
211
214
|
const { terminalEvents, normalizedTranscript, ledgers, trace } = evidence;
|
|
212
|
-
|
|
213
|
-
await
|
|
214
|
-
|
|
215
|
-
await writeContainedOutputFile(runPaths,
|
|
215
|
+
// The sandbox's raw id stays in sandbox-receipts.ndjson; these files name it by digest.
|
|
216
|
+
const ids = await readRunSandboxIds(runPaths);
|
|
217
|
+
const scrub = (text) => scrubSandboxIds(text, ids);
|
|
218
|
+
await writeContainedOutputFile(runPaths, TERMINAL_EVENTS_ARTIFACT, scrub(`${terminalEvents.map((e) => JSON.stringify(e)).join("\n")}${terminalEvents.length > 0 ? "\n" : ""}`), "utf8");
|
|
219
|
+
await writeContainedOutputFile(runPaths, TERMINAL_TRANSCRIPT_ARTIFACT, scrub(`${normalizedTranscript}\n`), "utf8");
|
|
220
|
+
await writeContainedOutputFile(runPaths, TERMINAL_LEDGERS_ARTIFACT, `${JSON.stringify(publicSandboxView(ledgers, ids), null, 2)}\n`, "utf8");
|
|
221
|
+
await writeContainedOutputFile(runPaths, "actor.json", scrub(`${JSON.stringify(trace, null, 2)}\n`), "utf8");
|
|
216
222
|
}
|
|
@@ -35,7 +35,7 @@ export function planTerminalStudy(config, input) {
|
|
|
35
35
|
const actorType = config.actors[0]?.type ?? "";
|
|
36
36
|
const descriptor = actorRegistry[actorType];
|
|
37
37
|
if (!descriptor || !isTerminalActorDescriptor(descriptor))
|
|
38
|
-
return refuse("HUMANISH_TERMINAL_ACTOR_UNSUPPORTED", `
|
|
38
|
+
return refuse("HUMANISH_TERMINAL_ACTOR_UNSUPPORTED", `actor.type "${actorType}" is not a registered terminal actor.`);
|
|
39
39
|
const runtimeVersion = config.execution?.runtime?.version;
|
|
40
40
|
const actor = config.actors[0];
|
|
41
41
|
if ((config.execution?.runtime !== undefined && !isExactRuntimeVersion(runtimeVersion)) ||
|
|
@@ -87,14 +87,14 @@ export function planTerminalStudy(config, input) {
|
|
|
87
87
|
const maxUsd = caps?.maxUsd;
|
|
88
88
|
const maxMinutes = caps?.maxMinutes;
|
|
89
89
|
if (caps === undefined || maxUsd === undefined || maxMinutes === undefined || maxMinutes <= 0)
|
|
90
|
-
return refuse("HUMANISH_TERMINAL_CAPS_MISSING", "A live terminal-product run gives the agent in the sandbox access to a model provider, so it needs a cap: set
|
|
90
|
+
return refuse("HUMANISH_TERMINAL_CAPS_MISSING", "A live terminal-product run gives the agent in the sandbox access to a model provider, so it needs a cap: set caps with maxUsd (0 means no spend) and a positive maxMinutes (the time limit for the codex command). The key is used only while the cap is in force.", descriptor.id);
|
|
91
91
|
// maxUsd is checked against the cost ledger after the session, and only known lines can trip it.
|
|
92
92
|
// The ledger's provider line takes only provider-reported cost, which Codex does not report (the
|
|
93
93
|
// token estimate in run.json is not a measurement), and core has no product, media or payment
|
|
94
94
|
// signal, so without a costProbe every line is null and a positive maxUsd could never trip. That
|
|
95
95
|
// cap would promise a bound nothing enforces, so it is refused; maxMinutes bounds a live run.
|
|
96
96
|
if (maxUsd > 0 && input.hasCostProbe !== true)
|
|
97
|
-
return refuse("HUMANISH_TERMINAL_UNPRICED_CAP", `
|
|
97
|
+
return refuse("HUMANISH_TERMINAL_UNPRICED_CAP", `caps.maxUsd=${maxUsd} cannot be enforced: Codex reports no provider cost for the participant (its token cost is only estimated after the run) and no product, media or payment spend is measured, so a positive dollar cap can never trip. Set caps.maxUsd to 0 and bound the run with caps.maxMinutes, the codex command's wall-clock kill. No sandbox was created and the runtime key was not used.`, descriptor.id);
|
|
98
98
|
// The sandbox's timeout covers the steps before the codex command, maxMinutes and the teardown
|
|
99
99
|
// buffer, and E2B refuses a sandbox over an hour. Refuse here, with the arithmetic, rather than
|
|
100
100
|
// after the plan prints, from a provider 400 that names neither knob.
|
|
@@ -102,7 +102,7 @@ export function planTerminalStudy(config, input) {
|
|
|
102
102
|
const sandboxTimeoutMs = terminalSandboxTimeoutMs({ maxMinutes, productInstall });
|
|
103
103
|
if (sandboxTimeoutMs > MAX_SANDBOX_MS) {
|
|
104
104
|
const headroomMinutes = (sandboxTimeoutMs - maxMinutes * 60_000) / 60_000;
|
|
105
|
-
return refuse("HUMANISH_TERMINAL_CAPS_INVALID", `
|
|
105
|
+
return refuse("HUMANISH_TERMINAL_CAPS_INVALID", `caps.maxMinutes ${maxMinutes} derives a ${sandboxTimeoutMs / 60_000}m sandbox deadline, and a sandbox may not live longer than ${MAX_SANDBOX_MS / 60_000}m. The deadline is maxMinutes plus ${headroomMinutes}m: the Node bootstrap (${NODE_BOOTSTRAP_TIMEOUT_MS / 60_000}m), the runtime version check (${TERMINAL_RUNTIME_VERSION_TIMEOUT_MS / 60_000}m)${productInstall ? `, the product setup (${PRODUCT_SETUP_TIMEOUT_MS / 60_000}m)` : ""} and the teardown buffer (${TERMINAL_SANDBOX_TIMEOUT_BUFFER_MS / 60_000}m). Lower caps.maxMinutes to at most ${MAX_SANDBOX_MS / 60_000 - headroomMinutes}. No sandbox was created and the runtime key was not used.`, descriptor.id);
|
|
106
106
|
}
|
|
107
107
|
return {
|
|
108
108
|
ok: true,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ObserverResult } from "../../observer/render.js";
|
|
2
2
|
import type { ActorCompletionReason, ActorStatus, ActorTrace } from "../../actors/contract.js";
|
|
3
|
-
import { type ExecutionFailure, type
|
|
3
|
+
import { type ExecutionFailure, type ParticipantFacts } from "../../run/judge.js";
|
|
4
4
|
import { type NoSpendProof, type TerminalCostLedger, type TerminalLedgers, type TerminalProductStudyResult } from "./types.js";
|
|
5
5
|
/**
|
|
6
6
|
* What judge.ts reads from a finished terminal session, after a blown cap has overridden it. It has
|
|
@@ -8,8 +8,9 @@ import { type NoSpendProof, type TerminalCostLedger, type TerminalLedgers, type
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function terminalParticipantFacts(trace: ActorTrace, sessionError: string | undefined): ParticipantFacts;
|
|
10
10
|
/**
|
|
11
|
-
* The live run's execution failures: a harness error, a blown spend
|
|
12
|
-
*
|
|
11
|
+
* The live run's execution failures before the Observer renders: a harness error, a blown spend
|
|
12
|
+
* cap and an unproven sandbox teardown. FinishedRun.renderObserver adds an Observer that did not
|
|
13
|
+
* render.
|
|
13
14
|
*/
|
|
14
15
|
export declare function terminalExecutionFailures(args: {
|
|
15
16
|
participant: ParticipantFacts;
|
|
@@ -18,7 +19,6 @@ export declare function terminalExecutionFailures(args: {
|
|
|
18
19
|
/** Already scrubbed and redacted. */
|
|
19
20
|
sessionReason: string;
|
|
20
21
|
cleanup: TerminalLedgers["cleanup"];
|
|
21
|
-
observer: Pick<ObserverResult, "ok" | "error">;
|
|
22
22
|
}): ExecutionFailure[];
|
|
23
23
|
/** The terminal-product study result for a live run, from its session, cleanup and cost ledger. */
|
|
24
24
|
export declare function terminalStudyResult(args: {
|
|
@@ -39,9 +39,8 @@ export declare function terminalStudyResult(args: {
|
|
|
39
39
|
/** The cap check's message when known spend or jobs exceeded the caps. */
|
|
40
40
|
capFailure: string | undefined;
|
|
41
41
|
declaredScorerFailure: string | undefined;
|
|
42
|
-
/**
|
|
43
|
-
|
|
44
|
-
execution: ExecutionOutcome;
|
|
42
|
+
/** run.json's outcome.ok (FinishedRun.outcome). On this evidence route it does not read whether the agent passed. */
|
|
43
|
+
ok: boolean;
|
|
45
44
|
observer: ObserverResult;
|
|
46
45
|
warnings: string[];
|
|
47
46
|
}): TerminalProductStudyResult;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { participantHarnessFailed, } from "../../run/judge.js";
|
|
2
2
|
import {} from "./types.js";
|
|
3
3
|
import { studyResultIdentity } from "../../run/study-result.js";
|
|
4
4
|
/**
|
|
@@ -16,11 +16,12 @@ export function terminalParticipantFacts(trace, sessionError) {
|
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
* The live run's execution failures: a harness error, a blown spend
|
|
20
|
-
*
|
|
19
|
+
* The live run's execution failures before the Observer renders: a harness error, a blown spend
|
|
20
|
+
* cap and an unproven sandbox teardown. FinishedRun.renderObserver adds an Observer that did not
|
|
21
|
+
* render.
|
|
21
22
|
*/
|
|
22
23
|
export function terminalExecutionFailures(args) {
|
|
23
|
-
const { participant, cleanup
|
|
24
|
+
const { participant, cleanup } = args;
|
|
24
25
|
return [
|
|
25
26
|
...(participantHarnessFailed(participant)
|
|
26
27
|
? [{ kind: "harness", message: participant.sessionError ?? args.sessionReason }]
|
|
@@ -34,34 +35,17 @@ export function terminalExecutionFailures(args) {
|
|
|
34
35
|
message: `Sandbox teardown unproven (killed=${cleanup.killed}, remaining=${cleanup.remaining}): ${cleanup.reason}`,
|
|
35
36
|
},
|
|
36
37
|
]),
|
|
37
|
-
...(observer.ok
|
|
38
|
-
? []
|
|
39
|
-
: [
|
|
40
|
-
{
|
|
41
|
-
kind: "evidence",
|
|
42
|
-
message: observer.error?.message ?? "Observer failed for the terminal-product run.",
|
|
43
|
-
},
|
|
44
|
-
]),
|
|
45
38
|
];
|
|
46
39
|
}
|
|
47
40
|
/** The terminal-product study result for a live run, from its session, cleanup and cost ledger. */
|
|
48
41
|
export function terminalStudyResult(args) {
|
|
49
|
-
const { cwd, studyId, actorId, productName, runId, sessionStatus, completionReason, sessionReason, sessionError, sandboxId, cleanup, cost, noSpendProof, capFailure, declaredScorerFailure,
|
|
42
|
+
const { cwd, studyId, actorId, productName, runId, sessionStatus, completionReason, sessionReason, sessionError, sandboxId, cleanup, cost, noSpendProof, capFailure, declaredScorerFailure, ok, observer, warnings, } = args;
|
|
50
43
|
// The run's exit code: verified evidence, no harness error and proven cleanup. A blocked/
|
|
51
44
|
// timed-out agent run is still ok-as-evidence at the bundle level (the failure is the evidence),
|
|
52
45
|
// but the study result surfaces ok:false on a harness error or unproven teardown (fail-closed).
|
|
53
46
|
// remaining===0 is the by-id-confirmed-reclaimed state; remaining===1 (still present) and
|
|
54
47
|
// remaining===-1 (kill(id) itself failed) are both unproven by design.
|
|
55
48
|
const cleanupProven = cleanup.killed && cleanup.remaining === 0;
|
|
56
|
-
// A config-declared scorer that failed to render a pass (status:"fail" / malformed / throw) fails the
|
|
57
|
-
// run result as well as the persisted verdict: the keystone route's declared rubric is a gate, so
|
|
58
|
-
// its fail must drive exit code. Library callers never set this (additive, back-compat).
|
|
59
|
-
const ok = resultOk({
|
|
60
|
-
judgment,
|
|
61
|
-
execution,
|
|
62
|
-
scorerFailures: declaredScorerFailure === undefined ? [] : [declaredScorerFailure],
|
|
63
|
-
policy: OUTCOME_POLICIES.terminal,
|
|
64
|
-
});
|
|
65
49
|
return {
|
|
66
50
|
...studyResultIdentity("terminal", studyId),
|
|
67
51
|
ok,
|
|
@@ -20,7 +20,7 @@ export function checkLiveTerminalMachine(plan, input, warnings) {
|
|
|
20
20
|
const { maxUsd } = plan.caps;
|
|
21
21
|
// planTerminalStudy refuses a positive maxUsd without a costProbe, so one is present here.
|
|
22
22
|
if (maxUsd > 0) {
|
|
23
|
-
warnings.push(`
|
|
23
|
+
warnings.push(`caps.maxUsd=${maxUsd} is checked after the session against the measured cost lines; a line left null (unmeasured) never trips it. caps.maxMinutes bounds the run while it runs.`);
|
|
24
24
|
}
|
|
25
25
|
// --- Deny-by-default credentials: build the command-scoped allowlist. ---
|
|
26
26
|
const runtimeEnv = buildRuntimeAuth({ runtimeAuth: plan.runtime.auth, env });
|
|
@@ -147,7 +147,10 @@ export interface TerminalProductStudyResult extends AutomaticAnalysisResult, Stu
|
|
|
147
147
|
};
|
|
148
148
|
/** Live-only: the sandbox lifecycle proof (the key/auth value is never surfaced here). */
|
|
149
149
|
sandbox?: {
|
|
150
|
+
/** "[redacted-sandbox-id]"; the raw id is only in the run's sandbox-receipts.ndjson. */
|
|
150
151
|
sandboxId: string;
|
|
152
|
+
/** The id's digest, which matches its receipt. */
|
|
153
|
+
sandboxIdDigest?: string;
|
|
151
154
|
killed: boolean;
|
|
152
155
|
/** By-id proof (never a re-list): 0 = confirmed reclaimed, 1 = still present (unconfirmed),
|
|
153
156
|
* -1 = kill(id) itself failed or was unavailable. See TerminalLedgers["cleanup"]. */
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { type ReviewSummary, type RunAdapterScore, type RunBundle } from "./bundle.js";
|
|
1
|
+
import { type ReviewSummary, type RunAdapterScore, type RunBundle, type RunOutcome } from "./bundle.js";
|
|
2
2
|
import { type StoredCleanupResult, type RunPointer } from "./results.js";
|
|
3
3
|
export declare function isRunBundle(value: unknown): value is RunBundle;
|
|
4
|
+
/** run.json's `outcome`: a finished run's ok and execution outcome, or the signal that stopped it. */
|
|
5
|
+
export declare function isRunOutcome(value: unknown): value is RunOutcome;
|
|
4
6
|
export declare function isCleanupResult(value: unknown): value is StoredCleanupResult;
|
|
5
7
|
export declare function isRunAdapterScore(value: unknown): value is RunAdapterScore;
|
|
6
8
|
export declare const ARCHIVE_SHA256_PATTERN: RegExp;
|
package/dist/run/bundle-shape.js
CHANGED
|
@@ -5,6 +5,7 @@ import { CLEANUP_SCHEMA, } from "./results.js";
|
|
|
5
5
|
import { isRunSimulationStatus, isRunStream, isRunStreamKind } from "./stream-shape.js";
|
|
6
6
|
import { isLocalEvidenceArtifactPath } from "./paths.js";
|
|
7
7
|
import { isRunFeedbackCandidate } from "./feedback-shape.js";
|
|
8
|
+
import { EXECUTION_FAILURE_KINDS } from "./judge.js";
|
|
8
9
|
import { isSharedWorldEvidence } from "./shared-world-shape.js";
|
|
9
10
|
import { isNonNegativeSafeInteger, isPositiveSafeInteger, isRecord } from "./type-guards.js";
|
|
10
11
|
export function isRunBundle(value) {
|
|
@@ -64,7 +65,30 @@ export function isRunBundle(value) {
|
|
|
64
65
|
value.adapterArtifacts.every(isRunAdapterArtifact))) &&
|
|
65
66
|
(value.providerResources === undefined ||
|
|
66
67
|
(Array.isArray(value.providerResources) &&
|
|
67
|
-
value.providerResources.every(isRunProviderResource)))
|
|
68
|
+
value.providerResources.every(isRunProviderResource))) &&
|
|
69
|
+
(value.outcome === undefined || isRunOutcome(value.outcome)));
|
|
70
|
+
}
|
|
71
|
+
function isExecutionFailureList(value) {
|
|
72
|
+
return (Array.isArray(value) &&
|
|
73
|
+
value.every((failure) => isRecord(failure) &&
|
|
74
|
+
typeof failure.kind === "string" &&
|
|
75
|
+
EXECUTION_FAILURE_KINDS.includes(failure.kind) &&
|
|
76
|
+
typeof failure.message === "string"));
|
|
77
|
+
}
|
|
78
|
+
/** run.json's `outcome`: a finished run's ok and execution outcome, or the signal that stopped it. */
|
|
79
|
+
export function isRunOutcome(value) {
|
|
80
|
+
if (!isRecord(value))
|
|
81
|
+
return false;
|
|
82
|
+
if (value.state === "interrupted")
|
|
83
|
+
return (value.ok === false &&
|
|
84
|
+
(value.signal === "SIGINT" || value.signal === "SIGTERM" || value.signal === "SIGHUP") &&
|
|
85
|
+
typeof value.at === "string");
|
|
86
|
+
return (value.state === "finished" &&
|
|
87
|
+
typeof value.ok === "boolean" &&
|
|
88
|
+
isRecord(value.execution) &&
|
|
89
|
+
typeof value.execution.succeeded === "boolean" &&
|
|
90
|
+
isExecutionFailureList(value.execution.failures) &&
|
|
91
|
+
(value.execution.warnings === undefined || isExecutionFailureList(value.execution.warnings)));
|
|
68
92
|
}
|
|
69
93
|
function isRunProviderResource(value) {
|
|
70
94
|
return (isRecord(value) &&
|
|
@@ -73,6 +97,7 @@ function isRunProviderResource(value) {
|
|
|
73
97
|
value.kind === "sandbox" &&
|
|
74
98
|
typeof value.id === "string" &&
|
|
75
99
|
value.id.trim().length > 0 &&
|
|
100
|
+
(value.idDigest === undefined || typeof value.idDigest === "string") &&
|
|
76
101
|
value.owner === "humanish" &&
|
|
77
102
|
(value.status === "running" || value.status === "killed" || value.status === "unknown") &&
|
|
78
103
|
(value.simId === undefined || typeof value.simId === "string") &&
|
package/dist/run/bundle.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { CommsReceivingEvidence } from "../comms/receiving-types.js";
|
|
2
2
|
import { type CapturedGitState } from "./git-state.js";
|
|
3
|
+
import type { ExecutionOutcome } from "./judge.js";
|
|
3
4
|
import type { SharedWorldEvidence } from "./shared-world-evidence.js";
|
|
4
5
|
import { type RunStudyProvenance } from "./study-provenance.js";
|
|
6
|
+
import type { RunInterruptSignal } from "./status.js";
|
|
5
7
|
import type { RunSimulationStatus, RunStream, RunStreamKind } from "./streams.js";
|
|
6
8
|
export declare const RUN_BUNDLE_SCHEMA = "humanish.run-bundle.v1";
|
|
7
9
|
/** The run bundle file, relative to the run directory. */
|
|
@@ -252,6 +254,13 @@ export interface RunBundle {
|
|
|
252
254
|
events: string;
|
|
253
255
|
};
|
|
254
256
|
review: ReviewSummary;
|
|
257
|
+
/**
|
|
258
|
+
* How the run ended as an execution. `review.verdict` is what the participants experienced;
|
|
259
|
+
* this is whether the run worked, which no surface may show as a pass when `ok` is false. Absent
|
|
260
|
+
* while the run is in progress, when its process died without writing it, and on runs recorded
|
|
261
|
+
* before this field, whose status.json holds the outcome instead.
|
|
262
|
+
*/
|
|
263
|
+
outcome?: RunOutcome;
|
|
255
264
|
feedbackCandidates: RunFeedbackCandidate[];
|
|
256
265
|
/** Structured subject provenance. Optional and additive: emitted by the
|
|
257
266
|
* computer-use and shared-world backends and the clone scripted-browser route; tolerated absent
|
|
@@ -347,6 +356,21 @@ export interface RunBundle {
|
|
|
347
356
|
*/
|
|
348
357
|
cost?: RunCostSummary;
|
|
349
358
|
}
|
|
359
|
+
/**
|
|
360
|
+
* How a run ended. `finished`: Run.finish published the final bundle with the route result's `ok`
|
|
361
|
+
* and its execution outcome (`judgeExecution` in src/run/judge.ts). `interrupted`: the CLI's signal
|
|
362
|
+
* handler stopped the run before it finished; run.json is then the last live flush.
|
|
363
|
+
*/
|
|
364
|
+
export type RunOutcome = {
|
|
365
|
+
state: "finished";
|
|
366
|
+
ok: boolean;
|
|
367
|
+
execution: ExecutionOutcome;
|
|
368
|
+
} | {
|
|
369
|
+
state: "interrupted";
|
|
370
|
+
ok: false;
|
|
371
|
+
signal: RunInterruptSignal;
|
|
372
|
+
at: string;
|
|
373
|
+
};
|
|
350
374
|
/**
|
|
351
375
|
* One contributing cost line of a RunCostSummary. A line is present even when it cannot be priced
|
|
352
376
|
* (it records that we tried and could not): an unpriceable line carries estimatedCostUsd: null + a
|
|
@@ -413,7 +437,13 @@ export interface RunProviderResource {
|
|
|
413
437
|
schema: "humanish.provider-resource.v1";
|
|
414
438
|
provider: "e2b-desktop";
|
|
415
439
|
kind: "sandbox";
|
|
440
|
+
/**
|
|
441
|
+
* "[redacted-sandbox-id]" in runs from 0.110 on; earlier runs recorded the raw id here. The raw id
|
|
442
|
+
* is in the run's sandbox-receipts.ndjson.
|
|
443
|
+
*/
|
|
416
444
|
id: string;
|
|
445
|
+
/** The id's digest, which matches its receipt. Absent on runs recorded before 0.110. */
|
|
446
|
+
idDigest?: string;
|
|
417
447
|
owner: "humanish";
|
|
418
448
|
status: "running" | "killed" | "unknown";
|
|
419
449
|
simId?: string;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { RunOutcome } from "./bundle.js";
|
|
2
|
+
import type { ExecutionFailure } from "./judge.js";
|
|
3
|
+
import { type RunLiveness } from "./status.js";
|
|
4
|
+
/** The states a run is shown in. */
|
|
5
|
+
export type RunDisplayState = "running" | "interrupted" | "passed" | "failed" | "blocked" | "timed_out" | "no_verdict" | "dry_run" | "unknown";
|
|
6
|
+
/** A run as a surface shows it. */
|
|
7
|
+
export interface RunDisplay {
|
|
8
|
+
state: RunDisplayState;
|
|
9
|
+
/** The state in words: "passed", "timed out", "no verdict". */
|
|
10
|
+
label: string;
|
|
11
|
+
/** How a surface colors it: `pass` only for `passed`, `fail` only for `failed`. */
|
|
12
|
+
tone: "pass" | "fail" | "warn" | "live" | "neutral";
|
|
13
|
+
/** The first execution failure that failed the run, as `kind: message`. */
|
|
14
|
+
reason?: string;
|
|
15
|
+
}
|
|
16
|
+
/** What runDisplay reads: whether the run is alive, what its participants experienced, and its ok. */
|
|
17
|
+
export interface RunDisplayFacts {
|
|
18
|
+
liveness: RunLiveness;
|
|
19
|
+
mode?: string | null | undefined;
|
|
20
|
+
/** `review.verdict`. */
|
|
21
|
+
verdict?: string | undefined;
|
|
22
|
+
/** The run's own ok from run.json's outcome; absent when the run recorded none. */
|
|
23
|
+
ok?: boolean | undefined;
|
|
24
|
+
/** The first execution failure that failed the run. */
|
|
25
|
+
failure?: ExecutionFailure | undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A run's state. A live or interrupted run is that, whatever its last flush said. A finished run
|
|
29
|
+
* shows its participants' blocked, timed-out or failed verdict; otherwise a run whose ok is false
|
|
30
|
+
* is failed, even with a pass verdict, because its execution failed. Only then does a pass verdict
|
|
31
|
+
* show as passed.
|
|
32
|
+
*/
|
|
33
|
+
export declare function runDisplay(facts: RunDisplayFacts): RunDisplay;
|
|
34
|
+
/** A state in words: "passed", "timed out", "no verdict". */
|
|
35
|
+
export declare function runDisplayLabel(state: RunDisplayState): string;
|
|
36
|
+
/** What bundleDisplayFacts reads from run.json; a listing reads it from an unchecked file. */
|
|
37
|
+
export interface DisplayedBundle {
|
|
38
|
+
runId: string;
|
|
39
|
+
mode?: string | undefined;
|
|
40
|
+
review?: {
|
|
41
|
+
verdict?: string | undefined;
|
|
42
|
+
} | undefined;
|
|
43
|
+
simulations?: ReadonlyArray<{
|
|
44
|
+
status?: string | undefined;
|
|
45
|
+
} | undefined> | undefined;
|
|
46
|
+
outcome?: RunOutcome | undefined;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The facts for a run from its bundle. run.json's `outcome` decides when it has one. A bundle
|
|
50
|
+
* without one is in progress, or was recorded before the field existed: its status record, when
|
|
51
|
+
* given and naming the run, then says whether the run is alive and, for the older run, holds its ok.
|
|
52
|
+
* With no record, a bundle whose simulations are still running is live.
|
|
53
|
+
*/
|
|
54
|
+
export declare function bundleDisplayFacts(bundle: DisplayedBundle, status?: unknown, nowMs?: number): RunDisplayFacts;
|
|
55
|
+
/**
|
|
56
|
+
* How review.md says the run ended: the display of the bundle it is rendered from, so a run whose
|
|
57
|
+
* execution failed never reads as a pass beside its participants' verdict.
|
|
58
|
+
*/
|
|
59
|
+
export declare function reviewOutcome(bundle: DisplayedBundle): string;
|