Skip to content

Commit 1c753da

Browse files
os-steveclaude
andauthored
fix(devx): stop the scim follow-up note from restating the model count (#11761) (#11795)
The `@better-auth/scim` entry in the FOLLOW_UPS ledger carried its own typed copy of a measurement that lives in `pnpm-workspace.yaml`'s pin comment. The copy said "all six new models present"; the pin comment now says seven. Because this string is printed verbatim by the nightly probe, the stale number was emitted on every run, to the one reader the probe exists to inform. The class here is one measurement written down twice with nothing holding the copies together, so this does not re-type the number: - the note now points at the `@better-auth/scim` block of pnpm-workspace.yaml and states no count of its own; - the ledger's header records the rule a note must follow — carry the ACTION, point at the PIN for the MEASUREMENT — and why deriving the count instead was measured as impractical (it sits in a `#` comment `readOverrides` skips, and that block states three different counts); - `restatedModelCounts()` mechanizes the count half of that rule, and the self-test carries a positive control (the exact deleted wording, which must still trip the guard) and a negative control (version numbers and issue refs, which must not). The pin itself is untouched: moving it is still the ADR-0071 migration. Claude-Session: https://claude.ai/code/session_e2eac1a7-8000-5c95-9749-38aec2ace6fc Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent cb954f1 commit 1c753da

1 file changed

Lines changed: 90 additions & 4 deletions

File tree

scripts/check-prerelease-pin-watch.mjs

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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: /^(better-auth|@better-auth\/.+)$/,
@@ -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(/\brc\.\d+\b/gi, '')
224+
.replace(/\b\d+(?:\.\d+)+(?:-[0-9A-Za-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

Comments
 (0)