Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

fields: a code/text value whose text is JSON is JSON.parsed by coerceToSafeValue and rendered as "[Object]" #7246

Closed

Description

@hotlong

What happens

Showcase Field Zoo record Specimen — Full: the Code Editor field (f_code, type code) holds the string

{
  "ok": true
}

(confirmed from GET /api/v1/data/showcase_field_zoo/<id>: a string, not an object). The detail page renders it as the literal [Object].

Why

packages/fields/src/index.tsx coerceToSafeValue (~lines 330-360): any string that starts with {/[ and ends with }/] is JSON.parsed, and the resulting object falls through to String(obj.name || obj.label || obj.externalId || obj.id || obj._id || '[Object]'). The branch exists for reference values that arrive as JSON-encoded strings ('{"externalId":"…"}'), but it runs for every text-like cell, including code (registered to TextCellRenderer, ~line 2425), textarea, text and json-as-text.

Expected

A code (and text/textarea) value is displayed as its text. The reference-string unwrapping should be scoped to reference-typed columns (lookup / master_detail / expanded values), not applied by shape to every string.

Repro

Any record whose text/code field contains a JSON object or array literal.

objectui @ 67dadd6. Found during the objectstack pin-bump dogfood (objectstack#14295).

Generated by Claude Code

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Sep 2, 2026
  2. self-assigned this
    on Sep 2, 2026
  3. hotlong commented on Sep 2, 2026

    @hotlong
    ContributorAuthor

    Claim: PM loop round 2 (dogfood dispatch)
    Session: session_62849a16-0144-4728-8942-9f60bb3a73f1
    Branch: claude/issue-7246-code-text-not-json-parsed
    Worktree: objectui-issue-7246
    Domain: domain:ui
    File surface: packages/fields/src/index.tsx (coerceToSafeValue and the text/code cell renderers) + its tests, .changeset/ (stop on breach; explain in the report)
    Container & model: M, model: opus, mode:subagent
    Clause-②: no
    Serial constraints cleared: none — no open objectui PR touches packages/fields/src/index.tsx (gh pr list 2026-09-02 11:20); in-flight #7244 (components) and the just-opened #7284 (core/app-shell/plugin-grid) do not touch fields

    Maintainer direct-dispatch channel (2026-08-10 standing authorization); instruction in this session, verbatim: 「P1/P2 都开 issue,packages 500 单独修,服务先留着」 → 「使用 pm-dispatch 派发」. Dispatched by the dogfood session that filed the card, outside the lane seat; the seat holder keeps precedence on any later claim conflict.

    Generated by Claude Code

  4. hotlong commented on Sep 2, 2026

    @hotlong
    ContributorAuthor

    Claim: os-dev subagent picking up the implementation.
    Session: session_62849a16-0144-4728-8942-9f60bb3a73f1 (os-dev subagent)
    Branch: claude/issue-7246-code-text-not-json-parsed (pushed, empty)
    Worktree: /Users/zhuangjianguo/Documents/GitHub/objectui-issue-7246
    Base: 2e32ed475ed77fc70790b571d112873e926e0e89

    Generated by Claude Code

  5. hotlong commented on Sep 2, 2026

    @hotlong
    ContributorAuthor

    os-dev-report

    {
      "issue": 7246,
      "status": "done",
      "branch": "claude/issue-7246-code-text-not-json-parsed",
      "pr": "https://github.com/objectstack-ai/objectui/pull/7343",
      "premise_still_valid": true,
      "summary": "Confirmed verbatim and fixed at the producer. coerceToSafeValue classified strings BY SHAPE — any string starting {/[ and ending }/] was JSON.parsed and run through the reference-label extraction, which answers '[Object]' for an object carrying no name/label/externalId/id. A string is now returned verbatim; object and array VALUES still coerce, so React error #310 stays fixed. Sharper than the dispatch hypothesis: NO reference-typed renderer ever called this helper — lookup/master_detail/tree route to LookupCellRenderer, which already carries its OWN JSON-string branch for the objectui#1426 external-id case (resolving through the referenced object's schema and linking to the record). So the branch was unreachable for its stated purpose and only ever damaged text cells; deleting it IS the scoping the issue asked for, not a removal. Call-site census of all 5 surfaces is declared in the PR body: 10 fields renderers fixed; LookupCellRenderer already compliant (owns the scoped branch); plugin-detail InlineFieldInput already compliant (guarded by typeof value === 'object', string branch unreachable); plugin-grid 5 type-agnostic sites fixed with no regression; components safeObjectLabel out of scope (mirrored copy that never had the branch).",
      "tests": "Union at final commit 3a80fcf79. Vitest from repo root per objectui AGENTS.md (NOT pnpm --filter, which is that repo's mechanically-blocked silent-green trap — this overrode the dispatch prompt's gate list; conflict noted below). packages/fields: 131 files / 2148 tests passed. packages/plugin-detail: 124 files / 1144 passed. packages/plugin-grid: 109 files / 993 passed. RED-FIRST: new test written before the fix ran 8 failed / 2 passed — the 2 passing were the object-value case and the CONTROL lookup case, which is the evidence that LookupCellRenderer handles objectui#1426 independently. REVERSE VERIFICATION from the committed state: deleted branch restored from origin/main; mutation proven on disk by blob hash a22a8afb != HEAD a6bc6c9e AND by marker count (2 vs 1), not by any editor exit code; result 2 files failed / 9 tests failed (direction as predicted: red); restore leg proven byte-exact via empty `git diff HEAD` plus blob back to a6bc6c9e, restore written as `git checkout HEAD -- ABSOLUTE_PATH`. type-check exit 0 (tsc --noEmit && tsc -p tsconfig.test.json) after building the dependency closure — the first attempt was Cannot-find-module noise, read as NOT MEASURED, not as a red gate; both edited test files proven present in the test program by --listFiles (1 hit each). check-changeset-presence and check-changeset-no-major both exit 0. LINT — DECLARED NARROWING to the 3 changed files with all three pieces of evidence: population from eslint's own isPathIgnored (false for all three), count from --format json (3 files, 0 errors, 143 warnings, all pre-existing-style no-explicit-any), and invariance (type-aware linting not enabled — parserOptions.project and projectService both null — so this diff cannot move the verdict on untouched files). Every heavy command routed through os-verify-lock.sh, which printed verbatim: 'UNLOCKED (declared) · no usable flock on this host, so the shared verify lock was NEVER taken and NOTHING was serialized' — declared in the PR body as instructed. All exit codes captured by redirect-then-read, never through a pipe. BROWSER: PM's :3911 backend was already dead (nothing listening — likely the same interruption that killed this session), so an own isolated stack was used (backend --fresh -p 4011, console vite --port 5193 --strictPort) and both were stopped by recorded PID; no one else's service touched. Premise reproduced independently from the API (f_code typeof = string). Same live page, DOM read directly — BEFORE: 'Code Editor[Object]', [Object] present; AFTER: 'Code Editor{ \"ok\": true }', [Object] absent; and reference columns Northwind (lookup) and Website Relaunch (master-detail) still resolve to labels, confirming the scoping live.",
      "mcp_calls": "0 — all GitHub work went through gh (REST/CLI); no GitHub MCP calls",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Notes for the PM, outside the machine-readable block:

    • Dispatch/AGENTS.md conflict, resolved toward AGENTS.md and reported rather than chosen silently. The dispatch prompt's gate list said pnpm --filter @object-ui/fields test. objectui's own AGENTS.md documents that exact form as one of two silently-green traps (it relocates vitest's root into the package, matches the root projects' includes against nothing, and reports another package's file count as a pass) and it is now mechanically blocked by scripts/vitest-invocation-guard.mjs. All suites were run the documented way: pnpm exec vitest run PACKAGE_PATH from the repo root.
    • skip-changeset was correctly NOT applied — objectui has no such mechanism (a same-named label object exists there from a historical mis-tag but nothing reads it). A normal @object-ui/fields patch changeset was written and both changeset gates pass.
    • Fixture triage was done by the rule's three dispositions, not a bulk respell. Two cases in coerce-safe-value.test.ts pinned exactly the deleted branch, so they were REPLACED (their assertions are now the wrong answer at that seam) and their scenario relocated to the control case on the reference renderer. A third was corrected from a JSON-string array to a real array. A fourth fixture found by sweeping the rule's consumption radius — complex-widgets.test.tsx:773, a LookupField on a type: 'lookup' field — was triaged as already compliant and left untouched; it still passes.
    • CI not awaited, per the standing dispatch contract. Gate status at hand-off is local-green only.

    Generated by Claude Code

  6. hotlong commented on Sep 2, 2026

    @hotlong
    ContributorAuthor

    ACCEPT — reviewer of record: PM session session_62849a16-0144-4728-8942-9f60bb3a73f1.

    Checked against GitHub, not the report: draft PR #7343 targets main, first line Fixes #7246, no other closing keyword, changed files stay inside the claimed surface (no governed path, no releases page), changeset declared, every check-run green at the current head. Spot-read: coerceToSafeValue no longer JSON-parses strings by shape; LookupCellRenderer keeps its own scoped external-id branch, so reference columns were never on this path (control test kept); red-first 8/2 then green, ablation 9 red, live DOM before/after captured. Flipping to ready and arming squash auto-merge; the queue lands it.

    PR: #7343

    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

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions