Skip to content

features.aiStudio is read inline at two call sites while features.marketplace has an accessor — one fail-open doctrine, two spellings #5577

Description

@os-sales

Observation filed while implementing #5521 (PR #5575). Not a defect today — both spellings are currently correct. Filed because the asymmetry is the kind that grows a third spelling.

What is there

packages/app-shell/src/runtime-config.ts gives features.marketplace a documented accessor:

exportfunctionisMarketplaceEnabled(): boolean{returncurrent.features?.marketplace!==false;}

Its docblock is where the fail-open doctrine is written down — "Fails OPEN (!== false): a runtime predating /api/v1/runtime/config, or one whose config fetch failed, keeps the default true" — plus the "never infer this from the shape of a failure" warning.

features.aiStudio has no such accessor. It is read inline at two call sites:

Why it is worth recording

The two inline reads are not identical, and the difference is not cosmetic. ChatDock's omits the optional chain on features. PR #5575 measured that features is genuinely absent on real code paths — four sibling Home suites mock getRuntimeConfig as getRuntimeConfig: () => ({ branding: … }), and hosts may supply a partial snapshot the same way. Reading .aiStudio off undefined there is a TypeError, not a fail-open; in #5575 the un-chained form crashed 29 tests across 4 suites before it was corrected.

Whether ChatDock can actually reach that state was not investigated — its own tests pass today, so this is a latent shape rather than a live bug, and it should be measured rather than assumed either way before anyone edits it.

The second cost is that the fail-open doctrine for aiStudio is written down nowhere. A reader at either call site sees !== false with no explanation of why it is not === true, and the next person adding a third reader has no canonical form to copy.

Shape of a fix

An isAiStudioEnabled() sibling next to isMarketplaceEnabled(), carrying the same docblock treatment, with both call sites moved onto it.

Why PR #5575 did not do it

Adding the export means teaching four neighbouring Home suites' module mocks about it — they mock ../../../runtime-config with an explicit factory, so any new export they do not list is undefined at the call site. That is four extra files outside the card's declared surface, for a refactor its card did not ask for. The trade is recorded in a code comment at the new call site rather than left implicit.

Refs


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions