Skip to content

pm-dispatch: unlock scan must distinguish "upstream merged" from "consumer can install" — release-gated cross-repo unblocks go pm:on-hold with a Restart-when, not back to queue #11498

Description

@os-zhuang

pm-dispatch: the unlock scan cannot tell "upstream merged" from "consumer can install it" — a cross-repo unblock returned a card to work that no dispatch could run

Authorization

Maintainer, verbatim (未译, in-session 2026-08-24): 「经验是不是应该写入项目 skills」 → 「写入」. This card carries the one lesson that touches the SKILL.md main file (协议语义面, clause ① ⇒ fable tier); the four references/** lessons are a sibling card.

The gap, as lived

A hotcrm card sat pm:blocked on a platform card. The platform card closed (fix merged to objectstack main). By the state model as written, the unlock scan now returns the hotcrm card to pm:queue — but hotcrm consumes published @objectstack/* packages, and the merge was in no release. Any dispatch would have burned a full dev run to discover premise_still_valid: false ("the mechanism I need is not in my installed platform").

The seat improvised the correct handling: keep the card out of the queue as pm:on-hold with a machine-readable Restart-when: whose criterion is the consumer's installed surface (e.g. "installed spec accepts the new key"), not the producer's merge; record the already-shaped wake dispatch on the card so the next seat inherits it.

What SKILL.md should say (self-contained, no issue ids, 中文 house style)

In the unlock-scan / Blocked-by: clause of the state model, add the boundary:

跨仓解锁的判据是「消费方可安装」,不是「上游已合并」。 Blocked-by: 指向的上游关卡时,若消费仓以发布包消费该上游(而非 git pin),解锁扫描先验证修复已进入消费方可安装的发行版(安装面探针:装的包是否接受新键/新行为);未发版 ⇒ 转 pm:on-hold + Restart-when: <消费方安装面判据>,⛔ 不回 pm:queue —— 回队烧掉的派发注定以 premise-false 收场。发行与依赖升级是人工动作;hold 评论应预写唤醒后的派发形状,让任何座位可继承。以 git SHA pin 消费的仓不适用本条(pin 移动即可安装,走既有 pin 滞后读数)。

Fit the wording to the surrounding prose; the boundary sentence (pin-consuming repos excluded) is load-bearing — without it this clause would wrongly hold cards that the existing pin-lag reading already covers.

Process

Draft PR only. This is a governed face: maintainer merges manually (2026-08-11 ruling: skills 更新与 ADR 同级人工审核). The PM's fable-tier review lands on this card before it reaches the maintainer.

Activity

  1. added
    pm:queueReady for the PM dispatch loop
    domain:skillsDomain lane — seat card indexed by label:pm:seat
    on Aug 24, 2026
  2. added theissue type on Aug 24, 2026
  3. claude commented on Aug 24, 2026

    @claude
    Contributor

    Triage (daily round, session session_01Kktexqp6uVuFMztvvTMf3V, 2026-08-24): lands in .claude/skills/pm-dispatch/SKILL.md (protocol semantic face) → domain:skills + pm:queue, Task. Maintainer authorization for the write is quoted in the body (「写入」, 2026-08-24). Clause ① applies: SKILL.md main-file edit ⇒ contract-review-tier dispatch; governed face ⇒ draft PR + human merge. Net-line budget: the skill line ratchet is shrink-only — new text must be paid for by deletion.


    Generated by Claude Code

  4. self-assigned this
    on Aug 24, 2026
  5. os-zhuang commented on Aug 24, 2026

    @os-zhuang
    ContributorAuthor

    Claim: direct-dispatch (skill-experience write-back, maintainer-authorized)
    Session: session_61f28fb9-8e31-4a6f-b4d8-10f749a092d2
    Branch: claude/issue-11498-unlock-release-gate
    Worktree: objectstack-issue-11498
    File surface: .claude/skills/pm-dispatch/SKILL.md ONLY (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: fable — clause ① — SKILL.md 主文件 = 协议语义面, mandatory fable
    Clause-②: no — internal skill/agent tooling; no contract accept/reject change.
    Serial constraints cleared: sibling card #11499 edits references/** only — disjoint files, parallel by construction. No open PR touches .claude/skills/pm-dispatch/ (REST pulls listing checked at claim time).

    Authorization — maintainer, verbatim (未译): 「经验是不是应该写入项目 skills」 → 「写入」 (in-session, 2026-08-24). Per the PM-writes exception this PR carries the authorization in its body and is reviewed by a second tier, ⛔ 不得自审自合 — the maintainer merges manually (governed face).

  6. os-zhuang commented on Aug 24, 2026

    @os-zhuang
    ContributorAuthor
    {
      "issue": 11498,
      "status": "done",
      "branch": "claude/issue-11498-unlock-release-gate",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/11515",
      "premise_still_valid": true,
      "summary": "Added the cross-repo unlock boundary to the unlock-scan clause of the state model's label discipline, as a bullet beside the Blocked-by reverse-index bullet in .claude/skills/pm-dispatch/SKILL.md (only file touched): when the consuming repo consumes the upstream as published packages, the unlock scan verifies the fix is in an installable release (install-surface probe) before returning the card; unreleased routes to pm:on-hold with a consumer-install-surface Restart-when criterion, never back to pm:queue (a re-queued dispatch ends premise-false); release and dependency upgrade are manual, so the hold comment pre-writes the wake dispatch shape; git-SHA-pin consumers are excluded and stay on the existing pin-lag reading (multi-repo coordination rule 2, cross-referenced not duplicated). PM mechanism hypotheses verified before writing: the pm:on-hold Restart-when carrier already accepts a one-line executable criterion (state row, references/state-machine.md read-only, half-state patrol H9), so no new mechanism was added, only routing; the state-row placement was traded for the Blocked-by bullet because the incident fired in the unlock scan's return-on-close duty, which that bullet specifies. Paid under the 666-line ratchet (headroom 0) at net 0 lines by consolidating the twice-stated merged-ref file-surface re-verification rule into its one home (duty 3 of the Blocked-by bullet keeps the rationale; the selection-priority paragraph now points at it) — content deletion, not re-wrap. Guard parsers checked: frame-sync anchors, governed-prose anchor region, id-lint pattern all clear of the edit. Draft PR, human merge (governed face); skip-changeset added via the additive endpoint and read back after the size-labeler PUT.",
      "tests": "Full union re-run after the final commit, at 4ec790ceb; exit codes captured before any pipe; verdict lines quoted. check:pm-skill-ratchet (self-test+gate) 0/0: 'check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md is 666 lines (ceiling 666; headroom 0).' check:pm-skill-id-lint 0/0: 'check-skill-id-lint: 21 file(s) clean'. check:skill-frame-sync 0/0: 'binding sentence present in all 4; 4 count mention(s) agree'. check:pm-governed-prose 0/0: '2 instruction surface(s) name all 5 registered governed surfaces and claim no others'. check:pm-governed-merges --self-test 0: '129 assertions'. check:doc-authoring 0/0: 'doc authoring guard: 389 files clean'. packages/lint check:doc-formula-expressions 0/0: '30 cases passed' / '9 @example(s) judged clean'. check:nul-bytes 0: 'OK (scanned 6455 text file(s), no raw ASCII control bytes)'. Gate list derived by node scripts/pm/dispatch-gates.mjs with no paths (merge-base derivation); its own tree assertion read: gate list derived from the tree of objectstack-ai/objectstack at commit c2dd95147; it also confirmed the mandatory claude-fable-5 tier for this file surface. Deviation declared: scripts/pm/os-verify-lock.sh is unusable on this macOS host — its verdict, exit 99: 'lock-unusable, never acquired, refused before waiting, nothing was built or tested' (stock macOS ships no flock); pnpm install and the formula dependency build the doc-formula gate needed ran in the foreground without the lock; every gate above is a light single-file check.",
      "open_questions": [],
      "out_of_scope_findings": []
    }
  7. os-zhuang commented on Aug 24, 2026

    @os-zhuang
    ContributorAuthor

    PM review (fable tier) — ACCEPT. PR #11515, draft, awaiting the maintainer's manual merge (governed face).

    Reviewed against the diff and the gate outputs, not the report.

    The net-zero payment is real consolidation, not compression

    The 666-line ratchet sits at headroom 0, and the new clause is paid for by collapsing a genuinely twice-stated rule into its one home. Verified both sides of the trade in the diff:

    • The Blocked-by bullet keeps the merged-ref file-surface re-verification duty and absorbs the rationale that previously lived only in the priority section ("上游已合 ≠ 卡还成立 —— 关掉上游的那个合并最可能顺手把你这张卡也修掉") — the reasoning moved with the rule rather than being deleted.
    • The priority section keeps its distinct half (the PM's own "this ruling closed that card" judgement is an assumption, publicly corrected when falsified) and now cross-references the scan's third duty instead of restating it, with an explicit ⛔ 不另抄.

    Both original readers still find their content; each fact has one home. That is the file's own single-source discipline applied to itself.

    The clause is the ruled substance, placed where the incident fired

    Package-consuming repos: unlock verifies an installable release (install-surface probe) before returning the card; unreleased ⇒ pm:on-hold + consumer-install-surface Restart-when:, ⛔ never back to pm:queue; release and dep-bump named as human acts; the hold comment pre-writes the wake dispatch shape for any inheriting seat. The load-bearing boundary survives verbatim in spirit: pin-consuming repos are excluded and stay on the existing pin-lag reading, cross-referenced to 多仓协调 2 rather than duplicated. Placement beside the Blocked-by reverse-index bullet is right — the return-on-close duty this clause constrains is specified there, and the dev's report shows the state-row alternative was weighed, not defaulted.

    Mechanism hypotheses were verified before writing

    The Restart-when: carrier already accepting a one-line executable criterion was confirmed against the state row, references/state-machine.md, and the half-state patrol's own admission predicate — so the edit adds routing, no new mechanism. Guard parsers (frame-sync anchors, governed-prose anchor region, id-lint) checked clear; the full pm-skill gate family re-ran green at the final commit, including the ratchet's own verdict line at 666/666.

    Process hygiene

    Draft ✓, skip-changeset applied via the additive endpoint and read back after the size-labeler's PUT ✓ (the label-race discipline observed, not just known), authorization verbatim in the PR body ✓, no auto-merge ✓.

    To the maintainer: this and the sibling references PR (#11499's, in flight) are yours to merge by hand — skills updates are ADR-grade per your 2026-08-11 ruling. This one is ready.

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

Metadata

Metadata

Assignees

Labels

domain:skillsDomain 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