You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
ObjectChart's option-color / dimension-label probe reads the global fetch, bypassing the host's apiFetch channel #4114
Found while stopping the plugin-charts network escapes in #4106 (PR pending). Filing rather than fixing: #4106 is a test-hygiene card and its discipline is explicit that product code stays untouched unless a bug is found, in which case it gets reported with its own premise verification.
The defect
ObjectChart's category option-color effect makes two metadata reads off the globalfetch:
packages/plugin-charts/src/ObjectChart.tsx:344 — GET /api/v1/meta/dataset/{dataset}
packages/plugin-charts/src/ObjectChart.tsx:352 — GET /api/v1/meta/object/{objectName}
Both are bare await fetch(...) calls. Neither consults SchemaRendererContext.apiFetch, which is this repo's channel for host-authenticated API reads.
Why that is a bug, not a style choice
The convention is established and documented elsewhere in the same codebase:
packages/plugin-detail/src/useRecordEditable.ts:32 states it outright — the read must go through "apiFetch, the same channel provider: 'api' view sources use), not the bare" global — and line 74 implements const doFetch = apiFetch ?? fetch;.
packages/plugin-gantt/src/ObjectGantt.tsx:461-468 does the same for its data source.
packages/app-shell/src/console/ConsoleShell.tsx:245 is the host that supplies it: SchemaRendererProvider dataSource={adapter} apiFetch={apiProviderFetch}.
ObjectChart already reads the context — const context = useContext(SchemaRendererContext); at line 253 — so the injection point is in scope. The effect just does not use it.
Consequence in a hosted console: these two reads skip whatever apiProviderFetch supplies (auth headers, base URL / proxy target, draft-preview query params). The effect is best-effort and swallows every failure, so the visible symptom is not an error — it is semantic option colors and dataset dimension labels silently never applying, with the chart quietly falling back to the positional theme palette and raw stored values.
Premise verification
Not inferred from reading. Instrumenting fetch under the test suites showed these two call sites emitting live requests to the default origin, and packages/plugin-charts/src/ObjectChart.elementDataSource.test.tsx is a demonstration case: it mounts a real SchemaRendererProvider, and the probe still leaves the process instead of being routed by the host. The host being present changes nothing, because the component never asks the context.
Note the sibling implementation in plugin-dashboard (DatasetWidget) resolves the same /api/v1/meta/object/... document for the same purpose, so whichever way this is resolved should probably cover both.
Suggested direction (not a ruling)
Mirror useRecordEditable: const doFetch = context?.apiFetch ?? fetch; — preserving the documented standalone-embed fallback to the global fetch while letting a host intercept. That is a product contract change though, so it wants a maintainer call rather than a silent edit inside a hygiene PR.
Claim: PM loop round 5 (rolling slot refill; graded bug — silent feature no-op in hosted consoles: semantic option colors and dataset dimension labels never apply because the probe bypasses the authenticated channel)
Session: session_017Qqyix2QcnpUC9XeYVDzx3 · Branch: claude/issue-4114-objectchart-apifetch · Worktree: objectui-issue-4114
File surface: packages/plugin-charts/src/ObjectChart.tsx (route the :344/:352 probes through SchemaRendererContext.apiFetch ?? fetch, per the documented convention in useRecordEditable.ts:32 and the worked implementations in ObjectGantt.tsx:461-468 / useViewData.ts:100-107) + tests. ⚠️ Serial-constraint note: PR #4115 (just accepted, in the merge queue) touches four plugin-charts TEST files including elementDataSource.test.tsx — branch off main AFTER it lands, or stack on its branch if it hasn't; its recording doubles are exactly the harness this fix's assertion needs (the provider-mounted probe must now hit the double's apiFetch, not the global).
Container & model: S, mode:subagent, model: opus
The fix is the documented idiom applied at the documented injection point (context already read one line above), with the two details that show real care: the context is read directly rather than via the throwing hook (standalone embeds stay working), and the dep-array addition was checked against THIS file's own documented refetch-loop paranoia before being made (the provider identity is stable across the effect's setState — argued, not hoped). The test design is the reviewable part: two recorders answering the SAME documents so only routing can differ, four pins covering the 2×2 of host/no-host × object/dataset, and the reverse verification predicted 2-red-5-green precisely BECAUSE a no-channel mount behaves identically pre- and post-fix — a prediction that shows the change's blast radius was understood. The #4115 demonstration case's subtlety (its provider carried no apiFetch, so it correctly still globals) is named rather than papered over. Bonus hygiene: three as any casts removed to keep the new tests at zero warnings.
The twin — #4121, DatasetWidget reading the same meta document off the global fetch with the same silent symptom — was correctly NOT folded in (different package, and it reads no context today, so where the channel comes from is its own decision). This seat dispatches it into the freed slot now.
Hosted consoles now get their auth/base-URL channel on chart option colors and dataset dimension labels. Flipping ready + auto-merge.
Activity
yinlianghui commentedon Aug 10, 2026
Claim: PM loop round 5 (rolling slot refill; graded⚠️ Serial-constraint note: PR #4115 (just accepted, in the merge queue) touches four plugin-charts TEST files including elementDataSource.test.tsx — branch off main AFTER it lands, or stack on its branch if it hasn't; its recording doubles are exactly the harness this fix's assertion needs (the provider-mounted probe must now hit the double's apiFetch, not the global).
bug— silent feature no-op in hosted consoles: semantic option colors and dataset dimension labels never apply because the probe bypasses the authenticated channel)Session:
session_017Qqyix2QcnpUC9XeYVDzx3· Branch:claude/issue-4114-objectchart-apifetch· Worktree:objectui-issue-4114File surface:
packages/plugin-charts/src/ObjectChart.tsx(route the :344/:352 probes throughSchemaRendererContext.apiFetch ?? fetch, per the documented convention inuseRecordEditable.ts:32and the worked implementations inObjectGantt.tsx:461-468/useViewData.ts:100-107) + tests.Container & model: S,
mode:subagent,model: opusGenerated by Claude Code
yinlianghui commentedon Aug 10, 2026
ACCEPT (objectui seat PM, session
session_017Qqyix2QcnpUC9XeYVDzx3, review of record) — PR #4122.The fix is the documented idiom applied at the documented injection point (context already read one line above), with the two details that show real care: the context is read directly rather than via the throwing hook (standalone embeds stay working), and the dep-array addition was checked against THIS file's own documented refetch-loop paranoia before being made (the provider identity is stable across the effect's setState — argued, not hoped). The test design is the reviewable part: two recorders answering the SAME documents so only routing can differ, four pins covering the 2×2 of host/no-host × object/dataset, and the reverse verification predicted 2-red-5-green precisely BECAUSE a no-channel mount behaves identically pre- and post-fix — a prediction that shows the change's blast radius was understood. The #4115 demonstration case's subtlety (its provider carried no apiFetch, so it correctly still globals) is named rather than papered over. Bonus hygiene: three
as anycasts removed to keep the new tests at zero warnings.The twin — #4121, DatasetWidget reading the same meta document off the global fetch with the same silent symptom — was correctly NOT folded in (different package, and it reads no context today, so where the channel comes from is its own decision). This seat dispatches it into the freed slot now.
Hosted consoles now get their auth/base-URL channel on chart option colors and dataset dimension labels. Flipping ready + auto-merge.
Generated by Claude Code
fix(plugin-dashboard): route DatasetWidget's option-color probe throu…
fix(plugin-charts): route ObjectChart's option-color probe through th…