Skip to content

release: switch the changesets version workflow ("Version Packages" PR refresh) from every-merge-to-main to manual dispatch before a release #10850

Closed
objectstack-ai/objectui
#5762

Description

@huangyiirene

Filed by the skills seat (session_01ApyDuQY2fkunMCqXiqvBhR) on the maintainer's direct instruction. Dedup-searched ("Version Packages", changesets version workflow): no existing card; the only neighbour is the epic noted under Coordination.

Provenance (maintainer, PM chat 2026-08-21, verbatim, untranslated)

我每周才发一次版本,changeset 每个pr 都跑有必要吗

After the assessment (keep per-PR changeset validation; cut the per-merge Version-Packages refresh):

立卡吧,version 工作流改成发版前手动触发

包括 objectui 仓库

What to change

The workflow that runs changeset version and creates/refreshes the "Version Packages" PR currently fires on every push to main (~18 merges/day at current cadence, each refresh burning a CI run) while releases are weekly. Change its trigger to workflow_dispatch only — the maintainer runs it right before cutting a release.

  • Locate the actual workflow first (likely .github/workflows/release.yml; measure, don't assume) and confirm which job half does the version-PR refresh vs the publish half.
  • Publish/release stays exactly as it is: releases are human-only in this repo (AGENTS.md "release act"), and this change strengthens that posture — the Version Packages PR appears only when a human asks for it.

Explicitly NOT in scope (ruled to keep)

Per-PR changeset validation gates stay on every PR: check-changeset-no-major, check-empty-changeset, check-adr-0087-registration, check:changeset-gate-self-tests, check:objectui-changeset, and the requirement that each PR carries its changeset. The ruling cuts the per-merge version-PR refresh only, not authoring-time validation.

Acceptance criterion (one line, executable)

After landing: the version-PR job's on: triggers contain workflow_dispatch and no push-to-main path, and a test merge to main starts zero Version-Packages refresh runs (verify in the Actions run list).

Coordination

⚠️ Epic #9465 (changesets v3 migration) declares .github/workflows/release.yml and cut-rc.yml in its file territory for its duration; 4/5 sub-issues are complete and #9500 is parked on the next pre-mode window, while #9499 rules on changesets/action v1→v2 against release.yml's pinned rationale. The executing seat must sequence this edit with the epic PM (or land it as agreed cleanup as the epic winds down) — two writers on one release machine is the shape that epic exists to prevent.

Sister card for the objectui repo follows (same ruling, that repo's own workflow); cross-link added when it exists.

Activity

  1. huangyiirene commented on Aug 21, 2026

    @huangyiirene
    CollaboratorAuthor

    Sister card filed: objectstack-ai/objectui#5571 (same ruling, objectui's own workflow — with a premise-first clause in case that repo has no per-merge refresh to begin with).


    Generated by Claude Code

  2. huangyiirene commented on Aug 21, 2026

    @huangyiirene
    CollaboratorAuthor

    Triage: lands in .github/workflows/ (version-PR refresh trigger) — domain:devx, ci/cd added; type Task and pm:queue already set by the filing seat on the maintainer's direct instruction. Rationale: workflow-engineering face, release ACT itself stays human (the card strengthens that posture). ⚠️ Dispatch constraint already in the body and binding: epic #9465 declares release.yml/cut-rc.yml territory — the executing seat must sequence with the epic PM before touching that file. Sister card: objectui#5571.


    Generated by Claude Code

  3. self-assigned this
    on Aug 23, 2026
  4. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    Contributor

    CLAIM(重限定为 objectui 半边)— session 757f0dc0-5dae-51d7-9053-c15c57ebfe3b(skills 席),branch(objectui 仓)claude/issue-10850-version-pr-schedule。

    前提刷新与范围重限定:

    1. objectstack 半边已交付:PR ci(release): refresh the Version Packages PR on a schedule, not on every push #11238(卡 release.yml 的 version-pr 车道改为「定时 + 按需」刷新——终结 Version Packages PR 被每次 main push 强刷、CI 永不收敛的合并竞态 #11233,维护者 2026-08-23 当面拍板「立卡派发 release.yml 的定时化改造」)把 version-pr 改为 0 */6 * * * schedule + refresh_version_pr 按需 dispatch。设计相对本卡 08-21 原案(「workflow_dispatch only」)多了 6 小时 cron——这是 2026-08-23 维护者对「定时 + 按需」方案的明示采纳,时间更晚、更具体,取代本卡的 manual-only 拼写;动机(每合并一次白烧一轮 CI、周发版频率)两案同治。
    2. 本卡剩余范围 = 维护者原话「包括 objectui 仓库」:objectui .github/workflows/changeset-release.yml 仍在每次 main push 上重刷其 Version Packages PR(E7 翻转后,「适配器无 setFallbackHandler」仍只记 debug —— 声明式端点静默不可达,而代码注释自己写明此时应转 warn #5400)。⚠️ 与 objectstack 不同,objectui 的该工作流自身携带 publish(合并 version PR 后自动发布,靠 per-commit concurrency + wait-older-runs 自排队串行)——改触发器时其发布路径与排队器必须原样保留。

    Generated by Claude Code

  5. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    Contributor
    {
      "issue": 10850,
      "status": "done",
      "branch": "claude/issue-10850-version-pr-schedule",
      "pr": "https://github.com/objectstack-ai/objectui/pull/5762",
      "premise_still_valid": true,
      "summary": "objectui half only, per the rescope in this card's claim comment (the objectstack half landed as PR #11238). objectui's `.github/workflows/changeset-release.yml` moved its Version-Packages refresh off `push` onto a 6-hourly `schedule` plus a `workflow_dispatch` input `refresh_version_pr` (boolean, default false), while the publish path keeps `push` exactly as it was. objectui's workflow is structurally unlike objectstack's: ONE changesets step carries both `version:` and `publish:`, and the action picks its branch from repository state, not from configuration. Its v1 source shows the asymmetry that drove the design -- omitting `publish:` makes publishing unreachable by construction, but omitting `version:` does NOT disable the refresh (runVersion falls back to bare `changeset version`). So the refresh lane is closed by construction, and the publish lane could only be closed by not invoking the action at all on a push carrying pending changesets. Chosen shape: a second job in the SAME file -- a cheap `lane` job (sparse checkout of `.changeset/`, `contents: read`) emits the single fact `pending_changesets`, the release job carries `needs: lane` plus one job-level `if:` holding the whole policy, and the changesets step is split into two mutually exclusive steps of which the refresh one has no `publish:` input and no npm credentials in env. The per-commit concurrency group and the 'Wait for older release runs' step are preserved byte-identically (the wait step verified mechanically at 2031 bytes vs origin/main); only prose the trigger change falsifies was updated. No gate added or removed.",
      "tests": "All at final commit b38e47f68 (union run after committing), each verdict quoted from the gate's own output line. vitest on the 4 test files that read this workflow: 'Test Files  4 passed (4)' / 'Tests  72 passed (72)'. `pnpm changeset:check`: 'All workspace packages are in the changeset fixed group.' + 'No changeset declares a major bump.'. `pnpm check:control-bytes`: 'check-control-bytes: OK (scanned 4803 tracked text file(s); skipped 85 binary).'. `pnpm docs:check-links`: 'Links are valid across 13 scan roots.'. `node scripts/check-changeset-presence.mjs`: 'No source of a released package changed in this range, so no changeset is owed.' -- so no changeset is owed and objectui has no skip-changeset label (confirmed: the repo's own docs record it never existed). YAML validated with the workspace's own yaml@2.9.0: 'parse errors: 0 warnings: 0', and `on:` parses as the string key rather than YAML-1.1 true. Heavy runs went through scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, waited 0s). ABLATION on the new detection logic: the script under test was EXTRACTED FROM THE SHIPPED YAML so what ran is what ships; the oracle is the real @changesets/read@1.0.0 plus the action's own readChangesetState filtering rule transcribed from its fetched source. Mirror and oracle agree on all 5 fixtures (main as it stands = 157 changesets -> true; version-PR-just-merged README-only -> false; pre mode all consumed -> false; pre EXITED same files -> true; only-an-empty-changeset -> true). The comparison was proven able to fail: removing the README.md exclusion was confirmed on disk by an anchored observation (README.md mentions 1 -> 0, 1189 -> 1134 bytes), after which the README-only fixture DIVERGED (mirror true vs oracle false); the restore leg was confirmed the same way (mentions back to 1) and agreement returned. No build/dist is involved, so no rebuild leg applies. Reported honestly: a FIRST attempt at that mutation did not land -- the perl anchor missed the extracted script's indentation and exited 0 -- and that reading was discarded as void rather than reported. LINT was narrowed to changed files, declared as a measurement: eslint's own config reports the .yml and .md files as 'File ignored because no matching configuration was supplied' (so 1 of 3 changed files is lintable), --format json counts 3 files reported / 0 errors, and eslint.config.js enables no type-aware linting (no projectService/project:), so this diff cannot move the verdict on any untouched file. NOT verified locally by design: the acceptance criterion ('a test merge to main starts zero Version-Packages refresh runs') is only observable in the Actions run list after landing; CI convergence is the PM's read.",
      "open_questions": [
        {
          "question": "objectui#5571 is the sister card filed for exactly this objectui half, still open and unassigned. This PR carries a closing keyword for objectstack#10850 only, so #5571 will stay open after the merge.",
          "options": [
            "A: close #5571 as delivered-by objectui#5762, leaving #10850 as the card of record",
            "B: retarget the PR's closing keyword to #5571 and close #10850 separately once both halves have landed",
            "C: leave both open until the acceptance criterion is observed in the Actions run list"
          ],
          "recommendation": "A -- the dispatched card is #10850 and its claim comment records the rescope, so #10850 is the card of record; #5571 is a duplicate of the half this PR delivers and should be closed with a pointer. I did not touch it: it is unassigned and closing another seat's card is a PM call."
        },
        {
          "question": "Footer form: the dispatch specified the bare `_Generated by [Claude Code](https://claude.ai/code)_`, but the standing os-dev contract requires the session-URL form because the bare one is stripped on every subsequent body edit. I used the session-URL form and am flagging the conflict rather than silently choosing.",
          "options": [
            "A: keep the session-URL form (what I did)",
            "B: rewrite the footer to the bare form as literally dispatched"
          ],
          "recommendation": "A, and it was validated empirically in this very run: GitHub's sanitizer ate two `<sha>` placeholders from the body at creation, I edited the body to repair them, and the session-URL footer survived that edit -- a bare footer would have been destroyed by it."
        }
      ],
      "out_of_scope_findings": []
    }

    Draft PR: objectstack-ai/objectui#5762 — held in draft pending PM review, no ready/queue/auto-merge action taken. objectui's governed surface (AGENTS.md, CLAUDE.md, .claude/**, docs/adr/**) is not touched by this diff, so the ordinary path would apply once reviewed.


    Generated by Claude Code

  6. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    Contributor

    os-dev-report

    (Supersedes the previous comment: its HTML-comment marker was eaten by GitHub's body sanitizer on the way into storage, which makes that copy invisible to the PM's marker scan. Same report, literal-text marker, one placeholder repaired. No comment-update tool is available to this seat, hence a repost rather than an edit.)

    {
      "issue": 10850,
      "status": "done",
      "branch": "claude/issue-10850-version-pr-schedule",
      "pr": "https://github.com/objectstack-ai/objectui/pull/5762",
      "premise_still_valid": true,
      "summary": "objectui half only, per the rescope in this card's claim comment (the objectstack half landed as PR #11238). objectui's `.github/workflows/changeset-release.yml` moved its Version-Packages refresh off `push` onto a 6-hourly `schedule` plus a `workflow_dispatch` input `refresh_version_pr` (boolean, default false), while the publish path keeps `push` exactly as it was. objectui's workflow is structurally unlike objectstack's: ONE changesets step carries both `version:` and `publish:`, and the action picks its branch from repository state, not from configuration. Its v1 source shows the asymmetry that drove the design -- omitting `publish:` makes publishing unreachable by construction, but omitting `version:` does NOT disable the refresh (runVersion falls back to bare `changeset version`). So the refresh lane is closed by construction, and the publish lane could only be closed by not invoking the action at all on a push carrying pending changesets. Chosen shape: a second job in the SAME file -- a cheap `lane` job (sparse checkout of `.changeset/`, `contents: read`) emits the single fact `pending_changesets`, the release job carries `needs: lane` plus one job-level `if:` holding the whole policy, and the changesets step is split into two mutually exclusive steps of which the refresh one has no `publish:` input and no npm credentials in env. The per-commit concurrency group and the 'Wait for older release runs' step are preserved byte-identically (the wait step verified mechanically at 2031 bytes vs origin/main); only prose the trigger change falsifies was updated. No gate added or removed.",
      "tests": "All at final commit b38e47f68 (union run after committing), each verdict quoted from the gate's own output line. vitest on the 4 test files that read this workflow: 'Test Files  4 passed (4)' / 'Tests  72 passed (72)'. `pnpm changeset:check`: 'All workspace packages are in the changeset fixed group.' + 'No changeset declares a major bump.'. `pnpm check:control-bytes`: 'check-control-bytes: OK (scanned 4803 tracked text file(s); skipped 85 binary).'. `pnpm docs:check-links`: 'Links are valid across 13 scan roots.'. `node scripts/check-changeset-presence.mjs`: 'No source of a released package changed in this range, so no changeset is owed.' -- so no changeset is owed and objectui has no skip-changeset label (confirmed: the repo's own docs record it never existed). YAML validated with the workspace's own yaml@2.9.0: 'parse errors: 0 warnings: 0', and `on:` parses as the string key rather than YAML-1.1 true. Heavy runs went through scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, waited 0s). ABLATION on the new detection logic: the script under test was EXTRACTED FROM THE SHIPPED YAML so what ran is what ships; the oracle is the real @changesets/read@1.0.0 plus the action's own readChangesetState filtering rule transcribed from its fetched source. Mirror and oracle agree on all 5 fixtures (main as it stands = 157 changesets -> true; version-PR-just-merged README-only -> false; pre mode all consumed -> false; pre EXITED same files -> true; only-an-empty-changeset -> true). The comparison was proven able to fail: removing the README.md exclusion was confirmed on disk by an anchored observation (README.md mentions 1 -> 0, 1189 -> 1134 bytes), after which the README-only fixture DIVERGED (mirror true vs oracle false); the restore leg was confirmed the same way (mentions back to 1) and agreement returned. No build/dist is involved, so no rebuild leg applies. Reported honestly: a FIRST attempt at that mutation did not land -- the perl anchor missed the extracted script's indentation and exited 0 -- and that reading was discarded as void rather than reported. LINT was narrowed to changed files, declared as a measurement: eslint's own config reports the .yml and .md files as 'File ignored because no matching configuration was supplied' (so 1 of 3 changed files is lintable), --format json counts 3 files reported / 0 errors, and eslint.config.js enables no type-aware linting (no projectService/project:), so this diff cannot move the verdict on any untouched file. NOT verified locally by design: the acceptance criterion ('a test merge to main starts zero Version-Packages refresh runs') is only observable in the Actions run list after landing; CI convergence is the PM's read.",
      "open_questions": [
        {
          "question": "objectui#5571 is the sister card filed for exactly this objectui half, still open and unassigned. This PR carries a closing keyword for objectstack#10850 only, so #5571 will stay open after the merge.",
          "options": [
            "A: close #5571 as delivered-by objectui#5762, leaving #10850 as the card of record",
            "B: retarget the PR's closing keyword to #5571 and close #10850 separately once both halves have landed",
            "C: leave both open until the acceptance criterion is observed in the Actions run list"
          ],
          "recommendation": "A -- the dispatched card is #10850 and its claim comment records the rescope, so #10850 is the card of record; #5571 is a duplicate of the half this PR delivers and should be closed with a pointer. I did not touch it: it is unassigned and closing another seat's card is a PM call."
        },
        {
          "question": "Footer form: the dispatch specified the bare `_Generated by [Claude Code](https://claude.ai/code)_`, but the standing os-dev contract requires the session-URL form because the bare one is stripped on every subsequent body edit. I used the session-URL form on the PR and am flagging the conflict rather than silently choosing.",
          "options": [
            "A: keep the session-URL form (what I did)",
            "B: rewrite the footer to the bare form as literally dispatched"
          ],
          "recommendation": "A, and it was validated empirically in this very run: GitHub's sanitizer ate two angle-bracket placeholders from the PR body at creation, I edited the body to repair them, and the session-URL footer survived that edit -- a bare footer would have been destroyed by it. The same sanitizer then ate this report's HTML-comment marker, which is why this comment exists."
        }
      ],
      "out_of_scope_findings": []
    }

    Draft PR: objectstack-ai/objectui#5762 — held in draft pending PM review, no ready/queue/auto-merge action taken. objectui's governed surface (AGENTS.md, CLAUDE.md, .claude/**, docs/adr/**) is not touched by this diff, so the ordinary path would apply once reviewed.


    Generated by Claude Code

  7. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    Contributor

    本 issue 在本次合并之前就已经是 closed 状态,这里只补上修复它的 PR:objectstack-ai/objectui 的 https://github.com/objectstack-ai/objectui/pull/5762。本工作流没有改动它的状态。

    (跨仓库的关闭关键字不会自动生效,本条由 cross-repo-issue-closer 工作流代为收口。)


    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

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions