Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .changeset/root-entry-nameability-data-delta.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
---
"@objectstack/spec": minor
---

feat(spec): make `BaseValidationRuleShape` and `FilterCondition` nameable from the root entry (#11709)

Additive follow-up to the #11350 root-entry nameability fix, same invariant
(a type that appears structurally in an entry's public declarations must be
nameable from that same entry): a minimal consumer program with an
un-annotated `export default defineStack(...)` and **no** `@objectstack/spec/data`
import anywhere in its program still failed declaration emit with exactly two
TS2883 diagnostics — `BaseValidationRuleShape` and `FilterCondition`, both
mentioned structurally by `defineStack`'s return type but reachable only
through hash-named internal dist chunks. The root entry now re-exports both
types from their declaring `/data` modules (`data/validation.zod`,
`data/filter.zod`), exactly as #11350 did for `FormFieldInput` /
`NavigationItemInput` / `StateNodeConfig`. No runtime change; existing
consumers that already imported these names from `@objectstack/spec/data` are
unaffected.
2 changes: 2 additions & 0 deletions packages/spec/api-surface/root.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,7 @@
"BUILTIN_IDENTITY_PLATFORM_ADMIN (const)",
"BUILTIN_MEMBERSHIP_ROLES (const)",
"BUILTIN_MEMBERSHIP_ROLE_OPTIONS (const)",
"BaseValidationRuleShape (interface)",
"BuiltinIdentityName (type)",
"BuiltinMembershipRole (type)",
"CONVERSIONS_BY_MAJOR (const)",
Expand DownExpand Up@@ -58,6 +59,7 @@
"ExpressionSchema (const)",
"F (const)",
"FIELD_KEY_GUIDANCE (const)",
"FilterCondition (type)",
"FormFieldInput (type)",
"GUEST_POSITION (const)",
"LintableAuthoringCollection (interface)",
Expand Down
2 changes: 2 additions & 0 deletions packages/spec/export-origins/root.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,7 @@
"BUILTIN_IDENTITY_PLATFORM_ADMIN": "src/identity/eval-user.zod.ts#BUILTIN_IDENTITY_PLATFORM_ADMIN (const)",
"BUILTIN_MEMBERSHIP_ROLES": "src/identity/membership-role.ts#BUILTIN_MEMBERSHIP_ROLES (const)",
"BUILTIN_MEMBERSHIP_ROLE_OPTIONS": "src/identity/membership-role.ts#BUILTIN_MEMBERSHIP_ROLE_OPTIONS (const)",
"BaseValidationRuleShape": "src/data/validation.zod.ts#BaseValidationRuleShape (interface)",
"BuiltinIdentityName": "src/identity/eval-user.zod.ts#BuiltinIdentityName (type)",
"BuiltinMembershipRole": "src/identity/membership-role.ts#BuiltinMembershipRole (type)",
"CONVERSIONS_BY_MAJOR": "src/conversions/registry.ts#CONVERSIONS_BY_MAJOR (const)",
Expand DownExpand Up@@ -58,6 +59,7 @@
"ExpressionSchema": "src/shared/expression.zod.ts#ExpressionSchema (const)",
"F": "src/shared/expression.zod.ts#F (const)",
"FIELD_KEY_GUIDANCE": "src/data/authoring-key-lint.ts#FIELD_KEY_GUIDANCE (const)",
"FilterCondition": "src/data/filter.zod.ts#FilterCondition (type)",
"FormFieldInput": "src/ui/view.zod.ts#FormFieldInput (type)",
"GUEST_POSITION": "src/identity/position.zod.ts#GUEST_POSITION (const)",
"LintableAuthoringCollection": "src/kernel/metadata-authoring-lint.ts#LintableAuthoringCollection (interface)",
Expand Down
26 changes: 17 additions & 9 deletions packages/spec/scripts/root-entry-type-nameability.pin.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,15 +36,23 @@
* measured that a program file importing a subpath entry makes that entry's
* names NAMEABLE program-wide. `context.ts` reproduces that, which is what
* scopes this pin to the ruled three (ui/automation names, reachable only
* via the root re-exports under pin). Measured against this same dist: the
* MINIMAL one-file program leaks two MORE names through `/data`
* (`BaseValidationRuleShape`, `FilterCondition`) that the fixed root entry
* still cannot name — deliberately NOT pinned here; that is #11350's
* recorded premise delta, filed as #11709 for its own ruling. For the same
* reason the program contains no `@objectstack/spec/ui` or `/automation`
* import and no direct `import type { FormFieldInput, … }` — any of those
* would mask the very symptom under pin. Direct existence of the three root
* exports is owned by `api-surface/root.json` + `check:api-surface` instead.
* via the root re-exports under pin). Measured against the #11350 dist: the
* MINIMAL one-file program leaked two MORE names through `/data`
* (`BaseValidationRuleShape`, `FilterCondition`) that the #11350 root entry
* still could not name — #11350's recorded premise delta, filed as #11709
* and ruled the same way (maintainer decision 2026-08-25: A′): the root
* entry now re-exports both from their declaring `/data` modules. Re-run of
* #11709's measurement: pre-fix, this same program minus `context.ts`
* produced exactly 2 × TS2883 (`BaseValidationRuleShape` via the
* `object.zod-*` dist chunk, `FilterCondition` via `filter.zod-*`);
* post-fix it is clean, so `context.ts` no longer masks any known leak —
* it stays because the pin's charter is the REAL consumers' program shape,
* and a follow-up gate for entry-complete nameability (all entries, no
* fixture scoping) is #11986's remit, not this pin's. The program still
* contains no `@objectstack/spec/ui` or `/automation` import and no direct
* `import type { FormFieldInput, … }` — any of those would mask the very
* symptom under pin. Direct existence of the five root re-exports is owned
* by `api-surface/root.json` + `check:api-surface` instead.
*
* - **canary** — the anti-phantom probe. TS2883 is a DECLARATION-EMIT
* diagnostic: drop `declaration: true` from the harness profile and the
Expand Down
8 changes: 8 additions & 0 deletions packages/spec/src/index.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -145,6 +145,14 @@ export { defineSkill } from './ai/skill.zod';
export type { FormFieldInput } from './ui/view.zod';
export type { NavigationItemInput } from './ui/app.zod';
export type { StateNodeConfig } from './automation/state-machine.zod';
// [#11709] #11350's recorded premise delta, ruled the same way (maintainer
// decision 2026-08-25, recorded on #11709): the MINIMAL one-file consumer —
// no `/data` subpath import anywhere in its program — leaks two more
// structural mentions of `defineStack`'s return type that the three lines
// above do not cover. Same invariant, same fix shape: re-export from the
// declaring module (both already public on `/data`).
export type { BaseValidationRuleShape } from './data/validation.zod';
export type { FilterCondition } from './data/filter.zod';

// DX factories for the remaining authoring domains (issue #2035) — one type-safe
// entry per writable domain, mirroring the 19 factories above. `defineX` is a
Expand Down
Loading