@@ -145,6 +145,33 @@ export class RegistryUnreadable extends Error {}
145145// Unmapped is legal and is itself reported: a prerelease pin with no recorded
146146// revert plan is the #5024 shape again, and saying so is cheaper than
147147// discovering it later.
148+ //
149+ // THE RULE FOR A NOTE: carry the ACTION, point at the PIN for the MEASUREMENT.
150+ // -----------------------------------------------------------------------------
151+ // A note's job is to tell its reader what to DO. It must not restate a fact
152+ // that is measured and written down somewhere else -- above all not a COUNT.
153+ // The SCIM model set is measured in the `@better-auth/scim` block of
154+ // `pnpm-workspace.yaml`; this note used to carry its own typed copy of that
155+ // measurement ("all six new models present"), which is a second copy with
156+ // nothing holding it to the first.
157+ //
158+ // It rotted exactly the way a second copy rots. The measurement was re-taken
159+ // and corrected in the pin comment (#11372, #11764) and the copy here went on
160+ // printing the old number on every nightly run -- to the single reader this
161+ // probe exists to inform, at the moment they have the least context. #11761
162+ // deleted the copy rather than correcting it a second time: a correction would
163+ // have left a third copy waiting to rot.
164+ //
165+ // Deriving the number here instead was considered and measured as impractical:
166+ // the count lives in a `#` comment, which `readOverrides` skips by design, and
167+ // that block states three different counts (the core set, what
168+ // `managedConnections` adds, and the total). A regex over wrapped English prose
169+ // would have to GUESS which one a note meant -- a tolerant reader of an
170+ // unspecified producer, which is the shape this repo removes rather than adds.
171+ // So the note points, and the pin comment stays the single source.
172+ //
173+ // `restatedModelCounts()` mechanizes the COUNT half of this rule -- the half
174+ // that has demonstrably rotted -- and the self-test proves it can still fail.
148175// ---------------------------------------------------------------------------
149176
150177/** @type {Array<{ match: RegExp, issues: string[], note: string }> } */
@@ -158,10 +185,12 @@ const FOLLOW_UPS = [
158185 note :
159186 'SCIM is a MIGRATION, not a bump (#3653): rc.2 replaced the model set and moved ' +
160187 'connections from runtime rows to boot config, and the STABLE 1.7 releases ship that ' +
161- 'same rewrite (measured on the 1.7.1 tarball: no scimProvider model, no generate-token ' +
162- 'endpoint, all six new models present). Do the migration against the stable models — ' +
163- 'do not "align" this pin with the family first. #3002 moved the REST of the family to ' +
164- 'stable ^1.7.1 and left this pin behind deliberately, so #3653 is the only card left.' ,
188+ 'same rewrite. That rewrite is measured against the published tarball and written ' +
189+ 'down ONCE, in the `@better-auth/scim` block of pnpm-workspace.yaml — read it there ' +
190+ 'for which models the stable line ships, what it dropped, and what `managedConnections` ' +
191+ 'adds. Do the migration against the stable models — do not "align" this pin with the ' +
192+ 'family first. #3002 moved the REST of the family to stable ^1.7.1 and left this pin ' +
193+ 'behind deliberately, so #3653 is the only card left.' ,
165194 } ,
166195 {
167196 match : / ^ ( b e t t e r - a u t h | @ b e t t e r - a u t h \/ .+ ) $ / ,
@@ -180,6 +209,28 @@ export function followUpFor(pkg) {
180209 return FOLLOW_UPS . find ( ( f ) => f . match . test ( pkg ) ) ?? null ;
181210}
182211
212+ /**
213+ * The ledger rule above, mechanized for the half that rots: a note may not
214+ * state a COUNT of upstream models. Version numbers and issue refs are stripped
215+ * first — `1.7.1` and `#3653` are identifiers, not counts of anything, and a
216+ * guard that reddens on them would be turned off rather than obeyed.
217+ *
218+ * @returns {string[] } every offending fragment; empty means the note obeys.
219+ */
220+ export function restatedModelCounts ( note ) {
221+ const prose = String ( note )
222+ . replace ( / # \d + / g, '' )
223+ . replace ( / \b r c \. \d + \b / gi, '' )
224+ . replace ( / \b \d + (?: \. \d + ) + (?: - [ 0 - 9 A - Z a - z . ] + ) ? \b / g, '' ) ;
225+ const CARDINAL =
226+ '(?:\\d+|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve)' ;
227+ const re = new RegExp (
228+ `\\b${ CARDINAL } \\b[^.]{0,40}?\\bmodels?\\b|\\bmodels?\\b[^.]{0,40}?\\b${ CARDINAL } \\b` ,
229+ 'gi' ,
230+ ) ;
231+ return prose . match ( re ) ?? [ ] ;
232+ }
233+
183234// ---------------------------------------------------------------------------
184235// Reading the pins
185236// ---------------------------------------------------------------------------
@@ -636,6 +687,41 @@ function selfTest() {
636687 'the rest of the family carries a follow-up card too' ,
637688 watch . find ( ( w ) => w . name === 'better-auth' ) . followUp . issues . join ( ) === '#3653' ,
638689 ) ;
690+
691+ // --- 1b. the ledger rule: a note points at the pin, it does not restate it -
692+ // Two correction rounds found one copy each and left the other (#11372 fixed
693+ // the pin comment, #11761 the note). What forbids a third copy is this check,
694+ // not the memory of those rounds.
695+ const restated = FOLLOW_UPS . flatMap ( ( f ) =>
696+ restatedModelCounts ( f . note ) . map ( ( m ) => `${ f . match . source } -> "${ m . trim ( ) } "` ) ,
697+ ) ;
698+ check (
699+ 'no follow-up note restates a model COUNT (the pin comment is the single source)' ,
700+ restated . length === 0 ,
701+ restated . join ( ' | ' ) ,
702+ ) ;
703+ check (
704+ 'the scim note routes its reader to that single source BY NAME' ,
705+ followUpFor ( '@better-auth/scim' ) . note . includes ( 'pnpm-workspace.yaml' ) ,
706+ followUpFor ( '@better-auth/scim' ) . note ,
707+ ) ;
708+ // Positive control. A guard that cannot fail is not a guard, and the zero
709+ // above is only worth reading next to this one: the exact wording #11761
710+ // deleted, kept here verbatim so the check can never quietly become a no-op.
711+ check (
712+ 'the count guard FIRES on the exact wording this ledger used to print' ,
713+ restatedModelCounts (
714+ 'the STABLE 1.7 releases ship that same rewrite (measured on the 1.7.1 tarball: no ' +
715+ 'scimProvider model, no generate-token endpoint, all six new models present).' ,
716+ ) . length > 0 ,
717+ ) ;
718+ // Negative control: a version is an identifier, not a count. A guard that
719+ // reddened on `1.7.1` next to `models` would be switched off, not obeyed.
720+ check (
721+ 'the count guard does NOT fire on version numbers or issue refs' ,
722+ restatedModelCounts ( 'the models changed in 1.7.1, again in rc.2, tracked by #3653' )
723+ . length === 0 ,
724+ ) ;
639725 check (
640726 'a prerelease pin with no declared follow-up is watched anyway (unmapped is legal)' ,
641727 buildWatchList ( readOverrides ( "overrides:\n 'nobody@<2.0.0-rc.1': '2.0.0-rc.1'\n" ) ) . length === 1 ,
0 commit comments