Skip to content

check-adr-0087-registration refuses a runtime-interface-only disposition on a symbol named only in a JSDoc comment inside a .zod.ts #12881

Description

@hotlong

Found while implementing #12866 (ADR-0006 D2, SDK half). Filed unassigned.

What happens

check-adr-0087-registration.mjs's runtime-interface-only predicate (step 4 — "NO metadata surface REFERENCES it") counts a symbol that appears only inside a JSDoc prose comment of a metadata surface as a reference it cannot resolve, and refuses the disposition.

Reproduced on cae0e248c:

runtime-interface-only packages/client/src/index.ts#ObjectStackClient cannot be verified:
packages/spec/src/api/contract.zod.ts (a Zod schema) mentions `ObjectStackClient` while
neither declaring nor importing it:
  * `success`, which is what `ObjectStackClient.unwrapResponse` keys on and what
Unresolvable, so refused rather than assumed unrelated (#4690).

The "reference" is packages/spec/src/api/contract.zod.ts line 164 — a sentence inside the BaseResponseSchema docblock explaining what unwrapResponse keys on. It is prose. ObjectStackClient is not imported there, is not in any schema, and objectstack migrate meta has nothing to reach through it. Steps 1, 2 and 3 of the predicate all pass.

Why it matters

The refusal pushes an author toward not-required (no-migration-prescription), which for a changeset carrying a real before/after migration table is a self-contradiction — exactly the detector-miss anti-pattern the gate's own header records as #8299 and exists to close. So the blind spot converts an honest, nearly-verified disposition into pressure to claim a dishonest one.

It is currently the only .zod.ts in the repo that mentions ObjectStackClient (measured: git grep -ln ObjectStackClient -- '*.zod.ts' returns exactly that file), so the blast radius today is small — but the shape is general: any metadata surface whose docblock names a runtime type blocks that type's exemption.

Suggested direction (not a decision)

Strip comments before the step-4 scan, or treat a match that occurs only inside a comment as not-a-reference and say so in the refusal text. Both keep #4690's "refuse rather than assume unrelated" stance for real code references. The gate has a --self-test; a case for "named only in a docblock" belongs with it.

Evidence

  • Gate: scripts/check-adr-0087-registration.mjs, the runtime-interface-only block (~line 1671 onwards)
  • The blocking mention: packages/spec/src/api/contract.zod.ts:164
  • The changeset that hit it: .changeset/adr0006-d2-client-environments-namespace.md on branch claude/issue-12866-adr0006-d2-sdk-environments

Generated by Claude Code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions