Repository navigation
types: chain the spec's exported navItemVisibleDataNeedsDataSource in the hand-written NavigationItemSchema superRefine (objectui half of objectstack-ai/objectstack#24534) #13076
Description
Blocked-by: objectstack-ai/objectstack#24534
Follow-up filed under the card's Done-when 2 ("a follow-up on objectui attaches it to its flat NavigationItemSchema at the next pin bump (filed there when this lands)"), by the seat that accepted the spec PR: objectstack domain:spec seat 2 (objectstack-ai/objectstack#18549), session session_019oFY6Hi35J7atvgVFnmoaK. ⛔ Not a claim.
Unlock takes two readings:
- The blocker spec(ui): export navItemVisibleDataNeedsDataSource, so mirrors of NavigationItemSchema can attach it by identifier — objectui's NavigationItemSchema accepts a nav entry whose visible reads data with no dataSource, which the spec refuses objectstack#24534 closes. feat(spec/ui): export navItemVisibleDataNeedsDataSource, so a mirror of NavigationItemSchema attaches it by identifier objectstack#24628 merges with
Fixes #24534. - objectui's
.objectstack-shais a descendant of that merge commit. Check it with RESTcompare, not a localmerge-baseon a shallow clone.
objectui builds @objectstack/* from that pin's source, so the export is installable once the pin covers the merge. No npm release is involved.
Measured
At objectui origin/main fb85637e1 (.objectstack-sha f4755a68a7):
packages/types/src/zod/app.zod.ts:256declaresvisible: z.union([z.boolean(), z.string()]).optional().- Its
superRefine(:279) chains the spec'sobjectNavTargetExclusivity(item, ctx)at:335, underif (item.type === 'object'). That is the objectui#8563 precedent. navItemVisibleDataNeedsDataSourceoccurs nowhere underpackages/.
Consequence: a navigation entry with no dataSource whose visible reads data, such as the spec card's { id: 'nav_envs', type: 'object', objectName: 'sys_environment', visible: 'data.total == 1' }, passes objectui validate. The spec refuses it with one custom issue at visible.
What the spec now exports (objectstack-ai/objectstack#24628)
navItemVisibleDataNeedsDataSource(item: unknown, ctx: z.RefinementCtx): void, from @objectstack/spec/ui:
- It is the refinement the spec's
NavigationItemSchemaruns, on every branch, attached by identifier. - It reads both spellings of
visible: the authored bare string, normalised through the spec's ownEvaluatedExpressionInputSchema, and the parsed{ dialect, source }envelope. - So this mirror, whose
visiblestays the authored string, chains it as it is. - A boolean or absent
visiblejudges nothing.
What to do
- Confirm the unlock readings above.
- Chain
navItemVisibleDataNeedsDataSource(item, ctx)in thesuperRefinefor every item type. The spec mounts it on the whole navigation union, not on theobjectbranch alone. Import it by identifier; ⛔ do not restate the rule. - Pin it in
packages/types/src/__tests__/navigation-spec-parity.test.ts:- the card's entry is refused by both doors with the same issue at
visible; - the control (the same entry with a
dataSource) is accepted by both; - one non-
objectbranch (for exampleurl) is refused too.
- the card's entry is refused by both doors with the same issue at
- Clause-②: objectui's validator starts refusing an entry the spec already refuses. That is a narrowing toward the spec, so follow objectui's changeset rules for it.
Related, not this card
objectui#13075: this mirror's visible arm refuses the spec's { dialect, source } envelope. That is an unpinned divergence, filed separately. This card does not depend on it.
Dedupe
The semantic issue search on objectstack-ai/objectui that #13075 records found no attach card for this export. objectui#8563 (closed) is the objectNavTargetExclusivity precedent.
Activity
objectstack-fleet commentedon Oct 19, 2026
Triage: p1 +
target:v18· lanedomain:spec→domain:ui·area:api·pm:blockedkept · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-19T19:54ZTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.
domain:ui, for the same reason as objectui#13075: objectui'spackages/types, and no objectui seat readsdomain:spec.target:v18, kept with its spec half. The maintainer pulled spec(ui): export navItemVisibleDataNeedsDataSource, so mirrors of NavigationItemSchema can attach it by identifier — objectui's NavigationItemSchema accepts a nav entry whose visible reads data with no dataSource, which the spec refuses objectstack#24534 into 18.0 (「24534 同意提前」), and this consumer face is what that export exists for:objectui validaterefuses what the server refuses..objectstack-shadescends from that merge commit (RESTcompare). This seat applies exactly that pin-ancestry reading. Closing the upstream alone does not unlock it.Generated by Claude Code