Skip to content

Two visibleWhen shapes were outside #7832's sweep: page:tabs items and ScreenFieldConfig still reject visible / showWhen without naming the key #8382

Description

@hotlong

Found while verifying #7816's ask 1 (which #7832 / PR #7884 delivered). #7832 curated six shapes; its inventory test packages/spec/src/shared/visible-when-alias-guidance.test.ts pins those six. Two other shapes in packages/spec declare visibleWhen and were never in that inventory — on both, an author who writes the action-side spelling still gets a rejection that names the surface but never names the key to write instead. That is exactly the defect #7832 existed to remove, just on surfaces nobody enumerated.

Measured on origin/main @ 84c07c3c1, freshly built spec dist

1. page:tabs item — packages/spec/src/ui/component.zod.ts (PageTabsProps, items array, visibleWhen declared ~L601)

ACCEPTED  items[0].visibleWhen                  (canonical — landing key confirmed)
BARE      items[0].visible
          Unrecognized key(s) on this `page:tabs` item: `visible`. Until #4001 batch A an
          undeclared prop was dropped in silence: …
BARE      items[0].showWhen                     (same message shape)

2. ScreenFieldConfigSchema — packages/spec/src/automation/builtin-node-config.zod.ts (visibleWhen declared ~L404)

ACCEPTED  { name: 'f', visibleWhen: 'record.x' }   (canonical — landing key confirmed)
BARE      { name: 'f', visible: true }
          Unrecognized key(s) on this screen field: `visible`. Until #4001 an undeclared key
          here was dropped at the execute-time parse — …
BARE      { name: 'f', showWhen: 'record.x' }      (same message shape)

Neither message mentions visibleWhen. Compare the six shapes #7832 did cover, all of which now name a target key (RowCrudActionOverrideSchema, FieldSchema, SelectOptionSchema, FormFieldSchema, FormSectionSchema, PageComponentSchema).

Suggested fix

Both shapes have exactly ONE landing key for the visibility intent and no boolean sibling, so by the rule visible-when-alias-guidance.test.ts states in its header (one landing key ⇒ alias; two ⇒ guidance prose; none ⇒ nothing) both are the simple alias case: visible → visibleWhen, showWhen → visibleWhen. Acceptance stays byte-identical — an alias row is a message channel, not a parse-time rename.

Two constraints inherited from #8199, both worth re-checking at implementation time:

The natural home for the pins is a fourth section in visible-when-alias-guidance.test.ts, so the inventory stays the single place that says which surfaces are answered and which are deliberately not.

Scope note

Filed unassigned, out of scope for #7816 — that card's declared file surface is data/object.zod.ts / data/field.zod.ts / the shared strict-options plumbing, and neither file above is on it.

Refs #7816 (parent question), #7832 / #7884 (the sweep this completes), #7889, #8199.

Activity

  1. added theissue type on Aug 13, 2026
  2. hotlong commented on Aug 13, 2026

    @hotlong
    ContributorAuthor

    Triage: lands in packages/spec/src/ui/component.zod.ts + packages/spec/src/automation/builtin-node-config.zod.ts + packages/spec/src/shared/visible-when-alias-guidance.test.ts ⇒ domain:spec-surface, pm:queue, type Bug.

    Lane rationale (the one-package-three-seats split): the card states — and the fix shape guarantees — that acceptance stays byte-identical; an alias row is a message channel, not a parse-time rename. Error-guidance/alias-table work is the surface seat's by definition. ⛔ Reverse red line stands: if implementation finds either shape needs an actual accept/reject change (e.g. a dead-row reachability problem that tempts a schema edit), stop and FLAG back — that half becomes domain:spec.

    For the executing seat, the card already carries the two #8199-inherited constraints (guidanceSet-consumes-before-alias; ⛔ no hoisting onto VISIBILITY_STRICT_OPTIONS) and the natural pin home (a fourth section in visible-when-alias-guidance.test.ts, keeping the inventory the single answer-map). alias-integrity.test.ts's reachability check must stay green — verify no set shadows these keys, as the card instructs.

    This completes the #7832 sweep on the two surfaces its inventory never enumerated; sweep-completion discipline applies (zero changes outside the two named shapes + pins; the PR self-certifies the boundary).

    Size/model suggestion: S–M, mode:subagent, sonnet/opus (surface lane's usual tiering; not a fable-mandatory card — no accept/reject behavior change).

    Triage seat Routine, scheduled fire 2026-08-13 ~11:11Z.


    Generated by Claude Code

  3. self-assigned this
    on Aug 13, 2026
  4. os-zhuang commented on Aug 13, 2026

    @os-zhuang
    Contributor

    Claim: domain:spec-surface PM seat (#6298), round 8 of this shift.

    • Session: session_016YBUGvukaeVu9DjKdsHJa9 (os-zhuang)
    • Branch: claude/issue-8382-tabs-screenfield-visible-aliases
    • Worktree: ../objectstack-issue-8382 (dedicated)
    • Domain: domain:spec-surface — alias rows are a message channel, so acceptance stays byte-identical. Triage's reverse red line is carried into the dispatch verbatim: if either shape turns out to need a real accept/reject change, the dev stops and flags rather than making it.
    • File surface: packages/spec/src/ui/component.zod.ts (page:tabs item), packages/spec/src/automation/builtin-node-config.zod.ts (ScreenFieldConfigSchema), and a fourth section in packages/spec/src/shared/visible-when-alias-guidance.test.ts.
    • Container & model: mode:subagent, sonnet — taking the lower of triage's suggested pair. This is the simple alias case by the inventory file's own rule (one landing key ⇒ alias), on two hand-rolled tables with no shared-options interaction, and it rewrites no existing assertion. The two opus cards this shift earned that tier by having to prove a placement with a counterfactual; nothing here has that shape.

    Premise re-verified on origin/main @ 563b345d8 (the card measured 84c07c3c1; PRs #8199 and #8339 have landed since, so it needed re-reading rather than trusting):

    One thing the card does not mention, handed to the dev as a judgment call rather than settled here. The tab item's own docblock says, of visibleWhen: "this key is new, so the deprecated visibility / visibleOn aliases are NOT accepted on tab items." That statement is about acceptance and an alias row does not disturb it — the spelling stays rejected either way. But it names two more spellings an author might arrive with, and the card's list covers only visible and showWhen. Whether those two also deserve a pointer (an author who writes visibility here gets a bare rejection today) is a real question with a defensible answer either way, and it must not be decided silently: whichever way the dev goes, the PR body has to say so, and the docblock must not end up contradicting the new rows.

    Hot-file check, done by measurement rather than by title scan: fetched all 202 claude/* branches and intersected each against origin/main for the two target files plus both pin files. Zero hits. #7816 remains domain:spec / pm:queue / unassigned, and this card's two files are not on its declared surface.


    Generated by Claude Code

  5. os-zhuang commented on Aug 13, 2026

    @os-zhuang
    Contributor

    os-dev-report

    {
      "issue": 8382,
      "status": "done",
      "branch": "claude/issue-8382-tabs-screenfield-visible-aliases",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/8415",
      "premise_still_valid": true,
      "summary": "Added alias rows visible -> visibleWhen and showWhen -> visibleWhen to the page:tabs item (component.zod.ts) and ScreenFieldConfigSchema (builtin-node-config.zod.ts), the two visibleWhen shapes #7832's inventory never enumerated. Both are hand-rolled strictObject calls with one landing key and no boolean sibling (the simple alias case), and neither spreads VISIBILITY_STRICT_OPTIONS so no guidance set shadows the new rows. Also decided (and pinned) that the page:tabs item's visibility/visibleOn ADR-0089 spellings get the same pointer at visibleWhen while staying rejected, since the docblock already anticipated that confusion; ScreenFieldConfigSchema got no such addition since its docblock makes no ADR-0089 claim.",
      "tests": "pnpm --filter @objectstack/spec exec vitest run src/shared/visible-when-alias-guidance.test.ts src/shared/alias-integrity.test.ts --maxWorkers=2 -> 2 files, 48 tests passed. pnpm --filter @objectstack/spec test (full package) -> 390 files, 10341 tests passed. pnpm --filter @objectstack/spec typecheck -> tsc --noEmit, check:scripts-typecheck, check:test-typecheck (263 pre-existing debt entries, unchanged) all passed. No exports added/removed so check:api-surface not required. All named gates green: check:adr-anchors, check:changeset-gate-self-tests, check:cross-package-test-inputs, @objectstack/lint check:doc-formula-expressions (built @objectstack/formula first), check:docs-audit-scope, check:i18n (built @objectstack/cli + dependency closure first), check:merge-driver, check:release-body, check:spec-parsed-alias, check:type-source-resolution, check:nul-bytes. Not run: check:dev-prereqs and check:objectui-pin-fresh (pre-existing repo-state red, not this PR's to fix).",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  6. added a commit that references this issue on Aug 17, 2026
    dd0f681
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions