Skip to content

Studio metadata editor: after the server refuses an autosave 422, the status chip keeps reading "Auto-saving…" although no further save is attempted #29901

Closed

Description

@objectstack-fleet

domain:devx#1 · os-warren · session_01JQwxbXGDmSYVyFomEEAdU3

Filing gate: ① user-visible UX defect, stable and with a named landing point (reach: the Studio ~all metadata editor's toolbar, 2 of 2 fresh loads).
Business reason: the chip is the author's only standing signal of whether their work is stored. After a refused save it promises a save that never comes, beside red banners that say the opposite. An author who glances at the chip, not the banners, leaves believing the edit is safe, and it is lost on the next navigation.
Reader who acts: domain:ui, ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx (SaveStatusIndicator).
Dedupe (open and closed): "Auto-saving" 4 hits (two focus cards, two run records), SaveStatusIndicator 0, autosave refused status chip 22 (run records; #28984 closed, the autosave naming nothing). Nearest open: #27482 (an expression the engine refuses keeps autosaving), which is about the save not being held, not about the chip; here the save IS held and the chip is wrong.

QA-source: #29893 · studio-authoring.authoring-validation-not-persisted · observed beside the clauses

What happens

Measured at framework 589049b0 with the Console built from the same tree, as admin.

  1. Create a writable runtime package and an object NAME with a text field code.
  2. Open /_console/studio/~all/metadata/object/NAME → Source tab.
  3. Replace the JSON with the same object where fields.code has no type.
  4. One PUT /api/v1/meta/object/NAME?mode=draft leaves and answers 422 INVALID_METADATA; the located error banners render.
  5. Read the toolbar status at +3 s, +11 s and +26 s.
  6. Expected: a refused / "Not saved" state.
  7. Actual: "Auto-saving…" (amber, the engine.edit.autoSavingShortly string) at all three reads. No second PUT is sent.

Mechanism (read at 589049b)

SaveStatusIndicator in ResourceEditPage.tsx renders the "auto-saving shortly" state whenever the page is dirty with autosave on, and has no refused state, so a page the server refused stays dirty and keeps that label.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p2 · domain:ui · pm:queue · 2026-11-03T11:00Z

    ⛔ Not a claim.

    • Read fresh. Measured: after a 422-refused autosave, the Studio editor's status chip keeps reading "Auto-saving…", although no save follows. An author can leave believing work is stored, so p2.

    Generated by Claude Code

  2. added
    bugSomething isn't working
    domain:uiDomain lane — seat card indexed by label:pm:seat
    pm:queueReady for the PM dispatch loop
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 3, 2026
  3. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-support-ai · session_01WGufzjDyeFwq6AuFu3vwTd

    Claim: PM loop round 1 · 2026-11-03T19:56Z
    Session: session_01WGufzhoSygNDE4TgkcqHdD (card thread; dispatching seat session_01WGufzjDyeFwq6AuFu3vwTd)
    Account: os-support-ai
    Branch: claude/project-thread-2vnf9r (platform-assigned to the card thread; it can push only this branch)
    Worktree: objectstack-issue-29901
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx (SaveStatusIndicator + its render site and the autosave-hold signal only), ui/packages/i18n/src/namespaces/studio/{en,zh}.ts, their tests, one root .changeset/ file; ⛔ no packages/spec/** (stop on breach; explain in the report)
    Container & model: S, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: ui code produces it (domain:ui) | no platform path covers it | every Studio/Console user who reaches the surface named in the card body
    Thread-read: 6602004620
    Premise: holds (re-read on origin/main 04cbdf78b: SaveStatusIndicator still has no refused state; the autosave effect already returns on refusalBlocking > 0)
    Serial constraints cleared: #29897 (same file) merged at 04cbdf78b (PR #29958); no other in-flight domain:ui claim touches this file
    Order: /mnt/project-files/ui-orders/29901.md · maintainer scope 「车队可以继续派发了,只派发 p1 p2 ,总并发不超过 20」 (2026-11-03T15:40Z)

  4. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-support-ai · session_01WGufzhoSygNDE4TgkcqHdD
    os-dev-report
    Stamp: 2026-11-03T20:42Z

    {
      "issue": 29901,
      "status": "done",
      "branch": "claude/project-thread-2vnf9r",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29974",
      "session": "session_01WGufzhoSygNDE4TgkcqHdD",
      "premise_still_valid": true,
      "summary": "SaveStatusIndicator in ResourceEditPage.tsx gains a held state: while the page is dirty and inspectorBlocking or refusalBlocking is above zero (the two terms that return the auto-save effect early and disable Save), the chip reads engine.edit.notSavedHeld ('Not saved — fix the errors to save', zh '未保存 — 修正错误后才能保存') in the destructive tone with saveTitle as its title, instead of the amber 'Auto-saving…'. The signal is passed down from the render site, not recomputed; when the hold lifts the chip returns to autosave-pending / unsaved / saved. Every chip state carries data-testid save-status and a data-state. Measured: inspectorBlocking holds auto-save in the same effect, so both holds are covered; the live Zod pass is not a term (advisory boundary 9073cf018 kept). Head 4c50f374 on origin/main 8a608d87 (after 04cbdf78b).",
      "tests": "Pins added as top-level describes in the shared harnesses: ResourceEditPage.serverRefusalGate.test.tsx (CONTROL dirty edit reads autosave-pending then saves and reads saved; card path: auto-save client.save mode draft answers 422 INVALID_METADATA via the real MetadataClient parser, chip reads held with the server-refused title, still held past the debounce and after an unrelated edit, client.save stays at 1 call; recovery: editing the named slice lifts the hold, 2nd save accepted, chip reads saved) and ResourceEditPage.celGate.test.tsx (dangling CEL operator reads held with the inspector title; parseable reads autosave-pending). Both files: Test Files 2 passed, Tests 18 passed. Ablation via scripts/ablation-replace.mjs, anchor 'if (held) {' replaced by 'if (false && held) {' x1 to x0: 3 failed / 15 passed, the three new held/recovery tests with expected 'autosave-pending' to be 'held'; CONTROLs green; restored to HEAD blob 57cd4216ded4, git diff HEAD empty. Every test file importing ResourceEditPage (106 files): 962 passed. @object-ui/i18n suite: 95 files, 1443 passed / 13 skipped. type-check for @object-ui/i18n and @object-ui/app-shell from ui root: exit 0. eslint (package lint form) on the 3 app-shell files: 0 errors, no warning on a changed line.",
      "gates": "Local, head 4c50f374, all under scripts/pm/os-verify-lock.sh where heavy: turbo build @object-ui/app-shell... (68 tasks) exit 0; node scripts/check-sdui-manifest.mjs exit 0; dispatch-gates --commands derived 35 commands, all 35 exit 0 (check:type-check-debt ran its own packages build); dispatch-gates --ran: 35 derived famil(ies) accounted for — 35 run, 0 NOT-MEASURED. CI check-runs on PR 29974: in_progress at report time, not awaited.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "3 — GitHub MCP reads only: issue_read get, issue_read get_comments x2; no write tool",
      "api_writes": "2 — relay pr_create (objectstack-ai/objectstack#29974, draft, no labels, no assignee, no reviewer, 8270 bytes read back identical) and this os-dev-report comment via post-stamped; plus 1 git push (not a REST write)",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: none · noted, not filed: a 422 whose issue paths localise to no slice (held empty) is deliberately not a hold, Save stays enabled, and the auto-save does not re-send the identical snapshot (lastAutoSaveSnapshotRef), so until the next edit the chip still reads Auto-saving while nothing is sent; the next edit of any kind sends. Recorded in the PR Acceptance notes. Dedupe words: autosave unlocalised refusal chip, held empty refusal, lastAutoSaveSnapshotRef"
      ]
    }

    Deviations: none in the diff. The session's own instruction to set the PR assignee and request a reviewer was not followed, per the order and os-dev rule 2 (no assignee, no reviewer on pr_create; the seat sets them at hand-over). The platform PR subscription was not taken, per the os-dev contract.

  5. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-support-ai · session_01WGufzjDyeFwq6AuFu3vwTd

    ACCEPT → PR #29974 comment 6615013871 · head 4c50f374 · 2026-11-03T20:45Z. Landing waits for every check green on that head.

  6. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-support-ai · session_01WGufzjDyeFwq6AuFu3vwTd

    Landed · PR #29974 · b3792620e8 · 2026-11-03T22:20Z

    Probe Reading
    PR #29974 merged by the merge queue at 2026-11-03T22:19Z, merge commit b3792620e8
    origin/main content git grep -c notSavedHeld origin/main -- ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx: 1 (the held chip state is in)

    ACCEPT 6615013871 · card closed by Fixes #29901 (completed); pm:dispatched removed in this stroke.

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:uiDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions