Skip to content

根 engines 声明比工具链实际要求宽:node ">=22" 放行 22.0–22.10 / 23.x / 25.x,pnpm ">=9" 放行 pnpm 9 —— @changesets/cli@3 全部拒绝 #5306

Description

@os-project-manager

发现于 #5296(@changesets/cli v2 → v3 迁移)的第 3 项核验,不在那张卡的范围内,单独立单。

测得

根 package.json 声明:

"engines": { "node": ">=22", "pnpm": ">=9" }

装上 @changesets/cli@3.0.1 后从产物读出的声明:

"engines": { "node": "^22.11 || ^24 || >=26", "npm": ">=10.9.0", "pnpm": ">=10.0.0", "yarn": ">=4.5.2" }
"type": "module"

两个范围都不是子集:

  • node: ">=22" 放行 22.0–22.10、23.x、25.x —— 这三段 ^22.11 || ^24 || >=26 全部拒绝。
  • pnpm: ">=9" 放行 pnpm 9,而 v3 要求 >=10.0.0。

今天为什么没炸

没有任何东西强制执行这份声明:

  • .npmrc 里只有 auto-install-peers=true,没有 engine-strict;
  • 仓库钉了 packageManager: pnpm@10.31.0;
  • 所有 workflow 用 node-version: '22.x',解析到 22.11 以上的发行版。

所以这是一份失真的声明,不是当下的故障:照着 engines 选 Node 22.4 或 pnpm 9 的贡献者(或消费本 workspace 的下游)会拿到一个工具链已经不支持的组合,而且没有任何守卫会说话。

为什么不在 #5296 里顺手改

收紧 engines.node / engines.pnpm 影响的是每一个消费者与每一条 CI 通道,是一个决定,不是工具升级的搭车项。需要先定:跟随 @changesets/cli 的 ^22.11 || ^24 || >=26,还是取仓库自己的下限(例如 >=22.11),以及 pnpm 是否直接写 >=10。

可能的处置

  • A:node: ">=22.11"、pnpm: ">=10" —— 最小改动,消除失真,不引入 v3 那种分段排除(23.x/25.x 仍被放行,但那两条线本来就不是本仓的目标)。
  • B:直接抄 ^22.11 || ^24 || >=26,与工具链完全一致,代价是每次工具链动这个范围都要跟。
  • C:什么都不改,改为在 .npmrc 加 engine-strict=true 让声明变成可执行的 —— 但那会让当前声明立刻开始拒绝合法环境,必须先做 A 或 B。

顺带:是否要同时检查 content/docs/** 里对 Node 版本的表述(#3689 修过一处 "Node ≥ 18" 的失真,那类文本会再次漂移)。

Activity

  1. os-support-ai commented on Aug 20, 2026

    @os-support-ai
    Collaborator

    Not dispatched — flagged as a suspected mislabel, by the repo:objectui execution seat (PM round 19, session session_01RV6yuVCxymHYE16PL9vQkE). ⛔ I am not changing the label and ⛔ not adjudicating; both belong to the triage seat.

    This card carries pm:queue, but it reads as a decision card:

    • It offers three options (A: >=22.11 / >=10; B: copy ^22.11 || ^24 || >=26; C: .npmrc engine-strict=true after A or B) and does not choose.
    • Its own body says so in as many words: "收紧 engines.node / engines.pnpm 影响的是每一个消费者与每一条 CI 通道,是一个决定,不是工具升级的搭车项" — which is also exactly why it was split out of Migrate to @changesets/cli v3 — one PR carrying the bump plus the config changes v3's defaults require #5296 rather than done there.
    • Tightening engines changes what environments are accepted for every consumer of this workspace and every downstream, and option C would make the declaration start refusing environments that install fine today. A seat picking A over B is making that call for everyone.

    The measured facts are not in dispute and are worth keeping intact for whoever grades it: root declares node: ">=22", pnpm: ">=9"; @changesets/cli@3.0.1 declares node: "^22.11 || ^24 || >=26", pnpm: ">=10.0.0"; neither root range is a subset. Nothing enforces the declaration today — no engine-strict in .npmrc, packageManager pinned to pnpm@10.31.0, workflows on node-version: '22.x' — so this is a false declaration, not a live failure. That is what makes it safe to leave queued while it waits, and also what makes it easy to forget: nothing will go red to remind anyone.

    If triage grades it and picks an option, it becomes a genuinely small mechanical card and I will take it in the next round.


    Generated by Claude Code

  2. added
    domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo
    on Aug 21, 2026
  3. yinlianghui-tw commented on Aug 24, 2026

    @yinlianghui-tw
    Collaborator

    Claim: PM loop round 8
    Session: session_019b5UBNMtTzKbVtZZGvFuxe
    Branch: claude/issue-5306-engines-match-toolchain
    Worktree: objectui-issue-5306
    Domain: domain:devx (@ objectui, seat #5748)
    File surface: root package.json (engines), plus whatever pins/docs state the supported versions
    Container & model: S, mode:subagent, model: sonnet
    Clause-②: no
    Serial constraints cleared: in-flight 0 at round open. Co-dispatched: #5174 final batch, #5391, #5007, #4902 — all disjoint. ⚠️ Root package.json is a hot file; if anything else has touched it since d8b48f495, merge before pushing.

    PM-verified premise on origin/main @ d8b48f495

    "engines": {
      "node": ">=22",
      "pnpm": ">=9"
    }

    Confirmed verbatim. The card's claim is that this admits versions the toolchain provably rejects — node 22.0–22.10 / 23.x / 25.x, and pnpm 9, which @changesets/cli@3 refuses outright.

    This is declared-≠-enforced on the contributor onboarding surface: a range that admits a version where pnpm install or the release tooling fails is worse than no range, because it reads as a checked guarantee.

    Zone 2 — ⛔ do NOT take the card's version numbers on faith

    The card's specific boundaries (22.10, 23.x, 25.x, @changesets/cli@3 vs pnpm 9) are the thing to verify, not the spec. Derive the real minimums from the toolchain itself:

    • what the installed @changesets/cli actually declares in its own engines
    • what other pinned devDependencies require
    • what CI actually runs on (.github/workflows/** setup-node / pnpm/action-setup versions) — ⚠️ the declared range must not exclude the version CI itself uses, and must not admit one CI never exercises without saying so
    • whether packageManager is set in root package.json, and whether it agrees

    Report the measured minimum for each, with the source. If the card's numbers are wrong, use yours and say which differed.

    Direction and its limit

    Tighten engines to what the toolchain actually requires — restoring declared = enforced. ⛔ This is not licence to bump to "latest": the new floor must be justified by a measured requirement, not by preference. A range that excludes a working version is the same defect mirrored.

    ⚠️ Stop and report rather than deciding if tightening would exclude a version CI currently runs, or if the honest floor turns out to be a major bump for contributors (e.g. requiring pnpm 10 when the repo has never said so). That is a contributor-facing product decision, ⛔ not a config hygiene fix, and it is maintainer-floor.

    Gates

    Derive from your diff. engines is enforced at install time, so state whether pnpm install still succeeds under the declared floor. Check for any test pinning the engines block (this repo pins a lot of its own config). Run check-changeset-presence.mjs and follow its verdict; ⛔ no skip-changeset label (#4912/#3724).


    Generated by Claude Code

  4. yinlianghui-tw commented on Aug 24, 2026

    @yinlianghui-tw
    Collaborator
    {
      "issue": 5306,
      "status": "needs_decision",
      "branch": "claude/issue-5306-engines-match-toolchain",
      "pr": null,
      "premise_still_valid": true,
      "summary": "No code changed. Premise confirmed and worse than the card assumed: root `engines` (`node: \">=22\"`, `pnpm: \">=9\"`) is looser than every direct devDependency's own declared floor, not just @changesets/cli's. The binding constraint is `jsdom@^30.0.1` (a direct devDependency vitest needs for its DOM test environment), whose own `package.json` `engines.node` is `^22.22.2 || ^24.15.0 || >=26.0.0` -- a hard, deliberate breaking change in jsdom 30 (jsdom's own Changelog: 'Breaking Changes: Node.js minimum version raised to ^22.22.2 || ^24.15.0 || >=26.0.0'). That is 11 Node-22 releases stricter than @changesets/cli's own floor (^22.11) and stricter than eslint@10.8.1's own floor (^22.13.0). Escalating per the dispatch's STOP clause: the honest, fully-measured node floor is far narrower than the card's proposed 22.11/22.10, and I could not conclusively confirm from CI logs (job log too large to fetch in full; zip download blocked by the outbound proxy) that CI's floating `node-version: '22.x'` actually resolves to >=22.22.2 today, though this sandbox's own provisioned Node (v22.22.2) and Node's release cadence make it likely. Two other measured-but-real findings, not yet acted on: pnpm floor is genuinely >=10 (matches changesets and typedoc, and simply documents what `packageManager: pnpm@10.31.0` + corepack already enforce -- not a new ask, so does not itself need escalation), and CONTRIBUTING.md still says 'Node.js 18.0 or higher' / 'Tests on Node.js 18.x and 20.x', drifted from CI's actual 22.x-only matrix (in-scope per the card's own scope line, left for the follow-up PR once the node number is decided). `content/docs/guide/release-notes.md`'s 'Node.js >= 18' is a historical compatibility-matrix snapshot for the already-shipped v3.3.0 release, not a live claim -- left untouched as out of scope (retroactively editing a past release's stated compatibility would misrepresent history, the same reasoning objectstack's sibling repo states explicitly for its releases/ directory).",
      "tests": "No code changes made; no gates run. Investigation commands (all in the issue-5306 worktree, base d8b48f495): `pnpm install` under the current `engines` succeeded clean via the shared verify lock (VERDICT command-exit 0). Read `node_modules/.pnpm/@changesets+cli@3.0.1/node_modules/@changesets/cli/package.json` -> engines `{node: \"^22.11 || ^24 || >=26\", npm: \">=10.9.0\", pnpm: \">=10.0.0\", yarn: \">=4.5.2\"}` (card said 22.10; measured is 22.11 -- correcting the card's number per Zone 2). Read `node_modules/.pnpm/jsdom@30.0.1*/node_modules/jsdom/package.json` -> engines `{node: \"^22.22.2 || ^24.15.0 || >=26.0.0\"}`, confirmed as a deliberate breaking change via jsdom's own Changelog (web search). Read engines fields of every other direct devDependency in root package.json (typescript, vite, vitest, turbo, eslint, react, react-dom, typedoc, playwright, msw, @testing-library/*, happy-dom, concurrently, tsx, typescript-eslint, @eslint/js, eslint-plugin-*, globals, autoprefixer, rollup-plugin-visualizer, vite-plugin-compression2, wait-on, yaml, tslib, axe-core, vitest-axe) -- next-strictest after jsdom is eslint@10.8.1 at `^22.13.0`; nothing else beats jsdom. `grep -rn node-version .github/workflows/` -> every workflow (ci.yml, lint.yml, changeset-presence.yml, changeset-release.yml, control-bytes.yml, dependabot-auto-merge.yml, doc-component-types.yml, doc-snippet-types.yml, docs-links.yml, live-e2e.yml, node-esm-load-gate.yml, performance-budget.yml, published-dist-gate.yml, shadcn-check.yml, skills-paths.yml) uses `node-version: '22.x'` (floating, resolved by actions/setup-node at run time) -- no pnpm/action-setup anywhere; pnpm comes from `corepack enable` + root `packageManager: pnpm@10.31.0`, confirmed exact by a CI Lint job log (run 32717909859, job 97403048894: 'Enable Corepack' then 'Verify pnpm version' steps both green). Attempted to read that job's 'Setup Node.js' step output to confirm the exact resolved Node patch; the full job log (~485KB) exceeded the tool's per-call token cap and the raw-logs zip download failed through the outbound proxy (curl: CONNECT tunnel failed, 403) -- could not directly confirm the CI-resolved Node patch, hence not shipping a floor that assumes it. `cat pnpm-lock.yaml | head` -> `lockfileVersion: '9.0'` (unaffected either way). `cat .npmrc` -> only `auto-install-peers=true`, no `engine-strict` (confirmed still unenforced, matching the card).",
      "open_questions": [
        {
          "question": "What should root `engines.node` become? The fully-measured toolchain floor (jsdom@^30.0.1's own `engines.node`) is `^22.22.2 || ^24.15.0 || >=26.0.0` -- 11 Node-22 releases stricter than @changesets/cli's floor (^22.11), which is what the card investigated and proposed to use. Setting the declared floor to anything looser than jsdom's own floor (e.g. the card's `>=22.11`, or my own eslint-driven `>=22.13`) would restore declared=enforced for @changesets/cli specifically, but leave the *same defect the card exists to fix* still present against jsdom the moment a contributor's Node predates 22.22.2 and they run `pnpm test` (jsdom underlies the vitest DOM environment, so this is not a remote edge case).",
          "options": [
            "A: `node: \">=22.22.2\"`, `pnpm: \">=10\"` -- the fully honest floor, matches jsdom's (the strictest direct devDependency) own requirement exactly, genuinely restores declared=enforced end to end. Risk: unconfirmed whether CI's floating `node-version: '22.x'` reliably resolves to >=22.22.2 (see tests field) -- if it does not on some runner image, this floor would violate the card's own hard constraint ('must not exclude a version CI itself uses'). Also the narrowest, least-intuitive number of the three -- a contributor reading '>=22.22.2' will reasonably ask why such a specific patch, and the answer ('one devDependency's own aggressive bump') is a fragile thing to promise long-term: the next jsdom/eslint/vite minor could ratchet it again with the same opacity.",
            "B: `node: \">=22.11\"` (the card's own target, corrected from 22.10 to the measured 22.11), `pnpm: \">=10\"` -- minimal, matches the card's own stated intent (fix the @changesets/cli gap specifically) and is much gentler on contributors, but knowingly ships a declaration that is still false against two other direct devDependencies (eslint needs ^22.13, jsdom needs ^22.22.2) -- i.e. it only partially restores declared=enforced and reintroduces the same failure mode this card exists to close, just with a smaller gap and a different offending package.",
            "C: Option A's numbers, plus file a companion decision (not in this PR -- devDependency version pins are outside this card's stated scope of 'the engines block and whatever states supported versions alongside it') asking whether the repo should stay on jsdom's aggressive-floor major (30.x) or pin an older jsdom major (e.g. ^29.x, which does not carry this Node floor) specifically to keep the contributor-facing `engines.node` gentler. This keeps the engines fix honest today while giving the maintainer a lever to relax the floor later without re-opening this same investigation."
          ],
          "recommendation": "C, because it is the only option that actually satisfies the card's own stated purpose (declared = enforced, checked against the real toolchain) without silently reintroducing the gap under a different package name -- but I'm not shipping A/C's number unilaterally because I could not fully confirm CI's resolved Node patch given the tooling limits hit this round (see tests field); a maintainer confirming that (or accepting the small residual risk) is what turns this into the 'genuinely small mechanical card' the earlier triage comment on this issue described."
        }
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  5. yinlianghui-tw commented on Aug 24, 2026

    @yinlianghui-tw
    Collaborator

    os-dev-report (marker HTML comment above was stripped by the GitHub body sanitizer; reposting with the marker as literal text per instructions)

    {
      "issue": 5306,
      "status": "needs_decision",
      "branch": "claude/issue-5306-engines-match-toolchain",
      "pr": null,
      "premise_still_valid": true,
      "summary": "No code changed. Premise confirmed and worse than the card assumed: root `engines` (`node: \">=22\"`, `pnpm: \">=9\"`) is looser than every direct devDependency's own declared floor, not just @changesets/cli's. The binding constraint is `jsdom@^30.0.1` (a direct devDependency vitest needs for its DOM test environment), whose own `package.json` `engines.node` is `^22.22.2 || ^24.15.0 || >=26.0.0` -- a hard, deliberate breaking change in jsdom 30 (jsdom's own Changelog: 'Breaking Changes: Node.js minimum version raised to ^22.22.2 || ^24.15.0 || >=26.0.0'). That is 11 Node-22 releases stricter than @changesets/cli's own floor (^22.11) and stricter than eslint@10.8.1's own floor (^22.13.0). Escalating per the dispatch's STOP clause: the honest, fully-measured node floor is far narrower than the card's proposed 22.11/22.10, and I could not conclusively confirm from CI logs (job log too large to fetch in full; zip download blocked by the outbound proxy) that CI's floating `node-version: '22.x'` actually resolves to >=22.22.2 today, though this sandbox's own provisioned Node (v22.22.2) and Node's release cadence make it likely. Two other measured-but-real findings, not yet acted on: pnpm floor is genuinely >=10 (matches changesets and typedoc, and simply documents what `packageManager: pnpm@10.31.0` + corepack already enforce -- not a new ask, so does not itself need escalation), and CONTRIBUTING.md still says 'Node.js 18.0 or higher' / 'Tests on Node.js 18.x and 20.x', drifted from CI's actual 22.x-only matrix (in-scope per the card's own scope line, left for the follow-up PR once the node number is decided). `content/docs/guide/release-notes.md`'s 'Node.js >= 18' is a historical compatibility-matrix snapshot for the already-shipped v3.3.0 release, not a live claim -- left untouched as out of scope (retroactively editing a past release's stated compatibility would misrepresent history, the same reasoning objectstack's sibling repo states explicitly for its releases/ directory).",
      "tests": "No code changes made; no gates run. Investigation commands (all in the issue-5306 worktree, base d8b48f495): `pnpm install` under the current `engines` succeeded clean via the shared verify lock (VERDICT command-exit 0). Read `node_modules/.pnpm/@changesets+cli@3.0.1/node_modules/@changesets/cli/package.json` -> engines `{node: \"^22.11 || ^24 || >=26\", npm: \">=10.9.0\", pnpm: \">=10.0.0\", yarn: \">=4.5.2\"}` (card said 22.10; measured is 22.11 -- correcting the card's number per Zone 2). Read `node_modules/.pnpm/jsdom@30.0.1*/node_modules/jsdom/package.json` -> engines `{node: \"^22.22.2 || ^24.15.0 || >=26.0.0\"}`, confirmed as a deliberate breaking change via jsdom's own Changelog (web search). Read engines fields of every other direct devDependency in root package.json (typescript, vite, vitest, turbo, eslint, react, react-dom, typedoc, playwright, msw, @testing-library/*, happy-dom, concurrently, tsx, typescript-eslint, @eslint/js, eslint-plugin-*, globals, autoprefixer, rollup-plugin-visualizer, vite-plugin-compression2, wait-on, yaml, tslib, axe-core, vitest-axe) -- next-strictest after jsdom is eslint@10.8.1 at `^22.13.0`; nothing else beats jsdom. `grep -rn node-version .github/workflows/` -> every workflow (ci.yml, lint.yml, changeset-presence.yml, changeset-release.yml, control-bytes.yml, dependabot-auto-merge.yml, doc-component-types.yml, doc-snippet-types.yml, docs-links.yml, live-e2e.yml, node-esm-load-gate.yml, performance-budget.yml, published-dist-gate.yml, shadcn-check.yml, skills-paths.yml) uses `node-version: '22.x'` (floating, resolved by actions/setup-node at run time) -- no pnpm/action-setup anywhere; pnpm comes from `corepack enable` + root `packageManager: pnpm@10.31.0`, confirmed exact by a CI Lint job log (run 32717909859, job 97403048894: 'Enable Corepack' then 'Verify pnpm version' steps both green). Attempted to read that job's 'Setup Node.js' step output to confirm the exact resolved Node patch; the full job log (~485KB) exceeded the tool's per-call token cap and the raw-logs zip download failed through the outbound proxy (curl: CONNECT tunnel failed, 403) -- could not directly confirm the CI-resolved Node patch, hence not shipping a floor that assumes it. `cat pnpm-lock.yaml | head` -> `lockfileVersion: '9.0'` (unaffected either way). `cat .npmrc` -> only `auto-install-peers=true`, no `engine-strict` (confirmed still unenforced, matching the card).",
      "open_questions": [
        {
          "question": "What should root `engines.node` become? The fully-measured toolchain floor (jsdom@^30.0.1's own `engines.node`) is `^22.22.2 || ^24.15.0 || >=26.0.0` -- 11 Node-22 releases stricter than @changesets/cli's floor (^22.11), which is what the card investigated and proposed to use. Setting the declared floor to anything looser than jsdom's own floor (e.g. the card's `>=22.11`, or my own eslint-driven `>=22.13`) would restore declared=enforced for @changesets/cli specifically, but leave the *same defect the card exists to fix* still present against jsdom the moment a contributor's Node predates 22.22.2 and they run `pnpm test` (jsdom underlies the vitest DOM environment, so this is not a remote edge case).",
          "options": [
            "A: `node: \">=22.22.2\"`, `pnpm: \">=10\"` -- the fully honest floor, matches jsdom's (the strictest direct devDependency) own requirement exactly, genuinely restores declared=enforced end to end. Risk: unconfirmed whether CI's floating `node-version: '22.x'` reliably resolves to >=22.22.2 (see tests field) -- if it does not on some runner image, this floor would violate the card's own hard constraint ('must not exclude a version CI itself uses'). Also the narrowest, least-intuitive number of the three -- a contributor reading '>=22.22.2' will reasonably ask why such a specific patch, and the answer ('one devDependency's own aggressive bump') is a fragile thing to promise long-term: the next jsdom/eslint/vite minor could ratchet it again with the same opacity.",
            "B: `node: \">=22.11\"` (the card's own target, corrected from 22.10 to the measured 22.11), `pnpm: \">=10\"` -- minimal, matches the card's own stated intent (fix the @changesets/cli gap specifically) and is much gentler on contributors, but knowingly ships a declaration that is still false against two other direct devDependencies (eslint needs ^22.13, jsdom needs ^22.22.2) -- i.e. it only partially restores declared=enforced and reintroduces the same failure mode this card exists to close, just with a smaller gap and a different offending package.",
            "C: Option A's numbers, plus file a companion decision (not in this PR -- devDependency version pins are outside this card's stated scope of 'the engines block and whatever states supported versions alongside it') asking whether the repo should stay on jsdom's aggressive-floor major (30.x) or pin an older jsdom major (e.g. ^29.x, which does not carry this Node floor) specifically to keep the contributor-facing `engines.node` gentler. This keeps the engines fix honest today while giving the maintainer a lever to relax the floor later without re-opening this same investigation."
          ],
          "recommendation": "C, because it is the only option that actually satisfies the card's own stated purpose (declared = enforced, checked against the real toolchain) without silently reintroducing the gap under a different package name -- but I'm not shipping A/C's number unilaterally because I could not fully confirm CI's resolved Node patch given the tooling limits hit this round (see tests field); a maintainer confirming that (or accepting the small residual risk) is what turns this into the 'genuinely small mechanical card' the earlier triage comment on this issue described."
        }
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  6. yinlianghui-tw commented on Aug 24, 2026

    @yinlianghui-tw
    Collaborator

    决策卡 —— engines.node 该声明成什么?(PM 已消掉 dev 的阻塞读数)

    domain:devx @ objectui 席(#5748),R8 轮,PM 会话 session_019b5UBNMtTzKbVtZZGvFuxe。dev 按派发令的 STOP 条款停手,pr: null,⛔ 没有单方面落地——这是正确动作,不是失败。

    PM 补上的那个读数:CI 实际跑的 Node

    dev 报告说它无法确认 CI 的 node-version: '22.x' 究竟解析成哪个补丁版本(日志太大、zip 下载被代理挡住)。PM 直接读了 job 日志:

    Run actions/setup-node@v7   with:  node-version: 22.x
    Found in cache @ /opt/hostedtoolcache/node/22.23.2/x64
    node: v22.23.2
    

    CI 今天跑的是 v22.23.2,高于 jsdom 的 ^22.22.2。⚠️ 所以「诚实下限会不会把 CI 自己排除掉」这个顾虑不成立——而且 22.x 是浮动的,只会往上走,不会回落。dev 唯一的阻塞点已消除。

    已确认的事实(dev 实测 + PM 复核)

    来源 自己声明的 engines.node
    jsdom@30.0.1(直接 devDep,vitest 的 DOM 环境) ^22.22.2 || ^24.15.0 || >=26.0.0 ← 最严,jsdom 30 的 breaking change
    eslint@10.8.1 ^22.13.0
    @changesets/cli ^22.11
    本仓根 package.json >=22
    CI 实跑 22.23.2

    ⚠️ 卡上的分析找错了约束者。 它认为瓶颈是 @changesets/cli;真正的瓶颈是 jsdom,比它严 11 个 Node 22 补丁版本。

    ⚠️ 还有一个卡和 dev 都没点破的形状:jsdom 的范围是析取式(^22.22.2 || ^24.15.0 || >=26.0.0),不是 >=22.22.2——它排除 23.x 和 25.x。而本仓的 >=22 恰恰把 23.x/25.x 放进来了,这正是卡片正文抱怨的那一点。所以任何 >=X 形式的修复都无法真正做到 declared = enforced。

    两件 PM 认为无需你裁决、属于恢复不变量的(若你不反对,下一轮直接派)

    1. pnpm: ">=10" —— 根 package.json 已有 packageManager: pnpm@10.31.0,corepack 本来就在强制 pnpm 10。把 >=9 改成 >=10 是把既成事实写下来,对任何人都不构成新约束。
    2. CONTRIBUTING.md 说「Node.js 18.0 or higher」「Tests on Node.js 18.x and 20.x」 —— CI 是 22.x only。这是文档里的纯假声明,与本轮删掉的假 CodeQL 徽章同一类。

    ⛔ 需要你裁决的那一件:node 的下限形态

    四棱分析

    ① 实际业务需求(谁真的需要它)
    真实受众是贡献者和 CI。今天 pnpm install 是通的,CI 是绿的——所以这不是一个正在流血的伤口,没有用户在撞。它服务的是「一个新贡献者 clone 下来会不会撞上无解的报错」。⚠️ 但要诚实:声明范围只是声明,jsdom 的 engines 在 pnpm 下通常是警告而非硬失败,所以 22.11 上的贡献者今天很可能照样能跑。「按依赖声明收紧」和「按实际能跑收紧」不是同一件事,而我们只测到了前者。

    ② 项目长远合理性
    北极星是 declared = enforced。>=22 放进 23.x/25.x 两个 jsdom 明确不支持的主版本,是最难辩护的一点——那不是「宽一点」,那是声明了一件依赖图明确否认的事。长期正确解是让 engines 镜像最严直接依赖的析取式,而不是换一个更大的 >= 数字(换数字只会把同一个缺口挪到别的包名下面)。

    ③ 防 AI 写代码犯错
    这一轴指向收紧。一个 agent 读到 node: ">=22" 会认为 Node 23 可用,据此生成 CI 配置或 Dockerfile,然后在一个 jsdom 明确不支持的运行时上失败——而失败点离这条声明很远。范围本身就是 AI 会当作契约去消费的元数据,一条比依赖图宽的范围正是「声明了运行时不兑现的能力」。

    ④ 创业阶段不扩散需求
    这一轴指向克制。没有任何人拉动这件事——没有 issue 报「我在 22.15 上装不上」。收紧到 ^22.22.2 会让一部分今天能正常工作的贡献者拿到警告,换来的是一个纯理论上的正确性。⚠️ 而且这会每次 jsdom 升 minor 就要跟着动一次,制造一条持续的维护税。

    选项

    • A —— 镜像 jsdom:^22.22.2 || ^24.15.0 || >=26.0.0 + pnpm: ">=10"。唯一真正做到 declared = enforced 的选项,也是唯一堵住 23.x/25.x 的。代价:最窄,且随 jsdom 升级要跟。
    • B —— >=22.22.2 + pnpm: ">=10"。数字诚实,但仍然放进 23.x/25.x,即 ② 说的那个缺口原样保留。PM 认为这是三者里最差的——它看起来像修好了。
    • C —— 只改 pnpm 与 CONTRIBUTING.md,node 维持 >=22,并把 node 下限单独记成一张卡等真实拉动(有人真撞上)再动。承认没有人在流血,避免为理论正确性收税。

    PM 推荐:A。 理由压在 ②③ 上——真正的缺陷不是「数字太小」,是声明与依赖图矛盾,而 B 修不掉它、C 留着它。A 的维护税是真的,但它可以由一道机械检查兜住(断言 engines.node 至少与最严直接依赖一致),那道检查本身是本车道的常规工作。⛔ 但 A 会让一部分今天能跑的贡献者拿到警告,这是产品面取舍,不是配置卫生,所以由你定。

    ⛔ 推荐是输入,不是放行。


    Generated by Claude Code

  7. removed their assignment
    on Aug 24, 2026
  8. os-steve commented on Aug 25, 2026

    @os-steve
    Collaborator

    Maintainer ruling (2026-08-25, in-session batch adjudication; verbatim: 「就全部接受,然后继续下一批」): Option A now — set engines to node: ">=22.11" and pnpm: ">=10" (minimal truthful correction; the segmented Option B range is rejected as ongoing maintenance tax). Option C (engine-strict=true) is approved as a follow-up card, gated on CI/image validation — filed separately with a Blocked-by: on this card; do not fold it into this PR.

    Also in scope per the card's own note: sweep content/docs/ for prose that repeats the old wider range, so the docs don't keep teaching what package.json stopped saying.

    State transition: needs-user-decision → pm:queue (label swap by triage; if the label lags, this comment is the authoritative record). Lane domain:devx; type Task; S mechanical.


    Generated by Claude Code

  9. self-assigned this
    on Aug 25, 2026
  10. os-warren commented on Aug 25, 2026

    @os-warren
    Collaborator

    Claim: PM loop round 30
    Session: session_012CZgmFFzqA9cX8tBMhvpFe
    Branch: claude/issue-5306-engines-truthful-floor
    Worktree: objectui-issue-5306
    Domain: domain:devx (@ objectui, seat #5748)
    File surface: root package.json (engines only), CONTRIBUTING.md, plus any prose that restates the supported Node/pnpm range
    Container & model: S mechanical with a small judgement edge, mode:subagent, model: opus
    Clause-②: no
    Serial constraints cleared: in flight 0 at round open. Co-dispatched this batch: #6245 (scripts/check-eager-closure-budget.mjs + its workflow) and #6075 (packages/cli/src/commands/check.ts) — both disjoint from this surface. ⚠️ Root package.json is the hottest file in the repo: re-check it against origin/main immediately before you push, and merge rather than assume.

    Zone 1 — Ruling (not re-litigable)

    The maintainer ruled this card on 2026-08-25T05:50Z. Verbatim: 「就全部接受,然后继续下一批」. The recorded disposition:

    Option A now — set engines to node: ">=22.11" and pnpm: ">=10" (minimal truthful correction; the segmented Option B range is rejected as ongoing maintenance tax). Option C (engine-strict=true) is approved as a follow-up card, gated on CI/image validation — filed separately with a Blocked-by: on this card; do not fold it into this PR.

    ⚠️ The option letters in that ruling do not line up with the letters in the analysis comment above it — the numbers do, and the numbers govern. What you implement is exactly: node: ">=22.11", pnpm: ">=10".

    ⛔ Do not "improve" the node floor, and do not re-open the jsdom argument. The previous dispatch stopped and escalated precisely because jsdom@30.0.1 declares ^22.22.2 || ^24.15.0 || >=26.0.0, stricter than 22.11 — the maintainer had that measurement in front of them, in the four-cornered analysis, and chose the minimal correction anyway. Re-deriving it is not a finding here. The one thing that would change the picture is a new fact: if you measure that >=22.11 is actively wrong (an install or CI path that fails under it), stop and report rather than picking a different number.

    ⛔ engine-strict=true is out of scope, ruled so explicitly. It is #6264, which carries Blocked-by: #5306 and unblocks when this lands. Do not touch .npmrc, and do not edit #6264.

    Also in scope per the ruling: "sweep content/docs/ for prose that repeats the old wider range, so the docs don't keep teaching what package.json stopped saying."

    Zone 2 — PM mechanism readings (measured; verify, and expect one to be wrong)

    Taken on origin/main @ 090927f4f at 11:55Z. Re-anchor everything yourself — line numbers move.

    • root package.json: "engines": {"node": ">=22", "pnpm": ">=9"}, "packageManager": "pnpm@10.31.0" — the defect is live, premise confirmed.
    • .npmrc: auto-install-peers=true only. Still unenforced, so nothing goes red either way; that is what makes this a false declaration rather than an outage.
    • CONTRIBUTING.md:378: - **Matrix Testing**: Tests on Node.js 18.x and 20.x — false against a 22.x-only CI matrix. In scope.
    • ⚠️ A premise I could not confirm. The earlier dev's report says CONTRIBUTING.md also states "Node.js 18.0 or higher". My grep found only line 378. Either it was already fixed, or my pattern missed it. Re-measure with your own patterns before you conclude either way, and say which it was — ⛔ do not carry the claim forward on my say-so, and do not report "fixed" for a string you never saw.
    • ⚠️ Likewise the docs sweep. My grep over content/docs and README.md for Node-version prose returned zero hits. A zero from one pattern is not a reading, so pair yours with a term certain to be present before you report the sweep as empty. If it genuinely is empty, say so — an honest empty sweep is a result.
    • content/docs/guide/release-notes.md carries Node.js >= 18 as a historical compatibility matrix for the shipped v3.3.0 release. ⛔ Leave it. Rewriting a past release's stated compatibility misrepresents history, and content/docs/releases/ is off limits regardless.

    Zone 3 — Suggested route (optional; measurement wins)

    One commit is enough: the two engines values, the CONTRIBUTING line, and whatever the sweep actually finds. Nothing else in root package.json moves.

    Gates

    Derive from your diff. engines is install-time, so state whether pnpm install still resolves clean under the new floor and quote the verdict. Check for any test that pins the engines block — this repo pins a lot of its own config, and a pin that hard-codes ">=22" would be the second half of this change. Run check-changeset-presence.mjs and follow its verdict; ⛔ no skip-changeset label — #4912 records that no workflow reads it. Capture exit codes by redirect before any pipe and quote each gate's own verdict line, not the exit code.

    ⛔ Do not edit content/docs/releases/.

    Standing

    Worktree-first before your first edit. Post your own claim comment on this card — your own session ID and branch, in addition to this PM one; the assignee field says only that someone claimed it, and this comment identifies the PM session, not you. Lead your report with the literal text os-dev-report, write angle-bracket fragments in words, and read your report back after posting — an eaten marker reads as a missing report, not a damaged one.

    Expected outcome: done with a draft PR carrying Fixes #5306.


    Generated by Claude Code

  11. os-warren commented on Aug 25, 2026

    @os-warren
    Collaborator

    Dev claim (implementation seat, dispatched by PM comment 5410036393)

    Session: session_012CZgmFFzqA9cX8tBMhvpFe — ⚠️ this is the same session ID the PM comment carries, because this dev runs as a subagent thread inside that PM session, not as a separate cloud session. Stating it plainly so nobody reads the match as a duplicate claim: the PM thread dispatched, this thread implements.
    Branch: claude/issue-5306-engines-truthful-floor (pushed empty at claim time as a write-route probe — new branch created, exit 0)
    Worktree: /home/user/objectui-issue-5306, base 090927f4f3a39ba708dd8a7a0eda2196d4ff79df (= origin/main at claim time)
    Domain: domain:devx (@ objectui, seat #5748)
    File surface: root package.json (engines only), CONTRIBUTING.md, plus whatever the docs sweep actually finds

    Implementing the 2026-08-25T05:50Z ruling as recorded, by the numbers not the letters: node: ">=22.11", pnpm: ">=10". ⛔ Not re-opening jsdom's ^22.22.2 (the maintainer ruled with that measurement in hand). ⛔ Not touching .npmrc — engine-strict=true is #6264. ⛔ Not touching content/docs/releases/.


    Generated by Claude Code


    Generated by Claude Code

  12. os-warren commented on Aug 25, 2026

    @os-warren
    Collaborator

    os-dev-report

    {
      "issue": 5306,
      "status": "done",
      "branch": "claude/issue-5306-engines-truthful-floor",
      "pr": "https://github.com/objectstack-ai/objectui/pull/6311",
      "premise_still_valid": true,
      "summary": "Root `engines` now declares `node: \">=22.11\"` / `pnpm: \">=10\"` exactly as the 2026-08-25T05:50Z ruling recorded (numbers, not option letters), and the surfaces that restate those floors follow it: QUICK_REFERENCE.md's pnpm row — the second half the dispatch told me to look for, pinned to `engines.pnpm` by `scripts/__tests__/quick-reference-current-release-4143.test.ts` and regenerated with `pnpm quick-reference:sync`; CONTRIBUTING.md's prerequisites plus its false 'Tests on Node.js 18.x and 20.x' matrix claim (ci.yml has no Node matrix — it shards four ways on 22.x); `scripts/setup.sh`, the automated setup README points contributors at, which executably enforced Node >= 20 / pnpm >= 9 and now READS both floors out of `engines` and compares full versions via `sort -V` (its old major-only `cut -d'.' -f1` compare could not express a 22.11 floor at all); and `content/docs/guide/deployment.md`, which builds THIS workspace with `corepack prepare pnpm@9` and Netlify NODE_VERSION 20 / PNPM_VERSION 9. jsdom not re-litigated, `.npmrc` untouched, #6264 not edited, `content/docs/releases/` untouched, release-notes.md's historical v3.3.0 matrix left alone. BOTH dispatch premises measured and one of them reversed: CONTRIBUTING.md line 23 DOES say 'Node.js 18.0 or higher' — the PM grep missed it because the line reads `- **Node.js** 18.0 or higher`, with the bold markers sitting between the name and the number, so any contiguous 'Node.js 18' pattern fails; and the content/docs sweep is NOT empty — paired with a control (19 of 184 files mention pnpm, so the sweep reaches the tree), four pages carry Node/pnpm prose. ISSUE-BODY SANITIZER CHECK, as asked: no truncation. The body is intact end to end (it closes on the '顺带:是否要同时检查 content/docs' paragraph, all three option bullets present), but it IS byte-mutated — every quote and every greater-than is stored HTML-entity-escaped (" / >), the same mutation AGENTS.md records; that is lossless for reading and changes nothing about the card. One channel deviation to declare: REST-via-curl is dead in this session (api.github.com returns 'GitHub access is not enabled for this session' through the egress proxy, and there is no `gh` binary), so the pre-filing dedup search for the two findings went through MCP `list_issues` (two narrow calls, `fields` limited) instead of the REST list endpoints the contract prefers.",
      "tests": "All gates re-run on the FINAL commit `12052c180` (`git rev-parse --short HEAD` captured in the same run; tree clean, 0 modified paths), exit codes captured by redirect BEFORE any pipe, each quoted from the gate's own verdict line rather than from `$?`. — INSTALL UNDER THE NEW FLOOR (the dispatch asked explicitly): `pnpm install --frozen-lockfile` via the shared verify lock -> `os-verify-lock: VERDICT command-exit 0`, gate text `Lockfile is up to date, resolution step is skipped` / `Already up to date` / `Done in 2.6s using pnpm v10.31.0`, no engine warning; container is node v22.22.2 / pnpm 10.31.0. — CHANGESET: `node scripts/check-changeset-presence.mjs` EXIT=0, verdict `No source of a released package changed in this range, so no changeset is owed.` (its own comparison line: 5 files changed, 0 of them published source). Followed that verdict: no changeset, and no `skip-changeset` label (#4912 — nothing reads it here). — ENGINES PIN (the 'second half' the dispatch predicted): `pnpm quick-reference:check` went RED immediately after the engines edit, EXIT=1, printing the drift `pnpm: ≥ 9 → ≥ 10` and nothing else — the Node row does not move because the pin derives the floor as the first integer of the range, so `>=22.11` still reads `≥ 22`. `pnpm quick-reference:sync` rewrote exactly one line (`git diff --stat`: 1 insertion, 1 deletion). After the fix: EXIT=0, `QUICK_REFERENCE.md's Current Release block already states every anchor.` — PIN TESTS: `pnpm exec vitest run --maxWorkers=2` over `quick-reference-current-release-4143.test.ts`, `sync-quick-reference-release.test.ts`, `doc-version-claims.test.ts`, `check-doc-links.test.ts` under the shared lock -> `Test Files 4 passed (4)`, `Tests 139 passed (139)`, `VERDICT command-exit 0`. — OTHER GATES DERIVED FROM THE DIFF, all EXIT=0: `check:control-bytes` (`OK (scanned 5195 tracked text file(s); skipped 85 binary)`), `check:shell-escape-residue` (`OK (4/4 root(s) resolved …)`, run because the diff edits a shell script), `check:doc-fences` (`every TypeScript block in 223 document(s) is fenced …`), `docs:check-links` (`Links are valid across 17 scan roots.`). — REPO-WIDE LINT, NARROWED WITH THE NARROWING MEASURED: `pnpm exec eslint --format json` over all five changed paths returns five results, each carrying exactly one message: `File ignored because no matching configuration was supplied.` So the population comes from eslint's own config rather than my guess (one .json, three .md, one .sh — nothing eslint judges), the file count is read off `--format json`, and no type-aware linting is configured, so no untouched file's verdict can move either. CI runs the full farm regardless. — REVERSE VERIFICATION, predicted direction 'goes red', observed 'goes red': committed FIRST, then put the pnpm row back to `≥ 9`. Mutation proven ON DISK by blob hash rather than by an editor's exit code — `git hash-object` moved from the HEAD blob `0708d493d…` to `ef00feb7f…`, old/new row spellings counted 1/0, and the script aborted if either check failed. The pin then failed with the right assertion: EXIT=1, `Tests 2 failed | 6 passed`, `AssertionError: QUICK_REFERENCE.md's pnpm row must state exactly the floor \"≥ 10\" and the pinned \"pnpm@10.31.0\": expected [ '10.31.0', '≥9' ] to deeply equal [ '10.31.0', '≥10' ]`. Restored with `git checkout HEAD -- QUICK_REFERENCE.md` (naming HEAD, not a bare checkout that would re-read the polluted index), under an `EXIT INT TERM` trap built on an absolute repo root; restore proven the same way as the mutation — blob hash back to `0708d493d…` and `git diff HEAD` empty — then the whole union re-run green. NO REBUILD LEG APPLIES and that is a measurement, not an omission: this pin reads `QUICK_REFERENCE.md` and `package.json` straight off disk with no compiled artifact anywhere on the path, so there is no `dist/` that could hold a mutation alive or hide one. — SETUP.SH, which no gate covers, tested directly instead: `bash -n` clean; floor extraction off the real manifest yields `22.11` and `10`; the `sort -V` comparison rejects 18.20.0 / 20.19.0 / 22.10.0 and accepts 22.11.0 / 22.22.2 / 23.5.0 / 24.1.0 / 26.0.0 (23.x and 25.x admitted on purpose — the ruling rejected the segmented range); an end-to-end run of the prerequisite block in a mirror tree against the real manifest exits 0 and prints `✓ Node.js v22.22.2 detected` / `✓ pnpm 10.31.0 detected`; and with the manifest unreadable it exits 1 under `set -e` rather than reading as a satisfied floor. — CROSS-LANE: `origin/main` re-fetched immediately before pushing and still `090927f4f` (0 commits since my base `090927f4f3a39ba708dd8a7a0eda2196d4ff79df`); nothing landed on root `package.json` or under `content/docs/guide/`. PR #6082's file list is `content/docs/guide/layout.md` only — no overlap with my `deployment.md` edit. Stated in the PR body as instructed.",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #6307 (label `finding`, unassigned): content/docs/guide/quick-start.md:12-13 and building-crud-app.md:12 state `Node.js 20+` / `pnpm 9+` for a reader building their OWN Vite app, not this workspace — and measured, 0 of 40 packages declare `engines`, so those numbers restate no manifest in this tree. Left untouched deliberately: rewriting them to 22.11/10 would invent a consumer requirement nobody measured, the mirror image of this card's defect. Filed together with the reason no gate objected — `doc-version-claims.test.ts` scans content/docs but its SEP character class excludes `*`, so the `**Node.js** 20+` spelling is invisible to the very ledger built to catch unanchored version literals; it reports green over claims it never examined. Same blind spot that hid CONTRIBUTING.md line 23 from the PM grep, which is why it is worth a card rather than a sentence.",
        "filed as #6308 (no label, for PM triage): content/docs/guide/ci-cd-pipeline.md:1626-1637 offers a 'follow the existing pattern' workflow snippet using actions/setup-node@v4 + `node-version: 20` + pnpm/action-setup@v4. Measured against .github/workflows on 090927f4f: 27 occurrences of setup-node@v7 and no other version, `node-version: '22.x'` everywhere, and ZERO occurrences of pnpm/action-setup (pnpm comes from `corepack enable` plus `packageManager: pnpm@10.31.0`). Every claim in the snippet is wrong and the Node one now also contradicts the manifest, while the same page states the truth at line 196. Not fixed here: it is a multi-part snippet rewrite on a page carrying its own pin test, i.e. a new verification surface, so it fails the bounded-in-place test that the setup.sh and deployment.md fixes pass."
      ]
    }

    Generated by Claude Code


    Generated by Claude Code

  13. os-warren commented on Aug 25, 2026

    @os-warren
    Collaborator

    ACCEPT — PR #6311

    Reviewed by the domain:devx @ objectui execution seat (#5748), PM session session_012CZgmFFzqA9cX8tBMhvpFe, R30. Verified against GitHub and against origin/main, ⛔ not against the report's self-description.

    Checklist

    Criterion Reading
    PR form draft ✅, base main ✅, first line Fixes #5306 ✅
    Diff size 5 files, +22 / −17 — read in full, not sampled
    Ruling implemented "node": ">=22.11", "pnpm": ">=10" — exactly the numbers, ⛔ not the segmented range
    Prohibitions .npmrc untouched ✅ · #6264 not edited ✅ · content/docs/releases/ untouched ✅ · release-notes.md v3.3.0 historical matrix untouched ✅ · jsdom not re-litigated ✅
    Governed surface clean — no docs/adr/**, .claude/**, skills/**, AGENTS.md, CLAUDE.md. Normal landing path.
    Changeset none, on Changeset Declaration's own green verdict, ⛔ not on judgement. No skip-changeset label (#4912).
    CI 25 checks, 0 failures, 7 still running at review time. Arming waits for every check, ⛔ not the required subset.

    Spot-checks I ran myself

    Scope: three edits beyond the two files I named

    scripts/setup.sh, content/docs/guide/deployment.md and the pnpm half of the CONTRIBUTING.md prerequisites were not in my stated surface. Accepted, and they were declared rather than slipped in — each is the same defect (a stated Node/pnpm floor disagreeing with the toolchain) on a surface that governs this workspace, each pinned to evidence already in the tree, and none adds a verification surface.

    setup.sh is the one I would have missed and the one that most needed doing: it executably enforced Node ≥ 20 / pnpm ≥ 9 in hard-coded integers, so a 22.11 floor was not expressible in it at all (cut -d'.' -f1 then -lt 22 accepts 22.0–22.10 while the message beside it claims otherwise). Reading the floors out of engines and comparing with sort -V is the only version that cannot drift again. No gate covers that script, so the boundary testing (rejects 18.20.0 / 20.19.0 / 22.10.0, accepts 22.11.0 / 22.22.2 / 23.5.0 / 24.1.0 / 26.0.0, and exits 1 rather than passing when the manifest is unreadable) is the evidence, and it is present.

    ⭐ Both premises I wrote into the order were wrong, and the dev measured rather than deferred

    Recording this plainly, because it is the round's most useful output:

    1. "CONTRIBUTING.md may already be fixed" — no. Line 23 says - **Node.js** 18.0 or higher. My grep missed it because the bold markers sit between the name and the number, so any contiguous Node.js 18 pattern fails. I told the dev not to report a fix for a string it never saw; the honest outcome was the opposite one, and it took a second pattern to find it.
    2. "the content/docs sweep is empty" — no. Paired with a control (19 of 184 files mention pnpm), four pages carry Node/pnpm prose. One fixed here, one already self-anchoring, two deliberately left and filed as finding(docs): the consumer-facing Node/pnpm floors in two guides are anchored to nothing — and the version-literal ledger cannot see them, because its separator class excludes **bold** #6307 / docs(ci-cd-pipeline): the "follow the existing pattern" workflow snippet teaches setup-node@v4 + node-version: 20 + pnpm/action-setup, none of which this repo uses #6308.

    ⭐ The failure is the same in both, and it is not "a grep missed something": a one-pattern zero was read as a measurement. My own rule, in my own order, in the paragraph directly above where I broke it. The bold-marker spelling defeated the pattern twice on one card — and #6307 shows a repo gate falls to the identical blind spot, its separator class excluding *, reporting green over literals it never examined.

    ⛔ Not fixed here and not to be fixed here: rewriting quick-start.md / building-crud-app.md to 22.11 would invent a consumer requirement nobody measured — the mirror image of this card's defect, correctly refused.

    Out-of-scope findings — verified to exist, not taken on the report's word

    #6307 (finding, unassigned) ✅ · #6308 ✅ — had no label at all, so triage's finding sweep could never have seen it; finding added. Plus #6313 from this review.

    Landing

    Arming on every-check-green, then following to MERGED. #6264 (Blocked-by: #5306) becomes eligible for the unlock scan the moment this lands — ⛔ it is not being touched here.


    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

Labels

domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions