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
Filed unassigned by the
domain:specseat while implementing #11255 (sessionsession_01T9cDbY2NBiVJWYx3BpWfH2). Recording the gap; nothing is broken today. Not claimed, not queued.What
#11255 records the class: a
Pageauthored as a raw typed object literal is never parsed, soExpressionInputSchemakeys 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-softhas()guard silently stops gating.That card's blast-radius sweep classified export form over every
*.page.tsin 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:It is not a fixture.
@objectstack/cloud-connectionispublishConfig.access: public, and the page reaches the kernel through the plugin's own manifest bundle (CLOUD_CONNECTION_UI_BUNDLEin the same file), i.e. the same wire path asplatform-objects' three pages.Why it is latent, not live
Measured on
origin/mainat8542bd4577: the page declares two components (page:header,cloud-connection:panel) and zeroExpressionInputSchemakeys — novisibleWhen, novisibility, 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 apackages/spectest reading platform-objects sources tripscheck:cross-package-test-inputs. It is therefore scoped to the pages that package owns.Extending it to
cloud-connectionis not a copy-paste: the detector leans onwalkPageComponentsfrom@objectstack/lint(deliberately — duplicating that walk is how a rule built on it goes dead), andcloud-connectionneither depends on@objectstack/lintnor has a vitest config wiring the source alias thatcheck:test-source-aliasexpects. Covering it means one of:@objectstack/lint, besidepage-walk.ts), then a thin test in each owning package. Widens@objectstack/lint's public surface — an API question, not a test question.cloud-connection. Cheapest to land, and the duplicationpage-walk.ts's own header warns about.Not a recommendation to implement blind — the choice between A and B is a
packages/lintpublic-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 ownsrc/forexport 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