humanish 0.115.0 → 0.117.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.
Files changed (195) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +7 -6
  3. package/TELEMETRY.md +6 -0
  4. package/dist/actors/codex/app-server-ui.js +11 -4
  5. package/dist/actors/codex/restricted-participant-policy.d.ts +0 -2
  6. package/dist/actors/codex/restricted-participant-policy.js +4 -32
  7. package/dist/actors/codex/restricted-participant.d.ts +5 -0
  8. package/dist/actors/codex/restricted-participant.js +3 -2
  9. package/dist/actors/computer-use/actor.d.ts +4 -0
  10. package/dist/actors/computer-use/actor.js +2 -0
  11. package/dist/actors/computer-use/loop/actions.d.ts +4 -4
  12. package/dist/actors/computer-use/loop/actions.js +25 -18
  13. package/dist/actors/computer-use/loop/debrief.js +61 -27
  14. package/dist/actors/computer-use/loop/session.d.ts +3 -0
  15. package/dist/actors/computer-use/loop/session.js +9 -1
  16. package/dist/actors/computer-use/loop/trace.js +1 -0
  17. package/dist/actors/computer-use/loop/types.d.ts +16 -14
  18. package/dist/actors/computer-use/loop.d.ts +1 -1
  19. package/dist/actors/computer-use/loop.js +1 -1
  20. package/dist/actors/computer-use/wait.d.ts +74 -0
  21. package/dist/actors/computer-use/wait.js +100 -0
  22. package/dist/actors/contract.d.ts +14 -0
  23. package/dist/actors/scripted-browser/steps.js +6 -5
  24. package/dist/analysis/analysis-limits.d.ts +35 -0
  25. package/dist/analysis/analysis-limits.js +41 -0
  26. package/dist/analysis/validation.js +14 -21
  27. package/dist/browser-control/protocol.d.ts +86 -6
  28. package/dist/browser-control/protocol.js +13 -6
  29. package/dist/cli/commands/analyze.js +2 -1
  30. package/dist/cli/commands/notes.js +2 -1
  31. package/dist/cli/commands/run-signals.js +5 -1
  32. package/dist/cli/commands/runs.js +2 -1
  33. package/dist/cli/commands/setup.js +3 -3
  34. package/dist/cli/commands/study-format.d.ts +5 -2
  35. package/dist/cli/commands/study-format.js +29 -9
  36. package/dist/cli/commands/study-route-computer-use.js +2 -2
  37. package/dist/cli/commands/study-route-scripted.js +1 -1
  38. package/dist/cli/commands/tui.js +59 -17
  39. package/dist/cli/doctor.js +9 -2
  40. package/dist/cli/findings-text.d.ts +5 -0
  41. package/dist/cli/findings-text.js +169 -0
  42. package/dist/cli/findings.d.ts +0 -4
  43. package/dist/cli/findings.js +5 -167
  44. package/dist/cli/io.js +6 -1
  45. package/dist/cli/update-check.js +4 -1
  46. package/dist/comms/connections.js +4 -3
  47. package/dist/comms/setup.js +18 -12
  48. package/dist/evidence/redaction.js +9 -1
  49. package/dist/evidence/secret-scrub.d.ts +15 -5
  50. package/dist/evidence/secret-scrub.js +67 -9
  51. package/dist/feedback/draft.js +1 -1
  52. package/dist/feedback/export-bundle.js +18 -14
  53. package/dist/feedback/feedback.js +25 -7
  54. package/dist/guest/desktop-executor.js +3 -1
  55. package/dist/guest/desktop-keys.js +59 -5
  56. package/dist/keys/key-resolution.d.ts +9 -0
  57. package/dist/keys/key-resolution.js +60 -48
  58. package/dist/keys/key-status.d.ts +2 -0
  59. package/dist/keys/key-status.js +9 -16
  60. package/dist/observer/pinned-files.js +1 -1
  61. package/dist/observer/render.js +3 -2
  62. package/dist/observer-app.html +5 -5
  63. package/dist/routes/computer-use/bundle-parts.d.ts +4 -4
  64. package/dist/routes/computer-use/bundle-parts.js +2 -2
  65. package/dist/routes/computer-use/bundle.d.ts +4 -5
  66. package/dist/routes/computer-use/bundle.js +1 -3
  67. package/dist/routes/computer-use/e2b-desktop/prepare.js +40 -31
  68. package/dist/routes/computer-use/fanout-records.js +10 -11
  69. package/dist/routes/computer-use/live-phase.d.ts +1 -1
  70. package/dist/routes/computer-use/live-phase.js +0 -1
  71. package/dist/routes/computer-use/local-vm.js +5 -2
  72. package/dist/routes/computer-use/participant-execution.d.ts +3 -2
  73. package/dist/routes/computer-use/participant-model.js +9 -0
  74. package/dist/routes/computer-use/participant-runs.d.ts +6 -2
  75. package/dist/routes/computer-use/participant-runs.js +9 -5
  76. package/dist/routes/computer-use/plan.d.ts +3 -0
  77. package/dist/routes/computer-use/plan.js +18 -13
  78. package/dist/routes/computer-use/rerun-selection.js +2 -2
  79. package/dist/routes/computer-use/result.js +3 -6
  80. package/dist/routes/computer-use/setup.d.ts +4 -6
  81. package/dist/routes/computer-use/setup.js +2 -6
  82. package/dist/routes/computer-use/single-bundle.d.ts +4 -5
  83. package/dist/routes/computer-use/single-bundle.js +22 -25
  84. package/dist/routes/computer-use/subject-projection.d.ts +4 -8
  85. package/dist/routes/computer-use/subject-projection.js +9 -31
  86. package/dist/routes/computer-use/types.d.ts +5 -42
  87. package/dist/routes/scripted/scenario.js +28 -12
  88. package/dist/routes/scripted/session-result.js +6 -3
  89. package/dist/routes/shared-world/bundle-records.js +2 -8
  90. package/dist/routes/shared-world/participant-specs.d.ts +0 -2
  91. package/dist/routes/shared-world/participant-specs.js +1 -20
  92. package/dist/routes/shared-world/plan.d.ts +3 -0
  93. package/dist/routes/shared-world/plan.js +25 -4
  94. package/dist/routes/shared-world/setup.js +2 -2
  95. package/dist/routes/terminal/ledger.d.ts +9 -9
  96. package/dist/routes/terminal/ledger.js +63 -40
  97. package/dist/routes/terminal/live-finish.js +7 -10
  98. package/dist/routes/terminal/live-sandbox.d.ts +1 -1
  99. package/dist/routes/terminal/live-sandbox.js +14 -11
  100. package/dist/routes/terminal/plan.d.ts +3 -0
  101. package/dist/routes/terminal/plan.js +8 -5
  102. package/dist/routes/terminal/sandbox.d.ts +4 -3
  103. package/dist/routes/terminal/sandbox.js +5 -5
  104. package/dist/routes/terminal/token-usage.d.ts +1 -2
  105. package/dist/routes/terminal/token-usage.js +4 -6
  106. package/dist/routes/terminal/types.d.ts +9 -1
  107. package/dist/run/bundle-shape.js +6 -1
  108. package/dist/run/bundle.d.ts +5 -3
  109. package/dist/run/contained-output.d.ts +53 -5
  110. package/dist/run/contained-output.js +141 -42
  111. package/dist/run/detail.d.ts +2 -1
  112. package/dist/run/detail.js +12 -7
  113. package/dist/run/escape-sequences.d.ts +11 -0
  114. package/dist/run/escape-sequences.js +93 -0
  115. package/dist/run/evidence-files.d.ts +8 -8
  116. package/dist/run/evidence-files.js +19 -23
  117. package/dist/run/locate.d.ts +32 -3
  118. package/dist/run/locate.js +45 -40
  119. package/dist/run/notes.d.ts +0 -8
  120. package/dist/run/notes.js +5 -51
  121. package/dist/run/outcomes.d.ts +24 -0
  122. package/dist/run/outcomes.js +19 -0
  123. package/dist/run/paths.d.ts +2 -0
  124. package/dist/run/paths.js +5 -1
  125. package/dist/run/preflight-receipts.js +13 -8
  126. package/dist/run/project.js +7 -4
  127. package/dist/run/reclaim-outcomes.d.ts +8 -6
  128. package/dist/run/reclaim-outcomes.js +10 -6
  129. package/dist/run/reclaim.d.ts +5 -0
  130. package/dist/run/reclaim.js +43 -16
  131. package/dist/run/run-clock.d.ts +50 -0
  132. package/dist/run/run-clock.js +66 -0
  133. package/dist/run/run.js +5 -2
  134. package/dist/run/sandbox-ids.d.ts +7 -2
  135. package/dist/run/sandbox-ids.js +27 -11
  136. package/dist/run/secrets.d.ts +2 -1
  137. package/dist/run/secrets.js +18 -22
  138. package/dist/run/stored-runs.js +14 -7
  139. package/dist/run/transient-comms-secrets.js +6 -17
  140. package/dist/run-study.js +22 -13
  141. package/dist/study/adapter-scorer-loader.js +6 -4
  142. package/dist/study/config.js +4 -1
  143. package/dist/study/discover.js +9 -6
  144. package/dist/study/init-paths.js +7 -5
  145. package/dist/study/keys.d.ts +2 -0
  146. package/dist/study/keys.js +2 -0
  147. package/dist/study/migrate/v2.js +2 -1
  148. package/dist/study/parse/actors.js +8 -0
  149. package/dist/study/persona-resolve.d.ts +2 -2
  150. package/dist/study/persona-resolve.js +9 -5
  151. package/dist/study/plan-participants.d.ts +4 -0
  152. package/dist/study/plan-participants.js +4 -0
  153. package/dist/study/plan-types.d.ts +2 -2
  154. package/dist/study/plan.d.ts +5 -3
  155. package/dist/study/plan.js +18 -9
  156. package/dist/study/preflight-probes.js +11 -3
  157. package/dist/study/preflight.js +9 -5
  158. package/dist/study/summary.d.ts +8 -2
  159. package/dist/study/summary.js +20 -22
  160. package/dist/study/types.d.ts +14 -0
  161. package/dist/study/validation.d.ts +5 -0
  162. package/dist/study/validation.js +8 -0
  163. package/dist/study/warnings.d.ts +19 -12
  164. package/dist/study/warnings.js +50 -17
  165. package/dist/subject/serve.d.ts +3 -0
  166. package/dist/subject/serve.js +4 -1
  167. package/dist/substrates/detached.js +14 -7
  168. package/dist/substrates/e2b/connection.d.ts +12 -0
  169. package/dist/substrates/e2b/connection.js +35 -0
  170. package/dist/substrates/e2b/desktop-executor.d.ts +1 -5
  171. package/dist/substrates/e2b/desktop-executor.js +45 -12
  172. package/dist/substrates/e2b/lifetime.d.ts +24 -4
  173. package/dist/substrates/e2b/lifetime.js +41 -4
  174. package/dist/substrates/e2b/sandbox.d.ts +4 -3
  175. package/dist/substrates/e2b/sandbox.js +13 -18
  176. package/dist/substrates/e2b/sdk.d.ts +20 -9
  177. package/dist/substrates/local/capacity.d.ts +18 -2
  178. package/dist/substrates/local/capacity.js +21 -2
  179. package/dist/substrates/local/runtime-host.js +21 -14
  180. package/dist/substrates/local/runtime.js +3 -11
  181. package/dist/tui/contract.d.ts +30 -5
  182. package/dist/tui/contract.js +4 -1
  183. package/dist/tui-app.js +150 -147
  184. package/dist/verify/artifacts.d.ts +9 -2
  185. package/dist/verify/artifacts.js +37 -13
  186. package/dist/verify/liveness.js +19 -5
  187. package/dist/verify/verify.js +54 -27
  188. package/docs/architecture/browser-control.md +10 -4
  189. package/docs/architecture/guest-desktop.md +7 -2
  190. package/docs/architecture/state-driven-executor.md +4 -2
  191. package/docs/contracts/run-bundle.md +18 -10
  192. package/docs/contracts/schemas.md +46 -29
  193. package/docs/contracts/study-analysis.md +10 -1
  194. package/docs/product/automatic-analysis.md +7 -1
  195. package/package.json +2 -2
