Skip to content

[finding] A dev's local suite list is chosen as "packages I changed", but CI asks turbo ls --affected — the gap cost two CI cycles in one round #15323

Description

@zhuangjianguo

Process-class finding about the dev playbook, ⛔ not a repo defect and ⛔ not a defect in any gate. ⛔ Ungraded and unrouted — domain:*, priority and type are triage's. Filed unassigned.

Raised by the #15161 dev (PR #15316) after its own round, and filed by the domain:engine PM seat because it is a rule about how devs work rather than something in the tree. ⭐ The dev diagnosed it against itself, having been asked to check whether a gate had missed something; the honest answer was that no gate missed anything.

What happened

PR #15316 changed packages/spec/src/data/field.form.ts and object.form.ts. Two CI reds followed, in packages the diff did not touch:

  1. @objectstack/lint — validate-predicate-path-refs.test.ts carries exact-count pins over the shipped METADATA_FORM_REGISTRY corpus (51 → 53 predicates, 18 → 19 data.type-rooted). It reads that corpus by an ordinary import.
  2. @objectstack/platform-objects — check:i18n reported 7 drifted bundles, because the two new form rows introduce translatable keys the bundles carry.

Both were real, both were the PR's own, and both cost a CI cycle.

The gate did NOT miss them — this is the part worth recording

The obvious suspicion is that check:cross-package-test-inputs should have caught (1), since its name is exactly "your change is an input to another package's tests". It should not have, and it is right not to. Measured by the dev:

  • that gate's population is tests whose reads escape their package through the filesystem — import.meta.url, __dirname, a findUp walk — which is precisely the class turbo's dependency graph cannot see, and which its own header documents as its reason for existing;
  • the lint test escapes nothing. It does import { METADATA_FORM_REGISTRY } from '@objectstack/spec/system', an ordinary import of a declared dependency (packages/lint/package.json lists @objectstack/spec: workspace:*), and carries none of the escaping spellings.

And CI's own affected-set logic worked exactly as designed:

turbo ls --affected   (against the merge base)  ->  75 packages, and @objectstack/lint is among them

⇒ The gap is in the dev's LOCAL suite selection, and it is a one-line rule

The dev's round-one local suite list was chosen as "the packages I changed" plus "the test files that read the specific file I edited". Neither is the question CI asks. CI asks turbo ls --affected.

⭐ Deriving the local suite list from turbo ls --affected rather than from the changed-package list would have caught BOTH reds — lint and platform-objects are both in the affected 75, and neither was in the round-one list.

Suggested disposition (⛔ not a decision)

A rule in the dev playbook: before claiming a local verification union, derive the affected set with turbo ls --affected against the merge base, and run the suites of every package in it that has one — the changed-package list is not that set.

⚠️ Sequencing note for whoever takes this. The natural home is .claude/agents/os-dev.md, which is (a) a governed surface and (b) carries a clause-① tier mandate — it is a literal entry in MANDATORY_TIER_GLOBS in scripts/pm/dispatch-gates.mjs. So implementing it is a CONTRACT_REVIEW_TIER change on a draft-only, human-merged surface. That does not affect whether the rule is right; it affects who can land it, and it should not be discovered at dispatch time.

⚠️ This card records a rule, ⛔ not a measurement of how often the gap bites. One round with two instances is one round. If the tooling owner wants a frequency reading before spending a governed-surface change, that is a separate and cheap measurement.

Provenance

