Repository navigation
[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
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:
- 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.
- 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 it … Shape 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:
- [finding] A seat-post body refresh silently expires every unread knock — the read window is 「comments newer than the last body edit」, and a director-ruled cross-lane review took 9 hours to arrive because of it #17905 — a seat-post body refresh silently expires every unread knock (the read window is "body + comments newer than the body's last edit"). Same family — a handoff with no durable carrier — but its mechanism is knock delivery, not assignee residue. ⇒ Fixing it would not have surfaced 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.
hotcrmhas no half-state patrol anchor, so thepm:dispatched+ assignee residue after aFixesauto-close has now been repaired by hand seven rounds running #14881 —hotcrm'spm:dispatched+ assignee residue after aFixesauto-close. Closest neighbour, and still distinct on three axes: a different trigger (auto-close, not re-route), a different repo, and a different root cause — hotcrm has no patrol anchor at all, whereas objectstack's anchor exists, swept 401 cards, and has no rule for this shape. ⇒ Building hotcrm's anchor would not add this rule.
Positive control for the search predicate: both neighbours were returned by it, from 34 titles.
Generated by Claude Code
Activity
claude commentedon Sep 13, 2026
Routed and graded by the skills seat under the maintainer's 2026-09-13 ruling —
finding→domain:skills·pm:on-hold·priority:p3·Task(sessionsession_01DAcomhvR9kKizeYgg89Vo8, GitHubos-project-manager, 2026-09-13T07:32Z).Authority for a lane seat routing a bare card — maintainer, verbatim, untranslated (live chat, recorded on #17942): 「②同意,执行席自路由,分诊也无需事后审计」. Landing: the mechanical half is an
Hrow inscripts/pm/check-half-states.mjs(PM loop tooling, this lane); the two protocol proposals land inSKILL.md/references/lanes/triage.md(governed, this lane).Why on hold, not queued. The row this card asks for — 「an open card whose assignee's lane ≠ its
domain:*label is a half-state」 — is true only while a re-routed card must change hands. #17942 (question 1) asks the maintainer whether a claimed card stays with the claiming seat to MERGED even when its surface belongs to another lane; if that is ruled A, adomain:speccard assigned to the cli seat is a LEGAL state and this row would flag every follow-through as a defect. The row's predicate therefore cannot be written until #17942 lands. Its proposal 1 (narrow 「分诊不重指派」 so a re-route clears the assignee) and proposal 2 (a card whose body says the landing site is undecided cannot be routed by landing site) are already folded into #17942's questions.Restart-when: closed #17942
On restart: re-derive the row's predicate against the landed rule (A: flag only re-routes of UNDISPATCHED cards that kept an assignee; B: the row as filed), and keep the measured instance (#17178, 4 h 35 m invisible) as the row's example. Grade: Task (a patrol gains a row; no contract violated), p3 — the instance cost is real but the shape is now bounded by #17942 either way.
Generated by Claude Code
claude commentedon Sep 13, 2026
Hold released — skills seat (session
session_01DAcomhvR9kKizeYgg89Vo8), 2026-09-13T15:03Z.Restart-when: closed #17942is met: #17942 closed completed by PR #18038 (c185d087) at 2026-09-13T14:36Z; double-check: no merged PR references this card after the hold comment 5651956018. Landed rule for the row's predicate: A — an in-flight card stays with the claiming seat to MERGED even when its post-dispatch face crosses lanes (PR #18038, contract-review.md 复核归属: the independence piece covers a claimed card's cross-lane face, 借复核不移卡), while routing of UNDISPATCHED cards is triage's alone (#17942 ruling ③, 5652544529 「同意」). So the row re-derives as: an open card WITHOUTpm:dispatchedwhose assignee's lane ≠ itsdomain:*— a re-route that kept an assignee — with #17178 (4 h 35 m invisible) as the example.pm:on-hold→pm:queuein this pass, read back; p3, Task,domain:skillsunchanged. Dispatch shape: oneHrow inscripts/pm/check-half-states.mjs, after PR #18033 lands and frees the file.Generated by Claude Code
claude commentedon Sep 13, 2026
Premise falsified at dispatch time — close recommended (not planned) — skills seat (session
session_01DAcomhvR9kKizeYgg89Vo8), 2026-09-13T16:04Z. Work-item check againstorigin/maina2497861before dispatching the H row this card asks for:pm:queuewith a NON-EMPTY assignee」 (scripts/pm/check-half-states.mjs:542) fires on every re-routed card that kept an assignee, whatever lane the assignee belongs to — the 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 instance (assignee cli, labeldomain:spec,pm:queue) is inside it.domain:*」 is now a LEGAL state, not a half-state: the claimed card follows through to MERGED with the claiming seat and imports the cross-lane review ([Decision] A claimed card follows through to MERGED; cross-lane surfaces import the review instead of exporting the card; in-scope derived work and unclaimed blockers stay with the claiming seat (maintainer question after #17718, 2026-09-13) #17942 Q1 = A; PR skills(pm-dispatch): charter revision — rulings A/③/C, governed-surface tiering, ui/triage lane lines (#17942 chain) #180189489e2c0, PR skills(pm-dispatch): charter references — clause-② applicability, the shape-1 red exception, the two-layer landing, the three-class blocker rule, the director batch (#17942 chain, second half) #18038c185d087: 认领即跟到 MERGED, 借复核不移卡), and a re-route viapm:retriageapplies to undispatched cards only (PR docs(pm,agents): three rules-layer lines catch up with the charter rulings #18051 in flight carries the two lagging table rows). The scenario this card measured — triage re-routing a CLAIMED card mid-flight — can no longer occur under ruling ③.So no row is left to write. The card stays
pm:queueuntil the maintainer or the triage seat closes itnot_plannedon this derivation; this seat will not dispatch it.Generated by Claude Code
claude commentedon Sep 13, 2026
Closed not planned on the maintainer's word — skills seat (session
session_01DAcomhvR9kKizeYgg89Vo8), 2026-09-13T16:15Z. Instruction: the maintainer (pm@objectstack.ai), in this seat's chat session at 2026-09-13T16:14Z, verbatim: 「17932 你决定」 then 「关」. Basis: the derivation above (5654398568) — H24 already flags apm:queuecard carrying an assignee, ruling A makes the dispatched-card reading legal, the two proposals were ruled on #17942.pm:queuestripped in the same write;domain:skillsandpriority:p3stay (ownership, not state). Reopen is free if a live instance appears that H24 does not catch.Generated by Claude Code