You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(gates): measure the changeset LEVEL axis's src/** over-read, and pin the proxy as a decision (#17224)
The LEVEL axis reads "did this PR grow the package's published surface?" from
where the changed file lives. That proxy over-reads, and the gap was filed
without a rate. Measured over the axis's whole life -- born c3b63f7
(2026-09-06), 449 commits landed, 233 of them introducing a changeset entry and
moving a package the axis calls grown:
* the over-read is common: 50 of 358 (package, PR) pairs, 14.0%
* its cost is zero: not one false refusal, with the declaration forced to
`yes` on every PR, and `refusable` is computed before the declaration is
read, so the same zero covers the NOT MEASURED lane
* the instance the card was filed on no longer refuses either -- it reads
`discharged` at exit 0 under the rule that landed after it
So neither remedy is bought, and no verdict changes here. The cheaper remedy
that was left open -- exempt a file no entry point re-exports -- is separately
recorded as measured UNSOUND: it holds only for a bundled build, and
packages/cli emits its whole program, so a module nothing imports still ships.
An instrument that skipped that distinction reported twelve false refusals for
that package which reading the build mode collapsed to zero.
Three self-test rows pin the proxy as a decision, with a nonsense control, so
that exempting unreachable files costs a deliberate deletion and a fresh rate.
Claude-Session: https://claude.ai/code/session_012GKcPZbMoGq7WPzKLfRBTU
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: scripts/check-changeset-no-major.mjs
+105Lines changed: 105 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -918,6 +918,63 @@ export function render(result) {
918
918
// merged PR, the thing it exists to find. ⛔ That count is a reading for the
919
919
// maintainer, never an argument for a tolerance: there is no allowlist and no
920
920
// grandfathering here, and the six are cleared by declaring, not by softening.
921
+
//
922
+
// ## THE LEVEL: `src/**` as a proxy for a public face — measured, left alone (#16985)
923
+
//
924
+
// Everything above decides WHICH packages this axis can see. This section is
925
+
// about what it then asserts about one: that a moved `packages/**/src/**` byte
926
+
// means the package's published surface grew. Those two facts do come apart —
927
+
// a module under `src/**` that no entry point reaches ships nothing at all —
928
+
// and #16985 filed the gap, correctly refusing to prescribe a repair before
929
+
// somebody produced a RATE. Its one instance (PR #16694, whose only `rest`
930
+
// change was `packages/rest/src/rest-route-ledger.ts`, a review record nothing
931
+
// imports) had an exit, and one instance is not a rate.
932
+
//
933
+
// MEASURED over the axis's WHOLE life, so the population is the thing itself
934
+
// rather than a sample of it: the axis was born at `c3b63f7add` (#16264,
935
+
// 2026-09-06) and 449 commits landed to `3c5f3c5991`, 233 of them introducing
936
+
// a changeset entry AND moving a package this axis calls «grown». Method as in
937
+
// the DEPTH note above — drive this file's own `scan`, `packagesTouched` and
938
+
// `judgeLevel` at each merge commit against its parent — with one reading added
939
+
// per package: does this diff ship anything? That question is answered from the
940
+
// build each package actually runs, never from the path (see
941
+
// `PUBLISHED_SOURCE_ROOT` for why the distinction is the whole ballgame).
942
+
//
943
+
// * THE OVER-READ IS COMMON. 50 of 358 (package, PR) pairs — 14.0%, spread
944
+
// across 37 of the 233 PRs — name a package the diff ships NOTHING for. 35
945
+
// of the 50 moved only `src/**/*.test.ts`, which a bundled package never
946
+
// emits; 12 moved only modules no entry point reaches; 3 moved both.
947
+
// * ITS COST IS ZERO, and that is the number that sizes the repair. 47 of the
948
+
// 50 never reach the offender list at all — the package is graded `minor`+,
949
+
// or is not graded. THREE do. Two of those sit beside a co-offender that
950
+
// genuinely ships (PR #17020, PR #17095), so the refusal is earned and the
951
+
// over-read costs a line in the message, not a verdict. The third is #16694
952
+
// itself, which on TODAY's rule reads `discharged` at exit 0: the
953
+
// `@objectstack/client: minor` in its own changeset discharges the PR under
954
+
// #16361, which landed after it. ⇒ Not one false refusal exists in the
955
+
// axis's entire history, including the instance the card was filed on.
956
+
// * THE ZERO IS DECLARATION-INDEPENDENT, which is what makes it a bound and
957
+
// not a coincidence of who declared what. It is measured with the
958
+
// declaration forced to `yes` on EVERY PR — the maximally exposed
959
+
// assumption, stronger than anything that actually happened — and
960
+
// `refusable` is computed before the declaration is consulted, so the same
961
+
// zero covers the `not-measured-material` lane too.
962
+
//
963
+
// ⇒ Triage sized the repair in advance: an exemption list if the false red is
964
+
// rare, an exported-surface reading if it is common. It is neither — it is
965
+
// ABSENT — so neither instrument is bought, and the proxy stands. #16361
966
+
// already took the half of this that was real by deleting the per-line claim
967
+
// from the rendering, which is why the residual is two noisy lines rather than
968
+
// a reader mistaking the pair for the finding.
969
+
//
970
+
// ⛔ This is a reading for the maintainer, never a verdict that the proxy is
971
+
// SOUND. It says the repair is unbought AT TODAY'S RATE. The shape that would
972
+
// buy it is named and still unobserved: a PR genuinely `Clause-②: yes` for
973
+
// package A that also moves a package-internal line under package B's `src/**`
974
+
// — there the author has no exit at all, because a carrier alone forces `yes`
975
+
// (see `declarationFromPullRequest`) and only the review seat can clear it. Two
976
+
// of the 128 refusable PRs already have the mixed offender shape; none has the
977
+
// declaration to go with it. ⇒ Re-measure before repairing, not instead of it.
921
978
922
979
/**
923
980
* The compiled-source root whose movement makes a package's PUBLISHED surface
@@ -931,6 +988,26 @@ export function render(result) {
931
988
* this axis outright, and print a tick while doing it: the exact shape #16692
932
989
* and #16713 both document. ⇒ The packed set is the reason for a SECOND leg
933
990
* below, never a replacement for this one.
991
+
*
992
+
* ⛔ Nor is the repair "exempt a file no entry point transitively re-exports",
993
+
* the cheaper alternative #16985 left open — MEASURED UNSOUND, and unsound by
994
+
* the same asymmetry that condemns the packed-set predicate. It holds only for
995
+
* a BUNDLED package: `tsup` builds from `src/index.ts`, so a module nothing
996
+
* reaches contributes no emitted byte. `packages/cli` does not bundle. It runs
997
+
* `tsc -p tsconfig.build.json`, which emits the whole `include` program, so a
998
+
* `src/**` file nothing imports STILL ships as its own `dist/*.js` — which is
999
+
* why that tsconfig carries an explicit `exclude` line for a review-record
1000
+
* module, and says in prose that its bundled siblings needed none. It is the
1001
+
* only whole-program public package here, 1 of 69, and one is enough: an
1002
+
* entry-graph exemption applied uniformly would turn this axis OFF for exactly
1003
+
* the package where it must not be, printing a GREEN — the expensive
1004
+
* direction, and the same failure #16692 and #16713 each landed to undo.
1005
+
*
1006
+
* ⚠️ That is measured rather than reasoned. While sizing #16985 an instrument
1007
+
* that skipped the build mode reported TWELVE false refusals for
1008
+
* `@objectstack/cli`; reading the build mode collapsed them to zero. An
1009
+
* exemption written from the same blind spot would have shipped that error as
1010
+
* a rule.
934
1011
*/
935
1012
constPUBLISHED_SOURCE_ROOT='src';
936
1013
@@ -3198,6 +3275,34 @@ function selfTest() {
3198
3275
'nonsense control on the superset run: a manifest under every ancestor must NOT make an ordinary file owned — otherwise the four rows above would hold for any input at all',
3199
3276
);
3200
3277
3278
+
// ── #16985: `src/**` is owned WITHOUT asking what re-exports it ────────
3279
+
//
3280
+
// These two rows are a DECISION, not an oversight, and they are here so
3281
+
// that undoing it costs a deliberate deletion. The over-read they pin is
3282
+
// real and was measured rather than denied — 14.0% of (package, PR) pairs
3283
+
// over the axis's whole life name a package the diff ships nothing for —
3284
+
// and it is KEPT because that over-read has never once changed a verdict
3285
+
// (zero false refusals, declaration-independent) and because the cheaper
3286
+
// repair is unsound for a whole-program build. Both readings, with their
3287
+
// method and their controls, are in the header; the unsoundness is at
3288
+
// `PUBLISHED_SOURCE_ROOT`. ⇒ An edit that exempts unreachable files must
3289
+
// delete these rows and bring a rate that buys the change.
'#16985: a module no entry point re-exports is owned all the same — the proxy is deliberate, and an entry-graph exemption is a false GREEN for a whole-program `tsc` package',
'#16985: a test file under `src/**` is owned too — 35 of the 50 measured over-reads are this shape, kept for the same reason and refused an exemption on the same evidence',
3298
+
);
3299
+
// Nonsense control on THIS pair, so the two rows above cannot be read as
3300
+
// "any path at all is owned": one segment over, nothing is.
0 commit comments