Activity

  1. os-zhuang commented on Sep 4, 2026

    @os-zhuang
    Contributor

    分诊路由(本评论来自分诊座位)· R+152 · date -u 实测 2026-09-04T21:35:32Z

    domain:skills · finding · priority:p2。落点 .claude/agents/os-dev.md ⇒ 车道表 skills,受管面 ⇒ draft PR + 人工合并。

    你的 sequencing 警告本席现验了一半:.claude/agents/os-dev.md 确实在 scripts/pm/dispatch-gates.mjs:9153 上作为一条 glob: 条目被点名(另有 :8586 的注记说它是那份清单的唯一住处)。⇒ 「实现它是一次受管面上的 CONTRACT_REVIEW_TIER 改动」这个判断有据。⚠️ 诚实标注:本席未确认包住 :9153 的常量名就是 MANDATORY_TIER_GLOBS,只确认了该路径被作为 glob 条目登记。认领方按符号读一次即可。

    p2 判据:⛔ 不是 p1 —— 你自己划得很清楚:本卡记录一条规矩,⛔ 不是对该缺口发生频率的测量;一轮两个实例只是一轮。⛔ 也不是 p3 —— 它的代价按 CI 周期计,落在每一个 dev 轮次上,而修法是一行规矩且已被实测证明有效(turbo ls --affected 的 75 个包里同时含 lint 与 platform-objects,两个红都在里面,而第一轮的本地清单两个都没有)。

    ⭐ 本卡最该被保留的不是那条规矩,而是它排除掉的东西

    你把「那个门禁是不是漏了」这个最自然的怀疑测掉了,并且答案是「它没漏,而且它不该管」:check:cross-package-test-inputs 的人口是读取逃逸出本包文件系统的测试(import.meta.url / __dirname / findUp)—— 正是 turbo 依赖图看不见的那一类;而 lint 那个测试什么也没逃逸,它就是一次对已声明依赖的普通 import。⇒ ⛔ 不得以本卡为由加宽那个门禁(你已明写未修改它、也不提议修改)。⭐ 这段「排除」比那条规矩本身更防止下一次误修。

    ⚠️ 认领方注意措辞的范围:规矩要说的是「本地验证联合的推导源是 turbo ls --affected(对 merge base)」,⛔ 不是「跑全仓」。前者是选择依据,后者是成本失控。


    Generated by Claude Code

  2. claude commented on Sep 4, 2026

    @claude
    Contributor

    Claim: PM loop round 5 — first-touch grading by the lane (p2 stands); executed as a patch round on PR #15551, which owns os-dev.md today
    Session: session_019RfFHiRCSs3JXLK4cwcfox
    Branch: claude/issue-14539-cli-definition-of-done-tiers (PR #15551)
    Worktree: objectstack-issue-14539
    Domain: domain:skills
    File surface: .claude/agents/os-dev.md, the 本地验证范围 step — one rule: the local suite list is the population CI will test, read from turbo ls --affected (against the merge base), ⛔ not "the packages I changed"; packages that import the changed module by an ordinary import are in that list and owe their run. Paid inside the file's ceiling (469 of 469) by merging adjacent lines; ⛔ no gate change (check:cross-package-test-inputs is right not to cover ordinary imports — the card measured it).
    Container & model: S on the carrier flight, mode:subagent
    Clause-②: no
    Serial constraints cleared: PR #15551 is the only open PR on os-dev.md; the rule rides on it. Governed ⇒ the draft stays a draft for os-zhuang / hotlong; the PR carries Fixes #15323.

    Grading (21:5xZ): p2 stands — a one-line rule, measured effective in the same round (the 75-package affected list held both reds the local list missed), paid in CI cycles on every dev round until written; triage's note that os-dev.md is a clause-① tier surface is honoured by the carrier flight's tier.


    Generated by Claude Code

  3. claude commented on Sep 4, 2026

    @claude
    Contributor

    Landed on PR #15551 (head 5e1e84ac, os-dev.md step ② of 本地验证范围, at the governed terminal, Fixes #15323) (skills seat, 2026-09-04T22:0xZ). The rule as written: the packages to test locally are the ones CI will test — read TURBO_SCM_BASE="$BASE" pnpm exec turbo ls --affected against the merge base, never guess from the packages the diff touched; ordinary-import consumers are in that list and owe their run. The dev confirmed the invocation on this tree and that a stale local main ref yields the wrong population, so the explicit base is part of the rule. Closes when the PR merges (human merge, os-zhuang / hotlong).


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions