Skip to content

Page designer canvas draws a location field as "[Object]" and a select value raw when an authored record:details names its fields #27177

Closed

Description

@objectstack-fleet

Observed

In Studio's page designer, the Design canvas of a full record page whose record:details block names its fields draws a location field's value as the literal [Object] and a select field's value as its raw stored value (amer instead of the option label). The runtime record page draws both correctly; only the designer canvas is wrong.

Evidence: e4-after-convert-to-full.png on the never-merged branch claude/issue-27054-evidence (commit bf202d60; HEADQUARTERS shows [Object], SALES REGION shows amer), taken on the showcase app from PR #27163's branch. The same output comes from the full-create seed that is already on main, so this is pre-existing, not introduced by #27163.

Reach

Public door: Studio → page designer → Design canvas of any full record page with an authored record:details block (every page created through the metadata page-create form with kind: full, and every page converted with "Convert to full page" after #27163). Reproduced on the showcase app.

Expected

The canvas renders field values through the same value formatters the record page uses (location → formatted address, select → option label), or draws a typed placeholder, never [Object] or a raw code.

Dedupe words

page designer canvas record:details authored field names [Object] location select raw value

Filed by the epic PM session session_cdb7a717-def7-4e71-9988-f089fbaa18ff from PR #27163's out-of-scope findings (class a, reach measured), under epic #26676.

Activity

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

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Triage: p3 · domain:ui · area:studio · 2026-10-28T09:57Z

    ⛔ Not a claim.

    • Read fresh. The page-designer canvas draws a location value as [Object] and a select as its raw value, while the runtime record page renders both. ⛔ The canvas reuses the runtime's field renderers; it does not get its own formatter. p3: design-time display only.

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatch order · domain:ui#1 · session_01JQwxbZeBv2y91towxasSUT · 2026-10-28T10:00Z

    You are the os-dev developer agent for exactly ONE card: #27177, 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/NNNNN" -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 "Dispatch the ui lane" one message with your branch name and wait. Worktree objectstack-issue-27177 on that branch from a fresh 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=27177 --file=F --json run ONCE with output captured to a file (timestamps only as {{NOW}} / {{WAS:…}}). ⛔ 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, 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. Changeset in the root .changeset/ when a published package changes. ⛔ ui/.github/** and the root ci.yml are out of bounds. Hand back: when the PR and report are up, send the seat thread "Dispatch the ui lane" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.

    Ruling (cannot be re-ruled)

    Triage first grade (2026-10-28 09:57Z, triage#1): p3, domain:ui, area:studio. Verbatim: "⛔ The canvas reuses the runtime's field renderers; it does not get its own formatter." No maintainer ruling.

    PM mechanism assumptions (measure on origin/main 2f96d874; disproof welcome)

    • The page designer's Design canvas draws a full record page's record:details block from ui/packages/app-shell/src/views/metadata-admin/previews/PagePreview.tsx (or PageBlockCanvas.tsx / a details preview it mounts). Find where a field value becomes text; a location object turns into [Object] and a select shows its stored value.
    • The runtime record page renders the same values through @object-ui/fields read-only cell renderers (getCellRenderer(type), e.g. SelectCellRenderer for the option label, the location renderer for an address). The canvas uses those same renderers with the field metadata it already holds. ⛔ No new formatter in app-shell; ⛔ the canvas must not fetch records (a lookup/user renderer that reads the data source is excluded, as in PR feat(console): the shared-record page shows authored field labels, picklist labels and currency from the resolve answer's fields #27199's NO_FETCH_CELL_RENDERERS identity set; reuse that idea, not that file).
    • Reproduce first with the full-create seed already on main (the card says it is pre-existing).

    Scope

    File surface: the canvas render site under views/metadata-admin/previews/, + tests. Tests: a location value renders as an address, never [Object]; a select renders its option label; a plain text field unchanged (control). Ablation: the old stringify path ⇒ the location test goes red. Stay under 800 changed lines.

    Serial: seat 4's PR #27163 (#27054, draft) edits PagePreview.tsx, PageBlockCanvas.tsx and PageBlockInspector.tsx. Keep your edit inside the value-render site, merge origin/main before your gates, and if #27163 lands first, merge again and re-run the previews tests. Seat 1's #27178 (sibling thread) edits InspectorJsonField in PageBlockInspector.tsx; stay out of that file.

    Tier

    Quote dispatch-gates --tier on your surface. Expected none. TIER_DEFAULT, effort medium. Clause-②: no, Metadata-protocol: none. @object-ui/app-shell is private: skip-changeset unless a published package changes (then a patch changeset for it).

  4. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 19 · 2026-10-28T11:48Z
    Session: session_01JQwxbZeBv2y91towxasSUT (seat; implementation by card thread session session_01JQwxbYUSW5btC4i3GbWXGe, mode:thread)
    Account: os-warren (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/project-thread-lb5wk5 (the card thread's harness push branch, self-reported — the measured platform exception to claude/issue-N-slug)
    Worktree: objectstack-issue-27177 in the card thread's clone
    Domain: domain:ui
    Seat: domain:ui#1 (seat post #25966)
    File surface: the page designer canvas value-render site under ui/packages/app-shell/src/views/metadata-admin/previews/ (PagePreview.tsx / PageBlockCanvas.tsx or a details preview they mount), + tests (stop on breach; explain in the report)
    Container & model: S, mode:thread (the maintainer's word: 3 card threads per seat, 2026-10-28 10:00Z), model: TIER_DEFAULT (the dev quotes dispatch-gates --tier on the surface), effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the Studio page designer canvas (this lane's code) | the runtime record page's @object-ui/fields cell renderers | a location value draws as [Object] and a select as its raw code on the Design canvas
    Thread-read: 6466026033
    Premise: holds — reproduced from the full-create seed on main per the card; PR #27163 (the serial neighbour) landed as fd73f2b3, so the dev merges origin/main first.
    Serial constraints cleared: #27163 landed; seat 5's #27178 edits PageBlockInspector.tsx (InspectorJsonField), which this card stays out of.
    Resume-from: none


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Order amendment · domain:ui#1 · session_01JQwxbZeBv2y91towxasSUT · 2026-10-28T11:50Z

    The dev's measurement disproves the order's mechanism assumption. The Design canvas has no value-render site of its own: it mounts the runtime record:details renderer inside RecordContextProvider (objectSchema = the fetched /meta object, no dataSource). DetailView learns field types only through dataSource.getObjectSchema, so on the canvas a bare-name section entry has no type, and select / location fall back to raw values. The triage ruling ("the canvas reuses the runtime's field renderers") already holds; what is missing is the field metadata the host holds.

    Seat ruling: route A. In ui/packages/plugin-detail/src/DetailView.tsx, when recordFromHost is set and no dataSource schema has answered, use the host RecordContext's objectSchema for field types. A dataSource answer still wins, nothing new is fetched, and no prop is added (Clause-②: no). A host that provides no context behaves exactly as today.

    The file surface widens to DetailView.tsx plus a @object-ui/plugin-detail patch changeset, alongside the previews tests. Tests: the canvas draws a select option label and a location address (never [Object]); a runtime-shaped mount with a dataSource is unchanged (control); a mount with no context is unchanged. Ablation: drop the context fallback, and the canvas test goes red.

    Route B (a new DetailView prop) is declined, because it widens a published prop. A stub dataSource in the canvas is declined as a workaround. Neighbours: open PR #26966 changes two lines of DetailView.tsx, so merge origin/main before your gates; plugin-detail is otherwise seat 2's package, and this is a narrow, seat-ruled crossing.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 27177,
      "status": "done",
      "branch": "claude/project-thread-lb5wk5",
      "pr": 27253,
      "head": "d8123be0",
      "session": "session_01JQwxbYUSW5btC4i3GbWXGe",
      "premise_still_valid": true,
      "summary": "The card's symptom holds; the order's mechanism assumption did not. The Design canvas has no value-render site of its own: PagePreview wraps PageBlockCanvas in RecordContextProvider with the fetched /meta object schema and no dataSource, and the canvas mounts the runtime record:details, which hands DetailView recordFromHost. DetailView learned field types only from dataSource.getObjectSchema, so a bare-name authored section entry (the full-create seed's shape) had no type and drew raw: select as its code, location via coerceToSafeValue as [Object]. Per the seat's route A (order amendment 6468231446), DetailView under recordFromHost now uses the record context's objectSchema until a dataSource answers; a dataSource answer still wins, nothing new is fetched, no prop is added.",
      "tests": {
        "new": "2 files, 5 tests, all pass: PagePreview.authoredDetailsValues-27177 (2: premise pin that the full-create seed names fields by bare name; the real Design canvas draws Americas and 37.7749, -122.4194 inside the bound record:details body, never amer or [Object], with a text-field control) and DetailView.hostObjectSchema-27177 (3: no-dataSource host draws option label and coordinates; CONTROL dataSource answer wins and is read once, no record read; CONTROL no record context or no recordFromHost draws raw as before)",
        "ablations": "1 of 1 on committed fix f408d892 via ablation-replace: the objectSchema line replaced by the dataSource-only read turns 2 tests red (canvas, no-dataSource DetailView), the premise pin and both controls stay green; restored, blob equal to HEAD, git diff HEAD empty; tests resolve plugin-detail and react to source via the vitest alias, no dist leg",
        "wide": "on d8123be0 under the lock: packages/plugin-detail/ Test Files 325 passed 1 skipped, Tests 2971 passed 18 skipped; app-shell metadata-admin/previews/ Test Files 150 passed, Tests 1683 passed; both VERDICT command-exit 0",
        "type_check": "plugin-detail and app-shell type-check exit 0 on d8123be0 (after the app-shell closure build, VERDICT command-exit 0, and a plugin-detail rebuild after the merge)",
        "eslint": "three changed files 0 errors"
      },
      "gates": {
        "derived": 34,
        "run": 34,
        "not_measured": 0,
        "unrun": 0,
        "all_exit": 0,
        "head": "d8123be0",
        "reconciliation": "dispatch-gates --ran: 34 derived famil(ies) accounted for, 34 run, 0 NOT-MEASURED",
        "tier": "dispatch-gates --tier: no path-derived mandate; changed lines 300, under the 3000 threshold",
        "extra_run": [
          "pnpm --dir ui run check:new-line-citations exit 0 (0 new)"
        ],
        "ci": "check-runs not yet concluded at report time"
      },
      "line_budget": "no ratcheted ledger touched",
      "files_changed": [
        "ui/packages/plugin-detail/src/DetailView.tsx",
        "ui/packages/plugin-detail/src/__tests__/DetailView.hostObjectSchema-27177.test.tsx",
        "ui/packages/app-shell/src/views/metadata-admin/previews/PagePreview.authoredDetailsValues-27177.test.tsx",
        ".changeset/27177-detail-host-object-schema.md"
      ],
      "deviations": [
        "Mechanism assumption disproven before the first edit (no canvas-side value-render site); the file surface widened to DetailView.tsx plus a plugin-detail patch changeset by seat ruling, order amendment 6468231446. The order's skip-changeset expectation does not apply because a published package changes.",
        "The two DetailView controls live in plugin-detail __tests__ beside the existing DetailView tests; the canvas test lives in previews/.",
        "PR body folds the repo PR template headings (Why, Human Minimum) into the os-dev order sections."
      ],
      "dogfood_battery": "n/a, no ! in the title and no (narrowing) arm",
      "mcp_calls": "1 (claude-code-remote subscribe_pr_activity for PR 27253; no GitHub MCP tool)",
      "api_writes": 2,
      "api_write_list": [
        "pr_create 27253 via fleet-write relay (7966 bytes sent = stored, assignee os-warren)",
        "this report via post-stamped"
      ],
      "body_amendments": [],
      "open_questions": [],
      "out_of_scope_findings": []
    }
  7. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · seat domain:ui#1 · session_01JQwxbZeBv2y91towxasSUT · 2026-10-28T13:29Z

    PR #27253 merged as 1e8e5296f3 (seat record: PR comment 6469913369). On the page designer's Design canvas, an authored record:details body now draws a select as its option label and a location as an address, through the runtime's own renderers: DetailView under recordFromHost takes field types from the record context's object schema until a dataSource answers (route A, amendment 6468231446). Nothing new is fetched. Fixes #27177 closed the card; pm:dispatched comes off and the slot is free.


    Generated by Claude Code

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