From 0787433192c30b506f3c4b09c337bc5d59e0b0ce Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 9 Oct 2026 11:58:02 +0000 Subject: [PATCH] fix(app-shell,cli,plugin-designer): one authority for Diagnostic, DiagnosticLevel and ConfirmDialogState (objectui#6349, batch 6) Three ledger rows, each two or three meanings behind one name, converge by renaming the sites that no package entry publishes: - Diagnostic: @object-ui/sdui-parser keeps the name (published at its root and read through it). The flow designer's structural-check finding becomes FlowSimDiagnostic; the doctor command's check result becomes DoctorDiagnostic. - DiagnosticLevel: the flow designer's 'error' | 'warning' keeps the name (its structural, server and expression problems all carry it); the doctor's 'ok' | 'warn' | 'error' becomes DoctorDiagnosticLevel. - ConfirmDialogState: app-shell's dialog data keeps the name; the designer's hook result becomes DesignerConfirmDialogState. The three rows leave KNOWN_COLLISIONS. Comment riders: the chat page's import comment and two plugin-chatbot comments name ChatbotEnhancedMessage as batch 5 left it, and the ledger's note above the Filter rows records ruling 5857342228 as landed in objectui#10823. Types and comments only. Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude --- .changeset/6349-batch6-app-shell.md | 7 +++ .changeset/6349-batch6-cli.md | 7 +++ .changeset/6349-batch6-plugin-chatbot.md | 7 +++ .changeset/6349-batch6-plugin-designer.md | 9 ++++ .../app-shell/src/console/ai/AiChatPage.tsx | 20 ++++----- .../metadata-admin/previews/flow-problems.ts | 6 +-- .../previews/simulator/flow-sim-types.ts | 15 +++++-- .../previews/simulator/flow-sim-validate.ts | 12 +++--- packages/cli/src/__tests__/doctor.test.ts | 6 +-- packages/cli/src/commands/doctor.ts | 20 ++++++--- .../plugin-chatbot/src/chatMessageAdapter.ts | 13 +++--- packages/plugin-chatbot/src/useObjectChat.ts | 10 ++--- packages/plugin-designer/src/hooks/index.ts | 2 +- .../src/hooks/useConfirmDialog.ts | 13 +++++- ...e-authority-per-exported-name-6273.test.ts | 43 ++++++++++++++----- 15 files changed, 134 insertions(+), 56 deletions(-) create mode 100644 .changeset/6349-batch6-app-shell.md create mode 100644 .changeset/6349-batch6-cli.md create mode 100644 .changeset/6349-batch6-plugin-chatbot.md create mode 100644 .changeset/6349-batch6-plugin-designer.md diff --git a/.changeset/6349-batch6-app-shell.md b/.changeset/6349-batch6-app-shell.md new file mode 100644 index 0000000000..8676ee1eb0 --- /dev/null +++ b/.changeset/6349-batch6-app-shell.md @@ -0,0 +1,7 @@ +--- +'@object-ui/app-shell': patch +--- + +The flow designer's structural-check finding type is declared as `FlowSimDiagnostic` instead of `Diagnostic` (objectui#6349, batch 6), because `@object-ui/sdui-parser` publishes `Diagnostic` for a parser finding, a different shape. The type is internal: this package's entry exports neither name, so no import changes. The doc comment above the chat page's `ChatbotEnhancedMessage` import now says what `@object-ui/plugin-chatbot` publishes since objectui#6349 batch 5. + +No runtime behaviour changes. diff --git a/.changeset/6349-batch6-cli.md b/.changeset/6349-batch6-cli.md new file mode 100644 index 0000000000..413b5d9efe --- /dev/null +++ b/.changeset/6349-batch6-cli.md @@ -0,0 +1,7 @@ +--- +'@object-ui/cli': patch +--- + +The `objectui doctor` check-result types are declared as `DoctorDiagnostic` and `DoctorDiagnosticLevel` instead of `Diagnostic` and `DiagnosticLevel` (objectui#6349, batch 6), because `@object-ui/sdui-parser` publishes `Diagnostic` for a parser finding, a different shape. Both types are internal to the command: this package's entry exports `serve` and `init` only, so no import changes. + +No runtime behaviour changes; `objectui doctor` prints the same output. diff --git a/.changeset/6349-batch6-plugin-chatbot.md b/.changeset/6349-batch6-plugin-chatbot.md new file mode 100644 index 0000000000..1bcf94e74a --- /dev/null +++ b/.changeset/6349-batch6-plugin-chatbot.md @@ -0,0 +1,7 @@ +--- +'@object-ui/plugin-chatbot': patch +--- + +Doc comments now name the runtime message type `ChatbotEnhancedMessage`, its name since objectui#6349 batch 5, instead of `ChatbotEnhanced.ChatMessage` (objectui#6349, batch 6). + +No type or runtime behaviour changes. diff --git a/.changeset/6349-batch6-plugin-designer.md b/.changeset/6349-batch6-plugin-designer.md new file mode 100644 index 0000000000..3eb93b509e --- /dev/null +++ b/.changeset/6349-batch6-plugin-designer.md @@ -0,0 +1,9 @@ +--- +'@object-ui/plugin-designer': minor +--- + +The result type of `useConfirmDialog` is declared as `DesignerConfirmDialogState` instead of `ConfirmDialogState` (objectui#6349, batch 6). `@object-ui/app-shell` declares an unrelated `ConfirmDialogState` (the data its action-confirm dialog renders, with the promise's resolver), and one exported name has one declaration. + +**Breaking-change note.** Nothing breaks for a consumer of this package: the package entry never exported `ConfirmDialogState`, so no import named it, and the hook's result keeps the same members (`isOpen`, `title`, `message`, `confirm`, `onConfirm`, `onCancel`). Only the type name shown in the published declaration of `useConfirmDialog` changes. `ReturnType` resolves to the same shape as before. + +No runtime behaviour changes. diff --git a/packages/app-shell/src/console/ai/AiChatPage.tsx b/packages/app-shell/src/console/ai/AiChatPage.tsx index 200963c5f2..8a1360dbd2 100644 --- a/packages/app-shell/src/console/ai/AiChatPage.tsx +++ b/packages/app-shell/src/console/ai/AiChatPage.tsx @@ -91,16 +91,16 @@ import { // The ENHANCED message shape — the one `` renders and the // one this file actually produces (`toolInvocations`, `buildProgress`). // - // `@object-ui/plugin-chatbot` publishes ONE chat-message contract: its - // barrel's `ChatMessage` IS this type, and `ChatbotEnhancedMessage` is a - // deprecated alias of the same declaration, kept so this import (PR #4379) - // keeps compiling. The collision that made the alias necessary is gone — - // the barrel used to DECLARE a second, minimal `ChatMessage` of its own - // (id/role/content/timestamp/avatar only) and the natural name resolved to - // it, which is how this file once could not read `toolInvocations` off its - // own function's return (objectui#4040). Retired in objectui#4383 / PR - // #4400; pinned in the plugin's `chat-message-contract.test.ts`. New code - // here should spell `ChatMessage`. + // `ChatbotEnhancedMessage` is the plugin's one name for its RUNTIME + // chat-message contract, not an alias of anything. The plugin root publishes + // no `ChatMessage` at all, so the bare name means only the `@object-ui/types` + // AUTHORING contract (objectui#6349, batch 5). The `as ChatMessage` below is + // a local rename only; this file never imports the authoring type. + // History: the barrel once DECLARED a second, minimal `ChatMessage` of its + // own (id/role/content/timestamp/avatar only) and the natural name resolved + // to it, which is how this file once could not read `toolInvocations` off + // its own function's return (objectui#4040; retired in objectui#4383 / PR + // #4400). Pinned in the plugin's `chat-message-contract.test.ts`. type ChatbotEnhancedMessage as ChatMessage, } from '@object-ui/plugin-chatbot'; diff --git a/packages/app-shell/src/views/metadata-admin/previews/flow-problems.ts b/packages/app-shell/src/views/metadata-admin/previews/flow-problems.ts index 260521ed87..a18422444a 100644 --- a/packages/app-shell/src/views/metadata-admin/previews/flow-problems.ts +++ b/packages/app-shell/src/views/metadata-admin/previews/flow-problems.ts @@ -24,7 +24,7 @@ import { createContext } from 'react'; import { collectFlowGraphs } from '@objectstack/spec/automation'; import { missingNodeRefDiagnostics, validateFlowDraft } from './simulator/flow-sim-validate.js'; -import type { Diagnostic, DiagnosticLevel, SimEdge, SimNode } from './simulator/flow-sim-types.js'; +import type { FlowSimDiagnostic, DiagnosticLevel, SimEdge, SimNode } from './simulator/flow-sim-types.js'; import { conditionText, edgeKey, type FlowDesignerEdge, type FlowDesignerNode } from './flow-canvas-layout.js'; import { flowExpressionProblems } from './flow-expr-problems.js'; import { describeExprSite, flowNodeIds, nodeIdPositions, type ExprSite } from './flow-node-refs.js'; @@ -158,7 +158,7 @@ interface StructuralMapping { * the author marks as a back-edge to resolve it — but flags EVERY hop (nodes + * edges) for the red error highlight so the whole loop reads as the problem. */ -function structuralMapping(diag: Diagnostic, edges: FlowDesignerEdge[]): StructuralMapping { +function structuralMapping(diag: FlowSimDiagnostic, edges: FlowDesignerEdge[]): StructuralMapping { if (diag.edge) { const { source, target } = diag.edge; return { target: { kind: 'edge', source, target, edgeKey: resolveEdgeKey(edges, source, target) } }; @@ -233,7 +233,7 @@ export function buildFlowProblems({ nodes, edges, serverDiagnostics, variables, const problems: FlowProblem[] = []; const v = validateFlowDraft(nodes as unknown as SimNode[], edges as unknown as SimEdge[], locale); - const pushStructural = (level: DiagnosticLevel, list: Diagnostic[], tag = '') => { + const pushStructural = (level: DiagnosticLevel, list: FlowSimDiagnostic[], tag = '') => { list.forEach((diag, i) => { const { target, highlight } = structuralMapping(diag, edges); problems.push({ diff --git a/packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-types.ts b/packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-types.ts index dbcb102b38..be737d6ee4 100644 --- a/packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-types.ts +++ b/packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-types.ts @@ -120,7 +120,16 @@ export interface SimState { export type DiagnosticLevel = 'error' | 'warning'; -export interface Diagnostic { +/** + * One finding of the client-side structural check (`validateFlowDraft`, + * `missingNodeRefDiagnostics`), anchored on a node, an edge or a cycle. + * + * Named `FlowSimDiagnostic`, not `Diagnostic`: `@object-ui/sdui-parser` + * publishes `Diagnostic` for a parser finding (`severity` + `code`), a + * different thing, and one exported name has one authority (objectui#6349, + * batch 6). + */ +export interface FlowSimDiagnostic { level: DiagnosticLevel; /** The node this diagnostic points at (for an inline badge + click-to-reveal). */ nodeId?: string; @@ -138,8 +147,8 @@ export interface Diagnostic { } export interface FlowValidation { - errors: Diagnostic[]; - warnings: Diagnostic[]; + errors: FlowSimDiagnostic[]; + warnings: FlowSimDiagnostic[]; /** Resolved entry node id, when exactly one is determinable. */ startNodeId?: string; } diff --git a/packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-validate.ts b/packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-validate.ts index 79c5185163..52500a1cd3 100644 --- a/packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-validate.ts +++ b/packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-validate.ts @@ -27,7 +27,7 @@ import { type AssignmentExpressionValue, } from '@objectstack/spec/automation'; import { EVALUATED_EXPRESSION_SOURCE_REQUIRED, EvaluatedExpressionSchema } from '@objectstack/spec/shared'; -import type { Diagnostic, FlowValidation, SimEdge, SimNode } from './flow-sim-types.js'; +import type { FlowSimDiagnostic, FlowValidation, SimEdge, SimNode } from './flow-sim-types.js'; import { conditionText } from '../flow-canvas-layout.js'; import { missingNodePositions } from '../flow-node-refs.js'; import { valueEnvelopeRefusal } from '../../inspectors/flow-value-envelope.js'; @@ -315,8 +315,8 @@ export function findCycle(nodeIds: string[], edges: SimEdge[]): string[] | null /** Static structural checks; `errors` block Run, `warnings` are advisory. */ export function validateFlowDraft(nodes: SimNode[], edges: SimEdge[], locale?: string): FlowValidation { - const errors: Diagnostic[] = []; - const warnings: Diagnostic[] = []; + const errors: FlowSimDiagnostic[] = []; + const warnings: FlowSimDiagnostic[] = []; const ids = nodes.map((n) => n.id); const idSet = new Set(); @@ -443,11 +443,11 @@ export function validateFlowDraft(nodes: SimNode[], edges: SimEdge[], locale?: s export function missingNodeRefDiagnostics( flow: { nodes?: unknown; edges?: unknown; variables?: unknown }, locale?: string, -): Diagnostic[] { - const out: Diagnostic[] = []; +): FlowSimDiagnostic[] { + const out: FlowSimDiagnostic[] = []; const seen = new Set(); for (const p of missingNodePositions(flow)) { - let diag: Diagnostic; + let diag: FlowSimDiagnostic; if (p.kind === 'boundary-host') { diag = { level: 'error', nodeId: p.nodeId, message: tFormat('engine.flowValidate.boundaryHostMissing', locale, { id: p.nodeId, host: p.id }) }; } else if (p.kind === 'expression-root') { diff --git a/packages/cli/src/__tests__/doctor.test.ts b/packages/cli/src/__tests__/doctor.test.ts index d8841526f8..381a7f4b7a 100644 --- a/packages/cli/src/__tests__/doctor.test.ts +++ b/packages/cli/src/__tests__/doctor.test.ts @@ -29,7 +29,7 @@ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'; import { join, dirname } from 'node:path'; import { tmpdir } from 'node:os'; -import { runDiagnostics, countIssues, type Diagnostic } from '../commands/doctor.js'; +import { runDiagnostics, countIssues, type DoctorDiagnostic } from '../commands/doctor.js'; let cwd: string; @@ -52,9 +52,9 @@ function writePkg(pkg: Record): void { write('package.json', JSON.stringify(pkg, null, 2)); } -const ids = (results: readonly Diagnostic[]): string[] => results.map((r) => r.id); +const ids = (results: readonly DoctorDiagnostic[]): string[] => results.map((r) => r.id); -function find(results: readonly Diagnostic[], id: string): Diagnostic | undefined { +function find(results: readonly DoctorDiagnostic[], id: string): DoctorDiagnostic | undefined { return results.find((r) => r.id === id); } diff --git a/packages/cli/src/commands/doctor.ts b/packages/cli/src/commands/doctor.ts index b7e513d6ad..3702bb7a81 100644 --- a/packages/cli/src/commands/doctor.ts +++ b/packages/cli/src/commands/doctor.ts @@ -60,10 +60,18 @@ import { existsSync, readFileSync } from 'fs'; import { dirname, join, resolve as resolvePath } from 'path'; /** `ok` never counts toward the issue total; `warn` and `error` both do. */ -export type DiagnosticLevel = 'ok' | 'warn' | 'error'; +export type DoctorDiagnosticLevel = 'ok' | 'warn' | 'error'; -export interface Diagnostic { - level: DiagnosticLevel; +/** + * One `objectui doctor` check result. + * + * `Doctor`-prefixed, like its level: `@object-ui/sdui-parser` publishes + * `Diagnostic` for a parser finding, and the flow designer's `DiagnosticLevel` + * is `'error' | 'warning'` with no `ok` verdict — different things, and one + * exported name has one authority (objectui#6349, batch 6). + */ +export interface DoctorDiagnostic { + level: DoctorDiagnosticLevel; /** The single line rendered for this finding. */ message: string; /** @@ -198,8 +206,8 @@ function isInstalledFrom(cwd: string, specifier: string): boolean { * Run every diagnostic against `cwd` and return the findings in render order. * Pure with respect to stdout — see the module docblock. */ -export function runDiagnostics(cwd: string): Diagnostic[] { - const results: Diagnostic[] = []; +export function runDiagnostics(cwd: string): DoctorDiagnostic[] { + const results: DoctorDiagnostic[] = []; const ok = (id: string, message: string): void => { results.push({ id, level: 'ok', message }); }; @@ -391,7 +399,7 @@ export function runDiagnostics(cwd: string): Diagnostic[] { } /** Number of findings that count as problems. `ok` findings never do. */ -export function countIssues(results: readonly Diagnostic[]): number { +export function countIssues(results: readonly DoctorDiagnostic[]): number { return results.filter((result) => result.level !== 'ok').length; } diff --git a/packages/plugin-chatbot/src/chatMessageAdapter.ts b/packages/plugin-chatbot/src/chatMessageAdapter.ts index 8eef1effd2..e9c0ec8cfe 100644 --- a/packages/plugin-chatbot/src/chatMessageAdapter.ts +++ b/packages/plugin-chatbot/src/chatMessageAdapter.ts @@ -10,16 +10,17 @@ * The `@object-ui/types` <-> `@object-ui/plugin-chatbot` chat-message seam * (objectui#4399). * - * Two `ChatMessage` types meet in `renderer.tsx`, both on purpose: + * Two chat-message types meet in `renderer.tsx`, both on purpose: * * - `@object-ui/types`' `ChatMessage` is the **authoring** contract — the * JSON an SDUI schema declares (`ChatMessageSchema` in * `packages/types/src/zod/complex.zod.ts`), so it is deliberately wider: * a `'tool'` role and a `Date` timestamp are authorable. - * - `./ChatbotEnhanced`'s `ChatMessage` is the **runtime** contract — what - * the React components actually render, so it is deliberately narrower - * (three roles, string timestamps) and carries render-only keys the - * authoring surface has no business declaring (`buildProgress`, `charts`). + * - `./ChatbotEnhanced`'s `ChatbotEnhancedMessage` is the **runtime** + * contract — what the React components actually render, so it is + * deliberately narrower (three roles, string timestamps) and carries + * render-only keys the authoring surface has no business declaring + * (`buildProgress`, `charts`). * * Until this module they met as three `messages as any` casts, which erased * ALL of the drift rather than the parts that are intentional: a new authored @@ -85,7 +86,7 @@ import type { /** * The render-only MESSAGE keys — declared by the runtime contract, never by the * authoring one. Named here (rather than spelled out at each use) so that - * adding a render-only key to `ChatbotEnhanced.ChatMessage` and forgetting this + * adding a render-only key to `ChatbotEnhancedMessage` and forgetting this * list is a one-line fix in one place. objectui#4424. */ type RuntimeOnlyMessageKeys = Pick< diff --git a/packages/plugin-chatbot/src/useObjectChat.ts b/packages/plugin-chatbot/src/useObjectChat.ts index a768954540..a0e4def678 100644 --- a/packages/plugin-chatbot/src/useObjectChat.ts +++ b/packages/plugin-chatbot/src/useObjectChat.ts @@ -998,11 +998,11 @@ export function useObjectChat(options: UseObjectChatOptions = {}): UseObjectChat const isLoading = status === 'submitted' || status === 'streaming'; - // Vercel AI SDK v6 UIMessage → the runtime ChatMessage. The shared mapper - // handles parts (text, reasoning, tool-*, source-*), streaming-cursor - // flagging, and legacy `msg.toolInvocations` fallback. We splice `metadata` - // back in because `ChatbotEnhanced.ChatMessage` doesn't carry it but the - // authoring contract does. + // Vercel AI SDK v6 UIMessage → the runtime `ChatbotEnhancedMessage`. The + // shared mapper handles parts (text, reasoning, tool-*, source-*), + // streaming-cursor flagging, and legacy `msg.toolInvocations` fallback. We + // splice `metadata` back in because `ChatbotEnhancedMessage` doesn't carry it + // but the authoring contract does. // // objectui#4424: this used to end in `as OuiChatMessage[]`, and that cast was // the card. It erased `buildProgress`, `blueprintProgress`, `charts` and diff --git a/packages/plugin-designer/src/hooks/index.ts b/packages/plugin-designer/src/hooks/index.ts index 1e7a113417..66354d299d 100644 --- a/packages/plugin-designer/src/hooks/index.ts +++ b/packages/plugin-designer/src/hooks/index.ts @@ -13,7 +13,7 @@ export { useDesignerHistory } from './useDesignerHistory'; export type { DesignerHistoryState, DesignerHistoryOptions } from './useDesignerHistory'; export { useConfirmDialog } from './useConfirmDialog'; -export type { ConfirmDialogState } from './useConfirmDialog'; +export type { DesignerConfirmDialogState } from './useConfirmDialog'; export { useClipboard } from './useClipboard'; export type { ClipboardState } from './useClipboard'; diff --git a/packages/plugin-designer/src/hooks/useConfirmDialog.ts b/packages/plugin-designer/src/hooks/useConfirmDialog.ts index efe74d287e..a1da9a0736 100644 --- a/packages/plugin-designer/src/hooks/useConfirmDialog.ts +++ b/packages/plugin-designer/src/hooks/useConfirmDialog.ts @@ -8,7 +8,16 @@ import { useState, useCallback, useRef } from 'react'; -export interface ConfirmDialogState { +/** + * What {@link useConfirmDialog} returns: the dialog's state plus the + * functions that drive it. + * + * `Designer`-prefixed, as `DesignerHistoryState` is: app-shell's + * `ConfirmDialogState` is a different thing (the data its action-confirm + * dialog renders, with the promise's resolver), and one exported name has one + * authority (objectui#6349, batch 6). + */ +export interface DesignerConfirmDialogState { /** Whether the dialog is open */ isOpen: boolean; /** Title for the dialog */ @@ -26,7 +35,7 @@ export interface ConfirmDialogState { /** * Hook for confirmation dialogs before destructive actions. */ -export function useConfirmDialog(): ConfirmDialogState { +export function useConfirmDialog(): DesignerConfirmDialogState { const [isOpen, setIsOpen] = useState(false); const [title, setTitle] = useState(''); const [message, setMessage] = useState(''); diff --git a/scripts/__tests__/one-authority-per-exported-name-6273.test.ts b/scripts/__tests__/one-authority-per-exported-name-6273.test.ts index 749f96547b..a0666a7bd2 100644 --- a/scripts/__tests__/one-authority-per-exported-name-6273.test.ts +++ b/scripts/__tests__/one-authority-per-exported-name-6273.test.ts @@ -423,20 +423,41 @@ const KNOWN_COLLISIONS: ReadonlyMap = new Map([ // `ConditionalFormattingRule` had a THIRD site, `packages/plugin-kanban/src/KanbanEnhanced.tsx`, // which left the tree when objectui#8932 deleted that module; the two below still collide. ['ConditionalFormattingRule', ['packages/plugin-kanban/src/KanbanImpl.tsx', 'packages/types/src/objectql.ts']], - ['ConfirmDialogState', ['packages/app-shell/src/views/ActionConfirmDialog.tsx', 'packages/plugin-designer/src/hooks/useConfirmDialog.ts']], + // `ConfirmDialogState` sat here, colliding between + // `packages/app-shell/src/views/ActionConfirmDialog.tsx` and + // `packages/plugin-designer/src/hooks/useConfirmDialog.ts`. Two meanings that + // share only `message`: app-shell's is the DATA its action-confirm dialog + // renders (`open`, `options`, the promise's `resolve`), the designer's is a + // hook RESULT (`isOpen`, `title` and the `confirm` / `onConfirm` / `onCancel` + // functions). Neither package's built entry exports the name. RENAME branch: + // the designer's declaration now spells `DesignerConfirmDialogState` + // (objectui#6349, batch 6). ['ConnectionState', ['packages/collaboration/src/useRealtimeSubscription.ts', 'packages/data-objectstack/src/index.ts']], ['DataSource', ['packages/app-shell/src/types.ts', 'packages/types/src/data.ts']], - ['Diagnostic', ['packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-types.ts', 'packages/cli/src/commands/doctor.ts', 'packages/sdui-parser/src/types.ts']], - ['DiagnosticLevel', ['packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-types.ts', 'packages/cli/src/commands/doctor.ts']], + // `Diagnostic` sat here with THREE sites and three meanings: + // `packages/sdui-parser/src/types.ts` (a parser finding: `severity`, `code`, + // `start`, `tag` — published at that package's root and read through it), + // `packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-types.ts` + // (a flow structural-check finding anchored on a node, edge or cycle) and + // `packages/cli/src/commands/doctor.ts` (a doctor check result with a stable + // `id`). Only the first was reachable from its package's built entry, so it + // keeps the name; RENAME branch for the other two, which now spell + // `FlowSimDiagnostic` and `DoctorDiagnostic` (objectui#6349, batch 6). + // `DiagnosticLevel` sat here too, colliding between the same flow-sim and + // doctor files: `'error' | 'warning'` there, `'ok' | 'warn' | 'error'` here. + // The flow designer's is the one general level (its structural, server and + // expression problems all carry it), so it keeps the name and the doctor's + // now spells `DoctorDiagnosticLevel` (objectui#6349, batch 6). ['DomProps', ['packages/core/src/utils/dom-props.ts', 'packages/fields/src/widgets/toDomProps.ts']], - // ⚠️ `FilterBuilderCondition` / `FilterGroup` are NOT one shape declared twice: - // the component's condition carries a required `id`, a required narrow `value` - // and `operator: string` (the dropdown's camelCase ids); the types copy has no - // `id`, `value?: any` and `operator: FilterBuilderOperator` (the snake_case - // union). Both headers claim ONE concept, so the remedy is a re-point, and the - // only dependency-legal direction (components -> types) retypes `operator` — - // the vocabulary objectui#7561 is asking a maintainer to rule on. Both rows - // wait for that ruling (objectui#6349, batch 3, stop-and-report). + // ⚠️ `FilterBuilderCondition` / `FilterGroup` still carry two declarations, + // but no longer two unrelated shapes. objectui#7561 and objectui#9306 are + // closed: the maintainer's ruling on objectui#9306 (letter A, comment + // `5857342228`) landed as PR objectui#10823, and `@object-ui/components` now + // DERIVES both from `@object-ui/types`, restating only `operator` and `value` + // as named extensions on the row (and the row-typed `conditions` on the + // group). A derived declaration is still an authority to this gate, so both + // rows stay until a batch measures a rename against that ruling + // (objectui#6349, batch 3 parked them; batch 6 recorded the ruling). ['FilterBuilderCondition', ['packages/components/src/custom/filter-builder.tsx', 'packages/types/src/complex.ts']], ['FilterBuilderOperator', ['packages/components/src/custom/filter-builder.tsx', 'packages/types/src/complex.ts']], ['FilterGroup', ['packages/components/src/custom/filter-builder.tsx', 'packages/types/src/complex.ts']],