Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

Dashboard table: numeric measure columns sort descending on first click #5845

Closed

Description

@os-zhuang

Dashboard table: numeric measure columns sort descending on first click

Ruling

Maintainer, verbatim (未译, in-session 2026-08-23): 「我觉得合理的需求都应该开发」 — ruling on the open question #5827's dev flagged and shipped as option A (asc-first uniformly). This card flips numeric measure columns to option B.

Why it is reasonable (the four-axis case, condensed)

Contract

Queued serially behind nothing; #5834 merged (62c0fa1). The totals-row card is queued behind THIS one (same file).

Activity

  1. self-assigned this
    on Aug 23, 2026
  2. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    ContributorAuthor

    Claim: direct-dispatch (hotcrm seat acting cross-repo under maintainer instruction)
    Session: session_61f28fb9-8e31-4a6f-b4d8-10f749a092d2
    Branch: claude/issue-5845-measure-desc-first
    Worktree: objectui-issue-5845
    File surface: packages/plugin-dashboard/src/DatasetWidget.tsx + __tests__/DatasetWidget.tablePolish.test.tsx (stop on breach; explain in the report)
    Container & model: S(判断面在既有语义上,按 M 待遇), mode:subagent, model: opus — Clause-②: no.
    Serial constraints cleared: #5834 merged (62c0fa1); the totals-row follow-up is queued BEHIND this card (same file) and is not in flight. No other open PR touches DatasetWidget.tsx (REST pulls listing checked at claim time).

    Authorization — maintainer ruling, verbatim (未译): 「我觉得合理的需求都应该开发」

  3. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    ContributorAuthor
    {"issue": 5845, "status": "done", "branch": "claude/issue-5845-measure-desc-first", "pr": "https://github.com/objectstack-ai/objectui/pull/5848", "premise_still_valid": true, "summary": "Numeric MEASURE columns in the flat dataset `table` widget now cycle descending -> ascending -> the dataset's own order; dimension columns and non-numeric measures keep ascending -> descending -> dataset order. The predicate is #5834's `numericColumns` set (a measure, or a measure's comparison column, whose every non-null value is a number) - the same set that decides right-alignment - so first-click direction follows the column's ROLE, not 'it looks like digits': a digit-keyed dimension (a year) still starts ascending and so does a min()/max() over a text field. PM MECHANISM ASSUMPTION, TESTED: 'two lines in cycleSort' is CONFINED correctly - nothing else in the file assumes asc-first, because aria-sort, the ChevronUp/ChevronDown indicator and the comparator all read activeSort.dir (the direction APPLIED, never the position in the cycle), so a desc-first initial state renders and announces itself truthfully with zero further change, and #5834's blanks-last arm is settled BEFORE the direction is applied and is therefore direction-agnostic by construction. But a literal two-line edit would have SHIPPED A BUG: the old cycle spelled both directions as literals (asc -> desc -> null), so swapping only the first yields desc -> desc -> null and a measure column that can never be sorted ascending. The middle step is now written as 'whatever firstDir is not', giving both column kinds all three states, and a column switch starts the new column at ITS OWN first direction rather than inheriting. One consequence named in the code: the descending arm is now what a measure's FIRST click runs, so #5834's negate-trap moved from the second interaction to the very first - a test pins blanks-last on that first click. Scope held: #5846 (totals row) untouched and the file not restructured for it.", "tests": "All from the repo root in a dedicated worktree; union re-run AFTER the final commit, at 2d4c3609b. Every exit code captured by redirecting to a file first, never read after a pipe. `pnpm --filter '@object-ui/plugin-dashboard^...' build` exit 0 (dependency closure). `pnpm --filter @object-ui/plugin-dashboard type-check` exit 0, script echoed ('tsc --noEmit && tsc -p tsconfig.test.json'), no diagnostics. `pnpm --filter @object-ui/plugin-dashboard lint` exit 0, verdict line '369 problems (0 errors, 369 warnings)' - the IDENTICAL count #5834 reported, so this diff adds no warning. `pnpm exec vitest run packages/plugin-dashboard/` exit 0, 'Test Files 77 passed (77)' / 'Tests 726 passed (726)'; the touched file itself went 11 -> 14 tests ('Tests 14 passed (14)'). NOT DONE, stated plainly: no separate baseline run on BASE d40d2953e - origin/main moved since #5834's 76/693 reading, so the 'nothing pre-existing moved' claim rests on the file-level 11 -> 14 delta and a green package suite, not on a re-measured baseline. check-changeset-presence.mjs exit 0 ('2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'), check-changeset-no-major.mjs exit 0 ('No changeset declares a `major` bump.'), check-control-bytes.mjs exit 0 ('OK (scanned 4868 tracked text file(s); skipped 85 binary)'), check:i18n-keys exit 0 ('Every in-scope call-site key resolves against the en pack (2928 keys)'). REVERSE VERIFICATION - direction stated BEFORE the run: reverting ONLY DatasetWidget.tsx to origin/main turns 6 of 14 red (the three #5845 cases plus #5827's 'new column at its own first direction', 'sorts numerically' and 'CSV export') and leaves the 8 alignment/dimension-cycle/blank-bucket/drill/hover cases green, since those are exactly the half the ruling does not touch. OBSERVED: 'Tests 6 failed | 8 passed (14)' and the six named failures are the six predicted. Mutation confirmed ON DISK by anchored greps, not by an editor exit code: `firstDir` 3 -> 0 and the deleted origin/main spelling `prev.dir === 'asc'` 0 -> 1. Restore leg confirmed the same way (3 / 0) plus an empty `git status --porcelain`, re-ran green at 14/14. No rebuild stands between edit and run - the suite imports the component by relative source path (../DatasetWidget), not through a package exports->dist hop - and the ablation script carried `trap ... EXIT INT TERM`, which did fire. NOT VERIFIED IN A BROWSER (same limit #5834 declared): component tests over the produced DOM, not a console rendering HotCRM's executive_dashboard. DECLARED NARROWINGS: the shared lock is inoperable on this host (os-verify-lock.sh --status prints 'CANNOT OPERATE THIS LOCK ... a stock macOS does not ship flock'), so commands ran directly rather than through the entry point; repo-wide check:* scanning left to CI; eslint was also run targeted at the two changed files (0 errors) in addition to the package-level run. objectui has no scripts/pm/dispatch-gates.mjs - the gate list above was derived by hand from this repo's package.json check:* scripts and .github/workflows, and objectstack's copy of that script was deliberately NOT pointed at objectui paths.", "open_questions": [], "out_of_scope_findings": []}
  4. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    ContributorAuthor

    PM review — ACCEPT. PR #5848. The "two-line change" premise was half false, and the falsification is the value of this run.

    The literal two-line edit would have shipped a bug

    The sibling dev's estimate (which my dispatch carried) assumed swapping the first direction sufficed. Measured: the old cycle spelled both directions as literals (asc → desc → null), so swapping only the first yields desc → desc → null — a measure column that can never be sorted ascending, green on a naive "first click is descending" test. The middle step is now "whatever firstDir is not", verified in the diff; both column kinds get all three states, and a column switch starts the new column at its own first direction instead of inheriting the previous column's.

    Two structural facts made the rest clean, both verified claims: aria-sort, the indicator and the comparator all read the applied direction (never the cycle position), so a desc-first initial state announces itself truthfully with zero further change; and #5834's blanks-last arm was settled before direction is applied, so it is direction-agnostic by construction — with a new test pinning blanks-last on the first click, where the negate-trap now lives.

    Verification

    Predicted 6 red / 8 green under ablation; observed exactly those six, and the eight greens are precisely the half the ruling does not touch (alignment, dimension cycle, blank bucket, drill pairing, hover). On-disk mutation confirmation both legs; 14/14 restored. Lint count identical to #5834's (369), so zero new warnings. Honestly declared: no re-measured baseline on moved main (file-level delta + green package suite carry the claim), and no browser verification — the PM runs the visual half in the overlay, as with the previous two cards.

    Disposition

    Ready + merge on CI green. #5846 (totals row, same file) dispatches after this lands — scope was held, the file was not restructured for it.

  5. removed their assignment
    on Aug 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions