@sema-agent/sdk 25.0.0 → 26.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -3
- package/dist/client.d.ts +0 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +0 -5
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +57 -25
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +40 -35
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +13 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +17 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/resources/approvals.d.ts +16 -2
- package/dist/resources/approvals.d.ts.map +1 -1
- package/dist/resources/approvals.js +7 -2
- package/dist/resources/approvals.js.map +1 -1
- package/dist/resources/fleet.d.ts +8 -12
- package/dist/resources/fleet.d.ts.map +1 -1
- package/dist/resources/fleet.js.map +1 -1
- package/dist/resources/rules.d.ts +2 -5
- package/dist/resources/rules.d.ts.map +1 -1
- package/dist/resources/rules.js.map +1 -1
- package/dist/resources/session-sync.d.ts +27 -32
- package/dist/resources/session-sync.d.ts.map +1 -1
- package/dist/resources/session-sync.js +25 -39
- package/dist/resources/session-sync.js.map +1 -1
- package/dist/resources/tool-approvals.d.ts +60 -99
- package/dist/resources/tool-approvals.d.ts.map +1 -1
- package/dist/resources/tool-approvals.js +41 -35
- package/dist/resources/tool-approvals.js.map +1 -1
- package/dist/settings.d.ts +13 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +0 -24
- package/dist/settings.js.map +1 -1
- package/dist/sync.d.ts +5 -5
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +13 -55
- package/dist/sync.js.map +1 -1
- package/dist/transport.d.ts +2 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +3 -0
- package/dist/transport.js.map +1 -1
- package/dist/types.d.ts +132 -110
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -1
- package/openapi.yaml +237 -532
- package/package.json +1 -1
- package/dist/resources/workspace.d.ts +0 -95
- package/dist/resources/workspace.d.ts.map +0 -1
- package/dist/resources/workspace.js +0 -60
- package/dist/resources/workspace.js.map +0 -1
package/openapi.yaml
CHANGED
|
@@ -172,7 +172,7 @@ tags:
|
|
|
172
172
|
themself said yes"), never operator. GATED AND OFF BY DEFAULT: the whole lane hangs on
|
|
173
173
|
PERMISSION_RULES_ENABLED (default false) plus a wired rule store — so on a stock deployment BOTH doors
|
|
174
174
|
answer 501 `capability.rule_store_required`, and so does the single-card half (the ask frame simply
|
|
175
|
-
carries no `
|
|
175
|
+
carries no `ruleOffers`). Read the observed frame / an actual response, never a version number.
|
|
176
176
|
The SINGLE-CARD half of the same lane is `persistRule` on POST /v1/tool-approvals/{id}/respond.
|
|
177
177
|
- name: adoption
|
|
178
178
|
description: >
|
|
@@ -2280,38 +2280,16 @@ paths:
|
|
|
2280
2280
|
get:
|
|
2281
2281
|
tags: [workspace]
|
|
2282
2282
|
operationId: workspaceList
|
|
2283
|
-
x-status: retired #
|
|
2284
|
-
summary: 'RETIRED (server 7.52.0, S-15) — snapshot listing;
|
|
2285
|
-
description: >
|
|
2286
|
-
🔴 RETIRED as of `@sema-agent/server` 7.52.0 (S-15/design/381): the E19 whole-tree snapshot store this
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
predicate). There is NO 1:1 replacement path — a future "rewind coverage" browse would be a NEW face
|
|
2292
|
-
with tracked-set semantics, not this name wired back. Related live faces: rewind restore rides
|
|
2293
|
-
`TaskRequest.restoreFiles` (probe `capabilities.restoreFiles`); per-file history blobs ride
|
|
2294
|
-
`GET /v1/sessions/{sessionId}/sync/history/blobs/{hash}`.
|
|
2295
|
-
Historical shape (servers 1.299–7.51): read-only projection over the E19 snapshot store. Rows carry
|
|
2296
|
-
`{key, files, bytes?}`; `latest` = the newest snapshot key. Owner-scoped (non-owner → 404, no
|
|
2297
|
-
oracle); 501 without the snapshot-store read faces (probe `capabilities.workspace`).
|
|
2298
|
-
parameters:
|
|
2299
|
-
- in: query
|
|
2300
|
-
name: limit
|
|
2301
|
-
required: false
|
|
2302
|
-
schema: { type: integer, minimum: 1, maximum: 100 }
|
|
2283
|
+
x-status: retired # server 7.52.0: whole-tree snapshot epoch retired; sdk 26.0.0 deleted the verb (support floor 7.52.0).
|
|
2284
|
+
summary: 'RETIRED (server 7.52.0, S-15) — snapshot listing; every supported server (>= 7.52.0) answers 501 capability.workspace_retired.'
|
|
2285
|
+
description: >
|
|
2286
|
+
🔴 RETIRED as of `@sema-agent/server` 7.52.0 (S-15/design/381): the E19 whole-tree snapshot store this face projected was replaced by per-edited-file
|
|
2287
|
+
rewind HISTORY (only files the agent edited — there is no "whole workspace" manifest to browse). The route SHAPE is kept server-side as a tombstone:
|
|
2288
|
+
every supported server answers 501 `capability.workspace_retired` (a named refusal, not a 404 that reads like a typo), and `capabilities.workspace` is
|
|
2289
|
+
always `false` (same predicate). No 1:1 replacement: rewind restore rides `TaskRequest.restoreFiles` (probe `capabilities.restoreFiles`); per-file
|
|
2290
|
+
history blobs ride `GET /v1/sessions/{sessionId}/sync/history/blobs/{hash}`. sdk 26.0.0 deleted `client.workspace` (its 200 shapes only existed on 1.299–7.51).
|
|
2303
2291
|
responses:
|
|
2304
|
-
'200':
|
|
2305
|
-
description: The snapshot listing.
|
|
2306
|
-
content:
|
|
2307
|
-
application/json:
|
|
2308
|
-
# 封闭两层(census 批2 第三段,2026-07-30):铸造点 `routes/sessions.ts`(信封与行两处)。条件键=信封 `latest`(零快照即省略)、行 `bytes`(blobSizes 面缺席=诚实省略)。
|
|
2309
|
-
# 4.3.0:形提成具名 `WorkspaceSnapshotPage`(SDK 同批把返回位的内联字面量也提成了 exported type,
|
|
2310
|
-
# 让 spec-resource-schema-gate 罩得住 —— CAPS-OPS-8)。
|
|
2311
|
-
schema: { $ref: '#/components/schemas/WorkspaceSnapshotPage' }
|
|
2312
|
-
'400': { $ref: '#/components/responses/BadRequest' }
|
|
2313
2292
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2314
|
-
'404': { $ref: '#/components/responses/NotFound' }
|
|
2315
2293
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
2316
2294
|
|
|
2317
2295
|
/v1/sessions/{sessionId}/workspace/{key}/tree:
|
|
@@ -2325,38 +2303,19 @@ paths:
|
|
|
2325
2303
|
name: key
|
|
2326
2304
|
required: true
|
|
2327
2305
|
schema: { type: string }
|
|
2328
|
-
description: 'Snapshot key (entryId), or the alias `latest` = the newest snapshot.'
|
|
2329
2306
|
get:
|
|
2330
2307
|
tags: [workspace]
|
|
2331
2308
|
operationId: workspaceTree
|
|
2332
|
-
x-status: retired #
|
|
2333
|
-
summary: 'RETIRED (server 7.52.0, S-15) — snapshot file tree;
|
|
2334
|
-
description: >
|
|
2335
|
-
🔴 RETIRED as of server 7.52.0
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
parameters:
|
|
2341
|
-
- in: query
|
|
2342
|
-
name: limit
|
|
2343
|
-
required: false
|
|
2344
|
-
schema: { type: integer, minimum: 1, maximum: 2000 }
|
|
2345
|
-
- in: query
|
|
2346
|
-
name: offset
|
|
2347
|
-
required: false
|
|
2348
|
-
schema: { type: integer, minimum: 0 }
|
|
2309
|
+
x-status: retired # server 7.52.0: whole-tree snapshot epoch retired; sdk 26.0.0 deleted the verb (support floor 7.52.0).
|
|
2310
|
+
summary: 'RETIRED (server 7.52.0, S-15) — snapshot file tree; every supported server (>= 7.52.0) answers 501 capability.workspace_retired.'
|
|
2311
|
+
description: >
|
|
2312
|
+
🔴 RETIRED as of `@sema-agent/server` 7.52.0 (S-15/design/381): the E19 whole-tree snapshot store this face projected was replaced by per-edited-file
|
|
2313
|
+
rewind HISTORY (only files the agent edited — there is no "whole workspace" manifest to browse). The route SHAPE is kept server-side as a tombstone:
|
|
2314
|
+
every supported server answers 501 `capability.workspace_retired` (a named refusal, not a 404 that reads like a typo), and `capabilities.workspace` is
|
|
2315
|
+
always `false` (same predicate). No 1:1 replacement: rewind restore rides `TaskRequest.restoreFiles` (probe `capabilities.restoreFiles`); per-file
|
|
2316
|
+
history blobs ride `GET /v1/sessions/{sessionId}/sync/history/blobs/{hash}`. sdk 26.0.0 deleted `client.workspace` (its 200 shapes only existed on 1.299–7.51).
|
|
2349
2317
|
responses:
|
|
2350
|
-
'200':
|
|
2351
|
-
description: One page of the tree.
|
|
2352
|
-
content:
|
|
2353
|
-
application/json:
|
|
2354
|
-
# 封闭两层(census 批2 第三段,2026-07-30):铸造点 `routes/sessions.ts`(信封与行两处)。条件键=信封 `nextOffset`(尾页省略)、行 `size`(blobSizes 面缺席省略)。
|
|
2355
|
-
# 4.3.0:形提成具名 `WorkspaceTreePage`(理由同 list 腿 —— CAPS-OPS-8)。
|
|
2356
|
-
schema: { $ref: '#/components/schemas/WorkspaceTreePage' }
|
|
2357
|
-
'400': { $ref: '#/components/responses/BadRequest' }
|
|
2358
2318
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2359
|
-
'404': { $ref: '#/components/responses/NotFound' }
|
|
2360
2319
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
2361
2320
|
|
|
2362
2321
|
/v1/sessions/{sessionId}/workspace/{key}/file:
|
|
@@ -2373,46 +2332,16 @@ paths:
|
|
|
2373
2332
|
get:
|
|
2374
2333
|
tags: [workspace]
|
|
2375
2334
|
operationId: workspaceFile
|
|
2376
|
-
x-status: retired #
|
|
2377
|
-
summary: 'RETIRED (server 7.52.0, S-15) — single
|
|
2378
|
-
description: >
|
|
2379
|
-
🔴 RETIRED as of server 7.52.0
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
untrusted; `x-content-type-options: nosniff` always set) + the `x-sema-content-binary` discriminator
|
|
2385
|
-
header (first-8KiB NUL sniff, [1894]③). Capped at `capabilities.workspace.maxFileBytes` (default
|
|
2386
|
-
8MiB, WORKSPACE_FILE_MAX_BYTES) — over-cap ⇒ 413 STRUCTURED envelope
|
|
2387
|
-
`{errorCode: "workspace_file_too_large", sizeBytes, limit}` ([1894]①; archive was the escape hatch).
|
|
2388
|
-
With the SQL size index the 413 fired BEFORE fetching the bytes.
|
|
2389
|
-
parameters:
|
|
2390
|
-
- in: query
|
|
2391
|
-
name: path
|
|
2392
|
-
required: true
|
|
2393
|
-
schema: { type: string }
|
|
2394
|
-
description: The tree's relPath, verbatim.
|
|
2335
|
+
x-status: retired # server 7.52.0: whole-tree snapshot epoch retired; sdk 26.0.0 deleted the verb (support floor 7.52.0).
|
|
2336
|
+
summary: 'RETIRED (server 7.52.0, S-15) — snapshot single file; every supported server (>= 7.52.0) answers 501 capability.workspace_retired.'
|
|
2337
|
+
description: >
|
|
2338
|
+
🔴 RETIRED as of `@sema-agent/server` 7.52.0 (S-15/design/381): the E19 whole-tree snapshot store this face projected was replaced by per-edited-file
|
|
2339
|
+
rewind HISTORY (only files the agent edited — there is no "whole workspace" manifest to browse). The route SHAPE is kept server-side as a tombstone:
|
|
2340
|
+
every supported server answers 501 `capability.workspace_retired` (a named refusal, not a 404 that reads like a typo), and `capabilities.workspace` is
|
|
2341
|
+
always `false` (same predicate). No 1:1 replacement: rewind restore rides `TaskRequest.restoreFiles` (probe `capabilities.restoreFiles`); per-file
|
|
2342
|
+
history blobs ride `GET /v1/sessions/{sessionId}/sync/history/blobs/{hash}`. sdk 26.0.0 deleted `client.workspace` (its 200 shapes only existed on 1.299–7.51).
|
|
2395
2343
|
responses:
|
|
2396
|
-
'200':
|
|
2397
|
-
description: The file bytes.
|
|
2398
|
-
content:
|
|
2399
|
-
application/octet-stream:
|
|
2400
|
-
schema: { type: string, format: binary }
|
|
2401
|
-
'400': { $ref: '#/components/responses/BadRequest' }
|
|
2402
2344
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2403
|
-
'404': { $ref: '#/components/responses/NotFound' }
|
|
2404
|
-
'413':
|
|
2405
|
-
description: 'Structured over-cap envelope: {error, errorCode: "workspace_file_too_large", sizeBytes, limit}.'
|
|
2406
|
-
content:
|
|
2407
|
-
application/json:
|
|
2408
|
-
schema:
|
|
2409
|
-
type: object
|
|
2410
|
-
required: [error, errorCode, sizeBytes, limit]
|
|
2411
|
-
properties:
|
|
2412
|
-
error: { type: string }
|
|
2413
|
-
errorCode: { type: string, enum: [workspace_file_too_large] }
|
|
2414
|
-
sizeBytes: { type: integer }
|
|
2415
|
-
limit: { type: integer }
|
|
2416
2345
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
2417
2346
|
|
|
2418
2347
|
/v1/sessions/{sessionId}/workspace/{key}/archive:
|
|
@@ -2429,28 +2358,17 @@ paths:
|
|
|
2429
2358
|
get:
|
|
2430
2359
|
tags: [workspace]
|
|
2431
2360
|
operationId: workspaceArchive
|
|
2432
|
-
x-status: retired #
|
|
2433
|
-
summary: 'RETIRED (server 7.52.0, S-15) —
|
|
2434
|
-
description: >
|
|
2435
|
-
🔴 RETIRED as of server 7.52.0
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
import) ⇒ 502 (retryable). A blob vanishing MID-stream destroyed the connection (honest truncation)
|
|
2441
|
-
rather than faking a complete archive.
|
|
2361
|
+
x-status: retired # server 7.52.0: whole-tree snapshot epoch retired; sdk 26.0.0 deleted the verb (support floor 7.52.0).
|
|
2362
|
+
summary: 'RETIRED (server 7.52.0, S-15) — snapshot tar archive; every supported server (>= 7.52.0) answers 501 capability.workspace_retired.'
|
|
2363
|
+
description: >
|
|
2364
|
+
🔴 RETIRED as of `@sema-agent/server` 7.52.0 (S-15/design/381): the E19 whole-tree snapshot store this face projected was replaced by per-edited-file
|
|
2365
|
+
rewind HISTORY (only files the agent edited — there is no "whole workspace" manifest to browse). The route SHAPE is kept server-side as a tombstone:
|
|
2366
|
+
every supported server answers 501 `capability.workspace_retired` (a named refusal, not a 404 that reads like a typo), and `capabilities.workspace` is
|
|
2367
|
+
always `false` (same predicate). No 1:1 replacement: rewind restore rides `TaskRequest.restoreFiles` (probe `capabilities.restoreFiles`); per-file
|
|
2368
|
+
history blobs ride `GET /v1/sessions/{sessionId}/sync/history/blobs/{hash}`. sdk 26.0.0 deleted `client.workspace` (its 200 shapes only existed on 1.299–7.51).
|
|
2442
2369
|
responses:
|
|
2443
|
-
'200':
|
|
2444
|
-
description: The tar stream.
|
|
2445
|
-
content:
|
|
2446
|
-
application/x-tar:
|
|
2447
|
-
schema: { type: string, format: binary }
|
|
2448
|
-
'400': { $ref: '#/components/responses/BadRequest' }
|
|
2449
2370
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2450
|
-
'404': { $ref: '#/components/responses/NotFound' }
|
|
2451
|
-
'422': { description: 'Snapshot contains paths not representable in ustar (names the first 5).' }
|
|
2452
2371
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
2453
|
-
'502': { description: 'Snapshot is missing blobs (raced a reap or a partial import) — retry or pick another snapshot.' }
|
|
2454
2372
|
|
|
2455
2373
|
/v1/sessions/{sessionId}/policy:
|
|
2456
2374
|
parameters:
|
|
@@ -3040,50 +2958,6 @@ paths:
|
|
|
3040
2958
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
3041
2959
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
3042
2960
|
|
|
3043
|
-
/v1/sessions/{sessionId}/sync/snapshots/{key}/blobs/{hash}:
|
|
3044
|
-
parameters:
|
|
3045
|
-
- $ref: '#/components/parameters/PrincipalHeader'
|
|
3046
|
-
- in: path
|
|
3047
|
-
name: sessionId
|
|
3048
|
-
required: true
|
|
3049
|
-
schema: { type: string }
|
|
3050
|
-
- in: path
|
|
3051
|
-
name: key
|
|
3052
|
-
required: true
|
|
3053
|
-
schema: { type: string }
|
|
3054
|
-
description: The snapshot key (= a `SessionTreeEntry.id`).
|
|
3055
|
-
- in: path
|
|
3056
|
-
name: hash
|
|
3057
|
-
required: true
|
|
3058
|
-
schema: { type: string, pattern: '^[0-9a-f]{64}$' }
|
|
3059
|
-
description: The content-address (SHA-256, 64 lowercase-hex).
|
|
3060
|
-
get:
|
|
3061
|
-
tags: [sessions]
|
|
3062
|
-
operationId: sessionSyncGetBlob
|
|
3063
|
-
x-status: retired # S-15 (server 7.52.0): the E19-era snapshot-scoped PULL arm was REPLACED by GET …/sync/history/blobs/{hash} — ≥7.52 this path 404s (not_found.route).
|
|
3064
|
-
summary: 'RETIRED (server 7.52.0, S-15) — snapshot-scoped blob PULL; use GET …/sync/history/blobs/{hash}. Live on ≤7.51 only.'
|
|
3065
|
-
description: >
|
|
3066
|
-
🔴 RETIRED as of `@sema-agent/server` 7.52.0 (S-15/design/381): a blob is scoped by the session's
|
|
3067
|
-
HISTORY GRAPH now, not by a per-snapshot manifest key, so this arm was replaced by
|
|
3068
|
-
`GET /v1/sessions/{sessionId}/sync/history/blobs/{hash}` (sessionSyncGetHistoryBlob — same
|
|
3069
|
-
octet-stream body, same no-oracle 404 posture, scope check = "referenced by this session's
|
|
3070
|
-
exportHistory envelope"). On ≥7.52 this path no longer matches the sync route family and answers 404
|
|
3071
|
-
`not_found.route`. SDK: `sessions.sync.getHistoryBlob` (the legacy `getBlob` verb stays, deprecated,
|
|
3072
|
-
for ≤7.51 servers inside the support range).
|
|
3073
|
-
Historical shape (≤7.51): one content-addressed blob's RAW bytes; the cloud served a hash ONLY if
|
|
3074
|
-
THIS session's `:key` manifest referenced it (foreign/unreferenced → 404 `blob not found`). 400 on a
|
|
3075
|
-
non-64-hex hash or an undecodable key/hash. Owner-scoped (404).
|
|
3076
|
-
responses:
|
|
3077
|
-
'200':
|
|
3078
|
-
description: The blob bytes.
|
|
3079
|
-
content:
|
|
3080
|
-
application/octet-stream:
|
|
3081
|
-
schema: { type: string, format: binary }
|
|
3082
|
-
'400': { $ref: '#/components/responses/BadRequest' }
|
|
3083
|
-
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
3084
|
-
'404': { $ref: '#/components/responses/NotFound' }
|
|
3085
|
-
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
3086
|
-
|
|
3087
2961
|
/v1/sessions/{sessionId}/sync/history/blobs/{hash}:
|
|
3088
2962
|
parameters:
|
|
3089
2963
|
- $ref: '#/components/parameters/PrincipalHeader'
|
|
@@ -3109,7 +2983,7 @@ paths:
|
|
|
3109
2983
|
→ 404 `not_found.blob`, never a blind read; a server whose file-history store has no blob faces
|
|
3110
2984
|
(e.g. the local file backend) answers the SAME 404 shape (no oracle — "nothing servable" and "not
|
|
3111
2985
|
referenced" are deliberately indistinguishable). 400 `request.id_invalid` on a non-64-hex hash.
|
|
3112
|
-
Owner-scoped (404). Replaces the retired `
|
|
2986
|
+
Owner-scoped (404). Replaces the retired snapshot-scoped PULL arm of servers <= 7.51 (below the support floor; sdk 26.0.0 deleted `getBlob` and its path).
|
|
3113
2987
|
responses:
|
|
3114
2988
|
'200':
|
|
3115
2989
|
description: The blob bytes.
|
|
@@ -3142,12 +3016,10 @@ paths:
|
|
|
3142
3016
|
body). The cloud verifies `sha256(body) === :hash` (the content-address integrity guard) BEFORE storing — a
|
|
3143
3017
|
mismatch → 400 `blob hash mismatch`. own-or-FRESH gate. Per-blob cap 64 MiB → 413 mid-stream beyond it. A
|
|
3144
3018
|
backend write failure (e.g. a MinIO non-2xx) → 502 `blob store write failed`. 204 on success (no body). The
|
|
3145
|
-
PUSH path is the BARE `blobs/:hash` (the PULL is `history/blobs/:hash`
|
|
3146
|
-
`snapshots/:key/blobs/:hash` before). 🔴 server ≥7.52 (S-15 换店): the blob faces ride the
|
|
3019
|
+
PUSH path is the BARE `blobs/:hash` (the PULL is `history/blobs/:hash`). The blob faces ride the
|
|
3147
3020
|
file-HISTORY store — a deployment whose store has no blob faces (the local file backend) answers 501
|
|
3148
3021
|
`capability.snapshot_store_required` ("blob upload requires a durable file-history store") while the
|
|
3149
|
-
rest of the sync surface keeps working
|
|
3150
|
-
code, same operator disposition (wire a backend with blob faces).
|
|
3022
|
+
rest of the sync surface keeps working (operator disposition: wire a backend with blob faces).
|
|
3151
3023
|
requestBody:
|
|
3152
3024
|
required: true
|
|
3153
3025
|
content:
|
|
@@ -3217,14 +3089,12 @@ paths:
|
|
|
3217
3089
|
x-status: live
|
|
3218
3090
|
summary: PUSH Phase A — classify + stage (mint a stagingId).
|
|
3219
3091
|
description: >
|
|
3220
|
-
2c session-sync PUSH Phase A — a SMALL metadata body (`entryIds,
|
|
3092
|
+
2c session-sync PUSH Phase A — a SMALL metadata body (`entryIds, fileHistory?, policy, anchors, resolution?, logDigest?, title?, pinned?`); the
|
|
3221
3093
|
entries stream in Phase B. The cloud classifies (§7), pre-checks blob presence (a missing referenced hash →
|
|
3222
3094
|
422 `missing_blob` — PUT it first), guards the import lease + any active run (409), then mints a stagingId.
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
`PUT …/sync/blobs/{hash}` first. ≤7.51 servers consume `snapshots` and do not know `fileHistory`. SDK 16.2.0 carries
|
|
3227
|
-
`fileHistory` in `pushSessionBundle` / `importSessionBundle` (and fills `snapshots: []` on the pull side when the manifest omits it); a hand-rolled
|
|
3095
|
+
The file history rides `fileHistory` (a `FileHistoryExport` envelope, `null` / absent = none) and every blob it references must have been
|
|
3096
|
+
`PUT …/sync/blobs/{hash}` first (the `snapshots` key of servers <= 7.51 is outside the support range; a supported server ignores it and sdk 26.0.0
|
|
3097
|
+
no longer declares it). The SDK carries `fileHistory` in `pushSessionBundle` / `importSessionBundle`; a hand-rolled
|
|
3228
3098
|
push must send `fileHistory` itself, and only to a peer whose `capabilities.sessionSyncFileHistory` is not false (server >= 7.116.0 — else the
|
|
3229
3099
|
commit 422s `missing_blob`).
|
|
3230
3100
|
`identical` → `{ relation:"identical", basis, payloadVerified }` with NO stagingId (skip Phase B);
|
|
@@ -3239,15 +3109,14 @@ paths:
|
|
|
3239
3109
|
application/json:
|
|
3240
3110
|
schema:
|
|
3241
3111
|
type: object
|
|
3242
|
-
required: [entryIds,
|
|
3112
|
+
required: [entryIds, policy, anchors]
|
|
3243
3113
|
properties:
|
|
3244
3114
|
entryIds: { type: array, items: { type: string } }
|
|
3245
|
-
snapshots: { type: array, items: { $ref: '#/components/schemas/SyncSnapshot' } }
|
|
3246
3115
|
fileHistory:
|
|
3247
3116
|
oneOf:
|
|
3248
3117
|
- { $ref: '#/components/schemas/FileHistoryExport' }
|
|
3249
3118
|
- { type: 'null' }
|
|
3250
|
-
description: '
|
|
3119
|
+
description: 'the file-history envelope; `null` / absent = none. Every blob it references must already be PUT.'
|
|
3251
3120
|
policy: { type: array, items: { $ref: '#/components/schemas/SessionRulesRecord' } }
|
|
3252
3121
|
anchors: { type: array, items: { $ref: '#/components/schemas/SyncAnchor' } }
|
|
3253
3122
|
title:
|
|
@@ -3324,7 +3193,7 @@ paths:
|
|
|
3324
3193
|
description: >
|
|
3325
3194
|
2c session-sync PUSH Phase B — stream the entry log as an NDJSON REQUEST body into the staged shadow id; the
|
|
3326
3195
|
cloud validates per-line (the streaming invariant gate) then `finish()` (exactly-one-root + leaf-resolvable) →
|
|
3327
|
-
commits (the atomic swap) → replays
|
|
3196
|
+
commits (the atomic swap) → replays fileHistory/policy/anchors. Returns `{ relation }` (the AUTHORITATIVE in-txn
|
|
3328
3197
|
re-classify). Re-POSTing the same stagingId is idempotent. Typed errors: a per-entry / structural violation →
|
|
3329
3198
|
422 `invalid_entries`; a line too large → 413; a commit-time TOCTOU flip to fork/stale → 409 `conflict`
|
|
3330
3199
|
(SyncConflictError); a refused policy loosen → 403 `loosen_forbidden`; a wrong/foreign stagingId → 404.
|
|
@@ -3385,6 +3254,15 @@ paths:
|
|
|
3385
3254
|
application/json:
|
|
3386
3255
|
schema: { $ref: '#/components/schemas/PendingList' }
|
|
3387
3256
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
3257
|
+
'500':
|
|
3258
|
+
description: >-
|
|
3259
|
+
server >= 7.134.0: a queue row whose stored body cannot be read (the store's refusal contract — a retry fails the same way; an operator has to repair
|
|
3260
|
+
or delete that row) answers `500` + `errorCode: "approvals.read_corrupt"` (body `{ error, errorCode }`; the bad row's coordinates stay off the wire) —
|
|
3261
|
+
the same judge and the same code as `GET /v1/approvals/stream`. Do NOT retry it as-is (the SDK's GET retry arm exempts the code). Every other read
|
|
3262
|
+
failure (connection / timeout / store hiccup) is still `500 internal.error`. Older servers answered the corrupt row with `internal.error`.
|
|
3263
|
+
content:
|
|
3264
|
+
application/json:
|
|
3265
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
3388
3266
|
|
|
3389
3267
|
/v1/approvals/stream:
|
|
3390
3268
|
parameters:
|
|
@@ -4458,7 +4336,7 @@ paths:
|
|
|
4458
4336
|
verbatim 400 texts, the two capability bits to probe first and the `deny` posture are on
|
|
4459
4337
|
the PersistRuleSelection schema. Allow-family only (on `deny` the whole field is ignored).
|
|
4460
4338
|
|
|
4461
|
-
⚠️ If the frame carried
|
|
4339
|
+
⚠️ If the frame carried no `ruleOffers`, do not send this key —
|
|
4462
4340
|
there is nothing redeemable for THIS card and the answer is necessarily
|
|
4463
4341
|
`rulePersisted:false` + `rule_lane_unavailable` (the missing material short-circuits BEFORE
|
|
4464
4342
|
any candidate comparison, so it is never `rule_not_offered`). Absence has several causes —
|
|
@@ -5327,39 +5205,6 @@ paths:
|
|
|
5327
5205
|
error: { type: string }
|
|
5328
5206
|
missing: { type: array, items: { type: string } }
|
|
5329
5207
|
|
|
5330
|
-
/v1/approvals/{approvalId}:
|
|
5331
|
-
parameters:
|
|
5332
|
-
- $ref: '#/components/parameters/PrincipalHeader'
|
|
5333
|
-
- in: path
|
|
5334
|
-
name: approvalId
|
|
5335
|
-
required: true
|
|
5336
|
-
schema: { type: string }
|
|
5337
|
-
get:
|
|
5338
|
-
tags: [approvals]
|
|
5339
|
-
operationId: approvalsGet
|
|
5340
|
-
x-status: retired # 5.0.0: legacy approval-store leg deleted — NO deployment serves this route.
|
|
5341
|
-
summary: 'RETIRED (server 5.0.0) — by-id approval read; every deployment answers 404. Use GET /v1/approvals.'
|
|
5342
|
-
description: >
|
|
5343
|
-
🔴 RETIRED as of `@sema-agent/server` 5.0.0 ([2354]/[2356] A-5): the legacy approval-store polling leg
|
|
5344
|
-
that served this route was deleted whole, and the durable checkpoint lane never had a by-id read
|
|
5345
|
-
(it can list by scope or look up by capability token — there is no simple-id query). A worker WITH a
|
|
5346
|
-
checkpoint store answers 404 `not_found.route`; a worker WITHOUT one never matches the `/v1/approvals*`
|
|
5347
|
-
prefix at all. Either way: 404 on every deployment, and that 404 is indistinguishable from "no such
|
|
5348
|
-
approval", which is exactly why the SDK stopped calling it (4.0.1 — `approvals.get` now reads
|
|
5349
|
-
`GET /v1/approvals` and filters by `sessionId`, one round trip instead of a guaranteed-404 probe plus
|
|
5350
|
-
the same list call).
|
|
5351
|
-
Kept in the spec as a tombstone rather than deleted: consumers generated against an older spec need to
|
|
5352
|
-
see WHY the path went away. Decide via `POST /v1/approvals/{sessionId}/decide`; list via `GET /v1/approvals`.
|
|
5353
|
-
Historical shape (below) is left intact for the same reason; it describes no live behavior.
|
|
5354
|
-
responses:
|
|
5355
|
-
'200':
|
|
5356
|
-
description: The approval row (full args projection).
|
|
5357
|
-
content:
|
|
5358
|
-
application/json:
|
|
5359
|
-
schema: { $ref: '#/components/schemas/ApprovalRow' }
|
|
5360
|
-
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
5361
|
-
'404': { $ref: '#/components/responses/NotFound' }
|
|
5362
|
-
|
|
5363
5208
|
/v1/memory/export:
|
|
5364
5209
|
parameters:
|
|
5365
5210
|
- $ref: '#/components/parameters/PrincipalHeader'
|
|
@@ -7801,7 +7646,7 @@ components:
|
|
|
7801
7646
|
`permissions.defaultMode`'s specific fold is documented on `TaskRequest.permissionMode`.
|
|
7802
7647
|
🔴 ON THIS SUBMIT FACE THE KEY SET IS CLOSED (server >= 7.57.0 for the sub-tree): accepted top-level keys
|
|
7803
7648
|
are `env` / `hooks` / `model` / `outputStyle` / `permissions` / `skillListingBudgetFraction` /
|
|
7804
|
-
`skillListingMaxDescChars` / `ultracode` / `webSearch` (server >= 7.133.0 adds the three TIGHTEN-ONLY seats `complianceAdditionalDenies` / `readDenyPatterns` / `writeProtectedExtra`), and accepted `permissions.*` keys are
|
|
7649
|
+
`skillListingMaxDescChars` / `ultracode` / `webSearch` (server >= 7.133.0 adds the three TIGHTEN-ONLY seats `complianceAdditionalDenies` / `readDenyPatterns` / `writeProtectedExtra`; server >= 7.134.0 adds `approvalFrameFamilies`), and accepted `permissions.*` keys are
|
|
7805
7650
|
`allow` / `ask` / `defaultMode` / `deny` / `disableAutoMode` (server >= 7.133.0 adds `neverAuto`); anything else is 400 `request.body_shape`
|
|
7806
7651
|
with the names in the refusal's `unknownKeys` / `unsupportedKeys` arrays (REFUSED, not dropped — a dropped
|
|
7807
7652
|
key reads as "in effect" to the caller). The object stays OPEN here because the same `SemaSettings`
|
|
@@ -7812,6 +7657,15 @@ components:
|
|
|
7812
7657
|
(the request face has no loosening arm); an empty array is the same as not sent. Bad value => 400 `request.field_invalid` with `field` + `reason` (`over_cap` + `count` + `cap` / `bad_entry` + the first bad `index`).
|
|
7813
7658
|
Caps: 1000 entries per seat, EXCEPT `readDenyPatterns`: at most 32 entries, at most 2 `*` per path segment and 16 `*` in the whole table (every star counts, nothing is folded). A `neverAuto` name that can never match any tool => 422.
|
|
7814
7659
|
A resume replay of a stored body whose seat went bad => 409 `resume_blocked_by_policy`. A compliance deny is a REFUSAL, not a narrowing: a request denying `web_fetch` is refused whole where the default tool surface still mounts `WebFetch` (the single-user default does).
|
|
7660
|
+
🔴 `settings.approvalFrameFamilies` (server >= 7.134.0; send it on sight of `capabilities.taskSettings.approvalFrameFamilies === true` — NOT of the top-level
|
|
7661
|
+
`capabilities.approvalFrameFamilies`, which <= 7.133.x already has while answering 400 `request.body_shape` for this key): the approval opening-frame FAMILIES this
|
|
7662
|
+
run's client RENDERS — an array of `tool_approval` / `approval_request`, each once (`[]` reads as absent). Bad value (not an array / a word outside the set / a
|
|
7663
|
+
repeat) => 400 `request.field_invalid` with `field: "settings.approvalFrameFamilies"`, `reason: "bad_entry"` and `index` (absent for a non-array). BEHAVIOR (BREAKING, wire):
|
|
7664
|
+
a run whose declaration does not contain the family this worker presents (`capabilities.approvalFrameFamilies`) has NO live approval channel — no card of either
|
|
7665
|
+
family (no fallback, no double send), no replay in the stream preamble of the sync stream or of `GET /v1/runs/{taskId}/events`; every ask goes to the unattended
|
|
7666
|
+
policy at once: with a durable store (`capabilities.approvals`) it parks per the operator policy (default; answer through `POST /v1/approvals/{sessionId}/decide`)
|
|
7667
|
+
or is refused naming the missing family; with NO durable store the gated tool is refused on the spot and the run finishes (no card, no decide). The declaration
|
|
7668
|
+
rides the persisted body onto resume legs.
|
|
7815
7669
|
🔴 `settings.hooks[]` (server >= 7.133.0; probe `capabilities.taskSettings.pluginHooks` / `managedHookGroups` — an absent or false bit = the keys are STRIPPED SILENTLY): group key `source` (closed: `managedPolicy` / `user` / `project` / `local` / `flag` /
|
|
7816
7670
|
`managedPlugin:<name>` / `plugin:<name>`; absent = unmanaged; managed groups run in an independent lane after the unmanaged rewrites), command-entry keys `plugin { name, root, dataDir?, options? }` and exec-form `args`; a malformed one =>
|
|
7817
7671
|
400 `request.field_invalid` with `detail: { reason: "wire_key_invalid", key, path }`; the plugin context has one 8192-character budget.
|
|
@@ -9659,6 +9513,14 @@ components:
|
|
|
9659
9513
|
redispatched: { type: array, items: { type: string } }
|
|
9660
9514
|
collapsed: { type: string }
|
|
9661
9515
|
|
|
9516
|
+
ApprovalFrameFamily:
|
|
9517
|
+
type: string
|
|
9518
|
+
enum: [tool_approval, approval_request]
|
|
9519
|
+
description: >-
|
|
9520
|
+
The approval opening-frame FAMILY words (closed; the server's `APPROVAL_FRAME_FAMILIES` verbatim and in order): `tool_approval` = the legacy family
|
|
9521
|
+
(live card `tool_approval` / close `tool_approval_complete`); `approval_request` = the card family (`approval_request` / `approval_complete` /
|
|
9522
|
+
batch revoke `approval_revoke`). ONE vocabulary for two faces: the capability `approvalFrameFamilies` (which family this worker presents) and, server >= 7.134.0,
|
|
9523
|
+
the request key `settings.approvalFrameFamilies` (which families this run's client renders).
|
|
9662
9524
|
ApprovalDecision:
|
|
9663
9525
|
type: object
|
|
9664
9526
|
description: HITL decision (`POST /v1/approvals/:sessionId/decide`).
|
|
@@ -9726,30 +9588,17 @@ components:
|
|
|
9726
9588
|
refused by the ENGINE before the CAS (409 `resume_outcome_invalid` + `field: "hostDecision"`, the card stays
|
|
9727
9589
|
pending); outside the closed set ⇒ 400 `request.field_invalid`; any value on a direct-door worker ⇒ 400
|
|
9728
9590
|
`decided_by_not_in_proof`. An older server (no `approvalDecidedBy` bit) refuses the key (400 `request.body_shape`).
|
|
9729
|
-
|
|
9730
|
-
|
|
9731
|
-
|
|
9732
|
-
|
|
9733
|
-
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
9737
|
-
|
|
9738
|
-
|
|
9739
|
-
|
|
9740
|
-
properties:
|
|
9741
|
-
id: { type: string }
|
|
9742
|
-
taskId: { type: [string, 'null'] }
|
|
9743
|
-
sessionId: { type: [string, 'null'] }
|
|
9744
|
-
owner: { type: [string, 'null'] }
|
|
9745
|
-
scope: { type: [string, 'null'], description: 'Single-DB fleet scope guard (tenant identity, owner-sourced).' }
|
|
9746
|
-
toolName: { type: string }
|
|
9747
|
-
args: { description: 'The reviewed tool-call args — full fidelity, not redacted (this IS the review surface).' }
|
|
9748
|
-
status: { type: string, enum: [pending, approved, denied, expired] }
|
|
9749
|
-
reason: { type: [string, 'null'] }
|
|
9750
|
-
decidedBy: { type: [string, 'null'] }
|
|
9751
|
-
createdAt: { type: string }
|
|
9752
|
-
decidedAt: { type: [string, 'null'] }
|
|
9591
|
+
feedback:
|
|
9592
|
+
type: string
|
|
9593
|
+
description: >-
|
|
9594
|
+
server >= 7.134.0 (core 7.54.0) — what the approving PERSON writes in the card's "and tell the agent what to do next" input: on the resumed
|
|
9595
|
+
leg it reaches the model as the user's own words (unfenced, unbounded — like the reference's accepted-prompt feedback). ONLY on a person's approve
|
|
9596
|
+
(`decision: "approve"`, `decidedBy` absent or `person`): on a deny or a `decidedBy: "policy"` decision ⇒ 400 `request.field_conflict` with
|
|
9597
|
+
`detail.kind: "approval_feedback"` and `detail.fields` `["feedback", "decision"]` / `["feedback", "decidedBy"]` (a denial's words go in `reason`);
|
|
9598
|
+
a non-string ⇒ 400 `request.field_invalid`; any value on a direct-door worker ⇒ 400 `feedback_not_in_proof` (not inside the signed proof); words
|
|
9599
|
+
carrying `<system-reminder>` ⇒ 409 `approval_binding_mismatch` (the engine's sentence; the card stays pending — ask the person to change the words,
|
|
9600
|
+
do not auto-refetch and re-decide on the code). The same door serves parked background-agent cards and workflow child cards; the live
|
|
9601
|
+
`POST /v1/tool-approvals/{id}/respond` does NOT take it. Servers <= 7.133.x refuse the key (400 `request.body_shape`, `unknownKeys: ["feedback"]`).
|
|
9753
9602
|
|
|
9754
9603
|
Capabilities:
|
|
9755
9604
|
type: object
|
|
@@ -10029,25 +9878,12 @@ components:
|
|
|
10029
9878
|
leaseClient: { type: boolean, description: 'server >= 7.121.0, a version bit (always true, rides with the `fleet` object): this binary carries the serving-lease CLIENT — when the engine is a fleet member (`FLEET_GENERATION`) and the center declares in its heartbeat reply that it answers renewals (`servingLease`), the engine renews and is governed by the lease. Deliberately NOT named `servingLease` (that is the center''s bit): this says the client exists, not that a lease is in force — read `/health.leaseState` for that. Absent = an older worker.' }
|
|
10030
9879
|
generationEcho: { type: boolean, description: 'server >= 7.121.0, a version bit (always true, rides with the `fleet` object): this binary echoes env `FLEET_GENERATION` as `generation` on the heartbeat and on `/health` (with `leaseState` / `leaseUntil`), and the drain endpoint `POST /v1/admin/drain` compares the four-part identity including `expectedGeneration`. Absent = an older worker.' }
|
|
10031
9880
|
workspace:
|
|
9881
|
+
type: boolean
|
|
9882
|
+
enum: [false]
|
|
10032
9883
|
description: >
|
|
10033
|
-
|
|
10034
|
-
|
|
10035
|
-
|
|
10036
|
-
⇒ 413 workspace_file_too_large envelope; the archive endpoint is the escape hatch).
|
|
10037
|
-
🔴 RETIRED (server ≥7.52, S-15/design/381): the whole-tree snapshot epoch this face projected was
|
|
10038
|
-
replaced by per-edited-file rewind history, so this key is now ALWAYS false and the four
|
|
10039
|
-
/v1/sessions/{sessionId}/workspace* routes answer 501 `capability.workspace_retired` (route shape
|
|
10040
|
-
kept as a tombstone — a named refusal, not a 404 that reads like a typo). Consumption posture
|
|
10041
|
-
unchanged: probe this bit, false ⇒ don't render the panel.
|
|
10042
|
-
oneOf:
|
|
10043
|
-
- type: boolean
|
|
10044
|
-
enum: [false]
|
|
10045
|
-
- type: object
|
|
10046
|
-
additionalProperties: true
|
|
10047
|
-
properties:
|
|
10048
|
-
browse: { type: boolean }
|
|
10049
|
-
archive: { type: boolean }
|
|
10050
|
-
maxFileBytes: { type: integer }
|
|
9884
|
+
The workspace-browse bit — ALWAYS `false` on every supported server (>= 7.52.0: the whole-tree snapshot epoch was replaced by
|
|
9885
|
+
per-edited-file rewind history; the four /v1/sessions/{sessionId}/workspace* routes answer 501 `capability.workspace_retired`, route shape kept as a
|
|
9886
|
+
tombstone). sdk 26.0.0 deleted the object arm `{ browse, archive, maxFileBytes }` (servers 1.299–7.51, below the support floor).
|
|
10051
9887
|
sessionEvents:
|
|
10052
9888
|
type: boolean
|
|
10053
9889
|
description: >
|
|
@@ -10140,7 +9976,7 @@ components:
|
|
|
10140
9976
|
approvalFrameFamilies:
|
|
10141
9977
|
type: array
|
|
10142
9978
|
maxItems: 1
|
|
10143
|
-
items: {
|
|
9979
|
+
items: { $ref: '#/components/schemas/ApprovalFrameFamily' }
|
|
10144
9980
|
description: >-
|
|
10145
9981
|
server >= 7.133.0, ALWAYS present (the projection of the same judgement as `streamApproval`) — which FRAME FAMILY this worker's approval opening frames belong to:
|
|
10146
9982
|
a closed-word array with AT MOST ONE member. `["approval_request"]` = the card protocol is on: one ask travels only `approval_request` -> `approval_complete` / `approval_revoke`
|
|
@@ -10148,6 +9984,9 @@ components:
|
|
|
10148
9984
|
remedy on the worker: `STREAM_APPROVAL_ENABLED=false`). `["tool_approval"]` = the card protocol is not on (`STREAM_APPROVAL_ENABLED=false`, no store backend, or no checkpoint store) but the live card leg is.
|
|
10149
9985
|
`[]` = per-call approvals are off altogether (`TOOL_APPROVAL_ENABLED=false`): no card is presented. Dispatch frame families off THIS array, never off `streamApproval`.
|
|
10150
9986
|
KEY ABSENT (not `[]`) = server <= 7.132.x — there a `streamApproval: true` leg sends BOTH families for one ask.
|
|
9987
|
+
🔴 server >= 7.134.0: this bit says which family THIS WORKER presents, no longer that you will receive cards — a run has a live approval channel only when
|
|
9988
|
+
its submit body declared that family in `settings.approvalFrameFamilies` (send it on sight of `taskSettings.approvalFrameFamilies`, not of this bit — <= 7.133.x
|
|
9989
|
+
already had this bit yet answers 400 `request.body_shape` for the key). The value does not change with a declaration. The words are the request key's words.
|
|
10151
9990
|
streamApproval:
|
|
10152
9991
|
type: boolean
|
|
10153
9992
|
description: >
|
|
@@ -10324,6 +10163,7 @@ components:
|
|
|
10324
10163
|
pluginHooks: { type: boolean, description: 'server >= 7.133.0 — the request `settings.hooks[]` PLUGIN-CONTEXT keys (command entry `plugin { name, root, dataDir?, options? }` / exec-form `args`) are accepted; same predicate as `hooks` (single-user true, multi-tenant false). ABSENT or false = the keys are stripped silently — send only on sight of the bit.' }
|
|
10325
10164
|
managedHookGroups: { type: boolean, description: 'server >= 7.133.0 — the request `settings.hooks[]` GROUP `source` key (managed lanes `managedPolicy` / `managedPlugin:<name>`) is accepted; same predicate as `hooks`. ABSENT or false = stripped silently (the managed-lane semantics do not apply, it is not a refusal).' }
|
|
10326
10165
|
tightenOnlySeats: { type: boolean, description: 'server >= 7.133.0, constant true — the four tighten-only request seats `settings.readDenyPatterns` / `settings.writeProtectedExtra` / `settings.complianceAdditionalDenies` / `settings.permissions.neverAuto` are accepted (each seat = deployment table UNION request list, only ever growing; an empty array is the same as not sent). ABSENT = server <= 7.132.x, which answers 400 `request.body_shape` for those keys — send only on sight of the bit.' }
|
|
10166
|
+
approvalFrameFamilies: { type: boolean, description: 'server >= 7.134.0, constant true — the request key `settings.approvalFrameFamilies` (which approval opening-frame families this run''s client renders) is accepted. THIS is the trigger bit for that key, NOT the top-level `approvalFrameFamilies`: servers <= 7.133.x already carry the top-level bit yet answer 400 `request.body_shape` (`unknownKeys: ["settings.approvalFrameFamilies"]`) for the key. ABSENT = do not send it.' }
|
|
10327
10167
|
settings:
|
|
10328
10168
|
type: object
|
|
10329
10169
|
description: >
|
|
@@ -11931,7 +11771,8 @@ components:
|
|
|
11931
11771
|
# 没声明 ⇒ 键缺席 ⇒ 不再是必有键(此前由 `input` 恒算成布尔,对没声明的条目报 false)。
|
|
11932
11772
|
# 🔴 server 7.131.0 起 `reasoning` 同样三态:env 车道 `MODEL_REASONING` / `MODEL_VISION` 缺省 true 退役、中心名册条目不写即不声明
|
|
11933
11773
|
# ⇒ 两键都「未声明 = 键缺席」,`required` 只剩 name / id / provider(sdk 23.1.0;TS 型 `ModelInfo.reasoning?` 早已可选)。
|
|
11934
|
-
required
|
|
11774
|
+
# sdk 26.0.0(支持底线 7.52.0):`routePairing` 进 required(≥7.45 恒铸,此前因地板 3.0.0 不进)。
|
|
11775
|
+
required: [name, id, provider, routePairing]
|
|
11935
11776
|
additionalProperties: false
|
|
11936
11777
|
properties:
|
|
11937
11778
|
name: { type: string, description: 'the @mention handle (user-pickable model name).' }
|
|
@@ -11955,8 +11796,8 @@ components:
|
|
|
11955
11796
|
adjudicated" must stay distinguishable on the wire). Declared here 2026-09-10 alongside `compat`:
|
|
11956
11797
|
this schema is CLOSED, and the key has been minted unconditionally since 7.45 — so every real
|
|
11957
11798
|
/v1/models response has been structurally rejected by a strict validator for the whole time (same
|
|
11958
|
-
class as `hasBidiControls` on InboxRow).
|
|
11959
|
-
|
|
11799
|
+
class as `hasBidiControls` on InboxRow). REQUIRED since sdk 26.0.0 (the support floor 7.52.0 is above 7.45; it
|
|
11800
|
+
was optional only while the floor was 3.0.0).
|
|
11960
11801
|
compat:
|
|
11961
11802
|
$ref: '#/components/schemas/ModelCompat'
|
|
11962
11803
|
description: >-
|
|
@@ -12766,19 +12607,6 @@ components:
|
|
|
12766
12607
|
startedAt: { type: integer }
|
|
12767
12608
|
elapsedMs: { type: integer }
|
|
12768
12609
|
tokens: { type: integer }
|
|
12769
|
-
# tokenDir REMOVED (engine ruling 2026-06-28): dead field, 0 producer / 0 consumer — spec caught up 2026-07-26.
|
|
12770
|
-
queuedCount:
|
|
12771
|
-
type: integer
|
|
12772
|
-
description: >-
|
|
12773
|
-
🔴 PHANTOM KEY — NO server version ever emits it (verified against the published 7.87.0 bytes:
|
|
12774
|
-
the row type declares it and the fleet route's per-key table forwards it, but NO producer writes it
|
|
12775
|
-
— not `publishTask`'s call sites, not core's bg-sink tick, not the durable reconcile leg — and the
|
|
12776
|
-
wire contract does not mention it either). The server deleted it as a DEAD KEY (S-459, zero
|
|
12777
|
-
behavioural impact since `!== undefined` was always false). It stays declared here only because
|
|
12778
|
-
removing an exported field is BREAKING = major-only; it is registered with its deletion condition
|
|
12779
|
-
in `test/_keyset-divergence.ts` (`FLEET_TASK_ROW_PHANTOM_KEYS`) and goes with the next major.
|
|
12780
|
-
DO NOT read it as "queue depth is already reported" — a permanently absent optional key is a FALSE
|
|
12781
|
-
LEAD. Real queue depth needs a NEW key WITH a producer, not this one resurrected.
|
|
12782
12610
|
awaitingPlanApproval: { type: boolean }
|
|
12783
12611
|
currentAction: { type: string, description: "The child's most recent tool intent as one human-readable line (UNTRUSTED argument head, redacted server-side)." }
|
|
12784
12612
|
currentTool:
|
|
@@ -12892,6 +12720,13 @@ components:
|
|
|
12892
12720
|
failedCount: { type: integer }
|
|
12893
12721
|
elapsedMs: { type: integer }
|
|
12894
12722
|
tokens: { type: integer }
|
|
12723
|
+
errorCode:
|
|
12724
|
+
type: string
|
|
12725
|
+
description: >-
|
|
12726
|
+
server >= 7.134.0 — the workflow run's MACHINE code (open set; the same words as the same-named slot on `GET /v1/workflows/{id}`): carried verbatim when the
|
|
12727
|
+
run row has one, the key ABSENT otherwise (never an empty string). A parked workflow run reads `status: "failed"` + `errorCode: "workflow.agent_parked"`
|
|
12728
|
+
(parked, not failed; the `status` vocabulary gains no word). Snapshot rows, `workflow` upsert frames and rows merged from the terminal window share one mint
|
|
12729
|
+
point; a `?session=` subscriber's demoted rows carry it too. ABSENT = an older server, or no code on this row — fall back to `status`.
|
|
12895
12730
|
FleetFrame:
|
|
12896
12731
|
description: >
|
|
12897
12732
|
One decoded frame off GET /v1/fleet/stream (service streamFleet emit set, src/http/routes/fleet.ts). On the
|
|
@@ -13105,7 +12940,8 @@ components:
|
|
|
13105
12940
|
DISTINCT vocabulary from AgentEvent (the durable log is BLOCK-grained, each frame is a delta to append).
|
|
13106
12941
|
Resumable (each `id:` = the durable task_event.seq; on 416 the server returns `{retainedFrom}` and the SDK
|
|
13107
12942
|
resumes from there after a turns full-sync). Known events: meta / block-thinking-delta / block-content-delta
|
|
13108
|
-
/ tool-call / tool-result /
|
|
12943
|
+
/ tool-call / tool-result / prompt-assembled / cross-boundary-taint (server >= 7.134.0: the device lane's taint row + `seq`, see
|
|
12944
|
+
`Event_cross_boundary_taint`) / turn / done / error (+ heartbeat keep-alives the SDK swallows). Open set.
|
|
13109
12945
|
NOTE: SSE framing on the wire (event name + JSON data + optional id), not a JSON body.
|
|
13110
12946
|
required: [event, data]
|
|
13111
12947
|
additionalProperties: true
|
|
@@ -13122,10 +12958,11 @@ components:
|
|
|
13122
12958
|
description: >
|
|
13123
12959
|
契约调和车1 G(2026-08-02;server [2373]C-12, `src/trace/project.ts` + the meta frame at
|
|
13124
12960
|
`routes/trace-usage.ts`): the frame's own event name, DOUBLE-EMITTED inside `data`. Always
|
|
13125
|
-
present on server >=
|
|
13126
|
-
|
|
13127
|
-
|
|
13128
|
-
|
|
12961
|
+
present on every named frame of a supported server (>= 7.52.0; minted since server 5.0.0) — the SDK's
|
|
12962
|
+
typed arms declare it REQUIRED since 26.0.0; it is not in this schema's `required` only because the one
|
|
12963
|
+
schema also covers heartbeats (`data: {}`, which carry none and which the SDK swallows). Equal to the SSE
|
|
12964
|
+
`event:` line verbatim — its reason to exist is the proxy/relay case that strips the `event:` line and
|
|
12965
|
+
forwards only the data JSON, where this is the only key left to dispatch on.
|
|
13129
12966
|
output:
|
|
13130
12967
|
allOf: [{ $ref: '#/components/schemas/ToolOutput' }]
|
|
13131
12968
|
description: >
|
|
@@ -13528,26 +13365,13 @@ components:
|
|
|
13528
13365
|
is RETIRED: the SQL backend rewrote its parked rows once at the 7.117.0 boot to `[{ member: "persisted", entries: [<old value>] }]`, but the
|
|
13529
13366
|
file backend's pre-upgrade parked rows and run results already on disk (`checkpointGate.riskDescriptor`) keep the old key verbatim
|
|
13530
13367
|
(text still redacted, no structured disclosure) — a consumer reading those must still tolerate the old string.
|
|
13531
|
-
# server 7.16.0 [3684]② — durable 队列行归因两键(与活卡 tool_approval 帧的同名键语义同族、判据不同源;
|
|
13532
|
-
# 两条腿对同一只 ask 的在场性可以不一致,两侧都只认在场、都禁把缺席读成否定)。
|
|
13533
|
-
ruleSuggestions:
|
|
13534
|
-
type: array
|
|
13535
|
-
minItems: 1
|
|
13536
|
-
items: { $ref: '#/components/schemas/RuleSuggestion' }
|
|
13537
|
-
description: >
|
|
13538
|
-
server 7.16.0 ([3684]②), ADDITIVE: the rule candidates minted for this ask, replayed off the durable
|
|
13539
|
-
row (checkpoint.rule_suggestions). DISPLAY-ONLY on this leg — the durable queue has no persistRule
|
|
13540
|
-
redemption; the only redemption path is the LIVE card leg (respond + persistRule). Array order =
|
|
13541
|
-
display order; an EXACT entry, when present, is always first. core contract caps candidates at 2;
|
|
13542
|
-
the server enforces a tolerance cap of 4 on read-back — lay out for 4. Absent = pre-column row
|
|
13543
|
-
(parked before the column existed) OR no candidates; render both as "no candidates", never an error.
|
|
13544
13368
|
ruleOffers:
|
|
13545
13369
|
type: array
|
|
13546
13370
|
minItems: 1
|
|
13547
13371
|
items: { $ref: '#/components/schemas/RuleOffer' }
|
|
13548
13372
|
description: >
|
|
13549
13373
|
server >= 7.46.0 (core 5.58.0, design/375) — the discriminated-union successor of the retired
|
|
13550
|
-
`ruleSuggestions`
|
|
13374
|
+
`ruleSuggestions` (servers <= 7.45; sdk 26.0.0 deleted it) on the DURABLE queue row (core `PendingAction.ruleOffers`, the same
|
|
13551
13375
|
contract as the sync leg's `AskRequest.ruleOffers`). A >= 7.46.0 row carries only the new key;
|
|
13552
13376
|
pre-5.58 rows fail the new narrow read entry by entry and land as "no supply" (no compatibility
|
|
13553
13377
|
read — a stale schema means re-ask).
|
|
@@ -13772,25 +13596,20 @@ components:
|
|
|
13772
13596
|
one-off question. The value comes WHOLE from core (`summarizeCheckpoint` echoes it only when the
|
|
13773
13597
|
cause is a member of the engine's set), so the server neither recomputes nor re-screens it. See
|
|
13774
13598
|
ClassifierUnavailable for the open-`cause` rule and the three shapes absence covers.
|
|
13775
|
-
RETIRED: server >= 7.72.0 (core 7.14.0
|
|
13599
|
+
RETIRED: server >= 7.72.0 (core 7.14.0) never mints this key on any of the three faces; its
|
|
13776
13600
|
successor is `disposition.cause` on the gate record (`unavailable` / `parse_error` — a different
|
|
13777
|
-
question, so an old switch does not port). Kept for servers in [7.69.0, 7.72.0) only (sdk 9.2.0)
|
|
13601
|
+
question, so an old switch does not port). Kept for servers in [7.69.0, 7.72.0) only (sdk 9.2.0); the row key retires
|
|
13602
|
+
together with the frame key (floor ≥ 7.106.0, next major); why the frame still declares it: `ToolApprovalFrame.classifierUnavailable`.
|
|
13778
13603
|
ruleStoreUnreadable:
|
|
13779
13604
|
type: string
|
|
13780
13605
|
enum: [store, call]
|
|
13781
13606
|
description: >-
|
|
13782
|
-
server >= 7.72.0 (core 7.14.0 #688 C3), ADDITIVE — WHICH HALF of the rule lane could not be read.
|
|
13783
|
-
|
|
13784
|
-
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
|
|
13788
|
-
which is not on the card). Absence = `origin` is not that word — NOT an assertion that the rule store
|
|
13789
|
-
is healthy.
|
|
13790
|
-
RETIRED: server >= 7.106.0 (core 7.34.0 C-R172, BREAKING — wire) never mints this key on either face — an
|
|
13791
|
-
unreadable rule store no longer raises a card: that read's rows are SKIPPED by partition and the session
|
|
13792
|
-
stream gets the user-facing `engine_notice` `permission.rule_store_unavailable` (`detail.at` = `prepare` /
|
|
13793
|
-
`call`). Kept for servers in [7.72.0, 7.106.0) only (sdk K-32); `origin: rule_store_unavailable` itself stays.
|
|
13607
|
+
server >= 7.72.0 (core 7.14.0 #688 C3), ADDITIVE — WHICH HALF of the rule lane could not be read (`store` / `call`).
|
|
13608
|
+
The same key, with the same two words and the same reading, as on the live frame; the authoritative statement of the shape, the presence
|
|
13609
|
+
rule, what the two words mean and the retirement wording is on `ToolApprovalFrame.ruleStoreUnreadable`, and this description points to it.
|
|
13610
|
+
RETIRED: server >= 7.106.0 never mints this key on either face (the frame's description names the successor). Kept for
|
|
13611
|
+
servers in [7.72.0, 7.106.0) only (sdk K-32); the row key retires together with the frame key (floor ≥ 7.106.0, next major);
|
|
13612
|
+
`origin: rule_store_unavailable` itself stays.
|
|
13794
13613
|
|
|
13795
13614
|
InboxList:
|
|
13796
13615
|
type: object
|
|
@@ -14685,26 +14504,6 @@ components:
|
|
|
14685
14504
|
parentId: { type: [string, 'null'] }
|
|
14686
14505
|
type: { type: string, description: Entry discriminator (message / leaf / compaction / …) — opaque to the SDK. }
|
|
14687
14506
|
|
|
14688
|
-
SyncSnapshot:
|
|
14689
|
-
type: object
|
|
14690
|
-
description: >
|
|
14691
|
-
One E19 file snapshot keyed by a `SessionTreeEntry.id`. `manifest` = `[relPath, blobHash]` tuples; the blob
|
|
14692
|
-
BYTES are NOT inlined (they ride the content-addressed blob routes).
|
|
14693
|
-
# 封闭(census 批2 第三段,2026-07-30):server 侧类型+铸造点(`session-sync.ts` PULL 出 /
|
|
14694
|
-
# `routes/session-sync.ts` PUSH 校验形)都恰是这两键。
|
|
14695
|
-
additionalProperties: false
|
|
14696
|
-
required: [key, manifest]
|
|
14697
|
-
properties:
|
|
14698
|
-
key: { type: string }
|
|
14699
|
-
manifest:
|
|
14700
|
-
type: array
|
|
14701
|
-
items:
|
|
14702
|
-
type: array
|
|
14703
|
-
minItems: 2
|
|
14704
|
-
maxItems: 2
|
|
14705
|
-
items: { type: string }
|
|
14706
|
-
description: A `[relPath, blobHash]` tuple.
|
|
14707
|
-
|
|
14708
14507
|
SyncAnchor:
|
|
14709
14508
|
type: object
|
|
14710
14509
|
description: One E18 resume-at anchor. `owner` is RE-KEYED to the importing principal on a PUSH (§9).
|
|
@@ -14732,31 +14531,28 @@ components:
|
|
|
14732
14531
|
description: >
|
|
14733
14532
|
2c session-sync `GET …/sync/manifest` payload (wrapped server-side as `{ manifest }`). The THIN cross-backend
|
|
14734
14533
|
snapshot: entry IDS (oldest-first, NOT payloads) + the file-history envelope + policy + anchors + leaf.
|
|
14735
|
-
|
|
14736
|
-
|
|
14737
|
-
|
|
14738
|
-
|
|
14739
|
-
|
|
14740
|
-
`
|
|
14741
|
-
(`GET …/sync/history/blobs/{hash}` / `PUT …/sync/blobs/{hash}`; probe `capabilities.sessionSyncFileHistory` on BOTH ends).
|
|
14742
|
-
The SDK's `manifest()` fills `snapshots: []` when the wire omits it.
|
|
14534
|
+
The server's `exportSessionManifest` mints `{ sessionId, entryIds, entryCount, leafId, fileHistory, policy, anchors }` (server >= 7.125.0 adds the
|
|
14535
|
+
session row's two writable bits `title` / `pinned`, present-iff the session is a row of the list face — see the two properties). `fileHistory`
|
|
14536
|
+
(core's versioned `FileHistoryExport` envelope; `null` = no history / the source store cannot export) is ALWAYS present on a supported server
|
|
14537
|
+
(>= 7.52.0); the retired E19 whole-tree snapshot key `snapshots` of servers <= 7.51 is below the support floor (sdk 26.0.0 deleted it). The blob BYTES
|
|
14538
|
+
never ride the manifest: content-addressed, via the history blob faces (`GET …/sync/history/blobs/{hash}` / `PUT …/sync/blobs/{hash}`; probe
|
|
14539
|
+
`capabilities.sessionSyncFileHistory` on BOTH ends). The SDK returns the wire verbatim.
|
|
14743
14540
|
# 封闭(census 批2 第三段,2026-07-30;16.2.0 按 7.116.0 发布字节重核):铸造点 `session-sync.ts`(exportSessionManifest 尾部
|
|
14744
14541
|
# 字面量)恰是 `{ sessionId, entryIds, entryCount, leafId, fileHistory, policy, anchors }` 7 键(≥7.52),无 `snapshots`;
|
|
14745
14542
|
# server ≥7.125.0 另有 `title` / `pinned` 两键(会话行可写位,present-iff 会话是列表面上的行;条件展开,不进 required);
|
|
14746
|
-
#
|
|
14543
|
+
# sdk 26.0.0(支持底线 7.52.0):`fileHistory` 进 required(支持面内恒铸),`snapshots` 删(≤7.51 才发)。
|
|
14747
14544
|
additionalProperties: false
|
|
14748
|
-
required: [sessionId, entryIds, entryCount, leafId, policy, anchors]
|
|
14545
|
+
required: [sessionId, entryIds, entryCount, leafId, fileHistory, policy, anchors]
|
|
14749
14546
|
properties:
|
|
14750
14547
|
sessionId: { type: string }
|
|
14751
14548
|
entryIds: { type: array, items: { type: string }, description: Oldest-first, verbatim cross-backend. }
|
|
14752
14549
|
entryCount: { type: integer, description: '= entryIds.length (the `/sync/entries` trailer count).' }
|
|
14753
14550
|
leafId: { type: [string, 'null'] }
|
|
14754
|
-
snapshots: { type: array, items: { $ref: '#/components/schemas/SyncSnapshot' }, description: 'server <= 7.51 ONLY (the retired E19 snapshot epoch); server >= 7.52 does not send it — see `fileHistory`.' }
|
|
14755
14551
|
fileHistory:
|
|
14756
14552
|
oneOf:
|
|
14757
14553
|
- { $ref: '#/components/schemas/FileHistoryExport' }
|
|
14758
14554
|
- { type: 'null' }
|
|
14759
|
-
description: '
|
|
14555
|
+
description: 'the per-edited-file rewind history envelope; `null` = no history / the source store cannot export. Always present on a supported server.'
|
|
14760
14556
|
policy: { type: array, items: { $ref: '#/components/schemas/SessionRulesRecord' } }
|
|
14761
14557
|
anchors: { type: array, items: { $ref: '#/components/schemas/SyncAnchor' } }
|
|
14762
14558
|
title:
|
|
@@ -14819,20 +14615,18 @@ components:
|
|
|
14819
14615
|
SessionBundle:
|
|
14820
14616
|
type: object
|
|
14821
14617
|
description: >
|
|
14822
|
-
The portable state of ONE session, ready to replay into another backend. Blobs are NOT inlined (
|
|
14823
|
-
|
|
14824
|
-
assembles this from a manifest + the streamed entries for a PUSH.
|
|
14825
|
-
|
|
14826
|
-
required: [sessionId, entries, snapshots, policy, anchors]
|
|
14618
|
+
The portable state of ONE session, ready to replay into another backend. Blobs are NOT inlined (the file-history
|
|
14619
|
+
envelope carries only blob hashes; the bytes stream through the content-addressed blob routes). The SDK
|
|
14620
|
+
assembles this from a manifest + the streamed entries for a PUSH.
|
|
14621
|
+
required: [sessionId, entries, fileHistory, policy, anchors]
|
|
14827
14622
|
properties:
|
|
14828
14623
|
sessionId: { type: string }
|
|
14829
14624
|
entries: { type: array, items: { $ref: '#/components/schemas/SyncEntry' } }
|
|
14830
|
-
snapshots: { type: array, items: { $ref: '#/components/schemas/SyncSnapshot' } }
|
|
14831
14625
|
fileHistory:
|
|
14832
14626
|
oneOf:
|
|
14833
14627
|
- { $ref: '#/components/schemas/FileHistoryExport' }
|
|
14834
14628
|
- { type: 'null' }
|
|
14835
|
-
description: '
|
|
14629
|
+
description: 'the file-history envelope (same as `SessionManifest.fileHistory`; `null` = none, or the pull did not carry it because the source has no blob faces).'
|
|
14836
14630
|
policy: { type: array, items: { $ref: '#/components/schemas/SessionRulesRecord' } }
|
|
14837
14631
|
anchors: { type: array, items: { $ref: '#/components/schemas/SyncAnchor' } }
|
|
14838
14632
|
|
|
@@ -15020,8 +14814,9 @@ components:
|
|
|
15020
14814
|
<= 7.105.0 answered the synchronous leg 200 + a failed body), `corrupt` (500 — the session rule store
|
|
15021
14815
|
cannot read its own bytes), `internal.memory_control_plane_corrupt` (500 — the memory control plane refuses
|
|
15022
14816
|
fail-closed) and `state.scenario_assignment_unknown` (503, server >= 7.119.0 — the center's scenario assignment for the
|
|
15023
|
-
principal is dangling; only re-pointing the assignment, or adding the scenario back to the deployment, helps)
|
|
15024
|
-
|
|
14817
|
+
principal is dangling; only re-pointing the assignment, or adding the scenario back to the deployment, helps) and
|
|
14818
|
+
`approvals.read_corrupt` (500, server >= 7.134.0 on `GET /v1/approvals` — a queue row's stored body cannot be read; an operator has to repair or
|
|
14819
|
+
delete the row). Every other 5xx code keeps the status-based retry.
|
|
15025
14820
|
🔴 `request.host_posture_refused` (422) has TWO triggers (same code, same status — "you wrote it right, this
|
|
15026
14821
|
deployment will not grant that host posture"): (1) the write-containment face (`permissionMode: bypassPermissions` ⇒
|
|
15027
14822
|
`writeFace: open`; read `capabilities.taskWriteFaceOpen` first); (2) server >= 7.106.0 / S-895: `inheritEnv: "all"` on a
|
|
@@ -15095,7 +14890,7 @@ components:
|
|
|
15095
14890
|
S-904): `over_cap` (more than `cap` entries; beside `count` + `cap`) / `bad_entry` (a non-string or empty item; beside
|
|
15096
14891
|
`index`); server >= 7.132.0 widens that group to every tool-name list on the body, the agent definitions and the two host-path lists, and adds
|
|
15097
14892
|
`too_long` (a text over its character cap; beside `count` + `cap`) — closed words `over_cap` / `too_long` / `bad_entry` (SDK `RequestFieldRefusalExtra`); server >= 7.133.0 adds `too_large` (a payload over its BYTE cap, only on 413 `request.payload_too_large`: `{ field: "body", reason: "too_large", cap }` — `count` ABSENT when the read stopped at the cap and cannot measure; a request body over 8 MiB is now always that 413) and the `request.invalid_json` reasons `not_json` | `not_object` (400, every JSON-body door; formerly `request.rejected`/`request.body_shape` by door).
|
|
15098
|
-
On 409 refusals of a resume (server >= 7.132.0): the engine's `CheckpointErrorReason` arm (`detail.reason` passed through; see `blockedBy`). On 400 `rules.inert_entry` (server >= 7.129.0): the engine's `ALLOW_ENTRY_INERT_REASONS` (`tool_name` / `wildcard_all` / `namespace_wildcard` / `content_unsupported` / `grammar` / `near_miss` / `earlier_grammar`). Out-of-vocabulary word ⇒ treat as unknown. (Other codes carry their own `reason` words.)
|
|
14893
|
+
On 409 refusals of a resume (server >= 7.132.0) and on 422 `parked_resume.startup_failed` (server >= 7.134.0 — the parked background agent's pre-claim failure; absent when the engine gave none): the engine's `CheckpointErrorReason` arm (`detail.reason` passed through; see `blockedBy`). On 409 `conflict.checkpoint_ctx_unsealable` (server >= 7.134.0): why the request's credentials cannot be sealed into, or unsealed from, the stored resume context — a closed five-word set (SDK `CHECKPOINT_CTX_UNSEALABLE_REASONS`); which doors can answer which word is written once, in the SDK documentation of `CHECKPOINT_CTX_UNSEALABLE_REASONS`, not here: `no_key_store` (this server has no sealed-key store) / `key_not_held` (sealed with a key this server does not hold — another replica's, or a replaced sealed-key directory) / `unopenable` (the sealed value is damaged or belongs to another session) / `plaintext` (an older server stored it unsealed) / `unrecognized_seal` (a seal format this version does not know) — the way out depends on the door and the `reason`: `key_not_held` (a resume door) — have the operator restore the sealed-key directory that sealed it and restart that replica (it reads its keys only at startup), then resend the same request; `no_key_store` on the submit door — give the service a writable sealed-key directory (`<data root>/sealed-key/`, read at startup), or resubmit WITHOUT those credentials — resending the same submit body is refused again; `no_key_store` on a resume door — the same way out as `key_not_held`: restore the directory that sealed it and restart, then resend (a fresh empty directory does not help: it holds no such key, so the next read says `key_not_held`); `unopenable` / `plaintext` / `unrecognized_seal` — submit the work as a new task (cancel the still-suspended one first); never auto-retry, never match the sentence. A resume door's refusal decides nothing and starts no resume (the card stays pending; the known exception is a terminal run's steer race arm, which first opens a wake card and, when the second read fails for any of the five reasons, withdraws it and then answers 409 — if the withdrawal fails the server only logs it); a submit door's refusal lands before the task runs (nothing runs; a run row already opened for it is closed as `failed` and its idempotency key released, both best-effort — a failed step is only logged by the server and the answer is still the 409). On 400 `rules.inert_entry` (server >= 7.129.0): the engine's `ALLOW_ENTRY_INERT_REASONS` (`tool_name` / `wildcard_all` / `namespace_wildcard` / `content_unsupported` / `grammar` / `near_miss` / `earlier_grammar`). Out-of-vocabulary word ⇒ treat as unknown. (Other codes carry their own `reason` words.)
|
|
15099
14894
|
retryAfterSec:
|
|
15100
14895
|
type: number
|
|
15101
14896
|
description: >-
|
|
@@ -15122,6 +14917,10 @@ components:
|
|
|
15122
14917
|
`null` and `""` count), the refusal landed before any decision, and `field` is the literal `settledBy`; the three doors now answer
|
|
15123
14918
|
the SAME sentence. Every such 400 carries it, even when another defect in the same body was hit first (the sentence then names that
|
|
15124
14919
|
defect). Branch on the code plus `field`, never on the sentence; a bad body WITHOUT that key carries no `field`. SDK: `err.extra.field`.
|
|
14920
|
+
server >= 7.134.0: on 409 `conflict.checkpoint_ctx_unsealable` `field` is the SUBMIT-BODY PATH of the credential slot that cannot be sealed or unsealed (arrays
|
|
14921
|
+
`[i]`, record members `.key`: `mcpServers[0].transport.headers.Authorization`, `settings.hooks.PreToolUse[0].hooks[0].headers.Authorization`; the key
|
|
14922
|
+
name is not a secret, the value never enters the refusal); on 400 `request.field_invalid` for the request key `settings.approvalFrameFamilies` it is
|
|
14923
|
+
that literal (with `reason: "bad_entry"` and the bad `index`; no `index` for a non-array).
|
|
15125
14924
|
detail:
|
|
15126
14925
|
description: >
|
|
15127
14926
|
🔴 SHAPES differ by code — branch on `field` (or the `errorCode`), never guess from the type of `detail`. On 503
|
|
@@ -15256,8 +15055,9 @@ components:
|
|
|
15256
15055
|
callerTrust: { type: string }
|
|
15257
15056
|
- type: object
|
|
15258
15057
|
description: >-
|
|
15259
|
-
server >= 7.133.0 — 400 `request.field_conflict`: the request body contradicts itself. `kind` = which constraint (a CLOSED fourteen
|
|
15260
|
-
system_prompt_fold | file_history_restore | skills_disabled | existing_session | scratchpad_root | ask_answer | policy_person_ask | plan_edit | plan_mode_after | bound_call_door | remember_decision
|
|
15058
|
+
server >= 7.133.0 — 400 `request.field_conflict`: the request body contradicts itself. `kind` = which constraint (a CLOSED set — fourteen words, fifteen from server >= 7.134.0 — read open: cascade_verify | image_profile | resume_anchor |
|
|
15059
|
+
system_prompt_fold | file_history_restore | skills_disabled | existing_session | scratchpad_root | ask_answer | policy_person_ask | plan_edit | plan_mode_after | bound_call_door | remember_decision |
|
|
15060
|
+
approval_feedback (server >= 7.134.0: `feedback` on a deny — fields `["feedback", "decision"]` — or on a policy decision — `["feedback", "decidedBy"]`));
|
|
15261
15061
|
`fields` = the named body coordinates, subject first (at least one; a dynamic index reads `agents[1].skills`); `count` / `cap` only on the fold-cap kind (the folded total and its cap).
|
|
15262
15062
|
required: [kind, fields]
|
|
15263
15063
|
additionalProperties: false
|
|
@@ -15303,6 +15103,8 @@ components:
|
|
|
15303
15103
|
the engine's `detail.code` passes through as `blockedBy` (today only `checkpoint.config_refused` carries it — the closed set is core's
|
|
15304
15104
|
`CHECKPOINT_CONFIG_REFUSAL_CODES`, 40 words since core 7.53.0; read it as "the errorCode a fresh run would report for the same bad configuration"),
|
|
15305
15105
|
next to `field` and `reason`, absent keys not minted (SDK `ResumeRefusalExtra`).
|
|
15106
|
+
server >= 7.134.0 / core 7.54.0: the SAME three keys on 422 `parked_resume.startup_failed` (a parked background agent's leg refused before the claim — the
|
|
15107
|
+
engine now hands the failure's code / field / reason to the redemption receipt; absent when the engine gave none; <= 7.133.x carried only `cause` there).
|
|
15306
15108
|
|
|
15307
15109
|
ResumeLegConflictError:
|
|
15308
15110
|
description: >
|
|
@@ -15386,6 +15188,9 @@ components:
|
|
|
15386
15188
|
# 🔴 census 轴一(2026-07-30)补的 4 臂:server 今天就真发,spec/SDK 两侧此前同缺(详见各 schema 处的注)。
|
|
15387
15189
|
- $ref: '#/components/schemas/Event_context_usage'
|
|
15388
15190
|
- $ref: '#/components/schemas/Event_config_assembled'
|
|
15191
|
+
# server >= 7.134.0 (core 7.54.0): the device lane's cross-boundary taint row — DURABLE only (the `GET /v1/runs/{taskId}/events` ledger replay), never
|
|
15192
|
+
# on the live stream and never on the `GET /v1/runs/{taskId}` poll object; the trace SSE twin is the `cross-boundary-taint` frame.
|
|
15193
|
+
- $ref: '#/components/schemas/Event_cross_boundary_taint'
|
|
15389
15194
|
- $ref: '#/components/schemas/Event_needs_review'
|
|
15390
15195
|
- $ref: '#/components/schemas/Event_message_committed'
|
|
15391
15196
|
# [2373]A-2(2026-08-03,server 5.0.0):compaction_outcome 三腿同源批的 spec 半场(SDK 臂 20867e1 同批)。
|
|
@@ -15464,6 +15269,7 @@ components:
|
|
|
15464
15269
|
failed: '#/components/schemas/Event_failed'
|
|
15465
15270
|
context_usage: '#/components/schemas/Event_context_usage'
|
|
15466
15271
|
config_assembled: '#/components/schemas/Event_config_assembled'
|
|
15272
|
+
cross_boundary_taint: '#/components/schemas/Event_cross_boundary_taint'
|
|
15467
15273
|
needs_review: '#/components/schemas/Event_needs_review'
|
|
15468
15274
|
message_committed: '#/components/schemas/Event_message_committed'
|
|
15469
15275
|
compaction_outcome: '#/components/schemas/Event_compaction_outcome'
|
|
@@ -15690,10 +15496,10 @@ components:
|
|
|
15690
15496
|
# 每只闭集 = 引擎今天的词 ∪ 引擎退役词表里那一集。这五张 enum 与引擎 `RETIRED_MEMBERS` 逐集逐词同(由 `server-7129-wire` 对拍);卡面 / 队列行 / 请求面的同名闭集只取今天的词。
|
|
15691
15497
|
GateRecordAskClass:
|
|
15692
15498
|
type: string
|
|
15693
|
-
enum: [content_question, hook, ancestor, dangerous_delete, unverifiable_delete, unverifiable_shell_text, transcript_write, org_rule, rule_unreadable, ask_rule, denial_limit_fallback, classifier_no_ruling, requires_user_interaction, operator_forced, shell_floor, target_unresolved, probe, write_protection, tool_marks_mcp, tool_marks_a2a, policy_rra, artifact_shared_read, mode, unstated, ordinary, write_protection_unresolved, governance_unavailable]
|
|
15499
|
+
enum: [content_question, hook, ancestor, dangerous_delete, unverifiable_delete, unverifiable_shell_text, transcript_write, org_rule, rule_unreadable, ask_rule, denial_limit_fallback, classifier_no_ruling, requires_user_interaction, cross_boundary, operator_forced, shell_floor, target_unresolved, probe, write_protection, tool_marks_mcp, tool_marks_a2a, policy_rra, artifact_shared_read, mode, unstated, ordinary, write_protection_unresolved, governance_unavailable]
|
|
15694
15500
|
description: >-
|
|
15695
15501
|
The class word on a GATE RECORD (`tool_end.gate.disposition.askClass` / `.classes` on the mode-refusal arm, `ModeRelease.askClass` / `.classes`) — server >= 7.129.0 reads the record as an ARCHIVE:
|
|
15696
|
-
today's `AskClass` set (twenty-
|
|
15502
|
+
today's `AskClass` set (twenty-six words; `cross_boundary` from server >= 7.134.0) PLUS the words the engine retired (`write_protection_unresolved`, retired in core 7.49.0 — renamed `target_unresolved`; `governance_unavailable`,
|
|
15697
15503
|
retired in core 7.51.0 — merged into `rule_unreadable`). A record the previous engine generation legally wrote is replayed byte for byte (a 7.50.x mode refusal can carry `governance_unavailable`);
|
|
15698
15504
|
a word NO engine generation ever minted (a case variant, the empty string, a future word) withholds the whole `gate` and counts `server.trace.gate-outcome-defective`.
|
|
15699
15505
|
Render a known archive word normally and an unknown one generically; never drop the record because the word is not in today's set.
|
|
@@ -15711,9 +15517,9 @@ components:
|
|
|
15711
15517
|
OMITTED `reason` for the two retired words (`released` was still sent); from 7.129.0 they arrive verbatim on the replay faces. Same reading as `GateRecordAskClass`.
|
|
15712
15518
|
GateRecordPersistedRuleMandate:
|
|
15713
15519
|
type: string
|
|
15714
|
-
enum: [operator_always, tool_marks, probe_mandate, probe_unanswered, write_protection, target_unresolved, write_protection_unresolved]
|
|
15520
|
+
enum: [operator_always, tool_marks, probe_mandate, probe_unanswered, write_protection, target_unresolved, cross_boundary_taint, write_protection_unresolved]
|
|
15715
15521
|
description: >-
|
|
15716
|
-
`released.mandate` on a GATE RECORD (archive read, server >= 7.129.0): today's
|
|
15522
|
+
`released.mandate` on a GATE RECORD (archive read, server >= 7.129.0): today's seven `PersistedRuleMandate` words (`cross_boundary_taint` from server >= 7.134.0) PLUS the retired `write_protection_unresolved` (core 7.49.0 rename). Same reading as `GateRecordAskClass`.
|
|
15717
15523
|
GateRecordAskOrigin:
|
|
15718
15524
|
type: string
|
|
15719
15525
|
enum: [content_question, plan_review, ancestor_marked, org_unavailable, org_rule, rule_store_unavailable, hook, ask_rule, denial_limit_fallback, shell_gate_tighten, safety_tighten, policy, unresolvable]
|
|
@@ -15944,9 +15750,10 @@ components:
|
|
|
15944
15750
|
`UNATTENDED_PERMISSION_MODE=dontAsk`).
|
|
15945
15751
|
AskClass:
|
|
15946
15752
|
type: string
|
|
15947
|
-
enum: [content_question, hook, ancestor, dangerous_delete, unverifiable_delete, unverifiable_shell_text, transcript_write, org_rule, rule_unreadable, ask_rule, denial_limit_fallback, classifier_no_ruling, requires_user_interaction, operator_forced, shell_floor, target_unresolved, probe, write_protection, tool_marks_mcp, tool_marks_a2a, policy_rra, artifact_shared_read, mode, unstated, ordinary]
|
|
15753
|
+
enum: [content_question, hook, ancestor, dangerous_delete, unverifiable_delete, unverifiable_shell_text, transcript_write, org_rule, rule_unreadable, ask_rule, denial_limit_fallback, classifier_no_ruling, requires_user_interaction, cross_boundary, operator_forced, shell_floor, target_unresolved, probe, write_protection, tool_marks_mcp, tool_marks_a2a, policy_rra, artifact_shared_read, mode, unstated, ordinary]
|
|
15948
15754
|
description: >
|
|
15949
|
-
core `ASK_CLASSES` (TWENTY-
|
|
15755
|
+
core `ASK_CLASSES` (TWENTY-SIX words as of core 7.54.0 / server >= 7.134.0: `cross_boundary` joined after `requires_user_interaction` — the device lane's
|
|
15756
|
+
cross-boundary confirmation, see below; TWENTY-FIVE as of core 7.51.0 / server >= 7.129.0: `governance_unavailable` was merged into `rule_unreadable`, no alias — sdk 23.0.0; a stored card / parked row written by server <= 7.128.x is rewritten once by the server at boot. The gate record reads the ARCHIVE form, see `GateRecordAskClass`. History: twenty-two words as of core 7.40.0, twenty-three as of core 7.41.0, twenty-four as of core 7.43.0, twenty-five as of core 7.45.0, twenty-six as of core 7.49.0 — 7.34.0 minted twenty; `unverifiable_shell_text` joined in 7.49.0 #1505 and rides server >= 7.126.0, where the
|
|
15950
15757
|
unresolved-write-target class was also RENAMED to `target_unresolved` (#955; zero alias — the previous spelling is in the SDK README's 22.0.0 migration table); `shell_floor` joined in 7.39.0 #1260 and rides
|
|
15951
15758
|
server >= 7.113.0; `unstated` joined in 7.40.0 and rides server >= 7.115.0; `requires_user_interaction` joined in 7.41.0 and rides
|
|
15952
15759
|
server >= 7.116.0; `classifier_no_ruling` joined in 7.43.0 #1353 and rides server >= 7.118.0; `dangerous_delete` joined in 7.45.0 and rides
|
|
@@ -17164,6 +16971,16 @@ components:
|
|
|
17164
16971
|
pathTarget: { $ref: '#/components/schemas/McpToolPathTarget' }
|
|
17165
16972
|
ruleFace: { $ref: '#/components/schemas/McpToolRuleFace' }
|
|
17166
16973
|
renderHints: { $ref: '#/components/schemas/McpToolRenderHints' }
|
|
16974
|
+
boundaryLegs:
|
|
16975
|
+
description: >-
|
|
16976
|
+
core 7.54.0 / server >= 7.134.0 (a REQUIRED engine member: every row of `wiring_manifest.tools.entries[]` and of a `tool_roster_delta` frame's
|
|
16977
|
+
`delta.roster.entries[]` carries it) — the LEGS a call of this tool travels (core `BOUNDARY_LEGS`, in that order: `env` = inside the execution
|
|
16978
|
+
environment / on the device, `outside_read` = a read beyond it, `outside_write` = a write beyond it), or `per_call` when its dispatch gives the legs
|
|
16979
|
+
per call (the engine's own definitions and the protocol tools state them; every other row follows its `effect`). The device lane's launch gate reads
|
|
16980
|
+
it. ABSENT = an older server (<= 7.133.x).
|
|
16981
|
+
oneOf:
|
|
16982
|
+
- { type: string, const: per_call }
|
|
16983
|
+
- { type: array, items: { type: string, enum: [env, outside_read, outside_write] } }
|
|
17167
16984
|
McpToolPathTarget:
|
|
17168
16985
|
type: object
|
|
17169
16986
|
required: [param, access]
|
|
@@ -17865,44 +17682,6 @@ components:
|
|
|
17865
17682
|
governance shell gate sits at the "classify" tier, a shell ask may come from the classifier or from
|
|
17866
17683
|
another gate; the server leaves the key absent rather than guessing). Never render absence as
|
|
17867
17684
|
"this gate can be bypassed by a posture".
|
|
17868
|
-
ruleSuggestions:
|
|
17869
|
-
type: array
|
|
17870
|
-
minItems: 1 # 空数组不可能出现:server 的合取项②要求 `req.ruleSuggestions` **非空**,否则整键省略(缺席 = 本卡无此选项)
|
|
17871
|
-
# 刻意**不**声明 maxItems:server 的 `.max(4)` 是**卡** schema(`ApprovalCardSchema`)上的约束,这条
|
|
17872
|
-
# live 帧腿没有它。在这里抄一个上界 = 声明一条 server 并不执行的约束(照 spec 生成的严格客户端会
|
|
17873
|
-
# 拒收一条合法帧)。数量上界的真源是引擎:core 5.22.0 的 `suggestRulesForCommand` **至多铸一条,且恒
|
|
17874
|
-
# `match: "exact"`**(不写死上界是给将来的 miner 留位,不是暗示今天会有更多)。
|
|
17875
|
-
items: { $ref: '#/components/schemas/RuleSuggestion' }
|
|
17876
|
-
description: >
|
|
17877
|
-
server #154 车二 (core 5.18.0, design/179), ADDITIVE, "tool_approval" only: the rule candidates
|
|
17878
|
-
the ENGINE minted for this ask. Render them as the "don't ask again" options and echo the chosen
|
|
17879
|
-
one back as `persistRule.rule` on POST /v1/tool-approvals/{id}/respond.
|
|
17880
|
-
|
|
17881
|
-
🔴 PRESENCE IS THE PROMISE: the key is present ONLY on a deployment that actually has a
|
|
17882
|
-
permission-rule store wired (the same object behind the engine's `permissionRules.storeWired`
|
|
17883
|
-
manifest bit). A deployment without one OMITS it rather than offering an option with nowhere to
|
|
17884
|
-
redeem — an unredeemable "don't ask again" is a wire lie, worse than absence.
|
|
17885
|
-
|
|
17886
|
-
🔴 THE CONVERSE DOES NOT HOLD: absence means "THIS CARD has no redeemable candidate", and three
|
|
17887
|
-
causes produce it — no rule store wired, the engine minted no candidate for this command (compound /
|
|
17888
|
-
redirect / substitution), or the command bytes were unreadable. One frame cannot tell them apart, so
|
|
17889
|
-
never diagnose the deployment's rule lane from a single absence, and never synthesize a candidate.
|
|
17890
|
-
|
|
17891
|
-
📏 HOW MANY, TODAY: core 5.22.0's miner (`suggestRulesForCommand`) emits AT MOST ONE candidate and
|
|
17892
|
-
always `match: "exact"` — no shipped producer mints the broader prefix option. `prefix` stays in the
|
|
17893
|
-
closed vocabulary because the wire validator accepts it and a later miner may emit it; render what
|
|
17894
|
-
arrives, but do NOT build a UI that assumes a narrow/broad PAIR is on offer.
|
|
17895
|
-
|
|
17896
|
-
🔴 The values are the engine's VERBATIM (closed `match` vocabulary + engine-minted text); the
|
|
17897
|
-
server neither re-mints nor re-orders them. A hand-built rule string is refused at redemption
|
|
17898
|
-
(`ruleRefusal: "rule_not_offered"`) — by construction, so a click on a harmless command cannot be
|
|
17899
|
-
turned into a rule for something else.
|
|
17900
|
-
|
|
17901
|
-
⚠️ REDEMPTION SCOPE: the key also rides the durable card replay, but its only redemption channel is
|
|
17902
|
-
the LIVE respond leg keyed by this frame's `approvalId` — an in-process map on ONE replica. Same
|
|
17903
|
-
replica ⇒ redeemable; after a restart / on another replica that `approvalId` 404s and the person
|
|
17904
|
-
must use the durable decide leg, which carries NO rule field in v1 (its body is strict — an extra
|
|
17905
|
-
`persistRule` is a loud 400, not a silent drop).
|
|
17906
17685
|
ruleOffers:
|
|
17907
17686
|
type: array
|
|
17908
17687
|
minItems: 1
|
|
@@ -17910,8 +17689,8 @@ components:
|
|
|
17910
17689
|
description: >
|
|
17911
17690
|
server >= 7.46.0 (core 5.58.0, design/375), "tool_approval" only — the ENGINE-minted "don't ask
|
|
17912
17691
|
again" OPTIONS for this ask, as a DISCRIMINATED UNION (`single` | `batch`). It is the BREAKING
|
|
17913
|
-
REPLACEMENT of `ruleSuggestions`
|
|
17914
|
-
alias
|
|
17692
|
+
REPLACEMENT of the triple-shaped `ruleSuggestions` of servers <= 7.45: a >= 7.46.0 engine mints the old key nowhere and there is no
|
|
17693
|
+
alias (sdk 26.0.0 deleted the old key with the support floor 7.52.0).
|
|
17915
17694
|
|
|
17916
17695
|
🔴 READ `kind` TO TELL THE ARMS APART, never a positional assumption. ORDER IS CONTRACT: a
|
|
17917
17696
|
whole-string exact `single` is index 0 when present and a `batch` is always last; core's own
|
|
@@ -17926,23 +17705,15 @@ components:
|
|
|
17926
17705
|
suppress its persistence actions entirely (core's normative clause) — a compacted index means the
|
|
17927
17706
|
k-th option the person clicked is not the k-th rule the server redeems.
|
|
17928
17707
|
|
|
17929
|
-
🔴 PRESENCE IS THE PROMISE
|
|
17708
|
+
🔴 PRESENCE IS THE PROMISE: present only where a permission-rule store
|
|
17930
17709
|
is really wired. The converse does not hold — a wired deployment still omits it for mandated /
|
|
17931
17710
|
requiresRealApproval / allow_outranked / ask_rule_matched / hook-produced / inherited-unresolved / ancestor-resolved /
|
|
17932
17711
|
anonymous asks. Absence reads as "THIS CARD has no such option", never as "this deployment has no
|
|
17933
17712
|
rule lane" (that is `capabilities.permissionRules`) and never as "your rule broke" (that is
|
|
17934
|
-
`allowRuleShadowed
|
|
17713
|
+
`allowRuleShadowed`).
|
|
17935
17714
|
|
|
17936
17715
|
⚠️ REDEMPTION SCOPE is the live respond leg keyed by this frame's `approvalId` only; a replayed
|
|
17937
17716
|
offer on another replica is not a promise that it is still redeemable.
|
|
17938
|
-
persistedRuleShadowed:
|
|
17939
|
-
type: string
|
|
17940
|
-
description: >-
|
|
17941
|
-
server >= 7.13.0 (core 5.25.0 #144), ADDITIVE, "tool_approval" only — this ask MATCHED one of the caller's persisted allow
|
|
17942
|
-
rules and that rule COULD NOT silence it; the value is the rule's VERBATIM text (secret-redacted + length-bounded; UNTRUSTED
|
|
17943
|
-
for display, like `message`). Absent != "you have no rule"; deliberately separate from `governanceForced`.
|
|
17944
|
-
RETIRED: server >= 7.117.0 (core 7.42.0, BREAKING rename, no alias) never mints this key on any face; its successor is
|
|
17945
|
-
`allowRuleShadowed` (all five allow-layer members, not just the rule store). Kept for servers in [7.13.0, 7.117.0) only (sdk 16.3.0).
|
|
17946
17717
|
allowRuleShadowed:
|
|
17947
17718
|
type: array
|
|
17948
17719
|
items: { $ref: '#/components/schemas/AllowRuleShadow' }
|
|
@@ -18220,17 +17991,18 @@ components:
|
|
|
18220
17991
|
classifierUnavailable:
|
|
18221
17992
|
$ref: '#/components/schemas/ClassifierUnavailable'
|
|
18222
17993
|
description: >-
|
|
18223
|
-
server >= 7.69.0 (core 7.10.0
|
|
17994
|
+
server >= 7.69.0 (core 7.10.0), ADDITIVE, present only when the classifier was consulted and
|
|
18224
17995
|
could not run — WHY this ask reached a human. See ClassifierUnavailable for the open-`cause` rule and
|
|
18225
17996
|
the three shapes absence covers.
|
|
18226
|
-
RETIRED: server >= 7.72.0 (core 7.14.0
|
|
17997
|
+
RETIRED: server >= 7.72.0 (core 7.14.0) never mints this key on any of the three faces; its
|
|
18227
17998
|
successor is `disposition.cause` on the gate record (`unavailable` / `parse_error` — a different
|
|
18228
|
-
question, so an old switch does not port). Kept
|
|
17999
|
+
question, so an old switch does not port). Kept on the frame because servers 7.69–7.71 are inside the supported range and still
|
|
18000
|
+
send it, and the closed inbox row declares the same key (frame and row read the same); it goes with the next major once the support floor is >= 7.106.0.
|
|
18229
18001
|
ruleStoreUnreadable:
|
|
18230
18002
|
type: string
|
|
18231
18003
|
enum: [store, call]
|
|
18232
18004
|
description: >-
|
|
18233
|
-
server >= 7.72.0 (core 7.14.0
|
|
18005
|
+
server >= 7.72.0 (core 7.14.0), ADDITIVE — WHICH HALF of the rule lane could not be read.
|
|
18234
18006
|
Present iff `origin === "rule_store_unavailable"`: `store` = the wired rule store could not be read
|
|
18235
18007
|
(look at the store / network); `call` = the store was read but THIS command could not be read against
|
|
18236
18008
|
the person's deny/ask rows (look at the command spelling). One `origin` word covers both facts, and
|
|
@@ -18238,10 +18010,11 @@ components:
|
|
|
18238
18010
|
frame and the inbox row; the `card_json` card deliberately does NOT carry it (it travels with `origin`,
|
|
18239
18011
|
which is not on the card). Absence = `origin` is not that word — NOT an assertion that the rule store
|
|
18240
18012
|
is healthy.
|
|
18241
|
-
RETIRED: server >= 7.106.0 (core 7.34.0
|
|
18242
|
-
unreadable rule store no longer raises a card
|
|
18243
|
-
|
|
18244
|
-
|
|
18013
|
+
RETIRED: server >= 7.106.0 (core 7.34.0, BREAKING — wire) never mints this key on either face — an
|
|
18014
|
+
unreadable rule store no longer raises a card; the signal moved to the session stream's user-facing
|
|
18015
|
+
`engine_notice` `permission.rule_store_unavailable` (`detail.at` = `prepare` / `call`; what the run does while the rules cannot be read is
|
|
18016
|
+
that notice's own text). Kept on the frame because servers 7.72–7.105 are inside the supported range and still send it, and the closed inbox row
|
|
18017
|
+
declares the same key; it goes with the next major once the support floor is >= 7.106.0 (`origin: rule_store_unavailable` itself stays).
|
|
18245
18018
|
readRootCandidate:
|
|
18246
18019
|
type: object
|
|
18247
18020
|
required: [dir, clearsThisAsk]
|
|
@@ -18395,33 +18168,15 @@ components:
|
|
|
18395
18168
|
posture. Semantics, the ABSENT != false clause and the discrimination boundary are stated verbatim on
|
|
18396
18169
|
ToolApprovalFrame.governanceForced. It sits at the card's top level rather than inside `risk` because
|
|
18397
18170
|
`risk` describes the ENGINE's judgement of the call, while this key says WHO imposed the gate.
|
|
18398
|
-
ruleSuggestions:
|
|
18399
|
-
type: array
|
|
18400
|
-
minItems: 1 # 同帧腿:空数组不可能出现(素材同源),缺席才是「本卡无此选项」
|
|
18401
|
-
maxItems: 4 # 卡形上**真有**这条上界(server `ApprovalCardSchema` 的 `.max(4)`);live 帧腿没有,故只写在这里
|
|
18402
|
-
items: { $ref: '#/components/schemas/RuleSuggestion' }
|
|
18403
|
-
description: >
|
|
18404
|
-
ADDITIVE (#154 车二 / core 5.18.0 design/179): the rule candidates the ENGINE minted for this ask —
|
|
18405
|
-
the card's "don't ask again" options; echo the chosen one back as `persistRule.rule`. Semantics,
|
|
18406
|
-
the PRESENCE-IS-THE-PROMISE clause (present only where a rule store is wired) and the redemption
|
|
18407
|
-
scope are stated verbatim on ToolApprovalFrame.ruleSuggestions — the live frame, the stored
|
|
18408
|
-
`card_json` and the replayed frame carry the SAME material.
|
|
18409
18171
|
ruleOffers:
|
|
18410
18172
|
type: array
|
|
18411
18173
|
minItems: 1
|
|
18412
18174
|
items: { $ref: '#/components/schemas/RuleOffer' }
|
|
18413
18175
|
description: >
|
|
18414
|
-
server >= 7.46.0 (core 5.58.0, design/375) — the discriminated-union replacement of
|
|
18415
|
-
`ruleSuggestions`
|
|
18176
|
+
server >= 7.46.0 (core 5.58.0, design/375) — the discriminated-union replacement of the retired
|
|
18177
|
+
`ruleSuggestions` (servers <= 7.45; sdk 26.0.0 deleted it). Same material as the live frame and the stored `card_json` (the server
|
|
18416
18178
|
projects all three through one `copyRuleOffer`), so semantics, order-is-contract, presence-is-the-
|
|
18417
18179
|
promise and the per-leg index rules are stated verbatim on ToolApprovalFrame.ruleOffers.
|
|
18418
|
-
persistedRuleShadowed:
|
|
18419
|
-
type: string
|
|
18420
|
-
description: >-
|
|
18421
|
-
server >= 7.13.0 (core 5.25.0 #144), ADDITIVE — the persisted rule this ask matched but which could not silence it; frame and
|
|
18422
|
-
card carry the SAME material (see ToolApprovalFrame.persistedRuleShadowed).
|
|
18423
|
-
RETIRED: server >= 7.117.0 (core 7.42.0) never mints this key on any face (its strict card schema even refuses a stored card
|
|
18424
|
-
carrying it); its successor is `allowRuleShadowed`. Kept for servers in [7.13.0, 7.117.0) only (sdk 16.3.0).
|
|
18425
18180
|
allowRuleShadowed:
|
|
18426
18181
|
type: array
|
|
18427
18182
|
items: { $ref: '#/components/schemas/AllowRuleShadow' }
|
|
@@ -18456,35 +18211,13 @@ components:
|
|
|
18456
18211
|
classifierUnavailable:
|
|
18457
18212
|
$ref: '#/components/schemas/ClassifierUnavailable'
|
|
18458
18213
|
description: >-
|
|
18459
|
-
|
|
18460
|
-
|
|
18461
|
-
|
|
18462
|
-
RETIRED: server >= 7.72.0 (core 7.14.0 #688) never mints this key on any of the three faces; its
|
|
18214
|
+
(minted by servers [7.69.0, 7.72.0), core 7.10.0 #616) WHY this ask reached a human. See ClassifierUnavailable for the open-`cause` rule and the three
|
|
18215
|
+
shapes absence covers.
|
|
18216
|
+
RETIRED: server >= 7.72.0 (core 7.14.0) never mints this key on any of the three faces; its
|
|
18463
18217
|
successor is `disposition.cause` on the gate record (`unavailable` / `parse_error` — a different
|
|
18464
|
-
question, so an old switch does not port).
|
|
18465
|
-
|
|
18466
|
-
RuleSuggestion:
|
|
18467
|
-
type: object
|
|
18468
|
-
description: >
|
|
18469
|
-
One ENGINE-minted rule candidate (#154 车二 / core 5.18.0 `RuleSuggestion`) — what a single click on
|
|
18470
|
-
"don't ask again" would persist.
|
|
18471
|
-
|
|
18472
|
-
🔴 THE TEXT COMES FROM THE ENGINE, NOT THE SHELL: the server derives it from the adjudicated command's
|
|
18473
|
-
own bytes; a client may only echo one of these back verbatim (`persistRule.rule`). Reporting text that
|
|
18474
|
-
is not among the candidates is refused (`ruleRefusal: "rule_not_offered"`) rather than guessed at, so
|
|
18475
|
-
"click on a harmless command, get a rule for something else" is not spellable on this path.
|
|
18476
|
-
# 封闭:core `RuleSuggestion` 恰三键(rule/match/command),server 逐字透传不重铸。
|
|
18477
|
-
additionalProperties: false
|
|
18478
|
-
required: [rule, match, command]
|
|
18479
|
-
properties:
|
|
18480
|
-
rule: { type: string, maxLength: 512, description: 'The canonical rule text to echo back on redemption (server MAX_RULE_TEXT_CHARS = 512).' }
|
|
18481
|
-
match:
|
|
18482
|
-
type: string
|
|
18483
|
-
enum: [exact, prefix]
|
|
18484
|
-
description: '`exact` = this one command only (`Bash(git status)`); `prefix` = word-boundary prefix (`Bash(git status:*)`). Closed vocabulary — an unknown value is not a candidate this contract describes; do not render it as redeemable.'
|
|
18485
|
-
command: { type: string, maxLength: 512, description: 'The command pattern inside the rule, for a shell that would rather not re-parse `rule`.' }
|
|
18218
|
+
question, so an old switch does not port). It stays declared on the CARD because the pinned server's card schema (`ApprovalCardSchema`, server 7.134.0) still accepts it: a still-pending `card_json` row a
|
|
18219
|
+
7.69–7.71 server wrote replays verbatim onto `approval_request.card` / the replay frame. (The FRAME's same-named key stays declared too; why, and until when: `ToolApprovalFrame.classifierUnavailable`.)
|
|
18486
18220
|
|
|
18487
|
-
# ─── S-139(sdk 8.3.0):对 server 7.60.0 整体重对账带进来的四张型面 ───────────────────────
|
|
18488
18221
|
ClassifierUnavailable:
|
|
18489
18222
|
# 8.9.0:三面(tool_approval 帧 / ApprovalCard / InboxRow)同形同值 ⇒ 具名单源,内联三份会各自漂。
|
|
18490
18223
|
type: object
|
|
@@ -18599,7 +18332,7 @@ components:
|
|
|
18599
18332
|
`ApprovalCard.ruleOffersAbsence`; server >= 7.55.0 / core #490 fix ②, S-15). The engine names which
|
|
18600
18333
|
door is shut: `mandated` = this ask must be confirmed every time (🔴 this arm must NOT point the user
|
|
18601
18334
|
at writing a rule — a rule would not silence it, and saying so sends them into a loop); `allow_outranked` = an
|
|
18602
|
-
allow-layer member matched this call but the ask sits at a higher tier, so another allow rule cannot clear it (the machine-readable twin of `allowRuleShadowed
|
|
18335
|
+
allow-layer member matched this call but the ask sits at a higher tier, so another allow rule cannot clear it (the machine-readable twin of `allowRuleShadowed`);
|
|
18603
18336
|
`ask_rule_matched` = an explicit `ask` rule matched this call (same frame `origin: ask_rule`): it keeps asking, an allow rule would not silence it either; a card from the deployment name-list gate
|
|
18604
18337
|
`APPROVAL_REQUIRE` / the supervisor route that reports an explicit ask-rule hit lands here too; `lane_cannot_speak` = a rule COULD clear this ask but the lane cannot speak this time (the engine could mint no coverable form for this command).
|
|
18605
18338
|
🔴 sdk 23.0.0 BREAKING (server >= 7.129.0 / engine 7.51.0, `RULE_OFFERS_ABSENCES`): the former `shadowed` meant two things and is split into the middle two words, no alias; a card / parked row that a server <= 7.128.x
|
|
@@ -18634,10 +18367,12 @@ components:
|
|
|
18634
18367
|
`READ_ROOT_COVERS` and its `isApprovalRequestFrameV1` judges `covers` by membership in it; a source-level anchor reads the word off the server's minting site and the engine's type.
|
|
18635
18368
|
PersistedRuleMandate:
|
|
18636
18369
|
type: string
|
|
18637
|
-
enum: [operator_always, tool_marks, probe_mandate, probe_unanswered, write_protection, target_unresolved]
|
|
18370
|
+
enum: [operator_always, tool_marks, probe_mandate, probe_unanswered, write_protection, target_unresolved, cross_boundary_taint]
|
|
18638
18371
|
description: >
|
|
18639
18372
|
WHICH WORD a mandated ask stands on (server >= 7.102.0 / S-721 / core 7.32.0 #1092) — core's
|
|
18640
|
-
`PERSISTED_RULE_MANDATES`
|
|
18373
|
+
`PERSISTED_RULE_MANDATES` (seven words since core 7.54.0 / server >= 7.134.0: `cross_boundary_taint` — the run executes on a device outside the deployment's
|
|
18374
|
+
trust boundary and the deployment is multi-tenant, so an org-side write, or after an off-target read a call bound for the device, is confirmed by the deployment's
|
|
18375
|
+
approver per call; no standing allow rule and no automatic lane answers it; core puts it at the HEAD of the mandate ladder, the array keeps core's constant order), transcribed verbatim and in order (core 7.32.1
|
|
18641
18376
|
`dist/core/ask-origin.d.ts:349`; the vocabulary's owner is core; the sixth word is `target_unresolved` from core 7.49.0 #955 / server >= 7.126.0 —
|
|
18642
18377
|
server 7.122.0–7.125.x sent the previous spelling, which reads as out of set here, see the SDK README's 22.0.0 migration table). Rides FOUR faces with one value: the
|
|
18643
18378
|
`tool_approval` frame, the `livePending` row top level, the operator queue row (`GET /v1/approvals`
|
|
@@ -18691,9 +18426,9 @@ components:
|
|
|
18691
18426
|
RuleOfferMatch:
|
|
18692
18427
|
type: string
|
|
18693
18428
|
description: >
|
|
18694
|
-
The MATCH FORM of a persisted rule —
|
|
18695
|
-
|
|
18696
|
-
|
|
18429
|
+
The MATCH FORM of a persisted rule — core's `PERSISTED_RULE_MATCHES`, verbatim and in order (the vocabulary is OWNED BY CORE: a package-root
|
|
18430
|
+
value since core 7.54.0, which server >= 7.134.0 reads directly instead of keeping its own transcription; earlier servers transcribed it and pinned set
|
|
18431
|
+
equality). ONE vocabulary for two faces: a card's rule offer (`RuleOffer.match`, the
|
|
18697
18432
|
server's card schema validates it with this very enum) and a persisted rule row (`GET /v1/rules`).
|
|
18698
18433
|
|
|
18699
18434
|
`exact` = this one command only (`Bash(git status)`). `prefix` = the historical colon-star
|
|
@@ -18896,8 +18631,7 @@ components:
|
|
|
18896
18631
|
maxLength: 512
|
|
18897
18632
|
description: >
|
|
18898
18633
|
With `edited` absent or false this is the CANDIDATE ARM: echo back, VERBATIM, the `rule` of the
|
|
18899
|
-
chosen `kind: "single"` entry of the frame's `ruleOffers
|
|
18900
|
-
`ruleSuggestions`). Do not hand-build it, re-case it or append `:*` — the server locates it by
|
|
18634
|
+
chosen `kind: "single"` entry of the frame's `ruleOffers`. Do not hand-build it, re-case it or append `:*` — the server locates it by
|
|
18901
18635
|
text and refuses otherwise (`rule_not_offered`). With `edited: true` this is the FREE-TEXT ARM
|
|
18902
18636
|
and the string is whatever the person typed.
|
|
18903
18637
|
edited:
|
|
@@ -19835,6 +19569,38 @@ components:
|
|
|
19835
19569
|
fields: {}
|
|
19836
19570
|
overrideReasons: {}
|
|
19837
19571
|
ts: {}
|
|
19572
|
+
CrossBoundaryTaintRow:
|
|
19573
|
+
type: object
|
|
19574
|
+
description: >
|
|
19575
|
+
server >= 7.134.0 / core 7.54.0 — the device lane's CROSS-BOUNDARY TAINT row: the engine's `permission.cross_boundary_taint` frame minus its envelope
|
|
19576
|
+
(`kind` / `version` / `taskId` / `ts`). Metadata only. Emitted ONLY on a tree that executes on a target device (one row when an armed tree prepares a
|
|
19577
|
+
leg — `prepare`, one on a durable resume leg — `resume`, one when this leg first lets an off-target read into the tree — `observed`, with that call);
|
|
19578
|
+
the host lane never emits it. Two exits, one row: the ledger event `cross_boundary_taint` on `GET /v1/runs/{taskId}/events` (`Event_cross_boundary_taint`)
|
|
19579
|
+
and the trace SSE `cross-boundary-taint` frame on `GET /v1/tasks/{taskId}/stream` (the row + `seq`). The `GET /v1/runs/{taskId}` poll object carries NO
|
|
19580
|
+
such key.
|
|
19581
|
+
# 不封闭(`additionalProperties: true`):本 schema 是 `Event_cross_boundary_taint` 的 allOf 目标(帧上多一个 `type`),封闭会把合法帧判成违约(同 PromptManifestRow)。
|
|
19582
|
+
additionalProperties: true
|
|
19583
|
+
required: [runId, phase, taint, governed]
|
|
19584
|
+
properties:
|
|
19585
|
+
runId: { type: string, description: 'the leg''s run id.' }
|
|
19586
|
+
phase: { type: string, enum: [prepare, resume, observed], description: 'core `permission.cross_boundary_taint` `phase` (engine closed set).' }
|
|
19587
|
+
taint:
|
|
19588
|
+
type: array
|
|
19589
|
+
description: 'The tree''s taint bits after the event — core `CROSS_BOUNDARY_TAINT_BITS` (`targetExecutionArmed` = the tree is armed to execute on the target; `offTargetReadObserved` = off-target read content was let into the tree).'
|
|
19590
|
+
items: { type: string, enum: [targetExecutionArmed, offTargetReadObserved] }
|
|
19591
|
+
governed: { type: boolean, description: 'the tree has run under the `multi_tenant` posture since it armed (derived from `REQUIRE_PRINCIPAL`).' }
|
|
19592
|
+
toolName: { type: string, description: '`observed` only: the call that let the off-target read in.' }
|
|
19593
|
+
toolCallId: { type: string, description: '`observed` only: that call''s id.' }
|
|
19594
|
+
Event_cross_boundary_taint:
|
|
19595
|
+
description: >
|
|
19596
|
+
DURABLE only (server >= 7.134.0 / core 7.54.0) — the ledger event of a `CrossBoundaryTaintRow` on `GET /v1/runs/{taskId}/events` (SSE `id:` = the row's
|
|
19597
|
+
seq). Never on the live stream, never on the `GET /v1/runs/{taskId}` poll object; an older server drops the frame on the spot.
|
|
19598
|
+
allOf:
|
|
19599
|
+
- $ref: '#/components/schemas/CrossBoundaryTaintRow'
|
|
19600
|
+
- type: object
|
|
19601
|
+
required: [type]
|
|
19602
|
+
properties:
|
|
19603
|
+
type: { const: cross_boundary_taint }
|
|
19838
19604
|
Event_needs_review:
|
|
19839
19605
|
type: object
|
|
19840
19606
|
description: >
|
|
@@ -21690,6 +21456,13 @@ components:
|
|
|
21690
21456
|
(the `livePending[]` row + `state`; answer door open); `decided` = the row is DECIDED (`decision` / `decidedAtMs` / `decisionNote?`, the same three keys as the late-replay body); `parked` = PARKING / PARKED
|
|
21691
21457
|
(a late answer redeems the parked card; `decidePath?` points at the durable decision path); `void` = DENIED / VOID (nobody decided it, the answer has nowhere to land; `cause?` is the same cause word as the
|
|
21692
21458
|
late-answer 404's, see ToolApprovalNotPendingCause).
|
|
21459
|
+
🔴 server >= 7.134.0: a PARKED row passes the gate judge (the same one the answer door's 409 `approval_stale` reads) — the gate still open ⇒ `parked`
|
|
21460
|
+
(+ `decidePath`; ONLY this state renders "go decide"); the gate settled by a person / policy ⇒ `decided` (no `decidePath`); the gate expired (a cancel expires it
|
|
21461
|
+
first) / superseded / settled by the host SLA sweep, the window or nobody-to-answer ⇒ `void` WITHOUT `cause`; the checkpoint row gone, or settled without a
|
|
21462
|
+
readable direction / time ⇒ 404 `tool_approval.not_pending` WITHOUT `cause`; the gate unreadable (store failure) ⇒ falls back to `parked`. Known boundary (re-read
|
|
21463
|
+
to settle it): a parked row's `decided` can return to `parked` when the resume leg fails before the approved action starts (the engine reopens the same gate), and
|
|
21464
|
+
a cancelled resume reads `void` once the server collects the reopened gate (`parked` in between, or `void` for an instant during the reopen).
|
|
21465
|
+
Older servers answered all of these with `parked` + `decidePath`.
|
|
21693
21466
|
oneOf:
|
|
21694
21467
|
- $ref: '#/components/schemas/ToolApprovalReadPending'
|
|
21695
21468
|
- $ref: '#/components/schemas/ToolApprovalReadDecided'
|
|
@@ -22083,74 +21856,6 @@ components:
|
|
|
22083
21856
|
delivery: { type: string, const: applied, description: 'Literal "applied" on today''s server.' }
|
|
22084
21857
|
marker: { type: string, description: 'Engine-minted delivery marker.' }
|
|
22085
21858
|
|
|
22086
|
-
WorkspaceSnapshotPage:
|
|
22087
|
-
# 4.3.0(CAPS-OPS-8):把 GET …/workspace 的 200 信封提成具名 schema。SDK 侧此前是 `list()` 返回位上的
|
|
22088
|
-
# **内联闭合字面量**,两道 spec 门(field-drift 只扫 types.ts / resource-schema 只扫 resources 的 exported
|
|
22089
|
-
# type)对方法返回位的内联形都是盲的 —— 于是它漏了这里一直标为 required 的 `sessionId`,CI 全绿。
|
|
22090
|
-
type: object
|
|
22091
|
-
description: >
|
|
22092
|
-
GET /v1/sessions/{sessionId}/workspace 的 200 信封(server src/http/routes/sessions.ts)。
|
|
22093
|
-
⚠️ `total` = **本页行数**(`snapshots.length`),不是快照总数,且这条腿没有任何分页游标 —— 与同族
|
|
22094
|
-
`WorkspaceTreePage.total`(真·全量)**同名反义**。`latest` 与展示行同源(防 ghost key)。
|
|
22095
|
-
additionalProperties: false
|
|
22096
|
-
required: [sessionId, snapshots, total]
|
|
22097
|
-
properties:
|
|
22098
|
-
sessionId: { type: string }
|
|
22099
|
-
snapshots:
|
|
22100
|
-
type: array
|
|
22101
|
-
items: { $ref: '#/components/schemas/WorkspaceSnapshotRow' }
|
|
22102
|
-
latest: { type: string, description: 'Newest snapshot key; absent when the session has none.' }
|
|
22103
|
-
total: { type: integer, description: 'ROWS ON THIS PAGE — not the snapshot count.' }
|
|
22104
|
-
|
|
22105
|
-
WorkspaceTreePage:
|
|
22106
|
-
# 4.3.0(CAPS-OPS-8):同上,tree 腿的 200 信封。
|
|
22107
|
-
type: object
|
|
22108
|
-
description: >
|
|
22109
|
-
GET /v1/sessions/{sessionId}/workspace/{key}/tree 的 200 信封(server src/http/routes/sessions.ts)。
|
|
22110
|
-
`total` 在这条腿上是**全量**(`all.length`)—— 与 `WorkspaceSnapshotPage.total` 语义相反。
|
|
22111
|
-
`key` 回的是解析后的真实键(请求可传 `latest` 别名)。
|
|
22112
|
-
additionalProperties: false
|
|
22113
|
-
required: [sessionId, key, entries, total]
|
|
22114
|
-
properties:
|
|
22115
|
-
sessionId: { type: string }
|
|
22116
|
-
key: { type: string, description: 'The RESOLVED snapshot key (a `latest` alias in the request comes back resolved).' }
|
|
22117
|
-
entries:
|
|
22118
|
-
type: array
|
|
22119
|
-
items: { $ref: '#/components/schemas/WorkspaceTreeEntry' }
|
|
22120
|
-
total: { type: integer, description: 'FULL entry count (not the page size).' }
|
|
22121
|
-
nextOffset: { type: integer, description: 'Present ⇒ more pages; send it back as ?offset=.' }
|
|
22122
|
-
|
|
22123
|
-
WorkspaceSnapshotRow:
|
|
22124
|
-
type: object
|
|
22125
|
-
description: >
|
|
22126
|
-
One snapshot row of GET /v1/sessions/{sessionId}/workspace (envelope `{sessionId, snapshots,
|
|
22127
|
-
latest?, total}`; server src/http/routes/sessions.ts — newest first, uuidv7 keys). E19 snapshot store's
|
|
22128
|
-
read-only projection: each row is the freeze at a turn boundary, NOT a live workspace.
|
|
22129
|
-
required: [key, files]
|
|
22130
|
-
additionalProperties: true
|
|
22131
|
-
properties:
|
|
22132
|
-
key: { type: string, description: 'Snapshot key (uuidv7 entry id; "latest" is an accepted alias on the sub-routes).' }
|
|
22133
|
-
files: { type: integer, description: 'Manifest row count.' }
|
|
22134
|
-
bytes: { type: integer, description: 'Total snapshot bytes — present only when the store has a sizes face (SQL backends); the local store honestly omits it ([1894]② additive).' }
|
|
22135
|
-
|
|
22136
|
-
WorkspaceTreeEntry:
|
|
22137
|
-
type: object
|
|
22138
|
-
description: >
|
|
22139
|
-
One file entry of GET /v1/sessions/{sessionId}/workspace/{key}/tree (envelope `{sessionId, key,
|
|
22140
|
-
entries, total, nextOffset?}`; server src/http/routes/sessions.ts — stable path order, offset paging).
|
|
22141
|
-
required: [path, hash]
|
|
22142
|
-
additionalProperties: true
|
|
22143
|
-
properties:
|
|
22144
|
-
path: { type: string, description: 'The relPath — pass VERBATIM as ?path= on the file sub-route.' }
|
|
22145
|
-
hash: { type: string, description: 'Content address (sha256) — enables cross-snapshot change highlighting ([1894]②).' }
|
|
22146
|
-
size: { type: integer, description: 'Present only when the store has a sizes face (SQL backends).' }
|
|
22147
|
-
|
|
22148
|
-
# ═══════════════════════════════════════════════════════════════════════════════════════════════
|
|
22149
|
-
# #154 车二(design/179 §7)—— 持久权限规则的 CC settings 导入面。形按 server 真码 + core 原形亲读
|
|
22150
|
-
# (`src/http/routes/rules.ts` / `src/rules-consent.ts`;preview/result 两形是 core `ImportPreview` /
|
|
22151
|
-
# `ImportResult` 的原样透传)。
|
|
22152
|
-
# ═══════════════════════════════════════════════════════════════════════════════════════════════
|
|
22153
|
-
|
|
22154
21859
|
CcImportSettingsLayer:
|
|
22155
21860
|
type: string
|
|
22156
21861
|
enum: [userSettings, projectSettings, localSettings]
|