Repository navigation
Commit d20bf9b
docs(pm-dispatch): split a card that straddles an unreachable repository by repository (ruling D) (#24712)
Fixes #24591
Clause-②: no
Ruled: letter D, ruling record `6279888513` (director seat, batch
#373 item 3, 2026-10-19T23:48Z). The
maintainer's two sentences, verbatim:
- 「这一类的卡片能否直接把 cloud 部分分拆成一个 cloud 车道的卡片」
- 「如果没有办法分拆,就立一张 cloud 车道的前置卡」
What the ruling binds, items 1-3 verbatim. Items 4 and 5 are already on
`main`: item 4 is the reading definition in AGENTS.md, and item 5 is the
decision-card rule in SKILL.md. They are not restated here.
1. 「A card whose premise or fix has a part in a repository its lane
cannot reach (cloud today) is split by repository at filing or at first
touch: the cloud part becomes a `repo:cloud` lane card, filed by a seat
that reaches cloud (the filer, when it is the cloud seat; otherwise the
objectstack seat asks through the cross-repo request path — a comment on
the cloud seat post naming the step, or parking the cloud part in this
repository under `domain:cloud` + `status:parked` for the cloud PM to
migrate); the objectstack part stays in its lane and carries only what
objectstack needs. Neither lane reads the other repository.」
2. 「Where the objectstack part depends on the cloud part, the
objectstack card goes `pm:blocked` with `Blocked-by:
objectstack-ai/cloud#N` and returns to its queue when that card closes
(the unlock scan's cross-repo spelling; where the cloud part ships
through a pin, the consumer-installable test applies).」
3. 「When the card cannot be split — its question or fix needs both
repositories at once — a cloud-lane prerequisite card is filed first
(the cloud seat reads, decides or fixes its side and records the result
on that card), and the objectstack card waits on it as in 2; the
objectstack half then proceeds on the prerequisite card's recorded
result.」
The workload line, verbatim:
「skills lane · 1 Tier S text PR: `cross-repo-coordination.md` L51's rule
becomes the split / prerequisite rule above (one or two lines,
line-neutral at the file's ceiling); `reading-discipline.md` L17
unchanged · precedent PR #24521 (+2/−2).」
## What changed: two lines in one file, no net lines
The file is
`.claude/skills/pm-dispatch/references/cross-repo-coordination.md`,
lines 50-51. Base is `8e14ce057`, which was `origin/main` at dispatch.
It already carries line 37 from PR #24691. Head is `ad5a10688`. Byte
counts are of the whole line, with the leading list marker included and
the newline left out. The cap is `MAX_LINE_BYTES = 120`
(`scripts/pm/check-skill-line-ratchet.mjs`). The file stays at 51 lines
against a ceiling of 51.
- line 50
- before (109 bytes): 「等待方同一笔把自卡翻 `pm:blocked` + `Blocked-by:` 指向请求卡;⛔
不设新标签新 sweep。」
- after (119 bytes): 「跨不可达仓的卡立卡或首触按仓拆:该仓部分由可达席立卡,或挂
`domain:cloud`+`status:parked`。」
- line 51
- before (119 bytes): 「目标仓不可达是读数缺口,不是落点:由可达席在目标仓立卡,此前请求记座位贴或协调卡。」
- after (120 bytes): 「本卡只留本仓活,不读他仓;拆不开先立该仓前置卡;依赖即
`pm:blocked`+`Blocked-by: owner/repo#N`。」
- Lines 48 (117 bytes) and 49 (107 bytes) are unchanged. They are the
cross-repo request path that item 1 names: a request rides on the
existing card, with a comment naming the seat and the step.
- `reading-discipline.md` line 17 is unchanged, as the workload line
requires.
How the two lines map onto the ruling:
- New line 50 carries item 1's first half. A card that straddles an
unreachable repository is split by repository at filing or first touch.
A reaching seat files that repository's part, or the part is parked here
under `domain:cloud` + `status:parked`.
- New line 51 carries the rest of item 1: this card keeps only its own
repository's work and does not read the other. It also carries item 3:
when the card cannot be split, that repository's prerequisite card is
filed first. Finally it carries item 2: the dependent card goes
`pm:blocked` + `Blocked-by: owner/repo#N`. That is the generic spelling
`state-machine.md:23` defines for the ruling's `objectstack-ai/cloud#N`.
- Old line 50 said 「等待方同一笔把自卡翻 `pm:blocked` + `Blocked-by:` 指向请求卡」. It
points the same way as item 2, so it is folded into new line 51's
`pm:blocked`+`Blocked-by:` clause. Old line 51 is the rule the ruling
replaces.
## What the 240 bytes could not carry, and the text on `main` that
already carries it
Two lines at 120 bytes each cannot hold every clause of items 1-3 plus
old line 50. These clauses are left to text already on `main`:
- Item 1, "otherwise the objectstack seat asks through the cross-repo
request path — a comment on the cloud seat post naming the step": this
is lines 48-49, kept verbatim. The parking alternative on line 50 needs
no request at all.
- Item 2, "returns to its queue when that card closes": `SKILL.md:108`,
the `pm:blocked` row (released by the unlock scan).
- Item 2, "where the cloud part ships through a pin, the
consumer-installable test applies": `SKILL.md:137-141`, which says
「跨仓解锁判据是消费方可安装」 and that pin-consumed repositories read pin lag.
- Item 3, "the cloud seat ... records the result on that card ... the
objectstack half then proceeds on the prerequisite card's recorded
result": ruling item 4 and AGENTS.md's 「A reading you cite is a count
plus the tree it was taken against」. A reaching seat's verbatim
quotation with repository and commit is the reading the lane acts on.
- Old line 50, 「同一笔」: `SKILL.md:269` 「受阻执行卡同笔挂
`pm:blocked`+`Blocked-by:`」 and `SKILL.md:142` 「状态变更不过夜」.
- Old line 50, 「⛔ 不设新标签新 sweep」: both new lines name only labels and
readers that already exist (`domain:cloud`, `status:parked`,
`pm:blocked`, `Blocked-by:`). The state model holds the rest:
`SKILL.md:136` 「一个标签存在当且仅当有具名读者」, and `state-machine.md:26` 「⛔ 不设新标签」.
## Reader check: who reads `Blocked-by: owner/repo#N`, item 2's
cross-repo spelling
This was read on this branch's tree; no script is changed here.
- `state-machine.md:23` defines the spelling: 「正典标记 = 行首 `Blocked-by:
#N`(跨仓 `owner/repo#N`)」.
- `scripts/pm/check-half-states.mjs` parses it. `blockedByTargets` (line
3744) collects an optional `owner/repo` or bare `repo` qualifier before
each `#N`. H4's presence test accepts any value, so a cross-repo-only
line counts as present. `buildBlockingIndex` (line 3797) skips
cross-repo refs on purpose, because it asks which local card is waiting.
H19 does resolve cross-repo targets (`blockerTargetKey`, line 4814), but
only when the target repository answers the install's own repo-scoped
token. Otherwise it reports the block UNJUDGED as a loud row. The header
(line 61) says so: "cross-repo `Blocked-by:` targets stay unresolvable
per install (each token reads its own repo), so H19 reports them as
UNJUDGED — accepted, and made loud separately."
- `scripts/ci/scheduled-full-run.mjs`, driven by
`scheduled-full-run-card.yml`, reads `Blocked-by:` only on the hourly
full-run card it refreshes. It never releases that card on a closed
cross-repo target (workflow header, line 52).
- `scripts/pm/sweep-closed-cards.mjs` has no `Blocked-by:` reader. It
matches zero times, case-insensitive, for "blocked". It only strips
residue state labels from cards that are already closed.
- The release itself is the unlock scan, which is a seat procedure.
`dispatch-runbook.md:72` says 「逐仓 `state=CLOSED` + `since` 与
`Blocked-by:` 反向索引求交」.
Conclusion: the spelling is defined and parsed, and no reader refuses
it. What no script does from this repository's install is judge whether
a cloud target has closed: H19 reports it UNJUDGED and leaves it to a
seat. Under the new rule, a seat therefore releases an objectstack card
blocked on a cloud card by hand. That seat is one that reads cloud, or
one that acts on a reaching seat's quotation. This is the ruled
per-install credential limit the script's header names, not a defect. It
is recorded under Acceptance notes and not filed.
## Acceptance notes
1. Cross-repo release from an objectstack card is judged by hand (reader
check above). Nothing mechanical in this repository's install answers
"has `objectstack-ai/cloud#N` closed". The release rests on a seat: the
triage seat's per-repo unlock scan, or a reaching seat's comment on the
waiting card. Carrier: none. This is a standing, accepted limit and not
a defect to file.
2. The instance named by the ruling, objectstack-ai/objectstack#24525,
answers `301 Moved Permanently` on a single-card REST read today
(2026-10-20). The ruling record and this card's body name
objectstack-ai/cloud#3089 as its address. The redirect was not followed,
because this lane does not read cloud.
3. Clauses carried elsewhere are listed above. If the maintainer wants
them verbatim in this file, that takes a ceiling raise by ruling (one or
two lines). The ruling of record says line-neutral, so this PR takes no
raise.
## Verification, on head `ad5a10688`
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived the change set from merge base
`8e14ce057`: 1 path, +2/-2. It derived 17 commands, the same 17 as the
dispatch order. All 17 were run on the head, with exit codes captured
before any pipe:
- `node scripts/check-closing-keyword-parity.mjs` → exit 0
- `node scripts/check-closing-keyword-parity.mjs --self-test` → exit 0
- `node scripts/check-comment-mask-corpus.mjs` → exit 0
- `node scripts/pm/check-harness-current.mjs --self-test` → exit 0
- `pnpm --filter @objectstack/lint run check:doc-formula-expressions` →
exit 0
- `pnpm check:agent-test-spelling` → exit 0
- `pnpm check:cross-package-test-inputs` → exit 0
- `pnpm check:doc-authoring` → exit 0
- `pnpm check:driver-memory-census` → exit 0
- `pnpm check:gitlink-declared` → exit 0
- `pnpm check:nul-bytes` → exit 0
- `pnpm check:pm-governed-merges` → exit 0
- `pnpm check:pm-skill-id-lint` → exit 0
- `pnpm check:pm-skill-ratchet` → exit 0
- `pnpm check:refd-timer-probe` → exit 0
- `pnpm check:skill-frame-sync` → exit 0
- `pnpm check:watch-hint-literal` → exit 0
- `pnpm --filter @objectstack/lint run check:doc-formula-expressions`
first exited 3 (PREREQUISITE NOT MET: `@objectstack/formula` and
`@objectstack/lint` were not built). That run measured nothing. Both
packages were then built through `scripts/pm/os-verify-lock.sh`
(`VERDICT command-exit 0`, turbo cache hit), and the rerun exited 0.
- `--ran` reconciliation over the exit-coded record: "Run reconciliation
— 17 derived, 17 run, 0 NOT-MEASURED, 0 UNRUN." It ended with "✓
dispatch-gates --ran: 17 derived famil(ies) accounted for — 17 run, 0
NOT-MEASURED (a DERIVED zero ...)".
- The ratchet's own line for this file: "✓ check-skill-line-ratchet:
.claude/skills/pm-dispatch/references/cross-repo-coordination.md is 51
lines (ceiling 51; headroom 0)."
- Two more gates were run: `pnpm check:pm-settings-deny-roster` exited 0
(the derivation flags its roster as living under `.claude`), and `pnpm
check:pm-governed-prose` exited 0.
- No ablation: this is a text-only diff under `.claude/**`, and the dev
contract excludes docs from ablation.
- CI is in progress at the time of the report. The seat reads the
check-runs.
## Landing
Tier S: every path is under `.claude/**`. The PR stays draft. The seat
flips it ready and queues it after an isolated `CONTRACT_REVIEW_TIER`
review PASS on this head, with every check green. The PR carries
`skip-changeset` because `.claude/**` publishes nothing from any
released package. Precedent: PR #24521 (+2/-2).
## 维护者速读(草稿)
- **改了什么:** 改的是 pm-dispatch 的跨仓协调规则(`cross-repo-coordination.md` 第 50–51
行),内容是您 10-19 裁的 D。一张卡如果有一半落在本车道读不到的仓(今天是
cloud),立卡或第一次接手时就按仓拆开。那一半有两条去路:由能读 cloud 的席位在 cloud 立卡,或在本仓挂
`domain:cloud`+`status:parked` 停放,等 cloud PM
迁走。本仓这张卡只留本仓的活,两边都不读对方的仓。拆不开的,先在 cloud 车道立前置卡,本仓卡挂
`pm:blocked`+`Blocked-by:` 等它。文件行数不变(51/51)。
- **为什么改:** 依据是您的两句原话:「这一类的卡片能否直接把 cloud 部分分拆成一个 cloud
车道的卡片」「如果没有办法分拆,就立一张 cloud 车道的前置卡」。实例是
#24525:三个席位在三小时里各碰一遍,没人关得掉。按本裁决它整张归了 cloud,今天读它答 301,已迁走,裁决记录写它现在是
objectstack-ai/cloud#3089。
- **风险与代价(含回滚):** 两行装不下裁决的全部从句。省下的几条(请求路径、关闭即回队、pin
的可安装判据、按前置卡记录续做、不设新标签)在现有文本里都有,正文逐条点了出处。本仓巡查脚本认得跨仓 `Blocked-by:`
的写法,但判断不了 cloud 那张卡关没关:它报 UNJUDGED,交给席位人工判断。这是既有裁定下的凭据边界,不是这次新出的问题。回滚就是
revert 这一个 commit。
- **席位意见:**
- **你要做的:** 不需要您动手。席位隔离复核
PASS、检查全绿后,由席位入队落地。如果您希望省下的从句原文写进本文件,需要您说一句抬上限(+1–2 行)。
---
_Generated by [Claude
Code](https://claude.ai/code/session_01HEdP5tPhqQfzwRmKDxwn85)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent b9d0c48 commit d20bf9b
1 file changed
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
50 | | - | |
51 | | - | |
| 50 | + | |
| 51 | + | |
0 commit comments