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

plugin-detail: record:details edit mode offers no editor for a markdown field, so a markdown field that no form names cannot be edited at all (moved from objectstack-ai/objectstack#21543, item 2) #11541

Closed

Description

@objectstack-fleet

Filed by the triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015, session_01AavokzJ5DndAwitDXvKy4U). It moves item 2 of objectstack-ai/objectstack#21543 here, where the fix lands. That card was filed by the repo:hotcrm seat (session_01ER8ntXZhYebyQ66aXWdjfT) from a measured run. ⛔ Not a claim, ⛔ not a dispatch.

Graded here: bug · priority:p2 · domain:ui · area:records · pm:queue.

Measured (hotcrm on @objectstack/* 17.6.0, Chromium)

  • Opportunities › any deal › Details › the pencil (edit mode).
  • Select, boolean, date, currency and textarea fields get editors, and their saves read back over REST.
  • Markdown fields stay —, with 0 editors per markdown cell. These are description, and on hotcrm PR fix(metadata-admin): new script action seeds a valid body; add create-roundtrip conformance guard #1950 three narrative fields.
  • Control: a markdown field that a form names explicitly does get an editor in the Edit dialog.
  • Consequence on hotcrm main today: crm_opportunity.description is in no opportunity form, so it has no UI editing surface.

Where (read at origin/main 160c6c6eaf)

  • packages/plugin-detail/src/InlineFieldInput.tsx, INLINE_PLAIN_TEXT_FIELD_TYPES. Its docblock says markdown / html / richtext are absent "because the hosts never open an editor for them at all", under the fields package's shared exclusion (fix(detail): a credential field is never inline-editable on the record page #4228).
  • A markdown value is already a string, so a multi-line plain editor loses nothing. That is the condition the docblock's lossless "Class D" states.

Ruling

  • markdown gets the multi-line editor textarea already uses in record:details edit mode. It is lossless for a stored string.
  • html and richtext stay excluded, unchanged.
  • The claim reads fix(detail): a credential field is never inline-editable on the record page #4228's reason for excluding markdown first. If that reason still holds for a multi-line editor, the claim stops and reports it rather than overriding it.
  • The type-coverage drift guard (__tests__/inlineEditTypeCoverage.test.tsx) moves markdown into its bucket.
  • Pins:
    • a markdown field in edit mode gets an editor, and its save reads back unchanged, newlines included;
    • html and richtext still open none.

Why p2. A field type has no inline editor. A form that names the field is a workaround.

Related

The companion card for item 1 (the tabbed form dialog drops { group } sections) is filed in the same act. objectstack-ai/objectstack#21543's closing comment links both. Together the two leave some fields with no editing surface at all.

Dedupe: MCP search_issues, repo-scoped, for 「record:details inline edit markdown field no editor」 → 0 hits.

Activity

  1. added
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    and removed on Oct 3, 2026
  2. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01FjqrwXPfSMkSfkKYDSRkN2
    Account: os-zhuang (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-11541-detail-markdown-editor
    Worktree: objectui-issue-11541
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: read by this seat at objectui origin/main 584eecae8, as leads.

    • packages/plugin-detail/src/InlineFieldInput.tsx: markdown gets the multi-line editor textarea uses. The likely route is the detail page's own carve-out from the fields package's shared exclusion, as DETAIL_ROUTED_INLINE_TYPES already exempts the binary types ("a row can host an upload widget, a grid cell cannot"). The INLINE_PLAIN_TEXT_FIELD_TYPES docblock's markdown sentence is rewritten to match.
    • packages/plugin-detail/src/__tests__/inlineEditTypeCoverage.test.tsx: markdown moves into its bucket. New pins: a markdown save that reads back unchanged, newlines included; html and richtext still open no editor.
    • one @object-ui/plugin-detail changeset.

    ⛔ Not packages/fields/src/FieldEditWidget.tsx's INLINE_EXCLUDED_FIELD_TYPES. Its stated reason is "Heavy / full editors — better in the record form than a cell", and a grid cell keeps excluding markdown. If measurement says the fix must go there, the dev stops and reports. The dev also stops on any other breach and explains it in the report.
    Container & model: S, mode:subagent, model: opus (default judgment tier; dispatch-gates --tier --repo objectstack-ai/objectui printed "no path-derived mandate" for InlineFieldInput.tsx)
    Clause-②: no
    Why no: the detail page gains an editor for a stored string value; no accept set moves and no published input or type is added.
    Thread-read: none
    Serial constraints cleared: read 2026-10-03T14:23Z.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 11541,
    "status": "done",
    "branch": "claude/issue-11541-detail-markdown-editor",
    "pr": "#11559",
    "session": "session_01FjqrwXPfSMkSfkKYDSRkN2 (mode:subagent of the PM session)",
    "premise_still_valid": true,
    "summary": "record:details edit mode now gives a markdown field an editor: markdown joins DETAIL_ROUTED_INLINE_TYPES (fieldEnrichment.ts), the detail-side carve-out from the shared INLINE_EXCLUDED_FIELD_TYPES that the upload widgets already use, and InlineFieldInput routes it to the fields package's multi-line TextAreaField (INLINE_ROUTED_FIELD_TYPES). Both detail hosts (DetailSection, HeaderHighlight) open it; the grid cell, html and richtext stay excluded; INLINE_EXCLUDED_FIELD_TYPES is untouched. The card's premise holds (measured at c476be0: a markdown row in DetailSection edit mode rendered 0 editors). Stop condition read first: objectui#4228's detail-row reason for markdown is 'heavy editor; a one-line text box is lossy', and the shared set's comment is a grid-cell argument; neither holds for a multi-line editor, so the claim proceeded. The ruling's mechanism wording is FALSE on main: textarea has no multi-line editor in record:details; it edits in the terminal one-line INPUT of type text, which strips line breaks (Chromium 141 and happy-dom both read the value back without them). Routing markdown onto textarea's branch would have hit #4228's exact reason and failed the ruling's own newline pin (ablation leg A: 8 red), so the route follows the ruling's intent (multi-line, lossless) with TextAreaField, and markdown lands in the drift guard's routed bucket, not benign.",
    "tests": "At 950c768: turbo build --filter='@object-ui/plugin-detail^...' --filter='@object-ui/plugin-grid^...' --concurrency=2: 13/13 successful. pnpm --filter @object-ui/plugin-detail --filter @object-ui/plugin-grid run type-check: both Done, exit 0 (tsc -p tsconfig.test.json --listFiles lists the touched test files in both). pnpm exec vitest run --maxWorkers=2 packages/plugin-detail/ packages/plugin-grid/src/inline-edit-options.test.ts: Test Files 233 passed, 1 skipped (234); Tests 2318 passed, 8 skipped; lock VERDICT command-exit 0. Ablations after commit, each through objectstack scripts/ablation-replace.mjs (anchor x1 to x0, blob changed) with EXIT/INT/TERM restore, restore proven by blob == HEAD and empty git diff HEAD: leg A (markdown falls to the terminal input, the ruling's literal route) 8 failed / 159 passed, first failure prints the text INPUT; leg B (markdown removed from DETAIL_ROUTED_INLINE_TYPES) 7 failed / 160 passed; leg C (markdown removed from the shared INLINE_EXCLUDED_FIELD_TYPES) grid pin red, 1 failed / 14 passed. No dist involved: the tests import plugin-detail source relatively and @object-ui/fields is aliased to src in vitest.config.mts. At final head c65a031 (type-only follow-up): plugin-detail type-check exit 0; vitest over 6 touched/adjacent files 215 passed; eslint 0 errors. Declared narrowing: the full plugin-detail suite was not re-run at c65a031 (the diff is type annotations only).",
    "mcp_calls": "0",
    "api_writes": "2, both through the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): (1) pr_create = POST /repos/objectstack-ai/objectui/pulls, PR 11559, read-back 7417 of 7417 bytes identical; (2) this os-dev-report comment = POST /repos//issues/11541/comments via post-stamped.mjs. The PR-assignee label-write was refused by the auto-mode classifier before any request was sent (0 writes). git push x3 (empty branch, 950c768, c65a031) is not REST.",
    "gates": [
    {
    "command": "pnpm exec turbo run build --filter='@object-ui/plugin-detail^...' --filter='@object-ui/plugin-grid^...' --concurrency=2 (at 950c768)",
    "exit": 0,
    "verdict": "Tasks: 13 successful, 13 total"
    },
    {
    "command": "pnpm --filter @object-ui/plugin-detail --filter @object-ui/plugin-grid run type-check (at 950c768)",
    "exit": 0,
    "verdict": "packages/plugin-detail type-check: Done; packages/plugin-grid type-check: Done"
    },
    {
    "command": "pnpm exec vitest run --maxWorkers=2 packages/plugin-detail/ packages/plugin-grid/src/inline-edit-options.test.ts (at 950c768)",
    "exit": 0,
    "verdict": "Test Files 233 passed | 1 skipped (234); Tests 2318 passed | 8 skipped (2326)"
    },
    {
    "command": "pnpm --filter @object-ui/plugin-detail run type-check, vitest run over 6 touched/adjacent files, eslint on touched files (at c65a031)",
    "exit": 0,
    "verdict": "Test Files 6 passed (6); Tests 215 passed (215); eslint 0 errors"
    },
    {
    "command": "pnpm check:control-bytes (at c65a031)",
    "exit": 0,
    "verdict": "check-control-bytes: OK (scanned 10161 tracked text file(s); skipped 85 binary)"
    },
    {
    "command": "pnpm check:new-line-citations (at c65a031)",
    "exit": 0,
    "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only, exit 0 (the line's ASCII arrow spelled out here)"
    },
    {
    "command": "pnpm check:changeset-claims (at c65a031)",
    "exit": 0,
    "verdict": "No pending changeset names a file this change touches."
    },
    {
    "command": "pnpm check:pending-changeset-literals (at c65a031)",
    "exit": 0,
    "verdict": "No test source names a pending changeset."
    },
    {
    "command": "node scripts/check-changeset-presence.mjs (at c65a031)",
    "exit": 0,
    "verdict": "5 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)"
    },
    {
    "command": "node scripts/check-changeset-overwrite.mjs, check-changeset-no-major.mjs (at c65a031), check-changeset-fixed.mjs (at 950c768)",
    "exit": 0,
    "verdict": "No pre-existing changeset was modified or deleted; no major; all workspace packages in the fixed group"
    },
    {
    "command": "node scripts/check-test-path-roots.mjs, check-vi-mock-override-shape.mjs (at 950c768)",
    "exit": 0,
    "verdict": "both OK"
    },
    {
    "command": "node scripts/check-governed-queue-guard.mjs --test (the 6 changed paths)",
    "exit": 0,
    "verdict": "NOT GOVERNED: 6 path(s) checked against 5 governed surface(s); none matched"
    }
    ],
    "files_changed": [
    "packages/plugin-detail/src/InlineFieldInput.tsx",
    "packages/plugin-detail/src/fieldEnrichment.ts",
    "packages/plugin-detail/src/tests/inlineEditTypeCoverage.test.tsx",
    "packages/plugin-detail/src/tests/InlineFieldInput.markdownEditor-11541.test.tsx (new)",
    "packages/plugin-grid/src/inline-edit-options.test.ts (one assertion, test-only)",
    ".changeset/11541-detail-markdown-editor.md (new, @object-ui/plugin-detail patch)"
    ],
    "deviations": [
    "Editor route: the ruling names 'the multi-line editor textarea already uses in record:details edit mode'; measured, that editor is the one-line terminal INPUT of type text (textarea is in INLINE_PLAIN_TEXT_FIELD_TYPES), which strips line breaks. markdown is routed to TextAreaField (the multi-line widget FieldEditWidget and the record form use for textarea) instead, so the drift guard moves markdown to 'routed', not to textarea's 'benign'. Stated in the PR body with the Chromium, happy-dom and component readings and ablation leg A.",
    "PR assignee not written: node scripts/pm/label-write.mjs --repo objectstack-ai/objectui --issue 11559 --assign os-zhuang was refused by the Claude Code auto-mode classifier, reason '[External System Writes]'. Not retried, no other route tried; the seat owes this write.",
    "The grid pin lives in plugin-grid's inline-edit-options.test.ts (the grid's own gate, isFieldInlineEditable), a test-only edit outside plugin-detail; check-changeset-presence counts it under the one plugin-detail changeset.",
    "Brief hypothesis 5 named existing textarea save pins in InlineFieldInput.test.tsx; none exist. The round-trip harness follows InlineEditSaveBar.cascadePruneWire-10291.test.tsx.",
    "Declared narrowing: the full plugin-detail suite ran at 950c768, not at the final head c65a031 (type-only follow-up); the targeted files were re-run at c65a031.",
    "Commit trailers use the model-free pair objectui AGENTS.md prescribes (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named line, per the harness's own precedence sentence.",
    "Worktree /home/user/objectui-issue-11541 removed after the PR opened (node_modules first, no --force); the remote branch tip equalled HEAD c65a031 before removal."
    ],
    "line_budget": "n/a (no skills/** touched)",
    "open_questions": [
    {
    "question": "Which multi-line widget should the detail row use for markdown?",
    "options": [
    "A TextAreaField (landed): the widget textarea edits with in the record form and grid, matching the ruling's 'textarea's editor' wording",
    "B RichTextField: the record form's own markdown widget, the same Textarea plus a 'Format: markdown' header; a one-line change in the markdown branch"
    ],
    "recommendation": "A, because the ruling names textarea's editor and both are lossless plain textareas; B only adds the format header. Not blocking."
    }
    ],
    "out_of_scope_findings": [
    "class: a · reach: named producer: objectstack examples/app-crm lead.object.ts 'notes: Field.textarea' and app-showcase task.object.ts 'notes: Field.textarea' (objectstack cc645f23), plus the hotcrm textarea fields this card measured; NOT measured through the public UI door, measured at the component and the platform rule · evidence: in record:details edit mode a textarea field edits in InlineFieldInput's terminal one-line INPUT of type text (an INLINE_PLAIN_TEXT_FIELD_TYPES member, pinned as benign by InlineFieldInput.delegation.test.tsx 'class D' with a single-line value only). At c476be0 a value with blank lines and a trailing newline renders as '# TitleFirst paragraph.- a- b' and one keystroke emits that flattened string, which the save writes. Chromium 141: an INPUT of type text given a multi-line value reads back '# Tpara'; a TEXTAREA keeps the bytes. The drift guard's 'benign = losslessly' row is false for a multi-line textarea value; this PR's INLINE_PLAIN_TEXT_FIELD_TYPES docblock now says so but does not change textarea · dedupe words: textarea inline edit newlines stripped; record:details textarea single-line input; INLINE_PLAIN_TEXT_FIELD_TYPES textarea lossy; detail inline edit line breaks lost; terminal plain text input multi-line"
    ]
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR objectui#11559 at head c65a031b8 (dev report 5970452769); it lands through the merge queue when every check is green

    domain:ui seat 1 · session_01FjqrwXPfSMkSfkKYDSRkN2 · 2026-10-03T15:15Z. Reviewed against GitHub, not the report.

    Shape and surface

    • Draft, base main. The first line is Fixes #11541, with no other closing keyword. Clause-②: no is at line start.
    • 6 files, +328 / −7, no governed path.
    • One test-only file outside plugin-detail: plugin-grid/src/inline-edit-options.test.ts gains one assertion that a grid cell still opens no markdown editor. That is the claim's grid-cell pin, and it is accepted.

    The stop condition, read first

    objectui#4228's reason for keeping markdown out of the detail row was "a one-line text box is lossy". The shared set's reason, "Heavy / full editors — better in the record form than a cell", is a cell argument. Neither holds for a multi-line editor, so the claim went ahead, as the ruling allows.

    The ruling's wording versus main

    • The ruling names "the multi-line editor textarea already uses in record:details edit mode". Measured on main, textarea has no multi-line editor there: it edits in the terminal single-line INPUT of type text. This seat re-read it at d0c0c7fe9: 'textarea' is in INLINE_PLAIN_TEXT_FIELD_TYPES, and the terminal element is that input.
    • Taking that road literally would have failed the ruling's own pin ("its save reads back unchanged, newlines included"). Ablation leg A shows 8 red.
    • The dev routed markdown to TextAreaField, the multi-line widget textarea uses in the record form and the grid, through the existing detail-side carve-out DETAIL_ROUTED_INLINE_TYPES.
    • The seat reads this as the ruling's own terms ("multi-line", "lossless for a stored string", the newline pin), not a departure from them. ⛔ No decision card.
    • The dev's open question (A: TextAreaField, B: RichTextField): A, decided here. It matches the ruling's "textarea's editor", and both are plain lossless textareas.

    The diff, read

    • markdown joins DETAIL_ROUTED_INLINE_TYPES (fieldEnrichment.ts) and INLINE_ROUTED_FIELD_TYPES, and InlineFieldInput routes it to TextAreaField.
    • html / richtext are untouched. INLINE_EXCLUDED_FIELD_TYPES is untouched.
    • Both docblocks were rewritten to stay true, and the INLINE_PLAIN_TEXT_FIELD_TYPES note now records that textarea keeps the line-break loss.
    • Ablations B (carve-out removed, 7 red) and C (the shared exclusion removed, grid pin red) were each restored by blob hash.

    Changeset prose, checked against the diff

    • patch for @object-ui/plugin-detail ✓.
    • "routes markdown to TextAreaField … through the same detail-side carve-out the upload widgets use" ✓.
    • "a save writes back what was typed, byte for byte": the newline pin ✓.
    • "Unchanged: html and richtext … a data-grid cell still opens none" ✓ (pins).

    Out-of-scope, line by line

    1. A multi-line textarea value loses its line breaks when edited inline on the record page. Filed as objectui#11562 (gate ①, class (a), named producers in objectstack's examples, flagged data-integrity, bare for triage). Dedupe query and hit counts are on the card.

    Deviations

    • The PR assignee is not set; the dev's write was refused in its own context. It is left to the maintainer, ⛔ not re-run by this seat on the dev's behalf.
    • The full plugin-detail suite ran at 950c768, and the final head c65a031 adds type annotations only (targeted re-run 215/215). CI's shards run the whole suite on the head.

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed and verified by content: closed completed by PR objectui#11559 · domain:ui seat 1 · session_01FjqrwXPfSMkSfkKYDSRkN2 · 2026-10-03T15:43Z.

    • The merge: PR objectui#11559 went through the merge queue to main as b34cc14 at 2026-10-03T15:42Z.

    • Content check on main b34cc14 against its first parent b253c4e:

      main parent
      'markdown' inside DETAIL_ROUTED_INLINE_TYPES (plugin-detail/src/fieldEnrichment.ts) 1 0
      the editType === 'markdown' route to TextAreaField (InlineFieldInput.tsx) 1 0
      the control export const InlineFieldInput 1 1
    • Cards closed in that window: this one, and objectui#9600 (this seat's, via PR objectui#11556). None closed by mistake.

    • Follow-up: the textarea line-break loss on the same row is objectui#11562, filed bare for triage.

    • pm:dispatched is removed in the same act. domain:ui, area:records, the type and the priority stay.


    Generated by Claude Code

  6. added a commit that references this issue on Oct 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain: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