pm(half-states): H66 lists a released pm:queue card whose remainder is not work - #18514
Merged
os-justin merged 5 commits intoSep 16, 2026
Merged
Conversation
… is not work A card released with a remainder no dev can execute wears `pm:queue` with no assignee, which the selection order reads as ready to dispatch. H66 reads the card's NEWEST comment out of the shared cache -- no new fetch class -- and lists the card when that comment is a release the label contradicts. The canonical `Release:` line's 去向 was measured first and came back ZERO of 29 threads on two boards, with the prose leg lit on 3 of the same 4 specimens as the control; both legs ship, the canonical one first, and the summary clause publishes the zero. Report-only: it never relabels and never returns a verdict. Adds this file's first battery roster + floor beside the existing handshake. Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu Co-authored-by: Claude <noreply@anthropic.com>
…t `[0].heading` Measured during the anchor ablation: the direct index throws while evaluating the case's arguments, so the suite ABORTS at that line and every later case never runs -- the exact shape this file's own row-wrapper note warns about. Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu Co-authored-by: Claude <noreply@anthropic.com>
Second abort site measured by the same ablation: `h66ReleaseVerdict` is three-valued, so a direct field read throws in the case's arguments and takes every later case with it. Both readers keep a nulled helper reporting under its own case name. Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu Co-authored-by: Claude <noreply@anthropic.com>
…leased-nondispatchable-remainder-row
The first live sweep measured the cost of buying nothing: 194 candidates, a thread in hand for ONE, because the only row that buys a card thread buys it for an ASSIGNED card and this population is that set's complement. The row now defers cache misses to a bounded pass at the foot of the sweep: candidates ordered newest-touched first, at most H66_THREAD_BUY_CAP=100 per run, ONE page each -- the NEWEST, located from the card's own comments count through H65's helpers, never page 1 on a long thread. A failed buy, or a carrier whose newest page cannot be located, is UNJUDGED and counted as such; candidates past the cap are NOT ATTEMPTED and counted separately. The cache write-back is guarded to the one case where the bought page IS the whole thread, so no reader is handed a partial window. seatWindowAudit gains seatPurchaseSites: the second located-page purchase is on a disjoint population, so the fetch-per-seat-post bound is split out and kept at one rather than raised. Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu Co-authored-by: Claude <noreply@anthropic.com>
os-justin
marked this pull request as ready for review
September 16, 2026 18:43
os-justin
deleted the
claude/issue-18299-released-nondispatchable-remainder-row
branch
September 16, 2026 19:05
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #18299
A card released with a remainder no dev can execute — a maintainer ruling, a reading only the reporter can take, a confirmation owed by another seat — wears
pm:queuewith no assignee, which the queue view and 「最老优先」 both read as ready to hand to a dev. The label cannot tell that apart from real queue work; only the card's newest seat comment can, and reading that costs a full card read per candidate.H66 is the detector the card asks for: report-only, a listing, never a relabel and never a gate verdict.
Authored by
session_01Gqi43smmqjJ5sUrhfoPeKu(Claude Code). Every reading below was taken on this branch at301de97, the head this body describes.The clause it enforces
Two lines of
.claude/skills/pm-dispatch/SKILL.md, quoted verbatim in the row's own sentence:pm:queue= 有具名落点或复现的具体缺陷,或范围明确的工具/门禁修复,无可问之事。」 — the label is a definition, not a habit.Release:行(会话/因/去向);下一任重新认领。」 — the release act, whose 去向 field is the only thing that can say where the card went.⛔ The row does not decide the state question. Whether these cards belong in
needs-user-decision, inpm:awaiting-maintaineror in a spelling that does not exist yet is left open exactly as the card leaves it; the remedy the row prints is 「judge by hand — this is a listing」.The measurement — the dispatch's A1 was falsified before anything was built
A1 assumed the machine-readable half is the
Release:line's third field (去向). Measured 2026-09-16 over both boards the filing card names, read-only:Release:linespm:queuecardsZero of 29. The lit control for that zero is the prose leg read by the same fetch over the same threads: it answers three on the same four specimens, so the zero is a property of the board, not of a broken reader.
⇒ Both legs ship, the canonical one first. It is kept, not dropped, for a mechanical reason: H47 exists to report exactly that absence, and as it is answered the canonical line starts appearing — on that day it is the only reading that can tell a return-to-queue (去向 =
pm:queue, ⛔ never a finding) from an exit, because both are written in the same announcement heading otherwise. The summary clause publishes the zero on every run.The prose leg's three anchors are frozen beside the live comment each was measured on — objectui#7696
5664140343, #81675663517223, #89385668851500— and the third anchor named by the filing card itself is labelledmeasured: false, so nobody later reads it as a measurement. Matching is heading-anchored (H58's fence/blockquote/table/code-span refusals, reused): the filing card, this PR and the row's own docblock all quote the spellings, and none of them may fire.pm:queueis not read over the whole comment body, and that is measured rather than stylistic: the two live release comments on objectui#8167 and #8938 both say 「pm:dispatchedstripped,pm:queueadded」 in their state-write paragraph, so a body-wide read would clear precisely the specimens this row exists to list.The bounded fetch leg — and why the first landing needed one
The row first shipped buying nothing: one
commentCachelookup per card. The first live sweep measured what that costs — 194 candidates, a thread in hand for 1. The corpus is thin by construction, not by luck: the only row that buys a card thread for a pm-tracked card is H2's claim read, and H2 buys one only for an ASSIGNED card, which is this population's exact complement. A listing that cannot see 99.5% of its own population is a row whose silence means nothing, and the filing card's own criterion already asks for the fetch — 「fetch the newest comment authored by a seat」.So a bounded buy pass now sits at the foot of the sweep:
commentscount through H65's exportedh65NewestPagePlan/h65CommentPagePathrather than a second copy of the arithmetic. ⛔ Never page 1 on a long thread: GitHub serves issue comments OLDEST-FIRST, so a page-less read returns the archive (the [finding] check-half-states: H44's seat leg is blind on the triage seat post it was written for — its corpus is the thread's FIRST comment page (oldest-first, five weeks stale on #6015) andH44_ROUND_OPEN_MARKERno longer matches the marker spelling; H56 / H64 share the corpus #18312 measurement — five weeks stale on a long thread).updated_atdescending,numberas a total-order tiebreak; an unreadable stamp sorts last, never promoted ahead of a dated card). A release is a write on the card, so that is where fresh evidence lives — deliberately the opposite of the dispatch order 「最老优先」, which says which card to work, not where the evidence is.H66_THREAD_BUY_CAP = 100. The standing caller ishalf-state-patrol.ymlonPATROL_CRON=37 1,7,13,19 * * *— four runs a day — under the Actions token's 1000 requests/hour per repository, beside the sweep's existing label pages, listings, PR windows, H50 walks, H43 probes, H45 parent reads and seat pages.commentscount is unreadable and whose page 1 came back FULL (so the newest comment cannot be located), leaves that card UNJUDGED — never clean, the H4 three-state contract — and is counted as such.commentCache, because a newest page is not the same object as the first page that cache holds. The write-back is guarded to the one case where the bought page is the whole thread (plan.page === 1);seatPostRowsForkeeps its own window out of that map for exactly this reason, and this applies the same rule to the one case where the two coincide. A card whose thread is already in hand is judged in place, free, and never deferred — so never re-bought.seatWindowAuditgainsseatPurchaseSites. The buy adds a second located-page purchase, so rather than raise the file-wide pin from 1 to 2 and lose the argument behind it, the seat-post bound is split out and stays at 1 — the new purchase is on a disjoint population (an unassignedpm:queueCARD, never apm:seatpost), so it cannot be the 「same page bought twice」 the original bound is about.Disjointness (the dispatch's A3), and the one overlap stated rather than hidden
pm:dispatched; this population ispm:queuewithout it. Disjoint by label.Claim:is the newest ownership record and noRelease:answers it. On the canonical legreleaseAnswersClaimis true and H47 returns null.pm:dispatchedand an assignee. Disjoint.Population excludes an assigned card (H24's row) and any card carrying a second member of
PM_EXCLUSIVE_STATE_LABELS— that pair is H3's, H25's or H29's contradiction. One vocabulary, ⛔ not a second list.Battery roster and floor
This file printed one total over a flat case list — the shape AGENTS.md 「Writing a
--self-test」 names as evidence rather than proof. The handshake (SELF_TEST_VERDICT) was already here; the floor was not. This PR adds the other half, copied fromscripts/check-agent-model-declared.mjsand ⛔ never imported:301de97H66 released queue cardThree failure conditions, each producing a real⚠️ The roster is partial and says so: the several hundred pre-existing
process.exit(1): a declared battery below its pin; a case registered against an undeclared battery; the roster belowSELF_TEST_BATTERY_FLOOR.t(...)cases stay unbatteried, and retrofitting them is a diff of its own.Cases cover every clause the dispatch named — (a) a 去向 naming a non-queue owner ⇒ listed · (b) 去向 =
pm:queue⇒ silent, including where an announcement heading sits beside it · (c) both prose forms ⇒ listed · (d) any later comment ⇒ silent, structurally, because the row reads the newest · (e) an assigned card ⇒ outside the population · (f) no comment at all ⇒ silent — plus the seven quoting shapes that must not fire, the anchor set's cap/freeze/provenance, the three-input-state contract, band, registry coverage, and the summary clause in both media. The buy leg adds: the cap respected when candidates exceed it, newest-touched ordering with the undated card last, a bought page judged by the same predicate as a cached one, a failed buy read as UNJUDGED, and the two source-audited guarantees below.Measurements — all at
301de97Gates —
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 40 commands at301de97; all 40 run, each exit code captured by redirect-then-$?and never through a pipe, 40 exit 0. Reconciled with--ran: 「40 derived famil(ies) accounted for — 40 run, 0 NOT-MEASURED (a DERIVED zero — all 40 recorded an exit code and none of them is 3)」.Lint — the whole-repo run, not a narrowing:
pnpm lint=eslint . --no-inline-configover eslint's own population of 6,798 files, exit 0 at301de97.Self-test —
node scripts/pm/check-half-states.mjs --self-testandpnpm check:pm-half-statesat301de97: exit 0, 「4546 cases pass. Batteries: H66 released queue card 183/172.」Live sweep — report-only, from an agent container at
301de97, exit 0: 465 half-states over 397 pm-labelled issues. The H66 clause, the new quadruple:⇒ the leg works and costs what it declares: 100 pages bought, every one read, nothing unjudged. The board genuinely has no card in this shape right now — the filing card's own four specimens were all dispositioned by hand between filing and this build. Before the leg the same sweep read
194 / 1 / — / 0, i.e. the row could see one card in two hundred.Request count — the run total is NOT MEASURED: the script exposes no request counter, and the container's
/rate_limitproxy reported a full 15000/15000 both before and after with the quota window rolling between the two reads, so the delta is not a measurement either. What is exposed is the leg's own cost, and it is exact:queueReleaseBought= 100, one request each, printed on the summary line every run.Ablations — three, each mutating the committed tree, proving the mutation on disk by occurrence count, restoring with
git checkout HEAD -- pathunder atrap, and verifying the restore by blob hash againstgit rev-parse HEAD:pathplus an emptygit diff HEAD:Control after every restore: exit 0, 4546 cases pass. ⭐ The first ablation also found two real defects in the battery it was measuring — a direct
[0].headingand a direct field read on a three-valued helper, each of which aborted the whole suite with a TypeError instead of reporting a case. Both are now read through describing readers, with the measurement recorded beside them.Renderers — both, offline over a synthetic finding:
renderPlainandrenderMarkdowneach render theH66row, the clause with its counts, and the markdown family ledger namesH66.Scope
scripts/pm/check-half-states.mjsonly. ⛔ objectui's copy is byte-pinned there and is not touched.skip-changeset:scripts/pm/**is the fast lane and nothing in any package'sfiles[]moves.Generated by Claude Code