Uh oh!
There was an error while loading. Please reload this page.
Rank the half-state anchor trim by row family, and make every family legible - #14071
Merged
Conversation
…very family legible Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Msg17tAHJ3jVTYFgHydCm2
…ervation Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Msg17tAHJ3jVTYFgHydCm2
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Msg17tAHJ3jVTYFgHydCm2
This was referenced Sep 1, 2026
os-sam
marked this pull request as ready for review
September 1, 2026 02:56
os-sam
enabled auto-merge
September 1, 2026 02:56
os-sam
commented
Sep 1, 2026
Collaborator
Provenance — flipped ready and armed auto-merge by the dispatching seat (skills-lane PM, session Generated by Claude Code |
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 freeto 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#13947
Verified at HEAD
0e42227db(one file:scripts/pm/check-half-states.mjs, +574 / −6).The defect, in triage's words
「族内按重要性裁,族外按运气裁」 — this file already carries a whole rank of per-family ceilings (
BLOCKING_DEPENDENT_LIST_CAP,H19_TARGET_LIST_CAP,H20_BRANCH_LIST_CAP,H36_SAMPLE_PATHS,H37_MEMBER_LIST_CAP,H17_INDEX_ROW_CAP,H40_ROW_CAP), and every one of them answers which of this family's rows matter most. The body trim answered a different question — which rows happened to be laid out first — and dropped 157 of 231 findings on the measured run.Premise re-checked on
origin/mainbefore writing a line, and it holds. The flat positional trim is still the live behaviour (renderMarkdown, theforloop overrowsbreaking onMARKDOWN_BODY_BUDGET). #13964's H40 arrived as a reserved section precisely to route around this, and its own header says so — that reservation and its unconditional summary clause are untouched here, and the#13947cases it left behind still pass verbatim.What lands
1. A row-family registry and an explicit priority table —
HALF_STATE_FAMILY_BANDS(the five bands, each carrying the question it answers) andHALF_STATE_FAMILY_BAND(code to band), sitting together above the renderer.renderMarkdown's sort gains one key between the existing bands and the card number:The two existing reservations are untouched by design: an UNJUDGED row is a gap in what was read, and #11218's reservation must survive this change rather than be re-litigated by it. Within one family the issue-number order is preserved, so the list is still stable run to run and diffable in the anchor's edit history.
gateH31H35unregisteredstallH4H12H16H19H20H26H27H28H32H33H36H38stateH1H2H3H7H8H9H10H13H18H21H23H24H25H29H30H34H37inventoryH5H6H11H14H15H22gateis H31's own header (「闸门被剥不是红灯是放行」 — 「被剥」 and 「从未挂过」 are indistinguishable in the evidence, and H35 reads the event behind that state);inventoryis triage's own examples of the class gate rows outrank (H14 / H22 / H5);stallis the class where no later sweep frees the card.2. An unconditional per-family ledger —
familyLedger+renderFamilyLedger, a first-class section rendered below the findings and reserved out of the budget exactly as the H17 index, the H39 census and the H40 section are. Ordering alone cannot fix this card: it moves which rows are lost, never whether their loss is readable. The load-bearing half is the closing sentence, which resolves the H31 acceptance test in words:computedandrendered, whether or not the trim left any of it in the body;Computed 0 row(s) this sweepline;An unregistered code is flagged in the table, called out beside it, and sorted just below the gate band — an unknown severity is protected from the trim rather than sacrificed to it (#4690's direction), and the flag makes that protection temporary by construction.
3. The trim keeps announcing itself. This is a legibility fix, not a silent-truncation fix. The omission notice, its wording, its run-log pointer and the three self-tests protecting it are unchanged; new cases assert the notice still fires on the severity-ordered body and beside the ledger.
4. A registry-coverage gate that cannot go stale.
familyRegistryCoveragereads this file's own source for the codes the sweep actually pushes and compares them with the registry — the AGENTS.md source-scan discipline (a detector with no dependencies cannot itself fail to resolve). A family added without a band fails--self-test, rather than inheriting one silently.Body-size arithmetic
The ledger's declared ceiling is
FAMILY_LEDGER_WORST_CASE_BYTES = 6000:FAMILY_LEDGER_ROW_CAP(64) × ~48 B ≈ 3.1 KBFAMILY_LEDGER_CALLOUT_CAP(12) × ~26 B + proseFAMILY_LEDGER_CALLOUT_CAP(12) × ~8 B + proseBuilt and measured, not claimed: 2,285 B with all 37 registered families carrying 999 rows each; 3,754 B with enough unregistered codes on top to reach the row cap. Both are pinned by self-test cases that construct the worst case. 6,000 is under an eighth of
MARKDOWN_BODY_BUDGET(60,000), and because the ledger is reserved out of that budget the 5,536-byte headroom up toISSUE_BODY_LIMIT(65,536) is untouched by it.familyLedgerReservationcomputes the run-in-hand upper bound —rendered = 0(longest callout) plus the exact digit slack, since0 ≤ rendered ≤ computedbounds the column's width — andrenderMarkdownsubtracts it before laying out a single finding row. A self-test drives everyshownvalue from 0 to the row count and asserts the render fits the bound; on a 58-row fixture the bound is 4 bytes above the observed worst case.Before / after on the live board
Measured by running the real sweep from this container (
node scripts/pm/check-half-states.mjs, exit 0, 2026-09-01), then rendering that identical 247-finding corpus throughorigin/main's renderer and this branch's:origin/mainH35, computed 2)On
origin/mainfive computed families —H1(1),H13(2),H23(1),H35(2),H36(5) — rendered zero rows and were, from the page, indistinguishable from families that found nothing.H35is a gate family: a gate label removed with no matching review-chain evidence, twice, invisible. On this branch everygateandstallfamily renders in full (H352/2,H45/5,H1913/13,H202/2,H2612/12,H281/1,H365/5,H382/2) and all 22 computed families carry an exactcomputed/renderedpair.The honest trade, stated rather than buried: fewer rows fit (47 vs 73, because the surviving high-band rows are longer and the ledger costs ~2.5 KB), so the announced omission count rises. That is the card's own framing — the defect was never "too few rows", it was 「说了丢多少、没说丢的是谁」. What changes is that no finding is now lost unaccountably, and the rows that do survive are the ones whose absence reads as a green light.
Sequencing
Comment 5482734531's constraint is met: sections and families are first-class in the renderer.
renderFamilyLedgeris a section renderer of the same shape asrenderDanglingReferences/renderTriggerIndex/renderClosedResidueCensus, composed into the same reserved block, so the clause-② live-sweep wiring can take its own section without inheriting the flat trim. That wiring is not in this PR (#13922and#13944are not addressed here).Verification
Self-test: 1,951 cases before, 2,017 after (+66),
node scripts/pm/check-half-states.mjs --self-testexit 0. Every pre-existing case passes unchanged.Ablation — three legs, each proving the new cases can fail. Mutation confirmed on disk by occurrence count before each run; restore proved by blob hash equal to the HEAD blob and an empty
git diff HEAD, with an absolute-pathtrapon EXIT/INT/TERM:renderMarkdownH31from the registryLeg A also caught a real vacuity in a case I had written. Asserting that the gate row's
indexOfis less than the inventory row's passes when the row was trimmed away entirely, becauseindexOfanswers minus one and minus one is less than everything — so the case stayed green on exactly the regression it existed to catch. Repaired in0e42227dbby requiring the index to be positive as well, with the reason recorded beside it.Gate union — derived at HEAD with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands(17 path-derived + 2 convention-triggered, because this diff edits a gate script). Exit codes captured by redirect before any pipe:Two gates in that family are NOT MEASURED locally, by their own printed verdicts, not by my reading:
node scripts/check-partof-closing-keyword.mjsexits 2 withNOT WIRED — neither PR_BODY nor PR_NUMBER is set … This is a wiring or usage failure, NOT a verdict. Its measurable half,pnpm check:partof-closing-keyword(28 cases), is green.node scripts/check-test-completeness.mjsexits 3 withthe local reading for this gate is NOT MEASURED. ⛔ It is not a red, and there is nothing here to fix.Repo-wide ESLint ran in full — no narrowing to declare.
pnpm lint(eslint . --no-inline-config) exit 0, 70 s under the shared verify lock.check:pm-clause2-carriers(64 cases) andcheck:stall-guard-headroom(32 assertions) are run explicitly because they import from the edited file and CI schedules them on every PR.Not in scope
skip-changesetapplied additively and read back..github/workflows/half-state-patrol.ymlis untouched; the renderer change did not require it.Generated by Claude Code