@@ -1,11 +1,11 @@
1
1
  import { type RunProviderResource, type RunSubjectProvenance } from "../../run/bundle.js";
2
2
  import { type ParticipantIds } from "../../run/participant-records.js";
3
- import { type CuaSubjectProvenanceArg, type ParticipantRunOutcome } from "./types.js";
3
+ import { type ParticipantRunOutcome } from "./types.js";
4
4
  /** The human-readable state story appended to the provenance event (and review.md via it). */
5
5
  export declare function describeSubjectState(state: RunSubjectProvenance["state"], dryRun: boolean): string;
6
- /** Human-readable provenance line for the single-participant subject.provenance event:
7
- * claims "cloned/packed and served" only when it actually happened. */
8
- export declare function subjectProvenanceMessage(provenance: CuaSubjectProvenanceArg, publicAppUrl: string, dryRun: boolean, hasSession: boolean): string;
6
+ /** Human-readable provenance line for the single-participant subject.provenance event of a clone
7
+ * or local-tree subject: claims "cloned/packed and served" only when it actually happened. */
8
+ export declare function subjectProvenanceMessage(provenance: RunSubjectProvenance, publicAppUrl: string, dryRun: boolean, hasSession: boolean): string;
9
9
  export declare function providerResourcesForOutcome(args: {
10
10
  outcome: ParticipantRunOutcome | undefined;
11
11
  createdAt: string;
@@ -24,8 +24,8 @@ export function describeSubjectState(state, dryRun) {
24
24
  return "external-public (operator-declared, operator-owned public deployment; neither provisioned nor seeded)";
25
25
  }
26
26
  }
27
- /** Human-readable provenance line for the single-participant subject.provenance event:
28
- * claims "cloned/packed and served" only when it actually happened. */
27
+ /** Human-readable provenance line for the single-participant subject.provenance event of a clone
28
+ * or local-tree subject: claims "cloned/packed and served" only when it actually happened. */
29
29
  export function subjectProvenanceMessage(provenance, publicAppUrl, dryRun, hasSession) {
30
30
  if (provenance.source === "clone") {
31
31
  if (dryRun) {
@@ -1,8 +1,8 @@
1
1
  import type { CuaActorDescriptor } from "../../actors/registry.js";
2
2
  import type { ComputerUsePlan } from "../../study/plan-types.js";
3
- import type { BundleRun, RunBundle, RunRerunLineage } from "../../run/bundle.js";
3
+ import type { BundleRun, RunBundle, RunRerunLineage, RunSubjectProvenance } from "../../run/bundle.js";
4
4
  import { type Judgment } from "../../run/judge.js";
5
- import type { CuaParticipantPlan, DesktopParticipantRun, CuaSubjectProjection, CuaSubjectProvenanceArg, ParticipantRunOutcome } from "./types.js";
5
+ import type { CuaParticipantPlan, DesktopParticipantRun, ParticipantRunOutcome } from "./types.js";
6
6
  /** What every bundle of one run shares, in progress or final. */
7
7
  export interface CuaRunBundleBase {
8
8
  /** The run every bundle of it belongs to. */
@@ -32,9 +32,8 @@ interface CuaRunBundleState {
32
32
  judgment: Judgment;
33
33
  dryRun: boolean;
34
34
  outcomes: ParticipantRunOutcome[] | undefined;
35
- subjects: CuaSubjectProjection[];
36
- aggregateSubject: CuaSubjectProjection;
37
- subjectProvenance: CuaSubjectProvenanceArg | undefined;
35
+ subjects: RunSubjectProvenance[];
36
+ aggregateSubject: RunSubjectProvenance;
38
37
  failFastReason?: string;
39
38
  inProgress?: true;
40
39
  }
@@ -117,9 +117,7 @@ function singleParticipantArgs(base, state) {
117
117
  }),
118
118
  source: base.source,
119
119
  ...(state.inProgress === undefined ? {} : { inProgress: state.inProgress }),
120
- ...(state.subjectProvenance === undefined
121
- ? {}
122
- : { subjectProvenance: state.subjectProvenance }),
120
+ subject: state.aggregateSubject,
123
121
  ...(desktopTemplate === undefined ? {} : { desktopTemplate }),
124
122
  ...(outcome?.desktopBrowser === undefined ? {} : { desktopBrowser: outcome.desktopBrowser }),
125
123
  providerResources: providerResourcesForOutcome({
@@ -5,6 +5,7 @@ import { validatePreparedRunArtifactPaths } from "../../../run/paths.js";
5
5
  import { provisionCloneSubject } from "../../../subject/clone.js";
6
6
  import { provisionDesktopCli } from "../../../subject/desktop-cli.js";
7
7
  import { provisionLocalTreeSubject } from "../../../subject/local-tree.js";
8
+ import { SubjectBuildError } from "../../../subject/serve.js";
8
9
  import { inspectDesktopScreenGeometry } from "../../../substrates/e2b/desktop-geometry.js";
9
10
  import { observeDesktopResources } from "../../../substrates/e2b/desktop-resources.js";
10
11
  import { acquireE2BDesktopSandbox, e2bDesktopTemplate } from "../../../substrates/e2b/sandbox.js";
@@ -166,37 +167,45 @@ export async function provisionParticipantSubject(ctx, state, desktop) {
166
167
  onPhase: ctx.onSubjectPhase,
167
168
  });
168
169
  }
169
- if (subject.kind === "clone") {
170
- state.subjectCommit = await provisionCloneSubject(shell, {
171
- repo: subject.repo,
172
- depth: residual.subject.clone?.depth ?? 1,
173
- serve: subject.serve,
174
- ...(subject.state === undefined ? {} : { state: subject.state }),
175
- hasGithubToken: subject.env.includes("GITHUB_TOKEN"),
176
- requestTimeoutMs: deps.requestTimeoutMs,
177
- scrub: deps.scrubKnownValues,
178
- onCommit: (commit) => {
179
- state.subjectCommit = commit;
180
- },
181
- onStateStep: (record) => {
182
- state.stateStepRecords.push(record);
183
- },
184
- onPhase: ctx.onSubjectPhase,
185
- ...deps.detachedTimers,
186
- });
170
+ try {
171
+ if (subject.kind === "clone") {
172
+ state.subjectCommit = await provisionCloneSubject(shell, {
173
+ repo: subject.repo,
174
+ depth: residual.subject.clone?.depth ?? 1,
175
+ serve: subject.serve,
176
+ ...(subject.state === undefined ? {} : { state: subject.state }),
177
+ hasGithubToken: subject.env.includes("GITHUB_TOKEN"),
178
+ requestTimeoutMs: deps.requestTimeoutMs,
179
+ scrub: deps.scrubKnownValues,
180
+ onCommit: (commit) => {
181
+ state.subjectCommit = commit;
182
+ },
183
+ onStateStep: (record) => {
184
+ state.stateStepRecords.push(record);
185
+ },
186
+ onPhase: ctx.onSubjectPhase,
187
+ ...deps.detachedTimers,
188
+ });
189
+ }
190
+ else if (subject.kind === "local-tree" && deps.localTreeArchiveBuffer) {
191
+ await provisionLocalTreeSubject(shell, {
192
+ archiveBuffer: deps.localTreeArchiveBuffer,
193
+ serve: subject.serve,
194
+ ...(subject.state === undefined ? {} : { state: subject.state }),
195
+ requestTimeoutMs: deps.requestTimeoutMs,
196
+ scrub: deps.scrubKnownValues,
197
+ onStateStep: (record) => {
198
+ state.stateStepRecords.push(record);
199
+ },
200
+ onPhase: ctx.onSubjectPhase,
201
+ ...deps.detachedTimers,
202
+ });
203
+ }
187
204
  }
188
- else if (subject.kind === "local-tree" && deps.localTreeArchiveBuffer) {
189
- await provisionLocalTreeSubject(shell, {
190
- archiveBuffer: deps.localTreeArchiveBuffer,
191
- serve: subject.serve,
192
- ...(subject.state === undefined ? {} : { state: subject.state }),
193
- requestTimeoutMs: deps.requestTimeoutMs,
194
- scrub: deps.scrubKnownValues,
195
- onStateStep: (record) => {
196
- state.stateStepRecords.push(record);
197
- },
198
- onPhase: ctx.onSubjectPhase,
199
- ...deps.detachedTimers,
200
- });
205
+ catch (error) {
206
+ // A failed serve.build gets its own code, so the run names the step the author has to fix.
207
+ if (error instanceof SubjectBuildError)
208
+ state.failureCode = "HUMANISH_COMPUTER_USE_SUBJECT_BUILD_FAILED";
209
+ throw error;
201
210
  }
202
211
  }
@@ -3,7 +3,7 @@
3
3
  import { participantAssignment } from "../../study/participant-assignment.js";
4
4
  import { participantEvent, participantRecord, participantStream, } from "../../run/participant-records.js";
5
5
  import { participantCaption } from "../../run/participant-caption.js";
6
- import { sessionEndingInWords } from "../../run/outcomes.js";
6
+ import { participantSummary } from "../../run/outcomes.js";
7
7
  import { declaredScreenForRender } from "../../substrates/e2b/desktop-geometry.js";
8
8
  import { describeSubjectState, phaseEventIdSuffix, publicSafeAppUrlLabel } from "./bundle-parts.js";
9
9
  import { participantSubjectEnv } from "./types.js";
@@ -60,15 +60,12 @@ function fanoutParticipantRecord(args, spec, index, view) {
60
60
  mode: "browser-sim",
61
61
  progress: args.inProgress === true && outcome === undefined ? 20 : 100,
62
62
  currentStep: reason,
63
- summary: session
64
- ? `${name} used the app and ${sessionEndingInWords(session.trace)}.`
65
- : args.inProgress === true && outcome === undefined
66
- ? `${name} is using the app.`
67
- : outcome?.skippedReason !== undefined
68
- ? `${name} was ${outcome.skippedReason}.`
69
- : outcome?.sessionError !== undefined
70
- ? `${name} did not finish a session: ${outcome.sessionError}`
71
- : `${name} would use ${publicTargetUrl}; no session ran.`,
63
+ summary: participantSummary(name, { name: "the app", target: publicTargetUrl }, {
64
+ trace: session?.trace,
65
+ skippedReason: outcome?.skippedReason,
66
+ sessionError: outcome?.sessionError,
67
+ inProgress: args.inProgress === true && outcome === undefined,
68
+ }),
72
69
  startedAt: args.run.createdAt,
73
70
  updatedAt: args.run.createdAt,
74
71
  });
@@ -208,7 +205,9 @@ function fanoutSubjectEvents(ctx, spec, view) {
208
205
  at: args.run.createdAt,
209
206
  level: "info",
210
207
  type: "cua-lab.subject.declared",
211
- message: `Participant ${spec.planned.id}: subject app declared at ${publicTargetUrl} (loopback inside the participant's own desktop sandbox).`,
208
+ message: subject.source === "desktop-cli"
209
+ ? `Participant ${spec.planned.id}: subject product declared: ${subject.product}, used from a terminal window inside the participant's own desktop sandbox.`
210
+ : `Participant ${spec.planned.id}: subject app declared at ${publicTargetUrl} (loopback inside the participant's own desktop sandbox).`,
212
211
  });
213
212
  }
214
213
  return events;
@@ -31,7 +31,7 @@ export declare function runStudyParticipants(setup: CuaRunSetup, participants: C
31
31
  killed: boolean;
32
32
  streamUrlPresent: boolean;
33
33
  };
34
- subject?: import("./types.js").CuaSubjectProjection;
34
+ subject?: import("../../run/bundle.js").RunSubjectProvenance;
35
35
  plan?: import("./types.js").CuaParticipantPlan;
36
36
  lanes?: import("./types.js").CuaParticipantResult[];
37
37
  laneSummary?: import("./types.js").CuaParticipantSummary;
@@ -37,7 +37,6 @@ export async function runStudyParticipants(setup, participants) {
37
37
  outcomes: undefined,
38
38
  subjects: inProgress.subjects,
39
39
  aggregateSubject: inProgress.aggregateSubject,
40
- subjectProvenance: inProgress.provenance,
41
40
  inProgress: true,
42
41
  });
43
42
  await run.writeSnapshot(inProgressBundle);
@@ -139,10 +139,11 @@ function createLocalParticipantDesktop(context, run, warnings, artifactRoot) {
139
139
  };
140
140
  }
141
141
  /** The Codex account participant, whose unconfirmed cleanup blocks the study's analysis. */
142
- function accountProvider(state) {
142
+ function accountProvider(state, maxWaitMs) {
143
143
  return async ({ executor }) => {
144
144
  const participant = createRestrictedCodexParticipant({
145
145
  speechEnabled: executor.speechEnabled === true,
146
+ ...(maxWaitMs === undefined ? {} : { maxWaitMs }),
146
147
  });
147
148
  state.participants.push(participant);
148
149
  const provider = Object.assign(participant.provider, {
@@ -183,7 +184,9 @@ export function prepareLocalVmRun(options) {
183
184
  };
184
185
  const { config: _config, assets: _assets, signal: _signal, ...runOptions } = options;
185
186
  return {
186
- options: account ? { ...runOptions, createProvider: accountProvider(state) } : runOptions,
187
+ options: account
188
+ ? { ...runOptions, createProvider: accountProvider(state, config.actor?.maxWaitMs) }
189
+ : runOptions,
187
190
  localVm: {
188
191
  desktop: (run, warnings, artifactRoot) => createLocalParticipantDesktop(context, run, warnings, artifactRoot),
189
192
  capacity: () => localRuntimeCapacity(),
@@ -1,5 +1,6 @@
1
1
  import { type PreparedOutputRoot } from "../../run/contained-output.js";
2
- import type { CuaParticipantDeps, CuaParticipantPlan, CuaParticipantResult, DesktopParticipantRun, CuaSubjectProjection, ParticipantRunOutcome } from "./types.js";
2
+ import type { CuaParticipantDeps, CuaParticipantPlan, CuaParticipantResult, DesktopParticipantRun, ParticipantRunOutcome } from "./types.js";
3
+ import type { RunSubjectProvenance } from "../../run/bundle.js";
3
4
  /** Build a participant's writeScreenshot closure: writes under screenshots/<screenshotDir>/ and records
4
5
  * the relative path the trace references (screenshots/<name> at N=1; screenshots/<laneId>/<name>
5
6
  * at N>1). */
@@ -24,7 +25,7 @@ export declare function runCuaParticipants(runs: DesktopParticipantRun[], deps:
24
25
  failFastReason?: string;
25
26
  }>;
26
27
  /** Project one participant outcome (or a dry-run contract spec) into the public CuaParticipantResult. */
27
- export declare function toParticipantResult(spec: DesktopParticipantRun, outcome: ParticipantRunOutcome | undefined, subject: CuaSubjectProjection, dryRun: boolean): CuaParticipantResult;
28
+ export declare function toParticipantResult(spec: DesktopParticipantRun, outcome: ParticipantRunOutcome | undefined, subject: RunSubjectProvenance, dryRun: boolean): CuaParticipantResult;
28
29
  /**
29
30
  * Run every participant of a live run. The in-process route drives its single participant in this
30
31
  * process; one hosted participant runs alone; a fan-out runs at the plan's concurrency and may stop early.
@@ -44,6 +44,9 @@ export async function startParticipantModel(spec, deps, executor) {
44
44
  : { reasoningEffort: spec.planned.limits.reasoningEffort }),
45
45
  ...(brain.declaredModel === undefined ? {} : { model: brain.declaredModel }),
46
46
  ...(executor.speechEnabled === true ? { speechEnabled: true } : {}),
47
+ ...(spec.planned.limits.maxWaitMs === undefined
48
+ ? {}
49
+ : { maxWaitMs: spec.planned.limits.maxWaitMs }),
47
50
  session: { env },
48
51
  });
49
52
  return { provider: codexParticipant.provider, codexParticipant };
@@ -130,6 +133,12 @@ export function participantSessionOptions(spec, deps, ready, provider, writeScre
130
133
  ? {}
131
134
  : { stopWhen: spec.planned.limits.stopWhen }),
132
135
  ...(spec.planned.limits.dwell === undefined ? {} : { dwell: spec.planned.limits.dwell }),
136
+ ...(spec.planned.limits.maxWaitMs === undefined
137
+ ? {}
138
+ : { maxWaitMs: spec.planned.limits.maxWaitMs }),
139
+ ...(spec.planned.limits.idleWaitMs === undefined
140
+ ? {}
141
+ : { idleWaitMs: spec.planned.limits.idleWaitMs }),
133
142
  ...(spec.planned.tasks === undefined ? {} : { tasks: spec.planned.tasks }),
134
143
  // The study budget: this participant notes its own running estimate on the shared
135
144
  // ledger and stops when the run total crosses the cap, independent of the per-participant
@@ -4,14 +4,18 @@ import { type ResolvedPersona } from "../../study/persona.js";
4
4
  import { type RunRerunLineage } from "../../run/bundle.js";
5
5
  import type { PreparedSelectedOutputDirectory } from "../../run/contained-output.js";
6
6
  import { type CuaActorStudyErrorCode, type CuaParticipantPlan, type CuaParticipantPlanEntry, type DesktopParticipantRun, type ParticipantRunsAndPlan } from "./types.js";
7
- export declare function defaultSessionTimeoutMs(config: StudyConfig): number;
7
+ /**
8
+ * The session budget of a study that declares no execution.timeoutMs. On a provisioned route it is
9
+ * what the `ceilingMs` sandbox ceiling leaves after provisioning, seeding and the teardown buffer.
10
+ */
11
+ export declare function defaultSessionTimeoutMs(config: StudyConfig, ceilingMs: number): number;
8
12
  /** Per-participant sandbox deadline (each one owns its own desktop). Mirrors the
9
13
  * single-participant formula verbatim so N=1 stays byte-stable: explicit sandboxTimeoutMs, else session budget + (clone
10
14
  * or local-tree: provision budget + Σ state-step budgets) + the server-side
11
15
  * reclamation buffer. Local-tree shares the clone route's provisioning budget: it swaps a
12
16
  * git clone for an upload+extract, but the shared install/build/state/start/probe pipeline
13
17
  * costs the same wall-clock room either way. */
14
- export declare function resolveParticipantSandboxMs(config: StudyConfig): number;
18
+ export declare function resolveParticipantSandboxMs(config: StudyConfig, ceilingMs: number): number;
15
19
  /**
16
20
  * The in-flight participant bound a study declares. Defaults to the participant count: every
17
21
  * declared participant runs at once, because a throttle nobody asked for silently turns "N actors
@@ -12,18 +12,22 @@ import {} from "../../run/bundle.js";
12
12
  import { participantAssignment } from "../../study/participant-assignment.js";
13
13
  import { resolveCommittedPersonas } from "../../study/persona-resolve.js";
14
14
  import { CUA_FANOUT_STRATEGY, CUA_MAX_CONCURRENCY_ENV, DEFAULT_APP_URL_SESSION_TIMEOUT_MS, MIN_DERIVED_SESSION_TIMEOUT_MS, } from "./types.js";
15
- import { MAX_SANDBOX_MS, SANDBOX_TIMEOUT_BUFFER_MS, SUBJECT_PROVISION_BUDGET_MS, } from "../../substrates/e2b/lifetime.js";
15
+ import { SANDBOX_TIMEOUT_BUFFER_MS, SUBJECT_PROVISION_BUDGET_MS, } from "../../substrates/e2b/lifetime.js";
16
16
  import { readPositiveInt } from "../../study/parse/values.js";
17
17
  import { digestUrl } from "./bundle-parts.js";
18
18
  import { composeParticipantInstructions, DEFAULT_MISSION } from "./participant-prompt.js";
19
19
  import { resolveCuaRerunSelection } from "./rerun-selection.js";
20
20
  import { plural } from "../../run/text.js";
21
- export function defaultSessionTimeoutMs(config) {
21
+ /**
22
+ * The session budget of a study that declares no execution.timeoutMs. On a provisioned route it is
23
+ * what the `ceilingMs` sandbox ceiling leaves after provisioning, seeding and the teardown buffer.
24
+ */
25
+ export function defaultSessionTimeoutMs(config, ceilingMs) {
22
26
  const provisionedRoute = config.subject.source === "clone" || config.subject.source === "local-tree";
23
27
  if (!provisionedRoute)
24
28
  return DEFAULT_APP_URL_SESSION_TIMEOUT_MS;
25
29
  const stateBudgetMs = (config.subject.state?.seed ?? []).reduce((sum, step) => sum + (step.timeoutMs ?? DEFAULT_STATE_STEP_TIMEOUT_MS), 0);
26
- const room = MAX_SANDBOX_MS - SUBJECT_PROVISION_BUDGET_MS - stateBudgetMs - SANDBOX_TIMEOUT_BUFFER_MS;
30
+ const room = ceilingMs - SUBJECT_PROVISION_BUDGET_MS - stateBudgetMs - SANDBOX_TIMEOUT_BUFFER_MS;
27
31
  return Math.max(MIN_DERIVED_SESSION_TIMEOUT_MS, Math.min(DEFAULT_APP_URL_SESSION_TIMEOUT_MS, room));
28
32
  }
29
33
  /** Per-participant sandbox deadline (each one owns its own desktop). Mirrors the
@@ -32,10 +36,10 @@ export function defaultSessionTimeoutMs(config) {
32
36
  * reclamation buffer. Local-tree shares the clone route's provisioning budget: it swaps a
33
37
  * git clone for an upload+extract, but the shared install/build/state/start/probe pipeline
34
38
  * costs the same wall-clock room either way. */
35
- export function resolveParticipantSandboxMs(config) {
39
+ export function resolveParticipantSandboxMs(config, ceilingMs) {
36
40
  if (isLocalBrowserStudy(config))
37
41
  return LOCAL_BROWSER_LIFETIME_MS;
38
- const timeoutMs = config.execution?.timeoutMs ?? defaultSessionTimeoutMs(config);
42
+ const timeoutMs = config.execution?.timeoutMs ?? defaultSessionTimeoutMs(config, ceilingMs);
39
43
  const provisionedRoute = config.subject.source === "clone" || config.subject.source === "local-tree";
40
44
  const stateBudgetMs = provisionedRoute
41
45
  ? (config.subject.state?.seed ?? []).reduce((sum, step) => sum + (step.timeoutMs ?? DEFAULT_STATE_STEP_TIMEOUT_MS), 0)
@@ -1,6 +1,7 @@
1
1
  import { type CuaActorDescriptor } from "../../actors/registry.js";
2
2
  import type { ComputerUsePlan, ComputerUseRunner, RoutePlanResult, RouteRefusal } from "../../study/plan-types.js";
3
3
  import type { StudyConfig, StudySubjectState } from "../../study/types.js";
4
+ import { type SandboxCeiling } from "../../substrates/e2b/lifetime.js";
4
5
  import { type ComputerUseRunInput, type CuaActorStudyErrorCode } from "./types.js";
5
6
  /** The error a computer-use study returns before a run starts. */
6
7
  export interface ComputerUseRefusal extends RouteRefusal<"computer-use", CuaActorStudyErrorCode> {
@@ -45,4 +46,6 @@ export declare function planComputerUseStudy(config: StudyConfig, input: {
45
46
  readonly driving?: CallerDriving;
46
47
  readonly countOverride?: number;
47
48
  readonly rerun?: ComputerUseRunInput["rerun"];
49
+ /** The longest sandbox lifetime the operator's E2B plan allows (sandboxCeiling). */
50
+ readonly sandboxCeiling: SandboxCeiling;
48
51
  }): ComputerUsePlanResult;
@@ -10,11 +10,11 @@ import { subjectStateInvalidReason } from "../../study/parse/subject-state.js";
10
10
  import { brainOf, callerBrainOf, planCaps, desktopRequirements, planBase, provisionedSubject, } from "../../study/plan-base.js";
11
11
  import { computerUseParticipants, declaredTargets } from "../../study/plan-participants.js";
12
12
  import { MAX_COMPUTER_USE_PARTICIPANTS } from "../../study/routing.js";
13
- import { cloneTargetValidationReason, computerUseValidationReason, desktopMediaValidationReason, outputTokenLimitValidationReason, receivingEmailValidationReason, taskProtocolValidationReason, } from "../../study/validation.js";
13
+ import { cloneTargetValidationReason, computerUseValidationReason, desktopMediaValidationReason, outputTokenLimitValidationReason, receivingEmailValidationReason, taskProtocolValidationReason, waitLimitValidationReason, } from "../../study/validation.js";
14
14
  import { desktopCliProductReason } from "../../study/composition-rules.js";
15
15
  import { isLocalBrowserStudy } from "../../substrates/local/runtime-config.js";
16
16
  import { boundedConcurrency, defaultSessionTimeoutMs, resolveParticipantSandboxMs, } from "./participant-runs.js";
17
- import { MAX_SANDBOX_MS } from "../../substrates/e2b/lifetime.js";
17
+ import { ceilingAdvice } from "../../substrates/e2b/lifetime.js";
18
18
  import {} from "./types.js";
19
19
  /** The registered descriptor for a planned actor id; planComputerUseStudy checked the registry. */
20
20
  export function cuaDescriptorOf(actor) {
@@ -74,16 +74,18 @@ const invalid = (message) => ({
74
74
  * is touched. The parser enforces most of these too; the engine repeats them for library callers
75
75
  * that hand it a config directly. The groups run in this order, and each returns its first reason.
76
76
  */
77
- function cuaStudyRejection(config, hasRunSession, driving, subjectRoute) {
77
+ function cuaStudyRejection(config, hasRunSession, driving, subjectRoute, ceilingMs) {
78
78
  return (unsupportedDeclarationReason(config, hasRunSession, driving, subjectRoute) ??
79
79
  subjectStructureReason(config, subjectRoute) ??
80
80
  entryTargetReason(config, subjectRoute) ??
81
81
  driverReason(driving, subjectRoute) ??
82
- rosterShapeReason(config));
82
+ rosterShapeReason(config, ceilingMs));
83
83
  }
84
84
  /** A declaration this route cannot honor, for any subject or with the caller's own driver. */
85
85
  function unsupportedDeclarationReason(config, hasRunSession, driving, { inProcessRoute }) {
86
- const reason = desktopMediaValidationReason(config) || outputTokenLimitValidationReason(config);
86
+ const reason = desktopMediaValidationReason(config) ||
87
+ outputTokenLimitValidationReason(config) ||
88
+ waitLimitValidationReason(config);
87
89
  if (reason)
88
90
  return invalid(reason);
89
91
  if (config.actor?.maxOutputTokens !== undefined &&
@@ -173,7 +175,7 @@ function driverReason(driving, { localAppSubject, inProcessRoute }) {
173
175
  return undefined;
174
176
  }
175
177
  /** The participant roster, then the sandbox deadline its session budget derives. */
176
- function rosterShapeReason(config) {
178
+ function rosterShapeReason(config, ceilingMs) {
177
179
  // Device XOR raw resolution, cap, unique ids,
178
180
  // allowPublicTargets with more than one participant, clone.fanout.
179
181
  const fanoutReason = computerUseValidationReason(config);
@@ -182,13 +184,13 @@ function rosterShapeReason(config) {
182
184
  // The sandbox deadline is derived from the session budget, so a study can ask for a session that
183
185
  // cannot legally be provisioned. Show the arithmetic: the provider's own error names a limit
184
186
  // but not which knob produced it.
185
- const derivedSandboxMs = resolveParticipantSandboxMs(config);
186
- if (derivedSandboxMs <= MAX_SANDBOX_MS)
187
+ const derivedSandboxMs = resolveParticipantSandboxMs(config, ceilingMs);
188
+ if (derivedSandboxMs <= ceilingMs)
187
189
  return undefined;
188
190
  const provisionedRoute = config.subject.source === "clone" || config.subject.source === "local-tree";
189
- const sessionMs = config.execution?.timeoutMs ?? defaultSessionTimeoutMs(config);
191
+ const sessionMs = config.execution?.timeoutMs ?? defaultSessionTimeoutMs(config, ceilingMs);
190
192
  const headroomMs = derivedSandboxMs - sessionMs;
191
- return invalid(`execution.timeoutMs ${Math.round(sessionMs / 60_000)}m derives a ${Math.round(derivedSandboxMs / 60_000)}m sandbox deadline, and a sandbox may not live longer than ${MAX_SANDBOX_MS / 60_000}m. The deadline is the session budget plus ${Math.round(headroomMs / 60_000)}m of provisioning and teardown headroom${provisionedRoute ? " (this route clones, installs, builds and serves the subject before the actor starts)" : ""}. Lower execution.timeoutMs to at most ${Math.round((MAX_SANDBOX_MS - headroomMs) / 60_000)}m, or set execution.desktop.sandboxTimeoutMs explicitly.`);
193
+ return invalid(`execution.timeoutMs ${Math.round(sessionMs / 60_000)}m derives a ${Math.round(derivedSandboxMs / 60_000)}m sandbox deadline, and a sandbox may not live longer than ${ceilingMs / 60_000}m. The deadline is the session budget plus ${Math.round(headroomMs / 60_000)}m of provisioning and teardown headroom${provisionedRoute ? " (this route clones, installs, builds and serves the subject before the actor starts)" : ""}. Lower execution.timeoutMs to at most ${Math.round((ceilingMs - headroomMs) / 60_000)}m, or set execution.desktop.sandboxTimeoutMs explicitly.${ceilingAdvice(derivedSandboxMs)}`);
192
194
  }
193
195
  /** The plan's rerun: the source run and, when given, the participants to rerun. */
194
196
  function rerunPlan({ sourceRunId, participantIds, }) {
@@ -223,7 +225,10 @@ export function planComputerUseStudy(config, input) {
223
225
  if (!descriptor || !isCuaActorDescriptor(descriptor))
224
226
  return refuse("in-scope", "HUMANISH_COMPUTER_USE_ACTOR_UNSUPPORTED", `actor.type "${actorType}" is not a registered computer-use actor.`);
225
227
  const actor = descriptor.id;
226
- const rejection = cuaStudyRejection(config, hasRunSession, driving, declaredSubjectRoute(config, driving));
228
+ const ceiling = input.sandboxCeiling;
229
+ if (!ceiling.ok)
230
+ return refuse("in-scope", "HUMANISH_COMPUTER_USE_SUBJECT_INVALID", ceiling.message, actor);
231
+ const rejection = cuaStudyRejection(config, hasRunSession, driving, declaredSubjectRoute(config, driving), ceiling.ms);
227
232
  if (rejection)
228
233
  return refuse("in-scope", rejection.code, rejection.message, actor);
229
234
  // A shared world runs every participant against one app; this route would run them as separate
@@ -288,8 +293,8 @@ export function planComputerUseStudy(config, input) {
288
293
  actor,
289
294
  runner,
290
295
  concurrency: boundedConcurrency(declared, n),
291
- sessionBudgetMs: config.execution?.timeoutMs ?? defaultSessionTimeoutMs(config),
292
- sandboxMs: resolveParticipantSandboxMs(config),
296
+ sessionBudgetMs: config.execution?.timeoutMs ?? defaultSessionTimeoutMs(config, ceiling.ms),
297
+ sandboxMs: resolveParticipantSandboxMs(config, ceiling.ms),
293
298
  caps: planCaps(config),
294
299
  ...(input.rerun === undefined ? {} : { rerun: rerunPlan(input.rerun) }),
295
300
  requirements: base.dryRun || runner.desktop === "in-process"
@@ -2,10 +2,10 @@
2
2
  // participants that failed, blocked, timed out or finished hollow are picked unless ids are given.
3
3
  import {} from "../../run/bundle.js";
4
4
  import { loadRunBundle } from "../../run/locate.js";
5
+ import { resolveLatestRunPointer } from "../../run/paths.js";
5
6
  import {} from "../../run/streams.js";
6
7
  import { plural } from "../../run/text.js";
7
8
  import { access } from "node:fs/promises";
8
- import path from "node:path";
9
9
  import { cli } from "../../cli/invocation.js";
10
10
  export async function resolveCuaRerunSelection(args) {
11
11
  const { studyId, sourceRunId } = args;
@@ -16,7 +16,7 @@ export async function resolveCuaRerunSelection(args) {
16
16
  const source = await loadRunBundle(args.cwd, sourceRunId);
17
17
  if (!source) {
18
18
  const noRuns = sourceRunId === "latest" &&
19
- !(await access(path.join(args.cwd, ".humanish", "runs", "latest.json")).then(() => true, () => false));
19
+ !(await access(resolveLatestRunPointer(args.cwd)).then(() => true, () => false));
20
20
  return refuse(noRuns
21
21
  ? "--rerun-failed-from latest found no run: this project has no runs yet, and a rerun repeats the failed participants of an earlier live run."
22
22
  : `--rerun-failed-from ${sourceRunId} names no run humanish can read in this project. ${cli("runs")} lists its runs.`);
@@ -7,8 +7,8 @@ import { participantCapWarning } from "./participant-model.js";
7
7
  import { summarizeCuaDiagnostics } from "./diagnostics.js";
8
8
  import { toParticipantResult } from "./participant-execution.js";
9
9
  import { buildCuaRunBundle, judgeComputerUseRun } from "./bundle.js";
10
- import { aggregateCuaSubject, projectParticipantSubjects, subjectProvenanceArg, } from "./subject-projection.js";
11
- import { CUA_FANOUT_STRATEGY, participantSubjectEnv, } from "./types.js";
10
+ import { aggregateCuaSubject, projectParticipantSubjects } from "./subject-projection.js";
11
+ import { CUA_FANOUT_STRATEGY, } from "./types.js";
12
12
  import { plannedAppUrl } from "./plan.js";
13
13
  import { studyResultIdentity } from "../../run/study-result.js";
14
14
  import { plural } from "../../run/text.js";
@@ -157,10 +157,9 @@ function cuaStudyResult(args) {
157
157
  export async function finishCuaRun(setup, finish, ran) {
158
158
  const { plan, input, cwd, streams, descriptor, run } = setup;
159
159
  const { participantRuns, participantPlan, bundleBase } = setup;
160
- const { rerunLineage, publicRepo, subjectArgs } = finish;
160
+ const { rerunLineage, subjectArgs } = finish;
161
161
  const { dryRun } = plan;
162
162
  const appUrl = plannedAppUrl(plan.runner.subject);
163
- const subjectEnvNames = [...participantSubjectEnv(plan.runner.subject)];
164
163
  const { runId } = run;
165
164
  const participantCount = participantRuns.length;
166
165
  const { outcomes, failFastReason, receiving, receivingWarnings, externalCommsWarnings } = ran;
@@ -174,7 +173,6 @@ export async function finishCuaRun(setup, finish, ran) {
174
173
  ...(capWarning === undefined ? [] : [capWarning]),
175
174
  ...aggregate.warnings,
176
175
  ];
177
- const finalProvenance = subjectProvenanceArg(aggregateSubject, publicRepo, subjectEnvNames);
178
176
  // One judgment for the whole run: the bundle's verdict and the result's ok both read it.
179
177
  const judgment = judgeComputerUseRun(bundleBase, { dryRun, outcomes });
180
178
  const bundle = buildCuaRunBundle(bundleBase, {
@@ -183,7 +181,6 @@ export async function finishCuaRun(setup, finish, ran) {
183
181
  outcomes,
184
182
  subjects,
185
183
  aggregateSubject,
186
- subjectProvenance: finalProvenance,
187
184
  ...(failFastReason === undefined ? {} : { failFastReason }),
188
185
  });
189
186
  const adapterWarnings = [];
@@ -3,14 +3,14 @@ import type { RefusedStudy } from "../../run/route-shell.js";
3
3
  import { RunSecrets } from "../../run/secrets.js";
4
4
  import type { CuaActorDescriptor } from "../../actors/registry.js";
5
5
  import type { StudyCommsEmail, StudyCommsExternal, StudyConfig } from "../../study/types.js";
6
- import { type RunRerunLineage } from "../../run/bundle.js";
6
+ import { type RunRerunLineage, type RunSubjectProvenance } from "../../run/bundle.js";
7
7
  import { type LocalTreeArchive } from "../../subject/local-tree-archive.js";
8
8
  import { type ComputerUseRefusal } from "./plan.js";
9
9
  import type { ComputerUsePlan } from "../../study/plan-types.js";
10
10
  import { trackRuntimeStreams, type LiveTraceFlush } from "./live-flush.js";
11
11
  import { type CuaRunBundleBase } from "./bundle.js";
12
12
  import { projectParticipantSubjects } from "./subject-projection.js";
13
- import { type CuaActorStudyErrorCode, type CuaActorStudyResult, type CuaParticipantDeps, type CuaParticipantPlan, type DesktopParticipantRun, type CuaSubjectProjection, type CuaSubjectProvenanceArg, type ComputerUseRunInput } from "./types.js";
13
+ import { type CuaActorStudyErrorCode, type CuaActorStudyResult, type CuaParticipantDeps, type CuaParticipantPlan, type DesktopParticipantRun, type ComputerUseRunInput } from "./types.js";
14
14
  /**
15
15
  * The envelope of a refusal the plan left for after the cwd checks. The participant cap and
16
16
  * in-process fan-out refusals come after the committed personas are read, so a persona-file error still wins.
@@ -51,9 +51,8 @@ export interface CuaParticipantsSetup {
51
51
  } | undefined;
52
52
  /** The subjects of the in-progress bundle, written before any participant starts. */
53
53
  inProgress: {
54
- subjects: CuaSubjectProjection[];
55
- aggregateSubject: CuaSubjectProjection;
56
- provenance: CuaSubjectProvenanceArg | undefined;
54
+ subjects: RunSubjectProvenance[];
55
+ aggregateSubject: RunSubjectProvenance;
57
56
  };
58
57
  /** The refusal envelope, for a run that stops before its bundle. */
59
58
  fail: (code: CuaActorStudyErrorCode, message: string, actorLabel?: string) => CuaActorStudyResult;
@@ -61,7 +60,6 @@ export interface CuaParticipantsSetup {
61
60
  /** What only finishCuaRun reads besides the participants' outcomes. */
62
61
  export interface CuaFinishFacts {
63
62
  rerunLineage: RunRerunLineage | undefined;
64
- publicRepo: string | undefined;
65
63
  subjectArgs: Omit<Parameters<typeof projectParticipantSubjects>[0], "outcomes" | "dryRun">;
66
64
  }
67
65
  type PreparedCuaRun = {
@@ -20,7 +20,7 @@ import { phaseEvent, planEvent } from "../../study/run-study-events.js";
20
20
  import { defaultSubjectPhaseSink } from "../../subject/steps.js";
21
21
  import {} from "./bundle.js";
22
22
  import { packRunLocalTree } from "./local-tree-pack.js";
23
- import { projectParticipantSubjects, subjectProvenanceArg } from "./subject-projection.js";
23
+ import { projectParticipantSubjects } from "./subject-projection.js";
24
24
  import { participantSubjectEnv, } from "./types.js";
25
25
  import { capacityShortfall } from "../../substrates/local/capacity.js";
26
26
  import { studyPersonaIds } from "../../study/persona-resolve.js";
@@ -248,9 +248,6 @@ export async function startCuaRun(plan, input, admitted, scope) {
248
248
  dryRun: false,
249
249
  });
250
250
  const inProgressAggregateSubject = inProgressSubjects[0];
251
- const inProgressProvenance = subjectProvenanceArg(inProgressAggregateSubject, publicRepo, [
252
- ...participantSubjectEnv(plan.runner.subject),
253
- ]);
254
251
  const bundleBase = {
255
252
  run,
256
253
  participantRuns,
@@ -287,11 +284,10 @@ export async function startCuaRun(plan, input, admitted, scope) {
287
284
  inProgress: {
288
285
  subjects: inProgressSubjects,
289
286
  aggregateSubject: inProgressAggregateSubject,
290
- provenance: inProgressProvenance,
291
287
  },
292
288
  fail: admitted.fail,
293
289
  },
294
- finish: { rerunLineage: admitted.rerunLineage, publicRepo, subjectArgs },
290
+ finish: { rerunLineage: admitted.rerunLineage, subjectArgs },
295
291
  };
296
292
  }
297
293
  /** The participant deps every participant reads, with computer use's own overrides. */
@@ -3,11 +3,10 @@ import type { SubjectPhaseEvent } from "../../subject/steps.js";
3
3
  import type { DesktopBrowserEvidence } from "../../substrates/e2b/desktop-browser.js";
4
4
  import type { ActorPersonaRef } from "../../actors/contract.js";
5
5
  import type { CuaLoopResult } from "../../actors/computer-use/loop.js";
6
- import { type BundleRun, type RunBundle, type RunFeedbackCandidate, type RunProviderResource } from "../../run/bundle.js";
6
+ import { type BundleRun, type RunBundle, type RunFeedbackCandidate, type RunProviderResource, type RunSubjectProvenance } from "../../run/bundle.js";
7
7
  import { type RunDesktopGeometry, type RunStream } from "../../run/streams.js";
8
8
  import { type Verdict } from "../../run/judge.js";
9
9
  import { type DesktopUsage } from "../../run/cost-summary.js";
10
- import type { CuaSubjectProvenanceArg } from "./types.js";
11
10
  /**
12
11
  * The bundle of a single-participant run: one participant and no rerun. buildCuaRunBundle
13
12
  * (bundle.ts) maps the run's base and state into these arguments.
@@ -70,9 +69,9 @@ export declare function buildSingleParticipantBundle(args: {
70
69
  reportedFriction: boolean;
71
70
  };
72
71
  source: RunBundle["source"];
73
- /** Provisioned-route provenance (clone or local-tree): what the actor actually drove (names
74
- * + digests only, never values or command text), including the subject's state story. */
75
- subjectProvenance?: CuaSubjectProvenanceArg;
72
+ /** The subject as subject-projection.ts projects it (names and digests only, never values or
73
+ * command text): run.json records it as `subject`, and the subject event describes it. */
74
+ subject: RunSubjectProvenance;
76
75
  /**
77
76
  * Entry kind for the non-clone subject.declared event, which declares what the subject
78
77
  * was. "local-app": an already-running local dev server driven in-process, un-pinnable, and