Repository navigation
Commit 7be3cc7
fix(scripts): name-fold loader gate rule 2 resolves the fixtures directory, not one spelling of it (#24236)
Fixes #24050
Clause-②: no. A repo gate's internal matcher; `scripts/` ships in no
package, so nothing publishes (`skip-changeset`).
One file: `scripts/check-position-name-fold-loaders.mjs` (+164 / -33).
Branched from `main` at `6e43b7bc3f`; head `e1b31d6ba`.
## What changed
**Rule 2 resolves the guarded directory instead of matching one spelling
of it.** It used to count a file only when its text held the
repo-relative literal `packages/metadata/src/__fixtures__`. Now every
path spelling on a line carrying `__fixtures__` is folded (case; a
backslash read as `/`; `.`, `..` and `//` segments resolved) and read
two ways:
- **as written:** the folded spelling holds the directory's four
segments in a row. This covers a repo-relative path, `ROOT +
'/packages/…'`, a URL, a vendored prefix, and a climb that comes back
in;
- **from the file that holds it:** a relative spelling, joined to that
file's own directory, lands on the directory or under it.
Segments are compared, never substrings. So
`packages/services/service-metadata/src/__fixtures__` stays another
package's directory, even though it contains the string
`metadata/src/__fixtures__`. The literal substring check still runs
first, unchanged, so rule 2 counts every file it counted at BASE.
- `referencesArtifact(text, relPath)` now takes the holding file's
repo-relative path, and throws a `TypeError` without it. A caller that
dropped it would otherwise lose every relative climb with no error.
`scanTree` now computes `rel` before the call.
- Rule 3's "lies in the guarded directory" test
(`isOtherPackageFixturePath`) now uses the same folded comparison
(`liesInFixturesDir`), so the file has one definition of it. This
changes no verdict. A token that rule 3 sets aside holds only word
characters, `.`, `-` and `/`, and it sits between rule-3 delimiters,
which are all rule-2 delimiters too. So it is exactly one rule-2
spelling, and if its folded form lies in the guarded directory, rule 2
has already answered `true`.
- `classifyReference`'s `self` test is unchanged. It judges the real
path the walk returns, not a spelling.
- **The header's soundness sentence** (`:40`–`:51`, formerly
`:41`–`:43`) now says what the scan checks:
- the basename;
- a path that resolves to the directory once folded and joined to the
holding file's directory;
- `__fixtures__` with `hotcrm` or `.artifact` on one line.
It also says what the scan does not follow:
- a computed path: a concatenation, a `.replace`, a variable, or a base
other than the holding file's directory or the repo root;
- a wildcard in a directory segment with no marker on its line.
The rule-2 and rule-3 docblocks are updated to match.
## Self-test: 30 cases now 39; the matcher battery's floor goes from 20
to 29
There are nine new matcher cases. The existing cases now pass a holding
file (`PROBE_FILE = 'packages/objectql/src/loader.ts'`), and their
verdicts are unchanged. The roster and its floor (4) are unchanged.
| new case | expected | at BASE |
|---|---|---|
| relative climb `readdirSync(resolve(HERE,
'../../../metadata/src/__fixtures__'))`, held by
`packages/objectql/src/loaders/catalog.ts` | true | **false: red** |
| the same text, held by
`packages/services/service-metadata/src/loaders/catalog.ts` (it lands in
`packages/services/metadata/…`) | false | false |
| case variant `readdirSync('packages/Metadata/src/__fixtures__')` |
true | **false: red** |
| backslash-separated spelling of the directory (source text with
escaped backslashes) | true | **false: red** |
| `readdirSync('packages/services/service-metadata/src/__fixtures__')` |
false | false |
| `` `packages/objectql/src/__fixtures__/hotcrm-${kind}.artifact.json`
`` | true | true |
| `glob('packages/objectql/src/__fixtures__/hotcrm-?.artifact.json')` |
true | true |
| `glob('packages/objectql/src/__fixtures__/hotcrm-[ab].artifact.json')`
| true | true |
|
`glob('packages/objectql/src/__fixtures__/x-{a,hotcrm}.artifact.json')`
| true | true |
The "at BASE" column comes from feeding each new case's text and holding
file to BASE's own `referencesArtifact` (the `6e43b7bc3f` blob, which
ignores the file argument).
**Deviation from Acceptance 2, measured.** "Each must fail against
today's matcher" holds for the relative climb and the case variant (and
the backslash case). It is false for the four token-boundary cases:
today's matcher already answers `true` for all four. Record
`6225074650`'s probe measured the same ("the head handles all four").
Those four cases pin rule 3's path token running past `$`, `?`, `[` and
`{`. Their red is shown by legs L6 to L9 below: each leg cuts the token
at one of those characters, and only its own case goes red.
`{a,hotcrm}` sits in the middle of a name (`x-{a,hotcrm}`) on purpose.
Directly after `__fixtures__/`, a cut at `{` leaves a token ending in
`/`, and the literal-file test keeps such a token anyway, so the case
would pin nothing. The record found the old `${name}` case pins nothing
for the same reason.
## Ablations: each leg mutates the committed head, runs `--self-test`,
then restores
Each leg goes through `scripts/ablation-replace.mjs` in WRAP mode. Per
leg, it checks on disk that the anchor count went from 1 to 0 and that
the blob changed. It proves the restore by blob == HEAD (`5e94de5be75b`)
and an empty `git diff HEAD`. An outer `trap` also restores the absolute
path from HEAD. This is a root script, so there is no build or `dist/`
leg.
| leg | mutation | red cases (of 39) |
|---|---|---|
| L1 | rule 2 reverted to BASE (literal substring only) | 3: relative
climb, case variant, backslash |
| L2 | case fold off | 1: case variant |
| L3 | backslash fold off | 1: backslash |
| L4 | holder-relative reading deleted | 1: relative climb |
| L5 | segment run replaced by the bare substring
`metadata/src/__fixtures__` | 2: the service-metadata `false` case, and
the same climb from the other holder |
| L6 | path token cut at `$` | 1: the `${kind}` case |
| L7 | path token cut at `?` | 1: `hotcrm-?` |
| L8 | path token cut at `[` | 1: `hotcrm-[ab]` |
| L9 | path token cut at `{` | 1: `x-{a,hotcrm}` |
After the last leg: worktree blob `5e94de5be75b` equals the HEAD blob,
`git diff HEAD` is 0 bytes, and `git status --porcelain` is empty.
## The gate over the real tree, against BASE
A scratch probe imported both blobs and ran them over the same walk:
10246 files, worktree at `e1b31d6ba`.
- **Rule 2 at BASE counts 1 file:**
`scripts/check-position-name-fold-loaders.mjs`.
- **Rule 2 now counts 4 files:** that one, plus three tests in
`packages/metadata/src/`. Each names the directory by `join(HERE,
'__fixtures__/…')`, resolved from its own directory:
- `plugin-artifact-forward-conversion.test.ts`
- `plugin-artifact-forward-conversion-retired-after.test.ts`
- `plugin-unbound-form-predicate-roots.test.ts`
All three were already references through rule 1 or rule 3.
- **References: 8 at BASE and 8 now, the same set** (6 test, 2 declared
instrument, 0 loader). The gate reports no new reference on `main`.
- The gate prints: `has no non-test loader. 10246 file(s) scanned under
packages, examples, apps, scripts, tools, .github; 8 reference(s): 6
test, 2 declared instrument, 0 loader.`
- Gate wall time on this box is about 1.5 s, against about 1.3 s at
BASE.
## Verification, on head `e1b31d6ba`
- `node scripts/check-position-name-fold-loaders.mjs --self-test` exits
0: `✓ check-position-name-fold-loaders self-test: 39 cases pass.` At
BASE it exits 0 with 30 cases.
- `node scripts/check-position-name-fold-loaders.mjs` exits 0, with the
line quoted above.
- Gate families were derived by `node scripts/pm/dispatch-gates.mjs
--commands --repo objectstack-ai/objectstack` with no paths: 32
commands, the same 32 the seat derived. All 32 ran locally and exited 0,
`pnpm check:pm-dispatch-gates` included (`✓ dispatch-gates self-test
(fast tier): 1884 cases pass`).
- `--ran` reconciliation: `32 derived, 32 run, 0 NOT-MEASURED, 0 UNRUN`
(a derived zero; all 32 recorded an exit code).
- `pnpm exec eslint --no-inline-config` on the one file exits 0. The
repo-wide `pnpm lint` is CI's.
- The control-byte self-scan of the file found nothing.
## Acceptance notes
- **The `..` guard is still undiscriminated.** No case discriminates
rule 3's `..` guard, the first test in `isOtherPackageFixturePath`. The
card's Measured section names it, but its Acceptance does not ask for a
case. Now that rule 2 resolves climbs, a `..` token that lands in the
guarded directory is rule 2's. The guard only keeps a token that
normalises to another package's literal file, which is conservative and
not load-bearing. Observation; carrier: none (承接者:无).
- **A wildcard directory segment with no marker is still unseen.** An
example is `glob('packages/*/src/__fixtures__/*.json')`. The header now
says so. Reach: no file under the scan roots spells such a glob. Not
filed; carrier: none (承接者:无).
- **Rule 1 (the basename) is still case-sensitive.** The card excludes
rule-1 changes. A case-variant basename joined to a variable base is a
computed path, which the header already places outside. Observation;
carrier: none (承接者:无).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Nk17Z26X5DB59iQztDBADH)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 7715d04 commit 7be3cc7
1 file changed
Lines changed: 164 additions & 33 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
45 | 52 | | |
46 | 53 | | |
47 | 54 | | |
| |||
84 | 91 | | |
85 | 92 | | |
86 | 93 | | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
87 | 97 | | |
88 | 98 | | |
89 | 99 | | |
| |||
137 | 147 | | |
138 | 148 | | |
139 | 149 | | |
140 | | - | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
141 | 153 | | |
142 | 154 | | |
143 | 155 | | |
| |||
161 | 173 | | |
162 | 174 | | |
163 | 175 | | |
164 | | - | |
| 176 | + | |
| 177 | + | |
165 | 178 | | |
166 | 179 | | |
167 | 180 | | |
168 | 181 | | |
169 | 182 | | |
170 | 183 | | |
171 | | - | |
172 | | - | |
| 184 | + | |
| 185 | + | |
173 | 186 | | |
174 | 187 | | |
175 | 188 | | |
176 | 189 | | |
177 | 190 | | |
178 | 191 | | |
179 | 192 | | |
180 | | - | |
| 193 | + | |
181 | 194 | | |
182 | 195 | | |
183 | 196 | | |
184 | 197 | | |
185 | 198 | | |
186 | 199 | | |
187 | 200 | | |
188 | | - | |
189 | | - | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
190 | 266 | | |
191 | 267 | | |
192 | 268 | | |
| |||
231 | 307 | | |
232 | 308 | | |
233 | 309 | | |
234 | | - | |
235 | 310 | | |
| 311 | + | |
236 | 312 | | |
237 | 313 | | |
238 | 314 | | |
| |||
356 | 432 | | |
357 | 433 | | |
358 | 434 | | |
359 | | - | |
| 435 | + | |
360 | 436 | | |
361 | 437 | | |
362 | 438 | | |
| |||
430 | 506 | | |
431 | 507 | | |
432 | 508 | | |
433 | | - | |
434 | | - | |
435 | | - | |
436 | | - | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
437 | 517 | | |
438 | 518 | | |
439 | | - | |
| 519 | + | |
440 | 520 | | |
441 | 521 | | |
442 | 522 | | |
443 | 523 | | |
444 | | - | |
| 524 | + | |
445 | 525 | | |
446 | 526 | | |
447 | 527 | | |
448 | 528 | | |
449 | | - | |
| 529 | + | |
450 | 530 | | |
451 | 531 | | |
452 | 532 | | |
453 | 533 | | |
454 | | - | |
| 534 | + | |
455 | 535 | | |
456 | 536 | | |
457 | 537 | | |
458 | 538 | | |
459 | | - | |
| 539 | + | |
460 | 540 | | |
461 | 541 | | |
462 | 542 | | |
463 | 543 | | |
464 | | - | |
| 544 | + | |
465 | 545 | | |
466 | 546 | | |
467 | 547 | | |
468 | 548 | | |
469 | | - | |
| 549 | + | |
470 | 550 | | |
471 | 551 | | |
472 | 552 | | |
473 | 553 | | |
474 | | - | |
| 554 | + | |
475 | 555 | | |
476 | 556 | | |
477 | 557 | | |
478 | 558 | | |
479 | | - | |
| 559 | + | |
480 | 560 | | |
481 | 561 | | |
482 | 562 | | |
483 | 563 | | |
484 | | - | |
| 564 | + | |
485 | 565 | | |
486 | 566 | | |
487 | 567 | | |
488 | 568 | | |
489 | | - | |
| 569 | + | |
490 | 570 | | |
491 | 571 | | |
492 | 572 | | |
493 | 573 | | |
494 | | - | |
| 574 | + | |
495 | 575 | | |
496 | 576 | | |
497 | 577 | | |
498 | 578 | | |
499 | | - | |
| 579 | + | |
500 | 580 | | |
501 | 581 | | |
502 | 582 | | |
503 | 583 | | |
504 | | - | |
| 584 | + | |
505 | 585 | | |
506 | 586 | | |
507 | 587 | | |
508 | 588 | | |
509 | | - | |
| 589 | + | |
510 | 590 | | |
511 | 591 | | |
512 | 592 | | |
513 | 593 | | |
514 | | - | |
| 594 | + | |
515 | 595 | | |
516 | 596 | | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
517 | 648 | | |
518 | 649 | | |
519 | 650 | | |
| |||
0 commit comments