feat(spec)!: ai:chat_window is retired — refused by name at the schema door, the floating chat overlay is the AI chat entry point (#21504) - #21531
Conversation
…shape Claude-Session: https://claude.ai/code/session_01YDt3PzwfrkuFzUBF89WPmM Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDt3PzwfrkuFzUBF89WPmM Co-authored-by: Claude <noreply@anthropic.com>
…tire-ai-chat-window Claude-Session: https://claude.ai/code/session_01YDt3PzwfrkuFzUBF89WPmM Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 2 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 6 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 138 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 7846296e0a847b299ea993b44b7adb5ad58369dc && git checkout 7846296e0a847b299ea993b44b7adb5ad58369dc
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin ad7c3518983a1bb63fd4601954ac92d055124e42 3f17d5229e35c592af07f771f7d1118f26e2678e && git checkout -B drift-repro ad7c3518983a1bb63fd4601954ac92d055124e42 && git merge --no-ff 3f17d5229e35c592af07f771f7d1118f26e2678e
node scripts/docs-audit/affected-docs.mjs --json ad7c3518983a1bb63fd4601954ac92d055124e42
|
Contract reviewServed-tier: Read-only review of PR #21531 (card #21504) against the net diff on Check-runs on the head, read at 2026-10-03T03:42Z: 32 runs — 18 ① Derived judgmentsEvery accept-set and public-surface change the diff implies, named right or wrong against the ruling and the precedent's actual shape.
② Semver levelChangeset ③ Boundary flagsDev flags (eight deviations, two out-of-scope findings, no open questions), each answered:
Implemented-by: VERDICT: PASS Generated by Claude Code |
ACCEPT — PR #21531 @
|
Fixes #21504
Clause-②: yes (narrowing)
Retires the
ai:chat_windowpage component type under ADR-0049 enforce-or-remove, refused by name throughRETIRED_PAGE_COMPONENT_TYPES, per triage ruling5963897014and theuser:profileprecedent (#14159, landed in PR #15112). No renderer for it ever shipped: objectui leaves it unregistered on purpose, because the floating chat overlay is the supported AI chat entry point. So an authored node validated clean and then drew "Unknown component type".ai:suggestionis not touched; triage ruled it a different class.What changed
ui/page.zod.ts'ai:chat_window'leavesPageComponentTypeand joinsRETIRED_PAGE_COMPONENT_TYPES. Its message names the floating chat overlay as the supported entry point and carries no tracker number.PageComponentSchema.typealready consults the map, so the open string arm cannot re-admit the name. The type's.describe()and the enum docblock name the new member.ui/component.zod.tsAIChatWindowProps(mode,agentId,context,aria) is deleted. TheComponentPropsMap['ai:chat_window']row stays asretiredComponentProps('ai:chat_window'): az.neverthat refuses every bag,{}included, with the same prescription.ui-ai-chat-window-retired, oneSTEP18_RATIONALEfragment, and theRETIRED_DEFS_BY_MAJOR[18]entryui/AIChatWindowProps, generated bygen:migration-registry. No D2 conversion, see below.component.test.tsgets a new describe withcode,path,paramsand the first sentence at each door: the map, the row (empty and populated bags),PageComponentSchema,PageSchemaat the element path, and the enum error map.ai:suggestionis the control and parses at every door, and the open arm stays open.component-type-vocabulary.test.ts: the type stays known, leaves the typo candidates, andai:stays reserved. The oldshould parse ai:chat_window with defaultaccept pin is flipped into the new describe.component-props-unknown-members.pin.test.ts(PR #21502) loses itsai:chat_windowcontext{}"no-reader" line, because the member left with the def.api-surface/,export-origins/,declaration-map/,authorable-surface/(4 lines, proof: "def no longer emitted by this build"),authorable-defaults/,json-schema.manifest/(1 key),docs-import-surface.baseline.json, the strictness-ledger counts, and the reference docs. Each was regenerated by its generator. The manifest and authorable-surface lines were deleted as the build gate prescribes, and its proof check accepted them.authorable-surface.base.jsonis untouched.content/docs/ui/pages.mdxcomponent list says the truth.validate-page-field-bindings.tsusedAIChatWindowProps.agentIdas its example of a non-field string prop. The example now names a live one,ElementImagePropsSchema.alt.@objectstack/specminor, BREAKING banner,Clause-②: yes (narrowing), FROM → TO table, ADR-0087 markerregistered ui-ai-chat-window-retired.How this follows the precedent, and the one place the claim's wording differs
The PR #15112 shape is matched element by element: the enum value removed, a map entry, the enum error map and the node-level check sharing one string, the row kept as
retiredComponentProps, pins at the three doors with a control, a vocabulary pin, regenerated artifacts, the docs list and aminorchangeset. The claim and the dispatch said that "theComponentPropsMaprow ... go[es]". The precedent does not delete the row. It replaces the row's props schema with a whole-bag refusal, and its docblock says why: deleting the row would turn a loud retirement into a silent skip on every reader that dispatches on it. Two tests on this tree depend on that.component-type-vocabulary.test.tsrequires every member ofRETIRED_PAGE_COMPONENT_TYPESto stayisKnownComponentType. objectui'sregistry-inputs-spec-parity.test.tsat the pin classifies a retired type through its kept row. So the row stays andAIChatWindowPropsgoes. That is how "the type leaves ... itsComponentPropsMaprow" lands here.Two kit items go beyond PR #15112, because the ruling asked for them. #15112 had no D3 entry: its row had zero keys, and its disposition was
not-required (no-migration-prescription). This one has a D3 entry because triage named one. It is in the element-node shape ofelement-filter-and-form-node-refused. It also has aRETIRED_DEFS_BY_MAJORentry, because a published def leaves the build. No D2 conversion is registered. The precedent registered none, and the only edit is deleting an authored page node, which is a layout decision that conversions must not make.Census (A1), at
529d9711fbai:chat_window:examples/**0,packages/apps/**0,apps/**0,skills/**0.content/docs/**had 3 hits: 2 in the auto-generated references and 1 in thepages.mdxlist. The otherpackages/**hits were the spec's own list and row, its tests, and a frozen formatter fixture inscripts/format-type.test.ts, which is left as is, as feat(spec): user:profile is explicitly not author-placeable — refused by name at the schema door (#14159) #15112 leftuser:profilein it. Control in the same query shape:element:dividerappears in 3 example files andrecord:detailsin 12.AIChatWindowProps: the def, the generated artifacts, and one illustrative comment inpackages/lint. That comment is updated, and it is not a consumer.89cad75d55: there is no renderer, and the palette excludes the type. No non-test source importsAIChatWindowPropsor indexes the row. The'ai:chat_window'key sits only inRecordobjects keyed by string, and in comments and tests. So the Console Pin Gate's build does not reference the removed names.skills/**names nothing, so it is untouched (no Tier H).Ablation (both legs committed first, mutated through
scripts/ablation-replace.mjswith an anchor that must hit, restored by blob)The subject resolves by relative import (
./page.zod,./component.zod) tosrc, so nodistrebuild was involved.ai:chat_windowentry fromRETIRED_PAGE_COMPONENT_TYPES(anchor 1 → 0, blob7d2faf0b1f79→501c4251ee90). The observed direction is louder than the pin.component.test.tsfails to load, with 1 file failed and no tests run. The error reads: retiredComponentProps:ai:chat_windowhas no RETIRED_PAGE_COMPONENT_TYPES entry (page.zod.ts). The kept row's factory refuses a row that has lost its prescription.emptyProps('ai:chat_window'). Result: 5 failed and 360 passed. The failures are the map pin, the row pin,PageComponentSchemaby name,PageSchemaat the element path, and the enum error map.HEAD(7d2faf0b1f79,891d947a3232),git diff HEADis empty, andgit statusis clean. Re-run after the restore:component.test.tshas 365 of 365 passing.Gates, at
3f17d5229e(mergedorigin/main88fb5e85a0, which touched no spec, lint or docs file this PR edits)@objectstack/specbuildexit 0.check:generated:✓ All 15 generated artifacts are up to date.@objectstack/spectest(--project local): 603 files, 17845 passed and 1 todo.typecheckexit 0, withcheck:test-typecheck: OK.@objectstack/lintbuild closure, thentest: 119 files, 5615 passed and 5 skipped.flags ai:chat_windowruns off the map.typecheckexit 0.check:livenessexit 0,check:migration-registry✓ ... is current (354 semantic, 246 retired-key, 218 retired-def),check:doc-authoringexit 0,check:nul-bytesOK (... no raw ASCII control bytes).--eventpayload:check-adr-0087-registration✓ 1 declared-breaking changeset(s) ... registered ui-ai-chat-window-retired (new here: ui-ai-chat-window-retired).check-changeset-no-major✓ LEVEL AXIS: this PR declares clause-② yes (narrowing).check-empty-changesetexit 0.dispatch-gates --ran:✓ 114 derived famil(ies) accounted for — 112 run, 2 NOT-MEASURED.check:dual-build-cjs-loads, reason: it needs a whole-repopnpm build, and it exited 3 with PREREQUISITE NOT MET.check:type-check-debt, reason: repo-wide tsc, killed by a 420s per-gate timeout on the shared box. The two packages this PR touches typecheck green.@objectstack/spectest:repo(--project repo), reason: one idle worker under 2% CPU for 10 minutes with no output, stopped. It is CI's.Acceptance notes
@objectstack/spec. It is the same step objectui#7122 took foruser:profileandelement:form. At the pin,block-config.test.ts("every exclusion names a real spec type") and theUNJUDGED_SPEC_BLOCKSentry inregistry-inputs-spec-parity.test.ts("NOT REGISTERED, DELIBERATELY", whose class is exclusive with "RETIRED UPSTREAM") both still treatai:chat_windowas a live enum member. They are objectui's tests against its installed spec, so they do not affect this repo's CI. Who picks it up: the next objectui spec-bump PR.no-readerreason kind no longer has a user. It is left as ledger vocabulary.defaultAgentfor whatagentIdwas used for. objectui at the pin forwardsapp.defaultAgent, limited toask/build, to the chat dock's one agent resolver (app-shell/src/layout/ChatDock.tsx:242,hooks/surfaceAgent.ts:127-128).Generated by Claude Code