Commit 933ea61
feat(scripts,adr): a published TYPE-surface narrowing gets an honest ADR-0087 disposition — the sixth category, paid for by a base-side type reading (#13596)
* feat(scripts,adr): a published TYPE-surface narrowing gets an honest ADR-0087 disposition — the sixth category, paid for by a base-side type reading
`check-adr-0087-registration` had no disposition a published TYPE-surface
narrowing could answer honestly. Measured on the real #12104 shape, driven
through the shipping `scan()`: `registered` refuses (no id is new, and writing
one puts false data in the ledger), `unpublished` refuses (`@objectstack/client`
publishes), `no-migration-prescription` refuses (the body carries a FROM/TO
table), `runtime-interface-only` inherits that same refusal — and
`already-registered` is *admitted*, which is worse: the gate verifies the id
resolves and pre-dates the base, never that the entry covers the change, so the
only thing closing that door is the author's honesty.
The exit the gate names in its own refusal text is factually false for this
class, so the move that remained was to drop the `**BREAKING**` token. Four
changesets took it (#8140, #11925, #12034, #12104). A whole recurring class of
genuinely compile-breaking change was being nudged away from this repo's
breaking-change marker, purely because the marker routed it into a ledger it
does not belong in — invisibly, with every gate green.
## The sixth category
`not-required (type-surface-only <path>#<Symbol>)`, admitted on four predicates,
all four, named rather than counted (`TYPE_SURFACE_PREDICATES`):
published every bumped package really publishes — the exact
inverse of `unpublished`, same manifests.
no-spec-diff the diff touches no `packages/spec/**` path.
no-metadata-surface-diff the diff moves no `*.zod.ts`, no spec
`contracts/**` entry, no object definition.
narrowed-from-erased the named symbol reads `any` / `unknown` /
unannotated at the MERGE BASE and concrete at HEAD.
This is the only category exempt from the `no-migration-prescription` refusal.
The exemption is necessary — without it the gate still refuses the exact class
the category serves — and predicate 4 is what pays for it. Predicates 1-3 alone
were measured NOT to separate #6048 from #12104: both come out published, no
spec movement, no metadata surface. The prescription refusal is the only guard
holding #6048 out, so exempting a category from it while checking only 1-3 would
hand the founding case a green exit.
Predicate 4 refuses it on a positive, re-runnable reading rather than a detector
miss (the #8299 method): #6048's `ActorUser` is a concretely typed exported
interface at base that LOST a member; this class starts from `any`.
## Machinery
Reuses `parseSymbolRef` / `exportedTypeDeclaration`, per the ruling; no TS-aware
diff reader. One new sibling reader, `memberReturnAnnotation`, because three of
the four live instances narrow a METHOD RETURN and not an exported type — a
category that could not read that shape would be born unable to serve its own
population. It reads one named symbol in one file at one rev, and looks at no
diff. String and comment spans are masked through `js-comment-mask.mjs`.
## Coverage
+55 self-test assertions (237 -> 292): a red case for each of the four
predicates, each moving exactly ONE predicate off true; the all-four-true green;
the predicate set pinned BY NAME plus a pin that the exported names are the ones
`verifyTypeSurfaceOnly` actually evaluates; the exemption asserted both ways;
and the #6048 regression pin in two layers — a unit pin reading the REAL
`packages/runtime/src/security/actor-user.ts` out of this tree, and a scan-level
pin over a two-commit reconstruction of the #6048 diff.
The ADR half is inseparable: the vocabulary is pinned bidirectionally, and both
directions were re-measured on this branch. This PR touches a governed surface
and is deliberately left as a draft for a human merge.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
* fix(scripts): the type-surface-only fixture demonstrates its OWN subject, so its migration table stops reading as an SDK call site
The `type-surface-only` fixture's changeset body carried a real FROM/TO
migration table -- correctly, since this is the one ADR-0087 category exempt
from the prescription refusal -- but the table rewrote
`client.analytics.query`, a method the fixture neither declares nor names.
`TSO_REF` names `queryDataset` and `TSO_BASE_CLIENT` declares `queryDataset`,
so the table was prescribing a migration this fixture's diff does not ship.
That incoherence also ejected the PR from the merge queue.
`packages/client/src/envelope-caller-census.test.ts` walks the whole repo for
the four dispatcher-served SDK methods and masks COMMENTS ONLY -- never string
literals. The table is a string literal, so its two `analytics.query(`
spellings were counted as real SDK call sites and the census ledger went red
on a count it has no row for (expected 21 to be 19).
Aligning the table to the fixture's own symbol fixes both at once, and the
direction is the honest one for it: the `/analytics/dataset/query` route is
served bare by `@objectstack/rest`, so there is no envelope, `.data.rows` is a
spelling `Promise< any >` used to permit, and the new annotation refuses it --
a prescription the COMPILER delivers, which is exactly what this category is
for.
The fixture keeps a genuine migration table; nothing in the census, its
ledger, or the ADR was touched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 52ef672 commit 933ea61
2 files changed
Lines changed: 956 additions & 10 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
584 | 584 | | |
585 | 585 | | |
586 | 586 | | |
| 587 | + | |
587 | 588 | | |
588 | 589 | | |
589 | 590 | | |
| |||
592 | 593 | | |
593 | 594 | | |
594 | 595 | | |
595 | | - | |
596 | | - | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
597 | 599 | | |
598 | 600 | | |
599 | 601 | | |
| |||
667 | 669 | | |
668 | 670 | | |
669 | 671 | | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
| 704 | + | |
| 705 | + | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
| 720 | + | |
| 721 | + | |
| 722 | + | |
| 723 | + | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
0 commit comments