This repository was archived by the owner on Oct 26, 2026. It is now read-only.
Repository navigation
Commit b46c58f
fix(types,plugin-chatbot): the authoring tool-invocation state union sheds the three runtime-only approval states (objectui#10018) (#10308)
Fixes #10018
Clause-②: no
This executes the residual clause of the objectui#8426 ruling (director
seat, decision batch #86, maintainer 「继续决策」), verbatim: 「the authoring
`state` union sheds the three runtime-only approval states, so a
schema-authored invocation cannot claim `approval-requested` without an
envelope」. The shape follows the seat's round-2 answers on the card
(comment `5817891136`): the fence against objectui#10273 is cleared for
the chat-invocation hunks, the file surface is widened, `onSend` uses
design B, and the envelope's enforcement is left to its own card.
## What changed
- **`@object-ui/types`.** `ChatToolInvocation.state` and its Zod mirror
`ChatToolInvocationSchema` drop `approval-requested`,
`approval-responded` and `output-denied`. An authored claim of one is
refused, with or without an `approval` envelope. The mirror refuses it
as one `invalid_value` at `state`.
- **The `onSend` slot (design B, zero new exports).**
`ChatbotSchema.onSend` hands a host the thread the runtime holds, and in
API mode that thread carries the three states. Its `messages` is
therefore typed as the authoring message widened by exactly those
states. Two NON-exported aliases in `complex.ts` do this:
`ChatToolRuntimeOnlyState` and `ChatMessageHandedBack`. The built
`complex.d.ts` emits both without `export`, and no barrel changes.
- **The seam, derived rather than copied (`chatMessageAdapter.ts`).**
`SeamToolInvocation.state` is the union of the authoring state and
`ChatbotEnhanced`'s runtime state. `toRuntimeToolState` takes that
union. The accepted set of values is unchanged, so existing callers
still compile.
- **`useObjectChat.ts`.** `initialMessages` is now the seam's input
shape, because app-shell hands it runtime values restored from server
history. The parts builder's un-backed-approval branch and its tests are
KEPT. A runtime producer still constructs an envelope-less
`approval-requested`: app-shell's `mergeToolResultsInto` promotes it
from a pending-action result, and `hydratedMessagesToChatMessages` hands
it to the builder. Its docblock now says this instead of predicting its
own removal.
- **One vocabulary across two packages.**
`chat-message-contract.test.ts` derives the types-side alias through
`ChatbotSchema['onSend']` and pins it EQUAL to `ChatbotEnhanced`'s
runtime-only states. It also pins the set to the SDK's approval triple,
pins the authoring union to hold none of them, and pins
`ObjectChatMessage` as assignable to the slot. The old
`_StillAnAuthoredMessage` pin asserted the subtype relation this change
removes, so it is inverted to `_NoLongerAnAuthoredMessage`.
- **Docblocks and published docs made true.** The envelope sentence
「Optional because the other seven states never carry one」 is replaced by
what holds after the shed: no authorable state requires the envelope;
the SDK admits an approved envelope on `output-available` and
`output-error` only; the three states that require one are not
authorable. The subtype promise is corrected in `ChatbotSchema.onSend`,
`ObjectChatMessage`, `UseObjectChatOptions.onSend`,
`packages/plugin-chatbot/src/renderer.tsx`'s header comment (comment
only, `3ce44937`), the plugin-chatbot README and
`content/docs/plugins/plugin-chatbot.mdx`.
- **Fixture triage (`chat-tool-approval-envelope-8442.test.ts`).**
`invocation()` now defaults to `output-available`. The id-judgment case
asserts its refusal AT `approval.id`: before this change it would have
kept passing on the state's refusal alone, a phantom check. The old 「is
OPTIONAL」 case becomes the refusal pin for the three states, envelope or
not.
## Changeset: `minor` with a BREAKING banner (版本号策略; `major` is banned)
- **Break 1.** Authored approval states are refused, at TS and at parse,
in `ChatbotSchema.messages` and anywhere else `ChatToolInvocation` is
authored.
- **Break 2.** An `onSend` handler typed against the authoring
`ChatMessage[]` stops type-checking, because the messages it receives
are no longer a subtype of that shape.
- **Declared, not newly accepted.**
`UseObjectChatOptions.initialMessages` now takes `SeamChatMessage`, so
nine optional runtime-only keys are declared on that option:
`buildProgress`, `blueprintProgress`, `charts`; `pendingActionId`,
`draftReview`, `proposedPlan`, `proposedChanges`, `builderHandoff`,
`replayOutcome`. The runtime is unchanged. Local mode keeps the six
tool-invocation keys (`normalizeMessages` forwards `toolInvocations`
whole) and drops the three message-level ones. API mode's
`aiInitialMessages` carries none of the nine into SDK parts.
- **Sibling pending changesets made true (`04ed6186`, prose only,
frontmatter byte-identical).** This change makes two other cards'
pending entries false in the same release, so they are corrected here
(the objectui#10019 precedent). In
`.changeset/8442-chat-tool-approval-envelope.md`, the 「ten declared
`state` values」 sentence and the closing no-narrowing paragraph are
corrected. In `.changeset/6169-chatbot-authoring-face-type.md`, the
`onSend` bullet is corrected.
- **Not measured.** Out-of-repo authors and hosts. In-repo, the
type-check of types, plugin-chatbot and app-shell below is the reading.
## Evidence
All readings are from the committed state. Code head: `3aa259d8`, which
merges `origin/main` at `8b1f0661`. The later commits change no
executable byte:
- **Round 3** (`3ce44937`, comments and changeset prose): plugin-chatbot
type-check exits 0. `check-changeset-presence`,
`check:changeset-claims`, `check:control-bytes` and
`check:new-line-citations` exit 0.
- **Round 4** (`04ed6186`, the two sibling changesets, prose only): the
same gates plus `check:pending-changeset-literals` exit 0, and
`check-changeset-overwrite` reads declared = declares for both.
- **Round 5** (`340efe60`, one changeset sentence): the Not-breaking
paragraph no longer claims the hook forwarded the nine keys; it states
what each builder does. The same gates exit 0.
The contract review of `3aa259d8..04ed618` found one false sentence,
and round 5 fixes it.
**Pins, red first on base `5ea623ea`, before any source edit:**
- `tsc -p tsconfig.test.json` on types exits 2 with exactly 7x TS2578
(unused `@ts-expect-error`). They sit on the six invocation literals
(each state, bare and enveloped) and the authored-message literal. No
control line errs.
- `vitest` on the new file reads `Tests 9 failed | 4 passed (13)`: the 9
refusals fail and the 4 controls pass.
**After the fix, at `3aa259d8`:**
- `type-check` (main + test programs, plus examples for types) exits 0
for `@object-ui/types`, `@object-ui/plugin-chatbot` and
`@object-ui/app-shell`. The new file's membership in the types test
program is shown by the red run above.
- From the repo root, `vitest run packages/types/
packages/plugin-chatbot/` reads `Test Files 263 passed (263)`, `Tests
5468 passed (5468)`.
- A verbose run of the touched files plus the app-shell hydration and
approval-rehydration suites reads `7 passed (7)`, `72 passed (72)`, and
lists each new case by name.
**Ablation 1: `approval-requested` re-added to the authoring union and
its mirror.**
- Setup: from the committed fix, through `ablation-replace.mjs` with
anchors hit x1; blobs `c7c58748` to `ff55f890` and `a1f3bd36` to
`39bdaf7d`. types was rebuilt, and the dist markers read 1
(`complex.d.ts` union member, `zod/complex.zod.js`).
- Prediction: the three `approval-requested` refusal pins red, the other
states' pins and every control green, `_IsTheApprovalTriple` red.
- Measured: types test program exits 2 with exactly 3x TS2578, all on
the `approval-requested` literals. vitest reads `4 failed | 15 passed
(19)`: the three `approval-requested` refusals plus the 8442 refusal
case, with all controls passing. plugin-chatbot main exits 0, and its
test program exits 2 with 1 error, `_IsTheApprovalTriple`.
- Restore: both blobs equal HEAD, `git diff HEAD` is empty, types was
rebuilt, and the dist markers read 0.
**Ablation 2: `output-denied` removed from the non-exported alias.**
This proves the Equal pin can fail.
- Measured: `_OneVocabulary`, `_IsWhatOnSendHandsBack` and
`_HandedBackIsAuthoringPlusTriple` go red, and so do renderer.tsx's
three `onSend: schema.onSend` forwards (main program TS2322).
- Restore: blob equals HEAD, types was rebuilt, and the dist marker
reads 0.
**Gates at `3aa259d8`, each exit 0:**
- `check:control-bytes` and `check:new-line-citations`.
- `node scripts/check-changeset-presence.mjs` and `changeset:check`
(fixed group, no-major).
- `check:changeset-claims` and `check:pending-changeset-literals`.
- Docs: `check:doc-types`, `check:doc-snippets` (672 of 672 blocks
judged), `check:doc-examples`, `check:doc-fences`,
`check:doc-example-ids`, `check:doc-example-readers`, `docs:check-links`
and `check:readme-exports`. The first runs of doc-snippets, doc-examples
and readme-exports read PRECONDITION NOT MET (unbuilt packages); they
are green after the scoped build each gate prints.
- `check:handler-key-reads`, `check:component-surface-parity` and
`check:test-path-roots`.
- `check-governed-queue-guard --test` reads NOT GOVERNED.
- `eslint --no-inline-config --format json` on the 7 changed TS files: 7
files, 0 errors, 20 warnings, 0 of them on an added line. The 20 are
pre-existing `no-explicit-any` and `react-hooks` warnings.
**NOT MEASURED:**
- Repo-wide `pnpm lint`, the full `pnpm test`, and CI convergence (left
to the seat per standing rules).
- Type-check of `apps/console`, `apps/site`, `examples/console-starter`
and `examples/schema-catalog`.
- Out-of-repo consumers.
## Overlap with objectui#10273 (per the seat's fence answer A)
This PR and objectui#10273 both edit `packages/types/src/complex.ts` and
`zod/complex.zod.ts`, and the hunks do not overlap:
- **This PR:** `ChatToolInvocation`, the two new non-exported aliases
after it and `ChatbotSchema.onSend` in `complex.ts`;
`ChatToolInvocationSchema` in `complex.zod.ts`. It does not edit
`zod-mirror-parity.test.ts`, because that pin's type equality moves with
both sides.
- **objectui#10273:** the import block and the Dashboard/Page twins in
`complex.ts`; `GlobalFilterSchema` in `complex.zod.ts`; the parity
census EXCLUSIONS.
Whichever lands second merges `origin/main`; the union of both is the
resolution.
## Acceptance notes
- The authoring `approval` envelope now has no authorable state whose
builder arm reads it. The seat is filing its enforcement as its own
card; this PR only makes its docblock true.
- `renderer.tsx`'s header comment made the same subtype promise. It is
retracted in `3ce44937` (comment only). The seat widened the claim
surface to that file.
- The warning text `warnApprovalStateWithoutEnvelope` prints ("not
representable as authored") was left unchanged to avoid churning the
tests that pin it. The docblock above it is what was rewritten.
The seat's session is
`https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC`. This PR was
implemented by a dispatched `os-dev` run in that session (seat
`domain:ui#1`, claim `5817363473`).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 92e6942 commit b46c58f
13 files changed
Lines changed: 456 additions & 93 deletions
File tree
- .changeset
- content/docs/plugins
- packages
- plugin-chatbot
- src
- __tests__
- types/src
- __tests__
- zod
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
22 | | - | |
23 | | - | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
12 | | - | |
13 | | - | |
14 | | - | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
51 | | - | |
52 | | - | |
53 | | - | |
54 | | - | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
714 | 714 | | |
715 | 715 | | |
716 | 716 | | |
717 | | - | |
718 | | - | |
719 | | - | |
720 | | - | |
721 | | - | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
| 720 | + | |
| 721 | + | |
| 722 | + | |
| 723 | + | |
| 724 | + | |
| 725 | + | |
722 | 726 | | |
723 | 727 | | |
724 | 728 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
130 | 130 | | |
131 | 131 | | |
132 | 132 | | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
133 | 136 | | |
134 | 137 | | |
135 | 138 | | |
136 | 139 | | |
137 | 140 | | |
138 | | - | |
139 | | - | |
140 | | - | |
141 | | - | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
142 | 147 | | |
143 | 148 | | |
144 | 149 | | |
| |||
332 | 337 | | |
333 | 338 | | |
334 | 339 | | |
335 | | - | |
| 340 | + | |
336 | 341 | | |
337 | 342 | | |
338 | 343 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | | - | |
| 44 | + | |
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
68 | 75 | | |
69 | 76 | | |
70 | 77 | | |
| |||
285 | 292 | | |
286 | 293 | | |
287 | 294 | | |
288 | | - | |
289 | | - | |
290 | | - | |
291 | | - | |
292 | | - | |
293 | | - | |
294 | | - | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
295 | 311 | | |
296 | 312 | | |
297 | 313 | | |
| |||
314 | 330 | | |
315 | 331 | | |
316 | 332 | | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
317 | 379 | | |
318 | 380 | | |
319 | 381 | | |
| |||
0 commit comments