fix(spec): alias visible/showWhen onto visibleWhen on page:tabs items and screen fields - #8415
Conversation
… items and screen fields #7832 curated the visible/showWhen action-side spellings onto visibleWhen across six shapes and pinned the inventory in visible-when-alias-guidance.test.ts. Two more visibleWhen shapes were never in that inventory: page:tabs items (ui/component.zod.ts) and the automation screen node's ScreenFieldConfigSchema (builtin-node-config.zod.ts). Both are hand-rolled strictObject calls with exactly one landing key and no boolean sibling, so both get the simple alias-row treatment: visible -> visibleWhen, showWhen -> visibleWhen. Acceptance is unchanged -- an alias row is a message channel, not a parse-time rename. The page:tabs item docblock also flags visibility/visibleOn (the ADR-0089 view/page spellings) as deliberately not accepted here; that is an acceptance statement an alias row does not disturb, so both also get a pointer at visibleWhen while staying rejected. Adds a fifth section to visible-when-alias-guidance.test.ts pinning both shapes' rename messages, canonical-still-parses, aliased-spellings-still- rejected, and the visibility/visibleOn decision, per Fixes #8382. Fixes #8382 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YBUGvukaeVu9DjKdsHJa9
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 1 package(s): 106 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
⛔ 7 release-owned page(s) also reference the affected code. These are read-only:
|
Fixes #8382
What changed
#7832 / PR #7884 curated the
visible/showWhenaction-side spellings ontovisibleWhenacross six shapes, pinned inpackages/spec/src/shared/visible-when-alias-guidance.test.ts. Two morevisibleWhenshapes were outside that inventory and still rejectedvisible/
showWhenwithout naming the key to write instead:packages/spec/src/ui/component.zod.ts— thepage:tabsitem(
surface: 'this \page:tabs` item',visibleWheninPageTabsProps'sitems` array).packages/spec/src/automation/builtin-node-config.zod.ts—ScreenFieldConfigSchema(surface: 'this screen field').Both have exactly one landing key for the visibility intent and no boolean
sibling, so both get the simple alias treatment per the inventory file's
own rule:
visible → visibleWhen,showWhen → visibleWhen.Before / after
page:tabsitemSame shape for
showWhen.ScreenFieldConfigSchemaSame shape for
showWhen. The pre-existingvisibleIfprescription (an exactguidanceentry, four edits from the right key) is untouched — an exact entrywins over the alias table, pinned in the new test section.
Acceptance invariance
Every key probed is rejected before this change and rejected after — only the
message changed. Pinned directly:
visible.safeParse/showWhen.safeParseon both shapes still fail.visibleWhenstill parses on both shapes, and the parsedvalue is unchanged (
page:tabsitems route it throughExpressionInputSchema, so the pin checks the normalized{ dialect: 'cel', source }shape rather than the raw string — that normalization predatesthis change).
Reachability — no guidance set shadows the new rows
Both shapes are hand-rolled
strictObjectcalls with their own options.Neither spreads
VISIBILITY_STRICT_OPTIONS(confirmed by reading both callsites on
origin/mainbefore writing the rows, per the card's instruction —the tab item carries only its own
key → valuealias row, the screen fieldcarries only its
visibleIfexact-guidance entry). So no shared guidance setconsumes
visible/showWhenahead of the new alias rows, andalias-integrity.test.ts's #7889 reachability check stays green — ran itdirectly alongside the new pins (see Tests below). The new pins themselves
assert the rename message actually fires (
Did you mean …), which is exactlywhat a shadowed/dead row would fail to produce.
⛔ Neither row was hoisted onto
VISIBILITY_STRICT_OPTIONS— both stay ontheir own hand-rolled tables, per the card's red line.
The
visibility/visibleOnjudgment call (page:tabsitem only)The tab item's
visibleWhendocblock states that the deprecated ADR-0089visibility/visibleOnaliases are not accepted on tab items — unlikethe view/page shapes that fold them into
visibleWhenvianormalizeVisibleWhen, this key is new and deliberately carries no legacybaggage. That sentence is about acceptance; an alias row does not disturb
it.
Decision: yes, both also get a pointer at
visibleWhen, alongsidevisible/
showWhen. Reasoning, on the three axes:visibility(pagecomponent) or
visibleOn(view form) under ADR-0089 and reaches for thesame word on a
page:tabsitem — a page-level surface, like the componentthe spelling came from — is signalling the identical intent. The docblock
itself anticipates exactly this confusion, which is why it calls the two
spellings out by name.
visible/showWhen; the file's own header rule makes this the aliascase for all four spellings, not just two. Landing all four rows on the
same shape/decision gives the surface one coherent answer instead of two
spellings resolved and two left bare for no principled reason.
fail
.strict()exactly as before. Only the message improves, which isthe AI-authoring-safe direction: loud rejection, now with a fix instead of
a dead end.
The docblock and the field's
.describe()string are both updated so theysay the same thing as the new rows:
visible/showWhen/visibility/visibleOnare all rejected onpage:tabsitems (none folded in, unlikeview/page surfaces), and each rejection now names
visibleWhen. Pinned in thenew test section so a future edit can't silently change either half (drop the
pointer, or silently start accepting one of the four).
ScreenFieldConfigSchema's docblock never made an ADR-0089 claim (it's anADR-0032 CEL predicate, not a view/page-family key), so no
visibility/visibleOnpointer was added there — out of the card's stated scope for thatshape and not implied by anything in its existing prose.
Changeset
patchon@objectstack/spec. Measured against the stated criterion (doesthe prose reach a consumer — reference page,
dist/**/*.d.tshover, or aparse-reachable error string): the new "Did you mean" text is a
safeParse/parseerror message string, reached the moment an author (humanor AI) writes any of the four spellings — parse-reachable by definition, same
as #7832's own changeset for the identical shape of change.
.changeset/tabs-screenfield-visible-when-aliases.md.Tests
Added a fifth section to
packages/spec/src/shared/visible-when-alias-guidance.test.ts(
#8382 — the two shapes #7832 never enumerated), following the file'sexisting conventions (
unknownKeyMessagehelper, minimal reach-the-surfacebodies). Per shape:
visible/showWheneach produce a "Did you mean" rename ontovisibleWhen.visibleWhenstill parses and the parsed value is unchanged.visible/showWhenstay rejected (safeParse().success === false).page:tabsitems additionally pin thevisibility/visibleOndecision:pointed at
visibleWhen, still rejected.ScreenFieldConfigSchemaadditionally pins that the pre-existingvisibleIfguidance is untouched (guidancewins overaliases).No exports added or removed, so
check:api-surfacewas not required (thepackage-scoped
typecheckabove already covers the touched surface); rantypecheckanyway per the gate list.Gates run
All green:
pnpm check:adr-anchorspnpm check:changeset-gate-self-testspnpm check:cross-package-test-inputspnpm --filter @objectstack/lint run check:doc-formula-expressions(built
@objectstack/formulafirst)pnpm check:docs-audit-scopepnpm check:i18n(built@objectstack/cliand its dependency closurefirst —
pnpm --workspace-concurrency=2 --filter '@objectstack/cli^...' build,concurrency flag before
--filterper the toolchain note)pnpm check:merge-driverpnpm check:release-bodypnpm check:spec-parsed-aliaspnpm check:type-source-resolutionpnpm check:nul-bytespnpm --filter @objectstack/spec test/typecheckNot run (repo's own pre-existing red state, not this PR's to fix, per the
dispatch prompt):
node scripts/check-dev-prereqs.mjs,check:objectui-pin-fresh.Scope fence self-certification
Diff touches exactly:
packages/spec/src/ui/component.zod.ts(the namedpage:tabsitem)packages/spec/src/automation/builtin-node-config.zod.ts(the namedScreenFieldConfigSchema)packages/spec/src/shared/visible-when-alias-guidance.test.ts(the newpin section)
.changeset/tabs-screenfield-visible-when-aliases.mdNothing in
data/object.zod.ts, the shared strict-options plumbing, orVISIBILITY_STRICT_OPTIONSitself — that surface stays #7816's. No accept/reject behavior changed on either shape (the triage red line): both
implementation passes confirmed this is the message-only alias case, so
nothing was flagged back.
content/docs/releases/untouched.Generated by Claude Code