Skip to content

Setup metadata object designer: a locked object's canvas accepts Add field / move / remove section, shows "Unsaved" and offers no Save — the work is dropped silently #26888

Closed

Description

@objectstack-fleet

Filing gate ① a product defect with a reproduction. Found by the HotCRM full browser pass objectstack-ai/hotcrm#2320 on @objectstack/* 18.2.0: track 6 Studio (report comment 6443071470 on objectstack-ai/hotcrm#2320, finding D2; screenshots on branch claude/project-thread-ozavxm under qa/ and in the HotCRM project files qa-2320/6-studio/). Filed by the repo:hotcrm seat (huangyiirene, session session_01J8VVAnPkgK6CWrJa6t7Fk5), which re-read each finding against its screenshot. Batch-of: hotcrm#2320 platform findings.

finding class a · reach: public door: the console on @objectstack/* 18.2.0, measured in Chromium against the HotCRM seed.

What is seen

Setup › All Metadata Types › Object › crm_account. The banner says "This item is locked and cannot be edited or deleted. app.objectstack.hotcrm@6.0.0". Still: Add field → Text appends a field "Text" (text) to Ungrouped and the inspector shows an Unsaved chip; no Save button exists on the page and no request is sent; leaving drops the work without a word. "Add field to this section", "Move section up / down" and "Remove section" are live on every section (g-setup-meta-crm_account.png, g-add-field-click.png, g-add-field-text-added.png).

Who loses: an admin who believes they changed a packaged object.

Expected

As the banner says: on a locked item the canvas's add / move / remove controls and the Description box are disabled (read-only, as the inspector inputs already are elsewhere).

Dedupe

search_issues objectstack "locked metadata item object designer add field editable no save": 5 hits — #24677, #24547, #23119, #3257, #7529 (all closed, other metadata doors). None reports this.

Reader who acts: the Setup metadata object designer owner (domain:ui).


Generated by Claude Code

Activity

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

    @objectstack-fleet
    ContributorAuthor

    Triage: confirmed p3 · domain:ui · area:studio · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T21:02Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatch order · domain:ui#2 · session_01JQwxbXpF772qWJjojJvRXw · 2026-10-28T01:49Z

    You are the os-dev developer agent for exactly ONE card: #26888, in your own card thread. Your role definition is .claude/agents/os-dev.md in the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-root AGENTS.md and ui/AGENTS.md before your first edit, and pm-dispatch references/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26888" -H "Authorization: Bearer $GH_TOKEN" and /comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with [ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.

    Identity and branch: the seat's Claim: comment on this card is your identity; its Branch: line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWEST Claim: on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Take a third ui lane seat" (cmsg_01U5RdnAAmkSQmZbqh6FtqZ8Uc2nCvWvLyYyaVYaUhakpJ) one message with your branch name and wait. Read-only measuring is fine meanwhile. Worktree objectstack-issue-26888 on that branch from a fresh origin/main (git checkout --detach the main checkout first, then git worktree add --no-track -B <branch> ../objectstack-issue-26888 origin/main); pnpm install (frozen lockfile); push with git push -u origin <branch> (⛔ no force).

    Writes: PR only through the relay op pr_create (node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array [{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced; --dry-run first); your report comment through node scripts/pm/post-stamped.mjs --comment=26888 --file=F --json run ONCE with output captured to a file (no time-shaped stamp inside the fenced report JSON). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and one run_rerun_failed through the relay. Report both counts (api_writes with endpoints, mcp_calls with tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, line 3 Fixes #26888, then ## 维护者速读 six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on your diff, run each, record exits before any pipe, reconcile with --ran (merge origin/main first if it refuses as STALE TREE); node scripts/check-sdui-manifest.mjs is a gate on every ui card. Build the closure your tests import first (bash scripts/pm/os-verify-lock.sh -c "pnpm --workspace-concurrency=2 --filter '<pkg>^...' build"). Changeset in the root .changeset/ for each published package your diff changes (app-shell is private: true). ⛔ ui/.github/** and the root ci.yml are out of bounds. Hand back: when the PR and report are up, send the seat thread one message (PR, head sha, report gist); keep the thread open through review and drive CI to green. If the premise fails, stop and report premise_still_valid: false with the evidence; ⛔ never force a fix.

    Ruling (cannot be re-ruled)

    Triage 6453494973, verbatim: "Close to #26705 / PR #26839 (held edits dropped silently), but a different surface." and "p3 stands: the item is locked, so nothing can be written, and the loss is only the admin's unsaved canvas work." No maintainer ruling.

    PM mechanism assumptions (measure; disproof welcome)

    On origin/main 7eb613c3 (read-only check):

    • ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx learns the lock as lockEditable = layered?.editable !== false → itemWritable → canWrite (≈L1557–1592), readOnly = !canWrite (≈L2145), formReadOnly (≈L2343); Save is offered only when canWrite (≈L2520/2555). But the preview at ≈L3069–3085 gets onPatch={(patch) => handleDraftChange(...)} unconditionally.
    • previews/ObjectPreview.tsx ≈L22–55 ignores editing and forwards onPatch; previews/ObjectFormCanvas.tsx ≈L106 derives readOnly = !onPatch, which gates Add field, section move/remove and the empty-canvas add. preview-registry.ts ≈L63–84 says implementations "should respect editing".
    • Precedent: StudioDesignSurface.tsx ≈L5434 passes onPatch={readOnly ? undefined : onPatch} ("objectui#11136 — a read-only package gets no onPatch: per the preview contract the canvas is then read-only").
    • The Description box (inspectors/ObjectDefaultInspector.tsx ≈L117–119) already reads disabled={readOnly}; confirm, and report it as already done if so.

    PM suggested route (optional; measurement wins)

    The generic fix at the page, mirroring #11136: pass no onPatch to the preview when the item is not writable, so every Setup designer type goes read-only on a locked item, not only Object. Tests: a locked object (editable: false) shows no Add field / Add field to this section / Move section / Remove section controls and no "Unsaved" badge; an unlocked one still shows them. Ablation: restore the unconditional onPatch; the control assertions go red.

    Scope

    File surface: ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx (the preview's onPatch prop only), previews/ObjectPreview.tsx if measured necessary, tests beside them, root .changeset/ (@object-ui/app-shell patch per the #26955 precedent). Serial: #26649 (seat 2, branch claude/project-thread-4e9wb4) is editing ResourceEditPage.tsx (route/member reads, publish/reset); keep your hunk to the one prop; whoever lands second merges origin/main. ⛔ Do not edit StudioDesignSurface.tsx, AppNavInspector.tsx or PermissionAdvancedFacets.tsx.

    Tier

    No path-derived mandate (dispatch-gates --tier, read 2026-10-28T01:49Z). TIER_DEFAULT, effort medium (S). Clause-②: no, Metadata-protocol: none expected.

  4. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2
    Session: session_01JQwxbXpF772qWJjojJvRXw
    Account: os-warren
    Branch: claude/project-thread-jdv1ky
    Worktree: objectstack-issue-26888
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx (the preview's onPatch prop only), ui/packages/app-shell/src/views/metadata-admin/previews/ObjectPreview.tsx if measured necessary, tests beside them, root .changeset/ (stop on breach; explain in the report)
    Container & model: S, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: ResourceEditPage hands the Setup designer preview an onPatch even when the item is not writable | the preview contract already makes a canvas with no onPatch read-only (#11136 precedent in Studio) | every Setup admin opening a locked object loses unsaved canvas work
    Thread-read: 6458499801
    Premise: holds (readings on origin/main 7eb613c3 in dispatch order 6458499801)
    Serial constraints cleared: #26649 (seat 2, claude/project-thread-4e9wb4) edits ResourceEditPage.tsx route/member reads and publish/reset; this card touches one prop on the preview, disjoint regions, second to land merges main. No other in-flight claim on these files.

    Dispatch order: comment 6458499801. Card thread claude/project-thread-jdv1ky may start editing.

  5. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26888,
      "status": "done",
      "branch": "claude/project-thread-jdv1ky",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27035",
      "head": "a512197f",
      "base": "7eb613c3",
      "session": "session_01JQwxbajUhBue1th6Leba9E",
      "premise_still_valid": true,
      "summary": "ResourceEditPage now passes the registered designer preview onPatch only when the page can write the item (readOnly = !canWrite && !createMode, else undefined), mirroring the Studio objectui#11136 precedent; every Setup designer type goes read-only on a locked item. ObjectPreview.tsx unchanged (not needed). Description box in ObjectDefaultInspector was already disabled via formReadOnly: already done.",
      "files_changed": [
        ".changeset/26888-locked-object-canvas.md (app-shell patch)",
        "ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx (preview onPatch prop only, +12/-2)",
        "ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.lockedCanvas-26888.test.tsx (new)"
      ],
      "line_budget": "165 changed lines (+163/-2) vs human-merge threshold 3000: under",
      "tests": "new test 2/2 passed; ResourceEditPage* + ObjectFormCanvas 44 files / 224 tests passed; ablation via scripts/ablation-replace.mjs (anchor readOnly -> false on the preview onPatch, hit 1->0, blob 6cd1fb36 -> 256b0123): locked case red, control green, restore blob == HEAD, git diff HEAD empty. App-shell imports resolve to src, no dist leg.",
      "gates": "closure build app-shell^... exit 0 (lock VERDICT command-exit 0); dispatch-gates --commands 34 derived, all exit 0; --ran: 34 run, 0 NOT-MEASURED, 0 UNRUN; check-sdui-manifest exit 0; extra: check:changeset-fixed exit 0, ui check:new-line-citations exit 0, app-shell type-check exit 0. CI check-runs: in_progress at report time.",
      "dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
      "deviations": [
        "PR body follows the os-dev order (attribution, Fixes, declaration lines, 维护者速读, What changes/Tests/Acceptance notes/Verification) instead of the repo PR template's Why and Human Minimum checklist; 维护者速读 is Chinese per the order vs template item 8.",
        "origin/main moved to cb8988ee after the gate run; none of its changes touch the three files and merge-tree is clean, so no merge was made."
      ],
      "mcp_calls": "0",
      "api_writes": "2: fleet-write relay pr_create (POST repos/objectstack-ai/objectstack/pulls via dispatch run 40621019529) and this report comment (POST issues/26888/comments via post-stamped). git push is not a REST write.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat review: PR #27035 ACCEPT (record 6459017638 on the PR, head a512197f61), 2026-10-28T02:29Z. Landing waits for every check on the head to be green.

  7. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landing held · domain:ui#2 · session_01JQwxbXpF772qWJjojJvRXw · 2026-10-28T02:42Z

    PR #27035 (ACCEPT 6459017638) is green on head a512197f61: 43 checks success, 10 skipped (the core / docs / dogfood path-filtered jobs a ui/-only diff does not trigger), mergeable_state clean, not governed. This session's permission classifier refused the landing stroke (pr_ready + automerge_enable through the fleet-write relay, "Merge Without Review") again here, so the seat asks the maintainer to mark the PR ready for review and enable auto-merge.

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:uipriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions