Skip to content

[finding] The pre-dispatch stale-premise check covers a ruling's named ACTIONS but not the cards it names — two rulings in one batch cited issues that were already closed when they were written #9038

Description

@qq9340100

Filed unassigned for the domain:skills seat by the domain:cli / domain:identity / domain:services PM seat (session session_01NaS1PAHJcPfAA2acnV53Tn). ⛔ Not a claim.

Provenance — maintainer-directed, 2026-08-16, live PM chat, verbatim:

把「派发前核对被点名卡的当前状态」立成 finding 给 skills 席,进派发前检查清单

The gap, stated against the text that already exists

pm-dispatch already carries a pre-dispatch stale-premise rule, and it is a good one:

派发前做 stale-premise check —— 裁决同罪(issue 与裁决描述的都是当时的仓:裁决是针对某个仓库状态的判断,写得权威、日期又近,恰恰更容易被当成现成事实 —— git log --oneline -20 -- ‹paths› 之外,裁决实施卡再核被点名的动作在 origin/main 上还没被做掉;花几分钟,不查则赔一次 agent 运行)

What it directs you to re-verify is the named actions against origin/main — has the fix already landed. That check works and has paid off repeatedly.

What it does not cover is the other thing rulings routinely name: other issues — blockers, claim surfaces to coordinate around, parked fixtures that "arm once this lands", cards said to be in flight. Those are assertions about GitHub state, not about origin/main, so re-reading the tree cannot falsify them and the existing check sails past.

Two measured instances, same batch, same day

Both from the 2026-08-15 batch ruling (maintainer, verbatim 「接受你的所有建议。」, session session_01LXPH2ApQmyHYeZGHfYv7Xs, 18 cards ruled in one sitting):

ruled cardthe card it namesthat card's actual stateruling written
#8684#8480"coordinate with #8480's packages/client claim surface before dispatching the SDK half"closed-completed 2026-08-15 02:46 (PR #8795 merged)15:33
#8839#8408"#8408's parked fixture arms once this lands — the implementing dev coordinates with that card"closed-completed 2026-08-15 07:4815:31

Neither ruling reasoned wrongly. Both inherited a dependency/claim list from a dev report that was accurate when written#8684's was taken at 02:01 and went stale forty-five minutes later — and carried it forward unchanged.

Why this shape in particular, and why it will recur

The structural cause is worth naming, because it means this is not two slips:

  • A batch ruling is written in one sitting about work spanning many hours. The larger the batch, the more of its inherited state is stale by the time the last card is written — and a batch gets written precisely when a lot is in motion, i.e. when staleness is fastest.
  • The failure is quiet and asymmetric. A stale action claim self-corrects: the dev goes to make the change and finds it already there. A stale card reference does not — it produces a dispatch order telling a dev to coordinate with something that cannot answer, or telling a PM to schedule around a constraint that no longer exists. Nothing red appears.
  • Authority makes it worse, exactly as the existing rule already observes. A ruling is authoritative and recent, which is what makes it read as present tense. This finding is that same insight applied one category over.

Measured cost of the un-caught version, on this repo, today: #8684 was held for hours on a serial constraint that never existed, and the PM comment that recorded the hold presented the constraint as measured fact. That was a different mis-attribution, but the same class — a stated verification treated as a performed one.

Options (offered, not chosen — the skills seat grades and the gate scope is not mine)

Recommendation: A now; B is worth its own grading later. A is the cheapest thing that closes the measured gap, and it fits where the failure actually happens — the moment a PM turns a ruling into a dispatch order. B is genuinely better and genuinely more expensive; it should be judged on its own merits rather than ridden in on a checklist edit, which is the same boundary this lane held on #8711's option C.

⚠️ Scope note — roughly 16 more cards from that batch are unexamined

I hit these two because I dispatched those two cards. The same batch ruled 18, and the same inheritance mechanism applies to all of them. ⛔ I have not swept the other ~16, and this finding does not claim they are affected — only that the mechanism that produced these two was not specific to them. Whoever grades this may want to decide separately whether that sweep is worth one pass.


⚠️ Body edit 2026-08-16 — this card lost text to the sanitizer on its first write, and that is worth recording here

The protocol quotation above originally carried git log --oneline -20 -- followed by the word paths in angle brackets, exactly as the skill spells it. The write-then-read check found it had been silently deleted — the quotation came back ending at the double dash. Restored above using ‹single guillemets› as the placeholder so it survives.

Two details that make this more than a typo, and that ⛔ should not be conflated with the read-layer escaping recorded in #9031:

  1. Backticks do not protect it. The stripped text was inside a code span at the time. Anything shaped as an angle bracket immediately followed by a letter is removed on write regardless of markdown context.
  2. This is a genuine at-rest loss, unlike the entity escaping.[finding] The HTML entities in issue bodies are a READ-layer artifact of the GitHub MCP tool, not at-rest storage — seats have been refusing body edits (and Blocked-by: lines) on a false premise #9031 measures that " / ' / > come back as " / ' / > purely as a read-layer artifact — storage is plain and bodies round-trip. This is the opposite: the content is really gone from storage. The two behaviours are separate and a single "the API mangles bodies" mental model gets one of them wrong in each direction.

Recording it on this card rather than only on #9031 because it is the same underlying lesson this finding is about — a confidently-written claim that nobody re-read — and because this card would otherwise have quoted the skill's own rule while silently dropping part of it, which is a poor advertisement for a checklist item about verification.

Related: #8684 (instance 1, and the fabricated serial constraint) · #8839 (instance 2; its dispatch order was rewritten to have the dev find the fixture in the tree rather than coordinate with a closed card) · #8480 / #8408 (the two closed cards) · #9031 (the read-layer escaping fact — distinct from the stripping recorded above, and now cross-referenced there).

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions