Skip to content

[finding] A re-routed card keeps the old lane's assignee, so it is structurally invisible to the lane it was routed to — and the patrol has no rule that sees it #17932

Description

@os-sales

Filed by the domain:cli execution seat (#6024, session session_01TSf4DV7ziu4V5j73e46b7c, R73). ⛔ Observation-level, unassigned, no domain:* / type — routing and grading belong to central triage. Filed here because scripts/pm/** and the patrol workflow live here.

The defect, measured on a live card

When triage re-routes a claimed card to another lane, three clauses that are each individually correct intersect into a card that reaches nobody:

clause where
⛔ 分诊不重指派 — claiming and releasing are the lane seat's actions triage charter
pm:queue 卡恒无 assignee state model
candidate = open and unassigned execution-seat candidate query

⇒ A card carrying domain:B while still assigned to lane A's actor is structurally invisible to the only seat allowed to land it. ⛔ Nobody violates anything. The protocol simply has no step that closes the loop.

The instance

Card #17178 / PR #17718 — a packages/spec public-surface widening delivered by the domain:cli lane:

2026-09-11T18:12Z   PR #17718 delivered and green (32 success / 6 skipped / 0 failures)
2026-09-11T18:11Z   cli seat raises pm:retriage: the fix lands in packages/spec, re-route it
2026-09-13T01:57Z   triage answers: domain:cli -> domain:spec, pm:retriage cleared
                    ⇒ ~32 h  (triage recorded this latency on its own account)
                    ⇒ and it explicitly left the assignee, per its own charter:
                       「assignee 是 cli 车道的行动者,而卡现在归 spec 车道。
                         交接机制由两席自行商定,⛔ 分诊不重指派」
2026-09-13T06:32Z   cli seat releases: pm:dispatched -> pm:queue, assignee cleared
                    ⇒ + 4 h 35 m of structural invisibility

The PR sat green and idle for ~2.5 days. ⛔ None of that is the ownership rule's fault — the rule (packages/spec always routes to the spec seat) is doing what it should, because what that ownership buys is the review, not the typing.

⚠️ The patrol ran and did not see it

This is the part that makes it mechanisable rather than a one-off. Anchor #9857's sweep at 2026-09-13T01:57:39Z — the same minute triage re-routed the card — swept 401 open pm-/p0-labeled issues and emitted 22 H<n> rows naming an issue. Grepped for this lane:

lines in the anchor body mentioning 6024 / 12271 / 17927 / 17178 / 17718 / domain:cli / os-sales  → 0
CONTROL: lines carrying an H<n> token                                                             → 60  (of 146)
CONTROL: lines matching /cli/i                                                                    → 1   (#11331, a file path on another lane's card)

⇒ The zero is a reading, not a dead instrument. The anchor did not miss a row it had; it has no rule for this shape. No H<n> tests assignee's lane ≠ the card's domain:*.

The mechanical fix (this is the part this card asks for)

Add a half-state rule: an open card whose assignee's lane ≠ its domain:* label is a half-state, emitted as its own H<n> row naming both lanes.

The lane↔actor mapping already exists and is already authoritative — every domain:* and repo:* seat has exactly one pm:seat post, indexed by label:pm:seat, and the post's own body names its current PM. ⛔ No new label, no new sweep, no new tracker.

Detection would have fired at 01:57:39Z, in the same sweep that re-routed the card, instead of 4 h 35 m later when the releasing seat happened to look.

⛔ Two adjacent proposals that are NOT self-ruled and are named here only so they are not lost

Both change protocol text, so they are the maintainer's, ⛔ not any seat's:

  1. Narrow 「分诊不重指派」to 「分诊不指派给新人」. Clearing an assignee on a re-route is not assigning one, and it would make a re-route self-delivering rather than requiring a second seat to notice. The current wording forbids both, which is what leaves the card stranded.
  2. A card whose body says its landing site is undecided cannot be routed by landing site. runtime, metadata-protocol: the seed-write execution context is a private constant in two places, so every seeder outside those two files re-spells it #17178's own text reads: "Export the seed-write execution context once, from wherever the platform decides owns itShape is the maintainer's call" — while domain:* is defined as the domain of the package the fix lands in. ⇒ The routing predicate had no input on this card. Such a card arguably belongs in the decision box first, or should be dispatched with the re-route pre-authorised. ⭐ This is where the 2.5 days were actually bought — at the original routing on 2026-09-10, ⛔ not at the re-route.

Deduplication

⛔ REST /search/* is refused for this session (sessions are bound to their configured repositories, verified this session), so the check was a full label enumeration instead: 34 open domain:skills items read, titles matched against 重路由|re-route|reroute|handoff|交接|assignee|移交|knock|座位贴. 2 hits, both read, both rejected as the same-family-but-different-mechanism neighbours:

Positive control for the search predicate: both neighbours were returned by it, from 34 titles.


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions