Skip to content

QA run · dashboards (FULL area) · a86db175 · 2026-08-11 · 6 PASS / 2 PARTIAL / 2 FAIL #7515

Closed

Description

@baozhoutao

Full dashboards area run of the checklist-test skill — all 10 items driven against a live showcase (2 opus subagents, isolated boot each). Labels: qa-run + bug.

Result: 6 PASS · 2 PARTIAL · 2 FAIL. Text-only per RUNNER.md.

Environment — framework a86db175 (PR #7304) · vendored console 09987b68 · showcase seed (10 tasks / 5 statuses / 4 priorities / 14 accounts) · isolated file DB + port per batch.

🔴 FAIL — 2 items

1. chart-type-matrix — combo widgets render as grouped bars

A widget authoring chartConfig.series = [{name:'task_count',type:'bar',yAxis:'left'},{name:'avg_progress',type:'line',yAxis:'right'}] plus two yAxis entries renders as two bar series on one shared 0–100 axis: .recharts-bar = 2, .recharts-bar-rectangle = 4, .recharts-line-curve = 0, .recharts-yAxis = 1. Reproduced 3× on independent fresh browser launches.

Repro: open /_console/apps/com.example.showcase/dashboard/showcase_chart_gallery, wait for the loader to appear then clear, settle, and count those selectors inside the "Task Count vs Avg Progress" card (combo_count_vs_progress).

Root cause (source-confirmed, two halves): objectui plugin-dashboard/src/DatasetWidget.tsx resolves the family with CHART_TYPE_MAP[widgetType] ?? 'bar' and CHART_TYPE_MAP has no combo entry; and chartConfigPresentation() in the same file deliberately does not forward series/xAxis/yAxis on the ADR-0021 dataset path ("they are DERIVED from the dataset selection"), so the authored per-series type and axis can never reach the renderer.

Not a stale-bundle artifact — verified against objectui origin/main, which is 138 commits ahead of the vendored pin and behaves identically. Tension worth a decision: widgetDispatch.ts on origin/main routes combo as a SERIES_CHART_TYPES member commenting "the chart renderer has always drawn it (it derives the base family from the series)" — but on the dataset path those series are exactly what DatasetWidget refuses to forward.

Honest caveat recorded, not ticked: kpi / gauge / solid-gauge / bullet all render value-only (pixel-identical to metric) — no dial, no arc, no bullet target band was drawn for any of them.

The other 19 variants pass with mark counts reconciled against API buckets, and compareTo renders its comparison series (with a loud prescriptive 400 when no dated window is supplied, rather than the pre-#5011 silent drop).

2. saved-report-ownership — DELETE /api/v1/reports/:id answers 500, and the mismatch leaks existence

Deleting another owner's report returns 500 REPORT_DELETE_FAILED, while deleting an id that does not exist returns 204. The 500-vs-204 split is an enumeration oracle over other users' report ids — precisely what the deny-as-404 posture exists to prevent. Reproduced 2× on two distinct reports.

Root cause: the DELETE ${dataPath}/reports/:id handler's catch goes straight to res.status(500) and never calls the file-local handleValidation(res, error) helper that maps REPORT_NOT_FOUND* → 404 — the sibling DELETE …/reports/schedules/:scheduleId handler does call it, which is why that route is correct. The service layer is already right (deleteReport() returns early for unknown ids and throws REPORT_NOT_FOUND for cross-owner, commented "others get a not-found so the delete neither fires nor reveals the report's existence") — the route discards that intent. Not stale-dist. One-line fix, plus aligning the unknown-id arm to the same status to close the side channel.

Good news on the same item: #6683's owner gate is live, and the item's revision-2 flip (expected-fail probe → positive deny assertion) is correct against today's server — cross-owner GET / run / upsert-overwrite all 404, schedule list returns empty, cross-owner unschedule 404, the owner's schedule survives, ownerId cannot be spoofed on create, anonymous 401. No cross-owner 2xx anywhere.

🟡 PARTIAL — 2 items

  • global-filters-rescope — everything proven except the persist-through-Studio half (blocked(environment): the showcase is installed as a read-only package so Studio Publish/Save-draft are disabled; the runner followed the UI's own prescription and created a writable package, still gated). The drive half was proven instead by authoring the exact shapes the inspector patches and confirming on reload that the re-targeted widget queries paid_on while siblings query issued_on, and the opted-out widget issues no query at all. Per-widget field mapping is exact on the wire and in the echoed SQL (region on invoice widgets vs sales_region on account widgets); dataset-sourced filter options are a real server GROUP BY, not a client top-N dedupe; client-side cosmetic filtering refuted outright.
  • system-overview-live-counts — tiles are live (each equals its own captured query and an independent direct aggregate; Active Sessions moved 25→26 together with the direct count). Partial because on the first capture the "Events by User" bar rendered its y-axis with zero bars and no empty state — its query had returned a single {user_id:null,…} row and the renderer drops the null-keyed category. Observed once, not reproduced, so recorded as a weakness per RUNNER rule 2 rather than promoted to a fail — but it is exactly the blank-widget shape this clause guards, and a board whose only audit actor is the system would meet it.

✅ PASS — 6 items

cube-query (6/6 — count and sum reconcile bucket-for-bucket with the direct /data aggregate, emitted SQL is a single-table GROUP BY so no join fan-out; the absent arm exercised on a deliberately crippled second boot → honest 404, never a silent 200-empty) · strict-widget-rejects-stray-keys (6/6 — all 11 legacy analytics keys rejected 422 with the key echoed and the ADR-0021 prescription verbatim; after 16 rejections the read-back is byte-identical to a never-existed stub) · dataset-report-authoring (8/8 — summary/matrix/joined/tabular each verified and reconciled; matrix all 8 cells + margins; joined blocks partition 244/10 exactly) · empty-null-bucket-boundaries (6/6 — empty window repaints to designed "No rows" with all 9 queries re-fired and all KPIs dropping to 0; the live null bucket is JSON null, not a '(null)' string sentinel) · chart-first-paint (4/4 — every chart had drawn marks at first paint with no resize, refuting the resize-to-draw failure this item exists for) · drill-through-range (5/5 — a month drill carries exactly that month's half-open bounds; a matrix-cell drill ANDs both dimensions using raw values, not display labels).

Smaller observations

  • The metadata door accepts a dataset binding that names nothing (200 on save and publish); reference integrity is enforced only at runtime — the widget then surfaces a visible error, which is why the negative still passes.
  • The ops dashboard's globalFilter is declared field:'status' with task status options while project-bound widgets carry no filterBindings, so it also lands on showcase_project.status and zeroes those tiles (showcase authoring gap, not a platform defect).
  • The System Overview board's default "Last 7 days" filter applies to sys_user.created_at, so "Total Users" is really users created in the last 7 days — indistinguishable from the true total only because the DB was fresh. Likewise sys_session_metrics carries no active-only filter, so the "Active Sessions" label overstates what it counts.
  • The dateRange "Custom…" picker did not open under automation — flagged for re-check against a fresh console build rather than filed.

Activity

  1. huangyiirene commented on Aug 11, 2026

    @huangyiirene
    Collaborator

    Extraction ledger — COMPLETE

    Every FAIL, PARTIAL and smaller observation in this run now has a card. This record stays open as the aggregation node and carries tracking, so the triage seat skips it and it is not itself a dispatch candidate.

    Run item Finding Card Lane
    chart-type-matrix (FAIL) combo widgets render as grouped bars — no combo in CHART_TYPE_MAP, and chartConfigPresentation() refuses to forward series/xAxis/yAxis on the dataset path objectstack-ai/objectui#4229 objectui
    saved-report-ownership (FAIL) SECURITY — DELETE /reports/:id answers 500 cross-owner but 204 for a nonexistent id: an enumeration oracle over other users' report ids #7523 domain:cli
    system-overview-live-counts (PARTIAL) "Total Users" is really users created in the last 7 days; "Active Sessions" counts every session — plus the once-observed null-keyed blank widget #7531 domain:metadata
    global-filters-rescope (PARTIAL) No card — the unproven half is blocked(environment) (showcase installed read-only, Studio Publish disabled), not a defect. The drive half was proven by other means. — —
    Smaller obs The metadata door accepts a dataset binding that names nothing (200 on save and publish) — referential integrity enforced only at runtime #7529 domain:metadata
    Smaller obs Ops dashboard globalFilter declares task statuses but also lands on showcase_project.status, zeroing those tiles #7568 domain:metadata
    Smaller obs dateRange "Custom…" picker did not open under automation #7570 ⚠️ no lane (see below)

    The 6 PASS items produced no cards, as expected.

    #7570 is deliberately filed as an unconfirmed observation, not a defect

    The run itself declined to file it, and that judgement is preserved rather than overridden: the evidence is automation-only, single-occurrence, and taken on vendored console 09987b68 while objectui origin/main was ~138 commits ahead. Its ## Root cause section says "Not located by the run", and it names the required next step — re-drive on a current console build, manually and under automation. If it reproduces it becomes an objectui card; if not it closes as an automation artifact. It carries no domain:* because there is nothing to fix in this repo unless it reproduces, and then the fix is in objectui.

    Recording this explicitly so a later sweep does not read the missing lane label as an oversight and "helpfully" route a non-defect into someone's queue.

    On #4229 — the design tension is in the card, not resolved by it

    The run found that objectui origin/main's widgetDispatch.ts routes combo as a SERIES_CHART_TYPES member, commenting "the chart renderer has always drawn it (it derives the base family from the series)" — while on the dataset path those series are exactly what DatasetWidget refuses to forward. Two parts of the same codebase disagree about whether combo is supported. The card carries that contradiction rather than picking a side.

    Also recorded there, untested rather than ticked: kpi / gauge / solid-gauge / bullet all render value-only, pixel-identical to metric — no dial, no arc, no bullet target band for any of them.

    Stale-premise status

    Checked against PRs merged since 2026-08-10; none of these appears already fixed. The check matters on this batch: a sibling card (#7524, approvals run) was closed because PR #7395 had fixed its defect hours after build a86db175 was cut.


    Generated by Claude Code

  2. huangyiirene commented on Aug 11, 2026

    @huangyiirene
    Collaborator

    Closing — extraction is complete (see the ledger comment above; every FAIL, PARTIAL and observation has its card, including the deliberately-unconfirmed #7570). A closed run record stays fully readable; nothing actionable remains anchored here.

    Provenance: maintainer instruction of 2026-08-11 (chat, verbatim): 「QA run 相关的 issue 如果任务已经分拆出去了,是不是应该直接关闭」 — same exit as the all-pass run records #7399 / #7326.


    Generated by Claude Code

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions