Repository navigation
QA run · dashboards (FULL area) · a86db175 · 2026-08-11 · 6 PASS / 2 PARTIAL / 2 FAIL #7515
Description
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 queriespaid_onwhile siblings queryissued_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 (regionon invoice widgets vssales_regionon account widgets); dataset-sourced filter options are a real serverGROUP 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
globalFilteris declaredfield:'status'with task status options while project-bound widgets carry nofilterBindings, so it also lands onshowcase_project.statusand 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. Likewisesys_session_metricscarries 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
huangyiirene commentedon Aug 11, 2026
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.chart-type-matrix(FAIL)combowidgets render as grouped bars — nocomboinCHART_TYPE_MAP, andchartConfigPresentation()refuses to forwardseries/xAxis/yAxison the dataset pathsaved-report-ownership(FAIL)DELETE /reports/:idanswers 500 cross-owner but 204 for a nonexistent id: an enumeration oracle over other users' report idsdomain:clisystem-overview-live-counts(PARTIAL)domain:metadataglobal-filters-rescope(PARTIAL)blocked(environment)(showcase installed read-only, Studio Publish disabled), not a defect. The drive half was proven by other means.domain:metadataglobalFilterdeclares task statuses but also lands onshowcase_project.status, zeroing those tilesdomain:metadatadateRange"Custom…" picker did not open under automationThe 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
09987b68while objectuiorigin/mainwas ~138 commits ahead. Its## Root causesection 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 nodomain:*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'swidgetDispatch.tsroutescomboas aSERIES_CHART_TYPESmember, 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 whatDatasetWidgetrefuses to forward. Two parts of the same codebase disagree about whethercombois supported. The card carries that contradiction rather than picking a side.Also recorded there, untested rather than ticked:
kpi/gauge/solid-gauge/bulletall render value-only, pixel-identical tometric— 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
a86db175was cut.Generated by Claude Code
huangyiirene commentedon Aug 11, 2026
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
fix(plugin-reports): stop `DELETE /reports/schedules/:scheduleId` rev…