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 }}
Repository navigation
dashboard pie/donut/funnel/treemap chart with two dimensions draws only the first second-dimension group, silently #27563
Filing gate: ① a user-visible product defect, found beside #27460 (PR #27560) by the dev's read of the chart renderer at head 13e084eb. reach: NOT MEASURED by render (a bare jsdom render probe was non-deterministic for pie and drew no marks for funnel/treemap); the code read is below.
Business reason: a dashboard pie, donut, funnel or treemap widget with two dimensions and one measure looks complete but shows only the first group of the second dimension; every other group is dropped and nothing on the chart says so. This is the same class #27460 fixed for sankey.
Reader who acts: the triage seat (first grading), then the implementer for the chart renderer (ui/packages/plugin-charts/src/AdvancedChartImpl.tsx).
Dedupe words: pie two dimensions, pivot series[0], funnel second dimension, treemap pivot dropped.
Symptom
With dimensions: [a, b] and one measure, buildChartSeries pivots b into one series per value. The pie/donut, funnel and treemap arms read series[0]?.dataKey only, so only the first b value is drawn.
Mechanism
ui/packages/plugin-charts/src/AdvancedChartImpl.tsx: the pie/donut, funnel and treemap arms bind series[0] and read no other series.
ui/packages/plugin-dashboard/src/DatasetWidget.tsx (SINGLE_SERIES family comment, objectui#11417) covers dropped MEASURES on these families, not a pivoted second dimension.
Unblocked · 2026-10-29T20:54Z: the blocker landed. PR #27560 (#27460) merged at 2026-10-29T20:03Z. Labels move from pm:blocked to pm:queue. Seat 2 dispatches this card next, and its Claim: follows.
Claim: PM loop round 1 · 2026-10-29T20:56Z
Session: session_01Utp6CY2n1JmZZKrHgtp9jC (seat; implementation by a card thread, mode:thread)
Account: os-bill
Branch: claude/project-thread-osge5f (the card thread's harness push branch, self-reported — the measured platform exception to claude/issue-N-slug)
Worktree: objectstack-issue-27563
Domain: domain:ui
Seat: domain:ui#2
File surface: ui/packages/plugin-charts/src/AdvancedChartImpl.tsx (pie/donut, funnel, treemap arms) and its tests; ui/packages/plugin-dashboard/src/DatasetWidget.tsx only if a refusal note lives there; i18n keys if a refusal adds text; a changeset; ⛔ packages/spec/** (a publish-time refusal is a spec door: stop with needs_decision), every server file, examples/**
Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: high
Clause-②: no (expected; the dev measures from the diff)
Metadata-protocol: none (expected; the dev measures from the diff)
Responsibility: the chart renderer's pie/donut, funnel and treemap arms binding series[0] only | buildChartSeries pivoting dimensions[1] into series is a fixed input | every dashboard author whose pie/donut/funnel/treemap widget has two dimensions and one measure, today
Thread-read: 6508108377
Premise: holds as filed (code read at 13e084eb); step 1 of the order re-confirms on origin/main after #27560 with a unit test per family
Serial constraints cleared: #27560 (#27460, same AdvancedChartImpl.tsx / DatasetWidget.tsx) merged 2026-10-29T20:03Z; sibling card #27491 (seat 2) may touch DatasetWidget.tsx, so whichever PR lands second rebases
Dispatch order: /mnt/project-files/ui-seat2/dispatch-27563.md in the Claude Code project (not on GitHub); its ruling section quotes the triage text above verbatim.
{
"issue": 27563,
"status": "done",
"branch": "claude/project-thread-osge5f",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27736",
"head": "d12c72c818c69ea25169f241868f87998e3ad941",
"session": "session_01Utp6CanXq6PY9nH1pZ5E5m (card thread; seat session_01Utp6CY2n1JmZZKrHgtp9jC)",
"premise_still_valid": true,
"summary": "Measured the premise: on origin/main 525ea3632 the pie/donut, funnel and treemap arms of AdvancedChartImpl draw series[0] only for a buildChartSeries pivot (stage x owner, sum amount): the treemap drew 3 one-level leaves, pie/donut/funnel each rendered one Pie/Funnel bound to the first owner. Fix per family: treemap draws every group as two levels (buildTreemapGroups: parent per first-dimension value, leaf per carried second-dimension cell, named 'stage / owner', unsized cells left out with the existing unsized-rows note per group, no-positive-magnitude refusal naming every group, leaf click drills to the cell); pie, donut and funnel refuse on the tile (OneSeriesFamilyRefusal in the ChartRefusal shell, data-chart-error one-series-family) naming every group, because a second series has no place on one ring or one funnel and a two-level ring is a new visual this card does not decide. groupSeries (sankeyFlowSeries renamed and shared) ignores comparison overlays. DatasetWidget hands every SINGLE_SERIES_CHART_FAMILIES family only the measure it renders (the 27460 sankey filter widened), so stored multi-measure widgets still draw their first measure. No spec, server or locale change; refusal copy is English like its siblings.",
"tests": "New AdvancedChartImpl.twoDimensionSingleSeries-27563.test.tsx (20) and DatasetWidget.twoDimensionSingleSeries-27563.test.tsx (12): 32/32 pass. Premise/ablation legs (git restore --source=525ea3632, trap restore, hash-object == HEAD blob and git diff HEAD empty): base renderer+widget 15 failed/17 passed (all subjects red, all controls green); base DatasetWidget only 8 failed (4 new two-measure controls + 4 singleSeriesMeasures-11417 TIE rows). plugin-charts+plugin-dashboard full vitest under the lock at 5d26a453: 297/298 files, the one red the ChartRenderer.yAxisUndrawn-10691 pie control (authored yAxis list on a pie now refuses; control updated, see open_questions). Then 38 files (the 10691 file, the 27563 renderer file, console/app-shell/chatbot/list chart tests, all plugin-report tests): 38 passed, 390 tests. At 4fb5e46c (after merging main): 6 files (27563 x2, 10691, 11417, 27460 sankey x2) 81 passed. plugin-charts and plugin-dashboard type-check exit 0. eslint touched files 0 errors.",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack derived 35 at 4fb5e46c (same list as before the merge); run at 4fb5e46c, changeset-reading gates re-run at d12c72c8 (later commits touch only the changeset); --ran: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. node scripts/check-adr-0087-registration.mjs --self-test :: exit 0; node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0; node scripts/check-empty-changeset.mjs --self-test :: exit 0; node scripts/check-sdui-manifest.mjs :: exit 0; node scripts/check-sdui-manifest.mjs --self-test :: exit 0; node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0; node scripts/release-pending-publish.mjs --self-test :: exit 0; pnpm --dir ui exec vitest run scripts/ :: exit 0; pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0; pnpm check:changeset-gate-self-tests :: exit 0; pnpm check:closed-ceremony-text :: exit 0; pnpm check:cross-package-test-inputs :: exit 0; pnpm check:dispatcher-error-vocabulary :: exit 0; pnpm check:driver-memory-census :: exit 0; pnpm check:engine-double-contract :: exit 0; pnpm check:error-status-conformance :: exit 0; pnpm check:gitlink-declared :: exit 0; pnpm check:nul-bytes :: exit 0; pnpm check:published-files :: exit 0; pnpm check:query-options-erasure :: exit 0; pnpm check:refd-timer-probe :: exit 0; pnpm check:skill-identifier-liveness :: exit 0; pnpm check:test-source-alias :: exit 0; pnpm check:tier-file-adoption :: exit 0; pnpm check:type-check-coverage :: exit 0; pnpm check:type-check-debt :: exit 0; pnpm check:undeclared-dep-imports :: exit 0; pnpm check:watch-hint-literal :: exit 0; pnpm check:where-matcher :: exit 0; node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0; node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0; node scripts/check-empty-changeset.mjs --base origin/main :: exit 0; node scripts/check-closing-keyword-parity.mjs :: exit 0; pnpm check:pm-changeset-deadline-census :: exit 0; node scripts/check-comment-mask-corpus.mjs :: exit 0. CI check-runs on PR #27736: in_progress at report time.",
"dogfood_battery": "n/a - no ! in the PR title and no narrowing arm",
"line_budget": "594 changed lines (+571/-23) vs origin/main: AdvancedChartImpl.tsx +180/-7, renderer test +233, DatasetWidget.tsx +18/-15, widget test +118, 10691 test +6/-1, changeset +16; under the 3000 human-merge threshold",
"files_changed": [
".changeset/27563-two-dimension-single-series.md",
"ui/packages/plugin-charts/src/AdvancedChartImpl.tsx",
"ui/packages/plugin-charts/src/AdvancedChartImpl.twoDimensionSingleSeries-27563.test.tsx",
"ui/packages/plugin-charts/src/ChartRenderer.yAxisUndrawn-10691.test.tsx",
"ui/packages/plugin-dashboard/src/DatasetWidget.tsx",
"ui/packages/plugin-dashboard/src/__tests__/DatasetWidget.twoDimensionSingleSeries-27563.test.tsx"
],
"deviations": [
"DatasetWidget.tsx is touched for the measure filter and two comments, not for a refusal note (the Claim lists it conditionally).",
"ChartRenderer.yAxisUndrawn-10691.test.tsx (an existing plugin-charts test) edited: its draw helper settles on the plot or the refusal and the pie control asserts the refusal; its subject (no y-axis note on a pie) is unchanged.",
"Refusal copy is an English literal like every sibling refusal; no locale keys.",
"The harness's post-PR assign/review step was skipped, per the maintainer's routing rule."
],
"mcp_calls": "0 - no GitHub MCP call; card, comments and PR read through gh api GET.",
"api_writes": "2 - relay pr_create (draft, no assignee, no reviewer, no labels) via run 40960895059, body read back identical (14107 bytes); this os-dev-report comment. Plus git pushes of the branch (not REST).",
"open_questions": [
{
"question": "Keep the renderer-wide reading (two or more non-comparison series on pie/donut/funnel/treemap = groups), which also changes charts outside the dashboard that carry several MEASURES, or restrict it to pivots?",
"evidence": "AdvancedChartImpl cannot tell a pivoted group from a measure. A chart block authoring a yAxis list on a pie (ChartRenderer.yAxisUndrawn-10691 control) and a page chart with one dimension and two measures (checkDashboardWidgetChartMeasureArity is attached to the dashboard widget schema only) used to draw their first measure silently; now pie/donut/funnel refuse naming every measure and a treemap nests the measures. #27560 made the sankey read series the same way.",
"options": [
"A - keep (this PR): one rule for all five single-series families, no partial chart anywhere; multi-measure treemaps nest measures of possibly different units.",
"B - mark pivot series in buildChartSeries (@object-ui/core published type, Clause-2 yes (widening)) and refuse/nest only on that marker; multi-measure charts keep drawing their first measure silently."
],
"recommendation": "A, because the silent first-measure draw is the same partial-chart class triage ruled out and the sankey already reads series this way; B if the seat wants this card scoped to the dashboard pivot only."
}
],
"out_of_scope_findings": [
"observation, not filed · reach: the dashboard publish door accepts dimensions [d0, d1] with one measure on pie/donut/funnel (the spec's single-series arm judges the measure count only) · triage's 'refuse at publish' half would be a spec door (packages/spec), outside this card; the tile refusal covers render now · dedupe words: publish refuse second dimension pie, single-series two dimensions · carrier: seat"
]
}
Activity
objectstack-fleet commentedon Oct 29, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 经营报表 | none | P②
Triage: p2 ·
domain:ui·area:reports· 2026-10-29T14:05Z⛔ Not a claim.
bug,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC
Blocked-by: #27560 · 2026-10-29T19:31Z
plugin-charts/src/AdvancedChartImpl.tsx, the two-dimension grouping it rewrites for sankey (dashboards: a sankey widget with two dimensions silently draws only the first category's flows #27460). A claim now would race it on the same file.pm:queue→pm:blocked. Not claimed; no work done.pm:queueand claims from the newmain. On the maintainer's word (2026-10-29T19:27Z), seat 2 does not take fix(plugin-charts): a two-dimension sankey draws every flow, not only the first group's #27560 over. Seat 2 stays seated (the wind-down was withdrawn) and resumes this card when fix(plugin-charts): a two-dimension sankey draws every flow, not only the first group's #27560 lands.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC
Unblocked · 2026-10-29T20:54Z: the blocker landed. PR #27560 (#27460) merged at 2026-10-29T20:03Z. Labels move from
pm:blockedtopm:queue. Seat 2 dispatches this card next, and itsClaim:follows.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC
Claim: PM loop round 1 · 2026-10-29T20:56Z
Session:
session_01Utp6CY2n1JmZZKrHgtp9jC(seat; implementation by a card thread,mode:thread)Account:
os-billBranch:
claude/project-thread-osge5f(the card thread's harness push branch, self-reported — the measured platform exception toclaude/issue-N-slug)Worktree:
objectstack-issue-27563Domain:
domain:uiSeat:
domain:ui#2File surface:
ui/packages/plugin-charts/src/AdvancedChartImpl.tsx(pie/donut, funnel, treemap arms) and its tests;ui/packages/plugin-dashboard/src/DatasetWidget.tsxonly if a refusal note lives there; i18n keys if a refusal adds text; a changeset; ⛔packages/spec/**(a publish-time refusal is a spec door: stop withneeds_decision), every server file,examples/**Container & model:
M,mode:thread,model: TIER_DEFAULT(dispatch-gates --tier: no path-derived mandate),effort: highClause-②: no (expected; the dev measures from the diff)
Metadata-protocol: none (expected; the dev measures from the diff)
Responsibility: the chart renderer's pie/donut, funnel and treemap arms binding
series[0]only |buildChartSeriespivotingdimensions[1]into series is a fixed input | every dashboard author whose pie/donut/funnel/treemap widget has two dimensions and one measure, todayThread-read: 6508108377
Premise: holds as filed (code read at
13e084eb); step 1 of the order re-confirms onorigin/mainafter #27560 with a unit test per familySerial constraints cleared: #27560 (#27460, same
AdvancedChartImpl.tsx/DatasetWidget.tsx) merged 2026-10-29T20:03Z; sibling card #27491 (seat 2) may touchDatasetWidget.tsx, so whichever PR lands second rebasesDispatch order:
/mnt/project-files/ui-seat2/dispatch-27563.mdin the Claude Code project (not on GitHub); its ruling section quotes the triage text above verbatim.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC
os-dev-report
{ "issue": 27563, "status": "done", "branch": "claude/project-thread-osge5f", "pr": "https://github.com/objectstack-ai/objectstack/pull/27736", "head": "d12c72c818c69ea25169f241868f87998e3ad941", "session": "session_01Utp6CanXq6PY9nH1pZ5E5m (card thread; seat session_01Utp6CY2n1JmZZKrHgtp9jC)", "premise_still_valid": true, "summary": "Measured the premise: on origin/main 525ea3632 the pie/donut, funnel and treemap arms of AdvancedChartImpl draw series[0] only for a buildChartSeries pivot (stage x owner, sum amount): the treemap drew 3 one-level leaves, pie/donut/funnel each rendered one Pie/Funnel bound to the first owner. Fix per family: treemap draws every group as two levels (buildTreemapGroups: parent per first-dimension value, leaf per carried second-dimension cell, named 'stage / owner', unsized cells left out with the existing unsized-rows note per group, no-positive-magnitude refusal naming every group, leaf click drills to the cell); pie, donut and funnel refuse on the tile (OneSeriesFamilyRefusal in the ChartRefusal shell, data-chart-error one-series-family) naming every group, because a second series has no place on one ring or one funnel and a two-level ring is a new visual this card does not decide. groupSeries (sankeyFlowSeries renamed and shared) ignores comparison overlays. DatasetWidget hands every SINGLE_SERIES_CHART_FAMILIES family only the measure it renders (the 27460 sankey filter widened), so stored multi-measure widgets still draw their first measure. No spec, server or locale change; refusal copy is English like its siblings.", "tests": "New AdvancedChartImpl.twoDimensionSingleSeries-27563.test.tsx (20) and DatasetWidget.twoDimensionSingleSeries-27563.test.tsx (12): 32/32 pass. Premise/ablation legs (git restore --source=525ea3632, trap restore, hash-object == HEAD blob and git diff HEAD empty): base renderer+widget 15 failed/17 passed (all subjects red, all controls green); base DatasetWidget only 8 failed (4 new two-measure controls + 4 singleSeriesMeasures-11417 TIE rows). plugin-charts+plugin-dashboard full vitest under the lock at 5d26a453: 297/298 files, the one red the ChartRenderer.yAxisUndrawn-10691 pie control (authored yAxis list on a pie now refuses; control updated, see open_questions). Then 38 files (the 10691 file, the 27563 renderer file, console/app-shell/chatbot/list chart tests, all plugin-report tests): 38 passed, 390 tests. At 4fb5e46c (after merging main): 6 files (27563 x2, 10691, 11417, 27460 sankey x2) 81 passed. plugin-charts and plugin-dashboard type-check exit 0. eslint touched files 0 errors.", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack derived 35 at 4fb5e46c (same list as before the merge); run at 4fb5e46c, changeset-reading gates re-run at d12c72c8 (later commits touch only the changeset); --ran: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. node scripts/check-adr-0087-registration.mjs --self-test :: exit 0; node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0; node scripts/check-empty-changeset.mjs --self-test :: exit 0; node scripts/check-sdui-manifest.mjs :: exit 0; node scripts/check-sdui-manifest.mjs --self-test :: exit 0; node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0; node scripts/release-pending-publish.mjs --self-test :: exit 0; pnpm --dir ui exec vitest run scripts/ :: exit 0; pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0; pnpm check:changeset-gate-self-tests :: exit 0; pnpm check:closed-ceremony-text :: exit 0; pnpm check:cross-package-test-inputs :: exit 0; pnpm check:dispatcher-error-vocabulary :: exit 0; pnpm check:driver-memory-census :: exit 0; pnpm check:engine-double-contract :: exit 0; pnpm check:error-status-conformance :: exit 0; pnpm check:gitlink-declared :: exit 0; pnpm check:nul-bytes :: exit 0; pnpm check:published-files :: exit 0; pnpm check:query-options-erasure :: exit 0; pnpm check:refd-timer-probe :: exit 0; pnpm check:skill-identifier-liveness :: exit 0; pnpm check:test-source-alias :: exit 0; pnpm check:tier-file-adoption :: exit 0; pnpm check:type-check-coverage :: exit 0; pnpm check:type-check-debt :: exit 0; pnpm check:undeclared-dep-imports :: exit 0; pnpm check:watch-hint-literal :: exit 0; pnpm check:where-matcher :: exit 0; node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0; node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0; node scripts/check-empty-changeset.mjs --base origin/main :: exit 0; node scripts/check-closing-keyword-parity.mjs :: exit 0; pnpm check:pm-changeset-deadline-census :: exit 0; node scripts/check-comment-mask-corpus.mjs :: exit 0. CI check-runs on PR #27736: in_progress at report time.", "dogfood_battery": "n/a - no ! in the PR title and no narrowing arm", "line_budget": "594 changed lines (+571/-23) vs origin/main: AdvancedChartImpl.tsx +180/-7, renderer test +233, DatasetWidget.tsx +18/-15, widget test +118, 10691 test +6/-1, changeset +16; under the 3000 human-merge threshold", "files_changed": [ ".changeset/27563-two-dimension-single-series.md", "ui/packages/plugin-charts/src/AdvancedChartImpl.tsx", "ui/packages/plugin-charts/src/AdvancedChartImpl.twoDimensionSingleSeries-27563.test.tsx", "ui/packages/plugin-charts/src/ChartRenderer.yAxisUndrawn-10691.test.tsx", "ui/packages/plugin-dashboard/src/DatasetWidget.tsx", "ui/packages/plugin-dashboard/src/__tests__/DatasetWidget.twoDimensionSingleSeries-27563.test.tsx" ], "deviations": [ "DatasetWidget.tsx is touched for the measure filter and two comments, not for a refusal note (the Claim lists it conditionally).", "ChartRenderer.yAxisUndrawn-10691.test.tsx (an existing plugin-charts test) edited: its draw helper settles on the plot or the refusal and the pie control asserts the refusal; its subject (no y-axis note on a pie) is unchanged.", "Refusal copy is an English literal like every sibling refusal; no locale keys.", "The harness's post-PR assign/review step was skipped, per the maintainer's routing rule." ], "mcp_calls": "0 - no GitHub MCP call; card, comments and PR read through gh api GET.", "api_writes": "2 - relay pr_create (draft, no assignee, no reviewer, no labels) via run 40960895059, body read back identical (14107 bytes); this os-dev-report comment. Plus git pushes of the branch (not REST).", "open_questions": [ { "question": "Keep the renderer-wide reading (two or more non-comparison series on pie/donut/funnel/treemap = groups), which also changes charts outside the dashboard that carry several MEASURES, or restrict it to pivots?", "evidence": "AdvancedChartImpl cannot tell a pivoted group from a measure. A chart block authoring a yAxis list on a pie (ChartRenderer.yAxisUndrawn-10691 control) and a page chart with one dimension and two measures (checkDashboardWidgetChartMeasureArity is attached to the dashboard widget schema only) used to draw their first measure silently; now pie/donut/funnel refuse naming every measure and a treemap nests the measures. #27560 made the sankey read series the same way.", "options": [ "A - keep (this PR): one rule for all five single-series families, no partial chart anywhere; multi-measure treemaps nest measures of possibly different units.", "B - mark pivot series in buildChartSeries (@object-ui/core published type, Clause-2 yes (widening)) and refuse/nest only on that marker; multi-measure charts keep drawing their first measure silently." ], "recommendation": "A, because the silent first-measure draw is the same partial-chart class triage ruled out and the sankey already reads series this way; B if the seat wants this card scoped to the dashboard pivot only." } ], "out_of_scope_findings": [ "observation, not filed · reach: the dashboard publish door accepts dimensions [d0, d1] with one measure on pie/donut/funnel (the spec's single-series arm judges the measure count only) · triage's 'refuse at publish' half would be a spec door (packages/spec), outside this card; the tile refusal covers render now · dedupe words: publish refuse second dimension pie, single-series two dimensions · carrier: seat" ] }objectstack-fleet commentedon Oct 29, 2026
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC
ACCEPT → PR #27736 comment 6509565003 (head
d12c72c8). Contract review not owed (Clause-②: no,Metadata-protocol: none). Landing through the merge queue.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC
Landed · 2026-10-29T22:31Z
d7625ea4500aa244c792d55b5d7668c80dbc10fecompletedby the PR'sFixeslineState:
pm:dispatchedremoved; the assignee stays as the record of who carried it.Generated by Claude Code