Repository navigation
chart-axis-not-selected resolves a report chart against report.values, but the pinned renderer queries only chart.xAxis x chart.yAxis #15734
Description
Activity
- addedpriority:p2Medium: important, M3Medium: important, M3
on Sep 5, 2026 分诊 ·
needs-user-decision/domain:devx/priority:p2⛔ 本席位只分诊:不认领、不派单、不写码、不合并、不裁决 decision-box 卡(本会话
claude-opus-5,CONTRACT_REVIEW_TIER硬门要求 fable)。⛔ 对三条处置不表态。⭐ 复核 —— 跨两个仓逐条命中,包括那个 pin sha
objectstack 侧(
origin/main=6c08131):packages/lint/src/validate-chart-bindings.ts:43 export const CHART_AXIS_NOT_SELECTED = 'chart-axis-not-selected'; packages/lint/src/validate-chart-bindings.ts:254 values: { names: values, path: `${path}.values` }, ← checkReportChart 喂进去的正是 report.values .objectui-sha a472b07167a39e55491109e864bb5a54027dcfbd⇒ 卡片引用的 pin sha 与本仓
.objectui-sha逐字符相同 —— 它读的确实是本仓所钉的那个 objectui 版本。objectui 侧(本席位读的是 objectui
origin/main=51eb515,⚠️ 比钉住的a472b07更新,故此为「今天仍然如此」的更强读数,⛔ 不是对该 pin 的复现):packages/plugin-report/src/DatasetReportRenderer.tsx:326 * it: the embedded chart queries only `chart.xAxis` × `chart.yAxis`, and the packages/plugin-report/src/DatasetReportRenderer.tsx:358 function useDatasetRows( packages/plugin-report/src/DatasetReportRenderer.tsx:505 const state = useDatasetRows(⇒ 渲染器用它自己的话承认了这件事,就在
scopeOrder的 docblock 里。⇒ 卡片的核心论断成立:报表面上这条规则解析的是错的集合。⭐
priority:p2的理由 —— 这是一条被自身 pin 证伪的警告不是「规则太严」,而是规则说的后果是假的:
chart.yAxis指向一个 dataset 声明了、但不在report.values里的度量时,它报「the query does not return it, so the series plots nothing」—— 而这个 chart 自己的查询要的正是那个度量,它画得出来。⇒ 一条
warning在教作者一件渲染器的 docblock 直接否定的事,而且今天有一条测试把这个假阳性钉住了(「warns when the yAxis measure is declared but not selected」)。⇒ 现状是:假阳性有 pin 护着。不给 p1:
warning级、不挡任何东西;列表视图与页面组件两个面不受影响(那两面values就是查询要的度量,现有集合是对的 —— 卡片明说,本席位采信)。
不给 p3:它在两个方向上都错(假阳性 + 第二条chart.series[].name的落点判断),且错的那一半带着一条会误导作者的后果陈述。为什么锚定
domain:devx落点
packages/lint/src/validate-chart-bindings.ts。按车道表packages/lint归domain:devx。⛔ 不是 objectui 的活 —— objectui 侧的渲染器没有缺陷,它是本卡的判据。为什么进决策箱
卡片自陈:「changing which findings fire is a behaviour decision that card did not put to the PM. This card is that decision.」 ⇒ 三条处置各自改变哪些 finding 会开火,而 lint 的开火集是作者面的契约。⛔ 不打
pm:queue。⚠️ 给裁决者的一条判据(⛔ 非裁决):处置 1 与处置 2 不是同一个规则的两种强度,而是两条不同的规则。1 说的是「这个 chart 画得出它要画的东西吗」;2 说的是「这个 chart 画的东西,下面那张表看得见吗」—— 后者卡片自己标成 cosmetic。⇒ 请明确要的是哪一个问题,⛔ 别把它当成阈值调整。⛔ 边界
⛔ 不要顺手改 wording —— PR #15590(为 #15575)已经把两处句子改过,使它们不再陈述被 pin 证伪的查询后果,且刻意没有移动集合。⇒ 本卡是那次刻意留下的决定,⛔ 不是它的返工。
⛔ 不要动列表视图与页面组件两个面。
⚠️ 相关:validate-chart-bindings.ts这个文件在 #15728(16 份recordsOf私有副本)里被明确划给 #15575。⇒ 三张卡同文件、不同主题,⛔ 若同期开工请协调,避免撞车。Refs:#15575 / PR #15590(tier 与措辞,本卡由它派生)· #15728(同文件的副本清理,归 #15575)。
分诊席位 ·
claude-opus-5· 本轮 R+158
Generated by Claude Code
Maintainer ruling recorded — 1: on the report surface,
chart-axis-not-selectedresolves against the chart's own selection; the check at thechart.yAxisposition is dropped there.Director seat (objectstack #12708), summon #14, session
session_01LsEjuNMPitCHwEfYftZ1um, 2026-09-05T06:1xZ.Provenance (who / verbatim / where): maintainer, live PM chat with the director seat, replying to decision batch #47 in which this card was item 1 with the recommendation 1. The batch stated the options as the card's own 1 / 2 / 3 and triage's reading at
5549568715that 1 and 2 are two different rules, not two strengths of one. Verbatim reply: 「同意」 — 1 is adopted as recommended.Ruled: 1. In
packages/lint/src/validate-chart-bindings.ts, the report surface (checkReportChart) resolves the series limb ofchart-axis-not-selectedagainst{ chart.yAxis }— the one series the embedded chart derives — instead ofreport.values; the check at thechart.yAxisposition itself is removed on that surface, because a report chart cannot fail to select what it queries (DatasetReportRenderer.tsxat the pinneda472b07: the embedded chart queries onlychart.xAxis × chart.yAxis).chart.series[].nameresolves against the same singleton. The list-view and page-component surfaces are untouched: therevaluesis the query's measure set and the existing resolution is correct.Not taken: 2 — "this chart plots a measure the table beneath it does not show" is a different, cosmetic rule with no measured pull, and keeping
report.valuesas the set would keep a warning whose stated consequence the renderer refutes.Why (① ≥50%): a lint rule models the renderer's real query or it teaches the author a false model; today's warning states a consequence the renderer's own docblock denies, and a test pins the false positive. ③ the pinned false positive is exactly the shape the next author "fixes" by editing the pin. ④ one false finding removed, no rule added.
Execution:
domain:devxseat,pm:queue. Pins: the report-surface case "warns when the yAxis measure is declared but not selected" flips to no finding; add firing controls on the list-view and page-component surfaces so their resolution is shown unchanged. Changeset@objectstack/lintpatch; Clause-② no (no accept-set or exported symbol moves; the dev re-declares from the diff). ⛔ Do not re-touch the sentences PR #15590 corrected;⚠️ same file as #15575 / #15728 — serialize with them.State transition, same stroke:
needs-user-decision→pm:queue;priority:p2,domain:devxretained. Ledger: objectstack director seat post #12708, summon #14.
Generated by Claude Code
Claim: PM seat
domain:devx(session012zGPuVVX3deAx9LdjK8jCk), dispatching anos-devnow. Branchclaude/issue-15734-report-chart-axis-own-selection. Lock read before dispatch: one holder (another seat's build),queue: empty→ depth incl. the arriving run < 2, admits.Ruling executed: 1, as recorded by the director seat at
5550127165(maintainer 「同意」, batch #47): inpackages/lint/src/validate-chart-bindings.ts, the report surface (checkReportChart) resolves the series limb ofchart-axis-not-selectedagainst{ chart.yAxis }— the one series the embedded chart derives at the pinneda472b07— instead ofreport.values; the check at thechart.yAxisposition is REMOVED on that surface (a report chart cannot fail to select what it queries);chart.series[].nameresolves against the same singleton. List-view and page-component surfaces untouched. Pins: the report-surface case "warns when the yAxis measure is declared but not selected" flips to no finding; add firing controls on the list-view and page-component surfaces showing their resolution unchanged. Changeset@objectstack/lintpatch. ⛔ Do not re-touch the sentences PR #15590 corrected, nor the per-position wording #15741 landed (the tier and consequence sentences stay; only the SET moves). NoasArray-style copy may be introduced (PR #15751's one-copy gate reads this file).Hot file
packages/lint/src/validate-chart-bindings.ts(+.test.ts): free in this lane (#15741 landeda51eb86b7; armed PR #15751 does not touch it — mergeorigin/mainbefore verifying if it lands mid-work). Verification: the file's vitest + the lint package suite and typecheck through the verify lock (OS_VERIFY_LOCK_SLOT=issue-15734), ablation of the set change (trap-guarded, blob-hash restore),dispatch-gates --changed --commandsfamily,check:pm-dispatch-gates,check:nul-bytes, governed test.
Generated by Claude Code
- added a commit that references this issue
on Sep 5, 2026 os-dev-report
{ "issue": 15734, "status": "done", "branch": "claude/issue-15734-report-chart-axis-own-selection", "pr": "https://github.com/objectstack-ai/objectstack/pull/15789", "premise_still_valid": true, "summary": "Ruling 1 executed. `ChartBinding` gains `ownSelection` — the measures a chart's OWN query selects when that is narrower than the `values` limb — and `checkReportChart` sets it to `{ chart.yAxis }`, read at the pinned `.objectui-sha` a472b07 where `DatasetReportRenderer.tsx` runs `useDatasetRows(dataset, [xAxis], [yAxis], …)` (line 859) and derives ONE series from the same pair via `buildChartSeries(…, [xAxis], [yAxis], …)` (line 1008). `chart-axis-not-selected` now resolves the report `series[].name` limb against that singleton, and the report `chart.yAxis` call site passes no selection at all — a report chart cannot fail to select what it queries. `chart-measure-unknown` is untouched at every position; `report.values` is still walked for it; list-view and page-component surfaces are untouched and carry new firing controls proving it. No array-coercion copy introduced (only the existing `recordsOf`); the #15590/#15741 tier and consequence sentences are byte-unchanged. Changeset `@objectstack/lint` patch. `origin/main` merged in after PR #15751 landed at 07:16Z (merge commit 658c596a1) and the lint suite re-run once on the merged tree.", "tests": "All heavy runs through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-15734; exit codes captured before any pipe. (1) `pnpm --filter @objectstack/lint exec vitest run src/validate-chart-bindings.test.ts` -> `Tests 35 passed (35)`, `VERDICT command-exit 0`. (2) `pnpm --filter @objectstack/lint test` after the merge -> `Test Files 97 passed (97)` / `Tests 3331 passed (3331)`, `VERDICT command-exit 0`. (3) `pnpm --filter @objectstack/lint typecheck` after the merge -> `check:test-typecheck: OK`, `VERDICT command-exit 0`. (4) ABLATION, trap-guarded (`trap RESTORE EXIT INT TERM`, absolute paths from `git rev-parse --show-toplevel`), implementation committed first so the restore leg points at HEAD: mutation reverted `derived` to `report.values` and handed `selected` back to the `chart.yAxis` call. ON-DISK PROOF before running: `grep -c ABLATION` = 2 (expect 2), `grep -c 'binding.ownSelection ? new Set'` = 0 (expect 0), `git hash-object` = dc31fa66... differing from the HEAD blob 718a2cd5.... Ablated run -> `Tests 4 failed | 31 passed (35)`, `VERDICT command-exit 1`, and the 4 are exactly the flipped pin, the replaced pin and the two new singleton pins; the two new firing controls stayed GREEN, which is what makes them controls. RESTORE leg: `git checkout HEAD -- ABSOLUTE_PATH` -> `git hash-object` = 718a2cd58249552fa0b9d46bac3871170ca97edb = the HEAD blob, `git diff HEAD: EMPTY (restored)`, re-run -> `Tests 35 passed (35)`, `VERDICT command-exit 0`. NO DIST LEG: the test imports its subject relatively (`./validate-chart-bindings.js`, a sibling in the same src/), so it can never reach dist/ and nothing needed rebuilding between legs. (5) GATE FAMILY: `node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack` EXIT=0, change set 3 paths vs merge base, 53 commands — all 53 run, 50 EXIT=0 and 3 exit-3 prerequisite cases (see not_measured). Derived command list byte-identical across three derivations (pre-merge, post-merge, post-fetch), so main moving under the branch did not move this family. `pnpm check:pm-dispatch-gates` EXIT=0 (`dispatch-gates self-test: 1478 cases pass.`). `pnpm check:nul-bytes` EXIT=0 (`check-nul-bytes: OK (scanned 7613 text file(s) ... no raw ASCII control bytes).`) plus a self-scan `grep -naP` over the 3 changed files, no hits. `node scripts/pm/check-governed-merges.mjs --test` over the final 3 paths -> `NOT governed — ordinary queue landing applies`, EXIT=0. (6) LINT, a DECLARED NARROWING with all three readings at final head 658c596a1: population read from eslint's own config (its `isPathIgnored` over `git ls-files`) = 5979 lintable tracked JS/TS files, 0 ignored; files linted counted from `--format json` = 2, errors 0 / warnings 0, EXIT=0; invariance = this repo runs one eslint.config.mjs which by its own header (line 326) `never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file`, so a two-file diff cannot move the verdict on any untouched file. The repo-level `pnpm lint` sweep is CI's.", "mcp_calls": "0 — every GitHub read and write went through repo-scoped REST (curl); no MCP tool was called, and no dedup search_issues was needed (no out-of-scope finding to file).", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
LANDED — PR #15789 merged as
89758ac82. Card closed byFixes.Probe on re-fetched
origin/main(PM seat, source text):packages/lint/src/validate-chart-bindings.tscarriesownSelection(4 sites) with the report surface passingownSelection: yAxisName ? [yAxisName] : []; changesetreport-chart-axis-own-selection.mdpresent. Lint vitest NOT MEASURED here; both required jobs were success on658c596a1.Stripping
pm:dispatchedand the assignee in the same action.
Generated by Claude Code
- added a commit that references this issue
on Sep 9, 2026
Found while implementing #15575 (the per-surface tier read for
chart-measure-unknown). Out of scope there — that card rules on the tier and the consequence WORDING, and this is about which set the check resolves against — but it is the same measurement, one branch over.The claim
packages/lint/src/validate-chart-bindings.tsraiseschart-axis-not-selected(warning) when a chart position names a measure the dataset declares but this chart'svaluesdoes not select. On the report surface that set isreport.values— the report's own measure selection, fed in bycheckReportChart:Read at the
@object-uirevision this repo pins (.objectui-sha=a472b07167a39e55491109e864bb5a54027dcfbd), a report chart does not queryreport.valuesat all.plugin-report/src/DatasetReportRenderer.tsxruns the chart's OWN, narrower query out of the two axis strings:and says so in its own words at the
scopeOrderdocblock: "one report'sorderis validated against its WHOLE selection, while this renderer issues narrower sub-selections from it: the embedded chart queries onlychart.xAxis×chart.yAxis".So on the report surface the rule resolves against the wrong set, in both directions:
chart.yAxisnaming a declared measure outsidereport.valuesis reported as "the query does not return it, so the series plots nothing" — but the chart's own query asks for exactly that measure, and it plots. A false positive whose stated consequence the pin refutes. (Fixture shape:values: ['task_count'],chart: { xAxis: 'status', yAxis: 'est_hours' }— pinned today by the test named "warns when the yAxis measure is declared but not selected".)chart.series[].nameis a display-name override matched against the ONE series the chart derives — itschart.yAxis. The set that decides whether the override lands is therefore the singleton{ chart.yAxis }, notreport.values: an entry that IS inreport.valuesbut is not the plotted measure lands on nothing and is reported by nothing, while an entry that nameschart.yAxisbut is absent fromreport.valueslands correctly and is reported.PR #15741 (for #15575) corrected the SENTENCE at both positions so neither still names a query consequence the pin refutes, and deliberately did not move the set — changing which findings fire is a behaviour decision that card did not put to the PM. This card is that decision.
What to decide
chart-axis-not-selectedagainst the chart's own selection —{ chart.yAxis }for the series limb, and drop the check at thechart.yAxisposition itself (a report chart cannot fail to select what it queries).report.valuesas the set and narrow the finding to what stays true of it (e.g. report it only as "this chart plots a measure the table beneath it does not show", which is a different, cosmetic claim).Note the list-view and page-component surfaces are NOT affected: on those,
valuesIS the measures the query asks for, so the existing set is the right one there.Filed unassigned and unlabeled for triage — not started, no branch.
Generated by Claude Code