Skip to content

fix(pm-gate): H26 reports no SCHEDULED releaser, not an impossible one - #9391

Draft
baozhoutao wants to merge 1 commit into
mainfrom
claude/issue-9317-h26-counted-not-asserted
Draft

fix(pm-gate): H26 reports no SCHEDULED releaser, not an impossible one#9391
baozhoutao wants to merge 1 commit into
mainfrom
claude/issue-9317-h26-counted-not-asserted

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Draft, and it must stay draft until a routing decision is made. The code change is complete
and its self-test is green, but check:upstream-port-parity goes RED on it for a structural
reason neither the card nor triage saw. That is reported below, not worked around.

Part of objectui#9317. Triage ruling: comment 5651018392.

What the row used to say, and why it was wrong

H26 asserted that pm:on-hold and needs-user-decision are "by definition states a card sits
in WHILE OPEN", so a pm:blocked card waiting on one had "NO MECHANISM THAT WILL EVER RELEASE
IT". That was asserted, never counted.

Re-derived on this branch rather than copied from the card — objectui, 2026-09-13, REST
/issues?labels=LABEL&state=STATE&per_page=100, pull requests excluded. Population: every
ISSUE in this repository carrying the label
(not comments, not PRs, not call sites):

label open issues closed issues closed state_reason
pm:on-hold 62 7 6 completed, 1 not_planned
needs-user-decision 3 3 3 completed
pm:blocked (control) 100 7

Control with a known direction, and it HIT: the same enumerator returned non-zero on all
three closed rows (7, 3, 7). A broken state=closed would have returned 0 on all three. So the
closed column is not a query artefact.

Nine of the ten measured closures are completed — the hold lifted and the work finished, which
is exactly the release the row said could not exist.

The file had already counted the refutation against itself. On this branch's base
b67b53bc0b3026cccbc263e54cf4baa4e1e5100f, re-measured rather than copied:

  • scripts/pm/check-half-states.mjs line 7922 — the objectui port census records
    pm:on-hold on 1 closed card in a 6.2-day window.
  • line 3772 — H22's docblock calls needs-user-decision "perfectly good states for a closed
    card to have ended in", the direct converse of H26's line 502, in the same file.

What it says now

The wait has NO SCHEDULED RELEASER — it is waiting on a releaser nobody has been assigned to
be. Not that the state cannot be exited.

⭐ H26's final sentence is kept verbatim, per triage acceptance 2 — it was always the
accurate half: the release has to come from the target's own state changing (a ruling answered,
a hold restarted) and someone has to want that.
It is now pinned by a new assertion, so a
later rewrite cannot quietly take it along with the retired half.

Six sites moved together, not four

The card and triage listed four. Re-measuring on this base found a fifth and a sixth:

# site base line listed by triage?
1 header docblock 500-502, 519 yes
2 the #11219 rationale 4508-4554 yes
3 INDEFINITE_TARGET_LABELS jsdoc 4558-4563 no
4 resolution-map rationale 8827-8829 no
5 the emitted string 4613-4616 yes
6 the H26: self-test 12156-12216 yes

⚠️ Site 4 is the one worth naming: its "can never close" is split across two lines, so the
line-oriented grep that finds every other site returns a confident miss on it. Both new sites
carry the same assertion as the four that were listed.

The control FIRES — triage acceptance 4

Green on its own cannot tell "fixed it" from "deleted the assertion along with the sentence it
named". So the self-test gains a positive pin on the new wording, and the retired-wording
pins were rewritten to assert absence rather than deleted:

  • NO SCHEDULED RELEASER is present — positive pin
  • WAITING ON A RELEASER NOBODY HAS BEEN ASSIGNED TO BE is present — positive pin
  • NO MECHANISM THAT WILL EVER RELEASE IT is gone — negative pin
  • can never CLOSE is gone — negative pin
  • and someone has to want that is present — the kept half, newly pinned

Two reverse-verification legs, each mutating the committed file, proving the mutation reached
disk by counting the marker before and after, then restoring via git checkout HEAD -- and
proving the restore by an empty git diff HEAD plus a sha256 match. No build step exists for
this file — it is a plain .mjs that node runs directly, so there is no dist/ a mutation could
fail to reach.

  • Leg A — put the retired wording back into the emitted string. Marker lines 2 to 1 on disk.
    Self-test exit 1, 2 of 1579 cases failed: "names who is missing, not what is impossible"
    and "the refuted wording is GONE from the row". ⇒ the new pins genuinely read the emitted
    string.
  • Leg B — delete the kept final sentence. Marker lines 2 to 1 on disk. Self-test exit 1, 1
    of 1579 failed
    : "KEEPS the accurate half: the release must be wanted". ⇒ acceptance 2 now
    has a real guard.

Unmutated: exit 0, 1579 cases pass.

⛔ Why this cannot land as-is — the blocker

scripts/pm/check-half-states.mjs in this repo is a byte-pinned verbatim port of
objectstack-ai/objectstack:scripts/pm/check-half-states.mjs, held at
scripts/upstream-port-pin.json (ref bf10debd5) modulo 11 declared divergences.
check:upstream-port-parity verifies it by reversing those divergences and comparing SHA-256.

Measured, both sides counted on this branch:

  • on the unedited base file the gate is green"byte-identical ... modulo 11 declared
    divergences"
    , exit 0;
  • with this change it is red — exit 1, "reconstruction does not match the pinned upstream
    blob"
    .

⇒ the drift is this change's, not pre-existing.

The defect is upstream. objectstack origin/main (32a32143036f34cab05772af3982384acd2a522f)
still carries all of the retired wording — 10 matching lines, at its lines 537-538, 5987,
6096-6099, 24443, 24467, 24491, 24495. The same six sites exist there verbatim.

The three routes, and why the obvious one is wrong:

  1. Declare 6 new divergences here. Fastest, and I did not take it. All 11 existing
    divergences are objectui-specific adaptations (the sweep target repo, an objectui-only
    page-window knob and its self-test rows). None is a correction of a shared defect, and none
    could be: the gate's own header rules that "the divergences are a checklist, not a licence"
    and that "the set is meant to SHRINK". A divergence whose why reads "upstream is wrong"
    is drift written down rather than drift decided — and it would leave the false sentence live
    in objectstack, where the same sweeper runs, which is the whole reason this card is p2.
  2. Fix upstream, then re-sync this pin. Correct, but the re-sync is its own large card: this
    port is ~11,000 lines behind (13,103 here vs 24,443 upstream), and --resync rewrites the
    ported file wholesale.
  3. Fix upstream, leave this stale copy alone, and let the corrected wording arrive here with
    whatever re-sync eventually happens. objectui#9317 then closes as fixed-at-the-producer.

My recommendation is 3, falling back to 2 if the port re-sync is wanted anyway. The
commit on this branch is the finished, tested patch, and it applies to the same six sites
upstream.

⛔ No upstream card exists for this yet — checked with a dedupe search whose control hit (24
check-half-states cards returned in objectstack, none about H26's wording). Filing it is the
PM's call, not mine: this seat holds a claim on objectui#9317 only, and opening work in
objectstack under a claim it does not hold would collide with that repo's own seats.

Downstream — named, not touched

Triage acceptance 5: ⛔ objectui#2231 and objectui#2890 are the domain:spec seat's cards and
are untouched here. Naming them so that seat can dispose of them: comment 5591833377 on
objectui#2231 quotes H26 verbatim as "This card's unlock predicate can never fire", and
objectui#2890 mirrors it. Both now rest on a premise this branch retires. Neither card is
addressed by this pull request and neither should be closed by it.

Checks run

check verdict
node scripts/pm/check-half-states.mjs --self-test exit 0 — 1579 cases pass
pnpm type-check:scripts exit 0 (the file is in that program — --listFiles confirms)
pnpm check:control-bytes exit 0 — 7561 tracked text files scanned
node scripts/check-changeset-presence.mjs exit 0 — nothing owed; the empty-frontmatter changeset declares it
pnpm changeset:check exit 0
vitest on the 4 pin tests reading this file 164 pass, 2 fail — both the port-parity blocker above
pnpm check:upstream-port-parity exit 1 — the blocker

🤖 Generated with Claude Code

https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr


Generated by Claude Code

H26 asserted that `pm:on-hold` and `needs-user-decision` are "by definition
states a card sits in WHILE OPEN", so a `pm:blocked` card waiting on one had
"NO MECHANISM THAT WILL EVER RELEASE IT". That was asserted, never counted,
and counting refutes it: re-derived on this branch (objectui, 2026-09-13, REST
`/issues?labels=<L>&state=<S>&per_page=100`, pull requests excluded, the
population being every issue in this repository carrying the label) —
`pm:on-hold` 62 open / 7 closed (6 completed, 1 not_planned),
`needs-user-decision` 3 open / 3 closed (3 completed), control `pm:blocked`
100 open / 7 closed. Nine of the ten measured closures are `completed`: the
hold lifted and the work finished, which is exactly the release the row said
could not exist.

The row now says the wait has NO SCHEDULED RELEASER — nobody has been assigned
to be one — and keeps its accurate final sentence verbatim: the release has to
come from the target's own state changing and someone has to want that.

Six sites move together, not four: the header docblock, the #11219 rationale,
the `INDEFINITE_TARGET_LABELS` jsdoc, the resolution-map rationale (its "can
never close" is split across two lines, so a line-oriented grep misses it), the
emitted string, and the `H26:` self-test. The self-test gains a positive pin on
the new wording plus negative pins that the retired wording is gone — without
the positive pin, green could not tell "fixed it" from "deleted the assertion
along with the sentence it named" — and a new pin on the kept final sentence so
a later rewrite cannot quietly take it with the retired half.

⚠️ This file is a byte-pinned port of objectstack's copy, so
`check:upstream-port-parity` goes RED on this change. See the PR body: the
defect is upstream and this must not land by declaring new divergences.

Refs: objectui#9317

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants