Skip to content

chore(gates): retire check-type-source-resolution (maintainer ruling E on #18373) - #18946

Merged
os-try-charles merged 3 commits into
mainfrom
claude/issue-18373-retire-type-source-resolution-gate
Sep 18, 2026
Merged

os-try-charles merged 3 commits into
mainfrom
claude/issue-18373-retire-type-source-resolution-gate

Conversation

@os-try-charles

@os-try-charles os-try-charles commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes #18373

Clause-②: no

skip-changeset — measured, not asserted; see Verification below.

Executes the maintainer ruling of 2026-09-18 on this card (batch #153 item 3, letter E):
retire check-type-source-resolution. This PR is EXECUTION — it does not re-argue A/B/C/D.

What the ruling ordered, and where each piece landed

the ruling's words landed as
delete scripts/check-type-source-resolution.mjs and its self-test file deleted. Its "self-test" was the file's OWN --self-test dispatch, not a separate file, so it went with it (git ls-files matched exactly one path for the name).
KNOWN_DIST_RESOLVED_TYPE_IMPORTS with it that registry lived inside the deleted file; the identifier now has 0 occurrences anywhere in the tree.
the check:type-source-resolution entry in the root package.json removed (one line).
the 「Type-source resolution gate」 step in .github/workflows/lint.yml step removed, together with the 23-line comment block that exists only to explain it.
AGENTS.md and any doc that names the gate as a standing check AGENTS.md names it zero times — re-measured here, see §1. This diff does not touch the governed surface.
docs/audits/gate-census-2026-09.md:215 verdict rewritten to the ruling's exact text, see §2.
PR #18708 not touched.
check:test-source-alias (the vitest-axis sibling) not touched, and its ledger is not touched.

1. AGENTS.md: the ruling's sentence describes a sentence that does not exist

Re-measured independently of the dispatch, whitespace-flattened first so wrapped prose
cannot give a false zero, every zero paired with a control drawn from the same flattened
population:

type-source-resolution        0        check:test-source-alias   1   (control, hits)
Type-source resolution        0        check:                   47   (control, hits)
type source resolution        0        test-source-alias         1   (control, hits)
TYPE SOURCE RESOLUTION        0
KNOWN_DIST_RESOLVED           0
check-type-source-resolution  0        file 78,857 bytes / flattened 76,881 bytes

My reading agrees with the dispatch's. So the ruling's AGENTS.md clause has no
referent, no line was hunted for there, and AGENTS.md / CLAUDE.md / .claude/** /
skills/** / docs/adr/** are all absent from this diff.

2. The two censuses — deliberately different acts

docs/audits/gate-census-2026-09.md — verdict REWRITTEN. Its verdict column is a
forward-looking disposition (what should happen to the gate), which is exactly what a
later ruling can override. The row's verdict now reads
retire · maintainer ruling 2026-09-18 on #18373, the ruling's own spelling.
Because that is a NEW verdict spelling, the document's own verdict-count table was kept
arithmetically true in the same edit: keep 133 to 132, a new row for the new spelling at
1, retire (all spellings) 59 to 60, keep (all spellings) 150 to 149. The union still
sums to 225 rows. Nothing else on the row moved — class, contract, blast radius and the
measured catch window are what the census measured, and this PR did not re-measure them.

docs/audits/2026-09-self-test-shape-census.md:341 — deliberately LEFT ALONE. The
dispatch flagged it as a second carrier the ruling did not name; it holds a
ROSTER | HELD row for this gate. It gets nothing, for a reason, not by omission:

Rule applied, and the same rule decides every prose carrier below: a sentence that makes
a present-tense claim about the gate acting is now false and is repaired; a sentence
recording a past measurement or why a past change happened is not.

3. The hard coupling: check:ratchet-remedy-authority, measured before and after

That gate keeps a hand-classified control corpus keyed on gate FILENAME, and its self-test
asserts the sweep reaches every entry. Both legs, run from this worktree:

leg --self-test main run
before any change (at 02bdeaaf2) exit 0 exit 0 — 257 scripts swept, 15 marked, 6 refused, control corpus 31
after deleting the file only exit 1the sweep still REACHES every known instance; it no longer reaches: check-type-source-resolution.mjs exit 1STALE: the control corpus ... covers scripts/check-type-source-resolution.mjs, which is no longer in the corpus. Drop the entry, or restore the file.
after the repair in this PR exit 0 exit 0 — 256 scripts swept, 15 marked, 5 refused, control corpus 30

The repair is the gate's own prescribed remedy, and no floor moved. What that gate pins
is SELF_TEST_BATTERIES — a roster of battery NAMES with a per-battery count floor and a
pinned roster SIZE, and its own comment at the roster says deleting an entry silences a
floor as effectively as zeroing it. That roster is a different registry from the
control corpus, and it is untouched in substance:

declared batteries: 21      SELF_TEST_BATTERY_FLOOR: 21      sum of counts: 30
battery (12) count: 1   (unchanged)

The control corpus (CONTROL) has no pinned size — the gate prints Object.keys(CONTROL).length
— and its STALE branch names dropping the entry as the fix. 257 to 256 swept, 6 to 5 refused
and 31 to 30 classified are the mechanical consequence of one file leaving the corpus, not a
weakened floor.

Three further carriers in that same file, each judged by the rule in §2:

  • :16 "The precedents are ..." — present tense, names four files a reader is told to open.
    The dead name is dropped; the other three stay.
  • :1221 the author-facing remedy "turn it down outright the way check-type-source-resolution.mjs does" —
    present tense, and after this PR it points an author at a file that does not exist. The
    exemplar is swapped to check-test-source-alias.mjs, the co-precedent of the identical
    PREDICATION shape that this same file already names at :16 and in battery (12).
    ⛔ This names that gate; it does not touch it or its ledger.
  • battery (12)'s label and its assertion text ("the shape the two registry gates use") —
    present tense, now one gate. Label renamed, assertion reworded. Roster size and the
    battery's own count are unchanged, so nothing is unpinned.
  • :662 "…which turned check-type-source-resolution's CORRECT remedy into a reported
    violation" — a record of a measurement that was taken and rejected. Historical: kept.

4. The coupling the dispatch did not name: check-type-check-coverage.mjs

Found by re-measuring rather than by the brief. That gate's live, author-facing TEST_DEBT
graduation remedy told an author route (b) was "Available ONLY while
pnpm check:type-source-resolution still passes with the tests re-admitted ... Run it before
you commit". After this PR that is a command that does not exist, in a message whose whole
job is to tell an author which of two routes is open.

Repaired so it keeps the WARNING and loses the dead instruction: it now records that the
gate that decided the route was retired under this ruling, that its silence is ⛔ not a
clearance, that what it measured has not changed (the re-admitted tests import workspace
packages the src program never held; it read red on 14 of the 18 entries with an exclusion
to drop), and that (a) is the route to prefer.

⛔ The self-test that pins that message is NOT weakened. Its present needles
(check:type-source-resolution, SHRINK-ONLY, tsconfig.test.json) and the sibling
FUTURE_DEBT case's absent needles are left byte-identical — the rewritten message
still carries all three, because it names the retired gate and its former registry
explicitly. Only the case LABEL and its explanatory why changed. pnpm check:type-check-coverage
exits 0 after the edit.

The other five mentions in that file (:934, :986, :1099, :4462, and the :537 /
:5629 provenance notes) are records of measurements — "MEASURED as a red main", "SINCE
MEASURED ... by dropping each entry's exclusion and reading check:type-source-resolution",
"measured by doing it". Under the §2 rule the measurements are kept; the two that also made
a present-tense claim about a live consumer (:537, :5629) now say the gate was retired.

5. The other repo-root tooling carriers

  • scripts/typecheck-configs.mjs — this library existed because two gates needed the same
    predicate. One is gone. Its self-test does not assert a consumer set (checked: no
    consumer array, only prose), so nothing reds; but "Two gates need this predicate", "both
    consumers resolve", "the two callers" and ":201 check-type-source-resolution.mjs imports
    the predicates" were all present-tense and false. Repaired to name the one live consumer and
    record the retirement. ⛔ Folding the module back into its remaining caller is explicitly
    left as a separate decision — its cases are floored in its own dispatch (PR test(scripts): batch 10a — class-3 floors at the verdict site for four self-tests #15327) and a
    fold-in would not inherit that floor.
  • scripts/check-undeclared-dep-imports.mjs:42 — "the two gates that look adjacent" is now one.
  • scripts/workspace-enumerator.mjs:66 — the WORKSPACE_PARENT_GLOBS declaration list named
    the deleted file; it now names the live one and records where the other went.
  • scripts/pm/dispatch-gates.mjs — five mentions, all left alone: every one is a recorded
    measurement in a docblock (pair counts of a matcher variant that was measured and refused).
    Historical under the §2 rule. The tool derives its families from package.json and the
    workflows at run time, so the retired gate simply leaves its output; it needs no edit and
    reds nothing.
  • scripts/pm/check-clause2-carriers.mjs:8209 / :8250verified offline before deciding,
    and left alone.
    The record is a frozen inline array of comment bodies passed
    headSha: 'offline'; nothing in it resolves a remote ref, and the two mentions are branch
    names inside a historical claim-contest fixture about this card, unrelated to the gate.
  • scripts/typecheck-configs.mjs:202's stale comment about its importer — see above; that is
    the comment the dispatch flagged as pointing the other way.

6. Out of scope, on purpose

  • packages/*/CHANGELOG.md (five files) — untouched. AGENTS.md:686 is unconditional:
    a factual error in a released entry is repaired in a dedicated docs-only PR, ⛔ never as a
    rider on code changes. They are also correct as historical records of what those releases did.
    Same for content/docs/releases/** (which names it zero times anyway).
  • About 30 prose carriers in packages/**/tsconfig*.json comments, test docblocks,
    packages/cli/bin/run-dev.js and examples/*/tsconfig.json — untouched, and reported to the
    PM as a residual.
    Boundary applied: the ruling scoped this diff itself when it moved the lane
    to domain:devx 「the diff is repo-root tooling, package.json and the lint workflow」.
    Editing those comments would pull roughly 18 packages and 3 examples into the changeset,
    change the diff's lane, and multiply the derived gate set — for comments that mostly explain
    why a paths rule exists, a reason that outlives the gate.

7. The workflow step removal leaves the required context intact

Measured, not asserted. The required context is the JOB's name:, and no context name is
derived from a step:

BASE 02bdeaaf2 : lint job `name:` = Lint & Repo Gates   steps = 179   (step present)
HEAD           : lint job `name:` = Lint & Repo Gates   steps = 178   (step absent)

The job keeps 178 other steps and its name is byte-identical, so the six required contexts
are unchanged. pnpm check:required-contexts exits 0. ⚠️ One wording note for the record:
the ruling writes the job as 「Lint and Repo Gates」; the job's actual name: is
Lint & Repo Gates (ampersand). Same job, and the ruling's conclusion holds.

8. skip-changeset, measured

Criterion: nothing already published moves. Measured against every workspace manifest's
files[], with a positive control proving the reader works rather than merely reporting zeros.

changed paths (9)                              files[] reaches
  .github/workflows/lint.yml                     NONE
  docs/audits/gate-census-2026-09.md             NONE
  package.json                    (private:true) NONE
  scripts/check-ratchet-remedy-authority.mjs     NONE
  scripts/check-type-check-coverage.mjs          NONE
  scripts/check-type-source-resolution.mjs       NONE   (deleted)
  scripts/check-undeclared-dep-imports.mjs       NONE
  scripts/typecheck-configs.mjs                  NONE
  scripts/workspace-enumerator.mjs               NONE

POSITIVE CONTROL — must be reported as reached
  packages/spec/src/data/query.zod.ts            @objectstack/spec   (glob entry)
  packages/cli/dist/index.js                     @objectstack/cli    (directory entry)
  packages/spec/CHANGELOG.md                     @objectstack/spec   (literal entry)

3 of 3 controls hit, across two packages and all three files[] entry kinds, so the zeros
above are readings and not an empty read. The root package.json is private: true and is
never published at all.

9. Verification

Gate set derived in-worktree with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths
passed — the tool takes its own change set from the merge base), then run. Union taken at
13b2b68ef, the final commit.

  • 69 of 69 derived commands run. 63 exit 0.
  • 6 exit 3 = PREREQUISITE NOT MET, NOT MEASURED, declared to CI: check:dts-closure,
    check:dual-build-cjs-loads, check:lean-entry-closure, check:sourcemap-no-sources-content,
    check:type-check-debt and @objectstack/lint check:doc-formula-expressions. Every one of
    them refuses because this worktree has no build; each prints its own "this is NOT a pass"
    line and exits 3 rather than 1. They are derived from the root package.json edit, and they
    read the dist/ of packages this diff does not touch — this diff changes no package source,
    so their verdict cannot depend on it. CI's build lanes measure them.
  • pnpm lint (eslint . --no-inline-config, the whole repo, no narrowing) — exit 0.
  • pnpm check:ratchet-remedy-authority — exit 0, before/after table in §3.
  • pnpm check:type-check-coverage — exit 0.
  • pnpm check:pm-dispatch-gates — exit 0, dispatch-gates self-test: 1848 cases pass
    (976.3s on this box; run on its own because it does not fit a ten-minute foreground window).
  • pnpm check:required-contexts, check:step-collectors, check:self-test-wired,
    check:self-test-workflow-commands, check:aggregator-roster, check:scripts-symbol-anchors,
    check:declaration-mirrors, check:ci-filter-parity, check:nul-bytes,
    check:workflow-step-name-quoting — all exit 0.
  • Control-byte self-scan over every changed file
    (grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]') — clean.
  • ⚠️ dispatch-gates prints its own warning that --commands is not a complete account
    of CI; the artifact-roster, wide-population, workflow-valued and path-scheduled CI families
    are outside that list by construction.
  • ⚠️ dispatch-gates also reported a STALE TREE note: origin/main moved 3 commits after this
    branch point and scripts/pm/check-widening-tells.mjs changed there. The derivation itself
    uses three-dot merge-base semantics, so the change set above is correct; the note affects only
    that one family's shape. No path of this diff overlaps it.

10. Serial constraint with two in-flight PRs

Both #18889 (draft) and #18414 (open, non-draft) also edit .github/workflows/lint.yml
and the root package.json. Re-checked immediately before pushing: both are still open and
unmerged
, so neither had landed under this branch. This diff is written to survive either
landing first — ⛔ no line number was used as a reading:

  • the workflow step is located by its own name, and the edit asserted the literal text of
    - name: Type-source resolution gate, its run: line and the first line of its comment block
    before removing anything; a shifted file fails the assertion instead of deleting the wrong step.
  • the package.json entry is matched as a unique exact string, never by offset.

The ruling's .github/workflows/lint.yml:4187 and the dispatch's package.json:172 were both
treated as clues; both happened to still be correct at 02bdeaaf2, but nothing here depends on that.

Also re-measured against a freshly fetched origin/main (46559f61c, five commits past this
branch point): none of those five commits touches any of this diff's nine paths, so no merge
was needed and no line re-derivation was owed.

#18708 is closed, unmerged (2026-09-18T06:37Z) — confirmed here, not assumed. This PR does not
touch it. #18903 is editing scripts/pm/check-clause2-carriers.mjs, the file holding the
frozen #18708 fixture this PR deliberately leaves alone — adjacent, not overlapping.

Acceptance notes

  • Noted, not filed: the gate census's inventory counts (182 check files, 225 rows) are pinned
    to the census's own tree and were deliberately not re-derived — only the verdict column and
    its roll-up were touched. Carrier for a future re-derivation: whoever executes the next
    batch of the 58 remaining retire rows.
  • Noted, not filed: docs/audits/gate-census-2026-09.md now carries a verdict spelling
    (retire · maintainer ruling ...) that no other row uses, where the existing convention for a
    ruling-driven retirement is the verdict retire (ruled) plus ruled retire: #NNNNN X in
    column 3. The ruling's literal text was followed rather than the convention.

Generated by Claude Code


Generated by Claude Code

…step, ratchet-remedy coupling)

Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk
Co-authored-by: Claude <noreply@anthropic.com>
…ed it as standing

Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk
Co-authored-by: Claude <noreply@anthropic.com>
@os-try-charles os-try-charles added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 18, 2026 — with Claude
@github-actions github-actions Bot added size/xl ci/cd dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation labels Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

站开说明:Validate Package Dependencies 这条红,不是本 PR 的

domain:devx 执行席(座位贴 #6023)。本 PR 只删门禁与相关散文,九个改动路径里没有 pnpm-lock.yaml(已核:diff 里含 lock 的文件数为 0)。

判据:三个都碰根 package.json 的 PR,同一条检查

PR head 跑于 Validate Package Dependencies
#18414 2026-09-16T09:55Z success
#18889(另一位作者,另一片代码) 2026-09-18T06:04Z failure
本 PR #18946 2026-09-18T07:23Z failure

⇒ 两个互不相干的 PR 在同一天同时红,而较早的那次 head 是绿的。这条检查是按路径触发的(近期已合的 PR 上它整条 absent,因为它们不碰 package.json),所以它不会在那些合入里留下痕迹——⛔ 「最近都合进去了」在这里不是反证。

⭐ 更强的读数不在本 PR 上:#18930 已经用一条亮对照把它钉在 main —— main 的定时跑 35301766597 失败,而前一天的定时跑 35176747270 成功。⇒ 公告是在那 24 小时里到的。⛔ 不是永久坏掉的 job,⛔ 不是基础设施抖动。

失败内容本身与本 PR 的改动无任何交集:

| https://osv.dev/GHSA-9rgm-9g3h-6x36 | 5.3 | npm | devalue | 5.9.0 | 5.9.2 | pnpm-lock.yaml |

⛔ 修法存在,但本席不把它搬进这个 PR,理由写在这里供复核

修法是 PR #18942(os-litant,卡 #18930 p1,已认领已交付):pnpm-workspace.yaml 里把 devalue 钉到 ^5.9.2,外加 pnpm install 重算锁文件。本席不移植,三条理由:

  1. 移植的安全性前提在这一类改动上不成立。 「先移植,等基线带上它就自动空转」之所以安全,是因为同一处改动会归一。锁文件不会 —— 两次独立的 pnpm install 产出互相冲突的 pnpm-lock.yaml,移植保证造出一处冲突,而不是一个空转。
  2. 修法已经有主、已经做完,就在 fix(deps): pin devalue onto the patched 5.9.2 line (GHSA-9rgm-9g3h-6x36) #18942 里等着落地。再做一遍是重复劳动加一处必然冲突。
  3. 那是一处依赖变更,塞进一个「退役门禁」的 PR 就是本席不该做的扩面。

⇒ 本 PR 在此待命:等 #18942 落地后把基线并进来重跑,⛔ 不重试装弹,⛔ 不用任何削弱门禁的办法买绿。重跑对一条真实公告无效,所以那一次「可用的重跑」本席也不花。

其余检查仍在跑;它们的判定另行读。

读数时刻 2026-09-18T07:32Z


Generated by Claude Code

@os-try-charles
os-try-charles marked this pull request as ready for review September 18, 2026 08:40
@os-try-charles
os-try-charles added this pull request to the merge queue Sep 18, 2026
Merged via the queue into main with commit 03b7b81 Sep 18, 2026
37 checks passed
@os-try-charles
os-try-charles deleted the claude/issue-18373-retire-type-source-resolution-gate branch September 18, 2026 09:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/xl skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants