humanish 0.115.0 → 0.116.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 (154) hide show
  1. package/CHANGELOG.md +22 -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/computer-use/loop/debrief.js +61 -27
  6. package/dist/actors/scripted-browser/steps.js +6 -5
  7. package/dist/analysis/analysis-limits.d.ts +35 -0
  8. package/dist/analysis/analysis-limits.js +41 -0
  9. package/dist/analysis/validation.js +14 -21
  10. package/dist/cli/commands/analyze.js +2 -1
  11. package/dist/cli/commands/notes.js +2 -1
  12. package/dist/cli/commands/run-signals.js +5 -1
  13. package/dist/cli/commands/runs.js +2 -1
  14. package/dist/cli/commands/setup.js +3 -3
  15. package/dist/cli/commands/study-format.d.ts +5 -2
  16. package/dist/cli/commands/study-format.js +29 -9
  17. package/dist/cli/commands/study-route-computer-use.js +2 -2
  18. package/dist/cli/commands/study-route-scripted.js +1 -1
  19. package/dist/cli/commands/tui.js +59 -17
  20. package/dist/cli/doctor.js +9 -2
  21. package/dist/cli/findings-text.d.ts +5 -0
  22. package/dist/cli/findings-text.js +169 -0
  23. package/dist/cli/findings.d.ts +0 -4
  24. package/dist/cli/findings.js +5 -167
  25. package/dist/cli/io.js +6 -1
  26. package/dist/cli/update-check.js +4 -1
  27. package/dist/comms/connections.js +4 -3
  28. package/dist/comms/setup.js +18 -12
  29. package/dist/evidence/redaction.js +9 -1
  30. package/dist/evidence/secret-scrub.d.ts +15 -5
  31. package/dist/evidence/secret-scrub.js +67 -9
  32. package/dist/feedback/draft.js +1 -1
  33. package/dist/feedback/export-bundle.js +18 -14
  34. package/dist/feedback/feedback.js +25 -7
  35. package/dist/guest/desktop-keys.js +59 -5
  36. package/dist/keys/key-resolution.d.ts +9 -0
  37. package/dist/keys/key-resolution.js +60 -48
  38. package/dist/keys/key-status.d.ts +2 -0
  39. package/dist/keys/key-status.js +9 -16
  40. package/dist/observer/pinned-files.js +1 -1
  41. package/dist/observer/render.js +3 -2
  42. package/dist/observer-app.html +7 -7
  43. package/dist/routes/computer-use/bundle-parts.d.ts +4 -4
  44. package/dist/routes/computer-use/bundle-parts.js +2 -2
  45. package/dist/routes/computer-use/bundle.d.ts +4 -5
  46. package/dist/routes/computer-use/bundle.js +1 -3
  47. package/dist/routes/computer-use/fanout-records.js +10 -11
  48. package/dist/routes/computer-use/live-phase.d.ts +1 -1
  49. package/dist/routes/computer-use/live-phase.js +0 -1
  50. package/dist/routes/computer-use/participant-execution.d.ts +3 -2
  51. package/dist/routes/computer-use/participant-runs.d.ts +6 -2
  52. package/dist/routes/computer-use/participant-runs.js +9 -5
  53. package/dist/routes/computer-use/plan.d.ts +3 -0
  54. package/dist/routes/computer-use/plan.js +14 -11
  55. package/dist/routes/computer-use/rerun-selection.js +2 -2
  56. package/dist/routes/computer-use/result.js +3 -6
  57. package/dist/routes/computer-use/setup.d.ts +4 -6
  58. package/dist/routes/computer-use/setup.js +2 -6
  59. package/dist/routes/computer-use/single-bundle.d.ts +4 -5
  60. package/dist/routes/computer-use/single-bundle.js +22 -25
  61. package/dist/routes/computer-use/subject-projection.d.ts +4 -8
  62. package/dist/routes/computer-use/subject-projection.js +9 -31
  63. package/dist/routes/computer-use/types.d.ts +4 -41
  64. package/dist/routes/scripted/scenario.js +28 -12
  65. package/dist/routes/scripted/session-result.js +6 -3
  66. package/dist/routes/shared-world/bundle-records.js +2 -8
  67. package/dist/routes/shared-world/participant-specs.d.ts +0 -2
  68. package/dist/routes/shared-world/participant-specs.js +1 -20
  69. package/dist/routes/shared-world/plan.d.ts +3 -0
  70. package/dist/routes/shared-world/plan.js +23 -3
  71. package/dist/routes/shared-world/setup.js +2 -2
  72. package/dist/routes/terminal/ledger.d.ts +9 -9
  73. package/dist/routes/terminal/ledger.js +63 -40
  74. package/dist/routes/terminal/live-finish.js +7 -10
  75. package/dist/routes/terminal/plan.d.ts +3 -0
  76. package/dist/routes/terminal/plan.js +8 -5
  77. package/dist/routes/terminal/token-usage.d.ts +1 -2
  78. package/dist/routes/terminal/token-usage.js +4 -6
  79. package/dist/routes/terminal/types.d.ts +9 -1
  80. package/dist/run/bundle-shape.js +6 -1
  81. package/dist/run/bundle.d.ts +5 -3
  82. package/dist/run/contained-output.d.ts +53 -5
  83. package/dist/run/contained-output.js +141 -42
  84. package/dist/run/detail.d.ts +2 -1
  85. package/dist/run/detail.js +12 -7
  86. package/dist/run/escape-sequences.d.ts +11 -0
  87. package/dist/run/escape-sequences.js +93 -0
  88. package/dist/run/evidence-files.d.ts +8 -8
  89. package/dist/run/evidence-files.js +19 -23
  90. package/dist/run/locate.d.ts +32 -3
  91. package/dist/run/locate.js +45 -40
  92. package/dist/run/notes.d.ts +0 -8
  93. package/dist/run/notes.js +5 -51
  94. package/dist/run/outcomes.d.ts +24 -0
  95. package/dist/run/outcomes.js +19 -0
  96. package/dist/run/paths.d.ts +2 -0
  97. package/dist/run/paths.js +5 -1
  98. package/dist/run/preflight-receipts.js +13 -8
  99. package/dist/run/project.js +7 -4
  100. package/dist/run/reclaim-outcomes.d.ts +8 -6
  101. package/dist/run/reclaim-outcomes.js +10 -6
  102. package/dist/run/reclaim.d.ts +5 -0
  103. package/dist/run/reclaim.js +43 -16
  104. package/dist/run/run-clock.d.ts +50 -0
  105. package/dist/run/run-clock.js +66 -0
  106. package/dist/run/run.js +5 -2
  107. package/dist/run/sandbox-ids.d.ts +7 -2
  108. package/dist/run/sandbox-ids.js +27 -11
  109. package/dist/run/secrets.d.ts +2 -1
  110. package/dist/run/secrets.js +18 -22
  111. package/dist/run/stored-runs.js +14 -7
  112. package/dist/run/transient-comms-secrets.js +6 -17
  113. package/dist/run-study.js +22 -13
  114. package/dist/study/adapter-scorer-loader.js +6 -4
  115. package/dist/study/discover.js +9 -6
  116. package/dist/study/init-paths.js +7 -5
  117. package/dist/study/persona-resolve.d.ts +2 -2
  118. package/dist/study/persona-resolve.js +9 -5
  119. package/dist/study/plan-types.d.ts +2 -2
  120. package/dist/study/plan.d.ts +5 -3
  121. package/dist/study/plan.js +18 -9
  122. package/dist/study/preflight-probes.js +11 -3
  123. package/dist/study/preflight.js +9 -5
  124. package/dist/study/summary.d.ts +8 -2
  125. package/dist/study/summary.js +20 -22
  126. package/dist/study/warnings.d.ts +19 -12
  127. package/dist/study/warnings.js +38 -17
  128. package/dist/substrates/e2b/connection.d.ts +12 -0
  129. package/dist/substrates/e2b/connection.js +35 -0
  130. package/dist/substrates/e2b/desktop-executor.d.ts +1 -3
  131. package/dist/substrates/e2b/desktop-executor.js +42 -9
  132. package/dist/substrates/e2b/lifetime.d.ts +24 -4
  133. package/dist/substrates/e2b/lifetime.js +41 -4
  134. package/dist/substrates/e2b/sandbox.d.ts +4 -3
  135. package/dist/substrates/e2b/sandbox.js +13 -18
  136. package/dist/substrates/e2b/sdk.d.ts +20 -9
  137. package/dist/substrates/local/capacity.d.ts +18 -2
  138. package/dist/substrates/local/capacity.js +21 -2
  139. package/dist/substrates/local/runtime-host.js +21 -14
  140. package/dist/substrates/local/runtime.js +3 -11
  141. package/dist/tui/contract.d.ts +30 -5
  142. package/dist/tui/contract.js +4 -1
  143. package/dist/tui-app.js +149 -147
  144. package/dist/verify/artifacts.d.ts +9 -2
  145. package/dist/verify/artifacts.js +37 -13
  146. package/dist/verify/liveness.js +19 -5
  147. package/dist/verify/verify.js +54 -27
  148. package/docs/architecture/guest-desktop.md +7 -2
  149. package/docs/architecture/state-driven-executor.md +4 -2
  150. package/docs/contracts/run-bundle.md +18 -10
  151. package/docs/contracts/schemas.md +27 -18
  152. package/docs/contracts/study-analysis.md +10 -1
  153. package/docs/product/automatic-analysis.md +7 -1
  154. 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({
@@ -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);
@@ -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.
@@ -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;
@@ -14,7 +14,7 @@ import { cloneTargetValidationReason, computerUseValidationReason, desktopMediaV
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,12 +74,12 @@ 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 }) {
@@ -173,7 +173,7 @@ function driverReason(driving, { localAppSubject, inProcessRoute }) {
173
173
  return undefined;
174
174
  }
175
175
  /** The participant roster, then the sandbox deadline its session budget derives. */
176
- function rosterShapeReason(config) {
176
+ function rosterShapeReason(config, ceilingMs) {
177
177
  // Device XOR raw resolution, cap, unique ids,
178
178
  // allowPublicTargets with more than one participant, clone.fanout.
179
179
  const fanoutReason = computerUseValidationReason(config);
@@ -182,13 +182,13 @@ function rosterShapeReason(config) {
182
182
  // The sandbox deadline is derived from the session budget, so a study can ask for a session that
183
183
  // cannot legally be provisioned. Show the arithmetic: the provider's own error names a limit
184
184
  // but not which knob produced it.
185
- const derivedSandboxMs = resolveParticipantSandboxMs(config);
186
- if (derivedSandboxMs <= MAX_SANDBOX_MS)
185
+ const derivedSandboxMs = resolveParticipantSandboxMs(config, ceilingMs);
186
+ if (derivedSandboxMs <= ceilingMs)
187
187
  return undefined;
188
188
  const provisionedRoute = config.subject.source === "clone" || config.subject.source === "local-tree";
189
- const sessionMs = config.execution?.timeoutMs ?? defaultSessionTimeoutMs(config);
189
+ const sessionMs = config.execution?.timeoutMs ?? defaultSessionTimeoutMs(config, ceilingMs);
190
190
  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.`);
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 ${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
192
  }
193
193
  /** The plan's rerun: the source run and, when given, the participants to rerun. */
194
194
  function rerunPlan({ sourceRunId, participantIds, }) {
@@ -223,7 +223,10 @@ export function planComputerUseStudy(config, input) {
223
223
  if (!descriptor || !isCuaActorDescriptor(descriptor))
224
224
  return refuse("in-scope", "HUMANISH_COMPUTER_USE_ACTOR_UNSUPPORTED", `actor.type "${actorType}" is not a registered computer-use actor.`);
225
225
  const actor = descriptor.id;
226
- const rejection = cuaStudyRejection(config, hasRunSession, driving, declaredSubjectRoute(config, driving));
226
+ const ceiling = input.sandboxCeiling;
227
+ if (!ceiling.ok)
228
+ return refuse("in-scope", "HUMANISH_COMPUTER_USE_SUBJECT_INVALID", ceiling.message, actor);
229
+ const rejection = cuaStudyRejection(config, hasRunSession, driving, declaredSubjectRoute(config, driving), ceiling.ms);
227
230
  if (rejection)
228
231
  return refuse("in-scope", rejection.code, rejection.message, actor);
229
232
  // A shared world runs every participant against one app; this route would run them as separate
@@ -288,8 +291,8 @@ export function planComputerUseStudy(config, input) {
288
291
  actor,
289
292
  runner,
290
293
  concurrency: boundedConcurrency(declared, n),
291
- sessionBudgetMs: config.execution?.timeoutMs ?? defaultSessionTimeoutMs(config),
292
- sandboxMs: resolveParticipantSandboxMs(config),
294
+ sessionBudgetMs: config.execution?.timeoutMs ?? defaultSessionTimeoutMs(config, ceiling.ms),
295
+ sandboxMs: resolveParticipantSandboxMs(config, ceiling.ms),
293
296
  caps: planCaps(config),
294
297
  ...(input.rerun === undefined ? {} : { rerun: rerunPlan(input.rerun) }),
295
298
  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
@@ -2,7 +2,7 @@ import { participantAssignment } from "../../study/participant-assignment.js";
2
2
  import { redactText } from "../../evidence/redaction.js";
3
3
  import { REVIEW_SCHEMA, bundleArtifacts, bundleHead, } from "../../run/bundle.js";
4
4
  import {} from "../../run/streams.js";
5
- import { aggregateTaskFunnels, formatParticipantOutcomes, formatRunTaskFunnel, sessionEndingInWords, withCuaReviewProvenance, } from "../../run/outcomes.js";
5
+ import { aggregateTaskFunnels, formatParticipantOutcomes, formatRunTaskFunnel, participantSummary, withCuaReviewProvenance, } from "../../run/outcomes.js";
6
6
  import { participantCaption } from "../../run/participant-caption.js";
7
7
  import { actorEnding } from "../../actors/stop-cause.js";
8
8
  import { describeSubjectState, phaseEventIdSuffix, publicSafeAppUrlLabel, subjectProvenanceMessage, } from "./bundle-parts.js";
@@ -103,13 +103,11 @@ function singleSimulation(args, view) {
103
103
  mode: "browser-sim",
104
104
  progress: args.inProgress === true ? 20 : 100,
105
105
  currentStep: reason,
106
- summary: args.session
107
- ? `${name} used the app ${browserPlace(args)}, and ${sessionEndingInWords(args.session.trace)}.`
108
- : args.inProgress === true
109
- ? `${name} is using the app ${browserPlace(args)}.`
110
- : args.sessionError !== undefined
111
- ? `${name} did not finish a session: ${args.sessionError}`
112
- : `${name} would use ${publicAppUrl}; no session ran.`,
106
+ summary: participantSummary(name, { name: "the app", place: browserPlace(args), target: publicAppUrl }, {
107
+ trace: args.session?.trace,
108
+ sessionError: args.sessionError,
109
+ inProgress: args.inProgress === true,
110
+ }),
113
111
  startedAt: args.run.createdAt,
114
112
  updatedAt: args.run.createdAt,
115
113
  });
@@ -183,6 +181,7 @@ function singleStream(args, view) {
183
181
  }
184
182
  function singleEvents(args, view) {
185
183
  const { publicAppUrl, desktopGeometry } = view;
184
+ const { subject } = args;
186
185
  const events = [
187
186
  {
188
187
  id: "event-000-created",
@@ -191,30 +190,32 @@ function singleEvents(args, view) {
191
190
  type: "cua-lab.run.created",
192
191
  message: `Created a computer-use run for ${args.studyId} (actor ${args.actorId}).`,
193
192
  },
194
- args.subjectProvenance
193
+ subject.source === "clone" || subject.source === "local-tree"
195
194
  ? participantEvent(SINGLE, {
196
195
  id: "event-001-subject",
197
196
  at: args.run.createdAt,
198
197
  level: "info",
199
198
  type: "cua-lab.subject.provenance",
200
199
  // Claim "cloned/packed and served" only when it actually happened.
201
- message: `${subjectProvenanceMessage(args.subjectProvenance, publicAppUrl, args.dryRun, args.session !== undefined)} (subject env names: ${args.subjectProvenance.envNames.length > 0 ? args.subjectProvenance.envNames.join(", ") : "none"}; values never persisted); state: ${describeSubjectState(args.subjectProvenance.state, args.dryRun)}.`,
200
+ message: `${subjectProvenanceMessage(subject, publicAppUrl, args.dryRun, args.session !== undefined)} (subject env names: ${subject.envNames !== undefined && subject.envNames.length > 0 ? subject.envNames.join(", ") : "none"}; values never persisted); state: ${describeSubjectState(subject.state, args.dryRun)}.`,
202
201
  })
203
202
  : participantEvent(SINGLE, {
204
203
  id: "event-001-subject",
205
204
  at: args.run.createdAt,
206
205
  level: "info",
207
206
  type: "cua-lab.subject.declared",
208
- // Declare what the subject was, including the absence of a pin. A
209
- // local-app / in-process subject is an already-running local dev server the caller
210
- // provisioned; it cannot be commit-pinned, so its provenance is unpinned and
211
- // no E2B desktop was created. A plain app-url entry runs inside the desktop sandbox, or,
212
- // on the local VM, reaches the host's loopback from the VM's browser.
213
- message: args.entryKind === "local-app"
214
- ? `Subject app declared at ${publicAppUrl}: a running local dev server driven in this process, with no clone and no E2B desktop. Provenance: provided by the caller and unpinned, because a running dev server has no commit to pin.`
215
- : runnerSubstrate(args) === "local-desktop"
216
- ? `Subject app declared at ${publicAppUrl} (the host's loopback, opened from a browser on a local VM).`
217
- : `Subject app declared at ${publicAppUrl} (loopback inside the desktop sandbox).`,
207
+ // Declare what the subject was, including the absence of a pin. A desktop-cli product
208
+ // is named, since it has no URL. A local-app / in-process subject is an already-running
209
+ // local dev server the caller provisioned; it cannot be commit-pinned, so its provenance
210
+ // is unpinned and no E2B desktop was created. A plain app-url entry runs inside the
211
+ // desktop sandbox, or, on the local VM, reaches the host's loopback from the VM's browser.
212
+ message: subject.source === "desktop-cli"
213
+ ? `Subject product declared: ${subject.product}, used from a terminal window inside the desktop sandbox.`
214
+ : args.entryKind === "local-app"
215
+ ? `Subject app declared at ${publicAppUrl}: a running local dev server driven in this process, with no clone and no E2B desktop. Provenance: provided by the caller and unpinned, because a running dev server has no commit to pin.`
216
+ : runnerSubstrate(args) === "local-desktop"
217
+ ? `Subject app declared at ${publicAppUrl} (the host's loopback, opened from a browser on a local VM).`
218
+ : `Subject app declared at ${publicAppUrl} (loopback inside the desktop sandbox).`,
218
219
  }),
219
220
  args.session
220
221
  ? participantEvent(SINGLE, {
@@ -428,11 +429,7 @@ export function buildSingleParticipantBundle(args) {
428
429
  ...(args.providerResources === undefined || args.providerResources.length === 0
429
430
  ? {}
430
431
  : { providerResources: args.providerResources }),
431
- // Structured subject provenance: code pin + state story. Uniform, and
432
- // stated on app-url bundles too: the caller minted the URL, its state is the caller's.
433
- // CuaSubjectProvenanceArg's two variants (clone, local-tree) are already RunSubjectProvenance-
434
- // shaped, so no reconstruction is needed beyond the app-url fallback.
435
- subject: args.subjectProvenance ?? { source: "app-url", state: { provenance: "undeclared" } },
432
+ subject: args.subject,
436
433
  ...(cost === undefined ? {} : { cost }),
437
434
  };
438
435
  }
@@ -2,7 +2,7 @@ import type { ComputerUsePlan } from "../../study/plan-types.js";
2
2
  import type { StudySubjectState } from "../../study/types.js";
3
3
  import { type RunSubjectProvenance, type RunSubjectStateStepRecord } from "../../run/bundle.js";
4
4
  import { type LocalTreeArchive } from "../../subject/local-tree-archive.js";
5
- import { type DesktopParticipantRun, type CuaSubjectProjection, type CuaSubjectProvenanceArg, type ParticipantRunOutcome } from "./types.js";
5
+ import { type DesktopParticipantRun, type ParticipantRunOutcome } from "./types.js";
6
6
  /**
7
7
  * Each participant's subject projection. A participant's outcome adds the subject commit it resolved and the
8
8
  * state steps it executed; without outcomes (dry run, or a run still in progress) the declared
@@ -15,7 +15,7 @@ export declare function projectParticipantSubjects(args: {
15
15
  runs: readonly DesktopParticipantRun[];
16
16
  outcomes: readonly ParticipantRunOutcome[] | undefined;
17
17
  dryRun: boolean;
18
- }): CuaSubjectProjection[];
18
+ }): RunSubjectProvenance[];
19
19
  /**
20
20
  * Resolve the bundle's state marker from the declaration and what actually ran.
21
21
  * Precedence: external declared → "unpinned" (seed records, if any, stay attached; a
@@ -28,10 +28,6 @@ export declare function resolveSubjectState(args: {
28
28
  dryRun: boolean;
29
29
  executed: RunSubjectStateStepRecord[];
30
30
  }): RunSubjectProvenance["state"];
31
- /** Narrow a resolved CuaSubjectProjection into the shape buildSingleParticipantBundle's
32
- * subjectProvenance param wants (provisioned-route sources only; app-url stays undeclared, the
33
- * default branch that builder already handles). */
34
- export declare function subjectProvenanceArg(subject: CuaSubjectProjection, publicRepo: string | undefined, subjectEnvNames: string[]): CuaSubjectProvenanceArg | undefined;
35
31
  /**
36
32
  * The run-level subject for the top level and the bundle. Local-tree participants all pack from the
37
33
  * same once-per-run archive, so every participant already carries the identical archiveSha256/commit/dirty and
@@ -39,11 +35,11 @@ export declare function subjectProvenanceArg(subject: CuaSubjectProjection, publ
39
35
  * commit; the aggregate carries it only when every participant agrees, and warns when they diverge.
40
36
  */
41
37
  export declare function aggregateCuaSubject(args: {
42
- subjects: readonly CuaSubjectProjection[];
38
+ subjects: readonly RunSubjectProvenance[];
43
39
  outcomes: readonly ParticipantRunOutcome[] | undefined;
44
40
  participantCount: number;
45
41
  dryRun: boolean;
46
42
  }): {
47
- subject: CuaSubjectProjection;
43
+ subject: RunSubjectProvenance;
48
44
  warnings: string[];
49
45
  };