test(spec): name each isomorphic pin for its module and schema, sorted - #19932
Conversation
Mechanical half of the re-key: every `IsoNNN` pin in type-alias-convention.pin.test.ts is renamed to `Iso_<module path key>__<schema export>` and the block is sorted by that name, one section per module. Bodies are byte-identical; the gate's `readIsomorphicPins` set is unchanged (789 = 789, difference 0). The runtime companion's pin counter now matches the name family instead of a numeral. Prose follows in the next commit. Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr Co-authored-by: Claude <noreply@anthropic.com>
The naming and sort rule is written at the head of the pin list, with the two cohorts that used to head their own blocks (phase 2, the #4593 backfill) filed there. Notes that pointed at a pin by position or by a numeral now name it; "positional and stay vacant" goes, since no pin name is positional any more; the count history gains a +0 receipt saying the numerals it cites are the pins' former names. Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
Seat read — PR #19932 at head
|
| reading | base | head |
|---|---|---|
path::Schema pin set |
789 | 789 |
| only-before / only-after | — | 0 / 0 |
export type Iso… lines |
789 | 789 |
| duplicate names | — | 0 |
| pin bodies changed, multiset compared | — | 0 |
| names in code-unit order | false (control) | true |
Dark control: dropping one pin from the head file reads 788.
Changeset. Test-only, so the disposition is skip-changeset. This seat applies the label now (references/review-checklist.md: 「Tests/docs-only … 走 skip-changeset 标签,⛔ 不走空 changeset」). No .changeset/*.md is touched.
The dev's open question, packages/spec/src/shared/duration.test.ts:11 still naming Iso868, is answered A. This PR is what makes that line stale, so the one-line fix rides the round that re-runs the re-key after #19809.
Landing is held, per the claim (5804903772). PR #19809 also edits this file. This PR is not armed until #19809 has landed or closed and the re-key has been re-run on that base; that head then owes this read again.
|
Correction to this seat's read above, at 2026-09-24T01:15Z. It says 「no at-tier contract review is owed」 for this test-only diff. Under the enqueue gate, that is wrong.
|
Contract reviewServed-tier: 82/82 Isolated at-tier reviewer subagent, run by the ① Derived judgmentsInputs read: card #19665 body plus all 6 comments (incl. dev report 5805419416); PR #19932 body, Surface. Pin set, independently re-derived (not the PR's instrument). Same pin set, same 789 bodies, byte for byte right of Name rule and order. Same script, head.ts: The transform is what the PR says it is. Extracted the fenced Counter regex. base.ts:2151 Prose. Every pin the rewritten notes cite by its new name exists exactly once at head (22 names grepped, e.g. Verification claims in the PR body are consistent with the head's check-runs, which I did not re-run: all 39 runs completed; every name's latest run is ② Semver levelNone; Check Changeset on the head, two runs. Run id 107444969426 (workflow run 35939802837, the ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Base merge onto main 2c1011b to re-measure the head. The pin file is byte-identical on the merge base and on main, so it merges untouched. Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr Co-authored-by: Claude <noreply@anthropic.com>
The pin file's isomorphic pins are now named for their module and schema; the EpochMs pin this test's header points at is `Iso_shared_epoch__EpochMs`, no longer `Iso868`. Comment text only. Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr Co-authored-by: Claude <noreply@anthropic.com>
…st files (objectstack-ai#19948) Fixes objectstack-ai#19936 Clause-②: no The clause-② enqueue gate's path limb read every file under `packages/spec/src`, while the contract-review rule owes an at-tier review for non-test files there only. For a test-only spec PR from an off-tier seat, the two rules gave opposite answers, so the PR could never enqueue. The ruling on the card (comment 5805897677, letter A) settles it toward the review rule: the path limb and `SUSPECT_TIER_GLOBS` except test files, using the repo's own test-file predicate. `contract-review.md` is unchanged. ## What changed ### `scripts/pm/dispatch-gates.mjs` - **`SUSPECT_TIER_GLOBS`**: the `packages/spec/src/**` entry gains `except: isTestPath` and an `exceptWhy` reason. The glob and its `why` are byte-identical, so `check-widening-tells.mjs`, which builds its contract surface from `g.glob` and `g.why`, sees no change. - **`deriveTier`**: a suspect glob's `except` is applied per path, before the suspicion is recorded. A mixed diff keeps the suspicion on its contract files. `MANDATORY_TIER_GLOBS` has no exception and its semantics are unchanged. - **The predicate is imported, not respelled**: `isTestPath` from `scripts/check-undeclared-dep-imports.mjs`. The docblock above the table says why this one was chosen (see the table below). - **Docs**: a new docblock section on `SUSPECT_TIER_GLOBS`, one sentence in the clause-② header paragraph, and one on `deriveTier`. - **Self-test**: 20 new cases, listed under Verification. One existing census row moved from `dispatch-gates.mjs:708` to `:713`, because the import shifted that file's own `inherited-population` declaration by five lines. That census names each declaration by file and line on purpose. ### `.claude/skills/pm-dispatch/references/landing-operations.md` line 10 The line is rewritten in place and no line is added. ```diff -- 路径肢 = diff 触及契约面 `packages/spec/src/**`,含 error-code-ledger 与 `*.zod.ts` 契约 schema。 +- 路径肢 = diff 触及契约面 `packages/spec/src/**` 非测试,含 error-code-ledger、`*.zod.ts` 契约 schema。 ``` The line goes from 111 to 119 bytes. `非测试` is the exact word `contract-review.md` line 9 uses. To stay under the 120-byte line cap, 与 became 、, with no change in meaning. The file is still 101 lines, at its ceiling of 101. ## Which test-file predicate, and why (measured) The ruling says to take "the repo's own test-file predicate, not a new spelling". The repo has several. Each was run over five shape probes and over the 1541 tracked files under `packages/spec/src` on this branch: | predicate | shape probes excepted | tracked files excepted | `*.zod.ts` excepted | |---|---|---|---| | `check-undeclared-dep-imports.mjs` `isTestPath` (exported) ⭐ | 5 of 5 | 499 | 0 | | `check-position-name-fold-loaders.mjs` `isTestFile` (exported) | 5 of 5 | 499 | 0 | | `check-examples-live-imports.mjs` (not exported) | 5 of 5 | 499 | 0 | | `check-dispatcher-error-vocabulary.mjs` `isTestFile` (not exported; also bare `fixtures/` anywhere) | 5 of 5 | 499 | 0 | | `check-runner-env-posture.mjs` `isTestFile` (also `.bench.`, `.pin.`, bare `fixtures/`) | 5 of 5 | 500 | 0 | | `check-adr-0087-registration.mjs` `TEST_FILE_RE` (filename only) | 2 of 5 | 500 | 0 | | this file's own `isTestFilePath` (filename only, deliberately) | 2 of 5 | 499 | 0 | | `tenant-audit-census.mjs` / `isystem-census.mjs` `isTestPath` (treats `qa/` as a test dir) | 4 of 5 (misses `test/`) | 501 | **1** (`qa/testing.zod.ts`) | The five shape probes cover the ruling's four shapes: `stack.test.ts`, `type-alias-convention.pin.test.ts`, a helper under `__tests__/`, a fixture under `__tests__/`, and a fixture under `test/`. `isTestPath` was chosen because its gate asks the ruling's exact question: which files under a package's `src/` are published source, and which are its tests. It is exported and it covers all four shapes. Its only test directories are `test/`, `tests/`, `__tests__/` and `__fixtures__/`, none of which is a contract domain under `packages/spec/src`. A predicate that also treats `qa/` as a test directory would drop a real contract: `packages/spec/src/qa/testing.zod.ts` is a real contract schema, and it stays a SUSPECT. That case is pinned. ## The lit case (ruling item 3) `node scripts/pm/dispatch-gates.mjs --tier --repo objectstack-ai/objectstack packages/spec/src/type-alias-convention.pin.test.ts` (the one file PR objectstack-ai#19932 changes): - base `43460b95`: prints the SUSPECT block, and its path row reads `- packages/spec/src/type-alias-convention.pin.test.ts ⇢ 'packages/spec/src/**' — the contract surface (error-code ledger, *.zod.ts contract schemas) — the normal landing zone of a clause-② card`. - head `ef4d57c0`: no line contains `SUSPECT`. It prints `Model tier — no path-derived mandate: the surface hits none of the 3 declared glob(s) …` and the standing clause-② note (`Clause ② is NOT reachable from paths: … This line is a FLOOR, never a clearance.`). Same command on `packages/spec/src/ui/view.zod.ts` at head `ef4d57c0`: the SUSPECT block still prints, and its path row reads `- packages/spec/src/ui/view.zod.ts ⇢ 'packages/spec/src/**' — the contract surface …`. The block's header line names the contract-review tier's model id, so it is not quoted here. ## Verification (at HEAD `ef4d57c0`) The gates came from `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, run with no paths (36 commands). Five more came from the dispatch-time list. Each exit code was captured before any pipe. The `--ran` result: `✓ dispatch-gates --ran: 36 derived famil(ies) accounted for — 36 run, 0 NOT-MEASURED`. | gate | exit | verdict line | |---|---|---| | `pnpm check:pm-dispatch-gates` | 0 | `✓ dispatch-gates self-test: 1925 cases pass.` (831 s, run detached as its header prescribes) | | `pnpm check:pm-skill-ratchet` | 0 | `landing-operations.md is 101 lines (ceiling 101; headroom 0)` | | `pnpm check:pm-skill-id-lint` | 0 | `34 file(s) clean` | | `node scripts/check-scripts-symbol-anchors.mjs` | 0 | `3668 anchors across 281 scripts resolve` | | `node scripts/check-self-test-wired.mjs` | 0 | `every one of the 229 script(s) CI runs that ship a --self-test has that self-test run by CI` | | `node scripts/pm/check-governed-queue-guard.mjs --self-test` | 0 | `279 cases pass` | | `node scripts/check-skills-token-ratchet.mjs` | 0 | `54 authored bundle file(s) within their ceilings` | | `pnpm check:pm-widening-tells` (not derived; it imports this table) | 0 | `525 cases pass` | | `pnpm --filter @objectstack/lint run check:doc-formula-expressions` | 0 | The first run exited 3 (PREREQUISITE NOT MET: `formula` and `lint` were not built). It exited 0 after `turbo run build` of those two packages under the verify lock. | | `pnpm check:nul-bytes` | 0 | `scanned 9353 text file(s) … no raw ASCII control bytes` | | the other 30 derived or listed commands | 0 | green | The 20 new self-test cases: - The lit case raises no suspicion. Its rendering has no SUSPECT line and still carries the clause-② note. - A `*.zod.ts` path is still a suspect. - Five shape cases are each excepted: a plain test, a pin test, a `__tests__/` helper, a fixture under `__tests__/`, and a fixture under `test/`. - A mixed diff keeps its contract file. - `qa/testing.zod.ts` stays a suspect while `qa/testing.test.ts` is excepted. - A directory surface that contains the contract surface is still a suspect. - A test-named file under a mandated root keeps its mandate. - The exception is the imported function, and its home is a gate script, so a card editing it derives this gate by gate-script identity. - Every excepting entry carries a reason. - Live: none of the 203 tracked `*.zod.ts` files is excepted, and the exception really drops tracked files. - End to end on the CLI: `--tier` on the lit case prints no SUSPECT line, and `--tier` on `view.zod.ts` does. **Ablation**, from committed state: - Mutation: `deriveTier`'s guard `if (hintCovers(g.glob, p) && !(typeof g.except === 'function' && g.except(p))) {` became `if (hintCovers(g.glob, p)) {`. It was applied through `scripts/ablation-replace.mjs` in WRAP mode, and the file hashes show it landed: anchor 1 → 0, replacement 0 → 1, blob `caf66526bc7d` → `f2f8a50e2b5e`. - Predicted before the run: 11 red. Observed: `✗ dispatch-gates self-test: 11 of 1925 case(s) failed.`, the predicted 11 exactly. They are the two lit-case cases, the five shape cases, the mixed diff, the `qa/testing.test.ts` case, the live non-vacuity case, and the CLI lit case. - The zod, `qa/testing.zod.ts`, ancestor, mandate, provenance and live-zod cases stayed green, as they should with no exception applied. - Restore: blob after restore `caf66526bc7d` equals HEAD, `git diff HEAD` is empty, and `git status --porcelain` is empty. **eslint, narrowed** to the one changed `.mjs` file: - Population: `eslint --print-config` shows 2 rules (`no-restricted-imports`, `comment-swallow/no-code-inside-block-comment`), both per-file, and no `parserOptions.project`. - Count: `--format json` reports 1 file, 0 errors, 0 warnings. - Invariance: no type-aware linting is enabled, so this diff cannot move any untouched file's verdict. The `.md` file is not linted. NOT MEASURED: `pnpm check:published-readme-exports`, exit 3. It needs a full `pnpm build` of the workspace, which was not run. It is an artifact-roster family printed for every card. This diff touches no package, no package README and no type surface. ## Acceptance notes - `check-widening-tells.mjs`, the mechanical half of the declaration limb, imports `SUSPECT_TIER_GLOBS` and `hintCovers` from this file. It already excludes tests with its own filename-only predicate (`isContractSourceFile`). A `__tests__/` helper under `packages/spec/src` would still be read there for tells. There are none on the tree today. That is outside this card's surface and was not changed. - A derivation gap that predates this PR: `dispatch-gates.mjs --commands scripts/pm/dispatch-gates.mjs` does not name `pnpm check:pm-widening-tells`, although that gate imports from this file. The same holds for its other two imports (`scripts/regen-artifacts.mjs`, `scripts/pm/check-half-states.mjs`). The documented remedy is a module constant in the importing gate, the `SURFACE_MODULE` shape in `check-dispatch-gates.mjs`. The gate was run here anyway. Carrier: none. - `packages/spec/src/benchmark.bench.ts` stays a SUSPECT. Neither the chosen predicate nor the ruling's four shapes name bench files. - The ruling's `__tests__/**` shape would also except a `*.zod.ts` placed under a test directory. The package's `files[]` entry for `src` zod files would still ship such a file. None exists today, and the new live pin reds the day one does. ## 维护者速读(草稿) **改了什么**:入队闸门的「路径肢」(`landing-operations.md` 第 10 行)和 `dispatch-gates.mjs` 的嫌疑表 `SUSPECT_TIER_GLOBS`,现在都把 `packages/spec/src/**` 下的测试文件排除在外。排除用的是仓里现成的测试文件判据(`check-undeclared-dep-imports.mjs` 的 `isTestPath`),直接 import,没有另写一份。`--tier` 对只改 spec 测试的 diff 不再打印 SUSPECT 行;改 `*.zod.ts` 的照旧打印。`contract-review.md` 未动。 **为什么改**:按裁决 A(评论 5805897677,维护者「同意」)。两条规则原先对「只改 spec 测试文件的 PR」互相矛盾:一条要求先有达档复核记录,另一条又说不许为它另起复核。结果出自不达档席位的这类 PR 永远进不了队列,眼下卡住的是 PR objectstack-ai#19932。测试文件不随包发布,改它不改变任何对外契约。 **风险与代价(含回滚)**:这道门放宽了,但只放宽到「测试文件」。另有两处自测直接对着真实文件树兜底:仓里 203 个 `*.zod.ts` 一个都不许被排除;`qa/testing.zod.ts` 这种名字像测试、实为契约的文件必须照旧打嫌疑行。消融实测:去掉排除,恰好预期的 11 条自测变红。强制档表(MANDATORY)没有任何排除。回滚:revert 本 PR 即可,无数据迁移。 **席位意见**: **你要做的**:无需操作。本 PR 属 Tier S(`.claude/**` + `scripts/pm/**`),由 skills 席位完成达档复核后入队;PR objectstack-ai#19932 在本 PR 落地后入队。 --- _Generated by [Claude Code](https://claude.ai/code/session_01A22sUB3mUWs6M36VgfijBq)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Fixes #19665
Clause-②: no
What this changes
packages/spec/src/type-alias-convention.pin.test.tskeyed its isomorphic pins on a dense, hand-kept counter (Iso0…Iso881). Two branches off one base each took "the next free number" for a different schema, at insertion points far apart, and git merged them cleanly into two declarations of one name:Iso871once already, thenIso877/Iso878on #19600, where onlycheck:test-typecheckcaught it.Each pin is now named for the pair that is already unique to it, its module path and its schema export name:
Iso_, then the module path belowpackages/spec/srcwithout.zod.ts, with each kebab segment camelCased and the segments joined by_(soai/knowledge-document.zod.tsbecomesai_knowledgeDocument), then__, then the schema export name. For example:Iso_shared_epoch__EpochMs.LC_ALL=C sortgives), with one heading per module. Each note about a module's pins sits under that module's heading and names the pins it covers. The schema alone now decides both a new pin's name and where it goes.There are four commits:
ece9f71d2c: the mechanical half. It is the transform below, run onfdeeea0cc9, byte for byte. That includes the runtime companion's pin counter, whose regex now matches the name family (Isofollowed by word characters) instead ofIsofollowed by digits.fc8eda2d62: prose only.789 -> 789entry.ea78da8908: a merge ofmainat2c1011b01b, to re-measure this head on currentmain.mainhas not touched the pin file since the merge base: its blob is5620656d04on bothfdeeea0cc9and2c1011b01b. So the merge leaves the file exactly asfc8eda2d62had it, and the re-key was not re-run.4a724cfbf3:packages/spec/src/shared/duration.test.ts:11cited theEpochMspin asIso868. It now citesIso_shared_epoch__EpochMs. This commit changes comment text only.The diff against
mainis two files: the pin file, and that one comment line induration.test.ts.No assertion is added and none is weakened. The exemption set is unchanged, and nothing is regenerated from a corpus measurement.
scripts/check-spec-parsed-alias.mjsis untouched, because its reader never reads the numeral.Acceptance: the assertion set is identical, member for member
Both sides are read with the gate's own
readIsomorphicPins: before isfdeeea0cc9and after isfc8eda2d62.readIsomorphicPinsentries=, keyed onpath.ts::Schema)Controls, to show the instrument can fire:
z.inferoperand to another schema keeps the set at 789 and reads 1 body changed.The module series is untouched: there are 174
import type * as M…lines before and after, and no import line is in the diff.The collision is gone: merge probe with a firing control
The probe ran
git merge-tree --write-treein a throwawaygit clone --bare --sharedwith no merge driver registered. The clone was removed afterwards. In each case, two branches off one base each add one pin for a different schema:fdeeea0cc9: both takeIso882, one inapi/analytics, one inui/viewIso882(the #19600 shape)fc8eda2d62:Iso_api_analytics__ProbeAlphaSchemaandIso_ui_view__ProbeBetaSchema, each at its sorted placeThe last row is the case that remains. Two new names with no existing pin between them insert at the same place, and git stops with a conflict; the resolution is to keep both lines. That failure is loud, and it cannot merge into a duplicate.
The module series (
M…) is left untouched, and it is not a measured collision: no one has yet seen two PRs that each import a new module. I ran one simulation of its mechanism only. Two branches that each appendimport type * as M189afterM188conflict at the tail of the import block (merge-tree exit 1). Keeping both lines when resolving would give tsc a duplicateM189. So in this simulation its failure mode is a conflict, not a silent clean merge.Landing order: this PR lands first, then #19809 re-runs the re-key on its own pin
On the maintainer's instruction, this PR lands before #19809. #19809 also edits this file: it re-pins
KanbanConfigSchemaasIso882and raises the count to 790. After this PR has landed, #19809 does this on its own branch:main. The pin file conflicts.limit#19809's own copy of the file, still on the old names, asF: rungit show H:packages/spec/src/type-alias-convention.pin.test.ts > F, whereHis fix(spec): one row bound per view — retire the unpublished per-kind viewlimit#19809's head before the merge. Then run the transform below onF. It renames and sorts every pin, including the new one, which becomesIso_ui_view__KanbanConfigSchema.limit#19809's pin set ismain's set plus its own pin. Atff13eece89it is: 790 pins, which aremain's 789 plusui/view.zod.ts::KanbanConfigSchema.git merge-file -p F BASE1 HEAD1 > out.BASE1is this file atece9f71d2c.HEAD1is this file atfc8eda2d62, which is the same bytesmainholds once this PR lands.789 -> 789entry first, then fix(spec): one row bound per view — retire the unpublished per-kind viewlimit#19809's entry restated as789 -> 790, with itstoHaveLength(790). In that entry, name the pinIso_ui_view__KanbanConfigSchemainstead ofIso882.limit#19809'sui/viewnote, name the pinIso_ui_view__KanbanConfigSchemainstead ofIso882, and drop "Iso829 stays vacant".readIsomorphicPinsonFbefore the transform with the result. The sets must be equal, the bodies unchanged, the names on the rule, and the block sorted.I dry-ran steps 2 and 3 against #19809's head
ff13eece89: 790 = 790, set difference 0 both ways, 0 bodies changed, 0 names off the rule, sorted, andIso_ui_view__KanbanConfigSchemadeclared once. The prose merge conflicts at that one hunk only.The transform is
node rekey.mjs FILE. It rewrites the file in place and is idempotent: running it onfc8eda2d62changes nothing. It is written without a less-than character so this body keeps it intact. Running exactly this text onfdeeea0cc9reproducesece9f71d2cbyte for byte.Verification
Round 2, on
4a724cfbf3, after the merge ofmainat2c1011b01b:fc8eda2d62's (blob8ae4405bd5).readIsomorphicPinsonmain's file and on this head's file reads 789 = 789, with a set difference of 0 both ways. Control: dropping one pin line reads 788, difference 1.pnpm --filter @objectstack/spec check:test-typecheck: OK (53 files / 255 errors / 142 signatures held).node scripts/check-spec-parsed-alias.mjs: "1459 bare z.input aliases, 789 pinned isomorphic, 670 paired with an XParsed. OK". Its--self-test: 18 assertions passed.pnpm --filter @objectstack/spec run typecheck: exit 0.vitest run --project localonsrc/type-alias-convention.pin.test.tsandsrc/shared/duration.test.ts: 2 files, 14 tests passed. The whole speclocalproject: 530 files, 15617 passed, 1 todo.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsderived 77 commands, and all 77 were run. The--ranreconciliation reads 77 run, 0 NOT MEASURED, 0 unrun. Four gates first exited 3 for unbuilt prerequisites (check:doc-formula-expressions,check:lean-entry-closure,check:dual-build-cjs-loads,check:type-check-debt), and each exited 0 after its build.Round 1, on
fc8eda2d62. The pin file's bytes have not changed since, so these still describe it:node scripts/ablation-replace.mjsrenamedIso_ui_view__TreeConfigSchemato the existing nameIso_ui_view__RowHeightSchema, andcheck:test-typecheckturned red ("2 type error(s) in a file the ledger does not cover"). The file was then restored: blob == HEAD andgit diff HEADis empty.fdeeea0cc9and the merge probe are in the sections above.Changeset
None. The file is a test.
@objectstack/spec'sfilesshipssrc/**/*.zod.tsanddistbut never*.test.ts, so nothing published changes.check-empty-changeset.mjsrefuses a new empty-frontmatter changeset, so the repo's disposition for this diff is theskip-changesetlabel. The seat applied that label after the PR opened. The one redCheck Changesetrun onfc8eda2d62came from theopenedevent, before the label; on4a724cfbf3that check isskipped.Acceptance notes
api/errors.zod.tspins (FieldErrorCodeandFieldErrorSchema) sat under theapi/error-code-ledger.zod.tsheading. The sorted layout files them under their own module.packages/spec/src/shared/duration.test.ts:11cited this file'sIso868in the present tense. That pin isEpochMs, nowIso_shared_epoch__EpochMs, and4a724cfbf3updates the citation. The otherIso-plus-digits hits underpackages/spec/src, outside this file, areui/component.zod.tslines 2052, 2523 and 2929 andui/i18n.zod.tsline 198. They nameIso818,Iso819,Iso839andIso759, pins that were deleted before this PR, so they are history and stay as they are.Isonames are in code-unit order and that each one equals the rule applied to itsMnpath and schema.Generated by Claude Code
Generated by Claude Code