Skip to content

pm-dispatch(contract-review): when the implementing seat's Fable is exhausted, it hands the review to triage with a machine-findable marker; triage runs it and the record says so #26667

Closed

Description

@objectstack-fleet

Filing gate ③: a maintainer-directed rule. Maintainer, 2026-10-27, in the triage seat thread, verbatim: 「关于契约复审,开发自己有fable时都可以自己审核,只有开发的fable用完了,才需要分诊,但是此时分诊要能看出来,区别出来。」 This follows the triage seat's options on who owns contract review (lean C, a triage backstop). The maintainer narrowed the backstop to one trigger. Filed by the triage seat (session_01AavokzJ5DndAwitDXvKy4U, seat post #6015). ⛔ Not a claim.

The ruling, as rule text to write

  1. Default unchanged: the seat that dispatched the work runs the contract review at CONTRACT_REVIEW_TIER (references/contract-review.md: 「谁跑 = 派发席」).
  2. Hand-off only on an exhausted Fable: when that seat's CONTRACT_REVIEW_TIER call fails for quota (HTTP 429 / quota exhausted), the seat does not review at a lower tier. It hands the review to triage.
  3. Triage must be able to tell the case apart. The hand-off is one PR comment in a fixed, machine-findable shape, plus the existing needs:contract-review label:
    Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (<HTTP status / error>, <UTC time>) · head <sha>
    
    A PR that carries needs:contract-review without this line is still its own seat's to review, and triage does not touch it.
  4. Triage's act: each round, triage lists open PRs whose latest hand-off line names the current head. For each one, it runs the review in an isolated CONTRACT_REVIEW_TIER subagent, with the same-shape record (## Contract review, Served-tier:, the head sha, ①②③ (and ④ where it applies), PASS/FAIL), and Reviewed-by: naming the triage seat. A PASS removes the label, per the existing rule. If triage's own call is also quota-refused, triage writes that once on the PR and leaves the label, ⛔ it never reviews at a lower tier.
  5. Stale-review tracking. Maintainer, 2026-10-27, after triage missed a moved head on PR chore(ui-merge): clear the objectui leftovers after the ui/ merge (#25753) #26598: 「改进 skills」. Each round, triage compares every open PR that carries a triage-rendered ## Contract review record against its current head. If the head has moved past the record's Head-sha, that record is stale. The one exception is a move covered by the existing regen-only / prose-only rule, judged on the committed tree.
    • Triage's own FAIL, head moved: in the same round, triage re-reviews the new head at CONTRACT_REVIEW_TIER. It checks every earlier must-fix item, and it reviews the delta commits as changes in their own right.
    • Triage's own PASS, head moved: triage posts one note on the PR saying the PASS no longer governs and a delta review is owed. That review falls to the PR's own seat, or to triage again if a fresh Contract-review-handoff: line appears.
    • The round record lists each triage-reviewed PR as record head → current head → state (current / stale-FAIL re-reviewed / stale-PASS noted), so a moved head cannot drop out of sight.
    • The recogniser in scripts/pm/record-recognisers.mjs exposes the record's Head-sha and its Reviewed-by session, so the comparison is one read, not prose parsing. ⛔ No gate reads it.
  6. What does not change: the review grants no landing, enqueue or approval. Tier H still waits on the governed approver. A head that moves after the hand-off needs a new hand-off line (or the seat's own review).

Where it lands

  • .claude/skills/pm-dispatch/references/contract-review.md (〈复核归属与资格〉: the hand-off arm and the line's shape).
  • references/triage-duties.md (the round step).
  • node scripts/pm/record-recognisers.mjs: recognise the hand-off line, so a seat or patrol reads it the same way. ⛔ No gate reads it.

Tier S (.claude/**) plus one scripts/pm/** recogniser. domain:skills. Within the ratchet headroom: widen existing lines where possible.

Until it lands

The triage seat already applies points 3–4 by hand to any PR that carries such a line, or an equivalent explicit statement that the dev's Fable was quota-refused (for example #26619's "Fable quota was exhausted (HTTP 429)"). It does not touch reviews a seat is running itself.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: audit line · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T13:00Z

    ⛔ Not a claim, ⛔ not a dispatch.

    • Triage: lands in references/contract-review.md and references/triage-duties.md + one recogniser in scripts/pm/record-recognisers.mjs; rationale: p2 · domain:skills, on the maintainer's verbatim rule in the body. Tier S. ⛔ No gate reads the hand-off line. Triage applies it by hand until it lands.

    Generated by Claude Code

  2. added
    priority:p1High: required for production / M2
    and removed on Oct 27, 2026
  3. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Scope amendment: stale-review tracking · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T13:18Z

    ⛔ Not a claim. Maintainer, 2026-10-27, verbatim: 「改进 skills」. That was the answer to triage's proposal after it missed that PR #26598 had moved past its own FAIL record (434b014e → c260fddc, 12:39Z) and reported the stale FAIL in R706 as current.

    • The body gains item 6: each round, triage checks the heads of the PRs it reviewed. On its own FAIL it re-reviews the moved head; on its own PASS it posts a stale note; and the round record lists every triage-reviewed PR's record head and current head.
    • p2 → p1: a review record that no longer matches the code it gates can let a governed PR land on a review of different code.
    • Lane: domain:skills, Tier S (.claude/**) plus the scripts/pm/** recogniser. Until the PR lands, triage applies items 3–6 by hand. It started with the re-review of chore(ui-merge): clear the objectui leftovers after the ui/ merge (#25753) #26598 at c260fddc, which is in flight.

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01ADHkmSrRBdu9MdC6fc33Uu
    Account: os-steve (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/project-thread-1l85f6 (the card thread's harness push branch, self-reported at 2026-10-27T14:28Z — the measured platform exception to claude/issue-N-slug)
    Worktree: objectstack-issue-26667
    Domain: domain:skills
    Seat: domain:skills#1
    File surface: .claude/skills/pm-dispatch/references/contract-review.md (〈复核归属与资格〉: the hand-off arm and the line's exact shape), .claude/skills/pm-dispatch/references/triage-duties.md (the round step: body items 4 and 6), scripts/pm/record-recognisers.mjs (ONE recogniser for Contract-review-handoff: with self-test pins; ⛔ no gate reads it); nothing else (stop on breach; explain in the report)
    Container & model: S, mode:thread, model: CONTRACT_REVIEW_TIER (dispatch-gates --tier: no path mandate; reason: per-card ruling — the edit changes who may render a contract review and when a record still gates a head, which a governed landing rests on), effort: high. Tier S: draft PR; ⛔ the dev never readies, arms or enqueues it.
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card (a maintainer-directed rule, body plus amendment 6442901713)
    Thread-read: 6442901713
    Premise: holds (seat re-measure on origin/main 5cc31c78, after PR #26695: contract-review.md:20 「谁跑 = 派发席,达档者席内审」 has no hand-off arm; no file names Contract-review-handoff; triage-duties.md has no stale-head step)
    Serial constraints cleared: PR #26695 merged (2eefc8a0c); no open PR names contract-review.md, triage-duties.md or record-recognisers.mjs (#26598 edits lanes/triage.md, not triage-duties.md; #26741 edits coordinator.md)

  5. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26667,
      "status": "done",
      "branch": "claude/project-thread-1l85f6",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26771",
      "session": "session_01ADHkmSUY4HbWjTHDfPyAYU",
      "premise_still_valid": true,
      "summary": "Head c59cd9c6 on origin/main dc9d1ff8 (after PR 26695 merged). contract-review.md 〈复核归属与资格〉 gains the hand-off arm (a quota-refused CONTRACT_REVIEW_TIER call never reviews lower; the seat posts the hand-off line, keeps needs:contract-review, triage runs it) and the line's exact shape; the label section's readers line became the label-vs-line relation (label alone = the seat's own, triage does not touch; head moved after hand-off = fresh line or the seat's own review). triage-duties.md gains six round-step lines for body items 4 and 6 (list hand-offs naming the current head and run them in an isolated at-tier subagent signed by triage; triage's own quota refusal written once, label kept, never lower; each round compare every triage record's Head-sha with the current head, regen/prose-only excepted; stale FAIL re-reviewed in the same round with every must-fix and the delta commits; stale PASS gets one no-longer-governs note; the round record lists record head → current head → state). record-recognisers.mjs gains ONE recogniser: readContractReviewHandoff (the line: target triage, the tier by constant NAME through the Served-tier token reader, reason + UTC time, 7–40 hex head; anything less is unreadable) and contractReviewHandoff(rows, head) answering absent (the seat's own) / triage (names the current head, prefix-matched) / stale (head moved) / unreadable, newest governs via latestMarkedComment. No gate reads it; locateReviewOfRecord and the queue guard untouched, pinned past a hand-off line beside a record.",
      "line_budget": "contract-review.md 55 → 55 (ceiling 60): +2 hand-off lines, −2 (read-only shape + input set, both verbatim in --brief-template's built-in text, pointed at by the surviving 简报 line and self-test pinned); readers line rewritten (its filter query lives in dispatch-runbook.md 〈跨账户复审〉). triage-duties.md 103 → 103 (ceiling 103, headroom 0): +6, −6 with homes: emergency authorization → dispatch-runbook 〈紧急卡直接分诊〉; two (c)-metadata boundary lines → os-dev.md rule 3 verbatim twins; report-only instrument close → instrument-discipline.md L8/L12; routing-is-triage's + parent never dispatched → cross-repo-coordination.md L31, seat-lifecycle.md L54, filing-gate.md ④; lane seats do not triage → lanes/skills.md L22, lanes/ui.md L8, cross-repo L32. No re-wraps. All new lines ≤ 120 B except the hand-off line itself: 122 B as ONE code span, the card's exact shape kept verbatim, passing under the ratchet's structural `unbreakable` class (wrapLine returns it unchanged).",
      "tests": "node scripts/pm/record-recognisers.mjs --self-test → ✓ 232 cases pass (219 + 13 new battery cases: current head ⇒ triage, moved ⇒ stale, absent ⇒ seat's own, prefix both ways, newest governs both ways, decoration, four separators + comma in reason, no reason/time/head unreadable, other target/default tier/model id unreadable, unreadable newest names the comment, non-array thread/short head unreadable, one key regex + mid-sentence not a line, guard reading untouched beside a hand-off line), exit 0. SELF_TEST_BATTERY_FLOOR 12 → 13. No ablation: scripts and docs are not ablated.",
      "gates": "On head c59cd9c6: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) derived 40 families; all 40 run with exit captured before any pipe; --ran: ✓ 40 derived accounted for — 40 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. All exit 0, including check:pm-record-recognisers (232 pass), check:pm-skill-ratchet (ceilings held, counts unchanged), check:pm-skill-id-lint (104 files clean), check:pm-governed-prose (13 surfaces), check:pm-dispatch-gates (1935 pass, fast tier), check:skill-frame-sync, check:nul-bytes. First union on 4143b36f had check:pm-dispatch-gates red (2/1935): the battery's readFileSync of contract-review.md was an unclassified governed read in GOVERNED_READ_FLOOR / not derived for that file; fixed by dropping that one pin (c59cd9c6), union re-run whole on the new head. CI families (pnpm lint, Test Core) read from the PR's check-runs, not re-run.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — no GitHub MCP tool called; reads via REST (curl, GITHUB_TOKEN) and git",
      "api_writes": "2 — pr_create via fleet-write relay (run 40528625410, PR 26771, body 9150/9150 bytes identical, assignee os-steve, label skip-changeset); this os-dev-report comment via post-stamped. git push ×2 (not REST).",
      "files_changed": [".claude/skills/pm-dispatch/references/contract-review.md", ".claude/skills/pm-dispatch/references/triage-duties.md", "scripts/pm/record-recognisers.mjs"],
      "deviations": ["Hand-off line in contract-review.md is 122 B (one code span, structurally exempt) — kept the card's exact shape over a 2-byte placeholder respelling.", "First gate union ran on 4143b36f, not the final head; the fix commit c59cd9c6 touched only record-recognisers.mjs and the whole union was re-run on c59cd9c6 before the PR was opened.", "The PR body spells the line's placeholders in words (STATUS-OR-ERROR, UTC-TIME, SHA) — angle brackets do not survive the body sanitizer; the file carries the angle-bracket shape."],
      "open_questions": [
        { "question": "Card item 6 asks the recogniser to expose a record's Head-sha and Reviewed-by session; the claim's surface is ONE recogniser for the hand-off line.", "options": ["A keep as landed: locateReviewOfRecord(...).sha / absent already answers the head comparison, and the exported REVIEWED_BY_LINE capture group gives the Reviewed-by value", "B a follow-up adds readReviewedBy(text) beside readLocalRuns with pins"], "recommendation": "A, because the comparison item 6 needs is already one read; B is a new exported reader the card did not specify a shape for." },
        { "question": "landing-operations.md L13 still names the maintainer's own review as the ONLY bypass when the review subagent cannot start; the quota case now hands to triage.", "options": ["A leave (outside this card's file surface; the hand-off arm is the narrower, later rule)", "B seat widens L13 in a follow-up to point at the hand-off arm"], "recommendation": "A for this PR; B is a one-line follow-up for the seat if it reads as a contradiction." }
      ],
      "out_of_scope_findings": ["carrier: skills seat · noted, not filed: landing-operations.md L13 vs the new hand-off arm (prose pointer, no reach, not a card)"]
    }
  6. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26667,
      "status": "done",
      "branch": "claude/project-thread-1l85f6",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26771",
      "session": "session_01ADHkmSUY4HbWjTHDfPyAYU",
      "premise_still_valid": true,
      "summary": "Patch round on the seat's review of c59cd9c6 (report 6445754588 stands for everything else). Head 5956f4ba: triage-duties.md keeps the two (c)-metadata boundary lines and the routing line (their only other home was os-dev.md, which the triage seat does not read); the three new lines are paid instead by three pointer-only lines whose content the file already pointed at: the three-exit first-touch line (filing-gate.md 立卡门 L23–28: the two exits, the decision-inbox exit and the Batch-of line), the three-state grading pointer (filing-gate.md 定级判据 L46–48, pointed at by the surviving 四类 pointer), and the 域分批/积压告警 pointer (dispatch-runbook.md 发现分诊轮细则 L23 and L27). File count 103 → 103; every line ≤ 120 B; no re-wrap. The other two files are unchanged since c59cd9c6.",
      "line_budget": "triage-duties.md 103 → 103 (ceiling 103): +6 round-step lines, −6 with homes the triage seat reads: emergency authorization → dispatch-runbook.md 〈紧急卡直接分诊〉 L13; report-only instrument close → instrument-discipline.md L8/L12; lane seats do not triage → lanes/skills.md L22, lanes/ui.md L8, cross-repo-coordination.md L32; three-exit first touch + Batch-of → filing-gate.md L25–28; three-state grading pointer → filing-gate.md L46–48; 域分批/积压告警 pointer → dispatch-runbook.md L23/L27. contract-review.md 55 → 55 as reported before.",
      "tests": "unchanged: node scripts/pm/record-recognisers.mjs --self-test → ✓ 232 cases pass, exit 0 (re-run on 5956f4ba).",
      "gates": "On head 5956f4ba: --commands derived 40 families; all 40 run with exits captured; --ran: ✓ 40 derived accounted for — 40 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. check:doc-formula-expressions first answered exit 3 (PREREQUISITE NOT MET: the re-created worktree had no formula/lint dist); after `turbo run build --filter=@objectstack/formula --filter=@objectstack/lint` under os-verify-lock (VERDICT command-exit 0) it ran exit 0 and the --ran record carries that run. check:pm-skill-ratchet ✓ (counts held), check:pm-skill-id-lint ✓ 104 files clean, check:pm-governed-prose ✓, check:pm-record-recognisers ✓ 232, check:pm-dispatch-gates ✓ 1935.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — no GitHub MCP tool called; reads via REST (curl, GITHUB_TOKEN) and git",
      "api_writes": "3 cumulative — pr_create via relay (PR 26771), report comment 6445754588, this patch-round report comment. git push ×3 (not REST).",
      "files_changed": [".claude/skills/pm-dispatch/references/contract-review.md", ".claude/skills/pm-dispatch/references/triage-duties.md", "scripts/pm/record-recognisers.mjs"],
      "deviations": ["PR body NOT patched (os-dev.md: the dev writes the body once; the seat order's issue_patch allowance yields to the file). The body's line-budget row for triage-duties.md names the first round's six cuts; the seat rewrites it to the six homes in `line_budget` above.", "Hand-off line 122 B as one code span (structural `unbreakable` exemption), as before."],
      "open_questions": [],
      "out_of_scope_findings": ["carrier: skills seat · noted, not filed: landing-operations.md L13 vs the hand-off arm (as reported before)"]
    }
  7. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #26771 comment 6446385869 · domain:skills#1 · 2026-10-27T15:41Z · Tier S; draft until a PASS contract review on the head (requested from the director seat) and the maintainer's act (os-zhuang, hotlong requested).

  8. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:skills#1 · session_01ADHkmSrRBdu9MdC6fc33Uu · 2026-10-27T23:19Z — PR #26771 merged through the queue (merge commit bdb00ffef4) on the os-zhuang approval, after the director's PASS on round 2; the contract-review fallback rule when the implementing seat's Fable is exhausted is in pm-dispatch, the three triage rules round 1 had deleted kept. The card closed by its Fixes line; pm:dispatched stripped in this act. #26762 (same triage-duties file) is claimed next.

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:p1High: required for production / M2tooling

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions