Uh oh!
There was an error while loading. Please reload this page.
fix(plugin-detail): give record:path one stage classification both rows read - #6015
Merged
yinlianghui merged 1 commit intoAug 24, 2026
Merged
Conversation
…ws read The desktop and mobile rows rendered the same stages[] and each derived its own `terminal` from it, so one stage of one record could paint — and, since the accessible name is derived from the same value, announce — two different ways chosen by viewport width alone. They diverged on two axes. Mid-path goal: WON_TOKENS matches the ordinary word 完成, so 草稿 → 完成 → 已归档 classified index 1 as won; desktop declined it (not the last forward stage) while mobile marked it the goal. Lost slice: desktop hardcoded terminal: 'lost' on every member of its positionally defined alt group (stages.slice(firstLostIdx)) while mobile classified each stage on its own, so a plain stage after a lost one announced closed lost on one row and plain on the other. Both rows now index a single stageTerminals array computed once: lost is a property of the stage, won is the goal terminus and so is the last forward stage or nothing, and positional grouping stays a layout concern. Narrowed on both axes and never widened — no stage gains a terminal on either row that it did not already carry there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSoz9uGhaaSgiq3hshtN7L
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
This was referenced Aug 24, 2026
yinlianghui
marked this pull request as ready for review
August 24, 2026 13:28
Uh oh!
There was an error while loading. Please reload this page.
yinlianghui
deleted the
claude/issue-5998-record-path-won-classification
branch
August 24, 2026 13:40
This was referenced Aug 24, 2026
Merged
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#5998
record:pathdraws a desktop row (hidden sm:flex) and a mobile row (flex sm:hidden) from the samestages[], and each derived its ownterminalclassification from that array.renderStagehands the sameterminaltorailClassand — since #5957 — tostageAriaLabel, so any disagreement surfaced in the paint and in the accessible name at once: one stage of one record, described two ways, chosen by nothing but the width of the window.The fix is not "make the two rows agree". Two independently-derived classifications that happen to agree leave the defect one edit away. Both rows now index one
stageTerminalsarray, computed once.Premise re-measured on the merge-base
Merge-base
11d3ab999(after PR #6000, which landed #5956 + #5957 on this exact file today). All four line numbers the dispatch quoted hold with no delta:WON_TOKENSat:107,stageKindsat:115,forwardKindsat:123, desktopisWonTerminusat:264/terminal:at:269, mobileconst kindat:328/terminal: kindat:336. Theterminal→railClass+stageAriaLabelcoupling #5957 introduced is intact, so unifying the classification fixes paint and announcement together rather than separately — verified by the accessible-name assertions in the new suite.Two axes, not one
1. Mid-path goal (the axis the card names).
WON_TOKENSmatches完成, an ordinary mid-path word rather than a Salesforce-styleclosed_wonvalue.草稿 → 完成 → 已归档classifies index 1 aswonwhilelastis 2. Desktop declined it (idx === last); mobile marked itbg-emerald-500/30and announcedgoal stage, not reached.2. The lost slice (the axis the card does NOT name — measured, and live). Desktop renders
stages.slice(firstLostIdx)as a separated alt group and hardcodedterminal: 'lost'on every member of that positionally-defined group, while mobile classified each stage on its own:草稿 → 失败 → 已归档已归档'lost'(destructive, "closed lost")undefined(plain)undefined草稿 → 失败 → 完成完成'lost''won'undefinedThe second row of that table is the sharpest form: the two rows disagreed on the value, not merely on whether one was present. This is the same defect and the same fix, so it is resolved here — flagged rather than folded in silently, per the dispatch.
The rule the unified array encodes
lostis a property of the stage itself.wonis the goal terminus, so it is the last forward stage or it is nothing.This is the dispatch's lean (reading 1) and it is conservative on both axes: it can only ever stop marking a stage as a terminus, never start. No stage gains a
terminalon either row that it did not already carry on that row. Nothing in the repo contradicted the lean — no existing test places a stage after alostone or pins a mid-pathwon, so mobile's behaviour was incidental rather than deliberate (checked across every consumer ofdata-stage-terminal).Verification
packages/plugin-detail/src/renderers/__tests__/record-path.crossRowClassification.test.tsx(6 cases). The pin is cross-row: for every stage, desktop and mobile must report the samedata-stage-terminal,data-stage-stateand accessible name.MID_PATH_WON(草稿 → 完成 → 已归档) and the counter-probeWON_LAST(草稿 → 已归档 → 完成) carry the same three stages and differ only in where完成sits. A fixture whosewonstage happens to sit last cannot distinguish the two readings and goes green under either, so the load-bearing case puts it mid-path; the counter-probe's green proves the fix is "paint the goal in one place" and not "never paint a goal", and — because it is a permutation of the same labels — provesWON_TOKENSstill fires on完成, so the mid-path result is a positional decision rather than the heuristic failing to match.Reverse verification, direction predicted before running, run under
trap … EXIT INT TERM, each mutation proved on disk by grepping the injected text and separately the removed text (an editor's exit code proves nothing on a zero-hit anchor):stageKinds[idx]: predicted red on the mid-path case and onwon-after-lost. Observed2 failed | 4 passed, exactly those two.terminal: 'lost': predicted red on both lost-axis cases. Observed2 failed | 4 passed, exactly those two.git diff HEAD --statempty after each restore, injected text absent, original text present.No ablation needed a rebuild: this suite imports
../record-path(this package's own source) and@object-ui/react/@object-ui/i18nthrough the rootvitest.config.mtsalias table, so nothing resolves through anydist/.Gates, at
fdc8aecd0pnpm --filter @object-ui/plugin-detail type-check0(afterpnpm --filter '@object-ui/plugin-detail^...' build— the first run's 17TS2307 Cannot find module '@object-ui/*'errors were staledist/*.d.ts, not this change)pnpm exec vitest run packages/plugin-detail/src(root form)0—Test Files 100 passed (100),Tests 938 passed (938)pnpm exec eslint --no-inline-configon the two changed source files0— new test fileerrors 0 warnings 0;record-path.tsxerrors 0 warnings 15, delta vs merge-base 0/0 (the merge-base copy of the same file lints to the identical{no-explicit-any: 13, exhaustive-deps: 1, preserve-manual-memoization: 1}, all in the untouched preamble and the twoschema.aria as anycasts)No i18n key added, renamed or moved —
detail.pathStageWonUpcomingand the rest are unchanged, sopackages/i18n/src/locales/**is untouched (#4730 holds it). Changeset:.changeset/5998-record-path-one-classification.md.One question left open, not implemented
classify()reacheswontwo ways — theWON_TOKENSheuristic and an explicitterminal: 'won'on the stage — and this PR applies the last-forward-stage restriction to both. An author who wroteterminal: 'won'on a mid-path stage said so deliberately, while the regex guessed; applying the restriction to the heuristic only is a defensible third option. It is not implemented here because it is a decision, not a dev call, and because it would be the one direction that widens rather than narrows. Note that desktop already ignored an explicit mid-pathterminal: 'won'before this PR, so nothing new is suppressed relative to the row that was already the stricter of the two. Details in the dev report on #5998.Generated by Claude Code
Generated by Claude Code