Skip to content

FlowNodeInspector's local FlowNode admits a description key the spec's strict FlowNodeSchema rejects — and its FlowEdge twin already disagrees with FlowEdgeInspector's #6287

Description

@yinlianghui-tw

Found while taking the measurement for #5899 (see PR #6284 for the full population). Filed unassigned as an observation, for PM triage. Not fixed there — out of that card's scope.

The divergence

packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.tsx:60:

interfaceFlowNode{id: string;type?: string;label?: string;description?: string;config?: Record<string,unknown>;[k: string]: unknown;}

Probed against the installed @objectstack/spec@17.2.0:

FlowNodeSchema.safeParse({ id, type, label, description, config })
→ unrecognized_keys: ["description"]

FlowNodeSchema is .strict(), and its refusal message is explicit about why:

Unrecognized key(s) on this flow node: … Until #4001 these were dropped silently — the node still parsed, so a mis-placed config shipped as a step that quietly ignored it.

So this inspector's type says an author may put description on a flow node; the contract refuses it. Same direction as the inverted arm recorded in #5652 — a local declaration admitting what the contract rejects. Second, smaller divergence in the same interface: label? is optional here and required by FlowNodeSchema.

The duplicate-copy half

The same file declares FlowEdge at line 69, and FlowEdgeInspector.tsx:49 declares FlowEdge too. The two copies already disagree:

FlowEdgeInspector.tsx:49FlowNodeInspector.tsx:69
conditionExpressionInputunknown

FlowEdgeInspector's version is the correct one and says so in its own doc comment — it was narrowed to ExpressionInput precisely because the looser string \| { source?: string } spelling described an envelope the server rejects, which is how #3171 came to be filed against a defect that does not reproduce (#3202). The second copy in FlowNodeInspector was not narrowed with it. "Two copies of one shape is how the wrong one survives being fixed" is FlowPreview.tsx's own comment about this exact pair.

ActionParam has the same problem: ActionDefaultInspector.tsx:266 and ActionPreview.tsx:47 are two hand subsets of ActionParamSchema that disagree on options / helpText / defaultValue, on the index signature, and on label's type.

Why nothing caught it

All of these are module-local interfaces, and both scanners in scripts/check-spec-symbol-derivation.mjs skip non-exported declarations — including declarations under the spec's own export names, which is rule 1's trigger. That hole is #5899's subject; these sit in its measured population.

Fix shape

The narrow fix is to drop description (or, if flow nodes genuinely should carry one, that is a spec change, not a local type widening) and make label required. The durable fix is the one FlowPreview.tsx already made for its own pair — stop restating the shape and alias the canvas's type, so there is one declaration per shape in the package instead of two or three.

Measured on a76b18cf2 against @objectstack/spec@17.2.0.

Related: #5899 (the instrument hole that hid it), PR #6284 (the census), #5652 (the same failure shape, found by reading rather than by a gate), #3202.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions