Skip to content

skills(pm): give sweep disjunct ① the drain clauses the finding box already has - #14152

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-14022-bare-card-drain
Sep 1, 2026
Merged

skills(pm): give sweep disjunct ① the drain clauses the finding box already has#14152
os-zhuang merged 2 commits into
mainfrom
claude/issue-14022-bare-card-drain

Conversation

@claude

@claude claude Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Fixes #14022

GOVERNED SURFACE — draft only, human merge. The diff is entirely under .claude/**
(Prime Directive 14 in AGENTS.md). No seat merges, queues, or arms auto-merge on it.

⚠️ FABLE-MANDATE FACE. node scripts/pm/dispatch-gates.mjs derives
Model tier — MANDATORY: claude-fable-5 for this diff, via clause ① of the model-tiering
ruling: .claude/skills/pm-dispatch/SKILL.md is the lane's own operating protocol and a
wrong edit propagates to every later dispatch. The skills seat pre-recorded the
compensating fable-tier review duty on the card before dispatch; it has now run on this
PR's SKILL.md face and its two blocking findings are applied here — see "The at-tier
review revised the adjudicated numbers" below, and the HOLD MERGE comment the seat lifts
after re-review. The second touched file (references/dispatch-runbook.md) dropped out of
the path mandate on 2026-08-20 and is not part of that face.

What was missing

Sweep disjunct ① (bare cards: no pm:*, no needs-user-decision, no domain:*) had a
stock query and nothing that drains it. Its whole ordering rule was five characters —
新入卡①优先最新 — sitting at .claude/skills/pm-dispatch/SKILL.md:347. Newest-first
minimises time-to-first-touch only while intake is at or below throughput; the moment it
is not, the seat only ever reads the arrivals and the tail is never reached by
construction
. Three measured rounds followed the rule exactly and produced 33 cards that
appeared in all three enumerations untouched. The cost is hidden severity, not latency: a
p1 with no labels is invisible to every lane's candidate query.

What lands — three clauses, one home each

All three go into the sweep paragraph and the round-brief indicator list, which is where
the disjunct-① spec actually lives (grep evidence below). Numbers carry their rationale
inline in compressed form; no issue ids in operative text.

1 — health metric. The round brief's health indicators go from four to five:
裸卡数与中位年龄 joins the finding line, sourced from sweep 析取①. A label-absence
population has no totalCount to read, so the runbook's hourly-tier reading recipe records
the one exception the new indicator creates: it comes from the round's own disjunct-①
enumeration, no extra query.

2 — first-touch every round, run to empty, with the ordering rule REPLACED. No
per-round total budget: 清得动就多清、清不动不欠, and a window that runs out resumes from
the breakpoint on the next fire. A bare card costs more per unit than a finding (full read

  • route + grade + type) — stated as the reason bare rounds run long, which the
    2026-08-25 ruling accepts, not as a reason to cap. The ordering rule becomes conditional:
    newest-first while the queue clears each round, oldest-first the moment it does not,
    with the inversion rationale written into the clause itself.

3 — auto-concentrated threshold. Bare count above 15 ⇒ the next fire switches its whole
round into domain-batched concentrated mode: batches of at most 5 same-family cards, run to
empty or to the breakpoint, resuming next fire. The threshold changes the round's mode,
never its size.

Clauses 2 and 3 land as a pair and the operative text says why: run-to-empty drains
steady state, the threshold absorbs bursts (measured: 13 arrivals in 40 minutes, roughly 4×
the steady rate, a consecutively-numbered audit-dump shape) by dedicating the next fire to
domain batching, and neither substitutes for the other — without the threshold a dump is
worked in arrival order across ordinary rounds, losing the same-family single-context read
while the tail keeps growing.

Existence proof (belongs here, not in the operative text)

This is not a proposal evaluated on paper. The maintainer ordered a manual concentrated
round on this exact population; it cleared 40 bare cards in one round, about 2.5 hours,
every card read in full, per-card criteria given, and no batch over 5
. The mechanism has
run on this population and worked. What was missing is only the part that does not require
the maintainer to order it in person.

Why this is protocol rather than habit

The seat has been doing oldest-first inside its own sweep for five consecutive rounds — and
across all five it remained ordering discretion, not protocol. That is both the
evidence that the mechanism works and the reason it has to be written down: a rule held for
five rounds by one seat's self-discipline evaporates on seat change. Three disjuncts hit
zero at R+84 under that discretion, which is exactly why the defect reads as "the mitigation
should not be load-bearing" rather than "something is leaking today".

⚠️ Premise check on today's origin/main — two cells of the card's table are stale

The card's defect premise is confirmed: 新入卡①优先最新 is present verbatim at
SKILL.md:347 on origin/main at 2bff79ae3, disjunct ① has no drain clause, and the
health-indicator list said 健康指标四个 with no bare-card line.

The card's remedy-source premise is stale, and the reviewer should see it. The card's
comparison table marks the finding box as carrying "first-touch every round, budget 3–5" and
"auto-concentrated at >15". Both left that paragraph on 2026-08-25, six days before the
card was filed, under the run-to-empty ruling (verbatim, untranslated:
「单轮跑数小时没关系啊。不读卡的批量盖章 可以通过每批5张这种约定来解决」). What main
actually carries today:

  • SKILL.md 发现分诊轮: **每 fire 跑到清空**:⛔ 无每轮总量预算质量靠**每批 ≤5 张同族卡逐张读**,不靠封顶总量
  • dispatch-runbook.md: **每批约定**:≤5 张同族卡、同上下文逐张读(维护者 2026-08-25,取代 15–20/批)
  • dispatch-runbook.md: **积压告警**(旧 >15 触发的去处):连续 COMPLETED 清空 fire 后仍 >15 ⇒ 入流 > 吞吐,报维护者。

The at-tier review revised the adjudicated numbers — what changed and on what grounds

The first push encoded the seat's adjudicated numbers verbatim (first-touch budget 3–5 as a
ceiling; concentrated round of 15–20 per round). The fable-tier compensating review found
that encoding faithful but wrong on the numbers, and both numbers are now gone. This
section is the record; the numbers were the seat's, and the review is where they were
corrected.

a — the concentrated round's 15–20 per-round total re-created the retired category. The
2026-08-25 ruling did not merely retire a batch size; it retired 封顶总量 as the quality
mechanism
. SKILL.md says so in its own words two paragraphs down from this clause:
**每 fire 跑到清空**:⛔ 无每轮总量预算质量靠**每批 ≤5 张同族卡逐张读**,不靠封顶总量
单轮数小时是可接受形态窗口耗尽未跑完的,下一 fire 从断点续跑. A per-round total for
disjunct ① is that category, whatever its unit. The second ground is sharper than the
first: the cap would have forbidden the maintainer's own existence-proof round — 40 bare
cards cleared in a single round is not reachable under a 15–20 round total, so the clause
would have outlawed the very evidence it rests on. What survives is the trigger, 域分批 and
每批 ≤5; the size cap is replaced by run-to-empty, window-bounded, resuming from the
breakpoint — the sibling's post-ruling wording, reused rather than re-invented.

b — the budget sentence was self-contradictory, and the safe reading was the harmful
one.
预算 3–5 张是上限不是配额 —— …清得动就多清、清不动不欠 gives two mutually exclusive
instructions in one breath; a seat reading conservatively takes the ceiling, which is the
chronic-under-clear hazard on exactly the population this card exists to drain. The numeric
ceiling is deleted and the clause is pure run-shape. No calibration number was kept,
though the review allowed one as expectation prose: on a population that has needed 9, 13
and 40 cards cleared in a round, a 常态 3–5 anchors low in precisely the flagged
direction. The per-unit-cost parenthetical stays, repositioned as the reason bare rounds run
long单轮数小时同为可接受形态,⛔ 不是封顶总量的理由.

c — the isomorphism claim is now literally true, so the parenthetical says which parts.
With a total cap gone, both boxes carry metric + run-to-empty drain + threshold. The
parenthetical no longer hedges with 参数按本总体自定 (the parameters largely vanished with
the numbers); it now reads 与发现箱同构:指标 + 跑到清空 + 阈值;本总体另加排序一条, naming
the ordering rule as this population's own addition — the finding box has no ordering rule
at all, and the ordering inversion is the measured defect this card was filed for.

Where it lives — the grep that decided it

git grep -n "优先最新"      -> .claude/skills/pm-dispatch/SKILL.md:347  (the only hit in the repo)
git grep -n "新入卡"        -> .claude/skills/pm-dispatch/SKILL.md:347  (the only hit)
git grep -n "健康指标"      -> SKILL.md:793 (the four-item list, the only place the count is pinned)
                               references/dispatch-runbook.md:74 (brief template — defers: 沿用主文件轮次报告节定义)
                               references/dispatch-runbook.md:92 (the per-label totalCount reading recipe)
                               references/platform-readings.md:85 (perPage sizing, no indicator list)

One home per fact, and the indicator list has exactly one definition — the runbook's
round-brief template inherits it by pointer rather than copying it, so there was no second
copy to move.

The published catalog is NOT touched, and that is measured, not assumed.
git grep -n "优先最新\|析取\|健康指标" -- skills/ returns zero hits.
skills/objectstack-pm-dispatch/SKILL.md carries the generic three-disjunct sweep
description for customer projects (its lines 173–222) with no ordering rule, no budget and
no health-indicator list — nothing in it goes stale from this change. So this diff does not
touch skills/** and owes no published-skill line/token budget reading.

Per-file budget and funding

file base after push 1 after the review patch ceiling headroom now funding
.claude/skills/pm-dispatch/SKILL.md 971 981 984 1005 21 existing headroom
.claude/skills/pm-dispatch/references/dispatch-runbook.md 276 277 277 278 1 existing headroom

The +13 on SKILL.md splits 11 (the disjunct-① drain clause) / 2 (the fifth health
indicator); the review patch cost +3 net, because the run-shape wording is longer than the
two numbers it replaced. No ceiling raised, so no maintainer ruling is quoted for a raise —
none is needed. ⛔ No re-wrap was used to buy lines: every line that came back over the
120-byte cap during authoring was re-wrapped within its own new content, and the one
pre-existing line that moved (SKILL.md:347, 121 bytes after the ordering-rule deletion)
was rebalanced against the line below it at net zero. Every touched line is at or under 120
bytes.

Gates — full derived union, after the last commit

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no
explicit paths; the script takes its own change set from the merge base). Re-derived after
the review patch — the same 9 families. Every row below was re-run at the new
HEAD 438df6a82
with a clean git status, exit codes captured before any pipe:

gate exit verdict line the gate printed
pnpm check:agent-test-spelling 0 ✓ check-agent-test-spelling: 0 violations — 428 file(s) · 5499 bare -- token(s) · 1320 launcher-rooted run(s) · 9 separator(s) JUDGED
pnpm check:doc-authoring 0 ✓ doc authoring guard: 394 files clean — no bare metadata literals. / ✓ 48 published skill files clean — no internal issue-id references.
pnpm --filter @objectstack/lint run check:doc-formula-expressions 0 ✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 427 files / 1451 TS blocks judged clean by @objectstack/formula. (needs its closure built first — see the note below)
pnpm check:pm-governed-merges 0 ✓ check-governed-merges --self-test: 243 assertions · live: the real generator declared 9 output(s) and certified this tree
pnpm check:pm-governed-prose 0 ✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces (docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md) and claim no others.
pnpm check:pm-skill-id-lint 0 ✓ check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g).
pnpm check:pm-skill-ratchet 0 four verdict lines, quoted in full below
pnpm check:skill-frame-sync 0 ✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files · 4 count mention(s) agree
node scripts/pm/check-governed-queue-guard.mjs 1 NOT MEASURED locally, not a red — see below

⚠️ Two rows that are readings about the harness, not about this diff.

  • check:doc-formula-expressions came back exit 3 on a freshly installed worktree,
    which the gate itself labels
    PREREQUISITE NOT MET — the workspace package @objectstack/formula is not built and
    Nothing was measured … It is NOT a finding. Recorded rather than swallowed, because a
    bare exit 3 read as a red is how a non-measurement gets reported as a failure. After
    pnpm exec turbo run build --filter=@objectstack/lint --concurrency=2 (which pulls the
    closure including @objectstack/formula) it runs exit 0; the review-patch run built
    the closure first, so the table's green is a real measurement.
  • check-governed-queue-guard exits 1 with
    could not read GITHUB_EVENT_PATH … "could not look" must never exit 0 here. It reads the
    workflow event payload and nothing else, so it is unrunnable outside CI by construction.
    Recorded as not-measured; CI measures it.

Line-ratchet verdicts, quoted for every touched governed file (check:pm-skill-ratchet,
same run):

✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md: widest table row is 642 bytes (pin 642; headroom 0).
✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md is 984 lines (ceiling 1005; headroom 21).
✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/dispatch-runbook.md: widest table row is 0 bytes (pin 0; headroom 0).
✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/dispatch-runbook.md is 277 lines (ceiling 278; headroom 1).

Beyond the derived union, at the same HEAD: repo-wide pnpm lint
(eslint . --no-inline-config) — exit 0, run in full rather than narrowed. Byte
discipline: grep -naP over both touched files for the C0 control range plus DEL returns no
hits. No gate or tooling script is edited by this diff, so no gate-script test suite is
owed. Every heavy run went through bash scripts/pm/os-verify-lock.sh -c with a stable
OS_VERIFY_LOCK_SLOT.

Changeset: none. The diff is .claude/**-only and publishes nothing from any package,
so skip-changeset is applied to this PR additively and read back (documentation and
size/s arrived afterwards from the labelers; the additive write was not stripped).

The seat's HOLD MERGE comment stands and was not touched — the seat lifts it after
re-review. Nothing here asks for it to be removed.

Authored in Claude Code session
https://claude.ai/code/session_01Msg17tAHJ3jVTYFgHydCm2 — recorded in the prose because a
body edit rewrites the footer below back to its bare form.


Generated by Claude Code

…lready has

Disjunct ① (bare cards: no pm:*, no needs-user-decision, no domain:*) had a
stock query and nothing that drains it, and its ordering rule 「新入卡①优先最新」
inverts into tail starvation the moment intake exceeds throughput.

Three clauses land in the sweep paragraph, one home each:

- first-touch grading every round, budget 3–5 stated as a CEILING not a quota
  (a bare card costs more per unit than a finding: full read + route + grade
  + type);
- the ordering rule REPLACED: newest-first while the queue clears each round,
  oldest-first the moment it does not, with the inversion rationale inline;
- bare count > 15 ⇒ the next fire runs a domain-batched concentrated round of
  15–20 cards per ROUND (not per batch — batches stay ≤5 same-family per the
  standing convention), with the pair rationale written in: the threshold
  absorbs bursts, the budget drains steady state, neither substitutes.

The round brief's health indicators go from four to five: bare count + median
age join the finding line. The runbook's hourly-tier reading recipe records the
one exception the new indicator creates — a label-absence population has no
totalCount to read, so it comes from the round's own disjunct-① enumeration.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Msg17tAHJ3jVTYFgHydCm2
@github-actions github-actions Bot added the size/s label Sep 1, 2026
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 1, 2026
@claude
claude Bot requested review from hotlong and os-zhuang September 1, 2026 08:33
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 1, 2026

os-sam commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

⚠️ HOLD MERGE — fable-tier compensating review found two blocking items; a patch round is in flight (dispatching seat, session session_01Msg17tAHJ3jVTYFgHydCm2).

The review verified the encoding faithful and the homes/pins clean — the blockers are against the SEAT's adjudicated numbers, not the build: ① the 15–20 张/轮 round-total cap on the concentrated round re-creates the 封顶总量 the 2026-08-25 run-to-empty ruling retired (⛔ 无每轮总量预算), and would have forbidden the maintainer's own 40-card existence-proof round; ② 「预算 3–5 张是上限不是配额 —— 清得动就多清」 carries two mutually exclusive instructions, and the conservative reading is the chronic-under-clear hazard. Both fixes converge on the sibling's post-ruling run-shape (run to empty, window-bounded, 断点续跑, quality via ≤5/batch), which also turns the 与发现箱同构 parenthetical true. The patch lands on this branch shortly; the seat will confirm here when the head is review-clean.


Generated by Claude Code

…pty shape

The at-tier compensating review found two blocking items against the numbers
the seat adjudicated, on two independent grounds.

1. The concentrated round's 15–20 per-round total re-created 封顶总量 — the
   exact category the 2026-08-25 run-to-empty ruling retired for the sibling
   box (⛔ 无每轮总量预算 … 不靠封顶总量 … 单轮数小时是可接受形态 … 下一 fire
   从断点续跑). It would also have forbidden the maintainer's own 40-card
   round, which is the existence proof the clause rests on. The trigger,
   域分批 and 每批 ≤5 stay; the size cap becomes run-to-empty, window-bounded,
   resuming from the breakpoint on the next fire — the sibling's post-ruling
   wording.

2. 「预算 3–5 张是上限不是配额 …清得动就多清、清不动不欠」 carried two
   mutually exclusive instructions, and the conservative reading is the
   chronic-under-clear hazard. The numeric ceiling is gone; the per-unit cost
   parenthetical is repositioned as the reason bare rounds run LONG — which
   the ruling accepts — rather than a reason to cap. No calibration number is
   kept: on a population that has needed 9, 13 and 40 cleared in a round, a
   「常态 3–5」 anchors low in precisely the direction the review flagged.

With both fixed, 「与发现箱同构」 is now literally true (metric + run-to-empty
drain + threshold), so the parenthetical says which three parts are shared and
names the ordering rule as this population's own addition. The pair rationale
survives with its terms updated: the threshold absorbs bursts by switching the
next fire into domain-batched mode, run-to-empty drains steady state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Msg17tAHJ3jVTYFgHydCm2

os-sam commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

HOLD LIFTED — head 438df6a82 is review-clean.

Both blocking findings from the fable compensating review are fixed on this branch (cap → run-to-empty mode switch; numeric budget ceiling deleted), verified by the seat against the fetched head, not the dev report: banned shapes grep = 0, revised clause read verbatim at SKILL.md:349–359, 984/1005 lines, all 9 union gate families green at this head. Full ACCEPT record with the seat's owned adjudication error is on #14022 (comment 5491533689).

This PR touches .claude/skills/pm-dispatch/SKILL.md — a governed, fable-mandate face — so it stays a draft for human merge; the seat does not flip it ready or queue it.


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 1, 2026 10:22
@os-zhuang
os-zhuang enabled auto-merge September 1, 2026 10:22

os-sam commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Queued under the authorized-approval ending — provenance.


Generated by Claude Code

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

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants