Observation filed while implementing #11986's gate. Filed unassigned, finding — this is a scope question for triage, not a defect report with an agreed fix.
#11986's gate probes the call surface: for each public entry it compiles export const c = E.<fn>(…) for every callable export and asserts the declaration emitter can name everything the result mentions. That is the shape all three decided instances took (#10868 → #11350 → #11709).
A second probe shape exists and was measured before the call shape was chosen: the plain reference, export const r = E.<name>; for every value export — which is what a consumer writes as export const mySchema = SomeSpecSchema; or when re-exporting a spec value. Measured on cdbd9204b65ae4ebec63f90f61669fb498efaa55, it finds 27 (entry, type) pairs across 11 of the 17 entries:
| entry | unnameable type(s) |
|---|
@objectstack/spec | NavigationItem, ObjectStackRawIssue |
@objectstack/spec/data | DerivationRule, FormField, IScopedContext |
@objectstack/spec/system | BaseValidationRuleShape, FilterCondition, FormField, FormFieldInput |
@objectstack/spec/kernel | NavigationItem, NavigationItemInput |
@objectstack/spec/ai | FilterCondition, FormField, StateNodeConfig |
@objectstack/spec/automation | FormField |
@objectstack/spec/api | BaseValidationRuleShape, FilterCondition, FormField, FormFieldInput, NavigationItem, NavigationItemInput, QueryAST, QueryInput |
@objectstack/spec/ui | FilterCondition |
@objectstack/spec/security | FormField |
@objectstack/spec/identity | FormField |
@objectstack/spec/shared | StrictObjectOptions |
The question for triage: is this in scope for the invariant? Reading the ruling literally (「a type that appears structurally in an entry's public declarations must be nameable from that same entry」) it is — these types do appear structurally, and a consumer that re-exports the value hits the same TS2883. Against that: no consumer has reported one, whereas the call class produced nine reported build failures and three maintainer decisions. Closing all 27 is 27 re-export lines across 11 barrels plus an api-surface/ regeneration, and it widens the public type surface of six entries that have no pull for it.
Two further measurements that bear on the decision, both from the same run:
- Five entries (
., /system, /api, /ui, /cloud) produce TS7056 under the reference shape — "the inferred type of this node exceeds the maximum length the compiler will serialize". Those probes are NOT MEASURED in either direction: the printer gives up before name resolution. So a reference-shape gate could not be made total the way the call-shape gate is; part of its surface is structurally unmeasurable with this instrument. - Cost: the reference shape measured ~105s across all entries versus ~42s for the call shape (~31–47s in the shipped gate).
Deliberately not decided in #11986's PR. Adding these 27 to that gate's ledger would have traded its one strong property — a ledger with a one-line repair for every row it carries — for a 27-row accommodation surface with no shrink plan, which is the debt-laundering shape the ledger exists to refuse. The gate's docblock says so explicitly, so a later author does not "extend" it by reflex.
If triage decides the class is in scope, the natural shape is a second gate (or a second probe mode) with its own ledger, not a widening of this one.
Related: #11986 (the call-shape gate), #12414 (the seven live call-shape leaks), #11709, #11350.
Observation filed while implementing #11986's gate. Filed unassigned,
finding— this is a scope question for triage, not a defect report with an agreed fix.#11986's gate probes the call surface: for each public entry it compiles
export const c = E.<fn>(…)for every callable export and asserts the declaration emitter can name everything the result mentions. That is the shape all three decided instances took (#10868 → #11350 → #11709).A second probe shape exists and was measured before the call shape was chosen: the plain reference,
export const r = E.<name>;for every value export — which is what a consumer writes asexport const mySchema = SomeSpecSchema;or when re-exporting a spec value. Measured oncdbd9204b65ae4ebec63f90f61669fb498efaa55, it finds 27 (entry, type) pairs across 11 of the 17 entries:@objectstack/specNavigationItem,ObjectStackRawIssue@objectstack/spec/dataDerivationRule,FormField,IScopedContext@objectstack/spec/systemBaseValidationRuleShape,FilterCondition,FormField,FormFieldInput@objectstack/spec/kernelNavigationItem,NavigationItemInput@objectstack/spec/aiFilterCondition,FormField,StateNodeConfig@objectstack/spec/automationFormField@objectstack/spec/apiBaseValidationRuleShape,FilterCondition,FormField,FormFieldInput,NavigationItem,NavigationItemInput,QueryAST,QueryInput@objectstack/spec/uiFilterCondition@objectstack/spec/securityFormField@objectstack/spec/identityFormField@objectstack/spec/sharedStrictObjectOptionsThe question for triage: is this in scope for the invariant? Reading the ruling literally (「a type that appears structurally in an entry's public declarations must be nameable from that same entry」) it is — these types do appear structurally, and a consumer that re-exports the value hits the same TS2883. Against that: no consumer has reported one, whereas the call class produced nine reported build failures and three maintainer decisions. Closing all 27 is 27 re-export lines across 11 barrels plus an
api-surface/regeneration, and it widens the public type surface of six entries that have no pull for it.Two further measurements that bear on the decision, both from the same run:
.,/system,/api,/ui,/cloud) produce TS7056 under the reference shape — "the inferred type of this node exceeds the maximum length the compiler will serialize". Those probes are NOT MEASURED in either direction: the printer gives up before name resolution. So a reference-shape gate could not be made total the way the call-shape gate is; part of its surface is structurally unmeasurable with this instrument.Deliberately not decided in #11986's PR. Adding these 27 to that gate's ledger would have traded its one strong property — a ledger with a one-line repair for every row it carries — for a 27-row accommodation surface with no shrink plan, which is the debt-laundering shape the ledger exists to refuse. The gate's docblock says so explicitly, so a later author does not "extend" it by reflex.
If triage decides the class is in scope, the natural shape is a second gate (or a second probe mode) with its own ledger, not a widening of this one.
Related: #11986 (the call-shape gate), #12414 (the seven live call-shape leaks), #11709, #11350.