pipeline dash: render the machine from emitted stateDescriptors, and drop the deleted ai:blocked-deploy from the frozen table - #166
Conversation
The consumer half of issue-pr-cron#130 (rain-org-health#164): a snapshot
carrying stateDescriptors IS the machine — owner grouping, per-state box
(key/label/act/kind), occupancy from each descriptor's declared source
({lane} cell with sparse-absent => 0, or {counts, items, itemsAreIssues}),
history series from hist with retired-key samples folded per the
descriptor's own histFold, descriptor order as render order. The
hand-written STATES table and HIST_FOLD survive only as the frozen
fallback for descriptor-less snapshots, the same posture as the legacy
no-lanes branch.
Conservation: every lanes cell and every counted top-level array must be
claimed by exactly one descriptor; unclaimed (and double-claimed)
occupancy renders as a loud --crit defect band in words — the invariant
that would have made the blocked-on re-lane scream instead of hiding 17
PRs. Malformed descriptors are reported the same way, never silently
dropped, and a descriptor's kind is clamped so snapshot content cannot
smuggle a meaningful class onto a box.
The live snapshot carries no stateDescriptors until the producer side of
issue-pr-cron#130 lands, and this render is a behavioral no-op on such
snapshots, so it can merge first.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…state-descriptors # Conflicts: # site/pipeline.html
…pancy claim The descHq human states now carry the zero-count state BETWEEN two non-zero ones, so a mutant that sorts boxes by size cannot pass the order pin by coincidence; and a descriptor whose items array is named differently from its counts key is pinned to claim BOTH, so the conservation sweep raises no spurious defect on a conserved snapshot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Found by the adversarial mutation pass: Number(cell && cell.count) is equivalent to the real coercion for a sparse-ABSENT cell (Number(null) is 0), so only a cell that exists with a junk or missing count discriminates the dropped `|| 0` — and no descriptor-path test carried that shape. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 2026-08-06 clarification on issue-pr-cron#130: lanes cells stay strictly claimed (zero exceptions); on the counts side every counts key must be claimed by exactly one descriptor through the keys it reads (its occupancy counts source or its hist mirror), outside the four named frozen-legacy keys — the non-state metrics totalProducerPrs / openIssues / archivedRepoPrs and the legacy duplicate closeCandidateIssues — and a counts-source descriptor's declared counts/items keys must resolve in the snapshot or the band reports them. Replaces the counted-top-level-array sweep, which the counts-key sweep subsumes. Retired states arrive as residue descriptors emitted only while nonzero, so the consumer keeps zero retired-detection: pinned by the new residue pair test (present renders with its "(retired #n)" label; drained renders nothing and nothing screams). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WalkthroughThe pipeline dashboard now renders machine state from validated ChangesPipeline descriptor rendering
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Snapshot
participant PipelineRenderer
participant ConservationDefectPanel
Snapshot->>PipelineRenderer: provide stateDescriptors and inventory
PipelineRenderer->>PipelineRenderer: validate descriptors and occupancy claims
PipelineRenderer->>ConservationDefectPanel: render conservation defects when claims are invalid
Possibly related issues
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…state-descriptors
Master gained rain-org-health#165 after this branch cut: the frozen hand table now files ai:blocked-on under the VETTER reading vet-lifecycle (with a staleLane read of the pre-re-key producer-blocked cell — a fallback-branch-only affordance). The frozen-fallback pin freezes whatever master's table is, so its expected key order moves blocked-on into the vetter group. The descriptor path is untouched: it reads only each descriptor's declared lane, and a stale cell on a descriptor snapshot is conservation-defect territory, never a silent fallback. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The live tool still emits drained retired counts keys at 0 (blockedInfra, relink, humanReject) while the kept-while-nonzero contract drops only the DESCRIPTORS, so the sweep as-was would paint a permanent false defect band on the first healthy descriptor snapshot. An unclaimed key holding nothing hides nothing: n === 0 with 0 held is skipped, in both the lanes sweep and the counts sweep. A double claim is structural — the same inventory wired twice — and stays a defect at any count, zero included. Mutation pass re-run on the merged tree: 23/23 killed, including the two new edges (zero-skip removed → false defects; zero-skip overbroad → zero-held double claims silenced). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A descriptor READS its histFold keys — that is where its series draws the absorbed retirees' samples from — so those counts keys are its claim too, deduped alongside the occupancy counts source and hist. Without it, the live shape paints a FALSE defect: ai:reject folds humanReject/relink while the residue rows carry no hist of their own (the successor draws the past, so the same history is not rendered twice), so a nonzero humanReject would be claimed by nobody even though its lane cell IS claimed and its history IS drawn. Masked today only because all three retired counts sit at 0 and the zero-held skip swallows it; it fires the moment any absorbed-retiree residue reappears. The invariant stays honest in both directions: a fold key must not also be a live row's hist (the producer side is held to that), so a key claimed as both still reads as the double claim it is. Suite 229 green; mutation table re-run at 25/25 killed, including the two new edges (fold claim dropped -> false defects; fold claim widened to blanket amnesty -> stranded retired keys hidden). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/dashboard.test.js`:
- Around line 3143-3169: Add a dashboard rendering test near the existing FSM
descriptor cases using a script-like payload for descriptor key, label, and act,
plus unclaimed lane and counts keys in the snapshot. Render through fsmBox, then
assert the payload appears in text, no img element is created, and the relevant
fsm-defect row exists and also contains the payload as text.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 5283af3c-28d7-49f7-9826-937f31285af5
📒 Files selected for processing (2)
site/pipeline.htmltest/dashboard.test.js
…rted A state key is the panel's IDENTITY for a state — the box's data-t, and the register/itemsFor map key the click-to-expand reads — so two descriptors sharing one key let the second's registration OVERWRITE the first's: two boxes on screen, both opening the SECOND one's list, the first box's inventory unreachable. That is #141's exact failure, and neither claim check saw it: with different occupancy sources the two claims are different ids, so both read as singly claimed. A repeat now renders NO state and is reported by key and index, in the malformed entry's wording, and — like a malformed entry — its claim is never registered, so the sweep additionally names the cell or counts key it meant to claim. FIRST occurrence wins: array order is render order. Two pre-existing double-claim tests manufactured their double claim by repeating a key, which is now the more specific defect; both are rebuilt on DISTINCT keys colliding on a counts id — the genuine remaining double-claim path, since a lane claim id embeds the claiming state's own key and so can only collide via a repeat. Suite 231 green; mutation table 27/27 killed, including the two new edges (guard dropped -> silent mis-wire; last-wins -> the repeat overwrites the first's registration). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… fixes SHOULD-FIX — the page holds TWO numbers for a lane state and never compared them: the lane cell it RENDERS, and the counts key its SERIES is drawn from. The tool computes those two ways (issue-pr-cron#228), so the live witness the moment the producer lands is ai:ready rendering 0, dimmed, under a sparkline sitting at 23 — with every claim check passing, because each key is claimed exactly once. The page is the only place the two meet, so it now compares them and reports a divergence naming both numbers and which one is on screen. It does not guess which is right and it does not drop the claim: every lane state's hist mirrors a counts key, so dropping it would paint false defects across a healthy snapshot. Also from review: - the frozen-legacy exception no longer suppresses DOUBLE claims on those four keys — it licenses a key going unclaimed, never the same inventory wired twice (two descriptors both drawing openIssues would render the population as two state series); - a descriptor's items array is claimed, so two descriptors naming one array is reported rather than rendering two boxes onto one list; - an unclaimed lane cell's held inventory is max(count, prs.length), so a cell carrying 17 PRs behind a dropped or non-numeric count is no longer scored 0 and skipped by the zero-held carve-out; - .fd-li and .sk wrap long unbroken tokens instead of overflowing, since both quote untrusted snapshot strings. descHq's decoy counts mirrors are now consistent with their cells: a mirror contradicting its cell is itself a reported defect, so the wrong-source read is discriminated by the divergence test instead. Prototype-shaped strings (__proto__, constructor) as key, counts, items and lane name are pinned as ordinary data, built through JSON.parse (the only way to get a genuine own __proto__ key, and how the page really receives the snapshot). Suite 237 green; mutation table 32/32 killed, including the five new edges (divergence dropped/inverted, legacy exception suppressing doubles, items double claim dropped, held ignoring prs). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`ai:blocked-deploy` is not a state of the FSM any more (issue-pr-cron#225): no label, no classifier arm, no counts emission, no parking transition. The frozen fallback table still listed it unconditionally, so once the tool stops emitting the lane cell the box renders permanently at zero under Human action, prescribing "resolve deploy" for a machine that no longer exists — the exact thing this file's own comment forbids (rain-org-health#145). Drop it from STATES, from the legacy no-`lanes` branch and from the dual-owner rationale, and add it to RETIRED_NO_SUCCESSOR beside `ai:blocked-infra`: a snapshot still carrying a nonzero count (an old snapshot, or the label reapplied by hand) surfaces as a straggler box whose act is stripping the residue, and zero or absent draws nothing. No HIST_FOLD entry. Nothing absorbed this inventory — `ai:reject` is where the PRs that carried the label now sit, but a reject measures a verdict on the PR's code, not a fact about a deploy, so folding the samples in would fabricate a step in a series that never held that work. The straggler tests are extended over BOTH no-successor retirees rather than duplicated, since it is one mechanism, plus a new pin that two retirees on one snapshot render as two independent boxes with their own lists and counts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@site/pipeline.html`:
- Around line 1022-1025: Update the lane cell scoring logic around laneCount to
detect when cell.count is unset or nonnumeric while cell.prs is populated,
matching the existing count-versus-hist disagreement handling; ensure this
defect is included in the misclaimed sweep. Change the related click-through
label to display the actual cell.prs list length instead of the normalized
count.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 34f448e4-93f3-4b2b-a6bd-8de3014615bb
📒 Files selected for processing (2)
site/pipeline.htmltest/dashboard.test.js
`Number(cell.count) || 0` cannot tell a missing or non-numeric count from a real zero, so a broken count over a populated `prs` rendered 0 while the click expanded onto real PRs — and the sweep could not see it, because a claimed cell leaves `misclaimed` early at n === 1. Same class as the count-vs-hist divergence, one level down: the page holds two numbers for one cell and is the only place they meet. The box now renders the LARGER, so a broken count cannot hide inventory the list proves is there and the number on the box is the number of rows it opens onto; the disagreement is reported naming both numbers and which was rendered. Only checked while the list is non-empty — a count over an EMPTY list is the missing-list case detailBody already reports at the click, not a snapshot defect. Targeted mutants (3, all killed): the check dropped; the check widened to fire on an empty list; the render reading the stated count instead of the larger. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tors' into 2026-08-06-consume-state-descriptors
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/dashboard.test.js`:
- Around line 3725-3771: Run deno fmt on the test block in dashboard.test.js,
ensuring the long stateDescriptors literals and surrounding test code use Deno’s
required formatting without changing test behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: e973be4c-3b04-439a-a5f5-e44b2ffe905b
📒 Files selected for processing (2)
site/pipeline.htmltest/dashboard.test.js
|
Reviewed 8cacfa3: approve — read the diff independently across four rounds and verified the final head. The dashboard now renders the pipeline machine from the tool's emitted |
Closes #167 — the deleted
ai:blocked-deploystate leaves the frozen fallback table (detail below).Closes #164 — the consumer half of rainlanguage/issue-pr-cron#130, built to the ratified schema contract (rainlanguage/issue-pr-cron#130 (comment)) as clarified on 2026-08-06 (rainlanguage/issue-pr-cron#130 (comment)).
The descriptor half depends on rainlanguage/issue-pr-cron#130 producer PR (rainlanguage/issue-pr-cron#223) for live effect, and is a behavioural no-op until then: the live snapshot carries no
stateDescriptors, so it renders the frozen fallback exactly as before. That is why this can merge first.The second change is NOT a no-op, and is the only thing that moves on the live board:
ai:blocked-deployleaves the frozen fallback table, so the box it renders today at a permanent dimmed zero disappears (before/after below).What
When the fetched snapshot carries
stateDescriptors, the machine renders from them and from nothing else:owner(producer|vetter|human) files it under that actor's heading; descriptor order is render order within the group; an actor the tool files no state under draws no empty heading.key/label(the emitted(retired #n)residue suffix rides through),act,kind(clamped to flow|rule|blk so snapshot content can never smuggle a meaningful class likezero/rising/selonto a box).{lane}: count + click-through prs from that lane's cell keyed by the state key, sparse-absent ⇒ 0;{counts, items, itemsAreIssues}: count fromcounts.<key>, click-through from the named top-level array, the flag picking which URL path is tried first. Every box registers its item list at the one wiring point (Four FSM boxes show a count and expand to an empty list — fromCounts never populates laneItems #141's lesson), so click-to-expand, the count==rows invariant, and the missing-list defect reading all hold identically for descriptor states.hist, retired-key samples folded per the descriptor's ownhistFold(an empty list folds nothing; the handHIST_FOLDMap serves only the frozen fallback). Sparklines, 7d trend borders, and the per-actor lead fallback all work unchanged.Conservation (the invariant that would have made the blocked-on drift scream instead of hiding 17 PRs): every
lanescell must be claimed by exactly one descriptor — zero exceptions; everycountskey must be claimed by exactly one descriptor through the keys it reads (occupancycountssource orhistmirror), outside the four named frozen-legacy keys (totalProducerPrs,openIssues,archivedRepoPrs— non-state metrics — andcloseCandidateIssues— the legacy duplicate of claimed inventory); and a counts-source descriptor's declaredcounts/itemskeys must resolve in the snapshot. Violations (unclaimed, double-claimed, unresolved, malformed descriptors, repeated keys) render as a loud--critdefect band in words — never silently ignored. A repeatedkeyrenders no state and is reported by key and index (first occurrence wins; array order is render order), with its claim unregistered so the sweep also names the occupancy it meant to claim — the state key is the box'sdata-tand the register/itemsFor map key, so a repeat would otherwise let the second's registration overwrite the first's and leave a box opening onto another state's list (#141's exact failure, invisible to both claim checks because different occupancy sources produce different claim ids). Cross-check (issue-pr-cron#228): the page holds two numbers for a lane state — the lane cell it RENDERS and thecountskey its SERIES is drawn from — which the tool computes two ways. Every claim check passes when they disagree, so the page compares them and reports a divergence naming both numbers and which is on screen (it does not guess which is right). A descriptor claims every counts key it READS — its occupancycountssource, itshist, and itshistFoldkeys (that is where its series draws the absorbed retirees' samples from, soai:rejectfoldinghumanReject/relinkclaims those keys while the residue rows carry nohistof their own). One deliberate carve-out: an UNCLAIMED key holding 0 is vacuously conserved (nothing is hidden) and raises no defect — the live tool still emits drained retired counts keys at 0 while kept-while-nonzero drops only the descriptors, so flagging zero-held keys would paint a permanent false defect on the first healthy descriptor snapshot; a zero-held double claim is structural and still defects — including on the frozen-legacy keys, which are exempt from unclaimed, never from a double claim. A descriptor'sitemsarray is claimed too, so two descriptors naming one array is reported rather than rendering two boxes onto one list; an unclaimed lane cell's held inventory ismax(count, prs.length), so a cell carrying PRs behind a dropped count is not scored 0 and skipped; and a repeated descriptorkeyrenders no state and is reported.The hand-written
STATEStable (andHIST_FOLD, and #161RETIRED_NO_SUCCESSORstraggler table) survive ONLY as the frozen fallback for descriptor-less snapshots — the same posture as the legacy no-lanesbranch. Master is merged in through #162 AND #165, so the frozen table is the post-#165 shape (vetter-ownedai:blocked-onreadingvet-lifecyclewith itsstaleLaneread — a fallback-branch-only affordance; the descriptor path reads only each descriptor's declared lane, and a stale cell on a descriptor snapshot is conservation-band territory). On a descriptor snapshot a stale retired-state cell surfaces through the conservation band instead of the straggler table.Also in this PR: the deleted
ai:blocked-deploystate leaves the frozen table (#167)ai:blocked-deployis not a state of the FSM any more (rainlanguage/issue-pr-cron#225 deletes the label constant, the classifier arm, the counts emission, the display section, thelabel_metarow and the parking arm; the label definition is gone from every repo that defined it). The frozen table still listed it unconditionally, so the moment the tool stops emitting the lane cell the box renders permanently at zero under Human action, prescribing "resolve deploy" for a machine that no longer exists — the exact thing this file's own comment forbids (#145). It belongs in this PR because this PR is what demotes that table to a frozen fallback, and a descriptor-bearing snapshot never carries the deleted state at all.STATES, from the legacy no-lanesbranch, and from the dual-owner rationale comment (one resolution survives there:ai:blocked-on).RETIRED_NO_SUCCESSORbesideai:blocked-infra, so a snapshot still carrying a nonzero count — an old snapshot, or the label reapplied by hand — surfaces as a straggler box whose act is stripping the residue, instead of vanishing. Zero or absent renders nothing.HIST_FOLDentry. Nothing absorbed this inventory.ai:rejectis where the PRs that carried the label now sit, but a relabel is not an absorption — a reject measures a verdict on the PR's code, never a fact about a deploy — so folding those samples intorejectwould fabricate a step in a series that never held that work. Its samples are drawn nowhere.RETIRED_NO_SUCCESSOR's heading generalised with it: it was scoped to states "whose FSM exit was the run ending", which isai:blocked-infra's exit but not this one (deleted outright). The property that actually governs both — and that drives both the straggler render and the absent fold — is that no surviving state absorbed the inventory, so the comment now states that property and gives each state's exit under it.Tests
nix run .#dashboard-test: 238 passed, 0 failed — 27 descriptor tests, plus the straggler suite extended over BOTH no-successor retirees (one mechanism, not a parallel set) and a new pin that two retirees on one snapshot render as two independent boxes with their own counts and lists.nix develop -c pre-commit run --all-files(CI's static suite) green.Visual evidence
Four renders for #167's change, shot at this head against master. The two descriptor renders further down are fixture-driven (clearly marked) and were shot at the descriptor commits; #167's commit does not touch the descriptor path, so they still hold.
Live BEFORE (master) / AFTER (this head). Both rendered from ONE frozen copy of the live snapshot served locally, so the branch is the only variable. The descriptor half is a no-op here (no
stateDescriptorslive); the whole visible difference is #167's: the dimmedai:blocked-deploy0 / RESOLVE DEPLOY box is gone, and the human group falls from two rows to one. The human total is unchanged at 25 — the box it removes held nothing, which is the point.FIXTURE-DRIVEN — the same snapshot with a nonzero
ai:blocked-deployresidue (count 3 + its three PRs + a history, i.e. an old snapshot or the label reapplied by hand). This is the straggler behaviour, and it is why the state is not simply deleted from the page: before, it is a modeled state with a sparkline and the act "RESOLVE DEPLOY"; after, it is a residue box with the act "STRIP THE LABEL", no sparkline (no series absorbed it), rendered after the modeled states. The human total counts it either way (28), so the inventory never goes missing.FIXTURE-DRIVEN — the live snapshot plus PR 223's actual row table (
human:designownerproducer,"ai:blocked-deploy (retired #162)",ai:blocked-onvetter-owned onvet-lifecycle). The machine renders from descriptors — and the new cross-check catches the REAL disagreement that ships with it:ai:readyrenders 0 (itsvetter-verdictscell is absent, all 23 being un-vetted at head) whilecounts.readysays 23, which is rainlanguage/issue-pr-cron#228:FIXTURE-DRIVEN — re-lane drift on top: the descriptor list still points blocked-on at the old
producer-blockedlane, so the 17 stranded PRs scream (unclaimed cell) alongside the two divergences:The two descriptor-fixture renders above were shot at the descriptor commits and still hold at this head: #167's commit touches only
STATES,RETIRED_NO_SUCCESSOR, the legacy no-lanesbranch and their comments — none of which the descriptor path reads.QA
test/dashboard.test.js— "a lane state whose counts mirror contradicts its rendered cell is a loud defect naming both numbers"; "lane states whose counts mirror agrees draw no divergence defect"; "a frozen-legacy counts key is exempt from unclaimed, never from a DOUBLE claim"; "two descriptors naming the same items array is a defect"; "an unclaimed cell holding PRs with no usable count still screams"; "prototype-shaped keys, counts, items and lane names are ordinary data"; "a repeated descriptor key renders one box and is reported, with the loser's occupancy named unclaimed"; "all-distinct descriptor keys draw no duplicate-key defect"; "a folded retired counts key is claimed by the folding descriptor, nonzero and all"; "a counts key claimed as both a fold and another descriptor's hist is still a double claim"; "zero-held unclaimed occupancy is vacuously conserved; nonzero screams; a zero-held double claim still defects"; "stateDescriptors drive the machine — owner grouping, act, count, and descriptor order"; "descriptor occupancy reads its declared source — lane prs and counts+items alike, itemsAreIssues picking the path"; "a descriptor's histFold folds retired-key samples into its series"; "a descriptor's empty histFold folds nothing — the hand-maintained fallback Map never applies"; "a lane cell no descriptor claims surfaces as a loud defect, never silence"; "a counts key no descriptor claims is a defect; a bare top-level array is not occupancy"; "occupancy claimed by TWO descriptors is a defect too"; "a malformed descriptor renders no state but is reported"; "a descriptor's kind is clamped to the display kinds"; "a descriptor lane cell with a junk count renders 0, never NaN"; "a descriptor claims BOTH its counts key and a differently-named items array"; "a residue descriptor renders while emitted; drained, its absence renders nothing and nothing screams"; "the frozen-legacy counts keys never defect; any other unclaimed counts key does"; "a descriptor whose counts or items source does not resolve is a loud defect"; "a descriptor-less snapshot renders the frozen hand table, defect-free — junk stateDescriptors falls back too"; "an empty stateDescriptors array screams via conservation rather than resurrecting the hand table". Each fails on base — base has no descriptor path, so every descriptor fixture renders the hand table and the exact-key/owner/count/defect assertions fail (the assertions name descriptor-only keys, orders and the.fsm-defectclass, none of which exist on base).site/pipeline.htmlwith the full suite run and the file restored byte-identically (verified by hash and a cleangit status). 16 cover pipeline dash: remove the deleted ai:blocked-deploy state (blocked-infra precedent) #167's change:RETIRED_NO_SUCCESSORdrops theai:blocked-deployentry → residue vanishes silently → killed; drops theai:blocked-infraentry → killed (the sibling is still load-bearing);STATESreintroducesai:blocked-deploy→ the permanent dimmed box returns → killed by the frozen-table pin and the owner-group count; the nonzero guard inverted, and dropped, on BOTH the lanes and legacy branches (4 mutants) → killed by the zero/absent test (a dropped guard is exactly the Dashboard still renders awaiting-re-vet; the state was deleted by issue-pr-cron#128 #145 defect);HIST_FOLDgains ablockedDeployfold, and ablockedInfrafold (2 mutants) → killed by the no-fold history test throughai:reject, the tempting target; straggler loses its legacy counts fallback → killed by the counts-only test; registers no item list, on both branches (2 mutants) → killed by the click-through; act reverted to "resolve deploy" → killed by the act pin; owner filter dropped (residue under every actor) → killed by the one-box-on-the-board assertion; count omitted from the owner total → killed by the total pins; straggler draws a sparkline from the retired series → killed by the no-spark assertions. The 32 descriptor mutants below were re-run in full at this head and all still die: each applied tosite/pipeline.html, full suite run, file restored — all KILLED, zero survivors in the final table (re-run in full at this head). divergence check dropped → a state counted two ways passes in silence → killed by the divergence test; divergence check inverted → killed by 11 tests; frozen-legacy exception moved to also suppress double claims → killed by the legacy-double test; items double-claim sweep dropped → killed by the shared-array test; held ignoresprs.length→ killed by the PRs-behind-no-count test. duplicate-key guard dropped → repeats render twice and mis-wire silently → killed by the repeated-key test; duplicate-key last-wins (the repeat evicts the first from the render) → killed by the same test's first-wins assertions. fold claim dropped → nonzero folded retired keys paint false defects → killed by the fold-claim test; fold claim widened to blanket amnesty (claim every counts key) → stranded retired keys hidden → killed by that test's second half plus 6 others. zero-skip removed → flags zero-held unclaimed keys → killed by the vacuous-conservation test; zero-skip overbroad (if (!held)) → silences zero-held double claims → killed by its structural-defect assertion. defect-band render →if (false)→ killed by the 5 conservation tests (7 failures);seriesFor(p.hist, p.histFold)→seriesFor(p.hist)→ killed by both histFold tests; lane count →Number(c[p.hist])→ killed by the decoy-mirror fixture (lane cell 3 vs counts 99); counts count →Number(c[p.key])→ killed by the two-name test;issue: !!occ.itemsAreIssues→false→ killed by the /issues/ href pin; render order → alphabetical sort → killed by the order pin (fixture deliberately not in count order); owner filter → all-under-human → killed by the group pins;count = Number(cell && cell.count)→ killed by the junk-count test; lane sweep / counts sweep skipped → killed by the unclaimed-cell / unclaimed-key tests;LEGACY_UNCLAIMEDemptied → killed by the frozen-legacy test; hist claim dropped → killed by 5 tests (spurious defects on lane mirrors); counts / items resolution checks dropped → killed by the resolution test; malformed report dropped → killed by the index assertions; kind clamp → any string → killed by the clamp test; descriptor gate → truthy / length-gated → killed by the junk-fallback and empty-array tests; claim counter capped at 1 → killed by the double-claim test; laneregisterdropped → killed by the lane click-through;else if (hasLanes)→ unconditional second render → killed by the exact-key pins (6 failures). Two earlier survivors were fixed by strengthening tests in place (fixture reordered out of count order; the junk-count pin added).Array.isArraygate + the empty/junk tests + the unchanged frozen-fallback branches.STATES, the legacy branch and the dual-owner comment; (b) add it toRETIRED_NO_SUCCESSORso a nonzero count surfaces as a straggler while zero/absent renders nothing; (c) NOHIST_FOLDentry; (d) tests move with the behaviour and a mutation pass proves the straggler surfacing load-bearing; (e) before/after renders. All five covered above — (d) by the 16 pipeline dash: remove the deleted ai:blocked-deploy state (blocked-infra precedent) #167 mutants and the extended straggler suite, (e) by the two render pairs.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes