@sema-agent/sdk 23.0.3 → 24.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.
Files changed (57) hide show
  1. package/README.md +67 -1
  2. package/dist/device/index.d.ts +1 -1
  3. package/dist/device/index.d.ts.map +1 -1
  4. package/dist/device/index.js +2 -0
  5. package/dist/device/index.js.map +1 -1
  6. package/dist/errors.d.ts +215 -3
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +87 -7
  9. package/dist/errors.js.map +1 -1
  10. package/dist/events.d.ts +129 -16
  11. package/dist/events.d.ts.map +1 -1
  12. package/dist/events.js +18 -0
  13. package/dist/events.js.map +1 -1
  14. package/dist/health.d.ts +4 -1
  15. package/dist/health.d.ts.map +1 -1
  16. package/dist/health.js.map +1 -1
  17. package/dist/index.d.ts +11 -3
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +9 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/registry/errors.d.ts +3 -0
  22. package/dist/registry/errors.d.ts.map +1 -1
  23. package/dist/registry/errors.js +3 -2
  24. package/dist/registry/errors.js.map +1 -1
  25. package/dist/registry/me-config.d.ts +1 -0
  26. package/dist/registry/me-config.d.ts.map +1 -1
  27. package/dist/registry/me-config.js +1 -1
  28. package/dist/registry/me-config.js.map +1 -1
  29. package/dist/registry/scope-config-feedback.d.ts +1 -0
  30. package/dist/registry/scope-config-feedback.d.ts.map +1 -1
  31. package/dist/registry/scope-config-feedback.js +1 -1
  32. package/dist/registry/scope-config-feedback.js.map +1 -1
  33. package/dist/resources/elicitations.d.ts +2 -1
  34. package/dist/resources/elicitations.d.ts.map +1 -1
  35. package/dist/resources/elicitations.js.map +1 -1
  36. package/dist/resources/questions.d.ts +2 -1
  37. package/dist/resources/questions.d.ts.map +1 -1
  38. package/dist/resources/questions.js.map +1 -1
  39. package/dist/resources/session-sync.d.ts +4 -2
  40. package/dist/resources/session-sync.d.ts.map +1 -1
  41. package/dist/resources/session-sync.js +4 -2
  42. package/dist/resources/session-sync.js.map +1 -1
  43. package/dist/resources/tool-approvals.d.ts +10 -6
  44. package/dist/resources/tool-approvals.d.ts.map +1 -1
  45. package/dist/resources/tool-approvals.js.map +1 -1
  46. package/dist/settings.d.ts +3 -0
  47. package/dist/settings.d.ts.map +1 -1
  48. package/dist/sse.d.ts +3 -0
  49. package/dist/sse.d.ts.map +1 -1
  50. package/dist/sse.js +3 -3
  51. package/dist/sse.js.map +1 -1
  52. package/dist/types.d.ts +348 -98
  53. package/dist/types.d.ts.map +1 -1
  54. package/dist/types.js +6 -2
  55. package/dist/types.js.map +1 -1
  56. package/openapi.yaml +590 -114
  57. package/package.json +2 -2
package/openapi.yaml CHANGED
@@ -423,7 +423,7 @@ paths:
423
423
  prepare-time refusal code that HAS a status in the server's per-code triage table (`resume_at.*` — `resume_at.not_found` is 404, the rest 422 —, governance codes,
424
424
  `rewind.store_unconfigured` / `rewind.capture_disabled` / `rewind.child_scope_unsupported` / `rewind_snapshot.unresolvable`, the
425
425
  registered `config.*` codes incl. the three roster-bound ones and — server >= 7.116.0 — `config.invalid_checkpoint_store` (400) and
426
- `config.user_invoked_skill_unknown` (400: top-level `userInvokedSkills` named a skill this run does not carry) and — server >= 7.117.0 — `config.image_invalid` (400: an inline image failed the engine's byte admission; `error` starts with `TaskSpec.images: `) and — server >= 7.126.0 — `config.tool_face_control` (400: `allowTools: ["mcp__*"]`, `excludeTools: ["*"]` (and, on server 7.126.0–7.128.x only, a name in `allowTools` / `excludeTools` that no tool of this run answers to — server >= 7.129.0 runs those as written and announces each once with the operator row `runner_config_advisory`), or an `excludeTools` entry that reaches a protocol tool this leg depends on; the engine rejects before the run starts, never silently ignoring the name; `error` is the engine's sentence naming the entry, its list and why), `corrupt_session`; codes outside the table, e.g. `rewind.invalid_spec`, stay
426
+ `config.user_invoked_skill_unknown` (400: top-level `userInvokedSkills` named a skill this run does not carry) and — server >= 7.117.0 — `config.image_invalid` (400: an inline image failed the engine's byte admission; `error` starts with `TaskSpec.images: `) and — server >= 7.126.0 — `config.tool_face_control` (400: `allowTools: ["mcp__*"]`, `excludeTools: ["*"]` (and, on server 7.126.0–7.128.x only, a name in `allowTools` / `excludeTools` that no tool of this run answers to — server >= 7.129.0 runs those as written and announces each once with the operator row `runner_config_advisory`), or an `excludeTools` entry that reaches a protocol tool this leg depends on; the engine rejects before the run starts, never silently ignoring the name; `error` is the engine's sentence naming the entry, its list and why) and — server >= 7.132.0, BREAKING (200 + failed body before) — `config.agent.unknown_tool` (400: a delegated agent's `allowTools` names a near-miss / a retired name with a successor / an impossible spelling, judged by the engine before the run; the intake refusal of `agents[i].denyTools` entries that read as nothing has answered this 400 since 7.131.0) and `config.legacy_tool_name` (400: a stored session-rule row names a tool the engine reads as nothing) and `prompt.assembled_role_refused` (400: `systemPrompt` / `appendSystemPrompt` — `settings.outputStyle` folded in — carries the engine's locked prompt text verbatim; send role text only) and — server >= 7.131.0 — `config.user_attachment_invalid` (400; server >= 7.132.0 the body adds `detail: { path, index? }`), `corrupt_session`; these registered codes answer 400 on all three submit legs without spending the `Idempotency-Key` (async / live legs: 2xx with the same code on the terminal run row); codes outside the table, e.g. `rewind.invalid_spec`, stay
427
427
  200 with a failed body) answers its 4xx / 5xx ERROR BODY only when the whole submission did ZERO WORK (cumulative
428
428
  `stats.turns === 0` AND `stats.tokens === 0` — the common case: nothing billed, not idempotency-cached). When a
429
429
  `verify` / `cascade` run's earlier tier already ran turns and only the last tier is refused, the SAME code arrives
@@ -7506,6 +7506,51 @@ components:
7506
7506
  type: array
7507
7507
  items: { type: string }
7508
7508
  description: 'core 5.11.0: extra READ-ONLY absolute host paths — read fence only (classify read-boundary auto-allow + read_file/grep containment); writes to the same dirs are still refused. Same shape/400 rules as additionalDirectories; servers <6.6.0 silently ignore (harmless additive).'
7509
+ userAttachments:
7510
+ type: array
7511
+ maxItems: 20
7512
+ description: >
7513
+ server >= 7.131.0 (core 7.50.0) — REQUEST-LEVEL ATTACHMENTS riding on this submission's objective, handed to the engine AS-IS
7514
+ (`TaskSpec.userAttachments`, at most 20). Each entry is rendered by the engine as a message right after the objective; the delivery
7515
+ outcome is reported ONCE on the stream's `human_input{carrier:"objective"}` frame (`attachments[]`: ordinal / kind / outcome / label).
7516
+ The ENGINE owns the shape judgement: a malformed entry, more than 20 entries, a `text` entry whose line-numbered rendering exceeds the
7517
+ Read cap, an image failing admission, or a `path` entry on a lane without a workspace is refused BEFORE the first model call with
7518
+ 400 `config.user_attachment_invalid` (sync leg; `config.` is not a prefix family ⇒ coded APIError). Objective-only: `/respond` refuses the
7519
+ key (400 `request.body_shape`, listed in `unsupportedKeys`); resume / delivery legs do not carry it. Probe `Capabilities.userAttachments`
7520
+ first — absent = older server (<= 7.130.x answers 400 `request.body_shape`), fold the attachment into the objective text instead.
7521
+ items:
7522
+ oneOf:
7523
+ - type: object
7524
+ required: [path]
7525
+ additionalProperties: false
7526
+ properties:
7527
+ path: { type: string, description: 'a file in THIS run''s workspace (hands scenarios only).' }
7528
+ lines:
7529
+ type: object
7530
+ required: [start]
7531
+ additionalProperties: false
7532
+ properties:
7533
+ start: { type: integer }
7534
+ end: { type: integer }
7535
+ - type: object
7536
+ required: [name, text]
7537
+ additionalProperties: false
7538
+ properties:
7539
+ name: { type: string }
7540
+ text: { type: string }
7541
+ startLine: { type: integer }
7542
+ - type: object
7543
+ required: [name, image]
7544
+ additionalProperties: false
7545
+ properties:
7546
+ name: { type: string }
7547
+ image:
7548
+ type: object
7549
+ required: [data, mimeType]
7550
+ additionalProperties: false
7551
+ properties:
7552
+ data: { type: string, description: 'base64 bytes.' }
7553
+ mimeType: { type: string }
7509
7554
  images:
7510
7555
  type: array
7511
7556
  description: >
@@ -9612,6 +9657,16 @@ components:
9612
9657
  a child process spawned on this host NEVER inherits a name the deployment declared as its own credential — every `inheritEnv` policy (`"all"` and `"scrub"` alike) subtracts that list first, and an allow list naming one is
9613
9658
  refused. It speaks of INHERITANCE only (the engine process's own environment stays readable to same-user processes on the host; a credential that never enters it remains the root fix).
9614
9659
  ABSENT = an old server (<= 7.128.x) or a word this deployment does not wire: read it as "not promised", not as "absent capability". A shell gates on the word, never on a version number.
9660
+ inherit_env.own_credential_values_withheld:
9661
+ type: boolean
9662
+ description: >-
9663
+ ENGINE CAPABILITY WORD (core `ENGINE_CAPABILITIES`' second word, core 7.52.0; server >= 7.132.0 projects it; the key IS the word, dotted):
9664
+ a child process spawned on this host does NOT inherit a variable whose VALUE equals one of this deployment's credential values (whole-string equality, whatever
9665
+ the variable is called) — a key copied into another variable name is withheld under `inheritEnv: "all"` too. 🔴 A FACT, not a promise — it can be `false`:
9666
+ true <=> every credential variable of the live configuration that has a value in the environment went into the engine's value arm; the engine refuses a value it
9667
+ reads as "not a credential" (blank / a placeholder word / one repeated character / under 8 characters) or "the value of a variable every child process gets"
9668
+ (startup does not refuse; the name arm still withholds) => `false`. A credential resolved only per request is not in the value arm. INHERITANCE only, like the first word.
9669
+ ABSENT = an old server (<= 7.131.x withholds by name only — a same-value copy under another name reaches the child under `"all"`). Gate on `=== true`.
9615
9670
  asyncRuns: { type: boolean }
9616
9671
  artifacts: { type: boolean }
9617
9672
  approvals: { type: boolean }
@@ -10086,6 +10141,29 @@ components:
10086
10141
  links, and there is no "links are then worker-relative" fallback — an unconfigured endpoint makes
10087
10142
  SendUserFile fail loudly and the sibling `sendUserFile` bit report false. A NON-boolean capability
10088
10143
  value (there are several — see `taskSettings`, `fleet`, `workspace`, `version`, `scenarios`).
10144
+ userAttachments:
10145
+ type: object
10146
+ description: >
10147
+ server >= 7.131.0 (core 7.50.0) — the REQUEST-LEVEL ATTACHMENT seat: the server accepts the top-level submit key `userAttachments`
10148
+ and hands it to the engine as-is; the value is the engine's own seat description (`USER_ATTACHMENT_SEAT`) VERBATIM and is always present
10149
+ (not deployment-shaped). `entries` = which entry points carry attachments (today always `["objective"]`); `kinds` = the kind words the
10150
+ engine can recognise (engine closed set); `supplies` = supply words (`path` / `content_text` / `content_image`); `limits` = the caps.
10151
+ `supplies` describes what the seat CAN carry, not what this deployment / scenario accepts right now: `path` entries are accepted only
10152
+ on hands scenarios (where the workspace lives is `executionLane`), elsewhere the engine refuses them with `config.user_attachment_invalid`.
10153
+ Key ABSENT = older server (<= 7.130.x): do not send the request key.
10154
+ required: [entries, kinds, supplies, limits]
10155
+ additionalProperties: false
10156
+ properties:
10157
+ entries: { type: array, items: { type: string } }
10158
+ kinds: { type: array, items: { type: string } }
10159
+ supplies: { type: array, items: { type: string } }
10160
+ limits:
10161
+ type: object
10162
+ required: [maxEntries, maxRenderedTextChars]
10163
+ additionalProperties: false
10164
+ properties:
10165
+ maxEntries: { type: integer }
10166
+ maxRenderedTextChars: { type: integer }
10089
10167
  taskSettings:
10090
10168
  type: object
10091
10169
  description: >
@@ -10824,7 +10902,19 @@ components:
10824
10902
  `principalHeader` (both set => 400 request.body_shape); a non-string value => 400 request.field_invalid.
10825
10903
  7.128.x accepts and carries the declaration but does NOT send an assertion yet (engine seat pending;
10826
10904
  operator line `mcp_assertion_header_not_sent`).
10827
- allowTools: { type: array, items: { type: string } }
10905
+ allowTools:
10906
+ type: array
10907
+ items: { type: string }
10908
+ description: >-
10909
+ Which of this server's tools to MOUNT (bare tool names, as the server lists them). Three sentences (server >= 7.132.0 contract; read off the engine's
10910
+ `intakeListedTools`, passed through verbatim, never checked against the live list): ABSENT = every listed tool mounts; `[]` = NONE mounts (the server is
10911
+ still connected, still probed, still on the `GET /v1/capabilities/mcp` status face) — `[]` MUST NOT be folded into absence (two facts on the wire;
10912
+ do not drop an empty array when serializing); a name the server does not list = SILENTLY NO MATCH (no 400, no warning — a narrowing mismatch mounts
10913
+ less, never more; for "loud on a typo" name the same tool in `toolFaces`, which notices an unknown name as `config.tool_face_undeclared`; `toolAxes`
10914
+ checks shape only). The engine's one loud case: a server without the `tools` capability and a non-empty list ⇒ operator warning
10915
+ `mcp.tools_capability_absent`. The list also gates the server's MCP RESOURCES: absent ⇒ list / read stay open; a list ⇒ open only if it names the
10916
+ reserved `list_resources` / `read_resource` (so `[]` closes them too). Bad shape (not a string array) ⇒ 400 `request.field_invalid` naming
10917
+ `mcpServers[i].allowTools`.
10828
10918
  elicitation: { type: boolean }
10829
10919
  toolAxes:
10830
10920
  type: object
@@ -10840,6 +10930,15 @@ components:
10840
10930
  server >= 7.66.0 — per-tool face overlays keyed by BARE tool name (see McpToolFace). Any malformed
10841
10931
  face drops the whole server.
10842
10932
  additionalProperties: { $ref: '#/components/schemas/McpToolFace' }
10933
+ startupTimeoutMs:
10934
+ type: number
10935
+ description: >-
10936
+ server >= 7.132.0 (an accepted key; core `McpServerSpec.startupTimeoutMs`): THIS server's startup bound in whole milliseconds — the handshake
10937
+ (connect + initialize) and the initial tool listing each carry it. One read order: this member, else the process-level `MCP_TIMEOUT`, else the MCP
10938
+ SDK's own 60 000 ms. Range 1 000 – 2 147 483 647. The value-shape judge lives ONLY in the engine: neither server door (new submit / probe) checks
10939
+ it at intake; a bad value (a string, a fraction, 0, a negative, NaN, `null`, out of range) refuses ONLY THIS server at its dial
10940
+ (`config.mcp_startup_timeout_invalid`; siblings mount) — never clamped, never read as the default. A <= 7.131.x server answers `400
10941
+ request.body_shape` (named in `unknownKeys`).
10843
10942
 
10844
10943
  A2aServerSpec:
10845
10944
  type: object
@@ -11660,13 +11759,15 @@ components:
11660
11759
  # 里 id/provider/reasoning 都是必填 ⇒ 四键无条件;contextWindow/maxOutputTokens 0/缺省即省略,
11661
11760
  # supportedEffortLevels 仅 reasoning 模型。🔴 server 7.117.0 起 `vision` 是三态(收 / 不收 / 没声明 `input`),
11662
11761
  # 没声明 ⇒ 键缺席 ⇒ 不再是必有键(此前由 `input` 恒算成布尔,对没声明的条目报 false)。
11663
- required: [name, id, provider, reasoning]
11762
+ # 🔴 server 7.131.0 起 `reasoning` 同样三态:env 车道 `MODEL_REASONING` / `MODEL_VISION` 缺省 true 退役、中心名册条目不写即不声明
11763
+ # ⇒ 两键都「未声明 = 键缺席」,`required` 只剩 name / id / provider(sdk 23.1.0;TS 型 `ModelInfo.reasoning?` 早已可选)。
11764
+ required: [name, id, provider]
11664
11765
  additionalProperties: false
11665
11766
  properties:
11666
11767
  name: { type: string, description: 'the @mention handle (user-pickable model name).' }
11667
11768
  id: { type: string, description: 'underlying model id (display, e.g. deepseek-v4-pro).' }
11668
11769
  provider: { type: string }
11669
- reasoning: { type: boolean, description: 'a reasoning-tier model (picker can badge it).' }
11770
+ reasoning: { type: boolean, description: 'a reasoning-tier model (picker can badge it). THREE states since server 7.131.0: `true` / `false` when the row declares it, ABSENT when undeclared (env lane without MODEL_REASONING; center entry without `reasoning`) — absent is not false.' }
11670
11771
  vision: { type: boolean, description: 'Whether this catalog row accepts image input — THREE states (server >= 7.117.0; before it a row that declared no `input` reported `false`): `true` = the row declares `input` and it contains "image"; `false` = declares `input` without it; ABSENT = the row declared no `input` (a hand-written catalog entry; the env lane and the config-center lane always declare it). ABSENT means UNKNOWN, not false: treat it as "send the image anyway and tell the user", do not read it as `false` and block the image locally — the server hands the image to the model for that same row at run time. Only an explicit `false` justifies "this model does not take images".' }
11671
11772
  contextWindow: { type: integer, description: 'E4 (SHIPPED) — context-window token DENOMINATOR for the %-used gauge; omitted when unknown.' }
11672
11773
  maxOutputTokens: { type: integer, description: 'E4 (SHIPPED) — single-call max output tokens; omitted when unknown.' }
@@ -11766,12 +11867,16 @@ components:
11766
11867
  x-open-enum: true
11767
11868
  description: >-
11768
11869
  A model row's key<->URL pairing posture (core `RoutePairingStatus`; server >= 7.45). OPEN on read —
11769
- the six words below are today's set, branch on the known ones and keep a `default` arm. NON-SECRET — no
11870
+ the eight words below are today's set (core `RoutePairingStatus`), branch on the known ones and keep a `default` arm. NON-SECRET — no
11770
11871
  URL, no credential.
11771
11872
  `ok:per-model` this model has its own credential · `ok:paired` deployment credential, and the model's URL
11772
11873
  is on the deployment's declared root · `ok:keyless` no credential anywhere (a local unauthenticated
11773
11874
  gateway) · `broken:credential_mismatch` / `broken:credential_missing` a real request WILL be refused by
11774
- the engine (flag it red) · `unknown` could not be adjudicated — render "unknown", NEVER "good" or "bad".
11875
+ the engine (flag it red) · server >= 7.132.0 / engine 7.52.0 adds two `broken:` words, same reading:
11876
+ `broken:credential_origin_mismatch` (this model's own credential is bound to the host it first went to and the row now points at another
11877
+ host — configure a credential for the new host or point it back; the same refusal on a stream is the `engine_notice`
11878
+ `route.credential_origin_mismatch`) and `broken:credential_answer_conflict` (the per-model credential hook answers the key twice — `apiKey`
11879
+ AND the lane's own key header; answer one of them) · `unknown` could not be adjudicated — render "unknown", NEVER "good" or "bad".
11775
11880
  🔴 sdk 23.0.0 BREAKING (server >= 7.129.0 / engine 7.51.0): `ok:unpinned` (a deployment credential on a deployment that declared no root, so the pairing was unverifiable) is RETIRED with no alias —
11776
11881
  on such a deployment the engine now judges the deployment credential `broken:credential_mismatch`. A server <= 7.128.x still sends `ok:unpinned`: it falls in the open tail, render it as
11777
11882
  "pairing not verified", never as good.
@@ -11781,11 +11886,11 @@ components:
11781
11886
 
11782
11887
  ResumeStartupCause:
11783
11888
  type: string
11784
- enum: [environment, session_gone, tool_unavailable, configuration, decision_rejected]
11889
+ enum: [environment, session_gone, transcript_corrupt, tool_unavailable, configuration, decision_rejected]
11785
11890
  description: >-
11786
- WHY a parked resume could not start its approved action — the engine's closed `RESUME_STARTUP_CAUSES` (core 7.51.0), word for word and in order. The body key of the 422 `parked_resume.startup_failed`
11891
+ WHY a parked resume could not start its approved action — the engine's closed `RESUME_STARTUP_CAUSES` (core 7.51.0; six words since core 7.52.0, server >= 7.132.0), word for word and in order. The body key of the 422 `parked_resume.startup_failed`
11787
11892
  (`ErrorResponse.cause`; SDK `ParkedResumeStartupError.startupCause`). Server >= 7.129.0 screens the engine's word against this set before it goes out (a word the engine did not say, or one outside the set => the key is absent).
11788
- `environment` the leg's infrastructure failed (workspace restore, an abort) — the decision is untouched, retrying replays it · `session_gone` the resumed agent's transcript session is missing ·
11893
+ `environment` the leg's infrastructure failed (workspace restore, an abort) — the decision is untouched, retrying replays it · `session_gone` the resumed agent's transcript session is missing · `transcript_corrupt` (core 7.52.0) the transcript is there but damaged (no header its store wrote, a leaf or parent entry missing, a lost tail the checkpoint was cut inside) — it reopens as `session_gone` does, only the receipt now names it ·
11789
11894
  `tool_unavailable` the approved tool is not available to the resumed leg (gone, or replaced by a different contract) — this approval cannot run, decide afresh · `configuration` the deployment's
11790
11895
  configuration refuses the resumed leg; a retry under the same configuration fails the same way · `decision_rejected` the decision does not fit the checkpoint (another gate's answer, an input the constraints
11791
11896
  refuse) — correct it and resubmit. The shared `ErrorResponse.cause` stays an open string in this document because the key is shared by other codes and by servers <= 7.128.x (which relay the engine's word unscreened).
@@ -13195,7 +13300,11 @@ components:
13195
13300
  🔴 OPEN SET — deliberately NOT an enum: observed values include `human`, `irreversible_ask`,
13196
13301
  `plan_review`, `needs_review`, `resource_limit`, and core keeps adding. Pinning an enum would make a
13197
13302
  new gate kind "not exist" for generated clients.
13198
- ABSENT on a pre-`gate_kind` legacy row (SQL column NULL) — degrade honestly, never assume `human`.
13303
+ 🔴 ALWAYS PRESENT on server >= 7.132.0 (a wire narrowing): every park stamps it, the one-time migration M21 filled the stored rows that lacked it
13304
+ (a row whose gate names no registered kind is expired), and a SQL row that still carries none is NOT LISTED (counted under
13305
+ `server.approvals.queue-row-gate-kind-missing`; no decide route can bind it) rather than served without the key. On a <= 7.131.x server it is
13306
+ absent on a pre-`gate_kind` legacy SQL row (column NULL). Either way the reading of an absent key is "unreadable — fail closed": never assume
13307
+ `human`, never route it. Deliberately still not in `required` while the supported floor (3.0.0) is below 7.132.0.
13199
13308
  input:
13200
13309
  description: >
13201
13310
  The pending tool call's args (post-hook), REDACTED + size-bounded — for a tool gate the write
@@ -13905,23 +14014,67 @@ components:
13905
14014
  message: { description: 'OPEN — the message payload as stored; shape belongs to the transcript format, not to this envelope. server >= 7.125.0: a `role: "user"` message carries the same present-iff rewind handle `taskId` as on the whole-record read (see `SessionRecord.messages`).' }
13906
14015
 
13907
14016
  PromptEpoch:
13908
- type: object
13909
14017
  description: >
13910
- A session's prompt-epoch pin (server >=1.220, additive on `GET /v1/sessions/:id`). Identifies WHICH
13911
- assembled system-prompt artifact this session is pinned to, so a transcript stays reproducible across
13912
- prompt-pack releases. IDs/digests only — never prompt text. OPEN object.
13913
- required: [epoch, artifactDigest, packId, assemblyApi, activatedBy]
13914
- additionalProperties: true
14018
+ A session's prompt-epoch record on `GET /v1/sessions/:id` (absent = a pre-epoch session — never null). 🔴 server >= 7.132.0 BREAKING (no alias): the value
14019
+ is the engine's `StoredPromptEpoch` reading VERBATIM (the server neither reads nor projects it) — a v3 pin `{ kind: "pin", descriptor }`, or a record of a
14020
+ retired shape recognized by its field names `{ kind: "legacy", centerPinned }` (the engine reads only whether it pinned a center artifact; the next run
14021
+ replaces it with a v3 record). The <= 7.131.x shape `{ epoch, artifactDigest, packId, assemblyApi, activatedBy }` is retired: `epoch` / `activatedBy` live
14022
+ in `descriptor`, `descriptor.identity` takes the identity role (a different digest over different inputs — not comparable), `packId` / `assemblyApi` have
14023
+ no successor. IDs / digests only — never prompt text.
14024
+ oneOf:
14025
+ - $ref: '#/components/schemas/PromptEpochPin'
14026
+ - $ref: '#/components/schemas/PromptEpochLegacy'
14027
+ discriminator:
14028
+ propertyName: kind
14029
+ mapping:
14030
+ pin: '#/components/schemas/PromptEpochPin'
14031
+ legacy: '#/components/schemas/PromptEpochLegacy'
14032
+ PromptEpochPin:
14033
+ type: object
14034
+ additionalProperties: false
14035
+ required: [kind, descriptor]
13915
14036
  properties:
13916
- epoch: { type: integer, description: Monotonic epoch counter within the session. }
13917
- artifactDigest: { type: string, description: 'Content digest of the assembled artifact (`sha256:<64 hex>`).' }
13918
- packId: { type: string, description: 'Prompt-pack identity, e.g. `sema-default@1`.' }
13919
- assemblyApi: { type: integer, description: Assembly-contract version (currently always 1). }
14037
+ kind: { const: pin }
14038
+ descriptor: { $ref: '#/components/schemas/PromptEpochDescriptor' }
14039
+ PromptEpochLegacy:
14040
+ type: object
14041
+ additionalProperties: false
14042
+ required: [kind, centerPinned]
14043
+ properties:
14044
+ kind: { const: legacy }
14045
+ centerPinned: { type: boolean, description: 'whether the retired-shape record pinned a center artifact.' }
14046
+ PromptEpochDescriptor:
14047
+ type: object
14048
+ description: 'A v3 epoch record (core `PromptEpochDescriptor`), persisted as a session entry and restated in every compaction entry.'
14049
+ additionalProperties: false
14050
+ required: [epoch, identity, layers, activatedBy]
14051
+ properties:
14052
+ epoch: { type: integer, description: 'monotonic per-session record counter.' }
14053
+ identity: { type: string, description: 'the run''s prompt identity digest (= the manifest''s `identity.artifact`).' }
14054
+ layers: { $ref: '#/components/schemas/PromptIdentityLayers' }
13920
14055
  activatedBy:
13921
14056
  type: string
13922
- description: >
13923
- Open enum — known values `session_start` | `compaction` | `legacy_migration`; treat unknown values as
13924
- opaque rather than failing closed.
14057
+ enum: [session_start, compaction, code_change, selection_change]
14058
+ description: 'how the record came to be — core `PROMPT_EPOCH_ACTIVATIONS`: `session_start` / `compaction` (legal boundaries), `code_change` (code or input layers moved), `selection_change` (only the selector values moved). CLOSED: the engine''s judge (`normalizePromptEpoch`) checks membership, a record with any other word does not read as a pin.'
14059
+ changed:
14060
+ type: array
14061
+ items: { type: string, enum: [catalog, renderers, deploy, task, published_schema] }
14062
+ description: 'only on a `code_change` record whose changed layers are known — core `PROMPT_EPOCH_CHANGES` (closed, judged by the engine like `activatedBy`).'
14063
+ sourceRevision: { type: string, description: 'opaque publish provenance of the pinned center layer — present only beside `layers.center`; never digested.' }
14064
+ PromptIdentityLayers:
14065
+ type: object
14066
+ description: >
14067
+ The inputs of a run's prompt identity (core `PromptIdentityLayers`; the epoch record's `layers` and the manifest's `identity.layers` are this one shape).
14068
+ Only `center` is pinned (resolved by digest on resume); the rest are what the run computed. Absent `center` / `deploy` / `task` = that layer contributed nothing.
14069
+ additionalProperties: false
14070
+ required: [catalog, renderers, binding]
14071
+ properties:
14072
+ catalog: { type: string }
14073
+ renderers: { type: object, additionalProperties: { type: number }, description: 'renderer id -> version.' }
14074
+ center: { type: string, description: 'the adopted center artifact''s digest.' }
14075
+ deploy: { type: string }
14076
+ task: { type: string }
14077
+ binding: { type: string, description: 'digest of the run''s selector values (the plain form is the manifest''s `selectors`).' }
13925
14078
 
13926
14079
  SessionListPage:
13927
14080
  type: object
@@ -14027,14 +14180,45 @@ components:
14027
14180
  # 封闭(census 批2 第三段,2026-07-30):三个铸造臂(`routes/sessions.ts` 的空面板 / 超时 degraded / 正常)键集并集恰是这 3 键;degraded 只在超时臂铸。
14028
14181
  # sdk 9.4.0:第 4 键 `lastLegMcp`(server ≥7.77.0)—— 同一个铸造点上按调用方裁的可选顶层键,不在
14029
14182
  # 面板那张短 TTL 单飞缓存里(缓存键=场景×principal,与会话无关)。
14030
- required: [asOf, servers]
14183
+ # server >= 7.131.0:第 5 键 `scenarioRefusal`(场景门拒时在场,此时 `servers` 缺席)⇒ `servers` 出 required。
14184
+ # 两臂恰一(server 7.132.0 三只铸造臂):served = `servers`(+ `degraded` 只在超时臂)/ refused = `scenarioRefusal`(无 `servers` / `degraded`)⇒ `oneOf` 判(sdk `McpStatusPanelServed` / `McpStatusPanelRefused`)。
14185
+ # 每一臂自己禁掉对方的键(不靠「另一臂恰好不过」:混合体 `{ servers, scenarioRefusal, degraded }` 曾因 refused 臂被 `degraded` 判掉而恰一臂过)。
14186
+ required: [asOf]
14031
14187
  additionalProperties: false
14188
+ oneOf:
14189
+ - required: [servers]
14190
+ not: { required: [scenarioRefusal] }
14191
+ - required: [scenarioRefusal]
14192
+ not: { anyOf: [{ required: [servers] }, { required: [degraded] }] }
14032
14193
  properties:
14033
14194
  asOf: { type: string }
14034
14195
  servers:
14035
14196
  type: array
14036
14197
  items: { $ref: '#/components/schemas/McpServerStatus' }
14198
+ description: >-
14199
+ The scenario half: what this principal's scenario would mount NOW. server >= 7.131.0: ABSENT only when the scenario gate refused (then
14200
+ `scenarioRefusal` is present) — distinct from `[]` (the gate passed and that scenario configures no MCP). Always present on older servers.
14037
14201
  degraded: { type: boolean }
14202
+ scenarioRefusal:
14203
+ type: object
14204
+ description: >-
14205
+ server >= 7.131.0 — present ONLY when the scenario gate refused (and then `servers` is absent); the panel still answers 200 because the ledger half
14206
+ (`lastLegMcp`) does not depend on the scenario. Exactly one of `servers` / `scenarioRefusal` is present (the `oneOf` above; `degraded` only beside `servers`). Members = the body of the same refusal answered
14207
+ whole-face (503 on `GET /v1/capabilities/mcp` / `GET /v1/sessions/{id}/a2a`), byte-equal (one sentence builder): today `errorCode`
14208
+ `state.scenario_assignment_unknown`, `error` naming the scenario and this deployment's roster, `detail: { scenario, source }` with `source` one of
14209
+ `ruling` (the center assigned this principal a scenario this deployment does not have) / `deployment` (a dangling `DEFAULT_SCENARIO`; sema-server refuses
14210
+ to boot on it, only an embedder's own `resolveSpec` reaches it). A gate that throws something that is not a typed refusal is still a 500.
14211
+ required: [errorCode, error]
14212
+ additionalProperties: true
14213
+ properties:
14214
+ errorCode: { type: string }
14215
+ error: { type: string }
14216
+ detail:
14217
+ type: object
14218
+ required: [scenario, source]
14219
+ properties:
14220
+ scenario: { type: string }
14221
+ source: { type: string, description: '`ruling` / `deployment` today; read open.' }
14038
14222
  lastLegMcp:
14039
14223
  type: object
14040
14224
  description: >
@@ -14566,6 +14750,10 @@ components:
14566
14750
  row (`status` / `instanceId`) — zero extra reads — and a cross-principal caller never reaches these codes
14567
14751
  (the owner gate answers `not_found.run`, same code and text as the unknown arm). Both dispositions are the
14568
14752
  same: stop retrying the handle, read the run's own outcome via GET /v1/runs/{taskId}.
14753
+ SettingsHooksConfigPath:
14754
+ type: array
14755
+ items: { type: [string, integer] }
14756
+ description: 'the coordinate of a `settings.hooks` verdict — segments relative to the request body''s `settings` (caller-text segments echo-bounded). SDK `SettingsHooksConfigPath`.'
14569
14757
  ErrorResponse:
14570
14758
  type: object
14571
14759
  description: >
@@ -14696,7 +14884,9 @@ components:
14696
14884
  unreadable) / `unreachable` (unreachable / 5xx / timeout / bad body / any status other than 200 / 409 / 400 / 401 / 403 —
14697
14885
  center 404 / 429 / 3xx included). On 400 `request.field_invalid` for a `settings.permissions` bucket (server >= 7.106.0 /
14698
14886
  S-904): `over_cap` (more than `cap` entries; beside `count` + `cap`) / `bad_entry` (a non-string or empty item; beside
14699
- `index`). 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.)
14887
+ `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
14888
+ `too_long` (a text over its character cap; beside `count` + `cap`) — closed three words `over_cap` / `too_long` / `bad_entry` (SDK `RequestFieldRefusalExtra`).
14889
+ 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.)
14700
14890
  retryAfterSec:
14701
14891
  type: number
14702
14892
  description: >-
@@ -14712,7 +14902,10 @@ components:
14712
14902
  carry their own `field`: the bucket on `rules.inert_entry`, the offending key on `rules.invalid_shape`.) Resume legs carry the same group on 409 `resume_blocked_by_policy`
14713
14903
  (`blockedBy: "request.field_invalid"`). Also on 409 `checkpoint.config_refused` (server >= 7.113.0): which part of the
14714
14904
  row's configuration was refused — `taskConfig` (change the configuration, then decide the SAME card again) or
14715
- `inheritedGate` (the row's recorded mode seed is bad — the run can only be cancelled). Also on 400 `request.field_invalid` for a
14905
+ `inheritedGate` (the row's recorded mode seed is bad — the run can only be cancelled) and — core 7.53.0 / server >= 7.132.0 — `deps` (the deployment's OWN
14906
+ seat is broken: fix the deployment, then decide the SAME card again). server >= 7.132.0: on 400 `request.field_invalid` cap / bad-entry refusals `field` is
14907
+ the IN-BODY COORDINATE of the capped / bad place (`skills[1].allowedTools`, `agents[0].denyTools[3]`, `agents`, `allowTools`, `additionalDirectories` …) —
14908
+ the same group as `reason` / `count` / `cap` / `index`. Also on 400 `request.field_invalid` for a
14716
14909
  `settings.hooks` tool-event matcher that selects an engine alias but not its canonical name (server >= 7.115.0 / S-1025):
14717
14910
  `field` is always the literal `settings.hooks` (see `detail`). Also on 400 `request.body_shape` (server >= 7.119.0), on the THREE
14718
14911
  tool-approval decision doors (`POST /v1/tool-approvals/{id}/respond`, `POST /v1/tasks/{taskId}/asks/{askId}/decision`,
@@ -14730,17 +14923,104 @@ components:
14730
14923
  `request.field_invalid` for a `settings.hooks` tool-event matcher (server >= 7.115.0 / S-1025; additive, the sentence and the code
14731
14924
  are unchanged): an OBJECT `{ event, alias, canonical }` — `event` = the tool event of the refused group (the first refused one when
14732
14925
  several are), `alias` / `canonical` = the engine catalog's alias and canonical name (closed strings, never the caller's raw bytes),
14733
- beside `field: "settings.hooks"`. On 400 `request.field_invalid` for the two `POST /v1/adoption` principal sentences (adoption):
14926
+ beside `field: "settings.hooks"`; 🔴 server >= 7.126.0 adds `reason` (`dead_alias` / `over_budget` / `invalid_regex`) and server >= 7.132.0 makes EVERY
14927
+ `settings.hooks` refusal carry this object with `path` ALWAYS present (the coordinate of the verdict, a segment array relative to the body's `settings`):
14928
+ the matcher forms (+ `budget_exceeded` with `totalMs`), the config reader's piece codes (+ `key`), `unsupported_entry_type` (+ `type`), the service caps
14929
+ `over_cap` / `too_long` (+ `count` / `cap`) and `unnamed_refusal` — see the hooks branch below and SDK `SettingsHooksRefusalDetail`. On 400
14930
+ `config.user_attachment_invalid` (server >= 7.132.0 / core 7.53.0): an OBJECT `{ path, index? }` — the field the engine names at the head of the sentence,
14931
+ `index` (0-based) only when the sentence names one attachment (SDK `UserAttachmentRefusalExtra`). On 400 `request.field_invalid` for the two `POST /v1/adoption` principal sentences (adoption):
14734
14932
  a human-readable STRING. Other codes (core `checkpoint.*` mirrors; `rules.*` refusals carry no `detail` — their keys are `field` / `entry` / `reason` / `verdict` / `currentName` / `guidance` / `got` at the top level) carry their
14735
14933
  own `detail`; read it by `errorCode`. SDK: `err.extra.detail` (verbatim, unnamed).
14736
14934
  oneOf:
14737
14935
  - type: object
14738
- required: [event, alias, canonical]
14936
+ description: 'the `settings.hooks` refusal detail (beside `field: "settings.hooks"`), one shape per `reason` — branch on `reason`, exhaustively (SDK `SettingsHooksRefusalDetail`). server >= 7.132.0: every hooks refusal carries it and `path` is always present; in-floor older servers: the three matcher shapes without `path` (7.126.0–7.131.x) and the reason-less dead-alias shape (7.115.0–7.125.x).'
14937
+ oneOf:
14938
+ - type: object
14939
+ description: 'matcher: selects an engine alias but not its canonical name (`path` absent on server 7.126.0–7.131.x).'
14940
+ required: [reason, event, alias, canonical]
14941
+ additionalProperties: false
14942
+ properties:
14943
+ reason: { type: string, enum: [dead_alias] }
14944
+ event: { type: string }
14945
+ alias: { type: string }
14946
+ canonical: { type: string }
14947
+ path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
14948
+ - type: object
14949
+ description: 'matcher: one regex evaluation over the per-evaluation budget (`path` absent on server 7.126.0–7.131.x).'
14950
+ required: [reason, event, groupIndex, budgetMs]
14951
+ additionalProperties: false
14952
+ properties:
14953
+ reason: { type: string, enum: [over_budget] }
14954
+ event: { type: string }
14955
+ groupIndex: { type: integer }
14956
+ budgetMs: { type: integer }
14957
+ path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
14958
+ - type: object
14959
+ description: 'matcher (server >= 7.132.0): the completed regex evaluations of one admission summed over `totalMs`.'
14960
+ required: [reason, event, groupIndex, totalMs, path]
14961
+ additionalProperties: false
14962
+ properties:
14963
+ reason: { type: string, enum: [budget_exceeded] }
14964
+ event: { type: string }
14965
+ groupIndex: { type: integer }
14966
+ totalMs: { type: integer }
14967
+ path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
14968
+ - type: object
14969
+ description: 'matcher: the regex does not compile (`path` absent on server 7.126.0–7.131.x).'
14970
+ required: [reason, event, groupIndex]
14971
+ additionalProperties: false
14972
+ properties:
14973
+ reason: { type: string, enum: [invalid_regex] }
14974
+ event: { type: string }
14975
+ groupIndex: { type: integer }
14976
+ path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
14977
+ - type: object
14978
+ description: 'the config reader''s classifier code verbatim (server >= 7.132.0; SDK `SETTINGS_HOOKS_PIECE_CODES`), `key` = the key that broke that piece when named.'
14979
+ required: [reason, path]
14980
+ additionalProperties: false
14981
+ properties:
14982
+ reason: { type: string, enum: [guard-outside-hooks, hooks-is-matcher, guard-under-unknown-event, guard-event-not-array, guard-matcher-invalid, guard-entry-invalid, hooks-not-object, unknown-event, event-not-array, matcher-invalid, entry-invalid] }
14983
+ path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
14984
+ key: { type: string }
14985
+ - type: object
14986
+ description: 'an entry type this service does not execute (server >= 7.132.0).'
14987
+ required: [reason, path, type]
14988
+ additionalProperties: false
14989
+ properties:
14990
+ reason: { type: string, enum: [unsupported_entry_type] }
14991
+ path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
14992
+ type: { type: string }
14993
+ - type: object
14994
+ description: 'a service cap (server >= 7.132.0).'
14995
+ required: [reason, path, count, cap]
14996
+ additionalProperties: false
14997
+ properties:
14998
+ reason: { type: string, enum: [over_cap, too_long] }
14999
+ path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
15000
+ count: { type: integer }
15001
+ cap: { type: integer }
15002
+ - type: object
15003
+ description: 'the classifier refused without naming a piece — contract drift, fail-closed (server >= 7.132.0).'
15004
+ required: [reason, path]
15005
+ additionalProperties: false
15006
+ properties:
15007
+ reason: { type: string, enum: [unnamed_refusal] }
15008
+ path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
15009
+ - type: object
15010
+ description: 'server 7.115.0–7.125.x: the dead-alias matcher refusal before `reason` existed.'
15011
+ required: [event, alias, canonical]
15012
+ additionalProperties: false
15013
+ properties:
15014
+ event: { type: string }
15015
+ alias: { type: string }
15016
+ canonical: { type: string }
15017
+ - type: object
15018
+ description: '400 `config.user_attachment_invalid` (server >= 7.132.0): the field the engine names; `index` only when one attachment is named.'
15019
+ required: [path]
14739
15020
  additionalProperties: false
14740
15021
  properties:
14741
- event: { type: string }
14742
- alias: { type: string }
14743
- canonical: { type: string }
15022
+ path: { type: string }
15023
+ index: { type: integer }
14744
15024
  - type: object
14745
15025
  required: [scenario, source]
14746
15026
  additionalProperties: false
@@ -14750,13 +15030,20 @@ components:
14750
15030
  - type: string
14751
15031
  count:
14752
15032
  type: integer
14753
- description: 'S-904 `reason: over_cap` only — how many entries the bucket had (server >= 7.106.0). SDK: `err.extra.count`.'
15033
+ description: '`reason: over_cap` / `too_long` only — how much was sent (entries / characters; S-904 since server >= 7.106.0, every capped face since >= 7.132.0). SDK: `err.extra.count`.'
14754
15034
  cap:
14755
15035
  type: integer
14756
- description: 'S-904 `reason: over_cap` only — the bucket cap (1000). SDK: `err.extra.cap`.'
15036
+ description: '`reason: over_cap` / `too_long` only — the cap (1000 for a permissions bucket; per face otherwise). SDK: `err.extra.cap`.'
14757
15037
  index:
14758
15038
  type: integer
14759
- description: 'S-904 `reason: bad_entry` only — the index of the first bad item; ABSENT when the bucket itself is not an array. SDK: `err.extra.index`.'
15039
+ description: '`reason: bad_entry` only — the index of the first bad item; ABSENT when the list itself is not an array. SDK: `err.extra.index`.'
15040
+ wallSource:
15041
+ type: string
15042
+ description: >-
15043
+ server >= 7.132.0, on a 413 refused against the database's limits — WHERE THE WALL'S NUMBER CAME FROM. On `request.payload_too_large` (a submit body over
15044
+ the database's single-row / packet wall): `reported` (the database's own number) / `assumed` (not reported — engine facts not established yet, or that
15045
+ wall's read failed and fell back to the documented default; refusing conservatively). On `blob_too_large_for_sql` (`PUT /v1/sessions/{id}/sync/blobs/{hash}`):
15046
+ `operator` (the operator's `SNAPSHOT_BLOB_SQL_MAX_BYTES`) / `reported` / `assumed`. Two closed sets, one per face (SDK `SqlWallSource` / `BlobSqlCapSource`).
14760
15047
  blockedBy:
14761
15048
  type: string
14762
15049
  description: >-
@@ -14767,11 +15054,19 @@ components:
14767
15054
  `ResumeBlockedByPolicyError.blockedBy` (`undefined` when the key is absent or not a string — never defaulted).
14768
15055
  server >= 7.117.0 adds a third fold source: a stored skill `disallowedTools` entry the engine now reads as nothing (the submit leg's 400 `request.field_invalid` sentence)
14769
15056
  ⇒ `blockedBy: "request.field_invalid"`, refused before the claim; the terminal-run steer leg answers it before minting the wake card.
15057
+ server >= 7.132.0 / core 7.52.0: also on an ENGINE-refused resume (the five resume legs, the PARKED redemption seat and the SLA deny sweep share one body):
15058
+ the engine's `detail.code` passes through as `blockedBy` (today only `checkpoint.config_refused` carries it — the closed set is core's
15059
+ `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"),
15060
+ next to `field` and `reason`, absent keys not minted (SDK `ResumeRefusalExtra`).
14770
15061
 
14771
15062
  ResumeLegConflictError:
14772
15063
  description: >
14773
15064
  The 409 body of a RESUME LEG that core refused BEFORE the claim (`POST /v1/approvals/{sessionId}/decide`,
14774
- `POST /v1/sessions/{sessionId}/wake`): `ErrorResponse` plus the one key those 409s may add, `retriable`. The key is declared HERE and
15065
+ `POST /v1/sessions/{sessionId}/wake`): `ErrorResponse` plus the one key those 409s may add, `retriable`. server >= 7.132.0: ONE writer and one
15066
+ rule — on the three kinds of resume refusal (the server's own stored-body replay refusal, the admission-policy fold `resume_blocked_by_policy`, an
15067
+ engine-refused resume) `retriable: true` is present <=> a pending card is still waiting and the run row stays `suspended`; so `resume_blocked_by_policy`
15068
+ now carries it too, and the terminal-run `POST /v1/runs/{id}/steer` refusal before a wake card is minted carries none (the `checkpoint.unsupported_version`
15069
+ allow-reading / mode-reading arms used to claim `true` there). The key is declared HERE and
14775
15070
  not on the shared `ErrorResponse` on purpose (codex r1 [medium], sdk 16.0.0): `ErrorResponse` is the body of every error
14776
15071
  response in this document, and declaring `retriable` there would offer a retry signal on 401 / 404 / 422 / 5xx bodies where the
14777
15072
  server never mints it. (`ErrorResponse` stays open, so a validator cannot REJECT the key elsewhere; the confinement is that only
@@ -14850,6 +15145,8 @@ components:
14850
15145
  - $ref: '#/components/schemas/Event_message_committed'
14851
15146
  # [2373]A-2(2026-08-03,server 5.0.0):compaction_outcome 三腿同源批的 spec 半场(SDK 臂 20867e1 同批)。
14852
15147
  - $ref: '#/components/schemas/Event_compaction_outcome'
15148
+ # server 7.132.0(core 7.53.0 #2008):压缩开始帧,与 compaction_outcome 同一族的三腿同源白名单构造器。
15149
+ - $ref: '#/components/schemas/Event_compaction_started'
14853
15150
  # [2400] ch2(SDK 4.2.0):CB-1 流控帽帧 + TR-7 durable 五臂 —— 两侧同缺,见各 schema 处的注。
14854
15151
  - $ref: '#/components/schemas/Event_error'
14855
15152
  - $ref: '#/components/schemas/Event_question'
@@ -14920,6 +15217,7 @@ components:
14920
15217
  needs_review: '#/components/schemas/Event_needs_review'
14921
15218
  message_committed: '#/components/schemas/Event_message_committed'
14922
15219
  compaction_outcome: '#/components/schemas/Event_compaction_outcome'
15220
+ compaction_started: '#/components/schemas/Event_compaction_started'
14923
15221
  error: '#/components/schemas/Event_error'
14924
15222
  question: '#/components/schemas/Event_question'
14925
15223
  question_complete: '#/components/schemas/Event_question_complete'
@@ -15866,6 +16164,9 @@ components:
15866
16164
  summaryMs: { type: integer }
15867
16165
  persistMs: { type: integer }
15868
16166
  ptlRetries: { type: integer }
16167
+ pass:
16168
+ type: string
16169
+ description: 'server >= 7.132.0 (core 7.53.0 #2008): the id of the compaction pass that LANDED — the same opaque value its `compaction_started.pass` carried. Pair the start with its end on `pass`, not on "the next `compacted`" (legs interleave on one stream). Absent = an older server / a pass that never announced a start.'
15869
16170
  Event_suggestions:
15870
16171
  type: object
15871
16172
  description: >
@@ -15899,7 +16200,7 @@ components:
15899
16200
  type: { const: status }
15900
16201
  # 🔴 A-057.27:6 员(此前只列 4,漏 recovered/gave_up 两个**终局**值 —— 一段重试序列恒恰一终局帧,
15901
16202
  # 两者对渲染方是同一句话「把重试行撤下来」)。闭集声明、开集读。
15902
- phase: { type: string, description: "rate_limited | retrying | reconnecting | circuit_open | recovered | gave_up (closed in core, read as open set)" }
16203
+ phase: { type: string, description: "rate_limited | retrying | reconnecting | circuit_open | recovered | gave_up | waiting_first_token (core's seven words since core 7.3.1 — `waiting_first_token` observes a first-token wait before any failure and carries `elapsedMs` / `timeoutMs`, never a retry countdown; closed in core, read as open set)" }
15903
16204
  detail: { type: string, description: "neutral human hint (NO provider/HTTP detail)" }
15904
16205
  retryInSec: { type: number }
15905
16206
  # 🔴 A-057.26:以下四键 server 真在发(builder brainStatusEventData,三腿共享),而本 schema 是
@@ -15908,7 +16209,7 @@ components:
15908
16209
  attempt: { type: number, description: "1-based index of the attempt that just FAILED (this wait precedes attempt+1)" }
15909
16210
  maxRetries: { type: number, description: "retry budget of the lane in force (refused-connect short lane = 2)" }
15910
16211
  retryInMs: { type: number, description: "same number as retryInSec at ms precision (countdown rendering)" }
15911
- errClass: { type: string, description: "connect_refused | transport | rate_limit | server | http | output_cap — retry-wait frames ONLY; never inferred from phase" }
16212
+ errClass: { type: string, description: "connect_refused | transport | stall | rate_limit | server | http | output_cap (core's seven words since core 7.14.0 — `stall` = this process's own stall watchdog cancelled the request) — retry-wait frames ONLY; never inferred from phase" }
15912
16213
  providerCondition: { type: string, description: "server >= 7.126.0 (core 7.49.0 #1454, passed through verbatim): what the provider said about the account / capacity — core's closed `PROVIDER_CONDITIONS`; a retry frame carries only the three retryable words `throttled | overloaded | unknown` (`quota_exhausted` / `stop_other` do not retry and ride the terminal `detail.providerCondition`). Presence law as `errorStatus`; read as an OPEN set (keep a default arm). ABSENT = not judged, read the same as `unknown` (back off, do not assert quota). Moves with `providerConditionSource`." }
15913
16214
  providerConditionSource: { type: string, description: "server >= 7.126.0 (core 7.49.0 #1454): the evidence the `providerCondition` verdict rests on — `unified_header | provider_code | status`; present exactly when `providerCondition` is; read as an OPEN set." }
15914
16215
  retryAtMs: { type: number, description: "server >= 7.52.0 (core 7.0.0): the WALL-CLOCK end of the wait = `Date.now() + retryInMs` at emit, on the emitting process's clock (not monotonic — never compare it with a local monotonic timer). `retryInMs` stays the authoritative RELATIVE amount; this is the producer's absolute note (a reader several hops away recomputing it would reset the countdown on every replay). Moves with `retryInMs`; absent ⇒ not minted." }
@@ -16031,9 +16332,12 @@ components:
16031
16332
  `message_committed` + stream order). Live emissions PRECEDE the commit and omit `entryId`.
16032
16333
  SERVICE PROJECTION: core's `principal` is deliberately NOT forwarded (the stream is already owner-scoped —
16033
16334
  the frame does not restate the tenant). `issuer` / `actor.id` / `actor.issuer` are host-derived identity
16034
- strings and arrive SECRET-REDACTED. Server >= 7.127.0 does NOT project core 7.50.0's `attachments` member (always absent here)
16035
- and does not accept the engine's request-layer `userAttachments` key: a submit / resume body carrying it is 400
16036
- `request.body_shape` (named in `unknownKeys`).
16335
+ strings and arrive SECRET-REDACTED. REQUEST-LAYER ATTACHMENTS (server >= 7.131.0 / core 7.50.0): the frame of the objective that declared
16336
+ attachments (`carrier: "objective"`, `delivery: "applied"`) carries `attachments` — one item per attachment, in declared order (submit key
16337
+ `TaskRequest.userAttachments`; probe `Capabilities.userAttachments`). It is the ADMISSION outcome, not delivery: each attachment's message lands as its
16338
+ own `message_committed{role:"user"}`. Attachments ride the objective only: a steer door (run / child / workflow child steer, child resume, interrupt
16339
+ bare or with text) carrying `userAttachments` is 400 `request.body_shape` (named in `unsupportedKeys`), and resume / delivery legs do not rebuild it.
16340
+ (7.127.0 – 7.130.x did not accept `userAttachments` and never carried `attachments`; the capability bit is absent there.)
16037
16341
  allOf: [{ $ref: '#/components/schemas/EventIdentity' }]
16038
16342
  additionalProperties: false # 封闭 + identity 本地镜像:见 Event_reasoning 处的长注
16039
16343
  required: [type, inputId]
@@ -16064,6 +16368,23 @@ components:
16064
16368
  hostAsserted: { type: boolean }
16065
16369
  issuer: { type: string }
16066
16370
  entryId: { type: string, description: 'The committed session entry this input became (absent on the live pre-commit emission).' }
16371
+ attachments:
16372
+ type: array
16373
+ description: >-
16374
+ server >= 7.131.0 (core 7.50.0): the per-attachment ADMISSION outcome of the request-layer attachments this objective declared, one item per
16375
+ attachment in declared order; present only on that objective's frame. The server copies each member key only when well-formed (a non-object member is
16376
+ not minted); `ordinal` / `outcome` / `label` are required members of the engine's `HumanInputAttachment` (core 7.53.0), hence `required` here. `ordinal` 1-based; `kind` the engine-recognized kind (absent when unreadable; read open); `outcome` `attached` / `partial` / `unchanged` /
16377
+ `not_attached` (engine words, verbatim — a file the engine may not read is NOT refused: its message still goes out saying why, and its outcome is
16378
+ `not_attached`); `label` the path or name the caller declared, credential-redacted.
16379
+ items:
16380
+ type: object
16381
+ required: [ordinal, outcome, label]
16382
+ additionalProperties: false
16383
+ properties:
16384
+ ordinal: { type: integer }
16385
+ kind: { type: string }
16386
+ outcome: { type: string }
16387
+ label: { type: string }
16067
16388
  eventId: { type: string }
16068
16389
  parentToolCallId: { type: string }
16069
16390
  sourceTaskId: { type: string }
@@ -16243,19 +16564,22 @@ components:
16243
16564
  already owns the single redaction mint point for it). The actionable cause is `errorCode`.
16244
16565
  A row missing `name` or `status` is dropped individually — the other servers'' rows still ship.
16245
16566
  items: { $ref: '#/components/schemas/WiringManifestMcpEntry' }
16246
- hooks:
16567
+ mods:
16247
16568
  type: array
16248
16569
  description: >
16249
- core 7.18.0 (#789), server >= 7.78.0 — TENANT-visible: the hook seats THIS leg wired, one row per
16250
- family, in core's declaration order. EFFECTIVE half only.
16251
- 🔴 PRESENT IFF at least one seat is wired — core NEVER emits an empty array, so "the key is here"
16252
- means non-empty. 🔴 ABSENCE READS "this leg wired no hook RECORD of its own", NOT "no hook runs":
16253
- a delegated child with no local record can still be screened (and refused) by an ANCESTOR's
16254
- `preToolUse` through the gate's constraint fold, which this face deliberately does not call a hook
16255
- of this leg. A row missing `family` or `owner` is dropped INDIVIDUALLY (same rule as `mcp[]`); all
16256
- rows dropped => the key is absent. 🔴 EXCLUDED from `configFingerprint` (the record is a per-task
16257
- seat), so two legs with the same fingerprint and different `hooks[]` are NOT in contradiction.
16258
- items: { $ref: '#/components/schemas/WiringManifestHookEntry' }
16570
+ core 7.52.0, server >= 7.132.0 (BREAKING — replaces `hooks[]`, which is gone with no alias) — TENANT-visible: this leg's MODS ADMISSION record, one row
16571
+ per registration of the two seats (deployment, task), in the engine's run order (tier, then deployment before task, then seat order). Two row forms
16572
+ (`WiringManifestModEntry`): a MOUNTED registration `{ name, seat, tier, events, observe?, skipped? }` — `events` / `observe` are the patterns it actually
16573
+ hung (observe-only ones in `observe`), `skipped[]` the judges skipped while it was judged — or a REFUSED one `{ name, seat, tier, refusedBy, reason }`.
16574
+ Registrant strings (`name`, `refusedBy`, `reason`, every `skipped[]` member) go out through the server's one wire-text exit (credential shapes
16575
+ replaced, length-capped) — the same one the `engine_notice` `mods.registration_refused` detail uses, so the same refusal reads byte-equal on both;
16576
+ `seat` / `tier` / `events` / `observe` are engine words passed through verbatim (vocabulary owner core; read open). PRESENT IFF the leg carries a
16577
+ registration — on this server always (it mounts the permission-denied meter on every leg: `server.permission-denied-meter`; `TOOL_TRACE=true` adds
16578
+ `server.tool-trace`, a branded deployment `server.brand-identity`; a single-user request's `settings.hooks` is the task-seat registration
16579
+ `settings.hooks`). 🔴 ABSENCE READS "this leg carries no registration", NOT "no extension judges this leg's calls" (a delegated child can still be
16580
+ screened through an ancestor's chain). A row that reads as neither form is dropped individually; all dropped => key absent. EXCLUDED from
16581
+ `configFingerprint` (the task seat is per task). EFFECTIVE half only.
16582
+ items: { $ref: '#/components/schemas/WiringManifestModEntry' }
16259
16583
  lsp:
16260
16584
  allOf: [{ $ref: '#/components/schemas/WiringManifestLspSeam' }]
16261
16585
  description: >
@@ -16652,6 +16976,26 @@ components:
16652
16976
  was armed but declined/failed (check the store, check authorisation), `false` = there was no lane at all
16653
16977
  (wire one up). The two recovery verbs differ, so a consumer MUST render them apart — NEVER fold them into
16654
16978
  one "nobody approved it".
16979
+ server 7.132.0 adds three codes to the user whitelist (appendix D.3 38 -> 41; all audience `user` in core's register) and changes one value:
16980
+ `config.session_rules_earlier_grammar` (core 7.53.0) — the session's STORED permission rules hold entries the grammar they were written in reads as nothing
16981
+ (an allow entry admits nothing; a `toolDeny` entry this engine reads as no rule makes those rules REFUSE EVERY CALL until an operator rewrites the row
16982
+ without its rev). `{ bucket, storedGrammar, entries: [{ entry, reader }], rewrite: { by, stampsGrammar }, rulesSessionId, sessionId }` — `entries` every
16983
+ one the engine handed over (the session-stream row passes the generic notice-detail bound: at most the first 32, no truncation mark — the full list is on
16984
+ the ops log line), `entry` the redacted rule text (the same reading as `permission.allowed_tool_not_granted`'s `entries[].entry`), `reader` one of
16985
+ `no_rule` / `named_no_tool`, `rewrite.by` = `operator_write_without_rev` (closed words owned by core, echoed — read open); `rulesSessionId` = whose
16986
+ rules (an ancestor's on a delegated child), `sessionId` = the run that read them. Once per distinct entry set per bucket per rule layer.
16987
+ `mods.registration_refused` (core 7.52.0) — an extension registration was NOT mounted (another registration's `plugin.register` judge refused it); the leg
16988
+ runs without it. `{ name, seat, tier, refusedBy, reason, sessionId }` — `seat` / `tier` engine words (echoed), `reason` the refusing registration's own
16989
+ words (UNTRUSTED-for-display); the same strings read byte-equal with the `wiring_manifest.mods[]` refused row. Unreachable on this server today (it wires
16990
+ no `plugin.register` judge). Once per leg per registration.
16991
+ `route.credential_origin_mismatch` (core 7.52.0) — a request was REFUSED and nothing was sent: this model's own credential is bound to the host it first
16992
+ went to and this request goes to another (the entry's `baseUrl` moved host, the credential stayed; a same-host path move does not count). The request's
16993
+ own failure carries the same code. `{ modelId, boundOrigin, requestOrigin, sessionId, runId }` — both origins in display spelling (scheme + host +
16994
+ port, no userinfo / path), never a credential or a digest of one. Once per run per (modelId, boundOrigin, requestOrigin). It replaces the retired
16995
+ operator code `route.base_url_changed_key_unchanged` (never on this whitelist). `config.credential_not_withheld` is operator-audience — ops log only.
16996
+ Value change: `permission.rule_row_dropped`'s `detail.rows[].rule` is, since core 7.53.0, the rule's original text (the same reading as
16997
+ `allowed_tool_not_granted`'s `entries[].entry`: at most 1 024 code points, longer cut to 1 024 + a truncation mark, CONTROL CHARACTERS RIDE AS DATA —
16998
+ neutralize at render); before it was the engine-neutralized single-line form (at most 201 code points). Same keys.
16655
16999
  `server.model_unreachable` (server-minted, audience `user`; server >= 7.108.0, `taskId` added in server 7.121.0) — a model call on
16656
17000
  this leg ended in error and its last request failed AT CONNECT (VPN switched mid-session / the proxy read at boot went stale / the
16657
17001
  gateway is gone) — not the provider's answer. `{ code, targetHost, proxyInUse?, remedy, sessionId, taskId? }`: `code` one of the
@@ -16893,56 +17237,78 @@ components:
16893
17237
  一律按不可分辨处理,消费方不要猜。
16894
17238
 
16895
17239
  PromptManifest:
16896
- # 新增(2026-07-25 回填批):server ≥1.219 的 prompt-assembly manifest。此前本文件完全没有它(全文 0 次提及),
16897
- # 尽管它同时是 `AgentEvent.prompt_assembled` 臂和 trace 流 `prompt-assembled` 帧的载荷。
16898
17240
  type: object
16899
17241
  description: >
16900
- The prompt-assembly manifest (core's `prompt.assembled` trace contract verbatim). Carries ONLY
16901
- ids/digests/counts — NEVER prompt bodies (privacy boundary). 🔴 Hashes are PROCESS-SALTED: they are NOT
16902
- comparable across worker restarts, so a UI must never diff them cross-process. `constitution`/`blocks`/
16903
- `totalChars` are the v1 face; `sections`/`tools` are the v2 ADDITIVE face (absent on a v1-only engine).
16904
- ⚠️ One task can carry MULTIPLE manifests — a cascade/verify run re-prepares under one taskId and every
16905
- rung's manifest is persisted in emission order.
16906
- required: [constitution, blocks, totalChars]
17242
+ The prompt manifest v3 (server >= 7.132.0 = engine 7.52.0 manifest v3; BREAKING): WHICH prompt this leg ran (`identity` + its selector values `selectors`),
17243
+ which blocks and sections it is made of, and where each section's text came from (`chain`; superseded overlays in `superseded`). IDs / sizes / digests
17244
+ only — NEVER prompt text. One row per prepare (cascade / verify re-prepare under one taskId, rows in order). Three exits carry the SAME stored row
17245
+ verbatim: the ledger replay `prompt_assembled`, the turns `prompt-assembled` block, the trace SSE `prompt-assembled` frame. Members = the engine frame
17246
+ minus its envelope (`kind` / `version` / `taskId` / `ts`) and `snapshot` / `lowering` (server `promptManifestRecordOf`).
17247
+ READING: EVERY member may be absent — an optional member absent means "none", never an empty value; a member present but unreadable is not put on the
17248
+ row (`identity` / `selectors` as whole sentences, sections / blocks / `superseded` / tools one row at a time), so a v3 row without `identity` means the
17249
+ engine's identity did not read (dropped and counted), NOT an old row. An empty list is a statement (`tools: []` = zero tools). Words (band names,
17250
+ activations, source classes, renderer ids, host role / form) are engine vocabulary, passed through verbatim — read open.
17251
+ 🔴 THE ONE READING OF "WHICH PROMPT DID THIS LEG RUN" IS `identity`. BREAKING (no alias): v2's top-level `constitution` is gone (the constitution band
17252
+ is locked and engine-composed; a prompt carrying locked text verbatim is refused before the run, `prompt.assembled_role_refused`); `sections[]` lost
17253
+ `slot` / `carrier` / `cadence` / `cacheClass`, `hash` became `contentHash` (`sha256:` unsalted for published text, `salted:` for text carrying the task's
17254
+ or the run's own inputs) and gained `band` (always) / `variant?` / `renderer?` / `locale` / `chain`; the row gained `identity` / `selectors` / `superseded?`.
17255
+ ⚠️ Rows written by <= 7.131.x keep the v2 shape (the server neither re-reads nor rewrites them) — see PromptManifestRow: a row carrying `constitution`
17256
+ is such an old row. ⚠️ Block `hash` is a PROCESS-SALTED short digest — not comparable across worker restarts.
17257
+ # 不封闭(`additionalProperties: true`):本 schema 是 `Event_prompt_assembled` 的 allOf 目标(帧上多一个 `type`),封闭会把合法帧判成违约(见 Event_reasoning 处的长注)。
17258
+ # 与旧行的互斥由 `not: { required: [constitution] }` 一句写死(v3 行永不带它),`PromptManifestRow` 的 oneOf 因此恰中一臂。
16907
17259
  additionalProperties: true
17260
+ not: { required: [constitution] }
16908
17261
  properties:
16909
- constitution:
16910
- type: string
16911
- description: 'who owned the constitution layer — `core` is the steady state; anything else is worth eyes.'
16912
- enum: [core, replaced, provider-assembled, legacy]
16913
- x-open-enum: true
17262
+ identity: { $ref: '#/components/schemas/PromptManifestIdentity' }
17263
+ selectors:
17264
+ type: object
17265
+ description: 'the run''s selector values (core `PromptManifestSelectors`) — the plain form of `identity.layers.binding`. `binding` = the scenario name (server >= 7.132.0 always writes `TaskSpec.promptBinding`).'
17266
+ additionalProperties: false
17267
+ required: [traits, host, facts]
17268
+ properties:
17269
+ binding: { type: string }
17270
+ traits: { type: array, items: { type: string } }
17271
+ host:
17272
+ type: object
17273
+ additionalProperties: false
17274
+ required: [role, form]
17275
+ properties:
17276
+ role: { type: string, description: 'engine word (`general` / `code` / `coordinator` / `cowork` today); read open.' }
17277
+ form: { type: string, description: 'engine word (`standard` / `minimal` today); read open.' }
17278
+ facts: { type: object, additionalProperties: { type: boolean } }
16914
17279
  blocks:
16915
17280
  type: array
16916
17281
  items:
16917
17282
  type: object
17283
+ additionalProperties: false
16918
17284
  required: [id, chars, hash]
16919
- additionalProperties: true
16920
17285
  properties:
16921
17286
  id: { type: string }
16922
17287
  chars: { type: integer }
16923
- hash: { type: string, description: 'process-salted digest — never compare across restarts.' }
17288
+ hash: { type: string, description: 'process-salted short digest — never compare across restarts.' }
16924
17289
  sections:
16925
17290
  type: array
16926
- description: 'v2 additive face — absent on a v1-only engine.'
17291
+ items: { $ref: '#/components/schemas/PromptManifestSection' }
17292
+ superseded:
17293
+ type: array
17294
+ description: 'every overlay the composition superseded (a later one on the same target won, or it changed nothing this run); absent when none was.'
16927
17295
  items:
16928
17296
  type: object
16929
- required: [id, slot, carrier, cadence, cacheClass, chars, hash]
16930
- additionalProperties: true
17297
+ additionalProperties: false
17298
+ required: [id, source, by, target, supersededBy]
16931
17299
  properties:
16932
17300
  id: { type: string }
16933
- slot: { type: string }
16934
- carrier: { type: string }
16935
- cadence: { type: string }
16936
- cacheClass: { type: string }
16937
- chars: { type: integer }
16938
- hash: { type: string }
17301
+ source: { type: string }
17302
+ by: { type: string }
17303
+ target: { type: string }
17304
+ supersededBy: { type: string, description: 'the winning overlay id, or the literal `(absent this run)`.' }
16939
17305
  tools:
16940
17306
  type: array
16941
- description: 'v2 additive face — the tool contract summary.'
17307
+ description: 'the mounted tools plane — per-tool contract identity, durable-replay aliases, shape digest and full wire-schema digest (initial mount face; deferred activations announce via tools_delta).'
16942
17308
  items:
16943
17309
  type: object
17310
+ additionalProperties: false
16944
17311
  required: [wireName, aliases, contractId, implementationRevision, cardId, shapeDigest, wireSchemaDigest]
16945
- additionalProperties: true
16946
17312
  properties:
16947
17313
  wireName: { type: string }
16948
17314
  aliases: { type: array, items: { type: string } }
@@ -16951,7 +17317,72 @@ components:
16951
17317
  cardId: { type: string }
16952
17318
  shapeDigest: { type: string }
16953
17319
  wireSchemaDigest: { type: string }
17320
+ toolDisclosure:
17321
+ type: object
17322
+ description: 'the resolved deferred-tool disclosure strategy (core `ToolDisclosureManifest`); absent when the leg deferred nothing.'
17323
+ additionalProperties: false
17324
+ required: [deferredTools, strategy, source]
17325
+ properties:
17326
+ deferredTools: { type: integer }
17327
+ strategy: { type: string, description: '`swap` / `static`; read open.' }
17328
+ source: { type: string, description: '`spec` / `env` / `default` / `degraded_no_direct_lane`; read open.' }
16954
17329
  totalChars: { type: integer }
17330
+ PromptManifestIdentity:
17331
+ type: object
17332
+ description: 'the run''s prompt identity as the manifest reports it (core `PromptManifestIdentity`): `artifact` = the identity digest, `layers` = its inputs, `epoch` / `activatedBy` = the session epoch record that names it.'
17333
+ additionalProperties: false
17334
+ required: [artifact, layers, epoch, activatedBy]
17335
+ properties:
17336
+ artifact: { type: string }
17337
+ layers: { $ref: '#/components/schemas/PromptIdentityLayers' }
17338
+ epoch: { type: integer }
17339
+ activatedBy: { type: string, description: 'core `PROMPT_EPOCH_ACTIVATIONS` word; read open.' }
17340
+ PromptManifestSection:
17341
+ type: object
17342
+ description: 'one rendered section (core `PromptManifestSection`).'
17343
+ additionalProperties: false
17344
+ required: [id, band, rank, chars, locale, contentHash, chain]
17345
+ properties:
17346
+ id: { type: string }
17347
+ band: { type: string }
17348
+ rank: { type: number }
17349
+ variant: { type: string }
17350
+ renderer:
17351
+ type: object
17352
+ additionalProperties: false
17353
+ required: [id, version]
17354
+ properties:
17355
+ id: { type: string, description: 'core `RENDERER_IDS` word; read open.' }
17356
+ version: { type: number }
17357
+ chars: { type: integer }
17358
+ locale: { type: string, description: '`canonical` (the catalog''s text) / `overlay` (text an overlay author wrote); read open.' }
17359
+ contentHash: { type: string, description: '`sha256:<hex>` unsalted for published text, `salted:<hex>` for text carrying the task''s or the run''s own inputs.' }
17360
+ chain:
17361
+ type: array
17362
+ items:
17363
+ type: object
17364
+ additionalProperties: false
17365
+ required: [source]
17366
+ properties:
17367
+ source: { type: string, description: '`bundled` or an overlay source class; read open.' }
17368
+ overlay: { type: string }
17369
+ op: { type: string }
17370
+ superseded: { const: true }
17371
+ PromptManifestRetiredRow:
17372
+ type: object
17373
+ description: >
17374
+ A `prompt_assembled` row written by a <= 7.131.x server (the v2 shape: top-level `constitution` + slot-keyed sections). The server neither re-reads nor
17375
+ rewrites it, so a run parked before the upgrade and resumed after carries both shapes in its ledger. The ONE discriminator (owned by the server contract):
17376
+ `constitution` present <=> an old row (old rows always carry it, v3 rows never do). Its members are deliberately NOT typed here (the v2 reading is retired).
17377
+ required: [constitution]
17378
+ additionalProperties: true
17379
+ properties:
17380
+ constitution: { type: string }
17381
+ PromptManifestRow:
17382
+ description: 'One row on the three manifest exits: a v3 row (PromptManifest) or an old row (PromptManifestRetiredRow) — tell them apart by the presence of `constitution`.'
17383
+ oneOf:
17384
+ - $ref: '#/components/schemas/PromptManifest'
17385
+ - $ref: '#/components/schemas/PromptManifestRetiredRow'
16955
17386
 
16956
17387
  Event_file_link:
16957
17388
  type: object
@@ -16983,7 +17414,7 @@ components:
16983
17414
  manifest's own keys sit at the top level next to `type`, they are NOT nested under a `manifest` key).
16984
17415
  Lands AHEAD of the first event of the turn it prepared. ⚠️ MULTIPLE per task on cascade/verify runs.
16985
17416
  allOf:
16986
- - $ref: '#/components/schemas/PromptManifest'
17417
+ - $ref: '#/components/schemas/PromptManifestRow'
16987
17418
  required: [type]
16988
17419
  properties:
16989
17420
  type: { const: prompt_assembled }
@@ -17234,15 +17665,16 @@ components:
17234
17665
  (no alias): the allow-layer members that MATCHED this call and could NOT clear this ask, one `{ member, entries, omitted? }` record per
17235
17666
  matching member (see AllowRuleShadow). `member` is one of `hook` / `deployment` / `persisted` / `skill` / `request`; `entries` are the
17236
17667
  entries that member matched, as their source spells them (UNTRUSTED for display like `message`, secret-redacted, <= 512 chars each,
17237
- <= 32 listed; a `hook` record's `entries` is always the empty list); `omitted` counts the entries not listed.
17668
+ <= 32 listed; a `hook` record's `entries` names the answering registration — server >= 7.132.0 / engine 7.52.0 mods: on this server only the
17669
+ request's own `settings.hooks` answers, so `["settings.hooks"]`; it was always the empty list on <= 7.131.x); `omitted` counts the entries not listed.
17238
17670
 
17239
17671
  The explaining sentence ("... matches this call but does not clear the ask — <reason>") is IN `message` (the engine writes it where it builds
17240
17672
  the card); this key is the structured twin of the same fact. Render a line from it ("your rule matched, but this call must be confirmed each
17241
17673
  time"): without it the only conclusion a user can draw is "my rule broke".
17242
17674
 
17243
17675
  🔴 ABSENT != "you have no rule": present only when a member matched AND could not clear the ask; a match that cleared never becomes an ask.
17244
- 🔴 `member: "hook"` does not say whose hook (a deployment PreToolUse hook and, on the single-user lane, the request's own `settings.hooks`
17245
- share one member). 🔴 Deliberately SEPARATE from `governanceForced` (that one: "who imposed the gate"; this one: "what happened to YOUR
17676
+ 🔴 `member: "hook"` names the answering registration in `entries` (server >= 7.132.0; the deployment seat's registrations are observers and never
17677
+ answer — on <= 7.131.x the record could not say whose hook). 🔴 Deliberately SEPARATE from `governanceForced` (that one: "who imposed the gate"; this one: "what happened to YOUR
17246
17678
  rule"). What the allow layer can NOT clear: any layer's deny / ask rule, operator `APPROVAL_REQUIRE` / `APPROVAL_NEVER_AUTO` /
17247
17679
  `MANUAL_MODE_SHELL_GATE=always`, write protection, sensitive-path writes, governance, a hook's ask, plan-mode asks. The durable dual is
17248
17680
  `gate.riskDescriptor.allowRuleShadowed` on the parked row (PendingCheckpoint.riskDescriptor). Rolling-upgrade caveat: a card stored by a
@@ -17686,7 +18118,7 @@ components:
17686
18118
  items: { $ref: '#/components/schemas/AllowRuleShadow' }
17687
18119
  description: >
17688
18120
  ADDITIVE (server >= 7.117.0 / core 7.42.0, BREAKING RENAME of the retired `persistedRuleShadowed`): the allow-layer members that matched this
17689
- call and could not clear this ask. Semantics, the five members, the always-empty `hook` entries, the explaining sentence living in `message`,
18121
+ call and could not clear this ask. Semantics, the five members, the `hook` record naming its registration (server >= 7.132.0; always empty before), the explaining sentence living in `message`,
17690
18122
  the ABSENT != "you have no rule" clause and the separation from `governanceForced` are stated verbatim on ToolApprovalFrame.allowRuleShadowed
17691
18123
  — the live frame, the stored `card_json`, the replayed frame and the `approval_request` card carry the SAME material.
17692
18124
  fromSubagent: { type: boolean, enum: [true], description: 'Present ⇔ the ask comes from a DELEGATED child — the explicit discriminator (a worker cannot forge it).' }
@@ -18997,6 +19429,31 @@ components:
18997
19429
  outcome: { type: string }
18998
19430
  trigger: { type: string, description: 'engine-shaped; current emitters send auto | manual | forced' }
18999
19431
  reason: { type: string }
19432
+ pass:
19433
+ type: string
19434
+ description: >-
19435
+ server >= 7.132.0 (core 7.53.0 #2008): the id of the pass this frame CONCLUDES (= its `compaction_started.pass`). PRESENT <=> that pass announced a start,
19436
+ so only on `failed` / `mooted` (a pass that ran its summary and did not land, or was cut while it ran — `mooted` with `reason: "task_ending"` = the task's
19437
+ own end cut the running summary, a form this frame closes since core 7.53.0). `blocked` / `suppressed` / `disabled` / `noop` and a manual request no
19438
+ boundary served carry none (those passes never started).
19439
+ eventId: { type: string }
19440
+ parentToolCallId: { type: string }
19441
+ Event_compaction_started:
19442
+ type: object
19443
+ description: >
19444
+ server >= 7.132.0 (core 7.53.0 #2008) — a compaction pass is UNDER WAY: announced at the pass's commit point (trigger gate passed, a cut point exists,
19445
+ `preCompact` did not block), BEFORE the summary call, so a summary waiting out a provider's retries is no longer silent on the stream. Projected verbatim by
19446
+ ONE whitelist builder (server `compactionStartedEventData`) on the live stream and both durable ledgers (bg / resume; `GET /v1/runs/{id}/events`); the
19447
+ §2.3 trace stream does not carry it. PAIRING: exactly one frame concludes the pass with the SAME `pass` — `compacted` when it lands,
19448
+ `compaction_outcome` (`failed` / `mooted`) when it does not; "compacting" runs from this frame to that one (or the stream's end), elapsed = now − startedAt.
19449
+ A segment boundary, like `compacted` / `compaction_outcome`. Servers <= 7.131.x never send it. Identity: the same TWO keys as `compaction_outcome`.
19450
+ additionalProperties: false # 封闭:铸造点 `compactionStartedEventData` 只投这三键 + 身份两键
19451
+ required: [type, trigger, pass, startedAt]
19452
+ properties:
19453
+ type: { const: compaction_started }
19454
+ trigger: { type: string, description: 'the same vocabulary (and the same value) as the frame that concludes the pass — engine-shaped, read open; today auto | manual | forced.' }
19455
+ pass: { type: string, description: 'the pass identity: an opaque engine-minted id, unique across runs — pair on it alone.' }
19456
+ startedAt: { type: integer, description: 'engine clock, epoch ms, at the moment the pass committed.' }
19000
19457
  eventId: { type: string }
19001
19458
  parentToolCallId: { type: string }
19002
19459
  Event_config_assembled:
@@ -19804,7 +20261,7 @@ components:
19804
20261
  description: >
19805
20262
  🔴 ONE RULE FOR EVERY "EFFECTIVE HALF ONLY" KEY (sdk 9.7.0, after a codex adversarial-review [high]):
19806
20263
  this schema's only consumer today is `GET /v1/diagnostics/wiring`'s `static` half, and every key marked
19807
- "effective half only" (`leg`, `ask.effective`, `configFingerprint`, `tools`, `hooks`, `lsp`,
20264
+ "effective half only" (`leg`, `ask.effective`, `configFingerprint`, `tools`, `mods`, `lsp`,
19808
20265
  `modelGate`, `autoMode`, `writeProtection`, `readDeny`, `autoConsolidation`, `fileHistory`, `instructions`) is ALWAYS ABSENT on that
19809
20266
  wire ⇒ THEIR ABSENCE HERE CARRIES NO INFORMATION. The per-key absence readings ("absent = not armed",
19810
20267
  "absent = a third state", …) hold for the LIVE FRAME (`Event_wiring_manifest`) and must not be carried
@@ -19950,14 +20407,12 @@ components:
19950
20407
  properties:
19951
20408
  armed: { type: boolean }
19952
20409
  reason: { type: string }
19953
- hooks:
20410
+ mods:
19954
20411
  type: array
19955
20412
  description: >
19956
- core 7.18.0 (#789), server >= 7.78.0 — the hook seats THIS leg wired, one row per family.
19957
- EFFECTIVE half only (the diagnostics endpoint's static half never carries it). Present iff at least
19958
- one seat is wired; absence means "no hook RECORD of this leg", never "no hook runs".
19959
- Full per-key contract: see Event_wiring_manifest.hooks.
19960
- items: { $ref: '#/components/schemas/WiringManifestHookEntry' }
20413
+ core 7.52.0, server >= 7.132.0 (BREAKING — replaces `hooks[]`) — the leg's mods admission record, one row per registration. EFFECTIVE half only (the
20414
+ diagnostics endpoint's static half never carries it). Full per-key contract: see Event_wiring_manifest.mods.
20415
+ items: { $ref: '#/components/schemas/WiringManifestModEntry' }
19961
20416
  lsp:
19962
20417
  allOf: [{ $ref: '#/components/schemas/WiringManifestLspSeam' }]
19963
20418
  description: >
@@ -20066,33 +20521,52 @@ components:
20066
20521
  type: array
20067
20522
  description: 'The selected chain member(s), spelled as the chain spells them (relative to the cwd); `[]` = the chain was walked, nothing was selected.'
20068
20523
  items: { type: string, enum: ['CLAUDE.md', '.claude/CLAUDE.md', 'AGENTS.md', '.claude/AGENTS.md'] }
20069
- WiringManifestHookEntry:
20070
- # sdk 9.5.0:与 `WiringManifestMcpEntry` 同一条裁定 —— 同一份行形被 live 帧与静态诊断面两处引用,
20071
- # 内联就是两份会各自漂的镜像,所以一开始就具名。
20524
+ WiringManifestModEntry:
20525
+ # server 7.132.0 / core 7.52.0:取代钩子席位行形(删,零别名)。同一份行形被 live 帧与静态诊断面两处引用 ⇒ 具名;两形各自具名(⑤bis 名单逐形对账)。
20526
+ description: >
20527
+ One row of a leg's MODS ADMISSION record (core 7.52.0 `ModAdmissionRecord`; server >= 7.132.0): a registration that was mounted, or one that was refused.
20528
+ Discriminate on presence — a mounted row carries `events`, a refused row carries `refusedBy` + `reason` (never both).
20529
+ oneOf:
20530
+ - $ref: '#/components/schemas/WiringManifestModMounted'
20531
+ - $ref: '#/components/schemas/WiringManifestModRefused'
20532
+ WiringManifestModMounted:
20072
20533
  type: object
20073
20534
  description: >
20074
- One row of a leg's HOOK seat manifest (core 7.18.0 #789): which family, where the seat came from, and
20075
- whether the `preToolUse` row was DECLARED observational.
20535
+ A MOUNTED registration: the patterns it actually hung (`events`), the ones it declared observe-only (`observe`, present iff any), and the judges skipped while it
20536
+ was judged (`skipped`, present iff non-empty — absence and an empty list are both "every judge answered").
20076
20537
  additionalProperties: false
20077
- required: [family, owner]
20538
+ required: [name, seat, tier, events]
20078
20539
  properties:
20079
- family:
20080
- type: string
20081
- description: >
20082
- The hook family. core's closed vocabulary today (`preToolUse` / `postToolUse` / `userPromptSubmit` /
20083
- `stop` / `postToolUseFailure` / `postToolBatch` / `preCompact` / `postCompact` / `stopFailure` /
20084
- `permissionDenied`) but READ AS OPEN: the server passes it through verbatim and does not enumerate,
20085
- so a newly minted family must pass through your default arm.
20086
- owner:
20087
- type: string
20088
- description: "Where the seat came from — core's `SeamProvenance` (`spec` / `deps`). Closed today, read as open."
20089
- observational:
20090
- type: boolean
20091
- enum: [true]
20092
- description: >
20093
- Only on the `preToolUse` row, and only when the deployment DECLARED the face observational: it still
20094
- runs on every call but is not folded into a delegated child's inherited constraints.
20095
- 🔴 NEVER-FALSE — core's words: "Absence means 'not declared', never 'declared false'".
20540
+ name: { type: string, description: 'the registration name (registrant text, through the server''s wire-text exit; UNTRUSTED-for-display).' }
20541
+ seat: { type: string, description: 'which seat it came from — core `MOD_SEATS` (`deployment` / `task`). Engine word, passed through verbatim; read open.' }
20542
+ tier: { type: string, description: 'its tier — core `MOD_TIERS` (`prepend` / `user` / `append` / `builtin` / `core`). Engine word, passed through verbatim; read open.' }
20543
+ events: { type: array, items: { type: string }, description: 'the event patterns it actually hung (engine words, verbatim).' }
20544
+ observe: { type: array, items: { type: string }, description: 'the patterns it hung observe-only (engine words, verbatim); absent = none.' }
20545
+ skipped:
20546
+ type: array
20547
+ description: 'judges the dispatch skipped while this registration was judged (core `ModSkip`); present iff non-empty. An element missing a member is dropped individually.'
20548
+ items:
20549
+ type: object
20550
+ additionalProperties: false
20551
+ required: [registration, cause, reason]
20552
+ properties:
20553
+ registration: { type: string, description: 'the skipped judge''s registration name (registrant text).' }
20554
+ cause: { type: string, description: 'why it did not answer for itself — core `MOD_FAILURE_CAUSES` today (`threw` / `timeout` / `violation` / `reentry`); read open.' }
20555
+ reason: { type: string, description: 'the judge''s own words (registrant text, UNTRUSTED-for-display).' }
20556
+ WiringManifestModRefused:
20557
+ type: object
20558
+ description: >
20559
+ A REFUSED registration: another registration's `plugin.register` judge refused it at admission; the leg runs without it. The same refusal also reaches
20560
+ the stream as the `engine_notice` `mods.registration_refused` (its `detail` strings read byte-equal with this row's). This deployment wires no
20561
+ `plugin.register` judge, so it cannot happen here today.
20562
+ additionalProperties: false
20563
+ required: [name, seat, tier, refusedBy, reason]
20564
+ properties:
20565
+ name: { type: string, description: 'the refused registration (registrant text).' }
20566
+ seat: { type: string, description: 'core `MOD_SEATS` word, verbatim; read open.' }
20567
+ tier: { type: string, description: 'core `MOD_TIERS` word, verbatim; read open.' }
20568
+ refusedBy: { type: string, description: 'the registration whose judge refused it (registrant text).' }
20569
+ reason: { type: string, description: 'the refusing judge''s own words (registrant text, UNTRUSTED-for-display).' }
20096
20570
  WiringManifestLspSeam:
20097
20571
  # sdk 9.5.0:同上 —— live 帧与静态面共用一份段形。
20098
20572
  type: object
@@ -20269,7 +20743,9 @@ components:
20269
20743
  description: >
20270
20744
  server >= 7.60 (S-131) — this deployment's SQL engine posture (engine / version / session isolation
20271
20745
  level / TiDB transaction mode), READ BACK off a live connection rather than echoed from env.
20272
- `null` = no SQL backend. NOT YET MIRRORED KEY-BY-KEY in this SDK generation — read as opaque.
20746
+ `null` = no SQL backend. server >= 7.132.0 adds three keys (additive): `maxRowBytes` / `maxPacketBytes` (the database's single-row / packet
20747
+ wall; `null` = that wall does not exist) and `wallSources` (each wall's provenance, `reported` / `assumed` — what a 413 body's `wallSource` reads).
20748
+ NOT YET MIRRORED KEY-BY-KEY in this SDK generation — read as opaque.
20273
20749
  configApply:
20274
20750
  type: ["object", "null"]
20275
20751
  additionalProperties: true