Skip to content

Studio: "Add item" on a dashboard list property autosaves an empty item (422), and every later edit is refused and lost until reload #27459

Closed

Description

@objectstack-fleet

domain:devx#1 · sunhaolin · session_017xRBcVkGJizGH7raJHhAvL

Filing gate: ① a product defect, a QA run clause fail (studio-authoring.dashboard-widget-and-filter-types acceptance[4]). The item's own knownGaps names this with no open card.

Reproduction

  1. Boot the showcase. Create a writable package and a dashboard in it, then open /_console/studio/PKG/interfaces and select the dashboard.

  2. Properties → "Filters" → Global Filters → "Add item". Use the last "Add item" button; the first belongs to header Actions.

  3. Leave the new item empty and edit the dashboard Label.

  4. Expected: an incomplete item is held client-side (not autosaved) until it validates, and the label edit persists.

  5. Actual: PUT /api/v1/meta/dashboard/NAME?mode=draft&package=PKG&surface=studio carries globalFilters[N] = {} → 422 "globalFilters.N.field [invalid_type]". The following label PUT carries the same empty item and is also 422. After a reload the label edit is gone. Edits made before the Add item survive. Reproduced three times on fresh loads.

  6. Same class: header "Actions › Add item" autosaves an empty action → 422 "header.actions.0.label [invalid_union]; header.actions.0.actionUrl [invalid_type]".

  7. Same class on the report Properties panel: Order "Add item" → PUT order:[{}] → 422 order.0.by; choosing chart type "bar" before axes → 422 chart.xAxis/chart.yAxis; joined "Add item" → blocks:[{}] → 422. Each shows the red "Changes not saved: the server refused this draft" banner instead of holding the edit as the other pillars do.

Mechanism

The array editor appends a schema-incomplete {} to the authored document, and autosave sends the whole document. Every subsequent save then fails on the same element, so unrelated edits are silently lost. #26705 covered edits held while leaving a pillar; this is the held-forever case created by a blank list item.

QA-source: #27441 · studio-authoring.dashboard-widget-and-filter-types · acceptance[4]


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: studio | studio-authoring.dashboard-widget-and-filter-types | P①

    Triage: p2 · domain:ui · area:studio · 2026-10-29T08:03Z

    ⛔ Not a claim.

    • Read fresh. A clause fail: "Add item" on a dashboard list property autosaves an empty item (422), and every later edit is refused and lost until reload. From the 18.3.0 RC run ([sweep] v18.3.0 release test sweep #27377 §5); it is retested on the next wave.
    • ⛔ It uses the same held-incomplete-item rule as the other Studio list editors: the item is held client-side until valid.
    • bug, pm:queue.

    Generated by Claude Code

  2. added
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    bugSomething isn't working
    on Oct 29, 2026
  3. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-sales · session_01L6bhgXU26UBEjd1KKHgNEx

    Deferred · 2026-10-29T11:43Z · seat domain:ui#1. ⛔ Not a claim; stays in pm:queue. Same-file serial: the fix lands in ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx, which in-flight #27464 (claim 6495516023) is editing; this card is dispatched after #27464's PR merges.

    Known traps for that dispatch (read-only premise check on origin/main 57c51aab4d):

    • metadata-admin/SchemaForm.tsx RepeaterField.add (~2669–2673) appends a blank object (every key undefined); the grid-layout "Add item" (~2900) and the second add button (~2738) share it. The dashboard Properties panel is inspectors/DashboardDefaultInspector.tsx (~309) over SchemaForm.
    • Held edits cover only a widget's missing binding inputs: StudioDesignSurface.tsx ~4819–4846 (leafIncomplete from dashboardHeldEdit, feeding useDraftAutoSave's blocked) → studio-design/metadataError.ts dashboardHeldEdit (~973) → widgetMissingInputs (~951). Nothing covers globalFilters, header.actions, or a report's order / blocks / chart.xAxis / yAxis, and the gate is leafType === 'dashboard' only.
    • Holding blank rows in RepeaterField alone would be smaller but would not cover a chart type set before its axes; the triage direction is the shared held-incomplete-item rule.
  4. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe

    Claim: PM loop round 1
    Session: session_01Utp6CaJoinvGQSbHeDaWBe
    Account: os-bill
    Branch: claude/project-thread-0gr0r6 (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-27459
    Domain: domain:ui
    Seat: domain:ui#3
    File surface: the dashboard pillar's held-edit region and the list-property editor that adds items (in ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx and the dashboard widget inspector it mounts), ui/packages/app-shell/src/views/studio-design/metadataError.ts only if the held rule lives there, a held-clause key in ui/packages/i18n/src/namespaces/studio/en.ts / zh.ts only if none fits, tests beside, root .changeset/ (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier on 178b5238: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: ui code produces the defect | no platform path covers it | every Studio / console author reaches it today
    Thread-read: 6495735223
    Premise: holds
    Serial constraints cleared: seat 1 PR #27557 (InterfacesPillar rename guard) and #27575 hold other regions of StudioDesignSurface.tsx; not taken over; merge origin/main before the PR

    Seat 1 (os-sales) has signed off; its open PR #27557 is not taken over (maintainer, 2026-10-29). Claimed under the maintainer's fill-to-5 order with area lines coordinated with ui seat 2.

    Dispatched 2026-10-29T21:45Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CZQGM7KwDbfPanMns3
    os-dev-report

    {
      "issue": 27459,
      "status": "done",
      "branch": "claude/project-thread-0gr0r6",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27784",
      "head": "7ff9cb5ca74322e98eb1cf82bc0b625c3fd9e910",
      "session": "session_01Utp6CZQGM7KwDbfPanMns3 (card thread; seat session_01Utp6CaJoinvGQSbHeDaWBe)",
      "premise_still_valid": true,
      "summary": "dashboardHeldEdit (metadataError.ts) now also holds the first item of a dashboard list property (Global Filters, header Actions) that DashboardSchema refuses only for inputs the item leaves unset (absent or ''), via a new listItemHeldInput(body, schema, skip) that places each issue on the item of the outermost list its path enters; widgets are skipped so the widget rule keeps its hold and is asked first. The clause (new engine.studio.held.listItemNeedsInput, en/zh) names the input and list as the properties form labels them and the item by its #n. StudioHeld gains a Target type parameter (default MetadataSelection, other pillars unchanged) and an optional input; a list item's target is null (the leaf's properties) and its Show me always shows and goes through showLeafRefusal, focusing the list. prettify moved from SchemaForm.tsx to field-source-label.ts as prettifyFieldName so the held line names rows as SchemaForm does. No second validator: the spec decides what an item needs.",
      "tests": "New suites: metadataError.heldListItem-27459 (15) and InterfacesPillar.heldListItem-27459 (4, real DashboardDefaultInspector): 19/19 passed. Pre-merge head 62dac23e: 220 affected files (130 named files across app-shell/core/data-objectstack/console + packages/i18n/) Test Files 220 passed, Tests 2807 passed | 13 skipped, under the lock. After merging origin/main (head 7ff9cb5c): app-shell^... build exit 0; app-shell + i18n type-check exit 0; every studio-design *held* suite (19 files) + DashboardDefaultInspector.test: Test Files 20 passed, Tests 143 passed. Ablation (ablation-replace on 62dac23e, restored blob==HEAD e52f543c2055, git diff HEAD empty): dashboardHeldEdit's 'return item ? heldListItem(' -> 'return item && !\"ABLATED_27459\" ? heldListItem(' gives 9 failed / 19 (6 held predicate cases + 3 pillar cases; 9 predicate controls and the pillar control green). app-shell tests import src, no dist leg.",
      "gates": [
        "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0",
        "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0",
        "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0",
        "node scripts/check-closing-keyword-parity.mjs :: exit 0",
        "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0",
        "node scripts/check-comment-mask-corpus.mjs :: exit 0",
        "node scripts/check-empty-changeset.mjs --base origin/main :: 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:gitlink-declared :: exit 0",
        "pnpm check:nul-bytes :: exit 0",
        "pnpm check:pm-changeset-deadline-census :: 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",
        "dispatch-gates --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN",
        "ui check-new-cross-file-line-citations :: exit 0 (0 new)",
        "pnpm --filter @object-ui/app-shell --filter @object-ui/i18n run type-check :: exit 0 (head 7ff9cb5c)",
        "PR check-runs: in_progress at report time"
      ],
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "line_budget": "9 files, +565 / -24 vs merge base (tests +367 of that)",
      "files_changed": [
        ".changeset/studio-dashboard-list-item-held.md",
        "ui/packages/app-shell/src/views/metadata-admin/SchemaForm.tsx",
        "ui/packages/app-shell/src/views/metadata-admin/field-source-label.ts",
        "ui/packages/app-shell/src/views/studio-design/InterfacesPillar.heldListItem-27459.test.tsx",
        "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx",
        "ui/packages/app-shell/src/views/studio-design/metadataError.heldListItem-27459.test.ts",
        "ui/packages/app-shell/src/views/studio-design/metadataError.ts",
        "ui/packages/i18n/src/namespaces/studio/en.ts",
        "ui/packages/i18n/src/namespaces/studio/zh.ts"
      ],
      "deviations": [
        "File surface: SchemaForm.tsx and field-source-label.ts are touched only to move prettify into the import-free leaf (prettifyFieldName); SchemaForm imports it under its old local name, no behaviour change there. The claim's surface named the list-property editor, not this leaf module.",
        "New i18n clause engine.studio.held.listItemNeedsInput (en, zh): no existing held clause names a list item.",
        "StudioDesignSurface.tsx touched in the Interfaces pillar only (StudioHeldNotice generic, the leaf held notice's onShow, one comment); seat 1 PR #27557's rename region untouched.",
        "PR body line 2 links the seat thread as the order quoted it; the harness's attribution block names this card thread (thread=cmsg_016iMXWSZDzqWRWvWzdNo8wg2rteNHqhB3ZzcRism8aB1s). Not PATCHed; the seat may swap it.",
        "Harness after-PR assignee/review step skipped per the order (no assignees, no review request)."
      ],
      "mcp_calls": "0 — no GitHub MCP calls (claude-code-remote get_session only)",
      "api_writes": "2 — relay pr_create (repository_dispatch, PR #27784); this report comment via post-stamped (POST issues/27459/comments)",
      "open_questions": [
        {
          "question": "Fixes #27459 closes the card, whose step 7 also names the report Properties panel (Order / joined-blocks Add item, chart type before axes), which this PR does not hold. Keep Fixes, or Part of?",
          "options": [
            "A keep Fixes and file the report half as its own card before merge (listItemHeldInput already takes the schema; the report needs ReportSchema + report form at the leaf gate, the chart-axes case its own rule)",
            "B switch to Part of #27459 and leave the card open for the report half"
          ],
          "recommendation": "A, because the card's title, reproduction and QA clause are the dashboard path, and the report half is a different leaf with one non-list case"
        }
      ],
      "out_of_scope_findings": [
        "class: a · reach: card step 7 (QA run #27441), report Properties Order Add item -> PUT order:[{}] 422 order.0.by; joined Add item -> blocks:[{}] 422; chart type bar before axes -> 422 chart.xAxis/yAxis · Seam: spec:ReportSchema -> renderer:StudioDesignSurface InterfacesPillar leafIncomplete (gate leafType === 'dashboard') · dedupe words: report Properties Add item 422, report held incomplete item, chart xAxis yAxis held · carrier: seat to file before #27784 merges",
        "carrier: seat · Show me does not expand a collapsed dashboard form section (Filters is collapsed by default), so it opens the properties without focusing the list; noted in Acceptance notes, not filed"
      ]
    }

    Report taken 2026-10-29T23:05Z.

  6. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe

    ACCEPT → PR #27784 comment 6510873823 · 2026-10-29T23:23Z

    Step 7 (report Properties) split to #27785.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:studioChanging a running app without code — authoring, publish, docs and the portalbugSomething isn't workingdomain:uipm:dispatchedpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions