Skip to content

Commit 08e38c6

Browse files
claude[bot]claude
andauthored
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>
1 parent bccf311 commit 08e38c6

1 file changed

Lines changed: 105 additions & 0 deletions

File tree

scripts/check-changeset-no-major.mjs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,63 @@ export function render(result) {
918918
// merged PR, the thing it exists to find. ⛔ That count is a reading for the
919919
// maintainer, never an argument for a tolerance: there is no allowlist and no
920920
// 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.
921978

922979
/**
923980
* The compiled-source root whose movement makes a package's PUBLISHED surface
@@ -931,6 +988,26 @@ export function render(result) {
931988
* this axis outright, and print a tick while doing it: the exact shape #16692
932989
* and #16713 both document. ⇒ The packed set is the reason for a SECOND leg
933990
* 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.
9341011
*/
9351012
const PUBLISHED_SOURCE_ROOT = 'src';
9361013

@@ -3198,6 +3275,34 @@ function selfTest() {
31983275
'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',
31993276
);
32003277

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.
3290+
const noManifest = () => null;
3291+
assert(
3292+
JSON.stringify(publishedSourceOwners('packages/rest/src/rest-route-ledger.ts', noManifest)) === '["packages/rest"]',
3293+
'#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',
3294+
);
3295+
assert(
3296+
JSON.stringify(publishedSourceOwners('packages/rest/src/rest-route-ledger.test.ts', noManifest)) === '["packages/rest"]',
3297+
'#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.
3301+
assert(
3302+
JSON.stringify(publishedSourceOwners('packages/rest/rest-route-ledger.ts', noManifest)) === '[]',
3303+
'#16985 control: the same file name outside `src/**` is owned by nobody — the two rows above are about `src/**`, not about the name',
3304+
);
3305+
32013306
// ── End to end, on real temp git repositories ─────────────────────────
32023307
const manifestJson = (bin) => JSON.stringify({ name: CLI, version: '0.0.0', files: ['dist', 'README.md'], bin });
32033308
const levelOf = ({ dir, base }) => {

0 commit comments

Comments
 (0)