@sema-agent/sdk 23.1.0 → 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 +61 -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 +307 -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 +518 -112
  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
@@ -9657,6 +9657,16 @@ components:
9657
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
9658
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).
9659
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`.
9660
9670
  asyncRuns: { type: boolean }
9661
9671
  artifacts: { type: boolean }
9662
9672
  approvals: { type: boolean }
@@ -10892,7 +10902,19 @@ components:
10892
10902
  `principalHeader` (both set => 400 request.body_shape); a non-string value => 400 request.field_invalid.
10893
10903
  7.128.x accepts and carries the declaration but does NOT send an assertion yet (engine seat pending;
10894
10904
  operator line `mcp_assertion_header_not_sent`).
10895
- 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`.
10896
10918
  elicitation: { type: boolean }
10897
10919
  toolAxes:
10898
10920
  type: object
@@ -10908,6 +10930,15 @@ components:
10908
10930
  server >= 7.66.0 — per-tool face overlays keyed by BARE tool name (see McpToolFace). Any malformed
10909
10931
  face drops the whole server.
10910
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`).
10911
10942
 
10912
10943
  A2aServerSpec:
10913
10944
  type: object
@@ -11836,12 +11867,16 @@ components:
11836
11867
  x-open-enum: true
11837
11868
  description: >-
11838
11869
  A model row's key<->URL pairing posture (core `RoutePairingStatus`; server >= 7.45). OPEN on read —
11839
- 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
11840
11871
  URL, no credential.
11841
11872
  `ok:per-model` this model has its own credential · `ok:paired` deployment credential, and the model's URL
11842
11873
  is on the deployment's declared root · `ok:keyless` no credential anywhere (a local unauthenticated
11843
11874
  gateway) · `broken:credential_mismatch` / `broken:credential_missing` a real request WILL be refused by
11844
- 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".
11845
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 —
11846
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
11847
11882
  "pairing not verified", never as good.
@@ -11851,11 +11886,11 @@ components:
11851
11886
 
11852
11887
  ResumeStartupCause:
11853
11888
  type: string
11854
- enum: [environment, session_gone, tool_unavailable, configuration, decision_rejected]
11889
+ enum: [environment, session_gone, transcript_corrupt, tool_unavailable, configuration, decision_rejected]
11855
11890
  description: >-
11856
- 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`
11857
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).
11858
- `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 ·
11859
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
11860
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
11861
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).
@@ -13265,7 +13300,11 @@ components:
13265
13300
  🔴 OPEN SET — deliberately NOT an enum: observed values include `human`, `irreversible_ask`,
13266
13301
  `plan_review`, `needs_review`, `resource_limit`, and core keeps adding. Pinning an enum would make a
13267
13302
  new gate kind "not exist" for generated clients.
13268
- 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.
13269
13308
  input:
13270
13309
  description: >
13271
13310
  The pending tool call's args (post-hook), REDACTED + size-bounded — for a tool gate the write
@@ -13975,23 +14014,67 @@ components:
13975
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`).' }
13976
14015
 
13977
14016
  PromptEpoch:
13978
- type: object
13979
14017
  description: >
13980
- A session's prompt-epoch pin (server >=1.220, additive on `GET /v1/sessions/:id`). Identifies WHICH
13981
- assembled system-prompt artifact this session is pinned to, so a transcript stays reproducible across
13982
- prompt-pack releases. IDs/digests only — never prompt text. OPEN object.
13983
- required: [epoch, artifactDigest, packId, assemblyApi, activatedBy]
13984
- 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]
14036
+ properties:
14037
+ kind: { const: pin }
14038
+ descriptor: { $ref: '#/components/schemas/PromptEpochDescriptor' }
14039
+ PromptEpochLegacy:
14040
+ type: object
14041
+ additionalProperties: false
14042
+ required: [kind, centerPinned]
13985
14043
  properties:
13986
- epoch: { type: integer, description: Monotonic epoch counter within the session. }
13987
- artifactDigest: { type: string, description: 'Content digest of the assembled artifact (`sha256:<64 hex>`).' }
13988
- packId: { type: string, description: 'Prompt-pack identity, e.g. `sema-default@1`.' }
13989
- assemblyApi: { type: integer, description: Assembly-contract version (currently always 1). }
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' }
13990
14055
  activatedBy:
13991
14056
  type: string
13992
- description: >
13993
- Open enum — known values `session_start` | `compaction` | `legacy_migration`; treat unknown values as
13994
- 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`).' }
13995
14078
 
13996
14079
  SessionListPage:
13997
14080
  type: object
@@ -14097,14 +14180,45 @@ components:
14097
14180
  # 封闭(census 批2 第三段,2026-07-30):三个铸造臂(`routes/sessions.ts` 的空面板 / 超时 degraded / 正常)键集并集恰是这 3 键;degraded 只在超时臂铸。
14098
14181
  # sdk 9.4.0:第 4 键 `lastLegMcp`(server ≥7.77.0)—— 同一个铸造点上按调用方裁的可选顶层键,不在
14099
14182
  # 面板那张短 TTL 单飞缓存里(缓存键=场景×principal,与会话无关)。
14100
- 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]
14101
14187
  additionalProperties: false
14188
+ oneOf:
14189
+ - required: [servers]
14190
+ not: { required: [scenarioRefusal] }
14191
+ - required: [scenarioRefusal]
14192
+ not: { anyOf: [{ required: [servers] }, { required: [degraded] }] }
14102
14193
  properties:
14103
14194
  asOf: { type: string }
14104
14195
  servers:
14105
14196
  type: array
14106
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.
14107
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.' }
14108
14222
  lastLegMcp:
14109
14223
  type: object
14110
14224
  description: >
@@ -14636,6 +14750,10 @@ components:
14636
14750
  row (`status` / `instanceId`) — zero extra reads — and a cross-principal caller never reaches these codes
14637
14751
  (the owner gate answers `not_found.run`, same code and text as the unknown arm). Both dispositions are the
14638
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`.'
14639
14757
  ErrorResponse:
14640
14758
  type: object
14641
14759
  description: >
@@ -14766,7 +14884,9 @@ components:
14766
14884
  unreadable) / `unreachable` (unreachable / 5xx / timeout / bad body / any status other than 200 / 409 / 400 / 401 / 403 —
14767
14885
  center 404 / 429 / 3xx included). On 400 `request.field_invalid` for a `settings.permissions` bucket (server >= 7.106.0 /
14768
14886
  S-904): `over_cap` (more than `cap` entries; beside `count` + `cap`) / `bad_entry` (a non-string or empty item; beside
14769
- `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.)
14770
14890
  retryAfterSec:
14771
14891
  type: number
14772
14892
  description: >-
@@ -14782,7 +14902,10 @@ components:
14782
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`
14783
14903
  (`blockedBy: "request.field_invalid"`). Also on 409 `checkpoint.config_refused` (server >= 7.113.0): which part of the
14784
14904
  row's configuration was refused — `taskConfig` (change the configuration, then decide the SAME card again) or
14785
- `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
14786
14909
  `settings.hooks` tool-event matcher that selects an engine alias but not its canonical name (server >= 7.115.0 / S-1025):
14787
14910
  `field` is always the literal `settings.hooks` (see `detail`). Also on 400 `request.body_shape` (server >= 7.119.0), on the THREE
14788
14911
  tool-approval decision doors (`POST /v1/tool-approvals/{id}/respond`, `POST /v1/tasks/{taskId}/asks/{askId}/decision`,
@@ -14800,17 +14923,104 @@ components:
14800
14923
  `request.field_invalid` for a `settings.hooks` tool-event matcher (server >= 7.115.0 / S-1025; additive, the sentence and the code
14801
14924
  are unchanged): an OBJECT `{ event, alias, canonical }` — `event` = the tool event of the refused group (the first refused one when
14802
14925
  several are), `alias` / `canonical` = the engine catalog's alias and canonical name (closed strings, never the caller's raw bytes),
14803
- 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):
14804
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
14805
14933
  own `detail`; read it by `errorCode`. SDK: `err.extra.detail` (verbatim, unnamed).
14806
14934
  oneOf:
14807
14935
  - type: object
14808
- 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]
14809
15020
  additionalProperties: false
14810
15021
  properties:
14811
- event: { type: string }
14812
- alias: { type: string }
14813
- canonical: { type: string }
15022
+ path: { type: string }
15023
+ index: { type: integer }
14814
15024
  - type: object
14815
15025
  required: [scenario, source]
14816
15026
  additionalProperties: false
@@ -14820,13 +15030,20 @@ components:
14820
15030
  - type: string
14821
15031
  count:
14822
15032
  type: integer
14823
- 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`.'
14824
15034
  cap:
14825
15035
  type: integer
14826
- 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`.'
14827
15037
  index:
14828
15038
  type: integer
14829
- 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`).
14830
15047
  blockedBy:
14831
15048
  type: string
14832
15049
  description: >-
@@ -14837,11 +15054,19 @@ components:
14837
15054
  `ResumeBlockedByPolicyError.blockedBy` (`undefined` when the key is absent or not a string — never defaulted).
14838
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)
14839
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`).
14840
15061
 
14841
15062
  ResumeLegConflictError:
14842
15063
  description: >
14843
15064
  The 409 body of a RESUME LEG that core refused BEFORE the claim (`POST /v1/approvals/{sessionId}/decide`,
14844
- `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
14845
15070
  not on the shared `ErrorResponse` on purpose (codex r1 [medium], sdk 16.0.0): `ErrorResponse` is the body of every error
14846
15071
  response in this document, and declaring `retriable` there would offer a retry signal on 401 / 404 / 422 / 5xx bodies where the
14847
15072
  server never mints it. (`ErrorResponse` stays open, so a validator cannot REJECT the key elsewhere; the confinement is that only
@@ -14920,6 +15145,8 @@ components:
14920
15145
  - $ref: '#/components/schemas/Event_message_committed'
14921
15146
  # [2373]A-2(2026-08-03,server 5.0.0):compaction_outcome 三腿同源批的 spec 半场(SDK 臂 20867e1 同批)。
14922
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'
14923
15150
  # [2400] ch2(SDK 4.2.0):CB-1 流控帽帧 + TR-7 durable 五臂 —— 两侧同缺,见各 schema 处的注。
14924
15151
  - $ref: '#/components/schemas/Event_error'
14925
15152
  - $ref: '#/components/schemas/Event_question'
@@ -14990,6 +15217,7 @@ components:
14990
15217
  needs_review: '#/components/schemas/Event_needs_review'
14991
15218
  message_committed: '#/components/schemas/Event_message_committed'
14992
15219
  compaction_outcome: '#/components/schemas/Event_compaction_outcome'
15220
+ compaction_started: '#/components/schemas/Event_compaction_started'
14993
15221
  error: '#/components/schemas/Event_error'
14994
15222
  question: '#/components/schemas/Event_question'
14995
15223
  question_complete: '#/components/schemas/Event_question_complete'
@@ -15936,6 +16164,9 @@ components:
15936
16164
  summaryMs: { type: integer }
15937
16165
  persistMs: { type: integer }
15938
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.'
15939
16170
  Event_suggestions:
15940
16171
  type: object
15941
16172
  description: >
@@ -15969,7 +16200,7 @@ components:
15969
16200
  type: { const: status }
15970
16201
  # 🔴 A-057.27:6 员(此前只列 4,漏 recovered/gave_up 两个**终局**值 —— 一段重试序列恒恰一终局帧,
15971
16202
  # 两者对渲染方是同一句话「把重试行撤下来」)。闭集声明、开集读。
15972
- 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)" }
15973
16204
  detail: { type: string, description: "neutral human hint (NO provider/HTTP detail)" }
15974
16205
  retryInSec: { type: number }
15975
16206
  # 🔴 A-057.26:以下四键 server 真在发(builder brainStatusEventData,三腿共享),而本 schema 是
@@ -15978,7 +16209,7 @@ components:
15978
16209
  attempt: { type: number, description: "1-based index of the attempt that just FAILED (this wait precedes attempt+1)" }
15979
16210
  maxRetries: { type: number, description: "retry budget of the lane in force (refused-connect short lane = 2)" }
15980
16211
  retryInMs: { type: number, description: "same number as retryInSec at ms precision (countdown rendering)" }
15981
- 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" }
15982
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`." }
15983
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." }
15984
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." }
@@ -16101,9 +16332,12 @@ components:
16101
16332
  `message_committed` + stream order). Live emissions PRECEDE the commit and omit `entryId`.
16102
16333
  SERVICE PROJECTION: core's `principal` is deliberately NOT forwarded (the stream is already owner-scoped —
16103
16334
  the frame does not restate the tenant). `issuer` / `actor.id` / `actor.issuer` are host-derived identity
16104
- strings and arrive SECRET-REDACTED. Server >= 7.127.0 does NOT project core 7.50.0's `attachments` member (always absent here)
16105
- and does not accept the engine's request-layer `userAttachments` key: a submit / resume body carrying it is 400
16106
- `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.)
16107
16341
  allOf: [{ $ref: '#/components/schemas/EventIdentity' }]
16108
16342
  additionalProperties: false # 封闭 + identity 本地镜像:见 Event_reasoning 处的长注
16109
16343
  required: [type, inputId]
@@ -16134,6 +16368,23 @@ components:
16134
16368
  hostAsserted: { type: boolean }
16135
16369
  issuer: { type: string }
16136
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 }
16137
16388
  eventId: { type: string }
16138
16389
  parentToolCallId: { type: string }
16139
16390
  sourceTaskId: { type: string }
@@ -16313,19 +16564,22 @@ components:
16313
16564
  already owns the single redaction mint point for it). The actionable cause is `errorCode`.
16314
16565
  A row missing `name` or `status` is dropped individually — the other servers'' rows still ship.
16315
16566
  items: { $ref: '#/components/schemas/WiringManifestMcpEntry' }
16316
- hooks:
16567
+ mods:
16317
16568
  type: array
16318
16569
  description: >
16319
- core 7.18.0 (#789), server >= 7.78.0 — TENANT-visible: the hook seats THIS leg wired, one row per
16320
- family, in core's declaration order. EFFECTIVE half only.
16321
- 🔴 PRESENT IFF at least one seat is wired — core NEVER emits an empty array, so "the key is here"
16322
- means non-empty. 🔴 ABSENCE READS "this leg wired no hook RECORD of its own", NOT "no hook runs":
16323
- a delegated child with no local record can still be screened (and refused) by an ANCESTOR's
16324
- `preToolUse` through the gate's constraint fold, which this face deliberately does not call a hook
16325
- of this leg. A row missing `family` or `owner` is dropped INDIVIDUALLY (same rule as `mcp[]`); all
16326
- rows dropped => the key is absent. 🔴 EXCLUDED from `configFingerprint` (the record is a per-task
16327
- seat), so two legs with the same fingerprint and different `hooks[]` are NOT in contradiction.
16328
- 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' }
16329
16583
  lsp:
16330
16584
  allOf: [{ $ref: '#/components/schemas/WiringManifestLspSeam' }]
16331
16585
  description: >
@@ -16722,6 +16976,26 @@ components:
16722
16976
  was armed but declined/failed (check the store, check authorisation), `false` = there was no lane at all
16723
16977
  (wire one up). The two recovery verbs differ, so a consumer MUST render them apart — NEVER fold them into
16724
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.
16725
16999
  `server.model_unreachable` (server-minted, audience `user`; server >= 7.108.0, `taskId` added in server 7.121.0) — a model call on
16726
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
16727
17001
  gateway is gone) — not the provider's answer. `{ code, targetHost, proxyInUse?, remedy, sessionId, taskId? }`: `code` one of the
@@ -16963,56 +17237,78 @@ components:
16963
17237
  一律按不可分辨处理,消费方不要猜。
16964
17238
 
16965
17239
  PromptManifest:
16966
- # 新增(2026-07-25 回填批):server ≥1.219 的 prompt-assembly manifest。此前本文件完全没有它(全文 0 次提及),
16967
- # 尽管它同时是 `AgentEvent.prompt_assembled` 臂和 trace 流 `prompt-assembled` 帧的载荷。
16968
17240
  type: object
16969
17241
  description: >
16970
- The prompt-assembly manifest (core's `prompt.assembled` trace contract verbatim). Carries ONLY
16971
- ids/digests/counts — NEVER prompt bodies (privacy boundary). 🔴 Hashes are PROCESS-SALTED: they are NOT
16972
- comparable across worker restarts, so a UI must never diff them cross-process. `constitution`/`blocks`/
16973
- `totalChars` are the v1 face; `sections`/`tools` are the v2 ADDITIVE face (absent on a v1-only engine).
16974
- ⚠️ One task can carry MULTIPLE manifests — a cascade/verify run re-prepares under one taskId and every
16975
- rung's manifest is persisted in emission order.
16976
- 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 因此恰中一臂。
16977
17259
  additionalProperties: true
17260
+ not: { required: [constitution] }
16978
17261
  properties:
16979
- constitution:
16980
- type: string
16981
- description: 'who owned the constitution layer — `core` is the steady state; anything else is worth eyes.'
16982
- enum: [core, replaced, provider-assembled, legacy]
16983
- 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 } }
16984
17279
  blocks:
16985
17280
  type: array
16986
17281
  items:
16987
17282
  type: object
17283
+ additionalProperties: false
16988
17284
  required: [id, chars, hash]
16989
- additionalProperties: true
16990
17285
  properties:
16991
17286
  id: { type: string }
16992
17287
  chars: { type: integer }
16993
- hash: { type: string, description: 'process-salted digest — never compare across restarts.' }
17288
+ hash: { type: string, description: 'process-salted short digest — never compare across restarts.' }
16994
17289
  sections:
16995
17290
  type: array
16996
- 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.'
16997
17295
  items:
16998
17296
  type: object
16999
- required: [id, slot, carrier, cadence, cacheClass, chars, hash]
17000
- additionalProperties: true
17297
+ additionalProperties: false
17298
+ required: [id, source, by, target, supersededBy]
17001
17299
  properties:
17002
17300
  id: { type: string }
