humanish 0.19.1 → 0.20.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/computer-use-actor.d.ts +3 -0
- package/dist/computer-use-actor.js +2 -1
- package/dist/computer-use-actor.js.map +1 -1
- package/dist/computer-use.d.ts +9 -0
- package/dist/computer-use.js +5 -1
- package/dist/computer-use.js.map +1 -1
- package/dist/concurrent-shared-world-lab.d.ts +23 -1
- package/dist/concurrent-shared-world-lab.js +431 -41
- package/dist/concurrent-shared-world-lab.js.map +1 -1
- package/dist/cua-actor-lab.d.ts +7 -0
- package/dist/cua-actor-lab.js +4 -1
- package/dist/cua-actor-lab.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/init-templates.js +52 -0
- package/dist/init-templates.js.map +1 -1
- package/dist/lab-config.d.ts +54 -3
- package/dist/lab-config.js +162 -9
- package/dist/lab-config.js.map +1 -1
- package/dist/run.d.ts +46 -2
- package/dist/run.js +226 -1
- package/dist/run.js.map +1 -1
- package/dist/shared-world-lab.d.ts +8 -0
- package/dist/shared-world-lab.js.map +1 -1
- package/docs/architecture/external-public-shared-world.md +117 -0
- package/docs/contracts/schemas.md +64 -5
- package/docs/goals/current.md +1 -1
- package/docs/principles/invariants-and-defaults.md +16 -0
- package/docs/product/cineguessr-3player-external-public.md +67 -0
- package/docs/ramp/README.md +1 -1
- package/docs/release/0.20.0-external-public-shared-world.md +43 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -49,13 +49,13 @@ export { TERMINAL_PRODUCT_LAB_SCHEMA, buildTerminalProductBundle, runTerminalPro
|
|
|
49
49
|
export type { CommandLogRecord, CostCategory, CostLine, InterventionRecord, LifecycleRecord, NoSpendProof, RunTerminalProductLabOptions, TerminalCostLedger, TerminalLedgers, TerminalProductLabHooks, TerminalProductLabResult, TerminalProductScoringContext } from "./e2b-terminal-lab.js";
|
|
50
50
|
export { SHARED_WORLD_LAB_PROVIDER_METADATA, SHARED_WORLD_LAB_SCHEMA, buildSharedWorldBundle, runSharedWorldLab } from "./shared-world-lab.js";
|
|
51
51
|
export type { RunSharedWorldLabOptions, SharedWorldLabErrorCode, SharedWorldLabHooks, SharedWorldLabResult, SharedWorldRoleResult } from "./shared-world-lab.js";
|
|
52
|
-
export { CONCURRENT_ATTRIBUTION_LIMITS, CONCURRENT_SHARED_WORLD_LAB_SCHEMA, CONCURRENT_SHARED_WORLD_PROVIDER_METADATA, buildConcurrentSharedWorldBundle, runConcurrentSharedWorld } from "./concurrent-shared-world-lab.js";
|
|
53
|
-
export type { ConcurrentSharedWorldLabErrorCode, ConcurrentSharedWorldLabResult, ConcurrentSharedWorldRoleResult, RunConcurrentSharedWorldLabOptions } from "./concurrent-shared-world-lab.js";
|
|
52
|
+
export { CONCURRENT_ATTRIBUTION_LIMITS, CONCURRENT_SHARED_WORLD_LAB_SCHEMA, CONCURRENT_SHARED_WORLD_PROVIDER_METADATA, EXTERNAL_PUBLIC_ATTRIBUTION_LIMITS, LOBBY_CODE_PATTERN, buildConcurrentSharedWorldBundle, extractLobbyCode, runConcurrentSharedWorld } from "./concurrent-shared-world-lab.js";
|
|
53
|
+
export type { ConcurrentSharedWorldLabErrorCode, ConcurrentSharedWorldLabResult, ConcurrentSharedWorldPlaneClass, ConcurrentSharedWorldRoleResult, RunConcurrentSharedWorldLabOptions } from "./concurrent-shared-world-lab.js";
|
|
54
54
|
export { probeUrl, readDetachedLog, runDetachedStep, startDetachedProcess } from "./e2b-detached.js";
|
|
55
55
|
export type { DetachedStepOptions, DetachedStepResult, DetachedTimers } from "./e2b-detached.js";
|
|
56
56
|
export { DEFAULT_DEVICE_PRESET, DEVICE_PRESETS, DEVICE_PRESET_NAMES, isDevicePresetName, resolveDevicePreset } from "./device-presets.js";
|
|
57
57
|
export type { DevicePreset, DevicePresetName } from "./device-presets.js";
|
|
58
|
-
export { actorResolvesToTerminal, cuaLaneCount, cuaLaneValidationReason, isHttpUrl, isLoopbackUrl, LAB_CONFIG_SCHEMA, MAX_CUA_LANES, concurrentSharedWorldValidationReason, parseLabConfig, resolveSeatUrl, routesToComputerUse, routesToConcurrentSharedWorld, routesToScriptedBrowser, routesToSharedWorld, routesToTerminalProduct, sharedWorldValidationReason, subjectStateInvalidReason } from "./lab-config.js";
|
|
58
|
+
export { actorResolvesToTerminal, cuaLaneCount, cuaLaneValidationReason, isHttpUrl, isLoopbackUrl, LAB_CONFIG_SCHEMA, MAX_CUA_LANES, concurrentSharedWorldValidationReason, externalPublicSharedWorldValidationReason, parseLabConfig, resolveSeatUrl, routesToComputerUse, routesToConcurrentSharedWorld, routesToExternalPublicSharedWorld, routesToProvisionedSharedWorld, routesToScriptedBrowser, routesToSharedWorld, routesToTerminalProduct, sharedWorldValidationReason, subjectStateInvalidReason } from "./lab-config.js";
|
|
59
59
|
export type { LabActor, LabActorLane, LabConfig, LabConfigParseResult, LabExecutionTerminal, LabRuntimeAuth, LabScenarioCaps, LabStateStepWhen, LabSubject, LabSubjectProduct, LabSubjectServe, LabSubjectSource, LabSubjectState, LabSubjectStateCheckpoint, LabSubjectStateStep, LabSubjectTopology, LabTerminalStdin, LabTerminalTransport } from "./lab-config.js";
|
|
60
60
|
export { resolveLabDryRun, runLab, selectLabBackend } from "./lab-engine.js";
|
|
61
61
|
export type { LabBackend, LabOutcome, RunLabOptions } from "./lab-engine.js";
|
package/dist/index.js
CHANGED
|
@@ -24,10 +24,10 @@ export { SCRIPTED_BROWSER_PROVIDER, runScriptedBrowserSession } from "./scripted
|
|
|
24
24
|
export { SCRIPTED_BROWSER_LAB_SCHEMA, buildScriptedLabBundle, runScriptedBrowserLab } from "./scripted-browser-lab.js";
|
|
25
25
|
export { TERMINAL_PRODUCT_LAB_SCHEMA, buildTerminalProductBundle, runTerminalProductLab } from "./e2b-terminal-lab.js";
|
|
26
26
|
export { SHARED_WORLD_LAB_PROVIDER_METADATA, SHARED_WORLD_LAB_SCHEMA, buildSharedWorldBundle, runSharedWorldLab } from "./shared-world-lab.js";
|
|
27
|
-
export { CONCURRENT_ATTRIBUTION_LIMITS, CONCURRENT_SHARED_WORLD_LAB_SCHEMA, CONCURRENT_SHARED_WORLD_PROVIDER_METADATA, buildConcurrentSharedWorldBundle, runConcurrentSharedWorld } from "./concurrent-shared-world-lab.js";
|
|
27
|
+
export { CONCURRENT_ATTRIBUTION_LIMITS, CONCURRENT_SHARED_WORLD_LAB_SCHEMA, CONCURRENT_SHARED_WORLD_PROVIDER_METADATA, EXTERNAL_PUBLIC_ATTRIBUTION_LIMITS, LOBBY_CODE_PATTERN, buildConcurrentSharedWorldBundle, extractLobbyCode, runConcurrentSharedWorld } from "./concurrent-shared-world-lab.js";
|
|
28
28
|
export { probeUrl, readDetachedLog, runDetachedStep, startDetachedProcess } from "./e2b-detached.js";
|
|
29
29
|
export { DEFAULT_DEVICE_PRESET, DEVICE_PRESETS, DEVICE_PRESET_NAMES, isDevicePresetName, resolveDevicePreset } from "./device-presets.js";
|
|
30
|
-
export { actorResolvesToTerminal, cuaLaneCount, cuaLaneValidationReason, isHttpUrl, isLoopbackUrl, LAB_CONFIG_SCHEMA, MAX_CUA_LANES, concurrentSharedWorldValidationReason, parseLabConfig, resolveSeatUrl, routesToComputerUse, routesToConcurrentSharedWorld, routesToScriptedBrowser, routesToSharedWorld, routesToTerminalProduct, sharedWorldValidationReason, subjectStateInvalidReason } from "./lab-config.js";
|
|
30
|
+
export { actorResolvesToTerminal, cuaLaneCount, cuaLaneValidationReason, isHttpUrl, isLoopbackUrl, LAB_CONFIG_SCHEMA, MAX_CUA_LANES, concurrentSharedWorldValidationReason, externalPublicSharedWorldValidationReason, parseLabConfig, resolveSeatUrl, routesToComputerUse, routesToConcurrentSharedWorld, routesToExternalPublicSharedWorld, routesToProvisionedSharedWorld, routesToScriptedBrowser, routesToSharedWorld, routesToTerminalProduct, sharedWorldValidationReason, subjectStateInvalidReason } from "./lab-config.js";
|
|
31
31
|
export { resolveLabDryRun, runLab, selectLabBackend } from "./lab-engine.js";
|
|
32
32
|
export { LAB_PREFLIGHT_SCHEMA, runLabPreflight } from "./lab-preflight.js";
|
|
33
33
|
export { CLI_RESPONSE_SCHEMA, createProgram } from "./program.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,6BAA6B,EAC7B,6BAA6B,EAC7B,2BAA2B,EAC3B,uBAAuB,EACvB,6BAA6B,EAC9B,MAAM,qBAAqB,CAAC;AAa7B,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,oBAAoB,EAAE,gCAAgC,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAEjJ,OAAO,EACL,mCAAmC,EACnC,uBAAuB,EACxB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAY3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,EACL,uBAAuB,EACvB,gCAAgC,EAChC,6BAA6B,EAC9B,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,0BAA0B,EAC1B,gCAAgC,EAChC,wBAAwB,EACzB,MAAM,wBAAwB,CAAC;AAOhC,OAAO,EACL,YAAY,EACZ,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAOtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACtB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,6BAA6B,EAC7B,wBAAwB,EACzB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,cAAc,EACf,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1D,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAExF,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE3F,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,yBAAyB,EACzB,8BAA8B,EAC9B,mBAAmB,EACpB,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,SAAS,EACT,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,cAAc,EACd,aAAa,EACb,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,MAAM,EACN,wBAAwB,EACxB,QAAQ,EACR,6BAA6B,EAC7B,UAAU,EACV,SAAS,EACT,SAAS,EACV,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAsC/C,OAAO,EACL,+BAA+B,EAC/B,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACf,MAAM,oBAAoB,CAAC;AAa5B,OAAO,EACL,yBAAyB,EACzB,yBAAyB,EAC1B,MAAM,6BAA6B,CAAC;AAWrC,OAAO,EACL,2BAA2B,EAC3B,sBAAsB,EACtB,qBAAqB,EACtB,MAAM,2BAA2B,CAAC;AAOnC,OAAO,EACL,2BAA2B,EAC3B,0BAA0B,EAC1B,qBAAqB,EACtB,MAAM,uBAAuB,CAAC;AAe/B,OAAO,EACL,kCAAkC,EAClC,uBAAuB,EACvB,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,uBAAuB,CAAC;AAQ/B,OAAO,EACL,6BAA6B,EAC7B,kCAAkC,EAClC,yCAAyC,EACzC,kCAAkC,EAClC,kBAAkB,EAClB,gCAAgC,EAChC,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,kCAAkC,CAAC;AAQ1C,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAErG,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,uBAAuB,EACvB,YAAY,EACZ,uBAAuB,EACvB,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,qCAAqC,EACrC,yCAAyC,EACzC,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,6BAA6B,EAC7B,iCAAiC,EACjC,8BAA8B,EAC9B,uBAAuB,EACvB,mBAAmB,EACnB,uBAAuB,EACvB,2BAA2B,EAC3B,yBAAyB,EAC1B,MAAM,iBAAiB,CAAC;AAqBzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAE7E,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAU3E,OAAO,EACL,mBAAmB,EACnB,aAAa,EACd,MAAM,cAAc,CAAC"}
|
package/dist/init-templates.js
CHANGED
|
@@ -197,6 +197,58 @@ scenario:
|
|
|
197
197
|
# policies:
|
|
198
198
|
# redactScreenshots: true # blur persisted frames (default off — full fidelity for local use)
|
|
199
199
|
# allowPublicTargets: true # required to drive a non-loopback app-url (a deployment you own)
|
|
200
|
+
defaults:
|
|
201
|
+
open: true
|
|
202
|
+
`
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
path: "humanish/labs/cineguessr-3player.yaml",
|
|
206
|
+
plane: "source",
|
|
207
|
+
contents: `schema: humanish.lab.v2
|
|
208
|
+
id: cineguessr-3player
|
|
209
|
+
title: External-public shared world (N mobile personas share ONE public app at once)
|
|
210
|
+
description: >-
|
|
211
|
+
A worked example of the EXTERNAL-PUBLIC shared-world route (#164 phase 2): N mobile-LAYOUT
|
|
212
|
+
personas play the SAME multiplayer lobby on a REAL public deployment AT ONCE. The public site is
|
|
213
|
+
the shared plane DIRECTLY — NO clone, NO getHost, NO subject sandbox, NO seed. A host-first barrier
|
|
214
|
+
extracts the shared-session code from the host seat's CDP-observed URL and threads it into the
|
|
215
|
+
follower join missions (followers go through the real Join flow). Dry-run (the default) emits ONE
|
|
216
|
+
external-public evidence bundle at $0. A live run needs OPENAI_API_KEY + E2B_API_KEY and
|
|
217
|
+
scenario.mode: live. Point appUrl + publicTarget at a public deployment YOU own/operate.
|
|
218
|
+
MOBILE FIDELITY: on the E2B-desktop route only width/height render (real mobile LAYOUT); there is
|
|
219
|
+
no touch input and DPR/isMobile are prompt-signal + metadata. HONESTY: attribution stays
|
|
220
|
+
shared-world, but every strength claim degrades honestly — provenance external-public (not seeded),
|
|
221
|
+
NO synthetic attestation (you cannot claim synthetic on a real site), NO authoritative shared-state
|
|
222
|
+
proof, concurrency by temporal co-occupancy + observed lobby convergence.
|
|
223
|
+
subject:
|
|
224
|
+
source: app-url # the real public deployment IS the shared plane (no clone, no getHost)
|
|
225
|
+
topology: shared-world # the declared override of the per-lane-worlds default
|
|
226
|
+
appUrl: https://your-public-app.example/ # a deployment YOU own/operate
|
|
227
|
+
publicTarget: # REQUIRED ownership attestation (the honest analog of exposure: synthetic)
|
|
228
|
+
owner: your-org/your-app
|
|
229
|
+
authorized: true
|
|
230
|
+
policies:
|
|
231
|
+
allowPublicTargets: true # REQUIRED: the shared plane is a real non-loopback public deployment
|
|
232
|
+
actors:
|
|
233
|
+
- type: openai-computer-use
|
|
234
|
+
mission: You are one of several users on the same shared session at once. Play your role, then stop.
|
|
235
|
+
lanes: # the roster (>=2) with EXACTLY ONE host: true seat
|
|
236
|
+
- id: host
|
|
237
|
+
host: true # the designated host seat that creates the shared session
|
|
238
|
+
device: mobile # 414x896 mobile LAYOUT (no touch; DPR is prompt-signal on this route)
|
|
239
|
+
instruction: Create a shared lobby, wait for the others to join, then start and play.
|
|
240
|
+
- id: player-2
|
|
241
|
+
device: mobile
|
|
242
|
+
instruction: Join the lobby you're told the code for, then play.
|
|
243
|
+
- id: player-3
|
|
244
|
+
device: small-mobile
|
|
245
|
+
instruction: Join the lobby you're told the code for, then play.
|
|
246
|
+
execution:
|
|
247
|
+
target: e2b-desktop
|
|
248
|
+
timeoutMs: 120000 # PER-SEAT session budget; also caps the host-first handoff deadline
|
|
249
|
+
concurrency: 3 # > 1 selects the CONCURRENT substrate
|
|
250
|
+
scenario:
|
|
251
|
+
mode: dry-run # default; the live path opens N real mobile-layout seats against the public app
|
|
200
252
|
defaults:
|
|
201
253
|
open: true
|
|
202
254
|
`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-templates.js","sourceRoot":"","sources":["../src/init-templates.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,YAAY,GAAkB;IACzC;QACE,IAAI,EAAE,oBAAoB;QAC1B,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;CAyBb;KACE;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;;;;;CAYb;KACE;IACD;QACE,IAAI,EAAE,2CAA2C;QACjD,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;;;;;CAYb;KACE;IACD;QACE,IAAI,EAAE,6CAA6C;QACnD,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;;;;;CAYb;KACE;IACD;QACE,IAAI,EAAE,yCAAyC;QAC/C,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;;;;;;CAab;KACE;IACD;QACE,IAAI,EAAE,+CAA+C;QACrD,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;;;;;;CAab;KACE;IACD;QACE,IAAI,EAAE,8BAA8B;QACpC,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;;;;;;CAab;KACE;IACD;QACE,IAAI,EAAE,gCAAgC;QACtC,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Db;KACE;IACD;QACE,IAAI,EAAE,kCAAkC;QACxC,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCb;KACE;IACD;QACE,IAAI,EAAE,gCAAgC;QACtC,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;CAOb;KACE;IACD;QACE,IAAI,EAAE,4CAA4C;QAClD,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;CAQb;KACE;IACD;QACE,IAAI,EAAE,0BAA0B;QAChC,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;;;;;CAYb;KACE;IACD;QACE,IAAI,EAAE,iCAAiC;QACvC,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;;;CAUb;KACE;IACD;QACE,IAAI,EAAE,iCAAiC;QACvC,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;CAQb;KACE;IACD;QACE,IAAI,EAAE,0BAA0B;QAChC,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;CAKb;KACE;IACD;QACE,IAAI,EAAE,6BAA6B;QACnC,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;CAMb;KACE;IACD;QACE,IAAI,EAAE,8CAA8C;QACpD,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE;;;;;;;;;;;;CAYb;KACE;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAuB;IACpD,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,SAAS,EAAE;IAC5C,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE;IAC7C,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,SAAS,EAAE;IAC3C,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,SAAS,EAAE;IAC5C,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,SAAS,EAAE;IAC5C,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,SAAS,EAAE;IAClD,EAAE,IAAI,EAAE,0BAA0B,EAAE,KAAK,EAAE,SAAS,EAAE;IACtD,EAAE,IAAI,EAAE,0BAA0B,EAAE,KAAK,EAAE,SAAS,EAAE;IACtD,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,SAAS,EAAE;CAChD,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAA2B;IACrD,QAAQ,EAAE,UAAU;IACpB,iBAAiB,EAAE,iBAAiB;IACpC,cAAc,EAAE,wBAAwB;IACxC,gBAAgB,EAAE,gBAAgB;IAClC,mBAAmB,EAAE,iCAAiC;IACtD,iBAAiB,EAAE,iBAAiB;CACrC,CAAC"}
|
|
1
|
+
{"version":3,"file":"init-templates.js","sourceRoot":"","sources":["../src/init-templates.ts"],"names":[],"mappings":"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"}
|
package/dist/lab-config.d.ts
CHANGED
|
@@ -162,6 +162,22 @@ export interface LabSubject {
|
|
|
162
162
|
* `topology: shared-world` + `execution.concurrency > 1`; inert/warned elsewhere.
|
|
163
163
|
*/
|
|
164
164
|
exposure?: "synthetic";
|
|
165
|
+
/**
|
|
166
|
+
* EXTERNAL-PUBLIC shared-world route ONLY (#164 phase 2): the author's REQUIRED ownership
|
|
167
|
+
* attestation when a real PUBLIC deployment (`source: app-url` + `topology: shared-world` +
|
|
168
|
+
* `concurrency > 1` + `policies.allowPublicTargets: true`) is used directly as the shared plane.
|
|
169
|
+
* The harness neither provisions nor exposes this target (no getHost, no clone, no seed), so it
|
|
170
|
+
* cannot attest the data is synthetic; instead the operator MUST attest they own/operate it.
|
|
171
|
+
* `owner` is a public-safe operator/repo label; `authorized` must be true. This is author-trust —
|
|
172
|
+
* the harness cannot verify ownership — surfaced honestly in the evidence class. Required on the
|
|
173
|
+
* external-public branch. On a non-`app-url` subject it is REJECTED (parse error); on any OTHER
|
|
174
|
+
* `app-url` config that does not route to external-public shared-world it is IGNORED-WITH-A-WARNING
|
|
175
|
+
* (forwardDeclaredWarnings), never silently consumed — it is meaningless without that plane.
|
|
176
|
+
*/
|
|
177
|
+
publicTarget?: {
|
|
178
|
+
owner: string;
|
|
179
|
+
authorized: boolean;
|
|
180
|
+
};
|
|
165
181
|
/** `clone`: one or more owner/repo slugs (public or authorized-private). */
|
|
166
182
|
repos?: string[];
|
|
167
183
|
clone?: LabSubjectClone;
|
|
@@ -257,6 +273,14 @@ export interface LabActorLane {
|
|
|
257
273
|
* non-shared-world route (the per-lane-worlds fan-out roster has no per-lane entry).
|
|
258
274
|
*/
|
|
259
275
|
entry?: string;
|
|
276
|
+
/**
|
|
277
|
+
* EXTERNAL-PUBLIC shared-world ONLY (#164 phase 2): marks this lane the DESIGNATED HOST seat — it
|
|
278
|
+
* creates the shared session (e.g. a multiplayer lobby) that the follower seats then join. Exactly
|
|
279
|
+
* ONE lane in the roster may carry `host: true` (validated in externalPublicSharedWorldValidationReason).
|
|
280
|
+
* The orchestrator watches the host seat's observed URL for the shared-session code and threads it
|
|
281
|
+
* into the follower missions at a host-first barrier. Inert/warned on every other route.
|
|
282
|
+
*/
|
|
283
|
+
host?: boolean;
|
|
260
284
|
}
|
|
261
285
|
/**
|
|
262
286
|
* Compact authoring sugar for repeated lane groups. The parser expands each group into concrete
|
|
@@ -544,11 +568,26 @@ export declare function routesToComputerUse(config: LabConfig): boolean;
|
|
|
544
568
|
* (the cua route) — the topology declaration is the override switch.
|
|
545
569
|
*/
|
|
546
570
|
export declare function routesToSharedWorld(config: LabConfig): boolean;
|
|
571
|
+
/** The getHost provisioned-subject shared-world shape (clone/local-tree served + exposed in-sandbox). */
|
|
572
|
+
export declare function routesToProvisionedSharedWorld(config: LabConfig): boolean;
|
|
573
|
+
/**
|
|
574
|
+
* The EXTERNAL-PUBLIC shared-world shape (#164 phase 2): a real PUBLIC deployment used DIRECTLY as
|
|
575
|
+
* the shared plane — `source: app-url` + `topology: shared-world` + a computer-use actor on
|
|
576
|
+
* e2b-desktop + `policies.allowPublicTargets: true`. NO getHost, NO clone, NO subject sandbox, NO
|
|
577
|
+
* seed. The operator-ownership attestation `subject.publicTarget` is required (validated in
|
|
578
|
+
* externalPublicSharedWorldValidationReason, not here — this predicate is the router only, so a
|
|
579
|
+
* half-declared external-public config still routes here to get its precise fail-closed reason
|
|
580
|
+
* rather than silently downgrading to the per-lane cua route). Always concurrent (concurrency > 1 is
|
|
581
|
+
* enforced by the validation reason).
|
|
582
|
+
*/
|
|
583
|
+
export declare function routesToExternalPublicSharedWorld(config: LabConfig): boolean;
|
|
547
584
|
/**
|
|
548
585
|
* True when this config routes to the CONCURRENT shared-world backend (#164 phase 2): a shared-world
|
|
549
|
-
* config with `execution.concurrency > 1` (N actor seats driving ONE
|
|
550
|
-
*
|
|
551
|
-
*
|
|
586
|
+
* config with `execution.concurrency > 1` (N actor seats driving ONE plane AT ONCE). Two plane
|
|
587
|
+
* classes: the getHost provisioned-subject shape (clone/local-tree) AND the external-public shape (a
|
|
588
|
+
* real public deployment used directly as the plane — `source: app-url` + `allowPublicTargets`, no
|
|
589
|
+
* getHost/clone/seed). `concurrency` absent or 1 stays the sequential PoC (getHost only).
|
|
590
|
+
* selectLabBackend checks this BEFORE routesToSharedWorld.
|
|
552
591
|
*/
|
|
553
592
|
export declare function routesToConcurrentSharedWorld(config: LabConfig): boolean;
|
|
554
593
|
/**
|
|
@@ -560,6 +599,18 @@ export declare function routesToConcurrentSharedWorld(config: LabConfig): boolea
|
|
|
560
599
|
* is exported npm surface).
|
|
561
600
|
*/
|
|
562
601
|
export declare function concurrentSharedWorldValidationReason(config: LabConfig): string | null;
|
|
602
|
+
/**
|
|
603
|
+
* Cross-validate the EXTERNAL-PUBLIC shared-world declaration (#164 phase 2): a real PUBLIC
|
|
604
|
+
* deployment used DIRECTLY as the shared plane (no getHost, no clone, no subject sandbox, no seed).
|
|
605
|
+
* The honest analog of concurrentSharedWorldValidationReason for a plane the harness does NOT own:
|
|
606
|
+
* it FORBIDS every provisioned-subject field (serve/state.seed/state.checkpoint/exposure/clone/repos
|
|
607
|
+
* are inert with no sandbox — fail closed, never silently ignored, per invariant 6), and REQUIRES a
|
|
608
|
+
* non-loopback appUrl + allowPublicTargets + the operator-ownership attestation subject.publicTarget +
|
|
609
|
+
* concurrency > 1 + an actors[0].lanes roster of ≥2 with EXACTLY ONE host lane. The getHost synthetic
|
|
610
|
+
* gate is deliberately unreachable here (there is no internet-reachable harness-owned URL to attest).
|
|
611
|
+
* Enforced at parse AND re-enforced in the engine (runConcurrentSharedWorld is exported npm surface).
|
|
612
|
+
*/
|
|
613
|
+
export declare function externalPublicSharedWorldValidationReason(config: LabConfig): string | null;
|
|
563
614
|
/**
|
|
564
615
|
* Resolve a shared-world seat's entry URL from `serve.url` + a role's `entry` (relative path or
|
|
565
616
|
* same-origin absolute URL). Returns null when the combination is not a same-origin loopback URL
|
package/dist/lab-config.js
CHANGED
|
@@ -284,9 +284,14 @@ export function parseLabConfig(raw) {
|
|
|
284
284
|
// silently downgrading to a per-lane-worlds cua run. With `execution.concurrency > 1` the
|
|
285
285
|
// concurrent extras (synthetic-subject attestation, 0.0.0.0 serve bind, no clone.keep) also apply.
|
|
286
286
|
if (config.subject.topology === "shared-world") {
|
|
287
|
-
const reason =
|
|
288
|
-
|
|
289
|
-
|
|
287
|
+
const reason = config.subject.source === "app-url"
|
|
288
|
+
// The external-public plane (a real public deployment as the shared plane): NEVER the getHost
|
|
289
|
+
// synthetic gate — that gate exists because getHost is internet-reachable AND harness-owned; a
|
|
290
|
+
// public site the harness neither provisioned nor exposed has neither property.
|
|
291
|
+
? externalPublicSharedWorldValidationReason(config)
|
|
292
|
+
: (config.execution?.concurrency ?? 1) > 1
|
|
293
|
+
? concurrentSharedWorldValidationReason(config)
|
|
294
|
+
: sharedWorldValidationReason(config);
|
|
290
295
|
if (reason) {
|
|
291
296
|
return invalid(reason);
|
|
292
297
|
}
|
|
@@ -434,9 +439,13 @@ export function cuaLaneValidationReason(config) {
|
|
|
434
439
|
}
|
|
435
440
|
// Public targets fan out into N independent worlds driving the SAME public app — that is an
|
|
436
441
|
// ambiguous shared-world-ish shape, not a per-lane target swarm. Permit N>1 public runs only when
|
|
437
|
-
// every roster lane declares its own target, making the adapter-owned topology explicit.
|
|
438
|
-
|
|
439
|
-
|
|
442
|
+
// every roster lane declares its own target, making the adapter-owned topology explicit. But when
|
|
443
|
+
// `subject.topology: shared-world` is ALSO declared, N lanes against one public target is the
|
|
444
|
+
// EXTERNAL-PUBLIC shared-world topology (#164 phase 2) — ROUTE it there (a real public deployment
|
|
445
|
+
// as the shared plane) instead of refusing; externalPublicSharedWorldValidationReason then applies.
|
|
446
|
+
if (laneCount > 1 && config.policies?.allowPublicTargets === true && declaredLaneTargets(config).length === 0
|
|
447
|
+
&& config.subject.topology !== "shared-world") {
|
|
448
|
+
return "policies.allowPublicTargets cannot be combined with multi-lane fan-out (N>1) — N lanes against one declared public target is the SHARED-WORLD topology (layer 7, #164), not per-lane worlds. Declare `subject.topology: shared-world` to run the external-public shared-world route, fan out against a loopback/provisioned subject, or run a single public-target lane.";
|
|
440
449
|
}
|
|
441
450
|
return null;
|
|
442
451
|
}
|
|
@@ -537,16 +546,39 @@ export function routesToComputerUse(config) {
|
|
|
537
546
|
* (the cua route) — the topology declaration is the override switch.
|
|
538
547
|
*/
|
|
539
548
|
export function routesToSharedWorld(config) {
|
|
549
|
+
return routesToProvisionedSharedWorld(config) || routesToExternalPublicSharedWorld(config);
|
|
550
|
+
}
|
|
551
|
+
/** The getHost provisioned-subject shared-world shape (clone/local-tree served + exposed in-sandbox). */
|
|
552
|
+
export function routesToProvisionedSharedWorld(config) {
|
|
540
553
|
return (config.subject.source === "clone" || config.subject.source === "local-tree")
|
|
541
554
|
&& config.subject.topology === "shared-world"
|
|
542
555
|
&& config.execution?.target === "e2b-desktop"
|
|
543
556
|
&& actorResolvesToComputerUse(config.actors[0]?.type);
|
|
544
557
|
}
|
|
558
|
+
/**
|
|
559
|
+
* The EXTERNAL-PUBLIC shared-world shape (#164 phase 2): a real PUBLIC deployment used DIRECTLY as
|
|
560
|
+
* the shared plane — `source: app-url` + `topology: shared-world` + a computer-use actor on
|
|
561
|
+
* e2b-desktop + `policies.allowPublicTargets: true`. NO getHost, NO clone, NO subject sandbox, NO
|
|
562
|
+
* seed. The operator-ownership attestation `subject.publicTarget` is required (validated in
|
|
563
|
+
* externalPublicSharedWorldValidationReason, not here — this predicate is the router only, so a
|
|
564
|
+
* half-declared external-public config still routes here to get its precise fail-closed reason
|
|
565
|
+
* rather than silently downgrading to the per-lane cua route). Always concurrent (concurrency > 1 is
|
|
566
|
+
* enforced by the validation reason).
|
|
567
|
+
*/
|
|
568
|
+
export function routesToExternalPublicSharedWorld(config) {
|
|
569
|
+
return config.subject.source === "app-url"
|
|
570
|
+
&& config.subject.topology === "shared-world"
|
|
571
|
+
&& config.execution?.target === "e2b-desktop"
|
|
572
|
+
&& actorResolvesToComputerUse(config.actors[0]?.type)
|
|
573
|
+
&& config.policies?.allowPublicTargets === true;
|
|
574
|
+
}
|
|
545
575
|
/**
|
|
546
576
|
* True when this config routes to the CONCURRENT shared-world backend (#164 phase 2): a shared-world
|
|
547
|
-
* config with `execution.concurrency > 1` (N actor seats driving ONE
|
|
548
|
-
*
|
|
549
|
-
*
|
|
577
|
+
* config with `execution.concurrency > 1` (N actor seats driving ONE plane AT ONCE). Two plane
|
|
578
|
+
* classes: the getHost provisioned-subject shape (clone/local-tree) AND the external-public shape (a
|
|
579
|
+
* real public deployment used directly as the plane — `source: app-url` + `allowPublicTargets`, no
|
|
580
|
+
* getHost/clone/seed). `concurrency` absent or 1 stays the sequential PoC (getHost only).
|
|
581
|
+
* selectLabBackend checks this BEFORE routesToSharedWorld.
|
|
550
582
|
*/
|
|
551
583
|
export function routesToConcurrentSharedWorld(config) {
|
|
552
584
|
return routesToSharedWorld(config) && (config.execution?.concurrency ?? 1) > 1;
|
|
@@ -580,6 +612,74 @@ export function concurrentSharedWorldValidationReason(config) {
|
|
|
580
612
|
}
|
|
581
613
|
return null;
|
|
582
614
|
}
|
|
615
|
+
/**
|
|
616
|
+
* Cross-validate the EXTERNAL-PUBLIC shared-world declaration (#164 phase 2): a real PUBLIC
|
|
617
|
+
* deployment used DIRECTLY as the shared plane (no getHost, no clone, no subject sandbox, no seed).
|
|
618
|
+
* The honest analog of concurrentSharedWorldValidationReason for a plane the harness does NOT own:
|
|
619
|
+
* it FORBIDS every provisioned-subject field (serve/state.seed/state.checkpoint/exposure/clone/repos
|
|
620
|
+
* are inert with no sandbox — fail closed, never silently ignored, per invariant 6), and REQUIRES a
|
|
621
|
+
* non-loopback appUrl + allowPublicTargets + the operator-ownership attestation subject.publicTarget +
|
|
622
|
+
* concurrency > 1 + an actors[0].lanes roster of ≥2 with EXACTLY ONE host lane. The getHost synthetic
|
|
623
|
+
* gate is deliberately unreachable here (there is no internet-reachable harness-owned URL to attest).
|
|
624
|
+
* Enforced at parse AND re-enforced in the engine (runConcurrentSharedWorld is exported npm surface).
|
|
625
|
+
*/
|
|
626
|
+
export function externalPublicSharedWorldValidationReason(config) {
|
|
627
|
+
const structuralReason = laneRosterStructuralValidationReason(config);
|
|
628
|
+
if (structuralReason) {
|
|
629
|
+
return structuralReason;
|
|
630
|
+
}
|
|
631
|
+
if (config.subject.source !== "app-url") {
|
|
632
|
+
return "the external-public shared-world route requires `subject.source: app-url` — a real public deployment is used directly as the shared plane (no clone, no provisioned subject).";
|
|
633
|
+
}
|
|
634
|
+
if (config.execution?.target !== "e2b-desktop") {
|
|
635
|
+
return "the external-public shared-world route requires `execution.target: e2b-desktop` — the role seats drive hosted desktop browsers against the one public deployment.";
|
|
636
|
+
}
|
|
637
|
+
if (!actorResolvesToComputerUse(config.actors[0]?.type)) {
|
|
638
|
+
return `the external-public shared-world route requires a registered computer-use actor (one of: ${registeredComputerUseActors().join(", ")}) — each role seat runs a computer-use session.`;
|
|
639
|
+
}
|
|
640
|
+
if ((config.execution?.concurrency ?? 1) <= 1) {
|
|
641
|
+
return "the external-public shared-world route requires `execution.concurrency > 1` (N concurrent seats sharing ONE public plane); concurrency 1 proves no shared world.";
|
|
642
|
+
}
|
|
643
|
+
if (config.policies?.allowPublicTargets !== true) {
|
|
644
|
+
return "the external-public shared-world route requires `policies.allowPublicTargets: true` — the shared plane is a real non-loopback public deployment.";
|
|
645
|
+
}
|
|
646
|
+
const appUrl = config.subject.appUrl ?? "";
|
|
647
|
+
if (!isHttpUrl(appUrl) || isLoopbackUrl(appUrl)) {
|
|
648
|
+
return "the external-public shared-world route requires a non-loopback http(s) `subject.appUrl` — a loopback URL is not a shared public plane (use the getHost provisioned route for a local subject).";
|
|
649
|
+
}
|
|
650
|
+
// The operator-ownership attestation (the honest analog of exposure: synthetic — you cannot claim
|
|
651
|
+
// synthetic on a real site, but you MUST attest you own/operate it). Author-trust; unverifiable.
|
|
652
|
+
if (config.subject.publicTarget?.authorized !== true) {
|
|
653
|
+
return "the external-public shared-world route requires `subject.publicTarget: { owner, authorized: true }` — you must attest you own/operate the public deployment used as the shared plane (author-trust; the harness cannot verify ownership).";
|
|
654
|
+
}
|
|
655
|
+
// FORBID every provisioned-subject field: with no sandbox they cannot act, so they are rejected
|
|
656
|
+
// with a precise reason, never silently ignored (invariant 6). exposure: synthetic in particular
|
|
657
|
+
// would be a LIE on a real site (the harness neither provisioned nor exposed it).
|
|
658
|
+
if (config.subject.exposure !== undefined) {
|
|
659
|
+
return "`subject.exposure: synthetic` is forbidden on the external-public shared-world route — you cannot attest a real public deployment is synthetic seeded data; use `subject.publicTarget` to attest ownership instead.";
|
|
660
|
+
}
|
|
661
|
+
if (config.subject.serve !== undefined) {
|
|
662
|
+
return "`subject.serve` is forbidden on the external-public shared-world route — the harness does not serve the plane (it is an already-deployed public app); there is no in-sandbox serve to run.";
|
|
663
|
+
}
|
|
664
|
+
if (config.subject.state?.seed !== undefined || config.subject.state?.checkpoint !== undefined || config.subject.state !== undefined) {
|
|
665
|
+
return "`subject.state` (seed/checkpoint/external) is forbidden on the external-public shared-world route — the harness neither seeds nor snapshots the plane (no in-sandbox filesystem to digest); no authoritative shared-state proof is possible on this class.";
|
|
666
|
+
}
|
|
667
|
+
if (config.subject.clone !== undefined || config.subject.repos !== undefined) {
|
|
668
|
+
return "`subject.clone`/`subject.repos` are forbidden on the external-public shared-world route — nothing is cloned; the public deployment IS the plane.";
|
|
669
|
+
}
|
|
670
|
+
const lanes = config.actors[0]?.lanes;
|
|
671
|
+
if (!lanes || lanes.length < 2) {
|
|
672
|
+
return "the external-public shared-world route requires an `actors[0].lanes` roster of at least 2 roles (a single-seat shared world proves no shared session).";
|
|
673
|
+
}
|
|
674
|
+
if (lanes.some((lane) => lane.entry !== undefined)) {
|
|
675
|
+
return "`actors[0].lanes[].entry` (the loopback same-origin seat path) is forbidden on the external-public shared-world route — there is no harness-served serve.url to resolve it against; seats open the public appUrl and reach the shared session through the real UI.";
|
|
676
|
+
}
|
|
677
|
+
const hostLanes = lanes.filter((lane) => lane.host === true);
|
|
678
|
+
if (hostLanes.length !== 1) {
|
|
679
|
+
return `the external-public shared-world route requires EXACTLY ONE \`host: true\` lane (the designated host seat that creates the shared session; got ${hostLanes.length}). The other ≥1 lanes are followers that join it.`;
|
|
680
|
+
}
|
|
681
|
+
return null;
|
|
682
|
+
}
|
|
583
683
|
/**
|
|
584
684
|
* Resolve a shared-world seat's entry URL from `serve.url` + a role's `entry` (relative path or
|
|
585
685
|
* same-origin absolute URL). Returns null when the combination is not a same-origin loopback URL
|
|
@@ -646,6 +746,9 @@ function forwardDeclaredWarnings(config) {
|
|
|
646
746
|
const routesToTerminal = routesToTerminalProduct(config);
|
|
647
747
|
const routesToShared = routesToSharedWorld(config);
|
|
648
748
|
const routesToConcurrent = routesToConcurrentSharedWorld(config);
|
|
749
|
+
// The external-public plane (a real public deployment as the shared plane) consumes host lanes +
|
|
750
|
+
// subject.publicTarget; it is only ever the concurrent app-url shape.
|
|
751
|
+
const routesToExternalPublic = routesToConcurrent && config.subject.source === "app-url";
|
|
649
752
|
const routesToHostedCuaBrowser = config.execution?.target === "e2b-desktop"
|
|
650
753
|
&& routesToCua;
|
|
651
754
|
for (const [index, actor] of config.actors.entries()) {
|
|
@@ -653,6 +756,10 @@ function forwardDeclaredWarnings(config) {
|
|
|
653
756
|
if (actor.lanes?.some((lane) => lane.entry !== undefined) && !routesToShared) {
|
|
654
757
|
inert.push(`actors[${index}].lanes[].entry (the per-role loopback entry is a shared-world capability; needs subject.topology: shared-world)`);
|
|
655
758
|
}
|
|
759
|
+
// The host-seat marker acts ONLY on the external-public shared-world route; inert elsewhere.
|
|
760
|
+
if (actor.lanes?.some((lane) => lane.host === true) && !routesToExternalPublic) {
|
|
761
|
+
inert.push(`actors[${index}].lanes[].host (the designated host-seat marker; needs the external-public shared-world route: app-url × topology shared-world × allowPublicTargets × concurrency > 1)`);
|
|
762
|
+
}
|
|
656
763
|
if (routesToCua || routesToTerminal) {
|
|
657
764
|
// The cua + terminal routes consume mission/persona/model + laneFocus.instruction (they
|
|
658
765
|
// compose the agent prompt + bundle provenance); laneFocus.id/label remain inert. On the
|
|
@@ -705,6 +812,11 @@ function forwardDeclaredWarnings(config) {
|
|
|
705
812
|
if (config.subject.state?.checkpoint !== undefined && !routesToShared) {
|
|
706
813
|
inert.push("subject.state.checkpoint (the shared-world state-checkpoint probe; needs subject.topology: shared-world)");
|
|
707
814
|
}
|
|
815
|
+
// publicTarget (the external-public ownership attestation) acts ONLY on the external-public
|
|
816
|
+
// shared-world route; inert elsewhere. (It is already parse-rejected on non-app-url sources.)
|
|
817
|
+
if (config.subject.publicTarget !== undefined && !routesToExternalPublic) {
|
|
818
|
+
inert.push("subject.publicTarget (the external-public ownership attestation; needs the external-public shared-world route: app-url × topology shared-world × allowPublicTargets × concurrency > 1)");
|
|
819
|
+
}
|
|
708
820
|
// exposure (the synthetic-subject attestation) acts ONLY on the CONCURRENT shared-world route
|
|
709
821
|
// (the getHost-exposed plane); inert on the sequential shared-world route (loopback) and elsewhere.
|
|
710
822
|
if (config.subject.exposure !== undefined && !routesToConcurrent && !(routesToScripted && config.subject.source === "clone")) {
|
|
@@ -848,6 +960,11 @@ function parseSubject(raw) {
|
|
|
848
960
|
if (source !== "local-tree" && raw.localTree !== undefined) {
|
|
849
961
|
return invalid("`subject.localTree` applies only to local-tree subjects (keep/exclude/maxArchiveBytes for packing the working tree).");
|
|
850
962
|
}
|
|
963
|
+
// publicTarget is app-url-ONLY (the external-public shared-world ownership attestation). It is
|
|
964
|
+
// meaningless without a real public deployment as the plane — reject it elsewhere (invariant 6).
|
|
965
|
+
if (source !== "app-url" && raw.publicTarget !== undefined) {
|
|
966
|
+
return invalid("`subject.publicTarget` applies only to app-url subjects on the external-public shared-world route (the operator's ownership attestation for a real public deployment used directly as the shared plane).");
|
|
967
|
+
}
|
|
851
968
|
if (source === "clone") {
|
|
852
969
|
const repos = strList(raw.repos);
|
|
853
970
|
if (!repos || repos.length === 0) {
|
|
@@ -950,6 +1067,15 @@ function parseSubject(raw) {
|
|
|
950
1067
|
return invalid("`subject.appUrl` must be an http(s) URL.");
|
|
951
1068
|
}
|
|
952
1069
|
subject.appUrl = appUrl;
|
|
1070
|
+
// publicTarget (external-public shared-world ownership attestation) is app-url-only. Shape it
|
|
1071
|
+
// here; its REQUIRED-on-that-route semantics live in externalPublicSharedWorldValidationReason.
|
|
1072
|
+
if (source === "app-url" && raw.publicTarget !== undefined) {
|
|
1073
|
+
const publicTargetResult = parsePublicTarget(raw.publicTarget);
|
|
1074
|
+
if (!publicTargetResult.ok) {
|
|
1075
|
+
return publicTargetResult;
|
|
1076
|
+
}
|
|
1077
|
+
subject.publicTarget = publicTargetResult.value;
|
|
1078
|
+
}
|
|
953
1079
|
}
|
|
954
1080
|
if (source === "terminal-product") {
|
|
955
1081
|
const productResult = parseProduct(raw.product);
|
|
@@ -960,6 +1086,24 @@ function parseSubject(raw) {
|
|
|
960
1086
|
}
|
|
961
1087
|
return { ok: true, value: subject };
|
|
962
1088
|
}
|
|
1089
|
+
// The publicTarget.owner is a public-safe operator/repo label surfaced in evidence (e.g.
|
|
1090
|
+
// "danielgwilson/cineguessr" or a bare org name). Slash allowed for the owner/repo convention.
|
|
1091
|
+
const PUBLIC_TARGET_OWNER_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_./-]*$/;
|
|
1092
|
+
/** Parse the external-public shared-world ownership attestation ({ owner, authorized: true }). The
|
|
1093
|
+
* harness cannot verify ownership — this is author-trust, surfaced honestly in the evidence class. */
|
|
1094
|
+
function parsePublicTarget(raw) {
|
|
1095
|
+
if (!isRecord(raw)) {
|
|
1096
|
+
return invalid("`subject.publicTarget` must be an object ({ owner, authorized: true }) — the operator's ownership attestation for the external-public shared plane.");
|
|
1097
|
+
}
|
|
1098
|
+
const owner = str(raw.owner);
|
|
1099
|
+
if (!owner || !PUBLIC_TARGET_OWNER_PATTERN.test(owner)) {
|
|
1100
|
+
return invalid("`subject.publicTarget.owner` must be a public-safe operator/repo label (e.g. owner/repo); it is recorded in evidence, so it must carry no secret.");
|
|
1101
|
+
}
|
|
1102
|
+
if (raw.authorized !== true) {
|
|
1103
|
+
return invalid("`subject.publicTarget.authorized` must be true — you must attest you own/operate the public deployment used as the shared plane (author-trust; the harness cannot verify ownership).");
|
|
1104
|
+
}
|
|
1105
|
+
return { ok: true, value: { owner, authorized: true } };
|
|
1106
|
+
}
|
|
963
1107
|
// The product name interpolates into evidence labels and the composed prompt; the public-safe
|
|
964
1108
|
// token shape is the same load-bearing constraint as a lab id.
|
|
965
1109
|
const PRODUCT_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/;
|
|
@@ -1438,6 +1582,15 @@ function parseLanes(raw, actorIndex) {
|
|
|
1438
1582
|
const laneEntry = str(entry.entry);
|
|
1439
1583
|
if (laneEntry !== undefined)
|
|
1440
1584
|
lane.entry = laneEntry;
|
|
1585
|
+
// `host` marks the designated host seat on the external-public shared-world route; the
|
|
1586
|
+
// exactly-one-host check runs in externalPublicSharedWorldValidationReason (route context).
|
|
1587
|
+
if (entry.host !== undefined) {
|
|
1588
|
+
if (typeof entry.host !== "boolean") {
|
|
1589
|
+
return invalid(`actors[${actorIndex}].lanes[${laneIndex}].host must be a boolean (marks the designated host seat on the external-public shared-world route).`);
|
|
1590
|
+
}
|
|
1591
|
+
if (entry.host)
|
|
1592
|
+
lane.host = true;
|
|
1593
|
+
}
|
|
1441
1594
|
lanes.push(lane);
|
|
1442
1595
|
}
|
|
1443
1596
|
return { ok: true, value: lanes };
|