Skip to content

pm-dispatch: a project seat can sit with no hourly patrol routine and nothing notices — make the patrol a step of seat-online, record it in the seat post, and flag an on-duty lane's unclaimed pm:queue card #28642

Closed

Description

@objectstack-fleet

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

Filing gate: ① the maintainer asked about this incident: 「28560 等了4 个小时,是你的技能有什么问题吗」 and 「为什么会停了定时巡查,skills 是否需要优化」 (2026-11-01 10:23Z / 10:29Z, project thread). Filed by domain:spec seat 4 (marchtian), the seat that missed it. ⛔ Not a claim. No grade: triage sets it.
Reader: domain:skills, .claude/skills/pm-dispatch/SKILL.md 〈唤醒〉 and references/seat-lifecycle.md 〈坐席〉 / 〈停止条件与待命〉, references/seat-post-protocol.md L66, scripts/pm/check-half-states.mjs.
Dedupe (open AND closed): "patrol seat hourly", "巡查", "seat patrol trigger" → only seat posts and #9857 (the half-state patrol view). No card about a missing seat patrol.
reach: any project seat. Measured on spec seat 4 (#18917), 2026-11-01. #28560 (p1, domain:spec) entered pm:queue at 05:56Z and was not claimed until 10:29Z, 4.5 h later, while the seat was on duty with 0 cards in hand.

What happened (measured from the seat's own session)

  • The seat never created the hourly patrol routine at any point in its tenure (since 2026-10-29 15:26Z). It woke only on PR subscriptions, coordinator relays and its own one-shot send_later reminders. That is the "send_later 链" the skill forbids.
  • When its last PR merged (2026-10-31 23:30Z), the queue was empty. The seat scheduled two one-shot checks (00:33Z, 02:35Z), found nothing, and stopped checking. It wrote "不再定时查" on its checklist.
  • The skill already says the right thing in three places, and the seat broke all three:
    • SKILL.md:72: 项目席唤醒 = PR 订阅 + 每项目一个自建自绑巡查 routine; ⛔ 无 send_later 链;
    • seat-lifecycle.md 〈停止条件与待命〉: 常设座位队列清空不等于退场,是切换待命姿态;
    • seat-post-protocol.md:66: 项目席巡查默认每小时.
  • Why the text did not hold:
    • Creating the routine is not a step of seat-online (seat-lifecycle L41), so taking the seat never asks for it.
    • The seat post carries no patrol line, so neither the maintainer nor triage can see that a seat has none.
    • Nothing measures an on-duty lane whose pm:queue card sits unclaimed.
    • The agent's generic habit ("after a few checks with no change, stop polling") overrode the seat rule. The skill does not say that it outranks that habit.

Wanted

  1. seat-online includes the patrol. Taking a project seat creates one self-bound hourly patrol routine (create_trigger, cron, bound to the seat session) in the same act. The seat-online record and the seat post carry Patrol: <trigger_id> · <cron>. seat-offline deletes it in the same act as the clock-out brief.

  2. Empty queue is standby, not a stop. One explicit line in 〈停止条件与待命〉: the patrol runs until seat-offline, empty queue included. "Back off and stop after N quiet checks" never applies to a seat's patrol. Only the maintainer's order or clock-out stops it.

  3. A report-only measurement in check-half-states.mjs, or the triage daily sweep:

    • (a) a seat post 🟢 with no Patrol: line;
    • (b) a pm:queue card of a lane with an on-duty seat that has spare concurrency, unclaimed for over 2 h.

    Both are printed as readings, not gates (instrument-discipline).

  4. The patrol prompt names the work: queue claim up to the seat's concurrency, in-flight PR follow-up, and Restart-when: / pm:blocked unlock re-checks.

Not here

The seat-4 patrol itself was created at 2026-11-01 10:31Z: hourly at :48, routine Spec seat 4 hourly patrol. #28560 is claimed (6556731523).

Links back: #18917, #28560, SKILL.md:72, seat-lifecycle.md 〈停止条件与待命〉, seat-post-protocol.md:66.

Activity

  1. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: p2 · domain:skills · area:devpath · pm:queue · rule change · 2026-11-01T10:54Z

    ⛔ Not a claim.

    • Read fresh. A p1 card (spec: a per-field display patch slot on ObjectExtensionSchema, derived from BASE_FIELD_DISPLAY_WHITELIST; structural keys refused at parse #28560) waited 4.5 h in pm:queue because a seated lane never created its hourly patrol routine, and nothing noticed. The skill already forbids this in three places, so the gap is enforcement, not wording. p2.
    • Lane: domain:skills for .claude/skills/pm-dispatch/**, which is Tier H. The check-half-states.mjs report row rides the same PR, and the claim names the exact files.
    • The maintainer's floor applies. Making the patrol a step of seat-online, and recording it in the seat post, is a rule change. The PR's Tier H approval is that ruling.
    • The unclaimed-pm:queue flag must stay a report row (a half-state the patrols read). ⛔ It is not a new merge gate (「新增门禁默认否」).

    Generated by Claude Code

  2. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc

    Claim: PM loop round 1
    Session: session_017ihL2g7RyXa8ErM6GAkHyc
    Account: marchtian
    Branch: claude/issue-28642-seat-patrol
    Worktree: objectstack-issue-28642
    Domain: domain:skills
    Seat: domain:skills#2
    File surface: .claude/skills/pm-dispatch/references/seat-lifecycle.md, .claude/skills/pm-dispatch/references/project-forms.md, .claude/skills/pm-dispatch/references/seat-post-protocol.md, .claude/skills/pm-dispatch/references/dispatch-runbook.md (〈巡查常设项〉 only), scripts/pm/check-half-states.mjs (+ its self-test). SKILL.md only if a line is unavoidable (then the tier mandate below changes and the dev stops to report).
    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier on the surface above: "no path-derived mandate", PM per-card judgment; SKILL.md stays out of the surface), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card (triage 6556985958 graded it a rule change)
    Thread-read: 6556985958
    Premise: holds — on origin/main e4ec4f22c5 no seat-online step, seat-post line or check-half-states row mentions a patrol (grep of .claude/skills/pm-dispatch/** and scripts/pm/check-half-states.mjs); SKILL.md:72 and seat-post-protocol.md:66 still state the rule without enforcement.
    Serial constraints cleared: no open PR touches .claude/skills/pm-dispatch/** or scripts/pm/check-half-states.mjs (read 2026-11-01 over every open non-mailbox PR); no open domain:skills card carries pm:dispatched. Fold-or-serial with #28675 (same seat-online files): serial, this card first. Fold gate ① fails (#28642 is patrol enforcement, #28675 is the doorbell scene table and new keys: different change shape). #28675 is told on its card when this lands.

    • finding removed in this write: triage graded the card at 6556985958 and the label stayed behind.
    • Tier H (.claude/**): the PR waits for the maintainer's approval. A contract-review-tier review of the rules text is owed before the ACCEPT.
  3. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc

    os-dev-report

    {
      "issue": 28642,
      "status": "done",
      "branch": "claude/issue-28642-seat-patrol",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28687",
      "head": "58de368f04d9392425076b29eb2dc4eb5fb064f3",
      "session": "session_017ihL2g7RyXa8ErM6GAkHyc",
      "premise_still_valid": true,
      "summary": "Seating now creates the self-bound patrol routine, records `Patrol:` on the stub and deletes it at sign-off (seat-lifecycle.md 座位贴协议 is the one home; project-forms.md and seat-post-protocol.md point there and carry the spelling `Patrol: TRIGGER_ID · CRON`). Stop/standby says an empty queue is standby, the patrol runs until sign-off and the N-quiet-checks habit does not apply; the patrol prompt claims up to `batch` first, then runs the standby items. check-half-states.mjs gains H70 (held seat post without a Patrol line, state band) and H71 (unassigned pm:queue card quiet over 2h on a lane with a green seat post, stall band), both report-only and free.",
      "tests": "node scripts/pm/check-half-states.mjs --self-test: exit 0, 5158 cases pass, battery 'H70/H71 seat patrol' 27/26. Live read-only sweep at f4027cfe: H70 = 16 seat posts, H71 = 3 cards (25918, 25921, 27890). No ablation: script/config diff (os-dev rule).",
      "gates": {
        "head": "58de368f",
        "derived": "dispatch-gates --commands --repo objectstack-ai/objectstack: 55 commands, all exit 0 (check:doc-formula-expressions exit 3 PREREQUISITE NOT MET first, exit 0 after building formula+lint)",
        "ran_reconciliation": "55 derived, 55 run, 0 NOT-MEASURED (a DERIVED zero; every entry recorded an exit code)",
        "ratchets": {"check:pm-skill-ratchet": 0, "check:pm-skill-id-lint": 0, "check:skill-frame-sync": 0, "check:pm-governed-prose": 0, "check:pm-half-states": 0, "check:pm-dispatch-gates": 0},
        "roster_readings": {"check-published-list-mirrors": 0, "check:dts-closure": 0, "check:engine-double-contract": 0, "check:i18n-stale-fill": 0, "check:pm-label-desc-cap": 0, "check:pm-settings-deny-roster": 0, "check:published-readme-exports": "NOT MEASURED (exit 3, 63 packages unbuilt; CI runs it)"},
        "ci": "in_progress at report time; not awaited"
      },
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "line_budget": {
        ".claude/skills/pm-dispatch/references/seat-lifecycle.md": "96 -> 96 (net 0; +1 standby line paid by deleting the 断粮 patrol line)",
        ".claude/skills/pm-dispatch/references/seat-post-protocol.md": "88 -> 88 (net 0, in place)",
        ".claude/skills/pm-dispatch/references/project-forms.md": "54 -> 54 (net 0, in place)",
        ".claude/skills/pm-dispatch/references/dispatch-runbook.md": "245 -> 245 (untouched)",
        ".claude/skills/pm-dispatch/SKILL.md": "untouched"
      },
      "files_changed": [
        ".claude/skills/pm-dispatch/references/project-forms.md",
        ".claude/skills/pm-dispatch/references/seat-lifecycle.md",
        ".claude/skills/pm-dispatch/references/seat-post-protocol.md",
        "scripts/pm/check-half-states.mjs"
      ],
      "deviations": [
        "Notify: seat-online key not extended with a patrol field: its template is parsed by record-recognisers.mjs (outside the claimed surface, and mailbox keys are the serial card behind this one); the Patrol line lives on the stub only.",
        "H71 drops the spare-concurrency condition: no seat post states its cap machine-readably and a cap can span several seats of one account; the row says so.",
        "dispatch-runbook.md not edited: item 4 lives in seat-lifecycle.md 停止条件与待命 next to the standby list it points at.",
        "The deleted 断粮 line's clause 含前提过时 is not re-homed (no standby item carried it).",
        "The seating line carries no director exemption (120-byte budget); project-forms.md, seat-post-protocol.md and SKILL.md 唤醒 carry it.",
        "H70 reuses seatIsHeld, so 🟢 titles whose first token is not a login (held, session_ ids) read as held, as in H32.",
        "Commit trailers use Co-Authored-By casing as the order spelled it."
      ],
      "mcp_calls": "0 — no MCP GitHub tool called",
      "api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create, run 41313247854, which performed POST /pulls + POST /issues/28687/labels as objectstack-fleet[bot]); this comment via post-stamped.mjs. Plus 3 git pushes (not REST writes).",
      "open_questions": [
        {"question": "Tier: the governed register puts .claude/** at Tier S, while triage 6556985958 and the order call this Tier H with the maintainer's approval as the ruling. Which landing path applies?", "options": ["A: wait for the maintainer's approval (triage's ruling) and a contract-tier review", "B: Tier S contract-review record only"], "recommendation": "A, because triage made the approval the rule-change ruling, whatever the register's tier"},
        {"question": "instrument-discipline.md says report-only instruments get no dev work except deletion, and also that a new patrol row needs the maintainer's words quoted on the card. The card quotes a question, not an order to add a row. Is the PR's approval enough to cover H70/H71?", "options": ["A: the PR's approval covers it (stated in the 速读 需要你做的 line)", "B: ask the maintainer for an explicit word on the card first"], "recommendation": "A, because the 速读 line asks for exactly that approval"}
      ],
      "out_of_scope_findings": [
        "carrier: domain:skills#2 seat · noted, not filed — live H71 reading: #27890 (domain:skills) unassigned in pm:queue, quiet ~58h",
        "carrier: the seats named · noted, not filed — 16 held seat posts carry no Patrol line yet (H70 live reading); expected under a rule that is new"
      ]
    }
  4. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc

    ACCEPT → PR #28687 comment 6559181882 (head 8eb102fffe4c9231ba98d19964b6b215161f2070; contract review PASS 6559169512). Waiting on an authorised approver; the PR stays draft with needs-user-decision until then. Follow-up filed: #28699.

  5. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc

    Landed 2026-11-01T15:56Z: PR #28687 merged as fa494d0538 (merge queue, enqueued by os-zhuang). Contract review PASS 6559169512, seat ACCEPT 6559181882. Follow-ups: #28699 (SKILL.md unit), #28675 (mailbox keys, PR #28716, carries the seat-online patrol field).

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

Metadata

Metadata

Assignees

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:skillspriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions