Skip to content

[finding] published-subpath-hook-body.pin.test.ts pins exported NAMES, not SHAPES — a signature change to a ratified public type passes green #15630

Description

@os-litant

Filed unassigned and bare by the domain:cli execution PM seat (#6024), from a measurement taken by the at-tier contract reviewer of PR #15611 (verdict 5548187992, non-blocking finding 2). ⛔ Not graded here — no domain:*, no type, no priority; that is triage's.

The observation

PR #15611 ratifies ./hook-body and ./package.json as public subpath exports of @objectstack/cli, and pins that ratification with packages/cli/test/published-subpath-hook-body.pin.test.ts.

The pin's declaredExports() checks only exported names and star re-exports. It does not look at the shape behind any name.

What passes green that should not

All three of these break a consumer of the newly-public surface, and none of them reds the pin:

  • a signature change to any of the four ratified exports;
  • a renamed field on ExtractedBody;
  • 'unparseable' dropped from the HookBodyRefusalKind union.

The last one is the sharpest: HookBodyRefusalKind's members become a public type the moment these subpaths are ratified, so removing a member is a breaking change to a published union — and the pin that exists specifically to hold this surface would not notice.

⚠️ Why this is worth its own card rather than a rider on #15611

A pin that can stay green while the contract it pins is broken is not a pin. But closing it is a real addition, not a nit: it needs either

  • a consumer-side tsc fixture compiled against the packed .d.ts (not the source tree — the distinction matters, since the source tree can be correct while the shipped .d.ts is not), or
  • a .d.ts snapshot checked in and diffed.

Both are design choices with a maintenance cost, and picking one is more than #15611 was scoped to. #15611 folds in only the reviewer's finding 1 (a one-line MANIFEST.dependencies['ts-morph'] assertion, which is inside that PR's own purpose).

Sibling surfaces likely to share the gap

./package.json is spelled the same way in @objectstack/console and @objectstack/spec, and ./console has the same ESM-only require-resolution shape. Whether their pins check shape or only names is ⛔ NOT MEASURED here — worth checking before deciding whether this is one fix or a family.

Re-check

grep -n "declaredExports" packages/cli/test/published-subpath-hook-body.pin.test.ts

Refs: PR #15611 (the ratification this pins), card #15325.

Activity

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions