@evolvingmachines/evolve 0.0.60 → 0.0.61
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/chunk-N2LMMVL4.js +427 -0
- package/dist/cli/index.cjs +38 -37
- package/dist/cli/index.d.cts +3 -1
- package/dist/cli/index.d.ts +3 -1
- package/dist/cli/index.js +29 -28
- package/dist/index.cjs +54 -54
- package/dist/index.d.cts +111 -7
- package/dist/index.d.ts +111 -7
- package/dist/index.js +38 -38
- package/dist/{types-DlpTxdR_.d.cts → types-CMEpx9QI.d.cts} +313 -5
- package/dist/{types-DlpTxdR_.d.ts → types-CMEpx9QI.d.ts} +313 -5
- package/hosted-error-codes.json +6 -0
- package/package.json +5 -5
- package/skills/evolve-evals/references/cli-reference/analysis.mdx +69 -0
- package/skills/evolve-evals/references/cli-reference/check.mdx +86 -0
- package/skills/evolve-evals/references/cli-reference/dataset.mdx +13 -0
- package/skills/evolve-evals/references/cli-reference/run.mdx +6 -0
- package/skills/evolve-evals/references/cli-reference/trial.mdx +71 -2
- package/skills/evolve-evals/references/core-concepts/trial-outputs.mdx +14 -0
- package/skills/evolve-evals/references/sdk/python.mdx +22 -0
- package/skills/evolve-evals/references/sdk/typescript.mdx +22 -0
- package/skills/evolve-evals/references/sdk-reference/analyses.mdx +70 -0
- package/skills/evolve-evals/references/sdk-reference/checks.mdx +105 -4
- package/skills/evolve-evals/references/sdk-reference/datasets.mdx +40 -0
- package/skills/evolve-evals/references/sdk-reference/errors.mdx +11 -0
- package/skills/evolve-evals/references/sdk-reference/jobs.mdx +1 -1
- package/skills/evolve-evals/references/sdk-reference/trials.mdx +70 -0
- package/spec/openapi.yaml +3021 -360
- package/dist/chunk-JS2UTK2I.js +0 -427
package/spec/openapi.yaml
CHANGED
|
@@ -2082,6 +2082,16 @@ paths:
|
|
|
2082
2082
|
— `text/plain` named `<trialId>_<stream>.log` for the raw logs,
|
|
2083
2083
|
`application/json` named `<trialId>_trace-atif.json` for the
|
|
2084
2084
|
ATIF trajectory; an absent one still answers the JSON `{"log": null}`.
|
|
2085
|
+
- `filesystem`: the run's FILE SYSTEM as one gzipped tarball — the
|
|
2086
|
+
same archive `GET /api/trials/{trialId}/filesystem/archive`
|
|
2087
|
+
streams for `path=/` (captured after the run, with `MANIFEST.tsv`
|
|
2088
|
+
naming the unchanged image files it does not carry; live from the
|
|
2089
|
+
box while it runs); `source=` forces one, and a source that is not
|
|
2090
|
+
there is 409 `filesystem_state` — never an empty archive. The
|
|
2091
|
+
archive route's own codes answer here too: 422
|
|
2092
|
+
`feature_unsupported` for a live tree too large to leave the box
|
|
2093
|
+
inside the capture budget, 503 `provider_unreachable` when the
|
|
2094
|
+
provider does not answer.
|
|
2085
2095
|
- `agent-home`: the agent home tree as JSON — the utf8 TEXT VIEW of
|
|
2086
2096
|
the captured bytes
|
|
2087
2097
|
(`{"files": {"<sandbox-path>": "<text>", ...} | null}`; a file that
|
|
@@ -2150,6 +2160,7 @@ paths:
|
|
|
2150
2160
|
- trace-atif # the normalized ATIF v1.7 trajectory
|
|
2151
2161
|
- trajectory # x-wave: 2 — the harness-native session file slot
|
|
2152
2162
|
- agent-home
|
|
2163
|
+
- filesystem # the run's file system as one .tar.gz (the archive route's answer)
|
|
2153
2164
|
- name: format
|
|
2154
2165
|
in: query
|
|
2155
2166
|
description: >
|
|
@@ -2195,13 +2206,22 @@ paths:
|
|
|
2195
2206
|
schema:
|
|
2196
2207
|
type: string
|
|
2197
2208
|
format: binary
|
|
2198
|
-
description: '`format=tgz` delivery of agent-home.'
|
|
2209
|
+
description: '`format=tgz` delivery of agent-home, or the `filesystem` archive.'
|
|
2199
2210
|
'400':
|
|
2200
2211
|
$ref: '#/components/responses/BadRequest'
|
|
2201
2212
|
'401':
|
|
2202
2213
|
$ref: '#/components/responses/Unauthorized'
|
|
2203
2214
|
'404':
|
|
2204
2215
|
$ref: '#/components/responses/NotFound'
|
|
2216
|
+
'409':
|
|
2217
|
+
description: >
|
|
2218
|
+
`filesystem_state` — `stream=filesystem` with `source=live` while
|
|
2219
|
+
the box is gone, or `source=capture` before a capture exists
|
|
2220
|
+
(details carry the requested source and the state).
|
|
2221
|
+
content:
|
|
2222
|
+
application/json:
|
|
2223
|
+
schema:
|
|
2224
|
+
$ref: '#/components/schemas/Error'
|
|
2205
2225
|
'413':
|
|
2206
2226
|
description: >
|
|
2207
2227
|
The agent-home JSON text view is over the server's whole-read
|
|
@@ -2211,10 +2231,27 @@ paths:
|
|
|
2211
2231
|
application/json:
|
|
2212
2232
|
schema:
|
|
2213
2233
|
$ref: '#/components/schemas/Error'
|
|
2234
|
+
'422':
|
|
2235
|
+
description: >
|
|
2236
|
+
`feature_unsupported` — `stream=filesystem` on a live box whose
|
|
2237
|
+
provider has no live view, or whose subtree cannot leave the box
|
|
2238
|
+
inside the capture budget (details.cause names it).
|
|
2239
|
+
content:
|
|
2240
|
+
application/json:
|
|
2241
|
+
schema:
|
|
2242
|
+
$ref: '#/components/schemas/Error'
|
|
2214
2243
|
'429':
|
|
2215
2244
|
$ref: '#/components/responses/TooManyRequests'
|
|
2216
2245
|
'500':
|
|
2217
2246
|
$ref: '#/components/responses/InternalError'
|
|
2247
|
+
'503':
|
|
2248
|
+
description: >
|
|
2249
|
+
`provider_unreachable` — `stream=filesystem` and the box's
|
|
2250
|
+
provider did not answer; retry after `Retry-After`.
|
|
2251
|
+
content:
|
|
2252
|
+
application/json:
|
|
2253
|
+
schema:
|
|
2254
|
+
$ref: '#/components/schemas/Error'
|
|
2218
2255
|
|
|
2219
2256
|
/api/trials/{trialId}/files:
|
|
2220
2257
|
get:
|
|
@@ -2332,33 +2369,44 @@ paths:
|
|
|
2332
2369
|
'500':
|
|
2333
2370
|
$ref: '#/components/responses/InternalError'
|
|
2334
2371
|
|
|
2335
|
-
/api/trials/{trialId}/
|
|
2336
|
-
|
|
2372
|
+
/api/trials/{trialId}/filesystem:
|
|
2373
|
+
get:
|
|
2337
2374
|
tags: [trials]
|
|
2338
|
-
operationId:
|
|
2339
|
-
summary:
|
|
2375
|
+
operationId: getTrialFilesystem
|
|
2376
|
+
summary: The trial's file system — which source it has
|
|
2340
2377
|
description: |
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2378
|
+
The Files surface of one trial (the file system family, one shape
|
|
2379
|
+
under every run owner: trials, analyses, task checks — and the task
|
|
2380
|
+
package as a fourth, read-only owner). `state` says what the
|
|
2381
|
+
listing, read, search, archive and change routes will answer from:
|
|
2382
|
+
`live` — the box is running and the routes read it as it changes;
|
|
2383
|
+
`captured` — the run ended and its file system was kept, the same
|
|
2384
|
+
routes read the kept tree; `capturing` — the run just ended and the
|
|
2385
|
+
capture is still being written; `none` — nothing to read yet (a
|
|
2386
|
+
queued run, a run older than the feature, a capture that failed —
|
|
2387
|
+
`capture.status` says which). `box` names the running box and its
|
|
2388
|
+
role, `watcher` how change events arrive (`native` from the
|
|
2389
|
+
provider, `poll` from the folders the viewer declared open), and
|
|
2390
|
+
`capture` the kept tree's record: when, after which phase, how many
|
|
2391
|
+
entries and changed files, `ready` | `incomplete` (`left_out` names
|
|
2392
|
+
what did not fit the budget) | `failed`.
|
|
2345
2393
|
parameters:
|
|
2346
2394
|
- $ref: '#/components/parameters/TrialId'
|
|
2347
2395
|
responses:
|
|
2348
|
-
'
|
|
2349
|
-
description: The
|
|
2396
|
+
'200':
|
|
2397
|
+
description: The file system's state.
|
|
2350
2398
|
content:
|
|
2351
2399
|
application/json:
|
|
2352
2400
|
schema:
|
|
2353
|
-
$ref: '#/components/schemas/
|
|
2401
|
+
$ref: '#/components/schemas/FilesystemStatus'
|
|
2354
2402
|
'401':
|
|
2355
2403
|
$ref: '#/components/responses/Unauthorized'
|
|
2356
2404
|
'404':
|
|
2357
2405
|
$ref: '#/components/responses/NotFound'
|
|
2358
|
-
'
|
|
2406
|
+
'503':
|
|
2359
2407
|
description: >
|
|
2360
|
-
`
|
|
2361
|
-
`
|
|
2408
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
2409
|
+
retry after `Retry-After`.
|
|
2362
2410
|
content:
|
|
2363
2411
|
application/json:
|
|
2364
2412
|
schema:
|
|
@@ -2368,296 +2416,2042 @@ paths:
|
|
|
2368
2416
|
'500':
|
|
2369
2417
|
$ref: '#/components/responses/InternalError'
|
|
2370
2418
|
|
|
2371
|
-
/api/trials/{trialId}/
|
|
2372
|
-
|
|
2419
|
+
/api/trials/{trialId}/filesystem/files:
|
|
2420
|
+
get:
|
|
2373
2421
|
tags: [trials]
|
|
2374
|
-
operationId:
|
|
2375
|
-
summary:
|
|
2422
|
+
operationId: listTrialFilesystemFolder
|
|
2423
|
+
summary: List one folder of the trial's file system
|
|
2376
2424
|
description: |
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
`
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
The source JOB may still be running: a settled trial's facts are
|
|
2388
|
-
final, so "run it again" is well-defined the moment it settles. A
|
|
2389
|
-
trial of an UPLOADED job is refused (`job_uploaded`, 409).
|
|
2390
|
-
|
|
2391
|
-
Supports `Idempotency-Key` — the identical fingerprint the job-level
|
|
2392
|
-
door computes for this one-trial selection, because it IS the
|
|
2393
|
-
identical request.
|
|
2425
|
+
One page of a folder, sorted by name, paged with `cursor` (the last
|
|
2426
|
+
name served) and `limit` (default 500, max 1000). `source` forces
|
|
2427
|
+
`live` or `capture`; omitted, whichever the run has (`state` on the
|
|
2428
|
+
status route). Every entry carries its type (`dir` | `file` |
|
|
2429
|
+
`symlink` — with `target` — | `other`), size, mtime, mode and owner;
|
|
2430
|
+
`changed` and `phase` say whether the run created or modified it
|
|
2431
|
+
and in which phase (null when not known for the source); on a
|
|
2432
|
+
captured listing `captured: false` marks a file the run never
|
|
2433
|
+
touched, which only the image holds — it lists but does not open.
|
|
2434
|
+
The kernel trees (`/proc`, `/sys`, `/dev`) are never listed.
|
|
2394
2435
|
parameters:
|
|
2395
2436
|
- $ref: '#/components/parameters/TrialId'
|
|
2396
|
-
- $ref: '#/components/parameters/
|
|
2437
|
+
- $ref: '#/components/parameters/FilesystemPath'
|
|
2438
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
2439
|
+
- $ref: '#/components/parameters/FilesystemCursor'
|
|
2440
|
+
- $ref: '#/components/parameters/FilesystemLimit'
|
|
2397
2441
|
responses:
|
|
2398
|
-
'202':
|
|
2399
|
-
description: >
|
|
2400
|
-
The retry job. `Location` names it (`/api/jobs/{jobId}`).
|
|
2401
|
-
content:
|
|
2402
|
-
application/json:
|
|
2403
|
-
schema:
|
|
2404
|
-
$ref: '#/components/schemas/Job'
|
|
2405
2442
|
'200':
|
|
2406
|
-
description:
|
|
2443
|
+
description: One page of the folder.
|
|
2407
2444
|
content:
|
|
2408
2445
|
application/json:
|
|
2409
2446
|
schema:
|
|
2410
|
-
$ref: '#/components/schemas/
|
|
2447
|
+
$ref: '#/components/schemas/FilesystemListing'
|
|
2448
|
+
'400':
|
|
2449
|
+
$ref: '#/components/responses/BadRequest'
|
|
2411
2450
|
'401':
|
|
2412
2451
|
$ref: '#/components/responses/Unauthorized'
|
|
2413
|
-
'
|
|
2414
|
-
|
|
2452
|
+
'404':
|
|
2453
|
+
$ref: '#/components/responses/NotFound'
|
|
2454
|
+
'409':
|
|
2455
|
+
description: >
|
|
2456
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
2457
|
+
`source=capture` before a capture exists (details carry the
|
|
2458
|
+
requested source and the state).
|
|
2459
|
+
content:
|
|
2460
|
+
application/json:
|
|
2461
|
+
schema:
|
|
2462
|
+
$ref: '#/components/schemas/Error'
|
|
2463
|
+
'503':
|
|
2464
|
+
description: >
|
|
2465
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
2466
|
+
retry after `Retry-After`.
|
|
2415
2467
|
content:
|
|
2416
2468
|
application/json:
|
|
2417
2469
|
schema:
|
|
2418
2470
|
$ref: '#/components/schemas/Error'
|
|
2471
|
+
'429':
|
|
2472
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
2473
|
+
'500':
|
|
2474
|
+
$ref: '#/components/responses/InternalError'
|
|
2475
|
+
|
|
2476
|
+
/api/trials/{trialId}/filesystem/files/{path}:
|
|
2477
|
+
get:
|
|
2478
|
+
tags: [trials]
|
|
2479
|
+
operationId: readTrialFilesystemFile
|
|
2480
|
+
summary: Read one file of the trial's file system, raw bytes
|
|
2481
|
+
description: |
|
|
2482
|
+
RAW BYTES of one file — application/octet-stream, byte fidelity, no
|
|
2483
|
+
translation (whether it is text is the reader's call: the first
|
|
2484
|
+
4 KiB, a NUL byte means binary). A standard single `Range` header
|
|
2485
|
+
(`bytes=a-b`, `bytes=a-`, `bytes=-n`) reads a slice and answers 206
|
|
2486
|
+
with `Content-Range`; `Accept-Ranges: bytes` advertises it; a
|
|
2487
|
+
malformed or multi-range header is the typed 400, an out-of-file
|
|
2488
|
+
range the 416. An unranged read above the deployment's whole-read
|
|
2489
|
+
ceiling is the typed 413 (`invalid_input`, param `Range`, details
|
|
2490
|
+
`size_bytes` / `max_unranged_bytes`) — read it in slices.
|
|
2491
|
+
`X-Source` names the source that answered, `X-Ms` the server time.
|
|
2492
|
+
A symlink reads as its target (one hop). A path the file system
|
|
2493
|
+
does not hold is 404 `not_found`; on a captured read, a file the
|
|
2494
|
+
run never touched is 404 `not_captured` (only the image holds it).
|
|
2495
|
+
A stream that breaks after the headers ends with an aborted
|
|
2496
|
+
connection, never a partial body delivered as success.
|
|
2497
|
+
parameters:
|
|
2498
|
+
- $ref: '#/components/parameters/TrialId'
|
|
2499
|
+
- name: path
|
|
2500
|
+
in: path
|
|
2501
|
+
required: true
|
|
2502
|
+
description: The absolute box path, e.g. `app/work/main.py` for `/app/work/main.py` (the leading slash is the route's).
|
|
2503
|
+
schema:
|
|
2504
|
+
type: string
|
|
2505
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
2506
|
+
- name: Range
|
|
2507
|
+
in: header
|
|
2508
|
+
description: Optional single byte range (`bytes=a-b` / `bytes=a-` / `bytes=-n`).
|
|
2509
|
+
schema:
|
|
2510
|
+
type: string
|
|
2511
|
+
responses:
|
|
2512
|
+
'200':
|
|
2513
|
+
description: The whole file (`X-Source`, `X-Ms`).
|
|
2514
|
+
content:
|
|
2515
|
+
application/octet-stream:
|
|
2516
|
+
schema:
|
|
2517
|
+
type: string
|
|
2518
|
+
format: binary
|
|
2519
|
+
'206':
|
|
2520
|
+
description: The requested byte range (`Content-Range` states position and size).
|
|
2521
|
+
content:
|
|
2522
|
+
application/octet-stream:
|
|
2523
|
+
schema:
|
|
2524
|
+
type: string
|
|
2525
|
+
format: binary
|
|
2526
|
+
'400':
|
|
2527
|
+
$ref: '#/components/responses/BadRequest'
|
|
2528
|
+
'401':
|
|
2529
|
+
$ref: '#/components/responses/Unauthorized'
|
|
2419
2530
|
'404':
|
|
2420
2531
|
$ref: '#/components/responses/NotFound'
|
|
2421
2532
|
'409':
|
|
2422
2533
|
description: >
|
|
2423
|
-
|
|
2424
|
-
|
|
2534
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
2535
|
+
`source=capture` before a capture exists (details carry the
|
|
2536
|
+
requested source and the state).
|
|
2425
2537
|
content:
|
|
2426
2538
|
application/json:
|
|
2427
2539
|
schema:
|
|
2428
2540
|
$ref: '#/components/schemas/Error'
|
|
2429
|
-
'
|
|
2541
|
+
'413':
|
|
2430
2542
|
description: >
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
— the owning organization's `max_queued_trials` ceiling would
|
|
2434
|
-
be crossed by this job (`details`: `{quota, limit, used,
|
|
2435
|
-
requested, org}`; the message starts `hosted quota exceeded:`).
|
|
2436
|
-
No `Retry-After`: the wait is not a known number. Nothing was
|
|
2437
|
-
created; retry once the organization's queue has drained, or
|
|
2438
|
-
ask the platform administrator to raise the ceiling. A ceiling
|
|
2439
|
-
of 0 means the organization is paused.
|
|
2543
|
+
An unranged read above the whole-read ceiling (`invalid_input`,
|
|
2544
|
+
param `Range`; details `size_bytes` / `max_unranged_bytes`).
|
|
2440
2545
|
content:
|
|
2441
2546
|
application/json:
|
|
2442
2547
|
schema:
|
|
2443
2548
|
$ref: '#/components/schemas/Error'
|
|
2549
|
+
'416':
|
|
2550
|
+
description: >
|
|
2551
|
+
Range selects nothing inside the file (`invalid_input`;
|
|
2552
|
+
`Content-Range` carries `bytes */<size>`).
|
|
2553
|
+
content:
|
|
2554
|
+
application/json:
|
|
2555
|
+
schema:
|
|
2556
|
+
$ref: '#/components/schemas/Error'
|
|
2557
|
+
'503':
|
|
2558
|
+
description: >
|
|
2559
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
2560
|
+
retry after `Retry-After`.
|
|
2561
|
+
content:
|
|
2562
|
+
application/json:
|
|
2563
|
+
schema:
|
|
2564
|
+
$ref: '#/components/schemas/Error'
|
|
2565
|
+
'429':
|
|
2566
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
2444
2567
|
'500':
|
|
2445
2568
|
$ref: '#/components/responses/InternalError'
|
|
2446
2569
|
|
|
2447
|
-
/api/trials/
|
|
2448
|
-
|
|
2570
|
+
/api/trials/{trialId}/filesystem/search:
|
|
2571
|
+
get:
|
|
2449
2572
|
tags: [trials]
|
|
2450
|
-
operationId:
|
|
2451
|
-
summary:
|
|
2573
|
+
operationId: searchTrialFilesystem
|
|
2574
|
+
summary: Search the trial's file system for text
|
|
2452
2575
|
description: |
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2576
|
+
Content search: `q` is the text (or, with `regex=true`, the
|
|
2577
|
+
pattern), `path` the folder to search under (default `/` — the
|
|
2578
|
+
whole box, `scope: "box"`, which can take seconds; a folder answers
|
|
2579
|
+
`scope: "path"` in well under a second), `limit` the hit cap
|
|
2580
|
+
(default 200, max 1000). `truncated: true` means more hits exist or
|
|
2581
|
+
the search budget ran out — narrow the path or the text. Live: the
|
|
2582
|
+
box is searched as it is; captured: the kept text is searched, and
|
|
2583
|
+
`image_files_excluded: true` says files the run never touched were
|
|
2584
|
+
not searchable. Binary files never hit.
|
|
2585
|
+
parameters:
|
|
2586
|
+
- $ref: '#/components/parameters/TrialId'
|
|
2587
|
+
- name: q
|
|
2588
|
+
in: query
|
|
2589
|
+
required: true
|
|
2590
|
+
description: The text to find; a regular expression with `regex=true`.
|
|
2591
|
+
schema:
|
|
2592
|
+
type: string
|
|
2593
|
+
- $ref: '#/components/parameters/FilesystemPath'
|
|
2594
|
+
- name: regex
|
|
2595
|
+
in: query
|
|
2596
|
+
description: Treat `q` as a regular expression (default false — a plain substring).
|
|
2597
|
+
schema:
|
|
2598
|
+
type: boolean
|
|
2599
|
+
default: false
|
|
2600
|
+
- $ref: '#/components/parameters/FilesystemLimit'
|
|
2601
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
2475
2602
|
responses:
|
|
2476
2603
|
'200':
|
|
2477
|
-
description:
|
|
2604
|
+
description: The hits found.
|
|
2478
2605
|
content:
|
|
2479
2606
|
application/json:
|
|
2480
2607
|
schema:
|
|
2481
|
-
$ref: '#/components/schemas/
|
|
2608
|
+
$ref: '#/components/schemas/FilesystemSearchResult'
|
|
2482
2609
|
'400':
|
|
2483
2610
|
$ref: '#/components/responses/BadRequest'
|
|
2484
2611
|
'401':
|
|
2485
2612
|
$ref: '#/components/responses/Unauthorized'
|
|
2613
|
+
'404':
|
|
2614
|
+
$ref: '#/components/responses/NotFound'
|
|
2615
|
+
'409':
|
|
2616
|
+
description: >
|
|
2617
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
2618
|
+
`source=capture` before a capture exists (details carry the
|
|
2619
|
+
requested source and the state).
|
|
2620
|
+
content:
|
|
2621
|
+
application/json:
|
|
2622
|
+
schema:
|
|
2623
|
+
$ref: '#/components/schemas/Error'
|
|
2624
|
+
'503':
|
|
2625
|
+
description: >
|
|
2626
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
2627
|
+
retry after `Retry-After`.
|
|
2628
|
+
content:
|
|
2629
|
+
application/json:
|
|
2630
|
+
schema:
|
|
2631
|
+
$ref: '#/components/schemas/Error'
|
|
2486
2632
|
'429':
|
|
2487
2633
|
$ref: '#/components/responses/TooManyRequests'
|
|
2488
2634
|
'500':
|
|
2489
2635
|
$ref: '#/components/responses/InternalError'
|
|
2490
2636
|
|
|
2491
|
-
|
|
2492
|
-
# Analyses — trace-analysis runs as a first-class list
|
|
2493
|
-
# ===========================================================================
|
|
2494
|
-
|
|
2495
|
-
/api/analyses:
|
|
2637
|
+
/api/trials/{trialId}/filesystem/events:
|
|
2496
2638
|
get:
|
|
2497
|
-
tags: [
|
|
2498
|
-
operationId:
|
|
2499
|
-
summary:
|
|
2639
|
+
tags: [trials]
|
|
2640
|
+
operationId: streamTrialFilesystemEvents
|
|
2641
|
+
summary: Change events while the trial's box lives (SSE)
|
|
2500
2642
|
description: |
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
`
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
`
|
|
2512
|
-
`scope=shared` lists analyses of your organizations' jobs that
|
|
2513
|
-
teammates created. Nothing is public, so Harbor's `all` is refused.
|
|
2514
|
-
An API key sees exactly what its owner may read — there is no
|
|
2515
|
-
wider scope.
|
|
2516
|
-
|
|
2517
|
-
Filters are server-side and compose with the cursor.
|
|
2643
|
+
Server-sent events. `event: state` first (`{state, box}`), then
|
|
2644
|
+
`event: fs` per change (`{seq, t, path, type: create|write|remove|
|
|
2645
|
+
rename, source: watch|poll}`, `id: <seq>`), `event: ping` every
|
|
2646
|
+
15 s. Resume with `Last-Event-ID: <seq>` (or `?after=`): the events
|
|
2647
|
+
after it replay when the server still holds them; when it does not,
|
|
2648
|
+
a fresh `state` frame is the signal to relist the open folders.
|
|
2649
|
+
On a provider without a native watcher (`watcher: "poll"` on the
|
|
2650
|
+
status route) events come from polling the folders declared with
|
|
2651
|
+
`POST …/filesystem/watch`, so declare them. A `state` frame follows
|
|
2652
|
+
every change of state; the stream ends once the file system settles
|
|
2653
|
+
(`captured` or `none`).
|
|
2518
2654
|
parameters:
|
|
2519
|
-
- $ref: '#/components/parameters/
|
|
2520
|
-
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
in: query
|
|
2524
|
-
description: Only analyses of this job's trials.
|
|
2655
|
+
- $ref: '#/components/parameters/TrialId'
|
|
2656
|
+
- name: Last-Event-ID
|
|
2657
|
+
in: header
|
|
2658
|
+
description: Resume after this event seq.
|
|
2525
2659
|
schema:
|
|
2526
2660
|
type: string
|
|
2527
|
-
|
|
2528
|
-
- name: status
|
|
2661
|
+
- name: after
|
|
2529
2662
|
in: query
|
|
2530
|
-
description:
|
|
2531
|
-
Filter by the analysis's own lifecycle word (the lowercase
|
|
2532
|
-
ladder `TrialAnalysis.status` speaks) — repeatable and/or
|
|
2533
|
-
comma-separated; an unknown word is refused (`invalid_input`)
|
|
2534
|
-
with the ladder in `details.valid_statuses`.
|
|
2663
|
+
description: The same as `Last-Event-ID`, for clients that cannot set headers.
|
|
2535
2664
|
schema:
|
|
2536
|
-
type:
|
|
2537
|
-
items:
|
|
2538
|
-
type: string
|
|
2539
|
-
enum: [queued, running, completed, failed]
|
|
2540
|
-
explode: true
|
|
2665
|
+
type: string
|
|
2541
2666
|
responses:
|
|
2542
2667
|
'200':
|
|
2543
|
-
description:
|
|
2668
|
+
description: The event stream.
|
|
2544
2669
|
content:
|
|
2545
|
-
|
|
2670
|
+
text/event-stream:
|
|
2546
2671
|
schema:
|
|
2547
|
-
|
|
2672
|
+
type: string
|
|
2548
2673
|
'400':
|
|
2549
2674
|
$ref: '#/components/responses/BadRequest'
|
|
2550
2675
|
'401':
|
|
2551
2676
|
$ref: '#/components/responses/Unauthorized'
|
|
2677
|
+
'404':
|
|
2678
|
+
$ref: '#/components/responses/NotFound'
|
|
2679
|
+
'503':
|
|
2680
|
+
description: >
|
|
2681
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
2682
|
+
retry after `Retry-After`.
|
|
2683
|
+
content:
|
|
2684
|
+
application/json:
|
|
2685
|
+
schema:
|
|
2686
|
+
$ref: '#/components/schemas/Error'
|
|
2552
2687
|
'429':
|
|
2553
2688
|
$ref: '#/components/responses/TooManyRequests'
|
|
2554
2689
|
'500':
|
|
2555
2690
|
$ref: '#/components/responses/InternalError'
|
|
2556
2691
|
|
|
2692
|
+
/api/trials/{trialId}/filesystem/watch:
|
|
2693
|
+
post:
|
|
2694
|
+
tags: [trials]
|
|
2695
|
+
operationId: watchTrialFilesystem
|
|
2696
|
+
summary: Declare the folders the viewer has open
|
|
2697
|
+
description: |
|
|
2698
|
+
The folders whose changes the event stream must report on a
|
|
2699
|
+
provider without a native watcher (`watcher: "poll"`): idempotent —
|
|
2700
|
+
the body's `paths` REPLACES the set; an empty set stops polling. At
|
|
2701
|
+
most 8 folders at once (a bigger set is the typed 400 naming the
|
|
2702
|
+
bound). On a provider with a native watcher the set is accepted
|
|
2703
|
+
and unused. Refused with `filesystem_state` when the box is gone.
|
|
2704
|
+
parameters:
|
|
2705
|
+
- $ref: '#/components/parameters/TrialId'
|
|
2706
|
+
requestBody:
|
|
2707
|
+
required: true
|
|
2708
|
+
content:
|
|
2709
|
+
application/json:
|
|
2710
|
+
schema:
|
|
2711
|
+
$ref: '#/components/schemas/FilesystemWatchRequest'
|
|
2712
|
+
responses:
|
|
2713
|
+
'200':
|
|
2714
|
+
description: The set in force.
|
|
2715
|
+
content:
|
|
2716
|
+
application/json:
|
|
2717
|
+
schema:
|
|
2718
|
+
$ref: '#/components/schemas/FilesystemWatchResult'
|
|
2719
|
+
'400':
|
|
2720
|
+
$ref: '#/components/responses/BadRequest'
|
|
2721
|
+
'401':
|
|
2722
|
+
$ref: '#/components/responses/Unauthorized'
|
|
2723
|
+
'404':
|
|
2724
|
+
$ref: '#/components/responses/NotFound'
|
|
2725
|
+
'409':
|
|
2726
|
+
description: >
|
|
2727
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
2728
|
+
`source=capture` before a capture exists (details carry the
|
|
2729
|
+
requested source and the state).
|
|
2730
|
+
content:
|
|
2731
|
+
application/json:
|
|
2732
|
+
schema:
|
|
2733
|
+
$ref: '#/components/schemas/Error'
|
|
2734
|
+
'503':
|
|
2735
|
+
description: >
|
|
2736
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
2737
|
+
retry after `Retry-After`.
|
|
2738
|
+
content:
|
|
2739
|
+
application/json:
|
|
2740
|
+
schema:
|
|
2741
|
+
$ref: '#/components/schemas/Error'
|
|
2742
|
+
'429':
|
|
2743
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
2744
|
+
'500':
|
|
2745
|
+
$ref: '#/components/responses/InternalError'
|
|
2746
|
+
|
|
2747
|
+
/api/trials/{trialId}/filesystem/changes:
|
|
2748
|
+
get:
|
|
2749
|
+
tags: [trials]
|
|
2750
|
+
operationId: listTrialFilesystemChanges
|
|
2751
|
+
summary: The files the trial changed
|
|
2752
|
+
description: |
|
|
2753
|
+
The flat list of what the run created, modified or removed since its
|
|
2754
|
+
box started, with `phase` (`setup` | `agent` | `verifier`); `total`
|
|
2755
|
+
and `changed_bytes` are the whole list's, `items` one page (`cursor`
|
|
2756
|
+
= an opaque position, `limit` default 500, max 1000); `phase=`
|
|
2757
|
+
narrows to one phase. Captured: stored with the kept tree. Live: the
|
|
2758
|
+
box start listing against a fresh one, seconds per call; a box whose
|
|
2759
|
+
start listing was not stored is the typed 422.
|
|
2760
|
+
parameters:
|
|
2761
|
+
- $ref: '#/components/parameters/TrialId'
|
|
2762
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
2763
|
+
- name: phase
|
|
2764
|
+
in: query
|
|
2765
|
+
description: Only changes of one phase (default all).
|
|
2766
|
+
schema:
|
|
2767
|
+
type: string
|
|
2768
|
+
enum: [setup, agent, verifier, all]
|
|
2769
|
+
default: all
|
|
2770
|
+
- $ref: '#/components/parameters/FilesystemCursor'
|
|
2771
|
+
- $ref: '#/components/parameters/FilesystemLimit'
|
|
2772
|
+
responses:
|
|
2773
|
+
'200':
|
|
2774
|
+
description: One page of the changed-files list.
|
|
2775
|
+
content:
|
|
2776
|
+
application/json:
|
|
2777
|
+
schema:
|
|
2778
|
+
$ref: '#/components/schemas/FilesystemChanges'
|
|
2779
|
+
'400':
|
|
2780
|
+
$ref: '#/components/responses/BadRequest'
|
|
2781
|
+
'401':
|
|
2782
|
+
$ref: '#/components/responses/Unauthorized'
|
|
2783
|
+
'404':
|
|
2784
|
+
$ref: '#/components/responses/NotFound'
|
|
2785
|
+
'409':
|
|
2786
|
+
description: >
|
|
2787
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
2788
|
+
`source=capture` before a capture exists (details carry the
|
|
2789
|
+
requested source and the state).
|
|
2790
|
+
content:
|
|
2791
|
+
application/json:
|
|
2792
|
+
schema:
|
|
2793
|
+
$ref: '#/components/schemas/Error'
|
|
2794
|
+
'422':
|
|
2795
|
+
description: >
|
|
2796
|
+
`feature_unsupported` — the shape or the provider has no live view
|
|
2797
|
+
of what was asked (details.cause names it).
|
|
2798
|
+
content:
|
|
2799
|
+
application/json:
|
|
2800
|
+
schema:
|
|
2801
|
+
$ref: '#/components/schemas/Error'
|
|
2802
|
+
'503':
|
|
2803
|
+
description: >
|
|
2804
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
2805
|
+
retry after `Retry-After`.
|
|
2806
|
+
content:
|
|
2807
|
+
application/json:
|
|
2808
|
+
schema:
|
|
2809
|
+
$ref: '#/components/schemas/Error'
|
|
2810
|
+
'429':
|
|
2811
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
2812
|
+
'500':
|
|
2813
|
+
$ref: '#/components/responses/InternalError'
|
|
2814
|
+
|
|
2815
|
+
/api/trials/{trialId}/filesystem/archive:
|
|
2816
|
+
get:
|
|
2817
|
+
tags: [trials]
|
|
2818
|
+
operationId: downloadTrialFilesystemArchive
|
|
2819
|
+
summary: Download one subtree of the trial's file system as a .tar.gz
|
|
2820
|
+
description: |
|
|
2821
|
+
A gzipped tarball of the subtree under `path` (default `/`, the
|
|
2822
|
+
whole tree), streamed. Captured: only the kept bytes ride; the
|
|
2823
|
+
files the run never touched are listed in `MANIFEST.tsv` at the
|
|
2824
|
+
archive root with `captured=false`. Live: read out of the running
|
|
2825
|
+
box under the capture budget — a subtree too large to leave the box
|
|
2826
|
+
inside it is refused up front, 422 `feature_unsupported` with the
|
|
2827
|
+
size in `details.cause`; a read-out that still stalls past the
|
|
2828
|
+
budget aborts the connection, never a truncated archive delivered
|
|
2829
|
+
as success. `X-Source` names the source. A folder the file system
|
|
2830
|
+
does not hold is 404 `not_found`.
|
|
2831
|
+
parameters:
|
|
2832
|
+
- $ref: '#/components/parameters/TrialId'
|
|
2833
|
+
- $ref: '#/components/parameters/FilesystemPath'
|
|
2834
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
2835
|
+
responses:
|
|
2836
|
+
'200':
|
|
2837
|
+
description: The archive (`Content-Disposition` names it `<id>_filesystem.tar.gz`).
|
|
2838
|
+
content:
|
|
2839
|
+
application/gzip:
|
|
2840
|
+
schema:
|
|
2841
|
+
type: string
|
|
2842
|
+
format: binary
|
|
2843
|
+
'400':
|
|
2844
|
+
$ref: '#/components/responses/BadRequest'
|
|
2845
|
+
'401':
|
|
2846
|
+
$ref: '#/components/responses/Unauthorized'
|
|
2847
|
+
'404':
|
|
2848
|
+
$ref: '#/components/responses/NotFound'
|
|
2849
|
+
'409':
|
|
2850
|
+
description: >
|
|
2851
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
2852
|
+
`source=capture` before a capture exists (details carry the
|
|
2853
|
+
requested source and the state).
|
|
2854
|
+
content:
|
|
2855
|
+
application/json:
|
|
2856
|
+
schema:
|
|
2857
|
+
$ref: '#/components/schemas/Error'
|
|
2858
|
+
'422':
|
|
2859
|
+
description: >
|
|
2860
|
+
`feature_unsupported` — the provider has no live view of what was
|
|
2861
|
+
asked, or the live subtree cannot leave the box inside the
|
|
2862
|
+
capture budget (details.cause names it, with the size).
|
|
2863
|
+
content:
|
|
2864
|
+
application/json:
|
|
2865
|
+
schema:
|
|
2866
|
+
$ref: '#/components/schemas/Error'
|
|
2867
|
+
'503':
|
|
2868
|
+
description: >
|
|
2869
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
2870
|
+
retry after `Retry-After`.
|
|
2871
|
+
content:
|
|
2872
|
+
application/json:
|
|
2873
|
+
schema:
|
|
2874
|
+
$ref: '#/components/schemas/Error'
|
|
2875
|
+
'429':
|
|
2876
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
2877
|
+
'500':
|
|
2878
|
+
$ref: '#/components/responses/InternalError'
|
|
2879
|
+
|
|
2880
|
+
/api/trials/{trialId}/logs:
|
|
2881
|
+
get:
|
|
2882
|
+
tags: [trials]
|
|
2883
|
+
operationId: getTrialSandboxLog
|
|
2884
|
+
summary: One page of a sandbox log stream of the trial
|
|
2885
|
+
description: |
|
|
2886
|
+
The box's own streams, recorded while it runs and kept after:
|
|
2887
|
+
`agent` (the harness's stdout/stderr), `verifier` (the verifier
|
|
2888
|
+
command's) and `system` (the box's system log — only when the job
|
|
2889
|
+
asked for it, `JobCreate.system_log`). `setup` and `metrics` are
|
|
2890
|
+
named but not recorded today. Lines are `{seq, t, fd: out|err, line}`;
|
|
2891
|
+
`cursor` is an opaque position, `limit` default 1000, max 1000. A
|
|
2892
|
+
stream the platform holds nothing for answers an empty page whose
|
|
2893
|
+
`reason` says why — never an error.
|
|
2894
|
+
parameters:
|
|
2895
|
+
- $ref: '#/components/parameters/TrialId'
|
|
2896
|
+
- name: stream
|
|
2897
|
+
in: query
|
|
2898
|
+
required: true
|
|
2899
|
+
schema:
|
|
2900
|
+
$ref: '#/components/schemas/SandboxLogStream'
|
|
2901
|
+
- $ref: '#/components/parameters/FilesystemCursor'
|
|
2902
|
+
- $ref: '#/components/parameters/FilesystemLimit'
|
|
2903
|
+
responses:
|
|
2904
|
+
'200':
|
|
2905
|
+
description: One page of the stream.
|
|
2906
|
+
content:
|
|
2907
|
+
application/json:
|
|
2908
|
+
schema:
|
|
2909
|
+
$ref: '#/components/schemas/SandboxLogLines'
|
|
2910
|
+
'400':
|
|
2911
|
+
$ref: '#/components/responses/BadRequest'
|
|
2912
|
+
'401':
|
|
2913
|
+
$ref: '#/components/responses/Unauthorized'
|
|
2914
|
+
'404':
|
|
2915
|
+
$ref: '#/components/responses/NotFound'
|
|
2916
|
+
'503':
|
|
2917
|
+
description: >
|
|
2918
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
2919
|
+
retry after `Retry-After`.
|
|
2920
|
+
content:
|
|
2921
|
+
application/json:
|
|
2922
|
+
schema:
|
|
2923
|
+
$ref: '#/components/schemas/Error'
|
|
2924
|
+
'429':
|
|
2925
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
2926
|
+
'500':
|
|
2927
|
+
$ref: '#/components/responses/InternalError'
|
|
2928
|
+
|
|
2929
|
+
/api/trials/{trialId}/logs/events:
|
|
2930
|
+
get:
|
|
2931
|
+
tags: [trials]
|
|
2932
|
+
operationId: streamTrialSandboxLogs
|
|
2933
|
+
summary: Sandbox log lines as they arrive (SSE)
|
|
2934
|
+
description: |
|
|
2935
|
+
Server-sent events over every stream at once: `event: line`
|
|
2936
|
+
(`{stream, seq, t, fd, line}`, `id: <stream>:<seq>`), `event: state`
|
|
2937
|
+
on open and on every change of the box's state, `event: ping` every
|
|
2938
|
+
15 s. Without
|
|
2939
|
+
`Last-Event-ID` every stream replays from its beginning and then
|
|
2940
|
+
follows; with `Last-Event-ID: <stream>:<seq>` that stream resumes
|
|
2941
|
+
after the seq the paged GET handed out. Once the box is gone and
|
|
2942
|
+
every recorded line has been sent, the stream ends — the paged GET
|
|
2943
|
+
is the reader after that.
|
|
2944
|
+
parameters:
|
|
2945
|
+
- $ref: '#/components/parameters/TrialId'
|
|
2946
|
+
- name: Last-Event-ID
|
|
2947
|
+
in: header
|
|
2948
|
+
description: Resume one stream after `<stream>:<seq>`.
|
|
2949
|
+
schema:
|
|
2950
|
+
type: string
|
|
2951
|
+
responses:
|
|
2952
|
+
'200':
|
|
2953
|
+
description: The event stream.
|
|
2954
|
+
content:
|
|
2955
|
+
text/event-stream:
|
|
2956
|
+
schema:
|
|
2957
|
+
type: string
|
|
2958
|
+
'400':
|
|
2959
|
+
$ref: '#/components/responses/BadRequest'
|
|
2960
|
+
'401':
|
|
2961
|
+
$ref: '#/components/responses/Unauthorized'
|
|
2962
|
+
'404':
|
|
2963
|
+
$ref: '#/components/responses/NotFound'
|
|
2964
|
+
'503':
|
|
2965
|
+
description: >
|
|
2966
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
2967
|
+
retry after `Retry-After`.
|
|
2968
|
+
content:
|
|
2969
|
+
application/json:
|
|
2970
|
+
schema:
|
|
2971
|
+
$ref: '#/components/schemas/Error'
|
|
2972
|
+
'429':
|
|
2973
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
2974
|
+
'500':
|
|
2975
|
+
$ref: '#/components/responses/InternalError'
|
|
2976
|
+
|
|
2977
|
+
/api/trials/{trialId}/procs:
|
|
2978
|
+
get:
|
|
2979
|
+
tags: [trials]
|
|
2980
|
+
operationId: getTrialProcs
|
|
2981
|
+
summary: The trial's box process list (live only)
|
|
2982
|
+
description: |
|
|
2983
|
+
The processes running in the box right now, as one text listing
|
|
2984
|
+
(`ps` sorted by memory; on an image without `ps`, the same table
|
|
2985
|
+
read from `/proc`, its first line saying so). Live only: once the
|
|
2986
|
+
box is gone the answer is 409 `filesystem_state`.
|
|
2987
|
+
parameters:
|
|
2988
|
+
- $ref: '#/components/parameters/TrialId'
|
|
2989
|
+
responses:
|
|
2990
|
+
'200':
|
|
2991
|
+
description: The listing.
|
|
2992
|
+
content:
|
|
2993
|
+
application/json:
|
|
2994
|
+
schema:
|
|
2995
|
+
$ref: '#/components/schemas/SandboxProcs'
|
|
2996
|
+
'401':
|
|
2997
|
+
$ref: '#/components/responses/Unauthorized'
|
|
2998
|
+
'404':
|
|
2999
|
+
$ref: '#/components/responses/NotFound'
|
|
3000
|
+
'409':
|
|
3001
|
+
description: >
|
|
3002
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
3003
|
+
`source=capture` before a capture exists (details carry the
|
|
3004
|
+
requested source and the state).
|
|
3005
|
+
content:
|
|
3006
|
+
application/json:
|
|
3007
|
+
schema:
|
|
3008
|
+
$ref: '#/components/schemas/Error'
|
|
3009
|
+
'503':
|
|
3010
|
+
description: >
|
|
3011
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
3012
|
+
retry after `Retry-After`.
|
|
3013
|
+
content:
|
|
3014
|
+
application/json:
|
|
3015
|
+
schema:
|
|
3016
|
+
$ref: '#/components/schemas/Error'
|
|
3017
|
+
'429':
|
|
3018
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3019
|
+
'500':
|
|
3020
|
+
$ref: '#/components/responses/InternalError'
|
|
3021
|
+
|
|
3022
|
+
|
|
3023
|
+
/api/trials/{trialId}/regrade:
|
|
3024
|
+
post:
|
|
3025
|
+
tags: [trials]
|
|
3026
|
+
operationId: regradeTrial
|
|
3027
|
+
summary: Regrade one trial
|
|
3028
|
+
description: |
|
|
3029
|
+
Verifier-only re-run of a single trial. **The response is a Job** — a
|
|
3030
|
+
one-trial regrade job with `source_jobs` recording the provenance.
|
|
3031
|
+
The source trial is immutable. A trial of an UPLOADED job is refused
|
|
3032
|
+
(`job_uploaded`, 409): no recorded verifier inputs exist to re-run.
|
|
3033
|
+
parameters:
|
|
3034
|
+
- $ref: '#/components/parameters/TrialId'
|
|
3035
|
+
responses:
|
|
3036
|
+
'202':
|
|
3037
|
+
description: The regrade job.
|
|
3038
|
+
content:
|
|
3039
|
+
application/json:
|
|
3040
|
+
schema:
|
|
3041
|
+
$ref: '#/components/schemas/Job'
|
|
3042
|
+
'401':
|
|
3043
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3044
|
+
'404':
|
|
3045
|
+
$ref: '#/components/responses/NotFound'
|
|
3046
|
+
'409':
|
|
3047
|
+
description: >
|
|
3048
|
+
`job_not_terminal`, `no_regradable_trials`, or
|
|
3049
|
+
`regrade_source_ineligible`.
|
|
3050
|
+
content:
|
|
3051
|
+
application/json:
|
|
3052
|
+
schema:
|
|
3053
|
+
$ref: '#/components/schemas/Error'
|
|
3054
|
+
'429':
|
|
3055
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3056
|
+
'500':
|
|
3057
|
+
$ref: '#/components/responses/InternalError'
|
|
3058
|
+
|
|
3059
|
+
/api/trials/{trialId}/retry:
|
|
3060
|
+
post:
|
|
3061
|
+
tags: [trials]
|
|
3062
|
+
operationId: retryTrial
|
|
3063
|
+
summary: Retry one settled trial
|
|
3064
|
+
description: |
|
|
3065
|
+
Run ONE settled trial again. **The response is a Job** — a one-trial
|
|
3066
|
+
retry job inheriting the source job's config, with `source_jobs`
|
|
3067
|
+
recording `action: "retry"`; view it with `GET /api/jobs/{jobId}`
|
|
3068
|
+
(the 202 carries a `Location` header naming it). The source trial is
|
|
3069
|
+
immutable.
|
|
3070
|
+
|
|
3071
|
+
The same operation as `POST /api/jobs/{jobId}/retry` with
|
|
3072
|
+
`{"trial_ids": [this]}` — one selection rule, one builder, one
|
|
3073
|
+
fingerprint — kept as its own door because the trial page (and
|
|
3074
|
+
Harbor's hosted `trial retry <id>`) address the trial, not the job.
|
|
3075
|
+
The source JOB may still be running: a settled trial's facts are
|
|
3076
|
+
final, so "run it again" is well-defined the moment it settles. A
|
|
3077
|
+
trial of an UPLOADED job is refused (`job_uploaded`, 409).
|
|
3078
|
+
|
|
3079
|
+
Supports `Idempotency-Key` — the identical fingerprint the job-level
|
|
3080
|
+
door computes for this one-trial selection, because it IS the
|
|
3081
|
+
identical request.
|
|
3082
|
+
parameters:
|
|
3083
|
+
- $ref: '#/components/parameters/TrialId'
|
|
3084
|
+
- $ref: '#/components/parameters/IdempotencyKey'
|
|
3085
|
+
responses:
|
|
3086
|
+
'202':
|
|
3087
|
+
description: >
|
|
3088
|
+
The retry job. `Location` names it (`/api/jobs/{jobId}`).
|
|
3089
|
+
content:
|
|
3090
|
+
application/json:
|
|
3091
|
+
schema:
|
|
3092
|
+
$ref: '#/components/schemas/Job'
|
|
3093
|
+
'200':
|
|
3094
|
+
description: Idempotent replay of an identical retry request.
|
|
3095
|
+
content:
|
|
3096
|
+
application/json:
|
|
3097
|
+
schema:
|
|
3098
|
+
$ref: '#/components/schemas/Job'
|
|
3099
|
+
'401':
|
|
3100
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3101
|
+
'402':
|
|
3102
|
+
description: Out of credits (`insufficient_credits`).
|
|
3103
|
+
content:
|
|
3104
|
+
application/json:
|
|
3105
|
+
schema:
|
|
3106
|
+
$ref: '#/components/schemas/Error'
|
|
3107
|
+
'404':
|
|
3108
|
+
$ref: '#/components/responses/NotFound'
|
|
3109
|
+
'409':
|
|
3110
|
+
description: >
|
|
3111
|
+
Trial still live (`trial_not_settled` — QUEUED, RUNNING, and
|
|
3112
|
+
SCORING trials cannot be retried), or `idempotency_key_reused`.
|
|
3113
|
+
content:
|
|
3114
|
+
application/json:
|
|
3115
|
+
schema:
|
|
3116
|
+
$ref: '#/components/schemas/Error'
|
|
3117
|
+
'429':
|
|
3118
|
+
description: >
|
|
3119
|
+
Two conditions, distinguished by code: `rate_limited` (the
|
|
3120
|
+
standard throttle — honor `Retry-After`), and `quota_exceeded`
|
|
3121
|
+
— the owning organization's `max_queued_trials` ceiling would
|
|
3122
|
+
be crossed by this job (`details`: `{quota, limit, used,
|
|
3123
|
+
requested, org}`; the message starts `hosted quota exceeded:`).
|
|
3124
|
+
No `Retry-After`: the wait is not a known number. Nothing was
|
|
3125
|
+
created; retry once the organization's queue has drained, or
|
|
3126
|
+
ask the platform administrator to raise the ceiling. A ceiling
|
|
3127
|
+
of 0 means the organization is paused.
|
|
3128
|
+
content:
|
|
3129
|
+
application/json:
|
|
3130
|
+
schema:
|
|
3131
|
+
$ref: '#/components/schemas/Error'
|
|
3132
|
+
'500':
|
|
3133
|
+
$ref: '#/components/responses/InternalError'
|
|
3134
|
+
|
|
3135
|
+
/api/trials/stop:
|
|
3136
|
+
post:
|
|
3137
|
+
tags: [trials]
|
|
3138
|
+
operationId: stopTrials
|
|
3139
|
+
summary: Stop selected running trials or trace analyses
|
|
3140
|
+
description: |
|
|
3141
|
+
Stops individual in-flight trials without cancelling their job: each
|
|
3142
|
+
trial's sandbox is killed and the trial is settled with its spend read
|
|
3143
|
+
from the gateway. Only the caller's own trials; ids belonging to
|
|
3144
|
+
someone else are reported in `not_found` (existence is never leaked).
|
|
3145
|
+
Idempotent — already-terminal trials are reported as such and left
|
|
3146
|
+
untouched.
|
|
3147
|
+
|
|
3148
|
+
Trace-analysis ids ride the same `trial_ids` array — what each id is
|
|
3149
|
+
gets resolved server-side, so a client never partitions a selection.
|
|
3150
|
+
A running analysis has its analyzer box killed and settles `failed`
|
|
3151
|
+
with failure phase `stopped`, its own spend read from the gateway; a
|
|
3152
|
+
queued one settles the same way before any box boots (nothing minted,
|
|
3153
|
+
nothing spent). Stopped analyses come back in `stopped_analyses` with
|
|
3154
|
+
their settled rows; the caller's already-settled analyses land in
|
|
3155
|
+
`already_terminal` and foreign or unknown ids in `not_found` — the
|
|
3156
|
+
trials' refusal semantics, id for id.
|
|
3157
|
+
requestBody:
|
|
3158
|
+
required: true
|
|
3159
|
+
content:
|
|
3160
|
+
application/json:
|
|
3161
|
+
schema:
|
|
3162
|
+
$ref: '#/components/schemas/StopRequest'
|
|
3163
|
+
responses:
|
|
3164
|
+
'200':
|
|
3165
|
+
description: Per-trial outcome of the stop request.
|
|
3166
|
+
content:
|
|
3167
|
+
application/json:
|
|
3168
|
+
schema:
|
|
3169
|
+
$ref: '#/components/schemas/StopResponse'
|
|
3170
|
+
'400':
|
|
3171
|
+
$ref: '#/components/responses/BadRequest'
|
|
3172
|
+
'401':
|
|
3173
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3174
|
+
'429':
|
|
3175
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3176
|
+
'500':
|
|
3177
|
+
$ref: '#/components/responses/InternalError'
|
|
3178
|
+
|
|
3179
|
+
# ===========================================================================
|
|
3180
|
+
# Analyses — trace-analysis runs as a first-class list
|
|
3181
|
+
# ===========================================================================
|
|
3182
|
+
|
|
3183
|
+
/api/analyses:
|
|
3184
|
+
get:
|
|
3185
|
+
tags: [analyses]
|
|
3186
|
+
operationId: listAnalyses
|
|
3187
|
+
summary: List trace-analysis runs
|
|
3188
|
+
description: |
|
|
3189
|
+
Every trace analysis the caller may read, newest first, cursor-paged.
|
|
3190
|
+
Items are the same `TrialAnalysis` object a trial serves as its
|
|
3191
|
+
LATEST analysis (`Trial.analysis`) — here every analysis answers,
|
|
3192
|
+
earlier waves included, each carrying the trial, job, and task it
|
|
3193
|
+
judged. Harbor has no analysis list (their analyze writes a local
|
|
3194
|
+
`analysis.json` per trial dir); hosted, the analyzer's run is a
|
|
3195
|
+
record of its own and this is its catalog.
|
|
3196
|
+
|
|
3197
|
+
Visibility follows the analyze verb (`POST /api/jobs/{jobId}/analyze`)
|
|
3198
|
+
one relation deeper: an analysis belongs to the analyzed trial's job.
|
|
3199
|
+
`scope=my` (the default) lists analyses of jobs you created;
|
|
3200
|
+
`scope=shared` lists analyses of your organizations' jobs that
|
|
3201
|
+
teammates created. Nothing is public, so Harbor's `all` is refused.
|
|
3202
|
+
An API key sees exactly what its owner may read — there is no
|
|
3203
|
+
wider scope.
|
|
3204
|
+
|
|
3205
|
+
Filters are server-side and compose with the cursor.
|
|
3206
|
+
parameters:
|
|
3207
|
+
- $ref: '#/components/parameters/Limit'
|
|
3208
|
+
- $ref: '#/components/parameters/Cursor'
|
|
3209
|
+
- $ref: '#/components/parameters/ListScope'
|
|
3210
|
+
- name: job
|
|
3211
|
+
in: query
|
|
3212
|
+
description: Only analyses of this job's trials.
|
|
3213
|
+
schema:
|
|
3214
|
+
type: string
|
|
3215
|
+
format: uuid
|
|
3216
|
+
- name: status
|
|
3217
|
+
in: query
|
|
3218
|
+
description: >
|
|
3219
|
+
Filter by the analysis's own lifecycle word (the lowercase
|
|
3220
|
+
ladder `TrialAnalysis.status` speaks) — repeatable and/or
|
|
3221
|
+
comma-separated; an unknown word is refused (`invalid_input`)
|
|
3222
|
+
with the ladder in `details.valid_statuses`.
|
|
3223
|
+
schema:
|
|
3224
|
+
type: array
|
|
3225
|
+
items:
|
|
3226
|
+
type: string
|
|
3227
|
+
enum: [queued, running, completed, failed]
|
|
3228
|
+
explode: true
|
|
3229
|
+
responses:
|
|
3230
|
+
'200':
|
|
3231
|
+
description: One page of analyses.
|
|
3232
|
+
content:
|
|
3233
|
+
application/json:
|
|
3234
|
+
schema:
|
|
3235
|
+
$ref: '#/components/schemas/AnalysisPage'
|
|
3236
|
+
'400':
|
|
3237
|
+
$ref: '#/components/responses/BadRequest'
|
|
3238
|
+
'401':
|
|
3239
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3240
|
+
'429':
|
|
3241
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3242
|
+
'500':
|
|
3243
|
+
$ref: '#/components/responses/InternalError'
|
|
3244
|
+
|
|
3245
|
+
/api/analyses/{analysisId}/filesystem:
|
|
3246
|
+
get:
|
|
3247
|
+
tags: [analyses]
|
|
3248
|
+
operationId: getAnalysisFilesystem
|
|
3249
|
+
summary: The analysis run's file system — which source it has
|
|
3250
|
+
description: |
|
|
3251
|
+
The Files surface of one analysis run (the file system family, one shape
|
|
3252
|
+
under every run owner: trials, analyses, task checks — and the task
|
|
3253
|
+
package as a fourth, read-only owner). `state` says what the
|
|
3254
|
+
listing, read, search, archive and change routes will answer from:
|
|
3255
|
+
`live` — the box is running and the routes read it as it changes;
|
|
3256
|
+
`captured` — the run ended and its file system was kept, the same
|
|
3257
|
+
routes read the kept tree; `capturing` — the run just ended and the
|
|
3258
|
+
capture is still being written; `none` — nothing to read yet (a
|
|
3259
|
+
queued run, a run older than the feature, a capture that failed —
|
|
3260
|
+
`capture.status` says which). `box` names the running box and its
|
|
3261
|
+
role, `watcher` how change events arrive (`native` from the
|
|
3262
|
+
provider, `poll` from the folders the viewer declared open), and
|
|
3263
|
+
`capture` the kept tree's record: when, after which phase, how many
|
|
3264
|
+
entries and changed files, `ready` | `incomplete` (`left_out` names
|
|
3265
|
+
what did not fit the budget) | `failed`.
|
|
3266
|
+
parameters:
|
|
3267
|
+
- $ref: '#/components/parameters/AnalysisId'
|
|
3268
|
+
responses:
|
|
3269
|
+
'200':
|
|
3270
|
+
description: The file system's state.
|
|
3271
|
+
content:
|
|
3272
|
+
application/json:
|
|
3273
|
+
schema:
|
|
3274
|
+
$ref: '#/components/schemas/FilesystemStatus'
|
|
3275
|
+
'401':
|
|
3276
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3277
|
+
'404':
|
|
3278
|
+
$ref: '#/components/responses/NotFound'
|
|
3279
|
+
'503':
|
|
3280
|
+
description: >
|
|
3281
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
3282
|
+
retry after `Retry-After`.
|
|
3283
|
+
content:
|
|
3284
|
+
application/json:
|
|
3285
|
+
schema:
|
|
3286
|
+
$ref: '#/components/schemas/Error'
|
|
3287
|
+
'429':
|
|
3288
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3289
|
+
'500':
|
|
3290
|
+
$ref: '#/components/responses/InternalError'
|
|
3291
|
+
|
|
3292
|
+
/api/analyses/{analysisId}/filesystem/files:
|
|
3293
|
+
get:
|
|
3294
|
+
tags: [analyses]
|
|
3295
|
+
operationId: listAnalysisFilesystemFolder
|
|
3296
|
+
summary: List one folder of the analysis run's file system
|
|
3297
|
+
description: |
|
|
3298
|
+
One page of a folder, sorted by name, paged with `cursor` (the last
|
|
3299
|
+
name served) and `limit` (default 500, max 1000). `source` forces
|
|
3300
|
+
`live` or `capture`; omitted, whichever the run has (`state` on the
|
|
3301
|
+
status route). Every entry carries its type (`dir` | `file` |
|
|
3302
|
+
`symlink` — with `target` — | `other`), size, mtime, mode and owner;
|
|
3303
|
+
`changed` and `phase` say whether the run created or modified it
|
|
3304
|
+
and in which phase (null when not known for the source); on a
|
|
3305
|
+
captured listing `captured: false` marks a file the run never
|
|
3306
|
+
touched, which only the image holds — it lists but does not open.
|
|
3307
|
+
The kernel trees (`/proc`, `/sys`, `/dev`) are never listed.
|
|
3308
|
+
parameters:
|
|
3309
|
+
- $ref: '#/components/parameters/AnalysisId'
|
|
3310
|
+
- $ref: '#/components/parameters/FilesystemPath'
|
|
3311
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
3312
|
+
- $ref: '#/components/parameters/FilesystemCursor'
|
|
3313
|
+
- $ref: '#/components/parameters/FilesystemLimit'
|
|
3314
|
+
responses:
|
|
3315
|
+
'200':
|
|
3316
|
+
description: One page of the folder.
|
|
3317
|
+
content:
|
|
3318
|
+
application/json:
|
|
3319
|
+
schema:
|
|
3320
|
+
$ref: '#/components/schemas/FilesystemListing'
|
|
3321
|
+
'400':
|
|
3322
|
+
$ref: '#/components/responses/BadRequest'
|
|
3323
|
+
'401':
|
|
3324
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3325
|
+
'404':
|
|
3326
|
+
$ref: '#/components/responses/NotFound'
|
|
3327
|
+
'409':
|
|
3328
|
+
description: >
|
|
3329
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
3330
|
+
`source=capture` before a capture exists (details carry the
|
|
3331
|
+
requested source and the state).
|
|
3332
|
+
content:
|
|
3333
|
+
application/json:
|
|
3334
|
+
schema:
|
|
3335
|
+
$ref: '#/components/schemas/Error'
|
|
3336
|
+
'503':
|
|
3337
|
+
description: >
|
|
3338
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
3339
|
+
retry after `Retry-After`.
|
|
3340
|
+
content:
|
|
3341
|
+
application/json:
|
|
3342
|
+
schema:
|
|
3343
|
+
$ref: '#/components/schemas/Error'
|
|
3344
|
+
'429':
|
|
3345
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3346
|
+
'500':
|
|
3347
|
+
$ref: '#/components/responses/InternalError'
|
|
3348
|
+
|
|
3349
|
+
/api/analyses/{analysisId}/filesystem/files/{path}:
|
|
3350
|
+
get:
|
|
3351
|
+
tags: [analyses]
|
|
3352
|
+
operationId: readAnalysisFilesystemFile
|
|
3353
|
+
summary: Read one file of the analysis run's file system, raw bytes
|
|
3354
|
+
description: |
|
|
3355
|
+
RAW BYTES of one file — application/octet-stream, byte fidelity, no
|
|
3356
|
+
translation (whether it is text is the reader's call: the first
|
|
3357
|
+
4 KiB, a NUL byte means binary). A standard single `Range` header
|
|
3358
|
+
(`bytes=a-b`, `bytes=a-`, `bytes=-n`) reads a slice and answers 206
|
|
3359
|
+
with `Content-Range`; `Accept-Ranges: bytes` advertises it; a
|
|
3360
|
+
malformed or multi-range header is the typed 400, an out-of-file
|
|
3361
|
+
range the 416. An unranged read above the deployment's whole-read
|
|
3362
|
+
ceiling is the typed 413 (`invalid_input`, param `Range`, details
|
|
3363
|
+
`size_bytes` / `max_unranged_bytes`) — read it in slices.
|
|
3364
|
+
`X-Source` names the source that answered, `X-Ms` the server time.
|
|
3365
|
+
A symlink reads as its target (one hop). A path the file system
|
|
3366
|
+
does not hold is 404 `not_found`; on a captured read, a file the
|
|
3367
|
+
run never touched is 404 `not_captured` (only the image holds it).
|
|
3368
|
+
A stream that breaks after the headers ends with an aborted
|
|
3369
|
+
connection, never a partial body delivered as success.
|
|
3370
|
+
parameters:
|
|
3371
|
+
- $ref: '#/components/parameters/AnalysisId'
|
|
3372
|
+
- name: path
|
|
3373
|
+
in: path
|
|
3374
|
+
required: true
|
|
3375
|
+
description: The absolute box path, e.g. `app/work/main.py` for `/app/work/main.py` (the leading slash is the route's).
|
|
3376
|
+
schema:
|
|
3377
|
+
type: string
|
|
3378
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
3379
|
+
- name: Range
|
|
3380
|
+
in: header
|
|
3381
|
+
description: Optional single byte range (`bytes=a-b` / `bytes=a-` / `bytes=-n`).
|
|
3382
|
+
schema:
|
|
3383
|
+
type: string
|
|
3384
|
+
responses:
|
|
3385
|
+
'200':
|
|
3386
|
+
description: The whole file (`X-Source`, `X-Ms`).
|
|
3387
|
+
content:
|
|
3388
|
+
application/octet-stream:
|
|
3389
|
+
schema:
|
|
3390
|
+
type: string
|
|
3391
|
+
format: binary
|
|
3392
|
+
'206':
|
|
3393
|
+
description: The requested byte range (`Content-Range` states position and size).
|
|
3394
|
+
content:
|
|
3395
|
+
application/octet-stream:
|
|
3396
|
+
schema:
|
|
3397
|
+
type: string
|
|
3398
|
+
format: binary
|
|
3399
|
+
'400':
|
|
3400
|
+
$ref: '#/components/responses/BadRequest'
|
|
3401
|
+
'401':
|
|
3402
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3403
|
+
'404':
|
|
3404
|
+
$ref: '#/components/responses/NotFound'
|
|
3405
|
+
'409':
|
|
3406
|
+
description: >
|
|
3407
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
3408
|
+
`source=capture` before a capture exists (details carry the
|
|
3409
|
+
requested source and the state).
|
|
3410
|
+
content:
|
|
3411
|
+
application/json:
|
|
3412
|
+
schema:
|
|
3413
|
+
$ref: '#/components/schemas/Error'
|
|
3414
|
+
'413':
|
|
3415
|
+
description: >
|
|
3416
|
+
An unranged read above the whole-read ceiling (`invalid_input`,
|
|
3417
|
+
param `Range`; details `size_bytes` / `max_unranged_bytes`).
|
|
3418
|
+
content:
|
|
3419
|
+
application/json:
|
|
3420
|
+
schema:
|
|
3421
|
+
$ref: '#/components/schemas/Error'
|
|
3422
|
+
'416':
|
|
3423
|
+
description: >
|
|
3424
|
+
Range selects nothing inside the file (`invalid_input`;
|
|
3425
|
+
`Content-Range` carries `bytes */<size>`).
|
|
3426
|
+
content:
|
|
3427
|
+
application/json:
|
|
3428
|
+
schema:
|
|
3429
|
+
$ref: '#/components/schemas/Error'
|
|
3430
|
+
'503':
|
|
3431
|
+
description: >
|
|
3432
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
3433
|
+
retry after `Retry-After`.
|
|
3434
|
+
content:
|
|
3435
|
+
application/json:
|
|
3436
|
+
schema:
|
|
3437
|
+
$ref: '#/components/schemas/Error'
|
|
3438
|
+
'429':
|
|
3439
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3440
|
+
'500':
|
|
3441
|
+
$ref: '#/components/responses/InternalError'
|
|
3442
|
+
|
|
3443
|
+
/api/analyses/{analysisId}/filesystem/search:
|
|
3444
|
+
get:
|
|
3445
|
+
tags: [analyses]
|
|
3446
|
+
operationId: searchAnalysisFilesystem
|
|
3447
|
+
summary: Search the analysis run's file system for text
|
|
3448
|
+
description: |
|
|
3449
|
+
Content search: `q` is the text (or, with `regex=true`, the
|
|
3450
|
+
pattern), `path` the folder to search under (default `/` — the
|
|
3451
|
+
whole box, `scope: "box"`, which can take seconds; a folder answers
|
|
3452
|
+
`scope: "path"` in well under a second), `limit` the hit cap
|
|
3453
|
+
(default 200, max 1000). `truncated: true` means more hits exist or
|
|
3454
|
+
the search budget ran out — narrow the path or the text. Live: the
|
|
3455
|
+
box is searched as it is; captured: the kept text is searched, and
|
|
3456
|
+
`image_files_excluded: true` says files the run never touched were
|
|
3457
|
+
not searchable. Binary files never hit.
|
|
3458
|
+
parameters:
|
|
3459
|
+
- $ref: '#/components/parameters/AnalysisId'
|
|
3460
|
+
- name: q
|
|
3461
|
+
in: query
|
|
3462
|
+
required: true
|
|
3463
|
+
description: The text to find; a regular expression with `regex=true`.
|
|
3464
|
+
schema:
|
|
3465
|
+
type: string
|
|
3466
|
+
- $ref: '#/components/parameters/FilesystemPath'
|
|
3467
|
+
- name: regex
|
|
3468
|
+
in: query
|
|
3469
|
+
description: Treat `q` as a regular expression (default false — a plain substring).
|
|
3470
|
+
schema:
|
|
3471
|
+
type: boolean
|
|
3472
|
+
default: false
|
|
3473
|
+
- $ref: '#/components/parameters/FilesystemLimit'
|
|
3474
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
3475
|
+
responses:
|
|
3476
|
+
'200':
|
|
3477
|
+
description: The hits found.
|
|
3478
|
+
content:
|
|
3479
|
+
application/json:
|
|
3480
|
+
schema:
|
|
3481
|
+
$ref: '#/components/schemas/FilesystemSearchResult'
|
|
3482
|
+
'400':
|
|
3483
|
+
$ref: '#/components/responses/BadRequest'
|
|
3484
|
+
'401':
|
|
3485
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3486
|
+
'404':
|
|
3487
|
+
$ref: '#/components/responses/NotFound'
|
|
3488
|
+
'409':
|
|
3489
|
+
description: >
|
|
3490
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
3491
|
+
`source=capture` before a capture exists (details carry the
|
|
3492
|
+
requested source and the state).
|
|
3493
|
+
content:
|
|
3494
|
+
application/json:
|
|
3495
|
+
schema:
|
|
3496
|
+
$ref: '#/components/schemas/Error'
|
|
3497
|
+
'503':
|
|
3498
|
+
description: >
|
|
3499
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
3500
|
+
retry after `Retry-After`.
|
|
3501
|
+
content:
|
|
3502
|
+
application/json:
|
|
3503
|
+
schema:
|
|
3504
|
+
$ref: '#/components/schemas/Error'
|
|
3505
|
+
'429':
|
|
3506
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3507
|
+
'500':
|
|
3508
|
+
$ref: '#/components/responses/InternalError'
|
|
3509
|
+
|
|
3510
|
+
/api/analyses/{analysisId}/filesystem/events:
|
|
3511
|
+
get:
|
|
3512
|
+
tags: [analyses]
|
|
3513
|
+
operationId: streamAnalysisFilesystemEvents
|
|
3514
|
+
summary: Change events while the analysis run's box lives (SSE)
|
|
3515
|
+
description: |
|
|
3516
|
+
Server-sent events. `event: state` first (`{state, box}`), then
|
|
3517
|
+
`event: fs` per change (`{seq, t, path, type: create|write|remove|
|
|
3518
|
+
rename, source: watch|poll}`, `id: <seq>`), `event: ping` every
|
|
3519
|
+
15 s. Resume with `Last-Event-ID: <seq>` (or `?after=`): the events
|
|
3520
|
+
after it replay when the server still holds them; when it does not,
|
|
3521
|
+
a fresh `state` frame is the signal to relist the open folders.
|
|
3522
|
+
On a provider without a native watcher (`watcher: "poll"` on the
|
|
3523
|
+
status route) events come from polling the folders declared with
|
|
3524
|
+
`POST …/filesystem/watch`, so declare them. A `state` frame follows
|
|
3525
|
+
every change of state; the stream ends once the file system settles
|
|
3526
|
+
(`captured` or `none`).
|
|
3527
|
+
parameters:
|
|
3528
|
+
- $ref: '#/components/parameters/AnalysisId'
|
|
3529
|
+
- name: Last-Event-ID
|
|
3530
|
+
in: header
|
|
3531
|
+
description: Resume after this event seq.
|
|
3532
|
+
schema:
|
|
3533
|
+
type: string
|
|
3534
|
+
- name: after
|
|
3535
|
+
in: query
|
|
3536
|
+
description: The same as `Last-Event-ID`, for clients that cannot set headers.
|
|
3537
|
+
schema:
|
|
3538
|
+
type: string
|
|
3539
|
+
responses:
|
|
3540
|
+
'200':
|
|
3541
|
+
description: The event stream.
|
|
3542
|
+
content:
|
|
3543
|
+
text/event-stream:
|
|
3544
|
+
schema:
|
|
3545
|
+
type: string
|
|
3546
|
+
'400':
|
|
3547
|
+
$ref: '#/components/responses/BadRequest'
|
|
3548
|
+
'401':
|
|
3549
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3550
|
+
'404':
|
|
3551
|
+
$ref: '#/components/responses/NotFound'
|
|
3552
|
+
'503':
|
|
3553
|
+
description: >
|
|
3554
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
3555
|
+
retry after `Retry-After`.
|
|
3556
|
+
content:
|
|
3557
|
+
application/json:
|
|
3558
|
+
schema:
|
|
3559
|
+
$ref: '#/components/schemas/Error'
|
|
3560
|
+
'429':
|
|
3561
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3562
|
+
'500':
|
|
3563
|
+
$ref: '#/components/responses/InternalError'
|
|
3564
|
+
|
|
3565
|
+
/api/analyses/{analysisId}/filesystem/watch:
|
|
3566
|
+
post:
|
|
3567
|
+
tags: [analyses]
|
|
3568
|
+
operationId: watchAnalysisFilesystem
|
|
3569
|
+
summary: Declare the folders the viewer has open
|
|
3570
|
+
description: |
|
|
3571
|
+
The folders whose changes the event stream must report on a
|
|
3572
|
+
provider without a native watcher (`watcher: "poll"`): idempotent —
|
|
3573
|
+
the body's `paths` REPLACES the set; an empty set stops polling. At
|
|
3574
|
+
most 8 folders at once (a bigger set is the typed 400 naming the
|
|
3575
|
+
bound). On a provider with a native watcher the set is accepted
|
|
3576
|
+
and unused. Refused with `filesystem_state` when the box is gone.
|
|
3577
|
+
parameters:
|
|
3578
|
+
- $ref: '#/components/parameters/AnalysisId'
|
|
3579
|
+
requestBody:
|
|
3580
|
+
required: true
|
|
3581
|
+
content:
|
|
3582
|
+
application/json:
|
|
3583
|
+
schema:
|
|
3584
|
+
$ref: '#/components/schemas/FilesystemWatchRequest'
|
|
3585
|
+
responses:
|
|
3586
|
+
'200':
|
|
3587
|
+
description: The set in force.
|
|
3588
|
+
content:
|
|
3589
|
+
application/json:
|
|
3590
|
+
schema:
|
|
3591
|
+
$ref: '#/components/schemas/FilesystemWatchResult'
|
|
3592
|
+
'400':
|
|
3593
|
+
$ref: '#/components/responses/BadRequest'
|
|
3594
|
+
'401':
|
|
3595
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3596
|
+
'404':
|
|
3597
|
+
$ref: '#/components/responses/NotFound'
|
|
3598
|
+
'409':
|
|
3599
|
+
description: >
|
|
3600
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
3601
|
+
`source=capture` before a capture exists (details carry the
|
|
3602
|
+
requested source and the state).
|
|
3603
|
+
content:
|
|
3604
|
+
application/json:
|
|
3605
|
+
schema:
|
|
3606
|
+
$ref: '#/components/schemas/Error'
|
|
3607
|
+
'503':
|
|
3608
|
+
description: >
|
|
3609
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
3610
|
+
retry after `Retry-After`.
|
|
3611
|
+
content:
|
|
3612
|
+
application/json:
|
|
3613
|
+
schema:
|
|
3614
|
+
$ref: '#/components/schemas/Error'
|
|
3615
|
+
'429':
|
|
3616
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3617
|
+
'500':
|
|
3618
|
+
$ref: '#/components/responses/InternalError'
|
|
3619
|
+
|
|
3620
|
+
/api/analyses/{analysisId}/filesystem/changes:
|
|
3621
|
+
get:
|
|
3622
|
+
tags: [analyses]
|
|
3623
|
+
operationId: listAnalysisFilesystemChanges
|
|
3624
|
+
summary: The files the analysis run changed
|
|
3625
|
+
description: |
|
|
3626
|
+
The flat list of what the run created, modified or removed since its
|
|
3627
|
+
box started, with `phase` (`setup` | `agent` | `verifier`); `total`
|
|
3628
|
+
and `changed_bytes` are the whole list's, `items` one page (`cursor`
|
|
3629
|
+
= an opaque position, `limit` default 500, max 1000); `phase=`
|
|
3630
|
+
narrows to one phase. Captured: stored with the kept tree. Live: the
|
|
3631
|
+
box start listing against a fresh one, seconds per call; a box whose
|
|
3632
|
+
start listing was not stored is the typed 422.
|
|
3633
|
+
parameters:
|
|
3634
|
+
- $ref: '#/components/parameters/AnalysisId'
|
|
3635
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
3636
|
+
- name: phase
|
|
3637
|
+
in: query
|
|
3638
|
+
description: Only changes of one phase (default all).
|
|
3639
|
+
schema:
|
|
3640
|
+
type: string
|
|
3641
|
+
enum: [setup, agent, verifier, all]
|
|
3642
|
+
default: all
|
|
3643
|
+
- $ref: '#/components/parameters/FilesystemCursor'
|
|
3644
|
+
- $ref: '#/components/parameters/FilesystemLimit'
|
|
3645
|
+
responses:
|
|
3646
|
+
'200':
|
|
3647
|
+
description: One page of the changed-files list.
|
|
3648
|
+
content:
|
|
3649
|
+
application/json:
|
|
3650
|
+
schema:
|
|
3651
|
+
$ref: '#/components/schemas/FilesystemChanges'
|
|
3652
|
+
'400':
|
|
3653
|
+
$ref: '#/components/responses/BadRequest'
|
|
3654
|
+
'401':
|
|
3655
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3656
|
+
'404':
|
|
3657
|
+
$ref: '#/components/responses/NotFound'
|
|
3658
|
+
'409':
|
|
3659
|
+
description: >
|
|
3660
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
3661
|
+
`source=capture` before a capture exists (details carry the
|
|
3662
|
+
requested source and the state).
|
|
3663
|
+
content:
|
|
3664
|
+
application/json:
|
|
3665
|
+
schema:
|
|
3666
|
+
$ref: '#/components/schemas/Error'
|
|
3667
|
+
'422':
|
|
3668
|
+
description: >
|
|
3669
|
+
`feature_unsupported` — the shape or the provider has no live view
|
|
3670
|
+
of what was asked (details.cause names it).
|
|
3671
|
+
content:
|
|
3672
|
+
application/json:
|
|
3673
|
+
schema:
|
|
3674
|
+
$ref: '#/components/schemas/Error'
|
|
3675
|
+
'503':
|
|
3676
|
+
description: >
|
|
3677
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
3678
|
+
retry after `Retry-After`.
|
|
3679
|
+
content:
|
|
3680
|
+
application/json:
|
|
3681
|
+
schema:
|
|
3682
|
+
$ref: '#/components/schemas/Error'
|
|
3683
|
+
'429':
|
|
3684
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3685
|
+
'500':
|
|
3686
|
+
$ref: '#/components/responses/InternalError'
|
|
3687
|
+
|
|
3688
|
+
/api/analyses/{analysisId}/filesystem/archive:
|
|
3689
|
+
get:
|
|
3690
|
+
tags: [analyses]
|
|
3691
|
+
operationId: downloadAnalysisFilesystemArchive
|
|
3692
|
+
summary: Download one subtree of the analysis run's file system as a .tar.gz
|
|
3693
|
+
description: |
|
|
3694
|
+
A gzipped tarball of the subtree under `path` (default `/`, the
|
|
3695
|
+
whole tree), streamed. Captured: only the kept bytes ride; the
|
|
3696
|
+
files the run never touched are listed in `MANIFEST.tsv` at the
|
|
3697
|
+
archive root with `captured=false`. Live: read out of the running
|
|
3698
|
+
box under the capture budget — a subtree too large to leave the box
|
|
3699
|
+
inside it is refused up front, 422 `feature_unsupported` with the
|
|
3700
|
+
size in `details.cause`; a read-out that still stalls past the
|
|
3701
|
+
budget aborts the connection, never a truncated archive delivered
|
|
3702
|
+
as success. `X-Source` names the source. A folder the file system
|
|
3703
|
+
does not hold is 404 `not_found`.
|
|
3704
|
+
parameters:
|
|
3705
|
+
- $ref: '#/components/parameters/AnalysisId'
|
|
3706
|
+
- $ref: '#/components/parameters/FilesystemPath'
|
|
3707
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
3708
|
+
responses:
|
|
3709
|
+
'200':
|
|
3710
|
+
description: The archive (`Content-Disposition` names it `<id>_filesystem.tar.gz`).
|
|
3711
|
+
content:
|
|
3712
|
+
application/gzip:
|
|
3713
|
+
schema:
|
|
3714
|
+
type: string
|
|
3715
|
+
format: binary
|
|
3716
|
+
'400':
|
|
3717
|
+
$ref: '#/components/responses/BadRequest'
|
|
3718
|
+
'401':
|
|
3719
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3720
|
+
'404':
|
|
3721
|
+
$ref: '#/components/responses/NotFound'
|
|
3722
|
+
'409':
|
|
3723
|
+
description: >
|
|
3724
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
3725
|
+
`source=capture` before a capture exists (details carry the
|
|
3726
|
+
requested source and the state).
|
|
3727
|
+
content:
|
|
3728
|
+
application/json:
|
|
3729
|
+
schema:
|
|
3730
|
+
$ref: '#/components/schemas/Error'
|
|
3731
|
+
'422':
|
|
3732
|
+
description: >
|
|
3733
|
+
`feature_unsupported` — the provider has no live view of what was
|
|
3734
|
+
asked, or the live subtree cannot leave the box inside the
|
|
3735
|
+
capture budget (details.cause names it, with the size).
|
|
3736
|
+
content:
|
|
3737
|
+
application/json:
|
|
3738
|
+
schema:
|
|
3739
|
+
$ref: '#/components/schemas/Error'
|
|
3740
|
+
'503':
|
|
3741
|
+
description: >
|
|
3742
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
3743
|
+
retry after `Retry-After`.
|
|
3744
|
+
content:
|
|
3745
|
+
application/json:
|
|
3746
|
+
schema:
|
|
3747
|
+
$ref: '#/components/schemas/Error'
|
|
3748
|
+
'429':
|
|
3749
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3750
|
+
'500':
|
|
3751
|
+
$ref: '#/components/responses/InternalError'
|
|
3752
|
+
|
|
3753
|
+
/api/analyses/{analysisId}/logs:
|
|
3754
|
+
get:
|
|
3755
|
+
tags: [analyses]
|
|
3756
|
+
operationId: getAnalysisSandboxLog
|
|
3757
|
+
summary: One page of a sandbox log stream of the analysis run
|
|
3758
|
+
description: |
|
|
3759
|
+
The box's own streams, recorded while it runs and kept after:
|
|
3760
|
+
`agent` (the harness's stdout/stderr), `verifier` (the verifier
|
|
3761
|
+
command's) and `system` (the box's system log — only when the job
|
|
3762
|
+
asked for it, `JobCreate.system_log`). `setup` and `metrics` are
|
|
3763
|
+
named but not recorded today. Lines are `{seq, t, fd: out|err, line}`;
|
|
3764
|
+
`cursor` is an opaque position, `limit` default 1000, max 1000. A
|
|
3765
|
+
stream the platform holds nothing for answers an empty page whose
|
|
3766
|
+
`reason` says why — never an error.
|
|
3767
|
+
parameters:
|
|
3768
|
+
- $ref: '#/components/parameters/AnalysisId'
|
|
3769
|
+
- name: stream
|
|
3770
|
+
in: query
|
|
3771
|
+
required: true
|
|
3772
|
+
schema:
|
|
3773
|
+
$ref: '#/components/schemas/SandboxLogStream'
|
|
3774
|
+
- $ref: '#/components/parameters/FilesystemCursor'
|
|
3775
|
+
- $ref: '#/components/parameters/FilesystemLimit'
|
|
3776
|
+
responses:
|
|
3777
|
+
'200':
|
|
3778
|
+
description: One page of the stream.
|
|
3779
|
+
content:
|
|
3780
|
+
application/json:
|
|
3781
|
+
schema:
|
|
3782
|
+
$ref: '#/components/schemas/SandboxLogLines'
|
|
3783
|
+
'400':
|
|
3784
|
+
$ref: '#/components/responses/BadRequest'
|
|
3785
|
+
'401':
|
|
3786
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3787
|
+
'404':
|
|
3788
|
+
$ref: '#/components/responses/NotFound'
|
|
3789
|
+
'503':
|
|
3790
|
+
description: >
|
|
3791
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
3792
|
+
retry after `Retry-After`.
|
|
3793
|
+
content:
|
|
3794
|
+
application/json:
|
|
3795
|
+
schema:
|
|
3796
|
+
$ref: '#/components/schemas/Error'
|
|
3797
|
+
'429':
|
|
3798
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3799
|
+
'500':
|
|
3800
|
+
$ref: '#/components/responses/InternalError'
|
|
3801
|
+
|
|
3802
|
+
/api/analyses/{analysisId}/logs/events:
|
|
3803
|
+
get:
|
|
3804
|
+
tags: [analyses]
|
|
3805
|
+
operationId: streamAnalysisSandboxLogs
|
|
3806
|
+
summary: Sandbox log lines as they arrive (SSE)
|
|
3807
|
+
description: |
|
|
3808
|
+
Server-sent events over every stream at once: `event: line`
|
|
3809
|
+
(`{stream, seq, t, fd, line}`, `id: <stream>:<seq>`), `event: state`
|
|
3810
|
+
on open and on every change of the box's state, `event: ping` every
|
|
3811
|
+
15 s. Without
|
|
3812
|
+
`Last-Event-ID` every stream replays from its beginning and then
|
|
3813
|
+
follows; with `Last-Event-ID: <stream>:<seq>` that stream resumes
|
|
3814
|
+
after the seq the paged GET handed out. Once the box is gone and
|
|
3815
|
+
every recorded line has been sent, the stream ends — the paged GET
|
|
3816
|
+
is the reader after that.
|
|
3817
|
+
parameters:
|
|
3818
|
+
- $ref: '#/components/parameters/AnalysisId'
|
|
3819
|
+
- name: Last-Event-ID
|
|
3820
|
+
in: header
|
|
3821
|
+
description: Resume one stream after `<stream>:<seq>`.
|
|
3822
|
+
schema:
|
|
3823
|
+
type: string
|
|
3824
|
+
responses:
|
|
3825
|
+
'200':
|
|
3826
|
+
description: The event stream.
|
|
3827
|
+
content:
|
|
3828
|
+
text/event-stream:
|
|
3829
|
+
schema:
|
|
3830
|
+
type: string
|
|
3831
|
+
'400':
|
|
3832
|
+
$ref: '#/components/responses/BadRequest'
|
|
3833
|
+
'401':
|
|
3834
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3835
|
+
'404':
|
|
3836
|
+
$ref: '#/components/responses/NotFound'
|
|
3837
|
+
'503':
|
|
3838
|
+
description: >
|
|
3839
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
3840
|
+
retry after `Retry-After`.
|
|
3841
|
+
content:
|
|
3842
|
+
application/json:
|
|
3843
|
+
schema:
|
|
3844
|
+
$ref: '#/components/schemas/Error'
|
|
3845
|
+
'429':
|
|
3846
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3847
|
+
'500':
|
|
3848
|
+
$ref: '#/components/responses/InternalError'
|
|
3849
|
+
|
|
3850
|
+
/api/analyses/{analysisId}/procs:
|
|
3851
|
+
get:
|
|
3852
|
+
tags: [analyses]
|
|
3853
|
+
operationId: getAnalysisProcs
|
|
3854
|
+
summary: The analysis run's box process list (live only)
|
|
3855
|
+
description: |
|
|
3856
|
+
The processes running in the box right now, as one text listing
|
|
3857
|
+
(`ps` sorted by memory; on an image without `ps`, the same table
|
|
3858
|
+
read from `/proc`, its first line saying so). Live only: once the
|
|
3859
|
+
box is gone the answer is 409 `filesystem_state`.
|
|
3860
|
+
parameters:
|
|
3861
|
+
- $ref: '#/components/parameters/AnalysisId'
|
|
3862
|
+
responses:
|
|
3863
|
+
'200':
|
|
3864
|
+
description: The listing.
|
|
3865
|
+
content:
|
|
3866
|
+
application/json:
|
|
3867
|
+
schema:
|
|
3868
|
+
$ref: '#/components/schemas/SandboxProcs'
|
|
3869
|
+
'401':
|
|
3870
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3871
|
+
'404':
|
|
3872
|
+
$ref: '#/components/responses/NotFound'
|
|
3873
|
+
'409':
|
|
3874
|
+
description: >
|
|
3875
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
3876
|
+
`source=capture` before a capture exists (details carry the
|
|
3877
|
+
requested source and the state).
|
|
3878
|
+
content:
|
|
3879
|
+
application/json:
|
|
3880
|
+
schema:
|
|
3881
|
+
$ref: '#/components/schemas/Error'
|
|
3882
|
+
'503':
|
|
3883
|
+
description: >
|
|
3884
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
3885
|
+
retry after `Retry-After`.
|
|
3886
|
+
content:
|
|
3887
|
+
application/json:
|
|
3888
|
+
schema:
|
|
3889
|
+
$ref: '#/components/schemas/Error'
|
|
3890
|
+
'429':
|
|
3891
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
3892
|
+
'500':
|
|
3893
|
+
$ref: '#/components/responses/InternalError'
|
|
3894
|
+
|
|
3895
|
+
|
|
2557
3896
|
/api/analyses/{analysisId}/download:
|
|
2558
3897
|
get:
|
|
2559
|
-
tags: [analyses]
|
|
2560
|
-
operationId: downloadAnalysis
|
|
2561
|
-
summary: Download one analysis run as Harbor's wrapper-trial folder
|
|
3898
|
+
tags: [analyses]
|
|
3899
|
+
operationId: downloadAnalysis
|
|
3900
|
+
summary: Download one analysis run as Harbor's wrapper-trial folder
|
|
3901
|
+
description: |
|
|
3902
|
+
One `.tar.gz` holding the analysis run laid out exactly as the
|
|
3903
|
+
trial directory Harbor's `harbor analyze` leaves on disk for it —
|
|
3904
|
+
the WRAPPER trial (their analyze/analyzer.py assemble_analyze_task
|
|
3905
|
+
wraps one analyzed trial in a generated task named
|
|
3906
|
+
`analyze-<trial dir>` and runs it as a Harbor trial; the folder is
|
|
3907
|
+
that trial's, models/trial/paths.py TrialPaths). The archive
|
|
3908
|
+
extracts to one directory named as Harbor names a trial
|
|
3909
|
+
(`<task name>__<7 chars>`, here `analyze-<analyzed trial dir>__…`):
|
|
3910
|
+
|
|
3911
|
+
analyze-<trial>__<7>/
|
|
3912
|
+
├── config.json TrialConfig, partial: the wrapper
|
|
3913
|
+
│ task's name, the agent (claude-code,
|
|
3914
|
+
│ the model), and under `x_evolve`
|
|
3915
|
+
│ the frozen policy — rubric, prompt,
|
|
3916
|
+
│ reasoning_effort — plus the analyzed
|
|
3917
|
+
│ trial/job/task and the provider
|
|
3918
|
+
├── lock.json TrialLock, partial: the agent and
|
|
3919
|
+
│ its model (no task digest exists —
|
|
3920
|
+
│ the wrapper task is never assembled
|
|
3921
|
+
│ here; see the x_evolve note below)
|
|
3922
|
+
├── result.json TrialResult: the wrapper name,
|
|
3923
|
+
│ agent_info, agent_result (tokens,
|
|
3924
|
+
│ measured cost), verifier_result
|
|
3925
|
+
│ (reward 1 = a valid analysis.json,
|
|
3926
|
+
│ 0 = the validator refused it),
|
|
3927
|
+
│ exception_info on an infrastructure
|
|
3928
|
+
│ failure, the timings, and under
|
|
3929
|
+
│ `x_evolve` the run's own facts
|
|
3930
|
+
│ (status, attempts, the typed failure,
|
|
3931
|
+
│ the box, the meter, and the task
|
|
3932
|
+
│ package's fate — `taskContent`
|
|
3933
|
+
│ retained_package|absent, `taskAbsentReason`
|
|
3934
|
+
│ when absent)
|
|
3935
|
+
├── trial.log the worker's phase log, rendered
|
|
3936
|
+
│ deterministically (the trial tree's
|
|
3937
|
+
│ own renderer)
|
|
3938
|
+
├── exception.txt when the run failed OUTSIDE the
|
|
3939
|
+
│ validator (an infrastructure phase)
|
|
3940
|
+
├── agent/
|
|
3941
|
+
│ ├── claude-code.txt the analyzer's stdout stream at
|
|
3942
|
+
│ │ Harbor's own tee name for claude-code
|
|
3943
|
+
│ ├── stderr.log its stderr, when stored
|
|
3944
|
+
│ ├── trace-parsed.jsonl the run's parsed event trace
|
|
3945
|
+
│ ├── .claude/ … the captured home at its real names,
|
|
3946
|
+
│ ├── agent-home.json the capture record beside it
|
|
3947
|
+
│ └── sessions/ … Harbor's own copy of the .claude/
|
|
3948
|
+
│ subtree (claude_code.py:482)
|
|
3949
|
+
├── verifier/ ONLY when the validator ruled —
|
|
3950
|
+
│ │ completed, or failed `invalid_result`
|
|
3951
|
+
│ ├── test-stdout.txt the validator's printed reasons
|
|
3952
|
+
│ │ (empty on a valid result, as
|
|
3953
|
+
│ │ Harbor's validate.py prints nothing)
|
|
3954
|
+
│ ├── reward.txt `1` or `0` — the exact bytes Harbor's
|
|
3955
|
+
│ │ wrapper test.sh writes
|
|
3956
|
+
│ └── reward.json {"reward": 1|0}
|
|
3957
|
+
└── artifacts/
|
|
3958
|
+
├── manifest.json always present — what was collected
|
|
3959
|
+
│ (`[]` when the run produced nothing)
|
|
3960
|
+
└── analysis.json the validated deliverable — summary
|
|
3961
|
+
+ checks — only on a completed run
|
|
3962
|
+
|
|
3963
|
+
The validator runs on the platform's worker, not inside the box
|
|
3964
|
+
(a recorded deviation: the rule is the platform's one result
|
|
3965
|
+
definition, which the box's validate.py records; the reasons are that
|
|
3966
|
+
definition's issues, one per line as `path: message`); the run's raw
|
|
3967
|
+
deliverable is not retained, so
|
|
3968
|
+
`artifacts/analysis.json` is the validated document in canonical
|
|
3969
|
+
JSON and a refused deliverable leaves no file. The image digest and
|
|
3970
|
+
the harness bundle version resolve per run but are not stored on
|
|
3971
|
+
the row, so `lock.json` cannot state them (capture-side, deferred).
|
|
3972
|
+
Data the platform does not hold is left out, never faked.
|
|
3973
|
+
|
|
3974
|
+
Deterministic: re-downloads are byte-identical (stored rows only,
|
|
3975
|
+
canonical JSON, fixed tar mtimes, zero gzip mtime). Readable by the
|
|
3976
|
+
analyzed job's creator and the owning organization's members;
|
|
3977
|
+
anyone else gets 404 `analysis_not_found`, indistinguishable from
|
|
3978
|
+
an id that does not exist. A run still queued or running refuses
|
|
3979
|
+
409 `analysis_not_terminal` — the folder is a record of a settled
|
|
3980
|
+
run.
|
|
3981
|
+
|
|
3982
|
+
`evolve analysis download <analysis-id>` extracts it and adds
|
|
3983
|
+
`evolve.json` (the platform record Harbor's layout has no slot for).
|
|
3984
|
+
parameters:
|
|
3985
|
+
- $ref: '#/components/parameters/AnalysisId'
|
|
3986
|
+
responses:
|
|
3987
|
+
'200':
|
|
3988
|
+
description: The archive.
|
|
3989
|
+
content:
|
|
3990
|
+
application/gzip:
|
|
3991
|
+
schema:
|
|
3992
|
+
type: string
|
|
3993
|
+
format: binary
|
|
3994
|
+
'401':
|
|
3995
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3996
|
+
'404':
|
|
3997
|
+
$ref: '#/components/responses/NotFound'
|
|
3998
|
+
'409':
|
|
3999
|
+
description: The analysis is still queued or running (`analysis_not_terminal`).
|
|
4000
|
+
content:
|
|
4001
|
+
application/json:
|
|
4002
|
+
schema:
|
|
4003
|
+
$ref: '#/components/schemas/Error'
|
|
4004
|
+
'429':
|
|
4005
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
4006
|
+
'500':
|
|
4007
|
+
$ref: '#/components/responses/InternalError'
|
|
4008
|
+
|
|
4009
|
+
# ===========================================================================
|
|
4010
|
+
# Checks — task quality checks (Harbor's `harbor check`, hosted)
|
|
4011
|
+
# ===========================================================================
|
|
4012
|
+
|
|
4013
|
+
/api/checks:
|
|
4014
|
+
post:
|
|
4015
|
+
tags: [checks]
|
|
4016
|
+
operationId: createCheck
|
|
4017
|
+
summary: Check task quality against a rubric (Harbor's `harbor check`)
|
|
4018
|
+
description: |
|
|
4019
|
+
Harbor's `harbor check <PATH>` (their cli/analyze.py:84-207
|
|
4020
|
+
check_command; analyze/checker.py run_checks), hosted: PATH — one
|
|
4021
|
+
task directory, or a directory of task directories — arrives as a
|
|
4022
|
+
gzipped tarball (`archive`), or a published dataset is named
|
|
4023
|
+
instead (`dataset`, the hosted form; `CheckRequest.dataset` states
|
|
4024
|
+
the deviation and its reason), and for each task directory it holds
|
|
4025
|
+
the checker agent (claude-code, Harbor's own check agent, in its own
|
|
4026
|
+
sandbox, under the network Harbor's check wrapper task gives it —
|
|
4027
|
+
open by default) reads EVERY file of the task and rules every rubric
|
|
4028
|
+
criterion `pass`, `fail`, `not_applicable` or `unknown` with a
|
|
4029
|
+
rationale and the evidence behind it, writing `check-result.json`
|
|
4030
|
+
(the platform's default check prompt and rubric, rendered through
|
|
4031
|
+
Harbor's own tokens and join; `prompt` and `rubric` replace them).
|
|
4032
|
+
**The response is the Check**
|
|
4033
|
+
(202): the record with one `results` entry per task, each `queued`
|
|
4034
|
+
— poll `GET /api/checks/{checkId}` to watch them settle (the
|
|
4035
|
+
`status` of the check reads `completed` once every task has).
|
|
4036
|
+
|
|
4037
|
+
Which task directories, exactly as Harbor decides it
|
|
4038
|
+
(checker.py:116-141 over the archive's listing): the archive root
|
|
4039
|
+
when it is a task directory (task.toml + environment/ +
|
|
4040
|
+
instruction.md + the test script of its `[environment].os` —
|
|
4041
|
+
tests/test.sh for linux, the default; tests/test.bat for windows;
|
|
4042
|
+
a `[[steps]]` task needs each step's instruction.md and its own or
|
|
4043
|
+
the shared test script — their Task.is_valid_dir), else every
|
|
4044
|
+
top-level directory that is one, sorted; then the
|
|
4045
|
+
`include_task_names` globs (any match keeps), the
|
|
4046
|
+
`exclude_task_names` globs (any match drops), then the first
|
|
4047
|
+
`n_tasks`. An empty selection is refused `no_checkable_tasks`
|
|
4048
|
+
(their "No valid task directories found", :140); nothing is stored.
|
|
4049
|
+
There is no task-count ceiling — Harbor's check has none (no
|
|
4050
|
+
invented number, owner 2026-09-13); the organization's
|
|
4051
|
+
`max_concurrent_analyses` paces the boxes. On the dataset form the
|
|
4052
|
+
same selection runs over the version's task names, and the same
|
|
4053
|
+
refusal answers. The `config`
|
|
4054
|
+
part is the JSON `CheckConfigInput`; absent or
|
|
4055
|
+
`{}` means the defaults (openrouter/deepseek/deepseek-v4.1-flash at its
|
|
4056
|
+
per-model effort, the platform's default check rubric — eleven
|
|
4057
|
+
criteria, `CheckConfigInput.rubric` names them).
|
|
4058
|
+
|
|
4059
|
+
The task bytes are never modified and never land anywhere but the
|
|
4060
|
+
checker's sandbox and the platform's rows: Harbor's own rule ("Do
|
|
4061
|
+
not modify any files under {task_path}"; nothing written into the
|
|
4062
|
+
reviewed directory — their report is the job dir's
|
|
4063
|
+
check_report.json). A checker run that completes without a valid
|
|
4064
|
+
`check-result.json` is automatically re-run at most once (fresh
|
|
4065
|
+
sandbox, same model and rubric; the task's `attempts` says how far
|
|
4066
|
+
the ladder went), the analyze verb's own hosted rule; a run cut by
|
|
4067
|
+
its budget settles `failed` with phase `timeout` at once and is
|
|
4068
|
+
never re-run.
|
|
4069
|
+
|
|
4070
|
+
Decision order: 400 `invalid_multipart` (not multipart, or a
|
|
4071
|
+
malformed body) → 413 `upload_too_large` (the archive over what the
|
|
4072
|
+
store can land or what the server's spool disk has free — both read
|
|
4073
|
+
live at the request, the refusal naming which; no platform number)
|
|
4074
|
+
→ 429
|
|
4075
|
+
`too_many_concurrent_check_uploads` (the server's spool bound,
|
|
4076
|
+
ruled at the archive part before its first byte) → 400
|
|
4077
|
+
`invalid_rubric` / `invalid_input` (the `config` part: the rubric
|
|
4078
|
+
grammar; then an off-roster model, a bad `prompt`, an off-lineup
|
|
4079
|
+
`sandbox_provider`, an off-vocabulary `reasoning_effort`, an
|
|
4080
|
+
out-of-range `n_concurrent`, a malformed glob list, an invalid
|
|
4081
|
+
`n_tasks` — in that order, the analyze door's own ladder under the
|
|
4082
|
+
`check.` prefix) → 400 `invalid_input` (both `archive` and `dataset`,
|
|
4083
|
+
or neither) → the dataset form's resolution refusals
|
|
4084
|
+
(`CheckRequest.dataset`) → 400 `invalid_archive` (not a readable gzipped
|
|
4085
|
+
tar, an unsafe entry, or a listing that would hold more heap than
|
|
4086
|
+
the server can still commit — read live, named in the refusal) →
|
|
4087
|
+
400 `no_checkable_tasks` → 202.
|
|
4088
|
+
requestBody:
|
|
4089
|
+
required: true
|
|
4090
|
+
content:
|
|
4091
|
+
multipart/form-data:
|
|
4092
|
+
schema:
|
|
4093
|
+
$ref: '#/components/schemas/CheckRequest'
|
|
4094
|
+
responses:
|
|
4095
|
+
'202':
|
|
4096
|
+
description: The check, its task checks queued.
|
|
4097
|
+
content:
|
|
4098
|
+
application/json:
|
|
4099
|
+
schema:
|
|
4100
|
+
$ref: '#/components/schemas/Check'
|
|
4101
|
+
'400':
|
|
4102
|
+
$ref: '#/components/responses/BadRequest'
|
|
4103
|
+
'401':
|
|
4104
|
+
$ref: '#/components/responses/Unauthorized'
|
|
4105
|
+
'413':
|
|
4106
|
+
description: The archive is over the physical ceiling read at the request — the store's, or the spool disk's (`upload_too_large`; details.max_bytes and details.source).
|
|
4107
|
+
content:
|
|
4108
|
+
application/json:
|
|
4109
|
+
schema:
|
|
4110
|
+
$ref: '#/components/schemas/Error'
|
|
4111
|
+
'429':
|
|
4112
|
+
description: >
|
|
4113
|
+
Two conditions, distinguished by code: `rate_limited` (the
|
|
4114
|
+
standard throttle — honor `Retry-After`), and
|
|
4115
|
+
`too_many_concurrent_check_uploads` — the server is already
|
|
4116
|
+
spooling its bound of concurrent check archives
|
|
4117
|
+
(`max_concurrent` in the details), refused before the first
|
|
4118
|
+
uploaded byte, with no `Retry-After` because the server cannot
|
|
4119
|
+
honestly compute one; retry when an in-flight upload finishes.
|
|
4120
|
+
content:
|
|
4121
|
+
application/json:
|
|
4122
|
+
schema:
|
|
4123
|
+
$ref: '#/components/schemas/Error'
|
|
4124
|
+
'500':
|
|
4125
|
+
$ref: '#/components/responses/InternalError'
|
|
4126
|
+
get:
|
|
4127
|
+
tags: [checks]
|
|
4128
|
+
operationId: listChecks
|
|
4129
|
+
summary: List task quality checks
|
|
2562
4130
|
description: |
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
`
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
4131
|
+
Every check the caller may read, newest first, cursor-paged — each
|
|
4132
|
+
item the full `Check` with its per-task results. Harbor has no
|
|
4133
|
+
check list (their check writes a local report per invocation);
|
|
4134
|
+
hosted, the run is a record of its own and this is its catalog.
|
|
4135
|
+
`scope=my` (the default) lists checks you created; `scope=shared`
|
|
4136
|
+
lists your organizations' checks that teammates created (the
|
|
4137
|
+
analyses list's own law, on the check's own org). Nothing is
|
|
4138
|
+
public, so Harbor's `all` is refused. `status` filters by the
|
|
4139
|
+
check's own ladder (`queued`, `running`, `completed`), repeatable
|
|
4140
|
+
and/or comma-separated; an unknown word is refused
|
|
4141
|
+
`invalid_input` with the ladder in `details.valid_statuses`.
|
|
4142
|
+
`dataset` narrows to the checks of one published dataset (the
|
|
4143
|
+
dataset form's `source.dataset`): `name` spans every version of
|
|
4144
|
+
it, `name@version` is one version — the spelling `CheckRequest.
|
|
4145
|
+
dataset` takes. Archive checks never match. A dataset the caller
|
|
4146
|
+
has no checks of is an ordinary empty page; a malformed value
|
|
4147
|
+
(an empty half around the `@`) is refused `invalid_input` on
|
|
4148
|
+
`dataset`.
|
|
4149
|
+
parameters:
|
|
4150
|
+
- $ref: '#/components/parameters/Limit'
|
|
4151
|
+
- $ref: '#/components/parameters/Cursor'
|
|
4152
|
+
- $ref: '#/components/parameters/ListScope'
|
|
4153
|
+
- name: status
|
|
4154
|
+
in: query
|
|
4155
|
+
schema:
|
|
4156
|
+
type: array
|
|
4157
|
+
items:
|
|
4158
|
+
type: string
|
|
4159
|
+
enum: [queued, running, completed]
|
|
4160
|
+
explode: true
|
|
4161
|
+
- name: dataset
|
|
4162
|
+
in: query
|
|
4163
|
+
description: >
|
|
4164
|
+
Only checks of this published dataset — `name` (every version)
|
|
4165
|
+
or `name@version` (one version), exact on the check's
|
|
4166
|
+
`source.dataset`.
|
|
4167
|
+
schema:
|
|
4168
|
+
type: string
|
|
4169
|
+
responses:
|
|
4170
|
+
'200':
|
|
4171
|
+
description: One page of checks.
|
|
4172
|
+
content:
|
|
4173
|
+
application/json:
|
|
4174
|
+
schema:
|
|
4175
|
+
$ref: '#/components/schemas/CheckPage'
|
|
4176
|
+
'400':
|
|
4177
|
+
$ref: '#/components/responses/BadRequest'
|
|
4178
|
+
'401':
|
|
4179
|
+
$ref: '#/components/responses/Unauthorized'
|
|
4180
|
+
'429':
|
|
4181
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
4182
|
+
'500':
|
|
4183
|
+
$ref: '#/components/responses/InternalError'
|
|
2571
4184
|
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
├── verifier/ ONLY when the validator ruled —
|
|
2611
|
-
│ │ completed, or failed `invalid_result`
|
|
2612
|
-
│ ├── test-stdout.txt the validator's printed reasons
|
|
2613
|
-
│ │ (empty on a valid result, as
|
|
2614
|
-
│ │ Harbor's validate.py prints nothing)
|
|
2615
|
-
│ ├── reward.txt `1` or `0` — the exact bytes Harbor's
|
|
2616
|
-
│ │ wrapper test.sh writes
|
|
2617
|
-
│ └── reward.json {"reward": 1|0}
|
|
2618
|
-
└── artifacts/
|
|
2619
|
-
├── manifest.json always present — what was collected
|
|
2620
|
-
│ (`[]` when the run produced nothing)
|
|
2621
|
-
└── analysis.json the validated deliverable — summary
|
|
2622
|
-
+ checks — only on a completed run
|
|
4185
|
+
/api/checks/defaults:
|
|
4186
|
+
get:
|
|
4187
|
+
tags: [checks]
|
|
4188
|
+
operationId: getCheckDefaults
|
|
4189
|
+
summary: The defaults a check runs under when its config names nothing
|
|
4190
|
+
description: |
|
|
4191
|
+
The resolved policy an empty `CheckConfigInput` falls back to — the
|
|
4192
|
+
five knobs the create door stamps on every check that names none:
|
|
4193
|
+
`model_name`, `rubric` (the platform's check rubric, the eleven
|
|
4194
|
+
criteria `CheckConfigInput` lists), `prompt` (the built-in check
|
|
4195
|
+
body, as the TEMPLATE a caller's own `prompt` replaces — with its
|
|
4196
|
+
`{task_path}`, `{file_tree}` and `{criteria_guidance}` slots
|
|
4197
|
+
unrendered; the output section Harbor appends is not part of it),
|
|
4198
|
+
`reasoning_effort` (the default model's per-model effort) and
|
|
4199
|
+
`sandbox_provider` (the fleet default). Read them to see what a
|
|
4200
|
+
bare `evolve check` runs under, or to start an edited rubric or
|
|
4201
|
+
prompt from the platform's own. `model_name` and `rubric` sent
|
|
4202
|
+
back resolve as if nothing was sent; `prompt`, `reasoning_effort`
|
|
4203
|
+
and `sandbox_provider` sent back are stored as named, so the check
|
|
4204
|
+
echoes the prompt text and keeps that effort and provider even
|
|
4205
|
+
when the fleet default later changes. Harbor
|
|
4206
|
+
has no such verb: its defaults are files on disk
|
|
4207
|
+
(cli/quality_checker/default-rubric.toml, analyze/prompts/
|
|
4208
|
+
check.txt), which a hosted caller cannot open — the hosted reading
|
|
4209
|
+
of the same files.
|
|
4210
|
+
responses:
|
|
4211
|
+
'200':
|
|
4212
|
+
description: The resolved defaults.
|
|
4213
|
+
content:
|
|
4214
|
+
application/json:
|
|
4215
|
+
schema:
|
|
4216
|
+
$ref: '#/components/schemas/CheckDefaults'
|
|
4217
|
+
'401':
|
|
4218
|
+
$ref: '#/components/responses/Unauthorized'
|
|
4219
|
+
'429':
|
|
4220
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
4221
|
+
'500':
|
|
4222
|
+
$ref: '#/components/responses/InternalError'
|
|
2623
4223
|
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
4224
|
+
/api/checks/{checkId}:
|
|
4225
|
+
get:
|
|
4226
|
+
tags: [checks]
|
|
4227
|
+
operationId: getCheck
|
|
4228
|
+
summary: Get one task quality check (the report)
|
|
4229
|
+
description: |
|
|
4230
|
+
The check with its per-task results — Harbor's CheckReport
|
|
4231
|
+
(`results`, their cli/quality_checker/models.py:38-41) plus the
|
|
4232
|
+
policy it ran under and its source. Readable by the creator and by
|
|
4233
|
+
every member of the owning organization; anyone else gets 404
|
|
4234
|
+
`check_not_found`, indistinguishable from an id that does not exist.
|
|
2634
4235
|
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
4236
|
+
Each task's result (`results[].id`) is also a run of its own, read
|
|
4237
|
+
exactly like an analysis run (owner ruling 2026-09-09): the
|
|
4238
|
+
checker's live trace, raw streams, agent home and its result file
|
|
4239
|
+
(`check-result.json`, Harbor's name for the checker's deliverable —
|
|
4240
|
+
checker.py:37) are served by the traces feed's per-run doors under
|
|
4241
|
+
the task check's id — the doors `evolve check trace` and `evolve
|
|
4242
|
+
check download` ride — under the check's own access law (creator or
|
|
4243
|
+
org member). A task check is stoppable there too (the feed's stop
|
|
4244
|
+
verb), one task at a time.
|
|
4245
|
+
parameters:
|
|
4246
|
+
- $ref: '#/components/parameters/CheckId'
|
|
4247
|
+
responses:
|
|
4248
|
+
'200':
|
|
4249
|
+
description: The check.
|
|
4250
|
+
content:
|
|
4251
|
+
application/json:
|
|
4252
|
+
schema:
|
|
4253
|
+
$ref: '#/components/schemas/Check'
|
|
4254
|
+
'401':
|
|
4255
|
+
$ref: '#/components/responses/Unauthorized'
|
|
4256
|
+
'404':
|
|
4257
|
+
$ref: '#/components/responses/NotFound'
|
|
4258
|
+
'429':
|
|
4259
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
4260
|
+
'500':
|
|
4261
|
+
$ref: '#/components/responses/InternalError'
|
|
4262
|
+
|
|
4263
|
+
/api/checks/{checkId}/tasks/{taskCheckId}/filesystem:
|
|
4264
|
+
get:
|
|
4265
|
+
tags: [checks]
|
|
4266
|
+
operationId: getTaskCheckFilesystem
|
|
4267
|
+
summary: The task check's file system — which source it has
|
|
4268
|
+
description: |
|
|
4269
|
+
The Files surface of one task check (the file system family, one shape
|
|
4270
|
+
under every run owner: trials, analyses, task checks — and the task
|
|
4271
|
+
package as a fourth, read-only owner). `state` says what the
|
|
4272
|
+
listing, read, search, archive and change routes will answer from:
|
|
4273
|
+
`live` — the box is running and the routes read it as it changes;
|
|
4274
|
+
`captured` — the run ended and its file system was kept, the same
|
|
4275
|
+
routes read the kept tree; `capturing` — the run just ended and the
|
|
4276
|
+
capture is still being written; `none` — nothing to read yet (a
|
|
4277
|
+
queued run, a run older than the feature, a capture that failed —
|
|
4278
|
+
`capture.status` says which). `box` names the running box and its
|
|
4279
|
+
role, `watcher` how change events arrive (`native` from the
|
|
4280
|
+
provider, `poll` from the folders the viewer declared open), and
|
|
4281
|
+
`capture` the kept tree's record: when, after which phase, how many
|
|
4282
|
+
entries and changed files, `ready` | `incomplete` (`left_out` names
|
|
4283
|
+
what did not fit the budget) | `failed`.
|
|
4284
|
+
parameters:
|
|
4285
|
+
- $ref: '#/components/parameters/CheckId'
|
|
4286
|
+
- $ref: '#/components/parameters/TaskCheckId'
|
|
4287
|
+
responses:
|
|
4288
|
+
'200':
|
|
4289
|
+
description: The file system's state.
|
|
4290
|
+
content:
|
|
4291
|
+
application/json:
|
|
4292
|
+
schema:
|
|
4293
|
+
$ref: '#/components/schemas/FilesystemStatus'
|
|
4294
|
+
'401':
|
|
4295
|
+
$ref: '#/components/responses/Unauthorized'
|
|
4296
|
+
'404':
|
|
4297
|
+
$ref: '#/components/responses/NotFound'
|
|
4298
|
+
'503':
|
|
4299
|
+
description: >
|
|
4300
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
4301
|
+
retry after `Retry-After`.
|
|
4302
|
+
content:
|
|
4303
|
+
application/json:
|
|
4304
|
+
schema:
|
|
4305
|
+
$ref: '#/components/schemas/Error'
|
|
4306
|
+
'429':
|
|
4307
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
4308
|
+
'500':
|
|
4309
|
+
$ref: '#/components/responses/InternalError'
|
|
4310
|
+
|
|
4311
|
+
/api/checks/{checkId}/tasks/{taskCheckId}/filesystem/files:
|
|
4312
|
+
get:
|
|
4313
|
+
tags: [checks]
|
|
4314
|
+
operationId: listTaskCheckFilesystemFolder
|
|
4315
|
+
summary: List one folder of the task check's file system
|
|
4316
|
+
description: |
|
|
4317
|
+
One page of a folder, sorted by name, paged with `cursor` (the last
|
|
4318
|
+
name served) and `limit` (default 500, max 1000). `source` forces
|
|
4319
|
+
`live` or `capture`; omitted, whichever the run has (`state` on the
|
|
4320
|
+
status route). Every entry carries its type (`dir` | `file` |
|
|
4321
|
+
`symlink` — with `target` — | `other`), size, mtime, mode and owner;
|
|
4322
|
+
`changed` and `phase` say whether the run created or modified it
|
|
4323
|
+
and in which phase (null when not known for the source); on a
|
|
4324
|
+
captured listing `captured: false` marks a file the run never
|
|
4325
|
+
touched, which only the image holds — it lists but does not open.
|
|
4326
|
+
The kernel trees (`/proc`, `/sys`, `/dev`) are never listed.
|
|
4327
|
+
parameters:
|
|
4328
|
+
- $ref: '#/components/parameters/CheckId'
|
|
4329
|
+
- $ref: '#/components/parameters/TaskCheckId'
|
|
4330
|
+
- $ref: '#/components/parameters/FilesystemPath'
|
|
4331
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
4332
|
+
- $ref: '#/components/parameters/FilesystemCursor'
|
|
4333
|
+
- $ref: '#/components/parameters/FilesystemLimit'
|
|
4334
|
+
responses:
|
|
4335
|
+
'200':
|
|
4336
|
+
description: One page of the folder.
|
|
4337
|
+
content:
|
|
4338
|
+
application/json:
|
|
4339
|
+
schema:
|
|
4340
|
+
$ref: '#/components/schemas/FilesystemListing'
|
|
4341
|
+
'400':
|
|
4342
|
+
$ref: '#/components/responses/BadRequest'
|
|
4343
|
+
'401':
|
|
4344
|
+
$ref: '#/components/responses/Unauthorized'
|
|
4345
|
+
'404':
|
|
4346
|
+
$ref: '#/components/responses/NotFound'
|
|
4347
|
+
'409':
|
|
4348
|
+
description: >
|
|
4349
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
4350
|
+
`source=capture` before a capture exists (details carry the
|
|
4351
|
+
requested source and the state).
|
|
4352
|
+
content:
|
|
4353
|
+
application/json:
|
|
4354
|
+
schema:
|
|
4355
|
+
$ref: '#/components/schemas/Error'
|
|
4356
|
+
'503':
|
|
4357
|
+
description: >
|
|
4358
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
4359
|
+
retry after `Retry-After`.
|
|
4360
|
+
content:
|
|
4361
|
+
application/json:
|
|
4362
|
+
schema:
|
|
4363
|
+
$ref: '#/components/schemas/Error'
|
|
4364
|
+
'429':
|
|
4365
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
4366
|
+
'500':
|
|
4367
|
+
$ref: '#/components/responses/InternalError'
|
|
2642
4368
|
|
|
2643
|
-
|
|
2644
|
-
|
|
4369
|
+
/api/checks/{checkId}/tasks/{taskCheckId}/filesystem/files/{path}:
|
|
4370
|
+
get:
|
|
4371
|
+
tags: [checks]
|
|
4372
|
+
operationId: readTaskCheckFilesystemFile
|
|
4373
|
+
summary: Read one file of the task check's file system, raw bytes
|
|
4374
|
+
description: |
|
|
4375
|
+
RAW BYTES of one file — application/octet-stream, byte fidelity, no
|
|
4376
|
+
translation (whether it is text is the reader's call: the first
|
|
4377
|
+
4 KiB, a NUL byte means binary). A standard single `Range` header
|
|
4378
|
+
(`bytes=a-b`, `bytes=a-`, `bytes=-n`) reads a slice and answers 206
|
|
4379
|
+
with `Content-Range`; `Accept-Ranges: bytes` advertises it; a
|
|
4380
|
+
malformed or multi-range header is the typed 400, an out-of-file
|
|
4381
|
+
range the 416. An unranged read above the deployment's whole-read
|
|
4382
|
+
ceiling is the typed 413 (`invalid_input`, param `Range`, details
|
|
4383
|
+
`size_bytes` / `max_unranged_bytes`) — read it in slices.
|
|
4384
|
+
`X-Source` names the source that answered, `X-Ms` the server time.
|
|
4385
|
+
A symlink reads as its target (one hop). A path the file system
|
|
4386
|
+
does not hold is 404 `not_found`; on a captured read, a file the
|
|
4387
|
+
run never touched is 404 `not_captured` (only the image holds it).
|
|
4388
|
+
A stream that breaks after the headers ends with an aborted
|
|
4389
|
+
connection, never a partial body delivered as success.
|
|
2645
4390
|
parameters:
|
|
2646
|
-
- $ref: '#/components/parameters/
|
|
4391
|
+
- $ref: '#/components/parameters/CheckId'
|
|
4392
|
+
- $ref: '#/components/parameters/TaskCheckId'
|
|
4393
|
+
- name: path
|
|
4394
|
+
in: path
|
|
4395
|
+
required: true
|
|
4396
|
+
description: The absolute box path, e.g. `app/work/main.py` for `/app/work/main.py` (the leading slash is the route's).
|
|
4397
|
+
schema:
|
|
4398
|
+
type: string
|
|
4399
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
4400
|
+
- name: Range
|
|
4401
|
+
in: header
|
|
4402
|
+
description: Optional single byte range (`bytes=a-b` / `bytes=a-` / `bytes=-n`).
|
|
4403
|
+
schema:
|
|
4404
|
+
type: string
|
|
2647
4405
|
responses:
|
|
2648
4406
|
'200':
|
|
2649
|
-
description: The
|
|
4407
|
+
description: The whole file (`X-Source`, `X-Ms`).
|
|
2650
4408
|
content:
|
|
2651
|
-
application/
|
|
4409
|
+
application/octet-stream:
|
|
2652
4410
|
schema:
|
|
2653
4411
|
type: string
|
|
2654
4412
|
format: binary
|
|
4413
|
+
'206':
|
|
4414
|
+
description: The requested byte range (`Content-Range` states position and size).
|
|
4415
|
+
content:
|
|
4416
|
+
application/octet-stream:
|
|
4417
|
+
schema:
|
|
4418
|
+
type: string
|
|
4419
|
+
format: binary
|
|
4420
|
+
'400':
|
|
4421
|
+
$ref: '#/components/responses/BadRequest'
|
|
2655
4422
|
'401':
|
|
2656
4423
|
$ref: '#/components/responses/Unauthorized'
|
|
2657
4424
|
'404':
|
|
2658
4425
|
$ref: '#/components/responses/NotFound'
|
|
2659
4426
|
'409':
|
|
2660
|
-
description:
|
|
4427
|
+
description: >
|
|
4428
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
4429
|
+
`source=capture` before a capture exists (details carry the
|
|
4430
|
+
requested source and the state).
|
|
4431
|
+
content:
|
|
4432
|
+
application/json:
|
|
4433
|
+
schema:
|
|
4434
|
+
$ref: '#/components/schemas/Error'
|
|
4435
|
+
'413':
|
|
4436
|
+
description: >
|
|
4437
|
+
An unranged read above the whole-read ceiling (`invalid_input`,
|
|
4438
|
+
param `Range`; details `size_bytes` / `max_unranged_bytes`).
|
|
4439
|
+
content:
|
|
4440
|
+
application/json:
|
|
4441
|
+
schema:
|
|
4442
|
+
$ref: '#/components/schemas/Error'
|
|
4443
|
+
'416':
|
|
4444
|
+
description: >
|
|
4445
|
+
Range selects nothing inside the file (`invalid_input`;
|
|
4446
|
+
`Content-Range` carries `bytes */<size>`).
|
|
4447
|
+
content:
|
|
4448
|
+
application/json:
|
|
4449
|
+
schema:
|
|
4450
|
+
$ref: '#/components/schemas/Error'
|
|
4451
|
+
'503':
|
|
4452
|
+
description: >
|
|
4453
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
4454
|
+
retry after `Retry-After`.
|
|
2661
4455
|
content:
|
|
2662
4456
|
application/json:
|
|
2663
4457
|
schema:
|
|
@@ -2667,206 +4461,467 @@ paths:
|
|
|
2667
4461
|
'500':
|
|
2668
4462
|
$ref: '#/components/responses/InternalError'
|
|
2669
4463
|
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
# ===========================================================================
|
|
2673
|
-
|
|
2674
|
-
/api/checks:
|
|
2675
|
-
post:
|
|
4464
|
+
/api/checks/{checkId}/tasks/{taskCheckId}/filesystem/search:
|
|
4465
|
+
get:
|
|
2676
4466
|
tags: [checks]
|
|
2677
|
-
operationId:
|
|
2678
|
-
summary:
|
|
4467
|
+
operationId: searchTaskCheckFilesystem
|
|
4468
|
+
summary: Search the task check's file system for text
|
|
2679
4469
|
description: |
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
the
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
4470
|
+
Content search: `q` is the text (or, with `regex=true`, the
|
|
4471
|
+
pattern), `path` the folder to search under (default `/` — the
|
|
4472
|
+
whole box, `scope: "box"`, which can take seconds; a folder answers
|
|
4473
|
+
`scope: "path"` in well under a second), `limit` the hit cap
|
|
4474
|
+
(default 200, max 1000). `truncated: true` means more hits exist or
|
|
4475
|
+
the search budget ran out — narrow the path or the text. Live: the
|
|
4476
|
+
box is searched as it is; captured: the kept text is searched, and
|
|
4477
|
+
`image_files_excluded: true` says files the run never touched were
|
|
4478
|
+
not searchable. Binary files never hit.
|
|
4479
|
+
parameters:
|
|
4480
|
+
- $ref: '#/components/parameters/CheckId'
|
|
4481
|
+
- $ref: '#/components/parameters/TaskCheckId'
|
|
4482
|
+
- name: q
|
|
4483
|
+
in: query
|
|
4484
|
+
required: true
|
|
4485
|
+
description: The text to find; a regular expression with `regex=true`.
|
|
4486
|
+
schema:
|
|
4487
|
+
type: string
|
|
4488
|
+
- $ref: '#/components/parameters/FilesystemPath'
|
|
4489
|
+
- name: regex
|
|
4490
|
+
in: query
|
|
4491
|
+
description: Treat `q` as a regular expression (default false — a plain substring).
|
|
4492
|
+
schema:
|
|
4493
|
+
type: boolean
|
|
4494
|
+
default: false
|
|
4495
|
+
- $ref: '#/components/parameters/FilesystemLimit'
|
|
4496
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
4497
|
+
responses:
|
|
4498
|
+
'200':
|
|
4499
|
+
description: The hits found.
|
|
4500
|
+
content:
|
|
4501
|
+
application/json:
|
|
4502
|
+
schema:
|
|
4503
|
+
$ref: '#/components/schemas/FilesystemSearchResult'
|
|
4504
|
+
'400':
|
|
4505
|
+
$ref: '#/components/responses/BadRequest'
|
|
4506
|
+
'401':
|
|
4507
|
+
$ref: '#/components/responses/Unauthorized'
|
|
4508
|
+
'404':
|
|
4509
|
+
$ref: '#/components/responses/NotFound'
|
|
4510
|
+
'409':
|
|
4511
|
+
description: >
|
|
4512
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
4513
|
+
`source=capture` before a capture exists (details carry the
|
|
4514
|
+
requested source and the state).
|
|
4515
|
+
content:
|
|
4516
|
+
application/json:
|
|
4517
|
+
schema:
|
|
4518
|
+
$ref: '#/components/schemas/Error'
|
|
4519
|
+
'503':
|
|
4520
|
+
description: >
|
|
4521
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
4522
|
+
retry after `Retry-After`.
|
|
4523
|
+
content:
|
|
4524
|
+
application/json:
|
|
4525
|
+
schema:
|
|
4526
|
+
$ref: '#/components/schemas/Error'
|
|
4527
|
+
'429':
|
|
4528
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
4529
|
+
'500':
|
|
4530
|
+
$ref: '#/components/responses/InternalError'
|
|
2719
4531
|
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
4532
|
+
/api/checks/{checkId}/tasks/{taskCheckId}/filesystem/events:
|
|
4533
|
+
get:
|
|
4534
|
+
tags: [checks]
|
|
4535
|
+
operationId: streamTaskCheckFilesystemEvents
|
|
4536
|
+
summary: Change events while the task check's box lives (SSE)
|
|
4537
|
+
description: |
|
|
4538
|
+
Server-sent events. `event: state` first (`{state, box}`), then
|
|
4539
|
+
`event: fs` per change (`{seq, t, path, type: create|write|remove|
|
|
4540
|
+
rename, source: watch|poll}`, `id: <seq>`), `event: ping` every
|
|
4541
|
+
15 s. Resume with `Last-Event-ID: <seq>` (or `?after=`): the events
|
|
4542
|
+
after it replay when the server still holds them; when it does not,
|
|
4543
|
+
a fresh `state` frame is the signal to relist the open folders.
|
|
4544
|
+
On a provider without a native watcher (`watcher: "poll"` on the
|
|
4545
|
+
status route) events come from polling the folders declared with
|
|
4546
|
+
`POST …/filesystem/watch`, so declare them. A `state` frame follows
|
|
4547
|
+
every change of state; the stream ends once the file system settles
|
|
4548
|
+
(`captured` or `none`).
|
|
4549
|
+
parameters:
|
|
4550
|
+
- $ref: '#/components/parameters/CheckId'
|
|
4551
|
+
- $ref: '#/components/parameters/TaskCheckId'
|
|
4552
|
+
- name: Last-Event-ID
|
|
4553
|
+
in: header
|
|
4554
|
+
description: Resume after this event seq.
|
|
4555
|
+
schema:
|
|
4556
|
+
type: string
|
|
4557
|
+
- name: after
|
|
4558
|
+
in: query
|
|
4559
|
+
description: The same as `Last-Event-ID`, for clients that cannot set headers.
|
|
4560
|
+
schema:
|
|
4561
|
+
type: string
|
|
4562
|
+
responses:
|
|
4563
|
+
'200':
|
|
4564
|
+
description: The event stream.
|
|
4565
|
+
content:
|
|
4566
|
+
text/event-stream:
|
|
4567
|
+
schema:
|
|
4568
|
+
type: string
|
|
4569
|
+
'400':
|
|
4570
|
+
$ref: '#/components/responses/BadRequest'
|
|
4571
|
+
'401':
|
|
4572
|
+
$ref: '#/components/responses/Unauthorized'
|
|
4573
|
+
'404':
|
|
4574
|
+
$ref: '#/components/responses/NotFound'
|
|
4575
|
+
'503':
|
|
4576
|
+
description: >
|
|
4577
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
4578
|
+
retry after `Retry-After`.
|
|
4579
|
+
content:
|
|
4580
|
+
application/json:
|
|
4581
|
+
schema:
|
|
4582
|
+
$ref: '#/components/schemas/Error'
|
|
4583
|
+
'429':
|
|
4584
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
4585
|
+
'500':
|
|
4586
|
+
$ref: '#/components/responses/InternalError'
|
|
2730
4587
|
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
tar, an unsafe entry, or a listing that would hold more heap than
|
|
2747
|
-
the server can still commit — read live, named in the refusal) →
|
|
2748
|
-
400 `no_checkable_tasks` → 202.
|
|
4588
|
+
/api/checks/{checkId}/tasks/{taskCheckId}/filesystem/watch:
|
|
4589
|
+
post:
|
|
4590
|
+
tags: [checks]
|
|
4591
|
+
operationId: watchTaskCheckFilesystem
|
|
4592
|
+
summary: Declare the folders the viewer has open
|
|
4593
|
+
description: |
|
|
4594
|
+
The folders whose changes the event stream must report on a
|
|
4595
|
+
provider without a native watcher (`watcher: "poll"`): idempotent —
|
|
4596
|
+
the body's `paths` REPLACES the set; an empty set stops polling. At
|
|
4597
|
+
most 8 folders at once (a bigger set is the typed 400 naming the
|
|
4598
|
+
bound). On a provider with a native watcher the set is accepted
|
|
4599
|
+
and unused. Refused with `filesystem_state` when the box is gone.
|
|
4600
|
+
parameters:
|
|
4601
|
+
- $ref: '#/components/parameters/CheckId'
|
|
4602
|
+
- $ref: '#/components/parameters/TaskCheckId'
|
|
2749
4603
|
requestBody:
|
|
2750
4604
|
required: true
|
|
2751
4605
|
content:
|
|
2752
|
-
|
|
4606
|
+
application/json:
|
|
2753
4607
|
schema:
|
|
2754
|
-
$ref: '#/components/schemas/
|
|
4608
|
+
$ref: '#/components/schemas/FilesystemWatchRequest'
|
|
2755
4609
|
responses:
|
|
2756
|
-
'
|
|
2757
|
-
description: The
|
|
4610
|
+
'200':
|
|
4611
|
+
description: The set in force.
|
|
4612
|
+
content:
|
|
4613
|
+
application/json:
|
|
4614
|
+
schema:
|
|
4615
|
+
$ref: '#/components/schemas/FilesystemWatchResult'
|
|
4616
|
+
'400':
|
|
4617
|
+
$ref: '#/components/responses/BadRequest'
|
|
4618
|
+
'401':
|
|
4619
|
+
$ref: '#/components/responses/Unauthorized'
|
|
4620
|
+
'404':
|
|
4621
|
+
$ref: '#/components/responses/NotFound'
|
|
4622
|
+
'409':
|
|
4623
|
+
description: >
|
|
4624
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
4625
|
+
`source=capture` before a capture exists (details carry the
|
|
4626
|
+
requested source and the state).
|
|
4627
|
+
content:
|
|
4628
|
+
application/json:
|
|
4629
|
+
schema:
|
|
4630
|
+
$ref: '#/components/schemas/Error'
|
|
4631
|
+
'503':
|
|
4632
|
+
description: >
|
|
4633
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
4634
|
+
retry after `Retry-After`.
|
|
4635
|
+
content:
|
|
4636
|
+
application/json:
|
|
4637
|
+
schema:
|
|
4638
|
+
$ref: '#/components/schemas/Error'
|
|
4639
|
+
'429':
|
|
4640
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
4641
|
+
'500':
|
|
4642
|
+
$ref: '#/components/responses/InternalError'
|
|
4643
|
+
|
|
4644
|
+
/api/checks/{checkId}/tasks/{taskCheckId}/filesystem/changes:
|
|
4645
|
+
get:
|
|
4646
|
+
tags: [checks]
|
|
4647
|
+
operationId: listTaskCheckFilesystemChanges
|
|
4648
|
+
summary: The files the task check changed
|
|
4649
|
+
description: |
|
|
4650
|
+
The flat list of what the run created, modified or removed since its
|
|
4651
|
+
box started, with `phase` (`setup` | `agent` | `verifier`); `total`
|
|
4652
|
+
and `changed_bytes` are the whole list's, `items` one page (`cursor`
|
|
4653
|
+
= an opaque position, `limit` default 500, max 1000); `phase=`
|
|
4654
|
+
narrows to one phase. Captured: stored with the kept tree. Live: the
|
|
4655
|
+
box start listing against a fresh one, seconds per call; a box whose
|
|
4656
|
+
start listing was not stored is the typed 422.
|
|
4657
|
+
parameters:
|
|
4658
|
+
- $ref: '#/components/parameters/CheckId'
|
|
4659
|
+
- $ref: '#/components/parameters/TaskCheckId'
|
|
4660
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
4661
|
+
- name: phase
|
|
4662
|
+
in: query
|
|
4663
|
+
description: Only changes of one phase (default all).
|
|
4664
|
+
schema:
|
|
4665
|
+
type: string
|
|
4666
|
+
enum: [setup, agent, verifier, all]
|
|
4667
|
+
default: all
|
|
4668
|
+
- $ref: '#/components/parameters/FilesystemCursor'
|
|
4669
|
+
- $ref: '#/components/parameters/FilesystemLimit'
|
|
4670
|
+
responses:
|
|
4671
|
+
'200':
|
|
4672
|
+
description: One page of the changed-files list.
|
|
4673
|
+
content:
|
|
4674
|
+
application/json:
|
|
4675
|
+
schema:
|
|
4676
|
+
$ref: '#/components/schemas/FilesystemChanges'
|
|
4677
|
+
'400':
|
|
4678
|
+
$ref: '#/components/responses/BadRequest'
|
|
4679
|
+
'401':
|
|
4680
|
+
$ref: '#/components/responses/Unauthorized'
|
|
4681
|
+
'404':
|
|
4682
|
+
$ref: '#/components/responses/NotFound'
|
|
4683
|
+
'409':
|
|
4684
|
+
description: >
|
|
4685
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
4686
|
+
`source=capture` before a capture exists (details carry the
|
|
4687
|
+
requested source and the state).
|
|
2758
4688
|
content:
|
|
2759
4689
|
application/json:
|
|
2760
4690
|
schema:
|
|
2761
|
-
$ref: '#/components/schemas/
|
|
4691
|
+
$ref: '#/components/schemas/Error'
|
|
4692
|
+
'422':
|
|
4693
|
+
description: >
|
|
4694
|
+
`feature_unsupported` — the shape or the provider has no live view
|
|
4695
|
+
of what was asked (details.cause names it).
|
|
4696
|
+
content:
|
|
4697
|
+
application/json:
|
|
4698
|
+
schema:
|
|
4699
|
+
$ref: '#/components/schemas/Error'
|
|
4700
|
+
'503':
|
|
4701
|
+
description: >
|
|
4702
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
4703
|
+
retry after `Retry-After`.
|
|
4704
|
+
content:
|
|
4705
|
+
application/json:
|
|
4706
|
+
schema:
|
|
4707
|
+
$ref: '#/components/schemas/Error'
|
|
4708
|
+
'429':
|
|
4709
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
4710
|
+
'500':
|
|
4711
|
+
$ref: '#/components/responses/InternalError'
|
|
4712
|
+
|
|
4713
|
+
/api/checks/{checkId}/tasks/{taskCheckId}/filesystem/archive:
|
|
4714
|
+
get:
|
|
4715
|
+
tags: [checks]
|
|
4716
|
+
operationId: downloadTaskCheckFilesystemArchive
|
|
4717
|
+
summary: Download one subtree of the task check's file system as a .tar.gz
|
|
4718
|
+
description: |
|
|
4719
|
+
A gzipped tarball of the subtree under `path` (default `/`, the
|
|
4720
|
+
whole tree), streamed. Captured: only the kept bytes ride; the
|
|
4721
|
+
files the run never touched are listed in `MANIFEST.tsv` at the
|
|
4722
|
+
archive root with `captured=false`. Live: read out of the running
|
|
4723
|
+
box under the capture budget — a subtree too large to leave the box
|
|
4724
|
+
inside it is refused up front, 422 `feature_unsupported` with the
|
|
4725
|
+
size in `details.cause`; a read-out that still stalls past the
|
|
4726
|
+
budget aborts the connection, never a truncated archive delivered
|
|
4727
|
+
as success. `X-Source` names the source. A folder the file system
|
|
4728
|
+
does not hold is 404 `not_found`.
|
|
4729
|
+
parameters:
|
|
4730
|
+
- $ref: '#/components/parameters/CheckId'
|
|
4731
|
+
- $ref: '#/components/parameters/TaskCheckId'
|
|
4732
|
+
- $ref: '#/components/parameters/FilesystemPath'
|
|
4733
|
+
- $ref: '#/components/parameters/FilesystemSource'
|
|
4734
|
+
responses:
|
|
4735
|
+
'200':
|
|
4736
|
+
description: The archive (`Content-Disposition` names it `<id>_filesystem.tar.gz`).
|
|
4737
|
+
content:
|
|
4738
|
+
application/gzip:
|
|
4739
|
+
schema:
|
|
4740
|
+
type: string
|
|
4741
|
+
format: binary
|
|
2762
4742
|
'400':
|
|
2763
4743
|
$ref: '#/components/responses/BadRequest'
|
|
2764
4744
|
'401':
|
|
2765
4745
|
$ref: '#/components/responses/Unauthorized'
|
|
2766
|
-
'
|
|
2767
|
-
|
|
4746
|
+
'404':
|
|
4747
|
+
$ref: '#/components/responses/NotFound'
|
|
4748
|
+
'409':
|
|
4749
|
+
description: >
|
|
4750
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
4751
|
+
`source=capture` before a capture exists (details carry the
|
|
4752
|
+
requested source and the state).
|
|
2768
4753
|
content:
|
|
2769
4754
|
application/json:
|
|
2770
4755
|
schema:
|
|
2771
4756
|
$ref: '#/components/schemas/Error'
|
|
2772
|
-
'
|
|
4757
|
+
'422':
|
|
2773
4758
|
description: >
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
4759
|
+
`feature_unsupported` — the provider has no live view of what was
|
|
4760
|
+
asked, or the live subtree cannot leave the box inside the
|
|
4761
|
+
capture budget (details.cause names it, with the size).
|
|
4762
|
+
content:
|
|
4763
|
+
application/json:
|
|
4764
|
+
schema:
|
|
4765
|
+
$ref: '#/components/schemas/Error'
|
|
4766
|
+
'503':
|
|
4767
|
+
description: >
|
|
4768
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
4769
|
+
retry after `Retry-After`.
|
|
2781
4770
|
content:
|
|
2782
4771
|
application/json:
|
|
2783
4772
|
schema:
|
|
2784
4773
|
$ref: '#/components/schemas/Error'
|
|
4774
|
+
'429':
|
|
4775
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
2785
4776
|
'500':
|
|
2786
4777
|
$ref: '#/components/responses/InternalError'
|
|
4778
|
+
|
|
4779
|
+
/api/checks/{checkId}/tasks/{taskCheckId}/logs:
|
|
2787
4780
|
get:
|
|
2788
4781
|
tags: [checks]
|
|
2789
|
-
operationId:
|
|
2790
|
-
summary:
|
|
4782
|
+
operationId: getTaskCheckSandboxLog
|
|
4783
|
+
summary: One page of a sandbox log stream of the task check
|
|
2791
4784
|
description: |
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
check's own ladder (`queued`, `running`, `completed`), repeatable
|
|
2801
|
-
and/or comma-separated; an unknown word is refused
|
|
2802
|
-
`invalid_input` with the ladder in `details.valid_statuses`.
|
|
4785
|
+
The box's own streams, recorded while it runs and kept after:
|
|
4786
|
+
`agent` (the harness's stdout/stderr), `verifier` (the verifier
|
|
4787
|
+
command's) and `system` (the box's system log — only when the job
|
|
4788
|
+
asked for it, `JobCreate.system_log`). `setup` and `metrics` are
|
|
4789
|
+
named but not recorded today. Lines are `{seq, t, fd: out|err, line}`;
|
|
4790
|
+
`cursor` is an opaque position, `limit` default 1000, max 1000. A
|
|
4791
|
+
stream the platform holds nothing for answers an empty page whose
|
|
4792
|
+
`reason` says why — never an error.
|
|
2803
4793
|
parameters:
|
|
2804
|
-
- $ref: '#/components/parameters/
|
|
2805
|
-
- $ref: '#/components/parameters/
|
|
2806
|
-
-
|
|
2807
|
-
- name: status
|
|
4794
|
+
- $ref: '#/components/parameters/CheckId'
|
|
4795
|
+
- $ref: '#/components/parameters/TaskCheckId'
|
|
4796
|
+
- name: stream
|
|
2808
4797
|
in: query
|
|
4798
|
+
required: true
|
|
2809
4799
|
schema:
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
enum: [queued, running, completed]
|
|
2814
|
-
explode: true
|
|
4800
|
+
$ref: '#/components/schemas/SandboxLogStream'
|
|
4801
|
+
- $ref: '#/components/parameters/FilesystemCursor'
|
|
4802
|
+
- $ref: '#/components/parameters/FilesystemLimit'
|
|
2815
4803
|
responses:
|
|
2816
4804
|
'200':
|
|
2817
|
-
description: One page of
|
|
4805
|
+
description: One page of the stream.
|
|
2818
4806
|
content:
|
|
2819
4807
|
application/json:
|
|
2820
4808
|
schema:
|
|
2821
|
-
$ref: '#/components/schemas/
|
|
4809
|
+
$ref: '#/components/schemas/SandboxLogLines'
|
|
2822
4810
|
'400':
|
|
2823
4811
|
$ref: '#/components/responses/BadRequest'
|
|
2824
4812
|
'401':
|
|
2825
4813
|
$ref: '#/components/responses/Unauthorized'
|
|
4814
|
+
'404':
|
|
4815
|
+
$ref: '#/components/responses/NotFound'
|
|
4816
|
+
'503':
|
|
4817
|
+
description: >
|
|
4818
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
4819
|
+
retry after `Retry-After`.
|
|
4820
|
+
content:
|
|
4821
|
+
application/json:
|
|
4822
|
+
schema:
|
|
4823
|
+
$ref: '#/components/schemas/Error'
|
|
2826
4824
|
'429':
|
|
2827
4825
|
$ref: '#/components/responses/TooManyRequests'
|
|
2828
4826
|
'500':
|
|
2829
4827
|
$ref: '#/components/responses/InternalError'
|
|
2830
4828
|
|
|
2831
|
-
/api/checks/{checkId}:
|
|
4829
|
+
/api/checks/{checkId}/tasks/{taskCheckId}/logs/events:
|
|
2832
4830
|
get:
|
|
2833
4831
|
tags: [checks]
|
|
2834
|
-
operationId:
|
|
2835
|
-
summary:
|
|
4832
|
+
operationId: streamTaskCheckSandboxLogs
|
|
4833
|
+
summary: Sandbox log lines as they arrive (SSE)
|
|
2836
4834
|
description: |
|
|
2837
|
-
|
|
2838
|
-
(`
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
`
|
|
4835
|
+
Server-sent events over every stream at once: `event: line`
|
|
4836
|
+
(`{stream, seq, t, fd, line}`, `id: <stream>:<seq>`), `event: state`
|
|
4837
|
+
on open and on every change of the box's state, `event: ping` every
|
|
4838
|
+
15 s. Without
|
|
4839
|
+
`Last-Event-ID` every stream replays from its beginning and then
|
|
4840
|
+
follows; with `Last-Event-ID: <stream>:<seq>` that stream resumes
|
|
4841
|
+
after the seq the paged GET handed out. Once the box is gone and
|
|
4842
|
+
every recorded line has been sent, the stream ends — the paged GET
|
|
4843
|
+
is the reader after that.
|
|
4844
|
+
parameters:
|
|
4845
|
+
- $ref: '#/components/parameters/CheckId'
|
|
4846
|
+
- $ref: '#/components/parameters/TaskCheckId'
|
|
4847
|
+
- name: Last-Event-ID
|
|
4848
|
+
in: header
|
|
4849
|
+
description: Resume one stream after `<stream>:<seq>`.
|
|
4850
|
+
schema:
|
|
4851
|
+
type: string
|
|
4852
|
+
responses:
|
|
4853
|
+
'200':
|
|
4854
|
+
description: The event stream.
|
|
4855
|
+
content:
|
|
4856
|
+
text/event-stream:
|
|
4857
|
+
schema:
|
|
4858
|
+
type: string
|
|
4859
|
+
'400':
|
|
4860
|
+
$ref: '#/components/responses/BadRequest'
|
|
4861
|
+
'401':
|
|
4862
|
+
$ref: '#/components/responses/Unauthorized'
|
|
4863
|
+
'404':
|
|
4864
|
+
$ref: '#/components/responses/NotFound'
|
|
4865
|
+
'503':
|
|
4866
|
+
description: >
|
|
4867
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
4868
|
+
retry after `Retry-After`.
|
|
4869
|
+
content:
|
|
4870
|
+
application/json:
|
|
4871
|
+
schema:
|
|
4872
|
+
$ref: '#/components/schemas/Error'
|
|
4873
|
+
'429':
|
|
4874
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
4875
|
+
'500':
|
|
4876
|
+
$ref: '#/components/responses/InternalError'
|
|
2842
4877
|
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
4878
|
+
/api/checks/{checkId}/tasks/{taskCheckId}/procs:
|
|
4879
|
+
get:
|
|
4880
|
+
tags: [checks]
|
|
4881
|
+
operationId: getTaskCheckProcs
|
|
4882
|
+
summary: The task check's box process list (live only)
|
|
4883
|
+
description: |
|
|
4884
|
+
The processes running in the box right now, as one text listing
|
|
4885
|
+
(`ps` sorted by memory; on an image without `ps`, the same table
|
|
4886
|
+
read from `/proc`, its first line saying so). Live only: once the
|
|
4887
|
+
box is gone the answer is 409 `filesystem_state`.
|
|
2852
4888
|
parameters:
|
|
2853
4889
|
- $ref: '#/components/parameters/CheckId'
|
|
4890
|
+
- $ref: '#/components/parameters/TaskCheckId'
|
|
2854
4891
|
responses:
|
|
2855
4892
|
'200':
|
|
2856
|
-
description: The
|
|
4893
|
+
description: The listing.
|
|
2857
4894
|
content:
|
|
2858
4895
|
application/json:
|
|
2859
4896
|
schema:
|
|
2860
|
-
$ref: '#/components/schemas/
|
|
4897
|
+
$ref: '#/components/schemas/SandboxProcs'
|
|
2861
4898
|
'401':
|
|
2862
4899
|
$ref: '#/components/responses/Unauthorized'
|
|
2863
4900
|
'404':
|
|
2864
4901
|
$ref: '#/components/responses/NotFound'
|
|
4902
|
+
'409':
|
|
4903
|
+
description: >
|
|
4904
|
+
`filesystem_state` — `source=live` while the box is gone, or
|
|
4905
|
+
`source=capture` before a capture exists (details carry the
|
|
4906
|
+
requested source and the state).
|
|
4907
|
+
content:
|
|
4908
|
+
application/json:
|
|
4909
|
+
schema:
|
|
4910
|
+
$ref: '#/components/schemas/Error'
|
|
4911
|
+
'503':
|
|
4912
|
+
description: >
|
|
4913
|
+
`provider_unreachable` — the box's provider did not answer;
|
|
4914
|
+
retry after `Retry-After`.
|
|
4915
|
+
content:
|
|
4916
|
+
application/json:
|
|
4917
|
+
schema:
|
|
4918
|
+
$ref: '#/components/schemas/Error'
|
|
2865
4919
|
'429':
|
|
2866
4920
|
$ref: '#/components/responses/TooManyRequests'
|
|
2867
4921
|
'500':
|
|
2868
4922
|
$ref: '#/components/responses/InternalError'
|
|
2869
4923
|
|
|
4924
|
+
|
|
2870
4925
|
/api/checks/{checkId}/download:
|
|
2871
4926
|
get:
|
|
2872
4927
|
tags: [checks]
|
|
@@ -3410,25 +5465,200 @@ paths:
|
|
|
3410
5465
|
required: true
|
|
3411
5466
|
schema:
|
|
3412
5467
|
type: string
|
|
3413
|
-
- name: task_name
|
|
5468
|
+
- name: task_name
|
|
5469
|
+
in: path
|
|
5470
|
+
required: true
|
|
5471
|
+
schema:
|
|
5472
|
+
type: string
|
|
5473
|
+
responses:
|
|
5474
|
+
'200':
|
|
5475
|
+
description: The task's build outcome.
|
|
5476
|
+
content:
|
|
5477
|
+
application/json:
|
|
5478
|
+
schema:
|
|
5479
|
+
$ref: '#/components/schemas/TaskBuild'
|
|
5480
|
+
'401':
|
|
5481
|
+
$ref: '#/components/responses/Unauthorized'
|
|
5482
|
+
'404':
|
|
5483
|
+
description: >
|
|
5484
|
+
`dataset_not_found`, `dataset_version_not_found`, or
|
|
5485
|
+
`task_not_found` (no build outcome recorded under that name in
|
|
5486
|
+
this version).
|
|
5487
|
+
content:
|
|
5488
|
+
application/json:
|
|
5489
|
+
schema:
|
|
5490
|
+
$ref: '#/components/schemas/Error'
|
|
5491
|
+
'429':
|
|
5492
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
5493
|
+
'500':
|
|
5494
|
+
$ref: '#/components/responses/InternalError'
|
|
5495
|
+
|
|
5496
|
+
/api/datasets/{name}/versions/{version}/tasks/{task_name}/filesystem:
|
|
5497
|
+
get:
|
|
5498
|
+
tags: [datasets]
|
|
5499
|
+
operationId: getTaskPackageFilesystem
|
|
5500
|
+
summary: The task package as a file system (status)
|
|
5501
|
+
description: |
|
|
5502
|
+
The task directory's files as the fourth, read-only owner of the
|
|
5503
|
+
file system family: served from the retained task package — the
|
|
5504
|
+
exact bytes the import stored, the ones every trial ran against.
|
|
5505
|
+
`state` is always `none` (no box, no capture), `source` is
|
|
5506
|
+
`package`; `package_retained` says whether the version keeps its
|
|
5507
|
+
package — one imported before packages were retained answers the
|
|
5508
|
+
listing and read with 409 `task_package_not_retained`. No events,
|
|
5509
|
+
no logs, no search beyond the path filter.
|
|
5510
|
+
parameters:
|
|
5511
|
+
- $ref: '#/components/parameters/DatasetName'
|
|
5512
|
+
- name: version
|
|
5513
|
+
in: path
|
|
5514
|
+
required: true
|
|
5515
|
+
schema:
|
|
5516
|
+
type: string
|
|
5517
|
+
- name: task_name
|
|
5518
|
+
in: path
|
|
5519
|
+
required: true
|
|
5520
|
+
schema:
|
|
5521
|
+
type: string
|
|
5522
|
+
responses:
|
|
5523
|
+
'200':
|
|
5524
|
+
description: The package owner's state.
|
|
5525
|
+
content:
|
|
5526
|
+
application/json:
|
|
5527
|
+
schema:
|
|
5528
|
+
$ref: '#/components/schemas/TaskPackageFilesystemStatus'
|
|
5529
|
+
'401':
|
|
5530
|
+
$ref: '#/components/responses/Unauthorized'
|
|
5531
|
+
'404':
|
|
5532
|
+
$ref: '#/components/responses/NotFound'
|
|
5533
|
+
'429':
|
|
5534
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
5535
|
+
'500':
|
|
5536
|
+
$ref: '#/components/responses/InternalError'
|
|
5537
|
+
|
|
5538
|
+
/api/datasets/{name}/versions/{version}/tasks/{task_name}/filesystem/files:
|
|
5539
|
+
get:
|
|
5540
|
+
tags: [datasets]
|
|
5541
|
+
operationId: listTaskPackageFolder
|
|
5542
|
+
summary: List one folder of the task package
|
|
5543
|
+
description: |
|
|
5544
|
+
The same page as a run's folder listing (`FilesystemListing`), over
|
|
5545
|
+
the task directory (`/` is the directory holding instruction.md,
|
|
5546
|
+
task.toml, environment/, tests/); `source` may only be `package`.
|
|
5547
|
+
Every file is held (`captured: true`); `changed` and `phase` are
|
|
5548
|
+
null. A version that keeps no package is 409
|
|
5549
|
+
`task_package_not_retained`.
|
|
5550
|
+
parameters:
|
|
5551
|
+
- $ref: '#/components/parameters/DatasetName'
|
|
5552
|
+
- name: version
|
|
5553
|
+
in: path
|
|
5554
|
+
required: true
|
|
5555
|
+
schema:
|
|
5556
|
+
type: string
|
|
5557
|
+
- name: task_name
|
|
5558
|
+
in: path
|
|
5559
|
+
required: true
|
|
5560
|
+
schema:
|
|
5561
|
+
type: string
|
|
5562
|
+
- $ref: '#/components/parameters/FilesystemPath'
|
|
5563
|
+
- $ref: '#/components/parameters/FilesystemCursor'
|
|
5564
|
+
- $ref: '#/components/parameters/FilesystemLimit'
|
|
5565
|
+
responses:
|
|
5566
|
+
'200':
|
|
5567
|
+
description: One page of the folder.
|
|
5568
|
+
content:
|
|
5569
|
+
application/json:
|
|
5570
|
+
schema:
|
|
5571
|
+
$ref: '#/components/schemas/FilesystemListing'
|
|
5572
|
+
'400':
|
|
5573
|
+
$ref: '#/components/responses/BadRequest'
|
|
5574
|
+
'401':
|
|
5575
|
+
$ref: '#/components/responses/Unauthorized'
|
|
5576
|
+
'404':
|
|
5577
|
+
$ref: '#/components/responses/NotFound'
|
|
5578
|
+
'409':
|
|
5579
|
+
description: '`task_package_not_retained` — the version keeps no package.'
|
|
5580
|
+
content:
|
|
5581
|
+
application/json:
|
|
5582
|
+
schema:
|
|
5583
|
+
$ref: '#/components/schemas/Error'
|
|
5584
|
+
'429':
|
|
5585
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
5586
|
+
'500':
|
|
5587
|
+
$ref: '#/components/responses/InternalError'
|
|
5588
|
+
|
|
5589
|
+
/api/datasets/{name}/versions/{version}/tasks/{task_name}/filesystem/files/{path}:
|
|
5590
|
+
get:
|
|
5591
|
+
tags: [datasets]
|
|
5592
|
+
operationId: readTaskPackageFile
|
|
5593
|
+
summary: Read one file of the task package, raw bytes
|
|
5594
|
+
description: |
|
|
5595
|
+
The run file read (`readTrialFilesystemFile`) over the task
|
|
5596
|
+
directory: raw bytes, a single `Range` honoured (206), the 413 above
|
|
5597
|
+
the whole-read ceiling, 404 `not_found` for a path the package does
|
|
5598
|
+
not hold, `X-Source: package`. A version that keeps no package is
|
|
5599
|
+
409 `task_package_not_retained`.
|
|
5600
|
+
parameters:
|
|
5601
|
+
- $ref: '#/components/parameters/DatasetName'
|
|
5602
|
+
- name: version
|
|
5603
|
+
in: path
|
|
5604
|
+
required: true
|
|
5605
|
+
schema:
|
|
5606
|
+
type: string
|
|
5607
|
+
- name: task_name
|
|
5608
|
+
in: path
|
|
5609
|
+
required: true
|
|
5610
|
+
schema:
|
|
5611
|
+
type: string
|
|
5612
|
+
- name: path
|
|
3414
5613
|
in: path
|
|
3415
5614
|
required: true
|
|
5615
|
+
description: The path inside the task directory, e.g. `tests/test.sh`.
|
|
5616
|
+
schema:
|
|
5617
|
+
type: string
|
|
5618
|
+
- name: Range
|
|
5619
|
+
in: header
|
|
5620
|
+
description: Optional single byte range (`bytes=a-b` / `bytes=a-` / `bytes=-n`).
|
|
3416
5621
|
schema:
|
|
3417
5622
|
type: string
|
|
3418
5623
|
responses:
|
|
3419
5624
|
'200':
|
|
3420
|
-
description: The
|
|
5625
|
+
description: The whole file.
|
|
3421
5626
|
content:
|
|
3422
|
-
application/
|
|
5627
|
+
application/octet-stream:
|
|
3423
5628
|
schema:
|
|
3424
|
-
|
|
5629
|
+
type: string
|
|
5630
|
+
format: binary
|
|
5631
|
+
'206':
|
|
5632
|
+
description: The requested byte range.
|
|
5633
|
+
content:
|
|
5634
|
+
application/octet-stream:
|
|
5635
|
+
schema:
|
|
5636
|
+
type: string
|
|
5637
|
+
format: binary
|
|
5638
|
+
'400':
|
|
5639
|
+
$ref: '#/components/responses/BadRequest'
|
|
3425
5640
|
'401':
|
|
3426
5641
|
$ref: '#/components/responses/Unauthorized'
|
|
3427
5642
|
'404':
|
|
5643
|
+
$ref: '#/components/responses/NotFound'
|
|
5644
|
+
'409':
|
|
5645
|
+
description: '`task_package_not_retained` — the version keeps no package.'
|
|
5646
|
+
content:
|
|
5647
|
+
application/json:
|
|
5648
|
+
schema:
|
|
5649
|
+
$ref: '#/components/schemas/Error'
|
|
5650
|
+
'413':
|
|
3428
5651
|
description: >
|
|
3429
|
-
|
|
3430
|
-
`
|
|
3431
|
-
|
|
5652
|
+
An unranged read above the whole-read ceiling (`invalid_input`,
|
|
5653
|
+
param `Range`; details `size_bytes` / `max_unranged_bytes`).
|
|
5654
|
+
content:
|
|
5655
|
+
application/json:
|
|
5656
|
+
schema:
|
|
5657
|
+
$ref: '#/components/schemas/Error'
|
|
5658
|
+
'416':
|
|
5659
|
+
description: >
|
|
5660
|
+
Range selects nothing inside the file (`invalid_input`;
|
|
5661
|
+
`Content-Range` carries `bytes */<size>`).
|
|
3432
5662
|
content:
|
|
3433
5663
|
application/json:
|
|
3434
5664
|
schema:
|
|
@@ -5053,6 +7283,11 @@ paths:
|
|
|
5053
7283
|
parameter: a session has one owner and no organization, so `my` is
|
|
5054
7284
|
the only visibility there is. The dashboard's own `admin=true` view
|
|
5055
7285
|
is a session-cookie door — an API key that sends it is refused 403.
|
|
7286
|
+
Each item (the same document `getSession` serves) carries the
|
|
7287
|
+
session's identity — `agent`, `model`, `provider`, `sandboxId` — and
|
|
7288
|
+
`reasoningEffort`, the effort the session was started with as the
|
|
7289
|
+
SDK resolved it; null for a harness without one and for sessions
|
|
7290
|
+
ingested before the field.
|
|
5056
7291
|
parameters:
|
|
5057
7292
|
- name: paginated
|
|
5058
7293
|
in: query
|
|
@@ -5178,7 +7413,13 @@ paths:
|
|
|
5178
7413
|
summary: Ingest session observability events
|
|
5179
7414
|
description: >
|
|
5180
7415
|
The SDK's observability push: session lifecycle and transcript events,
|
|
5181
|
-
batched. Returns `{ success: true }` on acceptance.
|
|
7416
|
+
batched. Returns `{ success: true }` on acceptance. The body carries
|
|
7417
|
+
the session's identity (`tag`, `provider`, `agent`, `model`,
|
|
7418
|
+
`sandboxId`, `timestamp`) beside the batch, and may carry
|
|
7419
|
+
`reasoningEffort` — the effort the session was started with, as the
|
|
7420
|
+
SDK resolved it: 1–32 characters of letters, digits, `_` or `-`,
|
|
7421
|
+
else 400 `invalid_input` naming the field. The first ingest of a
|
|
7422
|
+
session records it; a later ingest never overwrites a recorded value.
|
|
5182
7423
|
requestBody:
|
|
5183
7424
|
required: true
|
|
5184
7425
|
content:
|
|
@@ -6098,6 +8339,45 @@ components:
|
|
|
6098
8339
|
dataset route.
|
|
6099
8340
|
schema:
|
|
6100
8341
|
type: string
|
|
8342
|
+
TaskCheckId:
|
|
8343
|
+
name: taskCheckId
|
|
8344
|
+
in: path
|
|
8345
|
+
required: true
|
|
8346
|
+
description: One task check's id (`results[].id` on the check); its file system is its own, under the check that owns it.
|
|
8347
|
+
schema:
|
|
8348
|
+
type: string
|
|
8349
|
+
format: uuid
|
|
8350
|
+
FilesystemSource:
|
|
8351
|
+
name: source
|
|
8352
|
+
in: query
|
|
8353
|
+
description: >
|
|
8354
|
+
Force the source: `live` (the running box) or `capture` (the kept
|
|
8355
|
+
tree). Omitted, whichever the run has. A source that is not there
|
|
8356
|
+
is 409 `filesystem_state`.
|
|
8357
|
+
schema:
|
|
8358
|
+
type: string
|
|
8359
|
+
enum: [live, capture]
|
|
8360
|
+
FilesystemPath:
|
|
8361
|
+
name: path
|
|
8362
|
+
in: query
|
|
8363
|
+
description: An absolute box path (default `/`).
|
|
8364
|
+
schema:
|
|
8365
|
+
type: string
|
|
8366
|
+
default: /
|
|
8367
|
+
FilesystemCursor:
|
|
8368
|
+
name: cursor
|
|
8369
|
+
in: query
|
|
8370
|
+
description: Resume after this cursor (the previous page's `next_cursor`).
|
|
8371
|
+
schema:
|
|
8372
|
+
type: string
|
|
8373
|
+
FilesystemLimit:
|
|
8374
|
+
name: limit
|
|
8375
|
+
in: query
|
|
8376
|
+
description: Page size; the route's default, max 1000.
|
|
8377
|
+
schema:
|
|
8378
|
+
type: integer
|
|
8379
|
+
minimum: 1
|
|
8380
|
+
maximum: 1000
|
|
6101
8381
|
AgentName:
|
|
6102
8382
|
name: name
|
|
6103
8383
|
in: path
|
|
@@ -6539,6 +8819,13 @@ components:
|
|
|
6539
8819
|
- org_member_not_found
|
|
6540
8820
|
- invite_not_found
|
|
6541
8821
|
- invite_invalid
|
|
8822
|
+
# The file system + sandbox logs family (each code's meaning: its routes' responses).
|
|
8823
|
+
- not_found
|
|
8824
|
+
- not_captured
|
|
8825
|
+
- filesystem_state
|
|
8826
|
+
- feature_unsupported
|
|
8827
|
+
- provider_unreachable
|
|
8828
|
+
- task_package_not_retained
|
|
6542
8829
|
# Fallback
|
|
6543
8830
|
- internal_error
|
|
6544
8831
|
|
|
@@ -7428,6 +9715,15 @@ components:
|
|
|
7428
9715
|
$ref: '#/components/schemas/RetryConfigInput'
|
|
7429
9716
|
analyze:
|
|
7430
9717
|
$ref: '#/components/schemas/AnalyzeConfigInput'
|
|
9718
|
+
system_log:
|
|
9719
|
+
type: boolean
|
|
9720
|
+
default: false
|
|
9721
|
+
description: >
|
|
9722
|
+
Record the box's own SYSTEM log stream (the system journal or
|
|
9723
|
+
log files) beside the agent, verifier, setup and metrics
|
|
9724
|
+
streams every run keeps — read back at
|
|
9725
|
+
`GET /api/trials/{trialId}/logs?stream=system`. Off by default:
|
|
9726
|
+
it is one extra read-only reader inside a box under evaluation.
|
|
7431
9727
|
timeout_multiplier:
|
|
7432
9728
|
type: number
|
|
7433
9729
|
exclusiveMinimum: 0
|
|
@@ -8441,6 +10737,7 @@ components:
|
|
|
8441
10737
|
- agent_setup_timeout_multiplier
|
|
8442
10738
|
- environment_build_timeout_multiplier
|
|
8443
10739
|
- sandbox_provider
|
|
10740
|
+
- system_log
|
|
8444
10741
|
- counts
|
|
8445
10742
|
- build_exclusions
|
|
8446
10743
|
- n_total_trials
|
|
@@ -8504,6 +10801,13 @@ components:
|
|
|
8504
10801
|
IT ran under). Derived jobs (resume, retry) inherit it verbatim
|
|
8505
10802
|
— a re-run gets analyzed exactly like the trials it reproduces.
|
|
8506
10803
|
Always null on a regrade job.
|
|
10804
|
+
system_log:
|
|
10805
|
+
type: boolean
|
|
10806
|
+
description: >
|
|
10807
|
+
Whether the run records the box's own SYSTEM log stream
|
|
10808
|
+
(`JobCreate.system_log`), read back at `GET …/logs?stream=system`.
|
|
10809
|
+
Derived jobs inherit it; always false on a regrade job and on
|
|
10810
|
+
every job created before the switch existed.
|
|
8507
10811
|
timeout_multiplier:
|
|
8508
10812
|
type: number
|
|
8509
10813
|
description: >
|
|
@@ -10206,6 +12510,14 @@ components:
|
|
|
10206
12510
|
`--ek` (local-runner knobs with no hosted meaning), `-q` (a client
|
|
10207
12511
|
rendering option, not a wire field).
|
|
10208
12512
|
properties:
|
|
12513
|
+
name:
|
|
12514
|
+
type: string
|
|
12515
|
+
minLength: 1
|
|
12516
|
+
maxLength: 120
|
|
12517
|
+
description: |
|
|
12518
|
+
The caller's name for the check — Harbor's `--job-name` on
|
|
12519
|
+
`harbor check` (cli/analyze.py:138). Omitted, the accept
|
|
12520
|
+
timestamp in Harbor's own shape, `YYYY-MM-DD__HH-MM-SS` (UTC).
|
|
10209
12521
|
model_name:
|
|
10210
12522
|
type: string
|
|
10211
12523
|
default: openrouter/deepseek/deepseek-v4.1-flash
|
|
@@ -10391,6 +12703,7 @@ components:
|
|
|
10391
12703
|
of the measured task costs, null when none was measured.
|
|
10392
12704
|
required:
|
|
10393
12705
|
- id
|
|
12706
|
+
- name
|
|
10394
12707
|
- status
|
|
10395
12708
|
- source
|
|
10396
12709
|
- model_name
|
|
@@ -10410,6 +12723,9 @@ components:
|
|
|
10410
12723
|
id:
|
|
10411
12724
|
type: string
|
|
10412
12725
|
format: uuid
|
|
12726
|
+
name:
|
|
12727
|
+
type: string
|
|
12728
|
+
description: The caller's name, or the accept timestamp in Harbor's `YYYY-MM-DD__HH-MM-SS` shape.
|
|
10413
12729
|
status:
|
|
10414
12730
|
type: string
|
|
10415
12731
|
enum: [queued, running, completed]
|
|
@@ -10459,6 +12775,33 @@ components:
|
|
|
10459
12775
|
format: date-time
|
|
10460
12776
|
description: When the last task settled; null until every task has.
|
|
10461
12777
|
|
|
12778
|
+
CheckDefaults:
|
|
12779
|
+
type: object
|
|
12780
|
+
description: >
|
|
12781
|
+
The policy an empty `CheckConfigInput` resolves to (GET
|
|
12782
|
+
/api/checks/defaults) — each key the same value `Check` echoes for
|
|
12783
|
+
a check created with no config, except `prompt`, which `Check`
|
|
12784
|
+
serves as null (the built-in body) and this serves as that body's
|
|
12785
|
+
template text.
|
|
12786
|
+
required: [model_name, rubric, prompt, reasoning_effort, sandbox_provider]
|
|
12787
|
+
properties:
|
|
12788
|
+
model_name:
|
|
12789
|
+
type: string
|
|
12790
|
+
rubric:
|
|
12791
|
+
$ref: '#/components/schemas/Rubric'
|
|
12792
|
+
prompt:
|
|
12793
|
+
type: string
|
|
12794
|
+
description: >
|
|
12795
|
+
The built-in check prompt template, unrendered — pass it as
|
|
12796
|
+
`CheckConfigInput.prompt` to run the default body explicitly,
|
|
12797
|
+
or edit it from here.
|
|
12798
|
+
reasoning_effort:
|
|
12799
|
+
type: string
|
|
12800
|
+
description: The effort the default model runs at when the config names none.
|
|
12801
|
+
sandbox_provider:
|
|
12802
|
+
allOf:
|
|
12803
|
+
- $ref: '#/components/schemas/SandboxProvider'
|
|
12804
|
+
|
|
10462
12805
|
CheckPage:
|
|
10463
12806
|
type: object
|
|
10464
12807
|
description: Cursor page of task quality checks (envelope keys frozen verbatim).
|
|
@@ -10781,6 +13124,324 @@ components:
|
|
|
10781
13124
|
hasMore:
|
|
10782
13125
|
type: boolean
|
|
10783
13126
|
|
|
13127
|
+
# The file system + sandbox logs family: one set of shapes under every run owner and the task package.
|
|
13128
|
+
|
|
13129
|
+
FilesystemState:
|
|
13130
|
+
type: string
|
|
13131
|
+
description: >
|
|
13132
|
+
Which source the file system routes answer from: `live` (the box
|
|
13133
|
+
runs), `captured` (the kept tree), `capturing` (the capture is being
|
|
13134
|
+
written), `none` (nothing to read).
|
|
13135
|
+
enum: [live, captured, none, capturing]
|
|
13136
|
+
|
|
13137
|
+
FilesystemBox:
|
|
13138
|
+
type: object
|
|
13139
|
+
description: The running box a live file system reads.
|
|
13140
|
+
required: [provider, id, role, since]
|
|
13141
|
+
properties:
|
|
13142
|
+
provider:
|
|
13143
|
+
$ref: '#/components/schemas/SandboxProvider'
|
|
13144
|
+
id:
|
|
13145
|
+
type: string
|
|
13146
|
+
role:
|
|
13147
|
+
type: string
|
|
13148
|
+
enum: [agent, verifier, analyzer, checker]
|
|
13149
|
+
since:
|
|
13150
|
+
type: string
|
|
13151
|
+
format: date-time
|
|
13152
|
+
|
|
13153
|
+
FilesystemCapture:
|
|
13154
|
+
type: object
|
|
13155
|
+
description: The kept tree's record.
|
|
13156
|
+
required: [id, at, phase, entries, changed_files, changed_bytes, status, left_out, failure_reason]
|
|
13157
|
+
properties:
|
|
13158
|
+
id:
|
|
13159
|
+
type: string
|
|
13160
|
+
at:
|
|
13161
|
+
type: [string, 'null']
|
|
13162
|
+
format: date-time
|
|
13163
|
+
description: When the capture settled; null on one abandoned mid-way.
|
|
13164
|
+
phase:
|
|
13165
|
+
type: string
|
|
13166
|
+
enum: [after_verifier, after_seal, after_run]
|
|
13167
|
+
description: >
|
|
13168
|
+
The moment it was taken at: after a shared verifier ran in the box,
|
|
13169
|
+
after the seal (a separate verifier runs elsewhere), or after a run
|
|
13170
|
+
that failed.
|
|
13171
|
+
entries:
|
|
13172
|
+
type: integer
|
|
13173
|
+
changed_files:
|
|
13174
|
+
type: integer
|
|
13175
|
+
changed_bytes:
|
|
13176
|
+
type: integer
|
|
13177
|
+
status:
|
|
13178
|
+
type: string
|
|
13179
|
+
enum: [ready, incomplete, failed]
|
|
13180
|
+
left_out:
|
|
13181
|
+
type: array
|
|
13182
|
+
items:
|
|
13183
|
+
type: string
|
|
13184
|
+
description: Every path the run touched whose bytes are not stored (`incomplete`), in the capture's order.
|
|
13185
|
+
failure_reason:
|
|
13186
|
+
type: [string, 'null']
|
|
13187
|
+
description: Why a `failed` capture stored nothing; null otherwise.
|
|
13188
|
+
|
|
13189
|
+
FilesystemStatus:
|
|
13190
|
+
type: object
|
|
13191
|
+
required: [state, box, watcher, root, work_dir, capture]
|
|
13192
|
+
properties:
|
|
13193
|
+
state:
|
|
13194
|
+
$ref: '#/components/schemas/FilesystemState'
|
|
13195
|
+
box:
|
|
13196
|
+
oneOf:
|
|
13197
|
+
- $ref: '#/components/schemas/FilesystemBox'
|
|
13198
|
+
- type: 'null'
|
|
13199
|
+
watcher:
|
|
13200
|
+
type: [string, 'null']
|
|
13201
|
+
enum: [native, poll, null]
|
|
13202
|
+
description: How live change events arrive; null when not live.
|
|
13203
|
+
root:
|
|
13204
|
+
type: string
|
|
13205
|
+
description: Always `/`.
|
|
13206
|
+
work_dir:
|
|
13207
|
+
type: string
|
|
13208
|
+
description: Where the run works (Harbor's `/app`).
|
|
13209
|
+
capture:
|
|
13210
|
+
oneOf:
|
|
13211
|
+
- $ref: '#/components/schemas/FilesystemCapture'
|
|
13212
|
+
- type: 'null'
|
|
13213
|
+
|
|
13214
|
+
TaskPackageFilesystemStatus:
|
|
13215
|
+
type: object
|
|
13216
|
+
description: The task package owner's status — the run shape with `state` always `none`, plus the package facts.
|
|
13217
|
+
required: [state, box, watcher, root, work_dir, capture, source, package_retained]
|
|
13218
|
+
properties:
|
|
13219
|
+
state:
|
|
13220
|
+
type: string
|
|
13221
|
+
enum: [none]
|
|
13222
|
+
box:
|
|
13223
|
+
type: 'null'
|
|
13224
|
+
watcher:
|
|
13225
|
+
type: 'null'
|
|
13226
|
+
root:
|
|
13227
|
+
type: string
|
|
13228
|
+
work_dir:
|
|
13229
|
+
type: string
|
|
13230
|
+
capture:
|
|
13231
|
+
type: 'null'
|
|
13232
|
+
source:
|
|
13233
|
+
type: string
|
|
13234
|
+
enum: [package]
|
|
13235
|
+
package_retained:
|
|
13236
|
+
type: boolean
|
|
13237
|
+
|
|
13238
|
+
FilesystemEntry:
|
|
13239
|
+
type: object
|
|
13240
|
+
description: One entry of a folder listing.
|
|
13241
|
+
required: [name, type, size, mtime, mode, owner, changed, phase, captured]
|
|
13242
|
+
properties:
|
|
13243
|
+
name:
|
|
13244
|
+
type: string
|
|
13245
|
+
type:
|
|
13246
|
+
type: string
|
|
13247
|
+
enum: [dir, file, symlink, other]
|
|
13248
|
+
size:
|
|
13249
|
+
type: integer
|
|
13250
|
+
mtime:
|
|
13251
|
+
type: string
|
|
13252
|
+
format: date-time
|
|
13253
|
+
mode:
|
|
13254
|
+
type: string
|
|
13255
|
+
description: Octal, four digits, e.g. `0644`; the same words from both sources.
|
|
13256
|
+
owner:
|
|
13257
|
+
type: string
|
|
13258
|
+
description: The owning user as the box names it, e.g. `root`; the same words from both sources.
|
|
13259
|
+
changed:
|
|
13260
|
+
type: [string, 'null']
|
|
13261
|
+
enum: [created, modified, null]
|
|
13262
|
+
description: What the run did to it since the box started; null when not known for the source.
|
|
13263
|
+
phase:
|
|
13264
|
+
type: [string, 'null']
|
|
13265
|
+
enum: [setup, agent, verifier, null]
|
|
13266
|
+
description: Which part of the run changed it — the platform's own setup, the agent, or the verifier.
|
|
13267
|
+
captured:
|
|
13268
|
+
type: [boolean, 'null']
|
|
13269
|
+
description: >
|
|
13270
|
+
Captured source: false = the run never touched it, only the
|
|
13271
|
+
image holds it (lists, does not open). Live: null. Package: true.
|
|
13272
|
+
left_out:
|
|
13273
|
+
type: string
|
|
13274
|
+
description: Captured source, a file the run touched whose bytes are not stored — why, in the capture's own words.
|
|
13275
|
+
target:
|
|
13276
|
+
type: string
|
|
13277
|
+
description: A symlink's target.
|
|
13278
|
+
|
|
13279
|
+
FilesystemListing:
|
|
13280
|
+
type: object
|
|
13281
|
+
required: [path, source, entries, next_cursor, ms]
|
|
13282
|
+
properties:
|
|
13283
|
+
path:
|
|
13284
|
+
type: string
|
|
13285
|
+
source:
|
|
13286
|
+
type: string
|
|
13287
|
+
enum: [live, capture, package]
|
|
13288
|
+
entries:
|
|
13289
|
+
type: array
|
|
13290
|
+
items:
|
|
13291
|
+
$ref: '#/components/schemas/FilesystemEntry'
|
|
13292
|
+
next_cursor:
|
|
13293
|
+
type: [string, 'null']
|
|
13294
|
+
ms:
|
|
13295
|
+
type: integer
|
|
13296
|
+
description: Server time spent, milliseconds.
|
|
13297
|
+
|
|
13298
|
+
FilesystemSearchHit:
|
|
13299
|
+
type: object
|
|
13300
|
+
required: [path, line, snippet]
|
|
13301
|
+
properties:
|
|
13302
|
+
path:
|
|
13303
|
+
type: string
|
|
13304
|
+
line:
|
|
13305
|
+
type: integer
|
|
13306
|
+
snippet:
|
|
13307
|
+
type: string
|
|
13308
|
+
|
|
13309
|
+
FilesystemSearchResult:
|
|
13310
|
+
type: object
|
|
13311
|
+
required: [hits, truncated, scope, source, ms]
|
|
13312
|
+
properties:
|
|
13313
|
+
hits:
|
|
13314
|
+
type: array
|
|
13315
|
+
items:
|
|
13316
|
+
$ref: '#/components/schemas/FilesystemSearchHit'
|
|
13317
|
+
truncated:
|
|
13318
|
+
type: boolean
|
|
13319
|
+
description: More hits exist, or the search budget ran out.
|
|
13320
|
+
scope:
|
|
13321
|
+
type: string
|
|
13322
|
+
enum: [path, box]
|
|
13323
|
+
source:
|
|
13324
|
+
type: string
|
|
13325
|
+
enum: [live, capture]
|
|
13326
|
+
image_files_excluded:
|
|
13327
|
+
type: boolean
|
|
13328
|
+
description: Captured source only — files the run never touched were not searchable.
|
|
13329
|
+
ms:
|
|
13330
|
+
type: integer
|
|
13331
|
+
|
|
13332
|
+
FilesystemChange:
|
|
13333
|
+
type: object
|
|
13334
|
+
required: [path, type, changed, phase, size, mtime]
|
|
13335
|
+
properties:
|
|
13336
|
+
path:
|
|
13337
|
+
type: string
|
|
13338
|
+
type:
|
|
13339
|
+
type: string
|
|
13340
|
+
enum: [dir, file, symlink, other]
|
|
13341
|
+
changed:
|
|
13342
|
+
type: string
|
|
13343
|
+
enum: [created, modified, removed]
|
|
13344
|
+
phase:
|
|
13345
|
+
type: string
|
|
13346
|
+
enum: [setup, agent, verifier]
|
|
13347
|
+
size:
|
|
13348
|
+
type: integer
|
|
13349
|
+
mtime:
|
|
13350
|
+
type: string
|
|
13351
|
+
format: date-time
|
|
13352
|
+
left_out:
|
|
13353
|
+
type: string
|
|
13354
|
+
description: Captured source, a file whose bytes are not stored — why, in the capture's own words.
|
|
13355
|
+
|
|
13356
|
+
FilesystemChanges:
|
|
13357
|
+
type: object
|
|
13358
|
+
required: [source, total, changed_bytes, items, next_cursor]
|
|
13359
|
+
properties:
|
|
13360
|
+
source:
|
|
13361
|
+
type: string
|
|
13362
|
+
enum: [live, capture]
|
|
13363
|
+
total:
|
|
13364
|
+
type: integer
|
|
13365
|
+
changed_bytes:
|
|
13366
|
+
type: integer
|
|
13367
|
+
items:
|
|
13368
|
+
type: array
|
|
13369
|
+
items:
|
|
13370
|
+
$ref: '#/components/schemas/FilesystemChange'
|
|
13371
|
+
next_cursor:
|
|
13372
|
+
type: [string, 'null']
|
|
13373
|
+
|
|
13374
|
+
FilesystemWatchRequest:
|
|
13375
|
+
type: object
|
|
13376
|
+
required: [paths]
|
|
13377
|
+
properties:
|
|
13378
|
+
paths:
|
|
13379
|
+
type: array
|
|
13380
|
+
maxItems: 8
|
|
13381
|
+
items:
|
|
13382
|
+
type: string
|
|
13383
|
+
description: The folders the viewer has open, absolute box paths; replaces the set.
|
|
13384
|
+
|
|
13385
|
+
FilesystemWatchResult:
|
|
13386
|
+
type: object
|
|
13387
|
+
required: [watcher, paths]
|
|
13388
|
+
properties:
|
|
13389
|
+
watcher:
|
|
13390
|
+
type: string
|
|
13391
|
+
enum: [native, poll]
|
|
13392
|
+
paths:
|
|
13393
|
+
type: array
|
|
13394
|
+
items:
|
|
13395
|
+
type: string
|
|
13396
|
+
|
|
13397
|
+
SandboxLogStream:
|
|
13398
|
+
type: string
|
|
13399
|
+
description: The named sandbox streams a run records.
|
|
13400
|
+
enum: [agent, verifier, setup, system, metrics]
|
|
13401
|
+
|
|
13402
|
+
SandboxLogLine:
|
|
13403
|
+
type: object
|
|
13404
|
+
required: [seq, t, fd, line]
|
|
13405
|
+
properties:
|
|
13406
|
+
seq:
|
|
13407
|
+
type: integer
|
|
13408
|
+
t:
|
|
13409
|
+
type: [string, 'null']
|
|
13410
|
+
format: date-time
|
|
13411
|
+
description: When the line was recorded; null when the record holds no time for it.
|
|
13412
|
+
fd:
|
|
13413
|
+
type: string
|
|
13414
|
+
enum: [out, err]
|
|
13415
|
+
line:
|
|
13416
|
+
type: string
|
|
13417
|
+
|
|
13418
|
+
SandboxLogLines:
|
|
13419
|
+
type: object
|
|
13420
|
+
description: One page of a stream.
|
|
13421
|
+
required: [stream, lines, next_cursor]
|
|
13422
|
+
properties:
|
|
13423
|
+
stream:
|
|
13424
|
+
$ref: '#/components/schemas/SandboxLogStream'
|
|
13425
|
+
lines:
|
|
13426
|
+
type: array
|
|
13427
|
+
items:
|
|
13428
|
+
$ref: '#/components/schemas/SandboxLogLine'
|
|
13429
|
+
next_cursor:
|
|
13430
|
+
type: [string, 'null']
|
|
13431
|
+
reason:
|
|
13432
|
+
type: string
|
|
13433
|
+
description: Why the page is empty when the platform holds nothing for this stream (never an error).
|
|
13434
|
+
|
|
13435
|
+
SandboxProcs:
|
|
13436
|
+
type: object
|
|
13437
|
+
required: [text, ms]
|
|
13438
|
+
properties:
|
|
13439
|
+
text:
|
|
13440
|
+
type: string
|
|
13441
|
+
description: The process listing as text.
|
|
13442
|
+
ms:
|
|
13443
|
+
type: integer
|
|
13444
|
+
|
|
10784
13445
|
# -------------------------------------------------------------------------
|
|
10785
13446
|
# Job archive (the downloadJob tar) — the Evolve extension keys inside the
|
|
10786
13447
|
# otherwise Harbor-vocabulary record files. Not HTTP bodies: these schemas
|