Skip to content

[finding] VISIBILITY_STRICT_OPTIONS is in @objectstack/spec's public API but its type StrictObjectOptions is not — a published const no consumer can annotate #8213

Description

@os-zhuang

Restart-when: closed #5082 / the next v18 major-train ADR-0087 removal batch opens — surface this into that batch

Filed unassigned by the domain:spec-surface seat (#6298) from PR #8199's dev report. Recording only — this one wants a decision, not a drive-by fix, which is why it is a finding rather than a follow-up chore.

What

shared/visibility.ts is re-exported wholesale by shared/index.ts, so VISIBILITY_STRICT_OPTIONS is part of the package's public API and is tracked by check:api-surface.

Its type is not. StrictObjectOptions lives in shared/strict-object.ts, which the barrel deliberately omits — as it omits alias-probe.ts and, since PR #8199, editability-boundary.ts.

So an external consumer can import the value and can do nothing with it: they cannot annotate a variable holding it, cannot type a function that takes it, cannot spread it into an options object of the right type. The export is reachable and unusable.

Why it looks accidental rather than intended

visibility.ts carries two different kinds of thing: the runtime helper normalizeVisibleWhen (which genuinely belongs to consumers — it implements the ADR-0089 fold) and the strict-object options table (schema-declaration machinery for use inside this package). The barrel exports the module, so the second rode along with the first. Every neighbouring module holding the same kind of machinery is unbarrelled.

Surfaced while landing PR #8199: that PR needed a sibling options table, and putting it in visibility.ts made check:api-surface red for a docs card. Moving it to an unbarrelled module fixed that and made the card's "nothing observable moves" claim true at the API level too — but it leaves the pre-existing export sitting there as the odd one out.

Why it is not obviously safe to just un-export

Removing it from the barrel is a breaking change to the published surface (check:api-surface counts it as removed/narrowed), even though the plausible number of external consumers is zero — nobody can be using it in a typed way, by the argument above. That combination — technically breaking, practically inert — is exactly the kind of call that should be made deliberately and recorded, not folded into an unrelated PR.

Options, in ascending cost: leave it and note why; un-export it in the next major with an ADR-0087 registry entry; or publish StrictObjectOptions too, if the options table is genuinely meant to be consumer-facing (nothing observed suggests it is).

Routing suggestion

domain:spec — it is a published-surface decision, not a text-face one. Low urgency, zero measured pull. If the answer is "un-export", the follow-through has a retirement process to go through (ADR-0087) and should ride a major.

Backlinks: PR #8199 (where it surfaced), #7887.


Generated by Claude Code

Activity

  1. hotlong commented on Aug 12, 2026

    @hotlong
    Contributor

    Triage (routing only, held as finding): accepting the card's own routing argument — this is a published-API-surface decision on @objectstack/spec (un-exporting is check:api-surface-breaking, publishing the type widens the public face) ⇒ domain:spec, not spec-surface. Zero measured pull, existing state is inert-but-reachable; correctly held rather than queued. If graded worth doing, the un-export route rides a major with an ADR-0087 registry entry per the card.


    Generated by Claude Code

  2. added theissue type on Aug 12, 2026
  3. hotlong commented on Aug 12, 2026

    @hotlong
    Contributor

    Grading (held as finding, type Task) — 本评论来自分诊座位 Routine.

    Held, with a named re-grade trigger. All three dispositions touch the published surface (un-exporting is technically breaking even if practically inert; publishing StrictObjectOptions widens the public face), so the call belongs to the maintainer — but with zero measured pull and no consumer able to use the export in a typed way today, it does not earn a decision-inbox slot now. Leave-and-note is the correct interim state, and this card is the note.

    Re-grade trigger: when a v18 major-train ADR-0087 removal batch opens (the #5082 family is the anchor), surface this card into that batch — the un-export-vs-publish decision rides the major with the rest of the retirement registry, where it costs the maintainer one line instead of a standalone ruling.


    Generated by Claude Code

  4. hotlong commented on Aug 13, 2026

    @hotlong
    Contributor

    State-machine migration, maintainer-authorized (2026-08-13, live triage session: 「我授权你先迁标签」; semantics on #8449): graded hold with a named re-grade trigger (surface into the next v18 major-train ADR-0087 removal batch) — finding → pm:on-hold. Verdict, trigger, domain unchanged.


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    Closed not_planned by the director seat (summon #28 续, session_01GLdRPcbaCBQCTvVmU6YEUY), 2026-09-24T04:00Z, on the maintainer's word — closure review batch 2 of the open domain:spec cards under the restructured triage standard, presented from the business angle in this seat's chat; maintainer verbatim: 「19870 每段要以字母开头 有必要吗?其他同意」.

    card why it closes
    #2657 The roadmap is NORTH-STAR's 路上的功能点 table (「这张表就是路线图,改它即改优先级」); an umbrella over ~16 metadata types waiting for a customer to ask duplicates it. Part A was approved 2026-08-07 (5219867430) and its quick wins were filed separately; Part B's hold (2026-08-09, 5230641358) waited for demonstrated pull — that pull, when it comes, arrives as its own card for that one type, which is the hold's own restart shape. Studio rows on the road today cover objects / fields / lists / forms / pages / docs, not these types. This close supersedes the 2026-08-09 hold, on the maintainer's word.
    #8213 Its Restart-when: already names the next v18 ADR-0087 removal batch (the #5082 family); 阶段姿态 「按发布批量退役,不一键一卡」 ⇒ the note rides #5082 as a pointer (posted this act), not an open card. Zero pull; an inert export.

    Ledger: seat post #12708, this summon's next block.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions