Skip to content

pm-dispatch: record the triage seat's alternating-repo pickup and its 4-hour starvation guard as a lane reference (references/lanes/triage.md) — execution of the #15476 ruling A #15671

Description

@os-steve

Filed by the domain:skills seat (session session_019RfFHiRCSs3JXLK4cwcfox, os-steve) as the documentation half of the maintainer's ruling on #15476 (batch #41, recorded by the director seat in comment 5548638091, verbatim reply 「同意」). Self-triaged: priority:p2, governed surface, pm:queue until a slot frees.

The ruling (as recorded)

The triage seat stays single. Alternating-repo pickup is standing seat discipline: one round objectstack, one round objectui, one round objectstack …; within a repo, oldest-first. Starvation guard: if either repo's oldest un-routed card is older than 4 hours at the start of a round, that repo takes the round regardless of turn. No second seat, no fire-frequency change. The ruling's execution line: "one paragraph in the triage lane reference under .claude/skills/pm-dispatch/references/lanes/".

Placement (the seat's reading — the ruling's execution note assumed a file that does not exist)

references/lanes/ carries eight lane job descriptions (cli · devx · director · engine · hotcrm · services · skills · spec) and none for the triage seat; the triage seat's standing duties live in SKILL.md's「分诊座位职责」section, which is at its ceiling (811 of 811) and already has two cards serial on it (#15666, #15404). ⇒ Create references/lanes/triage.md as the triage seat's lane reference, holding today only what the ruling asks for: the pointer line every lane file opens with (the SKILL.md section it details), then the pickup rule as rules — one rule per line, ≤120 bytes, plain Chinese with identifiers in backticks, ⛔ only on prohibitions, no dates, no quotations, no card numbers:

  1. 分诊每 fire 只取一个仓,两仓轮替:objectstack、objectui、objectstack……;仓内按最旧优先。
  2. 饥饿守卫:轮次开始时任一仓最旧未路由卡超过 4 小时,该仓本轮优先,不论轮到谁。
  3. ⛔ 不回退到跨仓全局最旧优先;⛔ 不因积压增设第二分诊席或改 fire 频率。

Plus its CEILINGS row in scripts/pm/check-skill-line-ratchet.mjs, pinned at the landed count (headroom 0, the map's convention for a new file), and a MAX_TABLE_ROW_BYTES row at 0 (no table). ⛔ No edit to SKILL.md or any other lane file; the triage seat post (#6015) may point at the file afterwards — that is the triage seat's own edit, not this card's.

Serial and gates

The ratchet map is shared with PR #15641 (member 3 of #15379, re-merging main after being removed from the queue) on disjoint rows — this card dispatches after PR #15641 lands to keep the map's rows in one order. Gates: check:pm-skill-ratchet, check:skill-frame-sync, check:pm-skill-id-lint, check:pm-governed-prose, check:nul-bytes, whatever dispatch-gates --commands derives. Governed (.claude/**) ⇒ draft PR, in-seat review, os-zhuang + hotlong, human merge, skip-changeset. XS.

Related: #15476 (closed, the ruling) · #15379 (the rules-only programme this file is born under).

Activity

  1. self-assigned this
    on Sep 5, 2026
  2. claude commented on Sep 5, 2026

    @claude
    Contributor

    Claim: PM loop round 7 — unblocked when PR #15641 (member 3 of the corpus programme) MERGED 15:38Z; executes the recorded ruling on the triage seat's alternating-repo pickup and its 4-hour starvation guard as a new lane reference.
    Session: session_019RfFHiRCSs3JXLK4cwcfox
    Branch: claude/issue-15671-triage-lane-reference
    Worktree: objectstack-issue-15671
    Domain: domain:skills
    File surface: new .claude/skills/pm-dispatch/references/lanes/triage.md (the pointer line every lane file opens with, then the three pickup rules as rules — one per line, ≤120 bytes, no dates, no quotations, no card numbers) + its CEILINGS row (pinned at the landed count) and MAX_TABLE_ROW_BYTES row (0) in scripts/pm/check-skill-line-ratchet.mjs. ⛔ No edit to SKILL.md or any other lane file.
    Container & model: XS, mode:subagent, model: opus (dispatch-gates.mjs --tier: references/** and scripts/pm/** hit no mandated glob; clause ② not engaged — no contract accept/reject change).
    Clause-②: no
    Serial constraints cleared: no open PR adds a file under references/lanes/ or a row to the ratchet map (#15929, in flight, edits lanes/director.md in place). GOVERNED (.claude/** in the diff) ⇒ draft PR, in-seat review, os-zhuang + hotlong, human merge, skip-changeset; at ACCEPT the seat adds needs-user-decision + the 维护者速读. The PR carries Fixes #15671.


    Generated by Claude Code

  3. claude commented on Sep 5, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 15671,
      "status": "done",
      "branch": "claude/issue-15671-triage-lane-reference",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/15958",
      "premise_still_valid": true,
      "summary": "Two files, as ruled. NEW `.claude/skills/pm-dispatch/references/lanes/triage.md` — 7 lines: the H1 the sibling lane files open with, the pointer line naming the SKILL.md section it details (分诊座位职责), then the three ruled rules one per line (alternating-repo pickup with oldest-first inside a repo; the 4-hour starvation guard; the two prohibitions). Nothing else in the file. `scripts/pm/check-skill-line-ratchet.mjs` gains exactly two rows: `CEILINGS` at 7 (the landed count read from the gate's own run, headroom 0, the map's new-file convention) and `MAX_TABLE_ROW_BYTES` at 0 (no table row). The diff on that file is 8 added lines, 0 removed — no other row of either map moves, and SKILL.md and the eight existing lane files are untouched. Draft PR 15958 with `Fixes` on the card as its first body line and the 维护者速读(草稿) section (五段, 席位意见 left blank); `skip-changeset` applied through the additive labels endpoint with a comparison read-back. Not flipped ready, not enqueued, no auto-merge armed, no reviewers requested — those stay with the seat.",
      "tests": "Byte widths with `LC_ALL=C awk`: widest line is line 3 (the pointer line) at 119 B against the 120 B budget; rule lines 113 / 110 / 101 B. The verbatim director.md pointer spelling with 分诊座位职责 substituted measures 122 B, so the file takes the six domain lane files' shorter tail (⛔ 不迁入本文。). Gate derivation: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no paths passed; it derived the 2-path change set itself, 1 working-tree + 1 untracked) yielded 36 commands. All 36 were run, each exit code captured before any pipe (redirect-then-capture); reconcile: '✓ dispatch-gates --ran: 36 derived famil(ies) accounted for — 36 run, 0 NOT-MEASURED.' One of the 36 first returned exit 3 — `pnpm --filter @objectstack/lint run check:doc-formula-expressions`, PREREQUISITE NOT MET, nothing measured, not a finding; built @objectstack/formula + @objectstack/lint through the shared verify lock and re-ran it green. Named gates, all green on the final commit 32945f93f1 (re-run after committing, not before): '✓ check-skill-line-ratchet self-test: 155 cases pass.' (155 on main too — no case added or removed); '✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/lanes/triage.md is 7 lines (ceiling 7; headroom 0).'; '✓ check-skill-line-ratchet: ... widest table row is 0 bytes (pin 0; headroom 0).'; every other ceiling line in that run unchanged. '✓ check-skill-id-lint: 25 file(s) clean (pattern /#[0-9]{3,}/g).'; check-skill-frame-sync: 'binding sentence present in all 2; 4 count mention(s) agree; 74 markdown files scanned for undeclared copies.' (the decision frame is absent from the new file, and its anti-dormancy fingerprints do not fire); '✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces ... and claim no others.'; 'check-nul-bytes: OK (scanned 7694 text file(s) ... no raw ASCII control bytes)' plus a direct control-byte grep over both edited files (no match). Whole-repo `pnpm lint` (`eslint . --no-inline-config`) green through `bash scripts/pm/os-verify-lock.sh` slot issue-15671: 'VERDICT command-exit 0 · held the lock 82s · waited 0s' (shared-box seconds, as the lock's own line states). `node scripts/pm/check-governed-merges.mjs --test` on the two paths exits 3 — GOVERNED, `.claude/**` ×1. CI on head 32945f93f16ed7dc2785b3ae8e11c0f073a397f5, polled in the foreground until every run completed: 37 check runs, 26 success, 11 skipped, 0 failures (Lint & Repo Gates success; Check Changeset success/skipped under `skip-changeset`; all five Type Check runs success). No ablation was run: this card adds prose plus two ratchet map rows, and the gate's own live line on the new file is the direct measurement.",
      "mcp_calls": "3 — issue_read on the card, one targeted search_issues (dedup before filing the finding), one issue_write to file it. Everything else went through repo-scoped REST, which this session can reach (authenticated read probe 200): PR creation, the full body read-back, the additive label write and its comparison read-back, and the check-run polling. The REST /search/ endpoint is NOT reachable here — it answers 'This GitHub API path is not available: sessions are bound to their configured repositories', which is why the dedup used MCP.",
      "open_questions": [
        {
          "question": "The new file's first two lines are a judgment inside the ruling — the ruling fixed which SKILL.md section the pointer names, not the H1 shape or the pointer's tail. Triage is a seat rather than a domain lane, so I mirrored director.md's seat form: H1 `# 席位章程:分诊席(Triage)`, and the pointer line with the six domain lane files' shorter tail (⛔ 不迁入本文。) because director's own tail (本文件) puts the line at 122 bytes, over the 120-byte cap.",
          "options": [
            "A — keep it: seat form for a seat, tail borrowed from the domain lane files so the line fits at 119 B",
            "B — H1 as `# 车道岗位说明:分诊席` (the form hotcrm.md uses for a non-domain lane), same pointer line",
            "C — keep director's tail (本文件) and buy the 3 bytes elsewhere in the pointer line"
          ],
          "recommendation": "A. It is the only spelling where both halves are verbatim from an existing sibling and the line stays inside the byte cap; B invents a third H1 shape for the same file class, and C reworks a sentence eight files already share to save nothing a reader can see."
        }
      ],
      "out_of_scope_findings": [
        "filed as #15965: the ratchet self-test's lane roster is a hand-written list of eight names (`.every` over them), so the ninth lane file's CEILINGS row is pinned by no case — extending it also moves a label pinned in the self-test expectation table, which is outside this card's two-row scope. Proposed shape in the issue: derive the roster from the lanes/ directory.",
        "not filed — already open as #15957 (found independently by another seat at 16:24Z): the ratchet prints an unclaimed 2-byte pin tighten for spec-property-retirement/SKILL.md on every run. Pre-existing on main and untouched by this PR."
      ]
    }

    Generated by Claude Code

  4. github-actions commented on Sep 6, 2026

    @github-actions
    Contributor

    os-closed-card-sweep — machine-findable marker for this generated comment.

    Removed the pm-loop state label(s) this closed card no longer claims: pm:dispatched.

    A state label claims work is in flight. This card is closed on a merged delivery, so the claim
    is stale; every other label is left exactly as it was found. Nothing here is a judgement about
    the card, and no verdict-bearing label is ever touched by this sweep.

    posted by half-state-patrol run 34019805258 · trigger schedule

    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions