Skip to content

Migrate to Tailwind CSS v4 PostCSS architecture - #86

Closed
hotlong with Copilot wants to merge 4 commits into
dependabot/npm_and_yarn/tailwindcss-4.1.18from
copilot/fix-action-run-issue-again
Closed

hotlong with Copilot wants to merge 4 commits into
dependabot/npm_and_yarn/tailwindcss-4.1.18from
copilot/fix-action-run-issue-again

Conversation

Copilot AI commented Jan 15, 2026 •

Copy link
Copy Markdown
Contributor

Tailwind CSS v4 moved the PostCSS plugin to a separate package @tailwindcss/postcss. The build was failing with:

[postcss] It looks like you're trying to use `tailwindcss` directly as a PostCSS plugin.
The PostCSS plugin has moved to a separate package

Changes

PostCSS Configuration

  • Install @tailwindcss/postcss package across workspace
  • Update postcss.config.js files to reference @tailwindcss/postcss instead of tailwindcss

CSS Syntax Migration

  • Replace @tailwind directives with @import "tailwindcss" (v4 syntax)
  • Replace @apply border-border with border-color: hsl(var(--border)) where @apply references custom theme values
  • Maintain existing CSS custom properties for theming

Example:

- @tailwind base;
- @tailwind components;
- @tailwind utilities;
+ @import "tailwindcss";

  @layer base {
    * {
-     @apply border-border;
+     border-color: hsl(var(--border));
    }
  }

Package Dependencies

  • Update peerDependencies to support both v3 and v4: "tailwindcss": "^3.0.0 || ^4.0.0"
Original prompt

引用: https://github.com/objectstack-ai/objectui/actions/runs/21031227714/job/60467556908#step:6:1


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

dependabot Bot and others added 2 commits January 15, 2026 12:25
Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) from 3.4.19 to 4.1.18.
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.1.18/packages/tailwindcss)

---
updated-dependencies:
- dependency-name: tailwindcss
  dependency-version: 4.1.18
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
- Install @tailwindcss/postcss package
- Update PostCSS configs to use @tailwindcss/postcss
- Update CSS files to use Tailwind v4 syntax (@import "tailwindcss")
- Replace @apply directives with direct CSS properties
- Add @theme directive for custom colors
- Update peerDependencies to support Tailwind v4

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Based on code review feedback, removed the @theme directive since
the theme is already configured via tailwind.config.js and CSS
custom properties. This avoids duplication and potential inconsistencies.

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
@dependabot
dependabot Bot force-pushed the dependabot/npm_and_yarn/tailwindcss-4.1.18 branch from 3b389ba to 50038f0 Compare January 15, 2026 13:13
@hotlong
hotlong marked this pull request as ready for review January 15, 2026 13:13
@github-actions

Copy link
Copy Markdown
Contributor

✅ All checks passed!

  • ✅ Type check passed
  • ✅ Tests passed
  • ✅ Lint check completed

Copilot AI changed the title [WIP] Fix action run issue in ObjectUI Migrate to Tailwind CSS v4 PostCSS architecture Jan 15, 2026
Copilot AI requested a review from hotlong January 15, 2026 13:22
@dependabot
dependabot Bot force-pushed the dependabot/npm_and_yarn/tailwindcss-4.1.18 branch 4 times, most recently from a65f8de to 2fc59a2 Compare January 19, 2026 08:20
@hotlong hotlong closed this Jan 19, 2026
os-tesla pushed a commit that referenced this pull request Sep 19, 2026
…nd delete the last cast on useChat

`useObjectChat`'s API-mode builder declared its part array as
`Array<Record<string, unknown>>` and pushed plain objects into it. That is not
the chat runtime's part union, and the mismatch was absorbed by an `as any` on
the `messages` option instead of being reported. Re-measured 2x2 on this branch,
each leg mutated on disk with hash proof and restored by state: only the
both-casts-removed leg is red, with one TS2322 in each of the two type-check
programs.

The builder now CONSTRUCTS each part, so the option is checked and the cast is
gone. Per the ruling on this chain (director seat, decision batch #86,
2026-09-08, option A, contract-first) the fix lands at the producer, never as a
wider cast at the consumer.

- The three approval states are reachable: they require the runtime's
  `approval` envelope alongside them, `ChatToolInvocation` gained it in the
  first clause of this chain, and the builder now constructs those arms from it.
- The legacy authoring states `partial-call` / `call` / `result` are folded onto
  the lifecycle arms they mean instead of passing through as states the
  round-trip reader refuses.
- The dead `toolName` member is no longer written onto a `tool-*` part: only the
  dynamic-tool arm declares one, and the reader derives the name off `type`.
- `UseObjectChatOptions.initialMessages`' optional `parts` narrows to the store's
  own part array. Breaking for an external host that passes pre-built parts;
  nothing in this repo sets it.

An invocation claiming an approval state with no envelope to back it is not
constructible, and no envelope is invented for it: the state is derived from the
data it does carry and the producer is told once. An ObjectStack HITL approval
is deliberately not reported, since it is carried by `pendingActionId` and the
mapper re-promotes the state from the tool result.

Also lifts the `approval` envelope in the mapper's tool-invocation extraction,
closing the disagreement where the hydrated path carried the envelope and the
live path dropped it. The lift lands in the same round as its first reader.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq
os-bill pushed a commit that referenced this pull request Sep 24, 2026
…sheds the three runtime-only approval states

The residual clause of the objectui#8426 ruling (decision batch #86):
`approval-requested`, `approval-responded` and `output-denied` leave the
authoring `ChatToolInvocation.state` union and its Zod mirror, so a
schema-authored invocation cannot claim an approval state, with or without an
`approval` envelope.

The authoring type also served as the base of the chat runtime's seam, so the
split is derived rather than copied: `SeamToolInvocation.state` is the union of
the authoring and runtime vocabularies, `useObjectChat`'s `initialMessages` is
the seam's input shape (app-shell hands it runtime values), and
`ChatbotSchema.onSend` hands back the authoring message widened by exactly the
three states, named by a non-exported alias. A compile-time Equal pin ties that
alias to `ChatbotEnhanced`'s runtime union. No export is added.

The un-backed-approval branch in the parts builder is kept: a runtime producer
(app-shell's `mergeToolResultsInto`) still constructs an envelope-less
`approval-requested`. Its docblock now says so.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Sep 28, 2026
…nd delete the last cast on useChat (objectui#8426) (objectstack-ai#10017)

Fixes objectstack-ai#8426

The API-mode parts builder in `useObjectChat` declared its part array as
`Array(Record(string, unknown))` and pushed plain objects into it. That
is not the chat runtime's part union, and the mismatch was absorbed by
an `as any` on the `messages` option rather than reported. This makes
the builder **construct** the discriminated parts, so the option is
checked and the cast is gone.

Ruling carried in, not re-decided: director seat, decision batch objectstack-ai#86,
2026-09-08, **option A — contract-first**. Its first clause landed as
objectui#9229; this is the remaining one. The three shortcuts the
dispatch forbids by name (widen the declared type to `any`; keep the
cast with a comment; re-litigate A) are all absent.

## The 2x2, re-run on this branch before repairing

Each leg mutated on disk through an anchor that must hit, with blob-hash
proof, and restored by state (`git diff HEAD` empty after every leg).
Two type-check programs per leg: `tsc --noEmit` and `tsc -p
tsconfig.test.json`.

| outer `} as any)` | nested `(aiInitialMessages as any)` | main | test
|
|:--|:--|:--|:--|
| present | present | exit 0 | exit 0 |
| absent (today's `main`, PR objectstack-ai#8401) | present | exit 0 | exit 0 |
| present | removed | exit 0 | exit 0 |
| **absent** | **removed** | **exit 2**, 1x TS2322 | **exit 2**, 1x
TS2322 |

All four legs reproduce the card's table. The red leg's diagnostic,
verbatim:

```
error TS2322: Type '{ id: string; role: "user" | "assistant" | "system"; parts: Record(string, unknown)[]; }[] | undefined'
  is not assignable to type 'UIMessage(unknown, UIDataTypes, UITools)[] | undefined'
  ...  Type 'Record(string, unknown)' is not assignable to type 'UIMessagePart(UIDataTypes, UITools)'
```

(angle brackets transliterated to round ones above so the body survives
sanitizing.)

⚠️ **One thing did not survive, and it is a method note rather than a
finding about the card.** The first attempt at the two nested-cast legs
was a NO-OP: the mutation tool refused the write because the replacement
text was a substring of the anchor, so its rise-count check could not
distinguish the two. The file was restored and both legs then ran
against a **pristine** tree — reading exit 0, i.e. a false green
pointing the wrong way. They were re-run with a distinguishable
replacement, and the table above is the re-run. Recorded because a
silently-reverted ablation reads exactly like a passing one.

## After: both casts gone, both programs green

```
pnpm --filter @object-ui/plugin-chatbot type-check    -> exit 0   (tsc --noEmit && tsc -p tsconfig.test.json)
pnpm exec vitest run packages/plugin-chatbot/         -> exit 0   47 files, 522 tests passed
```

Program membership proved with a lit control rather than assumed — main
program 1626 files: `src/useObjectChat.ts` 1, `src/mapMessages.ts`
(positive control) 1, `useObjectChat.honestMessages.test.tsx` (negative
control) 0, and the same negative pattern returns 1 against the test
program's file list.

Dependents, on a freshly built union closure (`Scope: 36 of 47` built,
then `Scope: 7 of 47` type-checked): all seven pass, zero `error TS` —
`plugin-chatbot`, `app-shell`, `console`, `site`,
`example-schema-catalog`, `example-console-starter`,
`example-byo-backend-console`. That is the measurement behind the claim
that the published-input narrowing breaks nothing in this repository.

## Reverse verification — the green is not vacuous

Both legs run from the **committed** fix, mutated through an anchor that
must hit, restored to a byte-identical blob, and the restore leg re-run.

1. **Type.** Put the dead `toolName` back on a constructed tool arm.
Predicted red; measured red: `exit 2`, `TS2353: Object literal may only
specify known properties, and 'toolName' does not exist in type ...`.
Restored: exit 0.
2. **Test.** Delete the HITL carve-out in the un-backed-approval report.
Predicted red, and only the HITL test; measured exactly that: `Tests 1
failed | 11 passed (12)`, the failure being `says NOTHING when the
invocation is an ObjectStack HITL approval`. Restored: 12 passed.

## What changed

- **The three approval states are now reachable.** `approval-requested`,
`approval-responded` and `output-denied` require the runtime's
`approval` envelope beside them; `ChatToolInvocation` gained it in
objectui#9229 and the builder now constructs those arms from it. The
per-arm shapes differ (`approved` is forbidden on the outstanding
request, required on the response, pinned to `false` on the denial) so
each is built rather than spread.
- **`tool-${toolName}` is expressible.** The dynamic member the card
feared was the blocker is not one: the runtime's tool set is open, so
the mapped type collapses to an index signature and the discriminant is
a template. Pinned by a test.
- **Legacy authoring states are folded, not passed through.**
`partial-call` / `call` / `result` are not runtime states; passing them
through left the round-trip reader refusing them, so the invocation came
back stateless. Each test pairs the folded subject with a control
asserting the authored spelling is still rejected by the runtime's own
`validateUIMessages`.
- **The dead `toolName` excess property is dropped.** Only the
dynamic-tool arm declares one, and the reader derives the name off
`type`, so this is behaviour-preserving.
- **`UseObjectChatOptions.initialMessages`' optional `parts` narrows**
to the store's own part array. Breaking for an external host that passes
pre-built parts; `minor` per this repo's version policy, with the
breaking note carried in the changeset.
- **`mapMessages`' tool-invocation extraction lifts `approval`.**
Assigned to this card when objectui#9229 shipped the additive half, and
deliberately held until its first reader existed — lifting it earlier
would have minted a declared-but-unread key. It closes the recorded
asymmetry where the hydrated path carried the envelope and the live path
dropped it.

An invocation claiming an approval state with **no** envelope to back it
is not constructible, and no envelope is invented for it (inventing
`approval.id` is the fabrication AGENTS.md #0.1 forbids): the state is
derived from the data the invocation does carry, and the producer is
warned once, by name. An ObjectStack HITL approval is deliberately
**not** warned about — it is carried by `pendingActionId` and a
`pending_approval` result, and the mapper re-promotes the state from
that result on the way back out, so the approval card survives the round
trip.

## Acceptance notes

⚠️ **The ruling's residual clause is NOT in this PR, and it is not
silently dropped.** The ruling says the authoring `state` union should
shed the three runtime-only approval states so that "a schema-authored
invocation cannot claim `approval-requested` without an envelope". That
union lives on `ChatToolInvocation` in `@object-ui/types`, which
objectui#9229 left alone and whose own doc records the narrowing as this
card's. The dispatch fences `packages/types` **out** with "if you find
it incomplete, report; do not extend it here". So the conflict is
reported rather than resolved by me: the narrowing is what would delete
the un-backed-approval branch added here by construction, and it wants
its own card or an explicit widening of this one's fence.

Out of scope, noted, **not** filed:

- `(aiMessages[idx] as any)?.metadata` in the same file is untouched and
unrelated to this card's call. Successor: the next card on this file's
message-output path.
- objectui#9233 (`mergeToolResultsInto` rewriting `state` to
`output-available` for every merged result) is recorded on this card as
possibly changing what "done" means here. It is unchanged by this PR:
building the arms does not by itself put an approval card in front of an
operator on that sub-path. Successor: objectui#9233 itself, which is
open.
- objectui#9232 (the localStorage cache write side rebuilding tool parts
without `approval`) is likewise untouched and open. Successor:
objectui#9232.

## Gates run locally

`check:control-bytes` 0 · `check:new-line-citations` 0 (`0 new
citation(s)`) · `check:changeset-claims` 0 ·
`check:pending-changeset-literals` 0 · `check-changeset-presence` 0 (`1
changeset(s)`) · `check-changeset-no-major` 0 ·
`check-governed-queue-guard --test` — NOT GOVERNED · `eslint
--no-inline-config` on the four changed source files exit 0, 9
pre-existing warnings, none from this diff.

---
🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq

---
_Generated by [Claude
Code](https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Sep 28, 2026
…sheds the three runtime-only approval states (objectui#10018) (objectstack-ai#10308)

Fixes objectstack-ai#10018
Clause-②: no

This executes the residual clause of the objectui#8426 ruling (director
seat, decision batch objectstack-ai#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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants