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.

finding(plugin-charts): the scatter branch bypasses yAxisSpecProps, so a spec min/max/logarithmic/ticks/title on its y-axis is silently dropped #9675

Closed

Description

@os-justin

Found while pre-dispatch verification of objectui#7396 (that card is the scatter's visual edge clipping). This is a different defect on the same two axes, with a different blast radius, so it is filed rather than swept in.

What

AdvancedChartImpl.tsx derives every spec-driven y-axis prop in one helper:

/** Recharts props derived from one spec y-axis (domain / scale / ticks / label). */
const yAxisSpecProps = React.useCallback((axis: NormalizedAxis | undefined, side: 'left' | 'right' = 'left') => {
  if (!axis) return {};
  const domain = domainFor(axis);
  const ticks = ticksFor(axis, axisValues(side));
  return {
    ...(ticks ? { ticks } : {}),
    ...(domain ? { domain } : {}),
    // `allowDataOverflow` is what makes an explicit domain actually clip
    // rather than being silently widened to fit the data.
    ...(domain ? { allowDataOverflow: true } : {}),
    ...(axis.logarithmic ? { scale: 'log' as const, domain: domain ?? ([1, 'auto'] as any) } : {}),
    ...(axis.title ? { label: { value: axis.title, angle: -90, position: 'insideLeft' as const } } : {}),
  };
}, [axisValues]);

The scatter branch does not spread it. Measured on main at 15b33aeb4:

probe reading
SUBJECT — yAxisSpecProps( spread sites in the file 5 — lines 1918, 1919, 2016, 2035, 2045
SUBJECT — is the scatter YAxis (lines 1839-1847) among them no
CONTROL — the helper exists and is reachable from the scatter branch's own component yes, declared at line 1264 in the same component

The scatter YAxis, verbatim at lines 1839-1847, carries type, dataKey, name, tickLine, axisLine, tickFormatter and width — and nothing derived from the spec axis. Its XAxis (lines 1831-1837) likewise.

Cost — this one is a silent wrong answer, not a visual one

Five spec keys are accepted by the schema, normalized by normalizeChartSchema, and then dropped on the floor for exactly one chart family:

  • min / max — an author who pins a y domain gets the auto domain instead. The chart is drawn to a scale the author did not ask for, and nothing refuses.
  • logarithmic — a log axis renders linear.
  • ticks — explicit tick values are ignored.
  • title — the axis label never appears.

⭐ The discriminating property versus objectui#7396: there, the data is right and half a symbol is painted outside the plot box, which a reader can see. Here the picture is confidently wrong — a correct-looking chart at a scale the author overrode, with no diagnostic anywhere. An author who sets min: 0 to stop a truncated-baseline reading gets the truncated baseline back, silently.

Expected

The scatter's numeric axes go through the same derivation every other family uses, or the file states in writing why scatter is exempt.

Not in objectui#7396's scope, deliberately

objectui#7396 is p3 and purely visual. Its dispatch order names this card as out of scope, so the two do not get merged into one diff by accident. ⛔ Whichever lands first must not silently absorb the other: an explicit padding domain on those axes and a spec-derived domain are the same prop, and a fix for one that ignores the other will shadow it.

Not verified here

⛔ Whether any authored chart in this repository's corpus or in a downstream project actually sets min / max / logarithmic / ticks / title on a scatter y-axis is not measured — this card is the declaration-side reading only. A grader may want that liveness count before pricing it.


Generated by Claude Code

Activity

  1. self-assigned this
    on Sep 18, 2026
  2. os-tesla commented on Sep 18, 2026

    @os-tesla
    Collaborator

    Claim: PM loop round 1
    Session: session_018HrVaotisyhgmot9o2MLRq
    Branch: claude/issue-9675-scatter-yaxis-spec-props
    Worktree: objectui-issue-9675
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/plugin-charts/src/AdvancedChartImpl.tsx plus its test file — stop on breach; explain in the report
    Container & model: M, mode:subagent, model: default judgment tier
    Clause-②: no
    Thread-read: 5714856832
    Serial constraints cleared: see the mandatory intersection discharge below. Other in-flight domain:ui at claim time — objectui#8167 and objectui#9691 (this seat), objectui#9580 / objectui#9623 (this seat, delivered as PR objectui#9783 / objectui#9776), plus seat 1's objectui#9382 / objectui#9452 / objectui#9453 and objectui#9570 / objectui#9373 / objectui#9061 / objectui#7945. No in-flight card declares packages/plugin-charts/.

    ⚠️ Triage's mandatory in-flight check — discharged, and its named blocker was already stale when written

    Triage 5714856832 requires, before dispatch: 「objectui#7396(scatter 的视觉裁切)此刻是 pm:dispatched 且带真人 assignee,同一个文件、同一条 scatter 分支 … 派发本卡前先读 #7396 认领评论申报的文件面,相交则串行或让行。⛔ 三张 ⛔ 不并发。」

    Read now, ⛔ not inherited:

    probe reading
    objectui#7396 state closed / completed, closed_at 2026-09-17T11:49:08Z
    objectui#9681 state open, pm:queue, ⛔ no assignee
    ⇒ in-flight holders of AdvancedChartImpl.tsx none

    ⭐ Worth recording: objectui#7396 closed 78 minutes BEFORE triage wrote that it was 「此刻 pm:dispatched」. The obligation was right and is honoured here; the named blocker was already discharged at the moment it was named. ⇒ ⛔ an in-flight assertion is only as good as its timestamp — re-read, never inherit.

    fold-or-serial with objectui#9681 — this seat answers SERIAL, ⛔ not folded

    Both cards live in AdvancedChartImpl.tsx's scatter branch, so the five gates must be answered explicitly:

    • ⛔ gate ① fails. This card is a bypassed derivation (the scatter axes never spread yAxisSpecProps, so five spec keys are dropped) ⇒ route them through the shared helper. objectui#9681 is an inert declaration (ZAxis range={[60,400]} with no dataKey, so recharts never reads it) ⇒ wire it or delete it. Different defect shapes, different repairs. 同关键词/同子系统 is explicitly ⛔ not the test.
    • ✅ gate ② holds (same file), ✅ gate ③ (both graded p2), ✅ gate ④ (each independently checkable).
    • ⇒ one gate short of a fold, and they share a hot file ⇒ hard serial. objectui#9681 queues behind this card and ⛔ is not dispatched concurrently.

    ⚠️ The card's own collision warning is carried into the dispatch, verbatim: 「⛔ Whichever lands first must not silently absorb the other: an explicit padding domain on those axes and a spec-derived domain are the same prop, and a fix for one that ignores the other will shadow it.」 objectui#7396 has now landed first, so this card's dev must read what it left on those axes before adding a domain.

    Clause-② reasoning, recorded so the review is not re-deriving it

    no. The five keys (min/max/logarithmic/ticks/title) are already accepted by the schema and already normalised by normalizeChartSchema; they are dropped at render for one chart family. Honouring them ⛔ does not relax an accept set and ⛔ does not widen a public face — it fulfils a declared contract that the renderer was not paying (声明而未兑现是实现缺口 ⇒ 补实现).

    ⚠️ Declaration, ⛔ not a verdict: it is a user-visible render change on a published package, so the changeset must say so plainly, and if the dev's actual diff adds an exported symbol or a new key the declaration is wrong and the report must say so.

    domain:ui#2 execution seat · session_018HrVaotisyhgmot9o2MLRq · claim · reading taken 2026-09-18T04:55Z


    Generated by Claude Code

  3. os-tesla commented on Sep 18, 2026

    @os-tesla
    Collaborator

    os-dev-report

    {
    "issue": 9675,
    "status": "done",
    "branch": "claude/issue-9675-scatter-yaxis-spec-props",
    "pr": "#9790",
    "session": "session_018HrVaotisyhgmot9o2MLRq",
    "premise_still_valid": true,
    "summary": "The scatter branch now spreads the spec ChartAxis derivation on BOTH numeric axes, so min/max (domain), stepSize (ticks), logarithmic (scale), title (label) and format (tick text) are honoured instead of dropped. The shared derivation was hoisted to a plain module function numericAxisSpecProps taking the axis, its value population and a title layout; yAxisSpecProps is now a thin y wrapper, so the five pre-existing spread sites are untouched and no exported symbol is added. Card assignee was os-tesla (set by PM) and untouched; the newest Claim comment 5725363843 names THIS branch. Issue body shows NO sanitizer truncation - it ends with its attribution footer and its one fenced block is intact.",
    "premise_checks": {
    "zone2_1_spread_sites": "CONFIRMED in count, STALE in every line number. On origin/main 57c07f0 (not 15b33ae): helper declared at line 1328 (card said 1264); 5 spread sites at 1983, 1984, 2081, 2100, 2110 (card said 1918, 1919, 2016, 2035, 2045); scatter YAxis at 1902-1911 is NOT among them (card said 1839-1847). Probe git grep -nw yAxisSpecProps -- 'packages/**', lit control git grep -nw domainFor returns 11 hits so the matcher can fire. The scatter YAxis carries an 8th prop the card did not list: padding={SCATTER_Y_AXIS_PADDING}, landed by objectui#7396.",
    "zone2_2_accept_and_normalise": "CONFIRMED, and one spelling corrected. Accept side: node_modules/@objectstack/spec/json-schema/ui/ChartAxis.json declares field/title/format/min/max/stepSize/showGridLines/position/logarithmic with additionalProperties false, and ChartConfig gives xAxis and yAxis[] that SAME shape. Normalise side: normalizeAxis in normalizeChartSchema.ts copies each one onto NormalizedAxis, pinned by normalizeChartSchema.test.ts. CORRECTION: ticks is not a spec key - the authoring key is stepSize, and ticks is the recharts prop ticksFor derives from it. So the five are min / max / logarithmic / stepSize / title.",
    "zone2_3_xaxis": "CONFIRMED and it widened the repair. The scatter XAxis carried type/dataKey/name/tickLine/axisLine/minTickGap /padding and nothing spec-derived. It is the only x axis in the file that plots a MEASURE rather than a category band, so min/max/stepSize/logarithmic are meaningful there and were being dropped. Repaired, per the card's own Expected ("the scatter's numeric AXES") and its What ("Its XAxis ... likewise").",
    "zone2_4_corpus_count": "ZERO authored scatter charts in this repo declare any of these keys on an axis - there is no authored scatter schema in examples/schema-catalog at all (it holds advanced-line-chart.json, area-chart.json, simple-bar-chart.json). Lit control for the zero, two-sided: (a) the same yAxis-with-spec-keys matcher finds 10 sites elsewhere in the tree (normalizeChartSchema tests, plugin-dashboard tests), so it can fire; (b) the same corpus dirs do carry authored chartType metadata (schema-catalog JSON, content/docs examples), so the dirs are not empty. Per the dispatch the zero does not price the repair down: these are spec-declared keys and downstream authors are not in this tree.",
    "zone1_7396_composition": "NO SHADOWING - checked on current origin/main BEFORE adding a domain, as ordered. objectui#7396 landed SCATTER_X_AXIS_PADDING / SCATTER_Y_AXIS_PADDING and deliberately spent recharts' axis padding, which insets the pixel RANGE and leaves the domain alone. Its docblock says so in writing and names objectui#9675 by number: 'Moving the domain instead would ... write the very prop the scatter's missing yAxisSpecProps spread is about'. So domain was left free FOR this card. The two are now live at once and compose; a pin holds the pair together, and both docblocks (source + objectui#7396's own test) are updated because this branch made their 'still free' wording false.",
    "zone1_9681_untouched": "The ZAxis line is byte-identical to origin/main: ZAxis type=\"number\" range={[60, 400]}, no dataKey added, no line touched. The SERIAL chain is intact."
    },
    "tests": "ALL from the repo root (the package-directory form is refused by scripts/vitest-invocation-guard.mjs). Heavy runs through bash /home/user/objectstack/scripts/pm/os-verify-lock.sh, slot default. Exit codes captured before any pipe.\nRED-before-repair: new pin file AdvancedChartImpl.scatterSpecAxes-9675.test.tsx -> exit 1, 8 failed / 2 passed (10), e.g. "the y domain does not reach the authored max: expected '60' to be '100'", "expected ['0','15','30','45','60'] to deeply equal ['0','20','40','60']", "the decades are not equally spaced, so the y scale is still linear: expected 99.99999999999952 to be less than 1.05".\nGREEN-after-repair: 12 passed (12). Package: pnpm exec vitest run packages/plugin-charts/ -> exit 0, 62 files / 560 tests passed, objectui#7396's own file included. Consumers: pnpm exec vitest run packages/plugin-dashboard/ packages/plugin-report/ -> exit 0, 136 files / 1320 tests passed.\nABLATION, re-run on the FINAL HEAD (39a2fa0) after the late refactor commit: node ablate.mjs strips the three JSX spreads and reverts the y tickFormatter, each anchor required to hit EXACTLY once or the script exits 2. On-disk proof: anchor counts 4/1/1/0 -> 3/0/0/1; blob cf72af1b -> eb778003. Mutated tree -> exit 1, 10 failed / 2 passed (12). The 2 survivors are the controls (no spec axis declared -> the derivation contributes no prop), which is exactly why objectui#7396's pinned default tick arrays are untouched. RESTORE proved by state, not exit code: restored blob cf72af1b equals the HEAD blob, git diff HEAD empty, git status --short empty. trap RESTORE EXIT INT TERM with an absolute REPO_ROOT path, restore via git checkout HEAD -- PATH (never bare git checkout --).\nNO REBUILD NEEDED for the ablation and that is verified, not assumed: the pin imports './AdvancedChartImpl' relatively, inside the same package, so vitest resolves SOURCE and never the package exports -> dist. The build was run anyway (below) for the type/dist half.\nBuild/typecheck/lint: pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-charts^...' build -> exit 0 (needed first: a bare package build fails TS2307 on every @object-ui/* import in a fresh worktree). ... --filter @object-ui/plugin-charts build -> exit 0. ... type-check -> exit 0, and it is tsc --noEmit && tsc -p tsconfig.test.json, so the new test file IS covered. ... lint -> exit 0, 350 warnings, all the pre-existing no-explicit-any baseline (0 errors).",
    "gates": {
    "derivation": "HAND-DERIVED from objectui's own package.json scripts and .github/workflows/*, as ordered - scripts/pm/dispatch-gates.mjs does not exist in this repo. Every exit code was redirected to a file and read afterwards, never through a pipe.",
    "green_exit_0": [
    "pnpm exec vitest run packages/plugin-charts/ (62 files / 560 tests)",
    "pnpm exec vitest run packages/plugin-dashboard/ packages/plugin-report/ (136 files / 1320 tests)",
    "pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-charts^...' build",
    "pnpm --workspace-concurrency=2 --filter @object-ui/plugin-charts build",
    "pnpm --workspace-concurrency=2 --filter @object-ui/plugin-charts type-check",
    "pnpm --workspace-concurrency=2 --filter @object-ui/plugin-charts lint",
    "node scripts/check-changeset-presence.mjs (printed: 4 files changed, 3 published source, 1 changeset)",
    "node scripts/check-changeset-no-major.mjs",
    "node scripts/check-changeset-fixed.mjs",
    "node scripts/check-control-bytes.mjs",
    "node scripts/check-new-cross-file-line-citations.mjs (0 new citations, enforcement report-only)",
    "node scripts/check-test-path-roots.mjs",
    "node scripts/check-vi-mock-specifiers.mjs",
    "node scripts/check-vi-mock-inherit.mjs",
    "node scripts/check-vi-mock-override-shape.mjs",
    "node scripts/check-unreferenced-sources.mjs",
    "node scripts/check-changeset-claims.mjs",
    "node scripts/check-pending-changeset-literals.mjs",
    "node scripts/check-comment-mask-corpus.mjs",
    "node scripts/check-spec-symbol-derivation.mjs",
    "node scripts/check-lint-rule-coverage.mjs",
    "node scripts/check-lint-coverage.mjs (46/46 packages linted, 0 outstanding errors)",
    "node scripts/check-governed-queue-guard.mjs --test THE-4-CHANGED-PATHS -> NOT GOVERNED, 4 paths vs 5 governed surfaces, none matched"
    ],
    "not_measured": [
    "Remote CI (ci.yml, lint.yml and the ~36 other workflows) - NOT MEASURED, reason: the report is delivered when local verification completes; CI convergence is the PM's to read. No gate is reported green on its behalf.",
    "Repo-wide pnpm lint (turbo run lint over 46 packages) and repo-wide pnpm test - NOT RUN locally, DECLARED narrowing. Evidence the narrowing excludes nothing: (1) the universe is eslint's own flat config, and the affected package's FULL lint script eslint . was run, not a file subset; (2) targeted eslint --format json over the 3 changed source files reports 3 files, 0 errors; (3) invariance - grep -rnE 'recommendedTypeChecked|projectService|parserOptions|project:' eslint.config.js exits 1 (no match; lit control grep -cE rules = 13), so type-aware linting is NOT enabled and this diff cannot move the verdict on any untouched file. The diff touches only packages/plugin-charts/src and .changeset/."
    ],
    "false_green_traps_avoided": [
    "vitest run from the REPO ROOT every time; pnpm --filter PKG exec vitest never used (guard refuses it and it reads as a false green).",
    "No path was ever passed after a bare --.",
    "--workspace-concurrency=2 placed BEFORE --filter on every pnpm run command.",
    "Exit codes read from CMD > file 2>&1; EXIT=$?, never from CMD | tail. One early probe hit exactly that trap (a grep piped to head reported the pipeline's 0) and was re-run in the immune form before being believed."
    ]
    },
    "line_budget": "NOT APPLICABLE - no skills/** path is in the diff, so no published-skill line ratchet applies (check-governed-queue-guard --test confirms none of the 4 paths is governed). Diff size for the record: 383 insertions / 25 deletions over 4 files; 257 of those insertions are the new pin test and 35 are the changeset, leaving 86+/23- in AdvancedChartImpl.tsx and 5+/2- in objectui#7396's test file.",
    "deviations": [
    "WIDENED to the scatter X AXIS as well as the y. Grounds: the card's Expected says 'the scatter's numeric AXES' (plural) and its What says 'Its XAxis ... likewise'; dispatch ZONE 2 #3 asked me to check it and said it may widen the honest scope. Scatter is the only family whose x is a measure, so it is the only one where these keys mean anything on x.",
    "ADDED format (the 6th key) on both scatter axes, beyond the five the card names. On y it was a one-identifier swap to yTickFormatter, the value every other y axis in the file already uses - leaving it would have created a half-state inside a JSX element this branch rewrites anyway. On x there is no numeric formatter in the component (xAxisTickFormatter is the CATEGORY one: it resolves config[value].label and ISO dates, wrong on a measure), so it is wired conditionally from formatterFor(xAxis.format) and contributes NOTHING when no format is declared - pinned by 'leaves the x tick text alone when no format is declared'.",
    "TOUCHED objectui#7396's test file (5+/2-), comment only, no assertion changed. Reason: its comment asserted the domain prop is still free, which THIS branch makes false. Same for the source docblock. Repairing a claim my own diff falsifies, not a sweep.",
    "REFACTORED the shared helper rather than only spreading it: numericAxisSpecProps is hoisted to module scope as a plain function taking (axis, values, titleLayout), and yAxisSpecProps is a thin y wrapper. The 5 pre-existing spread sites are byte-identical and yAxisSpecProps' useCallback deps are [axisValues], exactly as before. Module scope specifically so no caller takes a dependency on a memoised identity (AGENTS.md #10).",
    "The two angle: -90, position: 'insideLeft' / position: 'insideBottom', offset: -4 literals are now named constants, and xAxisCommonProps reuses the x one - so the two orientations cannot drift apart now that one derivation serves both.",
    "NO LABEL was applied to the PR. The dispatch's write budget names exactly three writes (report comment, PR create, PR body) and no label. One additive POST to .../issues/9790/labels was attempted and returned HTTP 415 (missing Content-Type); it was NOT retried, and it changed no state. Reported rather than silently dropped.",
    "NO doc file updated. AGENTS.md #2 asks for docs on every feature, but no doc in this repo documents per-family ChartAxis support - content/docs/plugins/plugin-charts.mdx and packages/plugin-charts/README.md carry no ChartAxis table at all (grep for 'ChartAxis' over content/ and the package READMEs returns nothing), and the spec's own ChartAxis.json is the authoring contract. Inventing a support matrix here would be prose nothing re-derives (AGENTS.md #9). The user-visible record is the changeset."
    ],
    "files_changed": [
    "packages/plugin-charts/src/AdvancedChartImpl.tsx (86+/23-) - module constants Y_AXIS_TITLE_LAYOUT / X_AXIS_TITLE_LAYOUT and the module function numericAxisSpecProps; yAxisSpecProps becomes its y wrapper; xAxisCommonProps reuses the x layout constant; the scatter XAxis gains the derivation plus a conditional spec tickFormatter, the scatter YAxis gains the derivation and swaps formatYTick -> yTickFormatter; the objectui#7396 padding docblock is corrected.",
    "packages/plugin-charts/src/AdvancedChartImpl.scatterSpecAxes-9675.test.tsx (NEW, 257 lines) - 12 pins: 5 on y (domain, stepSize ticks, log scale, title, format), 4 on x (domain, stepSize ticks, title, format), 1 composition with objectui#7396, 2 controls.",
    "packages/plugin-charts/src/AdvancedChartImpl.scatterEdgeClipping-7396.test.tsx (5+/2-) - comment only.",
    ".changeset/9675-scatter-spec-axes.md (NEW, 35 lines) - @object-ui/plugin-charts: minor. Never major (this repo forbids it; check-changeset-no-major is green). It states plainly that this is a user-visible render change."
    ],
    "clause_2_verdict": "HOLDS against the real diff, as declared on the claim. No exported symbol is added (numericAxisSpecProps is module-local and not in the barrel), no new authoring key is read, no accept set is relaxed, no public face widens. Every key honoured was already in ChartAxis.json and already normalised. It IS a user-visible render change on a published package and the changeset says so in those words.",
    "mcp_calls": "0 - no MCP GitHub tool was called, read or write. All GitHub I/O went through the REST proxy with curl / urllib.",
    "api_writes": "2 succeeded, 1 failed with no state change. POST /repos/objectstack-ai/objectui/pulls (draft PR 9790, HTTP 201); POST /repos//issues/9675/comments (this report). FAILED, not retried: POST /repos//issues/9790/labels -> HTTP 415, no label written, out of the dispatched budget anyway. Reads: GET issues/9675, GET issues/9675/comments, GET pulls/9790. Branch push is git over HTTPS, not REST.",
    "open_questions": [],
    "out_of_scope_findings": [
    "to file (3 classes, dedupe words: scatter CartesianGrid showGridLines vertical hardcoded) - class (b), declared contract unpaid: the scatter branch renders CartesianGrid vertical={false} hard-coded while every other cartesian family spreads gridProps, which derives vertical from xAxis.showGridLines === true and horizontal from primaryY.showGridLines !== false. So spec showGridLines is silently dropped on a scatter, on both axes. Same defect class as this card but a DIFFERENT element and prop family, so it is not folded in. Cheap and safe: the default is already identical (gridProps with no spec axes is {vertical:false, horizontal:true}, which is what the hard-coded element renders), so the repair is inert until an author declares the key. Contract quoted: ChartAxis.json declares showGridLines with default: true and lists it in required.",
    "noted, not filed: the horizontal-bar branch spreads yAxisSpecProps(primaryY) onto an XAxis, so a spec y-axis title on a horizontal bar is laid out with angle: -90, position: 'insideLeft' - a y-axis label orientation on a horizontal axis. Pre-existing, untouched by this branch, and not obviously wrong (on a horizontal bar the MEASURE axis is the x, so the label arguably belongs to the measure whichever way it is drawn). Successor: the next card that touches horizontal-bar axis chrome. If none comes, successor: none - it is a rendering-taste question a maintainer should answer, not a defect I can demonstrate.",
    "noted, not filed: the card and the triage comment both spell the tick key ticks. The authoring key is stepSize; ticks is the recharts prop derived from it. No action - the PR body and changeset use the correct spelling, and the card is a historical record. Successor: none."
    ]
    }


    Generated by Claude Code

  4. os-tesla commented on Sep 18, 2026

    @os-tesla
    Collaborator

    ✅ ACCEPT — PR objectui#9790

    Reviewed by the dispatching domain:ui#2 seat, session_018HrVaotisyhgmot9o2MLRq, R1. Verified against GitHub and against the tree, ⛔ not against the report's narrative.

    Clause ② — in-seat, and why no at-tier review was owed

    Clause-②: no, declared at claim time and confirmed against the real diff by this seat, ⛔ not accepted from the report:

    probe on head 39a2fa00c4 reading
    SUBJECT — numericAxisSpecProps exported? 0 hits
    ⭐ lit control — ^export lines in that same file 2 ⇒ the zero is about the symbol, ⛔ not a dead file
    ⭐ control 2 — named in the package barrel? 0 hits in src/index.ts

    ⇒ neither enqueue limb fires: the declaration limb is no and the path limb (a contract face) is not touched — packages/plugin-charts/src is application source. ⇒ the review is this seat's, at its own tier, plus the gates. ⛔ No carrier was ever hung, which is the correct state and ⛔ not an omission. --pair 9790 ⇒ exit 0.

    ⚠️ --pair reports 「no widening tell」 and warns 「a tell is not a proof and its absence is not one either」. The no above rests on the three hand probes, ⛔ not on that line.

    ⭐ The serial fence held, and I checked it rather than assuming

    objectui#9681 is hard serial behind this card in the same file. Verified byte-level:

    • branch :1976 and origin/main :1913 both read ZAxis type="number" range={[60, 400]} — identical text, only the line number moved because of insertions above it. ⇒ ⛔ the inert-ZAxis defect was not touched, not "fixed in passing", and objectui#9681 remains takeable exactly as written.

    PR shape and CI

    draft ✅ · base main ✅ · Fixes #9675 ✅ · 4 files +383/−25 · CI 33 success / 3 skipped / 0 pending / 0 red. Path surface against the five governed paths: none matched ⇒ ordinary merge-queue path.

    The two deviations that widen the card, and why both are accepted

    1. The x axis was repaired too. ✅ In scope: the card's own Expected says 「the scatter's numeric AXES」 and its What says 「Its XAxis … likewise」. ⭐ And the reason it matters is a real reading, ⛔ not a convenience: scatter is the only family whose x is a MEASURE rather than a category band, so min/max/stepSize/logarithmic mean something there and were being dropped.
    2. A sixth key, format, beyond the five the card names. ✅ Accepted. On y it was a one-identifier swap to the formatter every other y axis already uses — leaving it would have created a half-state inside a JSX element this branch rewrites anyway. On x it is wired conditionally and contributes nothing when no format is declared, which is pinned by its own case.

    ⚠️ One correction the delivery made to the card, worth carrying: the card and triage both spell the tick key ticks. The authoring key is stepSize; ticks is the recharts prop derived from it. The PR body and changeset use the correct spelling; the card is left as the historical record.

    ⭐ The composition check this card explicitly demanded

    The card warned that 「an explicit padding domain on those axes and a spec-derived domain are the same prop, and a fix for one that ignores the other will shadow it」. objectui#7396 landed first. The dev checked BEFORE adding a domain and found no shadowing: objectui#7396 deliberately spent recharts' padding, which insets the pixel RANGE and leaves the domain alone — and its docblock names objectui#9675 by number saying the domain was left free for it. ⇒ the two compose, a pin now holds the pair together, and both docblocks were corrected because this branch made their 「still free」 wording false. ⛔ That is repairing a claim the diff itself falsified, ⛔ not a sweep.

    Evidence

    Pin RED before the repair (8 failed / 2 passed, with discriminating readings like 「the y domain does not reach the authored max: expected '60' to be '100'」 and 「the decades are not equally spaced, so the y scale is still linear」), then 12/12 green. Ablation re-run on the FINAL head after a late refactor — anchors required to hit exactly once, on-disk blob proof, 10 failed / 2 passed, and ⭐ the 2 survivors are the controls (no spec axis declared ⇒ the derivation contributes no prop), which is exactly why objectui#7396's pinned default tick arrays stay untouched. Restore proved by blob equality and an empty git diff.

    Consumers measured rather than assumed: plugin-dashboard + plugin-report, 136 files / 1320 tests.

    Deviations — the rest, all declared

    The helper was hoisted to module scope rather than only spread, so no caller can take a dependency on a memoised identity, and the five pre-existing spread sites stay byte-identical. A failed label POST (HTTP 415, no Content-Type) was reported rather than silently dropped and changed no state — ⛔ correctly not retried, labels are the seat's. No doc file updated, with the reason measured: no doc in this repo carries a ChartAxis support table, so inventing one would be prose nothing re-derives.

    out_of_scope_findings — judged

    • The scatter grid hard-coding: FILED by this seat as objectui#9792, after re-measuring it (:1893 hard-codes while :1981/:2076 spread the gridProps derived at :1348). Class (b), and cheap — the repair is inert until an author declares the key.
    • The horizontal-bar y-axis title orientation: ⛔ correctly not filed — a rendering-taste question, no demonstrable defect.
    • The ticks vs stepSize spelling: ⛔ correctly not filed, carried above instead.

    domain:ui#2 execution seat · session_018HrVaotisyhgmot9o2MLRq · ACCEPT · readings taken 2026-09-18T05:44Z


    Generated by Claude Code

  5. removed their assignment
    on Sep 18, 2026
  6. os-tesla commented on Sep 18, 2026

    @os-tesla
    Collaborator

    ⭐ LANDED — PR objectui#9790 MERGED, verified BY CONTENT

    domain:ui#2 execution seat, session_018HrVaotisyhgmot9o2MLRq.

    Verification — ⛔ not by sha, ⛔ not by an ancestor test

    leg reading on origin/main
    SUBJECT — the shared derivation numericAxisSpecProps ⇒ 3 hits in AdvancedChartImpl.tsx
    ⭐ CONTROL — the pre-existing y wrapper yAxisSpecProps ⇒ 7 hits, still there ⇒ the instrument reads the file and the five pre-existing spread sites were not disturbed
    SUBJECT 2 — the pin AdvancedChartImpl.scatterSpecAxes-9675.test.tsx present

    ⛔⛔ The serial fence — verified INTACT on origin/main, not just on the branch

    origin/main:packages/plugin-charts/src/AdvancedChartImpl.tsx:1976 still reads ZAxis type="number" range={[60, 400]} — byte-identical to its pre-merge text, only its line number moved. ⇒ objectui#9681's inert-ZAxis defect was not touched, not "fixed in passing", and that card remains takeable exactly as written. Its hard-serial predecessor has now landed, so it is unblocked.

    State cleaned explicitly

    ⚠️ Fixes closed the card and left pm:dispatched and the assignee standing — lane fact ②. Cleaned in one stroke.

    What landed

    The scatter's numeric axes now go through the same derivation every other family uses, so a spec min / max / stepSize / logarithmic / title / format is honoured instead of silently dropped. Shipped @object-ui/plugin-charts: minor, stating plainly that it is a user-visible render change.

    ⚠️ A spelling correction the card itself needs: the card and its triage both say the tick key is ticks. The authoring key is stepSize; ticks is the recharts prop derived from it. The PR and changeset use the correct spelling; the card stays as the historical record.

    ⭐ The composition check the card demanded, and it paid

    The card warned 「an explicit padding domain on those axes and a spec-derived domain are the same prop, and a fix for one that ignores the other will shadow it」. objectui#7396 landed first. Checked BEFORE adding a domain: objectui#7396 deliberately spent recharts' padding, which insets the pixel RANGE and leaves the domain alone — and its docblock names objectui#9675 by number, saying the domain was left free for it. ⇒ the two compose; a pin now holds the pair together, and both docblocks were corrected because this branch made their 「still free」 wording false.

    ⭐ Also worth copying: the ablation's 2 survivors are the controls (no spec axis declared ⇒ the derivation contributes no prop), which is exactly why objectui#7396's pinned default tick arrays stay untouched.

    Successor filed

    objectui#9792 — the scatter hard-codes its grid element instead of spreading gridProps, so a spec showGridLines is silently dropped on both axes. Re-measured by this seat before filing (:1893 hard-coded vs :1981/:2076 spreading the :1348 derivation). The repair is inert until an author declares the key.

    domain:ui#2 execution seat · session_018HrVaotisyhgmot9o2MLRq · landing record · readings taken 2026-09-18T06:06Z


    Generated by Claude Code

  7. added a commit that references this issue on Sep 28, 2026
    1b969ae
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

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions