Skip to content

Commit e8b9fd6

Browse files
committed
fix(ci): TypeScript Type Check 走 merge base,补上缺失的 fetch-depth: 0 (#6359)
`lint.yml` 的 `typecheck` job 用 `actions/checkout@v7` 的默认 `fetch-depth: 1`, 于是 `resolveSurfaceBase()` 里的 `merge-base HEAD origin/main` 在这个 job 里 永远走不通,每次都落到 origin/main 的 tip。而合并 ref 随 main 前进而陈旧, tip != merge base,「main 新增的键」就被读成「本 PR 删掉的键」——方向恰好反了。 同文件的 ESLint job 已有同一句 `fetch-depth: 0`,但失效方向不同:那道门 shallow 时降级为不校验(假绿),这道门 shallow 时降级为误报红。 一并把 shallow 那行日志从「静默降级说明」改成点名方向的诊断:tip 锚下 main 新增 == 本分支删除,且若在 CI 则该 job 的 checkout 需要 fetch-depth: 0。 判决逻辑一行未动;把 fallback 本身显式化的那一半爆炸半径过大,拆到 #6452。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3
1 parent 26b72e0 commit e8b9fd6

3 files changed

Lines changed: 53 additions & 4 deletions

File tree

.github/workflows/lint.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,22 @@ jobs:
489489
steps:
490490
- name: Checkout repository
491491
uses: actions/checkout@v7
492+
with:
493+
# The authorable-surface deletion gate (#4650) below anchors on the
494+
# MERGE BASE of HEAD with origin/main — that is the only anchor under
495+
# which "a key this PR deleted" and "a key main gained since the fork
496+
# point" are different facts. A shallow clone has no walkable
497+
# ancestry, so `merge-base` fails and the gate falls back to
498+
# origin/main's TIP, where those two facts collapse into one and the
499+
# SECOND one is reported as the first: #6359 had PR #6356 (which
500+
# touches no spec file at all) go red for "deleting"
501+
# ui/BulkActionDef:requiredPermissions — a key main had just ADDED.
502+
#
503+
# Same line as the ESLint job above, opposite failure mode, and that
504+
# is why it is spelled out here rather than cross-referenced: shallow
505+
# degrades the slot-lookup ratchet to "not verified" (a false GREEN),
506+
# and degrades this gate to a false RED on an innocent PR.
507+
fetch-depth: 0
492508

493509
- name: Setup Node.js
494510
uses: actions/setup-node@v7

packages/spec/scripts/build-schemas-check-mode.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1517,7 +1517,9 @@ describe('build-schemas.ts — the drift notice names the direction it measured
15171517
// Truncation moves TWO things here, and the second was a surprise worth
15181518
// writing down: `merge-base HEAD origin/main` itself fails once the walk is
15191519
// cut, so `resolveSurfaceBase` falls back to origin/main's TIP as the
1520-
// baseline (it says so — "using origin/main tip … as the baseline anchor").
1520+
// baseline (it says so — "no merge base is walkable here, so this run
1521+
// anchors on the origin/main TIP …", the line #6359 reworded to name what
1522+
// that anchor then MISJUDGES).
15211523
// The pair being compared is therefore anchor-at-`tip` vs baseline-at-
15221524
// `mainTip`, not the fork point at all. And the ancestry between them is
15231525
// exactly what a grafted history cannot answer: `mainTip` is its own shallow

packages/spec/scripts/build-schemas.ts

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,8 +1509,17 @@ function resolveSurfaceBase(): SurfaceBaseResolution | null {
15091509
const git = gitInPackage;
15101510
const committed = readCommittedSurfaceBase();
15111511

1512-
// CI's typecheck job checks out shallow with no branch refs, so fetch the
1513-
// one ref this check needs (depth 1 — a single snapshot) before giving up.
1512+
// A checkout with no branch refs (any `fetch-depth: 1` job) cannot name
1513+
// origin/main at all, so fetch the one ref this check needs before giving up.
1514+
//
1515+
// This fetch is GUARDED by the probe above and that is load-bearing (#6359):
1516+
// where the ref already resolves — every full clone, and every CI job that
1517+
// checks out `fetch-depth: 0` — it does not run, so it cannot undo the depth
1518+
// its job asked for. Where it does run, it is `--depth=1` because the only
1519+
// thing it is trying to buy is the ability to NAME origin/main; deepening it
1520+
// here would silently make every shallow build pay for a full history it was
1521+
// configured not to want. The job that needs walkable ancestry declares that
1522+
// in its checkout step, which is where the cost is visible.
15141523
let tipProbe = git('rev-parse', '--verify', '--quiet', 'origin/main^{commit}');
15151524
if (tipProbe.status !== 0) {
15161525
git('fetch', '--quiet', '--depth=1', 'origin', '+refs/heads/main:refs/remotes/origin/main');
@@ -1526,7 +1535,29 @@ function resolveSurfaceBase(): SurfaceBaseResolution | null {
15261535
const mergeBase = git('merge-base', 'HEAD', tip);
15271536
const rev = mergeBase.status === 0 ? mergeBase.stdout.trim() : tip;
15281537
if (mergeBase.status !== 0) {
1529-
console.log(` (shallow history — using origin/main tip ${tip.slice(0, 12)} as the baseline anchor)`);
1538+
// That "…is the merge base anyway" holds only while the merge ref is
1539+
// fresh. It is generated when the PR opens or updates and goes STALE as
1540+
// main advances, so on a branch that forked earlier the tip anchor
1541+
// carries keys the fork point never had — and this gate reads every one
1542+
// of them as a line THIS commit deleted. The direction is worth spelling
1543+
// out because the verdict it produces ("deleted without proof") reads
1544+
// like a severe spec violation and costs far more to diagnose than to
1545+
// fix: #6359 was one CI job missing `fetch-depth: 0`, and the PR it
1546+
// reddened (#6356) had not touched packages/spec at all.
1547+
//
1548+
// Diagnostic only — the verdict below is unchanged. Making this route
1549+
// stop MISJUDGING rather than merely announcing itself is a separate
1550+
// decision with a much wider blast radius: this block is top-level, so
1551+
// every `gen:schema` runs it, which means every shallow job that builds
1552+
// @objectstack/spec (ci.yml `build-core`, docker-publish, release, …)
1553+
// takes this path whenever that build is a cache miss. Tracked in #6452.
1554+
console.log(
1555+
` (shallow history — no merge base is walkable here, so this run anchors on the\n` +
1556+
` origin/main TIP ${tip.slice(0, 12)} instead. ⚠️ Under a tip anchor a key that main ADDED\n` +
1557+
` after this branch forked is indistinguishable from a key this branch DELETED. If a\n` +
1558+
` deletion is reported below for a file you did not touch, check that first — and if\n` +
1559+
` this is CI, the job's checkout step needs \`fetch-depth: 0\` (#6359).)`,
1560+
);
15301561
}
15311562
const baseline = readSurfaceKeysAtRev(
15321563
git,

0 commit comments

Comments
 (0)