17003
- slot: { type: string }
17004
- carrier: { type: string }
17005
- cadence: { type: string }
17006
- cacheClass: { type: string }
17007
- chars: { type: integer }
17008
- 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)`.' }
17009
17305
  tools:
17010
17306
  type: array
17011
- 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).'
17012
17308
  items:
17013
17309
  type: object
17310
+ additionalProperties: false
17014
17311
  required: [wireName, aliases, contractId, implementationRevision, cardId, shapeDigest, wireSchemaDigest]
17015
- additionalProperties: true
17016
17312
  properties:
17017
17313
  wireName: { type: string }
17018
17314
  aliases: { type: array, items: { type: string } }
@@ -17021,7 +17317,72 @@ components:
17021
17317
  cardId: { type: string }
17022
17318
  shapeDigest: { type: string }
17023
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.' }
17024
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'
17025
17386
 
17026
17387
  Event_file_link:
17027
17388
  type: object
@@ -17053,7 +17414,7 @@ components:
17053
17414
  manifest's own keys sit at the top level next to `type`, they are NOT nested under a `manifest` key).
17054
17415
  Lands AHEAD of the first event of the turn it prepared. ⚠️ MULTIPLE per task on cascade/verify runs.
17055
17416
  allOf:
17056
- - $ref: '#/components/schemas/PromptManifest'
17417
+ - $ref: '#/components/schemas/PromptManifestRow'
17057
17418
  required: [type]
17058
17419
  properties:
17059
17420
  type: { const: prompt_assembled }
@@ -17304,15 +17665,16 @@ components:
17304
17665
  (no alias): the allow-layer members that MATCHED this call and could NOT clear this ask, one `{ member, entries, omitted? }` record per
17305
17666
  matching member (see AllowRuleShadow). `member` is one of `hook` / `deployment` / `persisted` / `skill` / `request`; `entries` are the
17306
17667
  entries that member matched, as their source spells them (UNTRUSTED for display like `message`, secret-redacted, <= 512 chars each,
17307
- <= 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.
17308
17670
 
17309
17671
  The explaining sentence ("... matches this call but does not clear the ask — <reason>") is IN `message` (the engine writes it where it builds
17310
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
17311
17673
  time"): without it the only conclusion a user can draw is "my rule broke".
17312
17674
 
17313
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.
17314
- 🔴 `member: "hook"` does not say whose hook (a deployment PreToolUse hook and, on the single-user lane, the request's own `settings.hooks`
17315
- 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
17316
17678
  rule"). What the allow layer can NOT clear: any layer's deny / ask rule, operator `APPROVAL_REQUIRE` / `APPROVAL_NEVER_AUTO` /
17317
17679
  `MANUAL_MODE_SHELL_GATE=always`, write protection, sensitive-path writes, governance, a hook's ask, plan-mode asks. The durable dual is
17318
17680
  `gate.riskDescriptor.allowRuleShadowed` on the parked row (PendingCheckpoint.riskDescriptor). Rolling-upgrade caveat: a card stored by a
@@ -17756,7 +18118,7 @@ components:
17756
18118
  items: { $ref: '#/components/schemas/AllowRuleShadow' }
17757
18119
  description: >
17758
18120
  ADDITIVE (server >= 7.117.0 / core 7.42.0, BREAKING RENAME of the retired `persistedRuleShadowed`): the allow-layer members that matched this
17759
- 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`,
17760
18122
  the ABSENT != "you have no rule" clause and the separation from `governanceForced` are stated verbatim on ToolApprovalFrame.allowRuleShadowed
17761
18123
  — the live frame, the stored `card_json`, the replayed frame and the `approval_request` card carry the SAME material.
17762
18124
  fromSubagent: { type: boolean, enum: [true], description: 'Present ⇔ the ask comes from a DELEGATED child — the explicit discriminator (a worker cannot forge it).' }
@@ -19067,6 +19429,31 @@ components:
19067
19429
  outcome: { type: string }
19068
19430
  trigger: { type: string, description: 'engine-shaped; current emitters send auto | manual | forced' }
19069
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.' }
19070
19457
  eventId: { type: string }
19071
19458
  parentToolCallId: { type: string }
19072
19459
  Event_config_assembled:
@@ -19874,7 +20261,7 @@ components:
19874
20261
  description: >
19875
20262
  🔴 ONE RULE FOR EVERY "EFFECTIVE HALF ONLY" KEY (sdk 9.7.0, after a codex adversarial-review [high]):
19876
20263
  this schema's only consumer today is `GET /v1/diagnostics/wiring`'s `static` half, and every key marked
19877
- "effective half only" (`leg`, `ask.effective`, `configFingerprint`, `tools`, `hooks`, `lsp`,
20264
+ "effective half only" (`leg`, `ask.effective`, `configFingerprint`, `tools`, `mods`, `lsp`,
19878
20265
  `modelGate`, `autoMode`, `writeProtection`, `readDeny`, `autoConsolidation`, `fileHistory`, `instructions`) is ALWAYS ABSENT on that
19879
20266
  wire ⇒ THEIR ABSENCE HERE CARRIES NO INFORMATION. The per-key absence readings ("absent = not armed",
19880
20267
  "absent = a third state", …) hold for the LIVE FRAME (`Event_wiring_manifest`) and must not be carried
@@ -20020,14 +20407,12 @@ components:
20020
20407
  properties:
20021
20408
  armed: { type: boolean }
20022
20409
  reason: { type: string }
20023
- hooks:
20410
+ mods:
20024
20411
  type: array
20025
20412
  description: >
20026
- core 7.18.0 (#789), server >= 7.78.0 — the hook seats THIS leg wired, one row per family.
20027
- EFFECTIVE half only (the diagnostics endpoint's static half never carries it). Present iff at least
20028
- one seat is wired; absence means "no hook RECORD of this leg", never "no hook runs".
20029
- Full per-key contract: see Event_wiring_manifest.hooks.
20030
- 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' }
20031
20416
  lsp:
20032
20417
  allOf: [{ $ref: '#/components/schemas/WiringManifestLspSeam' }]
20033
20418
  description: >
@@ -20136,33 +20521,52 @@ components:
20136
20521
  type: array
20137
20522
  description: 'The selected chain member(s), spelled as the chain spells them (relative to the cwd); `[]` = the chain was walked, nothing was selected.'
20138
20523
  items: { type: string, enum: ['CLAUDE.md', '.claude/CLAUDE.md', 'AGENTS.md', '.claude/AGENTS.md'] }
20139
- WiringManifestHookEntry:
20140
- # sdk 9.5.0:与 `WiringManifestMcpEntry` 同一条裁定 —— 同一份行形被 live 帧与静态诊断面两处引用,
20141
- # 内联就是两份会各自漂的镜像,所以一开始就具名。
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:
20142
20533
  type: object
20143
20534
  description: >
20144
- One row of a leg's HOOK seat manifest (core 7.18.0 #789): which family, where the seat came from, and
20145
- 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").
20146
20537
  additionalProperties: false
20147
- required: [family, owner]
20538
+ required: [name, seat, tier, events]
20148
20539
  properties:
20149
- family:
20150
- type: string
20151
- description: >
20152
- The hook family. core's closed vocabulary today (`preToolUse` / `postToolUse` / `userPromptSubmit` /
20153
- `stop` / `postToolUseFailure` / `postToolBatch` / `preCompact` / `postCompact` / `stopFailure` /
20154
- `permissionDenied`) but READ AS OPEN: the server passes it through verbatim and does not enumerate,
20155
- so a newly minted family must pass through your default arm.
20156
- owner:
20157
- type: string
20158
- description: "Where the seat came from — core's `SeamProvenance` (`spec` / `deps`). Closed today, read as open."
20159
- observational:
20160
- type: boolean
20161
- enum: [true]
20162
- description: >
20163
- Only on the `preToolUse` row, and only when the deployment DECLARED the face observational: it still
20164
- runs on every call but is not folded into a delegated child's inherited constraints.
20165
- 🔴 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).' }
20166
20570
  WiringManifestLspSeam:
20167
20571
  # sdk 9.5.0:同上 —— live 帧与静态面共用一份段形。
20168
20572
  type: object
@@ -20339,7 +20743,9 @@ components:
20339
20743
  description: >
20340
20744
  server >= 7.60 (S-131) — this deployment's SQL engine posture (engine / version / session isolation
20341
20745
  level / TiDB transaction mode), READ BACK off a live connection rather than echoed from env.
20342
- `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.
20343
20749
  configApply:
20344
20750
  type: ["object", "null"]
20345
20751
  additionalProperties: true