Skip to content

Commit 0d80862

Browse files
claude[bot]claude
andauthored
Attribute a version to its package across prose distance, and put content/docs behind the gate (#13981) (#14017)
`check:vendor-version-stamps` did not read `content/docs`, and adding the root alone was measured to be insufficient rather than merely weak: the one site that matters, a customer-facing attestation in `permissions/authentication.mdx`, still landed UNATTRIBUTED because the package name sits ~90 characters back across a wrapped prose line, past the character window attribution used. Attribution is now two rules, neither of them a width: a name reaches to the end of its SENTENCE (a blank line, a bullet, a heading, a JSX tag, a `.` or a `;` outside a parenthetical), and the NEAREST CLAIMANT wins — every package in the tree may claim, with the vocabulary read from `pnpm-lock.yaml`. Widening the old window instead was swept and rejected with numbers: at gap 120 it attributes 23 more sites and binds `better-call@1.3.7`, `@better-auth/utils@0.4.2`, `minimatch 10.2.3` and an internal `'0.0.0-polyfill'` sentinel to a watched family member none of them is about, and at 200 it reds a permanently true historical sentence. `--attribution-sweep` prints both mechanisms side by side. Attribution alone did not separate the docs population's two buckets, so the classifier gains one shape: an UNANCHORED MEASUREMENT — "measured on 1.7.1" resting a standing claim on a reading taken against a version that no longer installs, with nothing saying when. The rule is POSITIONAL, because a sentence-wide substring test reds "Measured on the configuration the range *does* govern (…), 1.7.1 behaves identically" — where the verb governs a configuration, not the version. The gate found six stamps the old attribution could not see. All six are repaired the way the gate itself teaches — the sentence is scoped or anchored, never restamped, so no measurement is manufactured. Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC Co-authored-by: Claude <noreply@anthropic.com>
1 parent 3b2a3f6 commit 0d80862

7 files changed

Lines changed: 724 additions & 63 deletions

File tree

‎content/docs/permissions/authentication.mdx‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -850,11 +850,12 @@ fallback: omit it and the member simply joins no team.
850850

851851
<Callout type="warn" title="This is an ObjectStack mount, not a better-auth route">
852852
better-auth declares `addMember` as a **server-only** API with no HTTP path of
853-
its own — measured on 1.7.1, where `addMember` builds its endpoint with no path
854-
argument while every sibling in the same module (`/organization/remove-member`,
855-
`/organization/list-members`, `/organization/leave`, …) passes one. So the
856-
vendor's documentation does not list this URL, and an audit that enumerates
857-
better-auth's mounted surface will not find it there either. ObjectStack mounts it ahead of the
853+
its own — measured on the then-installed 1.7.1, where `addMember` builds its
854+
endpoint with no path argument while every sibling in the same module
855+
(`/organization/remove-member`, `/organization/list-members`,
856+
`/organization/leave`, …) passes one. So the vendor's documentation does not
857+
list this URL, and an audit that enumerates better-auth's mounted surface will
858+
not find it there either. ObjectStack mounts it ahead of the
858859
catch-all and wraps the vendor's server-only endpoint; the vendor's own checks
859860
(already-a-member, membership limit, team resolution, hooks) are not
860861
reimplemented.

‎packages/cli/test/init.test.ts‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -388,13 +388,13 @@ describe('benign peer-skew declarations (#10326)', () => {
388388

389389
it('kept the @better-auth/utils widening when the better-call pin retired (#3653)', () => {
390390
// @better-auth/scim appeared in TWO entries for two unrelated reasons, and
391-
// they retire on different days — which HAPPENED: the better-call one went
392-
// with the rc pin (stable 1.7.1 peers better-call 1.4.0), while the utils
393-
// one outlives it (stable 1.7.1 still peers @better-auth/utils 0.4.2;
394-
// its own retirement key is the pnpm 10.31 floor). Deleting both together
395-
// — the obvious move when the rc pin lifted — would have silently put the
396-
// utils report back on a newcomer's first screen; this pin is what stops
397-
// that regression from ever landing quietly.
391+
// they retire on different days — which HAPPENED in #3653: the better-call
392+
// one went with the rc pin (stable 1.7.1 peers better-call 1.4.0), while
393+
// the utils one outlives it (stable 1.7.1 still peers @better-auth/utils
394+
// 0.4.2; its own retirement key is the pnpm 10.31 floor). Deleting both
395+
// together — the obvious move when the rc pin lifted — would have silently
396+
// put the utils report back on a newcomer's first screen; this pin is what
397+
// stops that regression from ever landing quietly.
398398
expect(SCAFFOLD_ALLOWED_PEER_VERSIONS['@better-auth/scim>better-call']).toBeUndefined();
399399
expect(SCAFFOLD_ALLOWED_PEER_VERSIONS['@better-auth/scim>@better-auth/utils']).toBe('0.5.0');
400400
});

‎packages/plugins/plugin-auth/src/admin-has-permission-endpoint.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ const isPlainObject = (v: unknown): v is Record<string, unknown> =>
105105

106106
/**
107107
* The permission-query bodies the installed vendor handler EVALUATES, and no
108-
* others (see the header for why both directions matter). Measured on
109-
* better-auth 1.7.1 (`dist/plugins/admin/routes.mjs`, `userHasPermission`):
108+
* others (see the header for why both directions matter). Measured on the
109+
* then-installed better-auth 1.7.1 (`dist/plugins/admin/routes.mjs`,
110+
* `userHasPermission`):
110111
*
111112
* - the zod body schema is `{ userId?: coerce.string, role?: string }`
112113
* intersected with `xor(permission | permissions)`, each a

‎packages/plugins/plugin-auth/src/auth-manager.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2101,9 +2101,10 @@ export class AuthManager {
21012101
// resolved `baseURL` origin and treats `trustedOrigins` as purely
21022102
// ADDITIVE, so an empty list and an omitted key are equivalent and
21032103
// both leave exactly the deployment's own origin trusted; every other
2104-
// origin is refused with `403 INVALID_ORIGIN`. Measured against
2105-
// better-auth 1.7.1 (`getTrustedOrigins` in `dist/context/helpers.mjs`,
2106-
// `validateOrigin` in `dist/api/middlewares/origin-check.mjs`).
2104+
// origin is refused with `403 INVALID_ORIGIN`. Measured against the
2105+
// then-installed better-auth 1.7.1 (`getTrustedOrigins` in
2106+
// `dist/context/helpers.mjs`, `validateOrigin` in
2107+
// `dist/api/middlewares/origin-check.mjs`).
21072108
if (
21082109
process.env.NODE_ENV !== 'production' &&
21092110
!origins.length && (!corsOrigin || corsOrigin === '*')

‎packages/plugins/plugin-auth/src/auth-plugin.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2556,7 +2556,7 @@ export class AuthPlugin implements Plugin {
25562556
// ────────────────────────────────────────────────────────────────────
25572557
// #9941 — organization/add-member. better-auth declares `addMember`
25582558
// WITHOUT an HTTP path (server-only `auth.api.addMember`; measured on the
2559-
// installed 1.7.1), so the catch-all never mounts it — yet the
2559+
// then-installed 1.7.1), so the catch-all never mounts it — yet the
25602560
// `sys_member` `add_member` toolbar action has always targeted this URL,
25612561
// and on a multi-org posture it is the only UI path that can attach an
25622562
// existing user to an organization. This mount restores that declared

‎packages/plugins/plugin-auth/src/organization-add-member.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* ── Why this mount exists (the measurement) ─────────────────────────────────
88
*
99
* better-auth declares `addMember` WITHOUT an HTTP path — measured on the
10-
* installed 1.7.1, `dist/plugins/organization/routes/crud-members.mjs`:
10+
* then-installed 1.7.1, `dist/plugins/organization/routes/crud-members.mjs`:
1111
* `addMember` returns `createAuthEndpoint({ method: "POST", ... })` (no path
1212
* argument), while its siblings keep theirs
1313
* (`createAuthEndpoint("/organization/remove-member", …)`,

0 commit comments

Comments
 (0)