Skip to content

A raw-literal Page also ships from @objectstack/cloud-connection — the *.page.ts sweep missed it, so #11255's gate does not reach it #11480

Description

@os-steve

Filed unassigned by the domain:spec seat while implementing #11255 (session session_01T9cDbY2NBiVJWYx3BpWfH2). Recording the gap; nothing is broken today. Not claimed, not queued.

What

#11255 records the class: a Page authored as a raw typed object literal is never parsed, so ExpressionInputSchema keys reach /api/v1/meta/pagebare instead of as the canonical { dialect: 'cel', source } envelope — and objectui routes bare predicates to its legacy evaluator, where a fail-soft has() guard silently stops gating.

That card's blast-radius sweep classified export form over every *.page.ts in the repo. The filename is not the discriminator. There is a fourth raw-literal page in a published platform package, in a file the sweep's glob never looked at:

packages/cloud-connection/src/cloud-connection-ui.ts:19
export const CloudConnectionSettingsPage: Page = { … }

It is not a fixture. @objectstack/cloud-connection is publishConfig.access: public, and the page reaches the kernel through the plugin's own manifest bundle (CLOUD_CONNECTION_UI_BUNDLE in the same file), i.e. the same wire path as platform-objects' three pages.

Why it is latent, not live

Measured on origin/main at 8542bd4577: the page declares two components (page:header, cloud-connection:panel) and zeroExpressionInputSchema keys — no visibleWhen, no visibility, no props-level predicate. So there is nothing bare to serve today. The hazard is the same one #11255 is about: the next predicate added to this page reproduces the defect exactly, with every authoring-time signal green.

Why #11255's gate does not cover it

The gate landed in packages/platform-objects (a test over that package's own exports) because a packages/spec test reading platform-objects sources trips check:cross-package-test-inputs. It is therefore scoped to the pages that package owns.

Extending it to cloud-connection is not a copy-paste: the detector leans on walkPageComponents from @objectstack/lint (deliberately — duplicating that walk is how a rule built on it goes dead), and cloud-connection neither depends on @objectstack/lint nor has a vitest config wiring the source alias that check:test-source-alias expects. Covering it means one of:

  • A. Give the detector a shared home (an exported helper in @objectstack/lint, beside page-walk.ts), then a thin test in each owning package. Widens @objectstack/lint's public surface — an API question, not a test question.
  • B. A second self-contained copy of the detector in cloud-connection. Cheapest to land, and the duplication page-walk.ts's own header warns about.
  • C. Leave it, on the grounds that this page has no predicates and the class is now gated where predicates actually live.

Not a recommendation to implement blind — the choice between A and B is a packages/lint public-API call.

Suggested scope if picked up

Whatever route, the population question is worth fixing at the same time: discover pages by export shape, never by filename. #11255's gate already does this inside platform-objects (it scans the package's own src/ for export const X: Page = declarations and asserts the barrel covers every one), which is what surfaced this page's siblings in the first place — the same scan pointed one package over would have caught this file on day one.


Generated by Claude Code

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions