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. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 23, 2026
  4. self-assigned this
    on Aug 23, 2026
  5. 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

  6. 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

  7. 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

  8. 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

Labels

ci/cddomain:devxDomain lane — seat card indexed by label:pm:seat

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions