humanish 0.23.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/comms-email-catch.js +1 -1
- package/dist/{comms-faux-inbox.d.ts → comms-fake-inbox.d.ts} +13 -5
- package/dist/{comms-faux-inbox.js → comms-fake-inbox.js} +30 -6
- package/dist/comms-fake-inbox.js.map +1 -0
- package/dist/comms-sandbox-catch.d.ts +33 -2
- package/dist/comms-sandbox-catch.js +33 -1
- package/dist/comms-sandbox-catch.js.map +1 -1
- package/dist/comms-types.d.ts +4 -4
- package/dist/comms-types.js +1 -1
- package/dist/concurrent-shared-world-lab.js +1 -1
- package/dist/cua-actor-lab.d.ts +7 -0
- package/dist/cua-actor-lab.js +52 -3
- package/dist/cua-actor-lab.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/lab-config.d.ts +12 -5
- package/dist/lab-config.js +5 -5
- package/dist/lab-config.js.map +1 -1
- package/docs/architecture/external-public-shared-world.md +1 -1
- package/docs/contracts/schemas.md +1 -1
- package/docs/goals/current.md +1 -1
- package/docs/ramp/README.md +1 -1
- package/package.json +1 -1
- package/dist/comms-faux-inbox.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// A VENDOR-NEUTRAL loopback catch server for email-send APIs (#297). An app hardwired to a hosted
|
|
2
|
-
// email provider is redirected into the
|
|
2
|
+
// email provider is redirected into the fake bus with ONE env var and no code change: point the app's
|
|
3
3
|
// API base URL at this server. The catch does not depend on, or name itself after, any one vendor —
|
|
4
4
|
// it normalizes each provider's distinct wire shape (Resend's flat body, SendGrid's nested
|
|
5
5
|
// personalizations, Postmark's TitleCase, a custom app's own JSON) to one shape via pluggable
|
|
@@ -6,7 +6,7 @@ export declare function extractLinks(body: string): string[];
|
|
|
6
6
|
* "verification code 8A3F2K") are high-precision and preferred; if none are labeled, fall back to an
|
|
7
7
|
* isolated 4–8 digit run (a bare OTP). Pure; tokens are runtime-only literal-scrub targets. */
|
|
8
8
|
export declare function extractOtpCodes(body: string): string[];
|
|
9
|
-
export interface
|
|
9
|
+
export interface FakeInboxOptions {
|
|
10
10
|
/** "email" (default) or "sms" — the address shape + surface differ; machinery is identical. */
|
|
11
11
|
channel?: CommsChannelKind;
|
|
12
12
|
/** Email domain for minted addresses. Default example.test (an RFC 6761 reserved, unroutable test
|
|
@@ -15,18 +15,26 @@ export interface FauxInboxOptions {
|
|
|
15
15
|
/** Injected clock (ms) for deterministic tests. Default Date.now. */
|
|
16
16
|
now?: () => number;
|
|
17
17
|
}
|
|
18
|
-
/** The in-process
|
|
19
|
-
export declare class
|
|
18
|
+
/** The in-process fake adapter. Implements the same CommsChannel port a real provider adapter would. */
|
|
19
|
+
export declare class FakeInbox implements CommsChannel {
|
|
20
20
|
readonly channel: CommsChannelKind;
|
|
21
|
-
readonly kind: "
|
|
21
|
+
readonly kind: "fake";
|
|
22
22
|
private readonly domain;
|
|
23
23
|
private readonly clock;
|
|
24
24
|
private readonly byActor;
|
|
25
25
|
private readonly byValue;
|
|
26
26
|
private readonly queues;
|
|
27
27
|
private counter;
|
|
28
|
-
constructor(options?:
|
|
28
|
+
constructor(options?: FakeInboxOptions);
|
|
29
29
|
provision(actorId: string): Promise<CommsAddress>;
|
|
30
|
+
/**
|
|
31
|
+
* Provision an inbox for `actorId` at an EXPLICIT address (a lab-declared recipient), so the
|
|
32
|
+
* app-under-test's send to that literal address resolves in `deliverRaw` (which drops recipients
|
|
33
|
+
* with no provisioned inbox). Same value-collision guard as `provision`; if `actorId` already held
|
|
34
|
+
* a different auto-generated address, the declared address supersedes it (the lab's declaration
|
|
35
|
+
* wins). Idempotent: re-declaring the same address returns the existing inbox without clearing it.
|
|
36
|
+
*/
|
|
37
|
+
provisionAddress(actorId: string, value: string): Promise<CommsAddress>;
|
|
30
38
|
private route;
|
|
31
39
|
send(message: OutboundMessage): Promise<CommsMessage>;
|
|
32
40
|
deliverRaw(inbound: InboundRaw): Promise<CommsMessage[]>;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
// The
|
|
1
|
+
// The FAKE in-process email/SMS bus (#297 Stage 2). "Fake" in the precise test-double sense (Fowler):
|
|
2
|
+
// a working, in-memory implementation of the CommsChannel port that takes a production shortcut — the
|
|
3
|
+
// same slot as Kubernetes' `fake` clientset, distinct from a mock/stub. Deterministic, $0, offline,
|
|
4
|
+
// public-safe: a
|
|
2
5
|
// message an app-under-test "sends" (via an ingress like the vendor-neutral email catch) is routed to the
|
|
3
6
|
// addressed actor inbox and read back through the same CommsChannel port a real provider adapter
|
|
4
7
|
// would implement. Nothing leaves the process. See comms-types.ts for the port + public-safety notes.
|
|
@@ -73,10 +76,10 @@ function smsAddressFor(actorId) {
|
|
|
73
76
|
const digits = digestText(actorId, 16).replace(/[a-f]/g, (c) => String(c.charCodeAt(0) % 10)).slice(0, 7);
|
|
74
77
|
return `+1555${digits}`;
|
|
75
78
|
}
|
|
76
|
-
/** The in-process
|
|
77
|
-
export class
|
|
79
|
+
/** The in-process fake adapter. Implements the same CommsChannel port a real provider adapter would. */
|
|
80
|
+
export class FakeInbox {
|
|
78
81
|
channel;
|
|
79
|
-
kind = "
|
|
82
|
+
kind = "fake";
|
|
80
83
|
domain;
|
|
81
84
|
clock;
|
|
82
85
|
byActor = new Map();
|
|
@@ -95,7 +98,7 @@ export class FauxInbox {
|
|
|
95
98
|
const value = this.channel === "sms" ? smsAddressFor(actorId) : `${sanitizeLocalPart(actorId)}@${this.domain}`;
|
|
96
99
|
// Address collision guard: two distinct actor ids can sanitize to the same local part. Reuse the
|
|
97
100
|
// existing inbox rather than resetting its queue (which would drop already-delivered mail). Both
|
|
98
|
-
// actors then share it — a
|
|
101
|
+
// actors then share it — a fake-world edge; declare distinct addresses to avoid it.
|
|
99
102
|
const prior = this.byValue.get(value.toLowerCase());
|
|
100
103
|
if (prior) {
|
|
101
104
|
this.byActor.set(actorId, prior);
|
|
@@ -107,6 +110,27 @@ export class FauxInbox {
|
|
|
107
110
|
this.queues.set(value.toLowerCase(), []);
|
|
108
111
|
return address;
|
|
109
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Provision an inbox for `actorId` at an EXPLICIT address (a lab-declared recipient), so the
|
|
115
|
+
* app-under-test's send to that literal address resolves in `deliverRaw` (which drops recipients
|
|
116
|
+
* with no provisioned inbox). Same value-collision guard as `provision`; if `actorId` already held
|
|
117
|
+
* a different auto-generated address, the declared address supersedes it (the lab's declaration
|
|
118
|
+
* wins). Idempotent: re-declaring the same address returns the existing inbox without clearing it.
|
|
119
|
+
*/
|
|
120
|
+
async provisionAddress(actorId, value) {
|
|
121
|
+
const normalized = value.trim();
|
|
122
|
+
const key = normalized.toLowerCase();
|
|
123
|
+
const prior = this.byValue.get(key);
|
|
124
|
+
if (prior) {
|
|
125
|
+
this.byActor.set(actorId, prior);
|
|
126
|
+
return prior;
|
|
127
|
+
}
|
|
128
|
+
const address = { channel: this.channel, actorId, value: normalized, digest: digestText(normalized, 16) };
|
|
129
|
+
this.byActor.set(actorId, address);
|
|
130
|
+
this.byValue.set(key, address);
|
|
131
|
+
this.queues.set(key, []);
|
|
132
|
+
return address;
|
|
133
|
+
}
|
|
110
134
|
route(from, to, subject, body) {
|
|
111
135
|
const at = this.clock();
|
|
112
136
|
const message = {
|
|
@@ -154,4 +178,4 @@ export class FauxInbox {
|
|
|
154
178
|
return [...this.byActor.values()];
|
|
155
179
|
}
|
|
156
180
|
}
|
|
157
|
-
//# sourceMappingURL=comms-
|
|
181
|
+
//# sourceMappingURL=comms-fake-inbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comms-fake-inbox.js","sourceRoot":"","sources":["../src/comms-fake-inbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { CommsChannel } from "./comms-types.js";
|
|
1
|
+
import type { CommsAddress, CommsChannel } from "./comms-types.js";
|
|
2
|
+
import { type CommsThreadArtifact } from "./comms-evidence.js";
|
|
2
3
|
import { type EmailSendProfile } from "./comms-email-catch.js";
|
|
3
4
|
import { type DetachedTimers } from "./e2b-detached.js";
|
|
4
5
|
import type { E2BDesktopSandbox } from "./e2b-desktop-launch.js";
|
|
@@ -57,7 +58,37 @@ export declare function drainCommsCatch(desktop: E2BDesktopSandbox, deployed: Pi
|
|
|
57
58
|
}>;
|
|
58
59
|
/**
|
|
59
60
|
* Parse drained raw sends with the host profiles and route them into the CommsChannel (the host-side
|
|
60
|
-
*
|
|
61
|
+
* FakeInbox). Returns the number of inbox deliveries made. Same profiles as the host catch, so the
|
|
61
62
|
* in-sandbox and in-process routes normalize identically.
|
|
62
63
|
*/
|
|
63
64
|
export declare function routeCapturedSends(sends: RawCapturedSend[], channel: CommsChannel, profiles?: EmailSendProfile[]): Promise<number>;
|
|
65
|
+
/** Outcome of a whole-run comms collect. `artifact` is present only when captured mail matched a
|
|
66
|
+
* provisioned inbox; `captured > 0 && artifact === undefined` means the app sent mail to an address
|
|
67
|
+
* no declared recipient covers (captured but unevidenced) — the caller should surface that, not drop
|
|
68
|
+
* it silently. */
|
|
69
|
+
export interface CommsThreadCollection {
|
|
70
|
+
artifact?: CommsThreadArtifact;
|
|
71
|
+
/** Raw sends the in-sandbox catch captured this run (all POSTed paths). */
|
|
72
|
+
captured: number;
|
|
73
|
+
/** Distinct messages that matched a provisioned recipient inbox (drives whether an artifact exists). */
|
|
74
|
+
matched: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* End of a run's comms funnel: drain everything the in-sandbox catch captured, route it into the
|
|
78
|
+
* host `channel`, poll the provisioned `inboxes`, and build the digest-only thread artifact. The
|
|
79
|
+
* `artifact` is omitted when nothing was captured OR nothing matched a provisioned inbox (an empty
|
|
80
|
+
* file would be a false claim of a delivered thread) — but `captured`/`matched` are always reported so
|
|
81
|
+
* the caller can warn on captured-but-unevidenced mail rather than lose it silently. Composes the
|
|
82
|
+
* tested drain/route/build pieces so the CUA and shared-world routes collect evidence identically. The
|
|
83
|
+
* full NDJSON is drained from cursor 0 (a whole-run collect), so it is idempotent to call once at
|
|
84
|
+
* teardown.
|
|
85
|
+
*/
|
|
86
|
+
export declare function collectCommsThread(args: {
|
|
87
|
+
desktop: E2BDesktopSandbox;
|
|
88
|
+
deployed: Pick<DeployedCommsCatch, "deliveriesPath">;
|
|
89
|
+
channel: CommsChannel;
|
|
90
|
+
/** The inboxes provisioned for this run (declared recipients). Only mail to these is evidenced. */
|
|
91
|
+
inboxes: CommsAddress[];
|
|
92
|
+
profiles?: EmailSendProfile[];
|
|
93
|
+
requestTimeoutMs?: number;
|
|
94
|
+
}): Promise<CommsThreadCollection>;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// each poll `cat` its append-only NDJSON of captured sends back to the host, where the real profiles
|
|
7
7
|
// parse them and route into the CommsChannel. A FIXED loopback port is chosen up front so the app's
|
|
8
8
|
// injected base-URL env (`http://127.0.0.1:<port>`) is known before the sandbox is created.
|
|
9
|
+
import { buildCommsThreadArtifact } from "./comms-evidence.js";
|
|
9
10
|
import { DEFAULT_EMAIL_PROFILES } from "./comms-email-catch.js";
|
|
10
11
|
import { startDetachedProcess } from "./e2b-detached.js";
|
|
11
12
|
/** The default in-sandbox loopback port for the catch. Fixed (not ephemeral) so the injected base-URL
|
|
@@ -126,7 +127,7 @@ export async function drainCommsCatch(desktop, deployed, cursor = 0, requestTime
|
|
|
126
127
|
}
|
|
127
128
|
/**
|
|
128
129
|
* Parse drained raw sends with the host profiles and route them into the CommsChannel (the host-side
|
|
129
|
-
*
|
|
130
|
+
* FakeInbox). Returns the number of inbox deliveries made. Same profiles as the host catch, so the
|
|
130
131
|
* in-sandbox and in-process routes normalize identically.
|
|
131
132
|
*/
|
|
132
133
|
export async function routeCapturedSends(sends, channel, profiles = DEFAULT_EMAIL_PROFILES) {
|
|
@@ -154,4 +155,35 @@ export async function routeCapturedSends(sends, channel, profiles = DEFAULT_EMAI
|
|
|
154
155
|
}
|
|
155
156
|
return delivered;
|
|
156
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* End of a run's comms funnel: drain everything the in-sandbox catch captured, route it into the
|
|
160
|
+
* host `channel`, poll the provisioned `inboxes`, and build the digest-only thread artifact. The
|
|
161
|
+
* `artifact` is omitted when nothing was captured OR nothing matched a provisioned inbox (an empty
|
|
162
|
+
* file would be a false claim of a delivered thread) — but `captured`/`matched` are always reported so
|
|
163
|
+
* the caller can warn on captured-but-unevidenced mail rather than lose it silently. Composes the
|
|
164
|
+
* tested drain/route/build pieces so the CUA and shared-world routes collect evidence identically. The
|
|
165
|
+
* full NDJSON is drained from cursor 0 (a whole-run collect), so it is idempotent to call once at
|
|
166
|
+
* teardown.
|
|
167
|
+
*/
|
|
168
|
+
export async function collectCommsThread(args) {
|
|
169
|
+
const { sends } = await drainCommsCatch(args.desktop, args.deployed, 0, args.requestTimeoutMs);
|
|
170
|
+
if (sends.length === 0)
|
|
171
|
+
return { captured: 0, matched: 0 };
|
|
172
|
+
await routeCapturedSends(sends, args.channel, args.profiles);
|
|
173
|
+
const seen = new Set();
|
|
174
|
+
const messages = [];
|
|
175
|
+
for (const inbox of args.inboxes) {
|
|
176
|
+
for (const message of await args.channel.poll(inbox, 0)) {
|
|
177
|
+
// A single send addressed to several provisioned inboxes must appear once in the thread.
|
|
178
|
+
if (seen.has(message.id))
|
|
179
|
+
continue;
|
|
180
|
+
seen.add(message.id);
|
|
181
|
+
messages.push(message);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (messages.length === 0)
|
|
185
|
+
return { captured: sends.length, matched: 0 };
|
|
186
|
+
messages.sort((a, b) => a.deliveredAt - b.deliveredAt || a.id.localeCompare(b.id));
|
|
187
|
+
return { artifact: buildCommsThreadArtifact(messages), captured: sends.length, matched: messages.length };
|
|
188
|
+
}
|
|
157
189
|
//# sourceMappingURL=comms-sandbox-catch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comms-sandbox-catch.js","sourceRoot":"","sources":["../src/comms-sandbox-catch.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"comms-sandbox-catch.js","sourceRoot":"","sources":["../src/comms-sandbox-catch.ts"],"names":[],"mappings":"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"}
|
package/dist/comms-types.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export interface CommsMessage {
|
|
|
18
18
|
/** Resolved recipient inboxes this message was delivered to. */
|
|
19
19
|
to: CommsAddress[];
|
|
20
20
|
subject?: string;
|
|
21
|
-
/** Runtime-only for real; local-only for
|
|
21
|
+
/** Runtime-only for real; local-only for fake (never a share path without redaction — #108). */
|
|
22
22
|
body: string;
|
|
23
23
|
/** Actionable links extracted from the body (magic-link / invite / reset). Runtime-only. */
|
|
24
24
|
links: string[];
|
|
@@ -43,12 +43,12 @@ export interface InboundRaw {
|
|
|
43
43
|
body: string;
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* The port.
|
|
47
|
-
* real (network) adapter fits without changing callers; the
|
|
46
|
+
* The port. Fake (in-process) + real-email + real-sms adapters implement it identically. Async so a
|
|
47
|
+
* real (network) adapter fits without changing callers; the fake adapter just resolves immediately.
|
|
48
48
|
*/
|
|
49
49
|
export interface CommsChannel {
|
|
50
50
|
readonly channel: CommsChannelKind;
|
|
51
|
-
readonly kind: "
|
|
51
|
+
readonly kind: "fake" | "real";
|
|
52
52
|
/** Mint/allocate an inbox for an actor (address auto-generated). Idempotent per actor. */
|
|
53
53
|
provision(actorId: string): Promise<CommsAddress>;
|
|
54
54
|
/** Route a composed message from one actor to addressed inboxes. Returns the delivered record. */
|
package/dist/comms-types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// The addressed message bus (#297) — the seam that makes "off-app" comms (email/SMS the persona
|
|
2
2
|
// actually lives in) a first-class, persona-driven testable surface. A single port, addressed by
|
|
3
|
-
// actor;
|
|
3
|
+
// actor; fake (in-process) and real (provider-backed) adapters implement it identically, so the
|
|
4
4
|
// persona surface + evidence writer consume it without knowing which is behind it.
|
|
5
5
|
//
|
|
6
6
|
// PUBLIC-SAFETY: raw address values, message bodies, links, and codes are RUNTIME-ONLY. Only the
|
|
@@ -919,7 +919,7 @@ export async function runConcurrentSharedWorld(options) {
|
|
|
919
919
|
//
|
|
920
920
|
// TEMPORARY SHIM (tracked by #296): this CDP URL-relay handoff — reading the host's /lobby/CODE off
|
|
921
921
|
// its own browser and threading it into the follower missions — is a temporary coordination shim.
|
|
922
|
-
// It is to be augmented/replaced by the actor message bus (
|
|
922
|
+
// It is to be augmented/replaced by the actor message bus (fake SMS/email invite) in #297: the
|
|
923
923
|
// human-realistic version is the HOST SENDING the invite link and followers RECEIVING and tapping
|
|
924
924
|
// it, rather than the orchestrator relaying the code out-of-band.
|
|
925
925
|
const lobbyCodeLatch = deferred();
|
package/dist/cua-actor-lab.d.ts
CHANGED
|
@@ -512,6 +512,10 @@ export interface LaneRunOutcome {
|
|
|
512
512
|
harnessError: boolean;
|
|
513
513
|
failureCode?: CuaActorLabErrorCode;
|
|
514
514
|
entryKind?: "local-app";
|
|
515
|
+
/** Relative run-dir path of the digest-only comms-thread evidence artifact this lane wrote
|
|
516
|
+
* (humanish.comms-thread.v1), when a comms lab captured mail into its in-sandbox catch. Registered
|
|
517
|
+
* in the lane's stream artifacts. Absent when no comms lab ran or nothing was captured. */
|
|
518
|
+
commsArtifactPath?: string;
|
|
515
519
|
}
|
|
516
520
|
/** Build a lane's writeScreenshot closure: writes under screenshots/<screenshotDir>/ and records
|
|
517
521
|
* the relative path the trace references (screenshots/<name> at N=1; screenshots/<laneId>/<name>
|
|
@@ -733,6 +737,9 @@ export declare function buildCuaBundle(args: {
|
|
|
733
737
|
isMobile?: boolean;
|
|
734
738
|
runId: string;
|
|
735
739
|
screenshots: string[];
|
|
740
|
+
/** Relative run-dir path of the digest-only comms-thread evidence artifact (humanish.comms-thread.v1),
|
|
741
|
+
* when a comms lab captured mail; registered as a "log" stream artifact. */
|
|
742
|
+
commsArtifactPath?: string;
|
|
736
743
|
/**
|
|
737
744
|
* Capture-time screenshot policy ("blurred" when policies.redactScreenshots, else "raw").
|
|
738
745
|
* When a session ran, its trace's `redaction.screenshots` is the evidence-of-record and
|
package/dist/cua-actor-lab.js
CHANGED
|
@@ -31,7 +31,8 @@ import { CHROMIUM_EVIDENCE_HYGIENE_FLAGS, chromiumEvidenceProfilePreferencesJson
|
|
|
31
31
|
import { DEFAULT_OPENAI_CU_MODEL } from "./openai-responses-cu.js";
|
|
32
32
|
import { createDesktopSandbox, loadE2BDesktopModule } from "./e2b-desktop-launch.js";
|
|
33
33
|
import { probeUrl, readDetachedLog, runDetachedStep, startDetachedProcess } from "./e2b-detached.js";
|
|
34
|
-
import { DEFAULT_SANDBOX_CATCH_PORT, deployCommsCatch } from "./comms-sandbox-catch.js";
|
|
34
|
+
import { DEFAULT_SANDBOX_CATCH_PORT, collectCommsThread, deployCommsCatch } from "./comms-sandbox-catch.js";
|
|
35
|
+
import { FakeInbox } from "./comms-fake-inbox.js";
|
|
35
36
|
import { DEFAULT_DEVICE_PRESET, isDevicePresetName, resolveDevicePreset } from "./device-presets.js";
|
|
36
37
|
import { cuaLaneValidationReason, isHttpUrl, isLoopbackUrl, MAX_CUA_LANES, subjectStateInvalidReason } from "./lab-config.js";
|
|
37
38
|
import { mapWithConcurrency } from "./concurrency.js";
|
|
@@ -994,6 +995,10 @@ export async function runCuaLane(spec, deps) {
|
|
|
994
995
|
// sandbox-create (below, so the app reads it at boot); the catch is started right after create.
|
|
995
996
|
const commsEmail = (cloneRoute || localTreeRoute) ? config.comms?.email : undefined;
|
|
996
997
|
const commsPort = commsEmail ? (commsEmail.port ?? DEFAULT_SANDBOX_CATCH_PORT) : undefined;
|
|
998
|
+
// Hoisted so the finally can drain the catch before teardown; `commsArtifactPath` is the written
|
|
999
|
+
// evidence path folded into the lane outcome.
|
|
1000
|
+
let deployedComms;
|
|
1001
|
+
let commsArtifactPath;
|
|
997
1002
|
const commsEnv = commsEmail && commsPort !== undefined
|
|
998
1003
|
? { [commsEmail.injectEnv]: `http://127.0.0.1:${commsPort}` }
|
|
999
1004
|
: {};
|
|
@@ -1082,7 +1087,7 @@ export async function runCuaLane(spec, deps) {
|
|
|
1082
1087
|
// into its env at create) resolves the moment it boots. A comms-declared lab that can't stand the
|
|
1083
1088
|
// catch up is a setup failure (fail closed) rather than silently sending real mail.
|
|
1084
1089
|
if (commsEmail && commsPort !== undefined) {
|
|
1085
|
-
|
|
1090
|
+
deployedComms = await deployCommsCatch(desktop, { port: commsPort, requestTimeoutMs: deps.requestTimeoutMs });
|
|
1086
1091
|
if (!deployedComms.ready) {
|
|
1087
1092
|
throw new Error(`comms email catch did not become ready on 127.0.0.1:${commsPort} in the subject sandbox`);
|
|
1088
1093
|
}
|
|
@@ -1284,6 +1289,42 @@ export async function runCuaLane(spec, deps) {
|
|
|
1284
1289
|
: { warnings: [...(desktopGeometry.warnings ?? []), ...geometryWarnings] })
|
|
1285
1290
|
};
|
|
1286
1291
|
}
|
|
1292
|
+
// Off-app comms evidence (#297): before this lane's sandbox is torn down, drain everything the
|
|
1293
|
+
// in-sandbox catch captured, route it into a host fake inbox addressed to the declared
|
|
1294
|
+
// recipients, and write the digest-only thread artifact. Wrapped so a drain failure NEVER
|
|
1295
|
+
// breaks teardown — the sandbox must still be killed either way. Runs only for a ready catch.
|
|
1296
|
+
if (commsEmail && deployedComms?.ready) {
|
|
1297
|
+
try {
|
|
1298
|
+
const commsChannel = new FakeInbox();
|
|
1299
|
+
const commsInboxes = [];
|
|
1300
|
+
for (const recipient of commsEmail.recipients ?? []) {
|
|
1301
|
+
if (recipient.address !== undefined) {
|
|
1302
|
+
commsInboxes.push(await commsChannel.provisionAddress(recipient.lane, recipient.address));
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
const collected = await collectCommsThread({
|
|
1306
|
+
desktop,
|
|
1307
|
+
deployed: deployedComms,
|
|
1308
|
+
channel: commsChannel,
|
|
1309
|
+
inboxes: commsInboxes,
|
|
1310
|
+
requestTimeoutMs: deps.requestTimeoutMs
|
|
1311
|
+
});
|
|
1312
|
+
if (collected.artifact) {
|
|
1313
|
+
const path = deps.laneCount === 1 ? "comms/thread.json" : `comms/${spec.streamId}.thread.json`;
|
|
1314
|
+
await writeContainedOutputFile(deps.artifactRoot, path, `${JSON.stringify(collected.artifact, null, 2)}\n`, "utf8");
|
|
1315
|
+
commsArtifactPath = path;
|
|
1316
|
+
}
|
|
1317
|
+
else if (collected.captured > 0) {
|
|
1318
|
+
// Captured mail that matched no declared recipient must not vanish silently (invariant 6:
|
|
1319
|
+
// honest signals): tell the operator to declare comms.email.recipients[].address to match
|
|
1320
|
+
// the address the app actually sends to (e.g. the one the persona surface will sign up with).
|
|
1321
|
+
warnings.push(`Comms catch captured ${collected.captured} email send(s) but none matched a declared recipient inbox — no comms evidence written. Declare comms.email.recipients[].address to match the address the app sends to.`);
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
catch (error) {
|
|
1325
|
+
warnings.push(`Comms evidence collection failed (run continues; sandbox still torn down): ${redactText(deps.scrubKnownValues(toErrorMessage(error)))}`);
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1287
1328
|
const failed = sessionError !== undefined || session === undefined;
|
|
1288
1329
|
// Each route's own keep flag gates its own lane only: a clone.keep can never leak into
|
|
1289
1330
|
// a local-tree lane's teardown decision, and vice versa.
|
|
@@ -1363,7 +1404,8 @@ export async function runCuaLane(spec, deps) {
|
|
|
1363
1404
|
noEngagement,
|
|
1364
1405
|
selfReportedBlocker,
|
|
1365
1406
|
harnessError,
|
|
1366
|
-
...(failureCode === undefined ? {} : { failureCode })
|
|
1407
|
+
...(failureCode === undefined ? {} : { failureCode }),
|
|
1408
|
+
...(commsArtifactPath === undefined ? {} : { commsArtifactPath })
|
|
1367
1409
|
};
|
|
1368
1410
|
}
|
|
1369
1411
|
/** Run the single IN-PROCESS lane (a custom executor + provider; NO E2B). Always one lane. */
|
|
@@ -2252,6 +2294,7 @@ function buildSingleLaneBundle(args) {
|
|
|
2252
2294
|
}),
|
|
2253
2295
|
...(args.localAppSubject || args.inProcessRoute ? { entryKind: "local-app" } : {}),
|
|
2254
2296
|
...(outcome?.session ? { traceArtifactPath: spec.traceArtifactPath } : {}),
|
|
2297
|
+
...(outcome?.commsArtifactPath === undefined ? {} : { commsArtifactPath: outcome.commsArtifactPath }),
|
|
2255
2298
|
...(desktopSpanToMinutes(outcome?.desktopDurationMs) === undefined
|
|
2256
2299
|
? {}
|
|
2257
2300
|
: { desktopMinutes: desktopSpanToMinutes(outcome?.desktopDurationMs) }),
|
|
@@ -2768,6 +2811,9 @@ export function buildCuaBundle(args) {
|
|
|
2768
2811
|
...(args.traceArtifactPath
|
|
2769
2812
|
? [{ label: "actor trace", path: args.traceArtifactPath, kind: "trace" }]
|
|
2770
2813
|
: []),
|
|
2814
|
+
...(args.commsArtifactPath
|
|
2815
|
+
? [{ label: "comms thread", path: args.commsArtifactPath, kind: "log" }]
|
|
2816
|
+
: []),
|
|
2771
2817
|
...args.screenshots.map((screenshot, index) => ({
|
|
2772
2818
|
label: `screenshot ${String(index + 1).padStart(2, "0")} (${screenshotMode})`,
|
|
2773
2819
|
path: screenshot,
|
|
@@ -3115,6 +3161,9 @@ export function buildCuaFanoutBundle(args) {
|
|
|
3115
3161
|
...(session
|
|
3116
3162
|
? [{ label: `lane ${spec.laneId} actor trace`, path: spec.traceArtifactPath, kind: "trace" }]
|
|
3117
3163
|
: []),
|
|
3164
|
+
...(outcome?.commsArtifactPath
|
|
3165
|
+
? [{ label: `lane ${spec.laneId} comms thread`, path: outcome.commsArtifactPath, kind: "log" }]
|
|
3166
|
+
: []),
|
|
3118
3167
|
...screenshots.map((screenshot, screenshotIndex) => ({
|
|
3119
3168
|
label: `lane ${spec.laneId} screenshot ${String(screenshotIndex + 1).padStart(2, "0")} (${screenshotMode})`,
|
|
3120
3169
|
path: screenshot,
|