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.

Form Preview renders the draft definition instead of 'No published definition yet' #12515

Closed

Description

@objectstack-fleet

Source

Measured on objectui main d4bc81eab, 2026-10-15: Data pillar › Form tab › Preview on an unpublished object shows a yellow banner "You have unpublished changes — this preview shows the pre-publish (published) state; confirm the draft in Layout, and to see the post-publish result, click Publish in the top bar first" and, below it, an empty state "No published definition yet — Preview renders the published runtime form, but this object isn't published yet. Confirm the draft in Layout, then click Publish in the top bar to preview" (engine.studio.data.form.noPublishedTitle). The same instruction is given twice and the tab is empty exactly when a designer most wants to see the form.

Target

  1. Preview renders the runtime form from the draft definition (the draft object and its draft layout fed to the same form renderer the app uses), with a "Draft preview" chip in the toolbar.
  2. When a published version also exists, a Draft / Published toggle next to the chip; the banner retires.
  3. If the runtime form cannot take a draft definition without a server change, the card reports the fork on the epic with what the renderer needs, and does not build a second renderer.

File surface

packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (Form tab preview branch), ObjectFormDesigner.tsx, the form renderer host it mounts, packages/app-shell/src/views/metadata-admin/i18n.ts, tests beside.

Acceptance

  1. Test: an unpublished object with three draft fields shows the three fields in Preview.
  2. Screenshots of Preview for an unpublished and a published object, light and dark.
  3. DataPillar.*.test.tsx green.

Constraints

  • Preview never saves; the draft is read-only there.
  • Existing data-testids stay.

Filed by the epic PM session session_cdb7a717-def7-4e71-9988-f089fbaa18ff from the 2026-10-15 Studio test pass: objectui main d4bc81eab, HotCRM 63db83e2, the vite console on :5180 against objectstack serve --dev on :4001, viewport 1482 × 1119, dark theme with a light-theme check.

Evidence

Screenshots from the test pass, kept on the temporary branch claude/studio-test-pass-evidence-20261015 of objectstack-ai/objectui (commit 72115588c, never merged: the maintainer ruled that screenshots do not enter main, and asked for a temporary branch referenced from the card). The branch's docs/design/studio-redesign/findings/2026-10-15/README.md maps every file to its card. Pane captures, 800 × 604 of a 1482 × 1119 viewport, dark unless named light.

form preview no published
docs/design/studio-redesign/findings/2026-10-15/12515-form-preview-no-published.jpg — form preview no published.

Parent: #12446

Body refreshed 2026-10-15T15:19Z by the epic PM session: an Evidence section with the test-pass screenshots added.

Activity

  1. added
    enhancementNew feature or request
    pm:epicParent delegated to a dedicated epic PM — other PMs never dispatch into its subtree
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    on Oct 15, 2026
  2. added and removed
    pm:epicParent delegated to a dedicated epic PM — other PMs never dispatch into its subtree
    on Oct 15, 2026
  3. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (domain:ui lane queue; an objectui#12446 test-pass card)
    Session: session_01SJn1GEkrbbBQkhGC26wEDw
    Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12515-form-draft-preview
    Worktree: objectui-issue-12515 (in the cloud session's own container)
    Domain: domain:ui
    Seat: domain:ui#4
    File surface: packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (the DataPillar Form tab preview branch only), ObjectFormDesigner.tsx, the form renderer host it mounts, metadata-admin/i18n.ts (retired and new keys in every locale), new tests beside them, one .changeset/12515-*.md (stop on breach; explain in the report)
    Container & model: M, mode:cloud, model: opus (cloud on the maintainer's stance 「可以的话,ui 后续开发尽量用云 session,并且要求截图给我看」; lane scope on 「你也可以接ui车道的卡」; batch 5 on 「上限提到 5,提速」, this session's chat, 2026-10-15)
    Clause-②: no
    Responsibility: n/a — not a defect card
    Thread-read: none
    Serial constraints cleared: objectui#12451 (the Form tab) landed as 68c9b40 and objectui#12453 (its read-only caption) as 2a69285. objectui#12516 (ObjectFormDesigner.tsx, the add-field handler) stays queued behind this card. No open PR touches ObjectFormDesigner.tsx. In flight on StudioDesignSurface.tsx from this seat at this claim: objectui#12508 round 2 (the InterfacesPillar canvas mount and studio-canvas-preview.tsx only), and the sibling cards of this wave: objectui#12510 (accessible names across the shell), objectui#12514 (the Automations and Access empty branches), objectui#12515 (the Form tab preview branch) and objectui#12522 (the InterfacesPillar page branch). They are in disjoint regions; any textual overlap is resolved by merging origin/main.

  4. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 12515,
    "status": "done",
    "branch": "claude/issue-12515-form-draft-preview",
    "pr": null,
    "session": "session_013vU6SkD1BChLe3MmBFUaA6",
    "premise_still_valid": true,
    "summary": "On main 572bbce the Form tab's Preview for a draft-only object never mounted the form: it drew the banner and 'No published definition yet', and it sent no request. Preview now mounts the same runtime ObjectForm with a data source (formPreviewSource) whose getObjectSchema answers the open object from DataPillar's objDraft and passes every other read to the real adapter. That gives no second renderer and needs no server change, so target 3's fork does not arise. A 'Draft preview' chip and a Draft / Published toggle (only beside a published version that differs) replace the banner, three keys retire and five are added in en and zh, and the preview data source refuses every write. PM assumptions: 1 holds, except the renderer has no inline-schema prop, so the draft goes in through getObjectSchema on a data-source wrapper. 2 is falsified as worded: before, the unpublished Preview made no request at all, because it never mounted. After, the form asks nothing for the object, and the only 404 comes from LookupField reading a draft-only lookup target. 3 holds as built. 4 holds visually (an empty picker, no error) with that one console 404. The 'form renderer host' is ObjectForm from @object-ui/plugin-form, unchanged. ObjectFormDesigner.tsx is also unchanged; its FormToolbar is reused. The card assignee was already os-sales and was not written.",
    "tests": "New DataPillar.formDraftPreview-12515.test.tsx (4 tests): three draft fields shown with the chip, no toggle, no adapter read, no request answering 400 or above; published plus draft shows the draft, and the Published side shows the published fields and drops the chip; CONTROL: published and clean has neither chip nor toggle; never saves: a submitted preview form reaches no write. Ablations via objectstack scripts/ablation-replace.mjs (each landed on disk with anchor 1 -> 0 and the blob changed; restored with git diff HEAD at 0 bytes). Draft answering off: 3 of 4 red. Write refusal off: red, 'expected vi.fn() to not be called at all, but actually been called 1 times'. Published field list replaced by the draft's: green on the first fixture, which only added a field, because ObjectForm skips unknown names; the fixture now also removes a field, and that ablation is red. The first two ablations ran against the test at 92f61ed, the third at 0e09c1b. Runs at 0e09c1b, repo-root vitest through os-verify-lock: DataPillar.* 21 files/87 tests passed; StudioDesignSurface.* 80 files in three parts (25/118, 27/169, 28/263) passed.",
    "gates": "Local, at 0e09c1b, exit codes captured before any pipe: vitest DataPillar.* exit 0; vitest StudioDesignSurface.* three parts exit 0/0/0; pnpm --filter @object-ui/app-shell type-check exit 0 (after turbo build of the app-shell^... closure, 28/28, exit 0; first attempt before the build exited 2 on missing sibling dist, a prerequisite, not a measurement); pnpm --filter @object-ui/app-shell build exit 0 (dist completeness 1104 files); eslint --no-inline-config on the three touched files exit 0 (0 errors; the new test and i18n.ts add no warnings; StudioDesignSurface.tsx has the same 8 warning sites as main, shifted); pnpm check:i18n-keys 0; check:i18n-drift 0; check:i18n-dead-keys 0 (none of the engine.studio.data.form keys listed); check:i18n-designer-parity 0; node scripts/check-changeset-presence.mjs 0; check:new-line-citations 0; check:test-path-roots 0. objectui has no scripts/pm/dispatch-gates.mjs, so the list was derived by hand per the dispatch; no --ran reconciliation. The full @object-ui/app-shell suite was NOT MEASURED locally (reason: the card's acceptance names DataPillar.*, not the full package, and the package exceeds the foreground cap); CI runs it. CI check-runs: NOT MEASURED, because no PR is open (the PM opens it).",
    "mcp_calls": "5: mcp__claude-code-remote__add_repo x2 (objectstack, hotcrm; read, nothing attached), ToolSearch x1, mcp__github__issue_read x2 (get, get_comments on #12515). No MCP write tool.",
    "api_writes": "0 REST writes. The two epic comments 6188626991 and 6192878850 were read with unauthenticated GET on api.github.com. git push x4 (not REST): the empty feature branch, 92f61ed, 0e09c1b, and the evidence branch 4b1b322. Local-backend-only calls (localhost, not GitHub): POST /api/v1/packages, PUT meta drafts, POST publish-drafts.",
    "open_questions": [
    {
    "question": "A lookup in a draft-only object that points at another draft-only object makes LookupField send GET /meta/object/TARGET, which answers 404, in the Form Preview. The widget drops the failure and renders an empty picker; the 404 shows only in the console. Should the preview data source also answer draft definitions of other objects in the package?",
    "options": [
    "A: leave it (this PR). The picker is inert in Preview, nothing visible is wrong, and the residual is recorded in Acceptance notes.",
    "B: have formPreviewSource answer any draft-only object in the package from its served draft, at one extra draft read per target instead of a 404.",
    "C: route the Studio's draft-world definition reads through the server's existing ?preview=draft overlay at the adapter, a separate card covering this and objectui#12508's canvas read together."
    ],
    "recommendation": "A now, C if the console 404 is to go. Business need: measured only with a synthetic lookup between two new objects; no visible defect, and the picker cannot be opened in Preview. Long-term: B makes a second, client-side draft world beside the server's ?preview=draft overlay; C puts that one contract at the adapter. AI-error axis: B adds tolerant client-side resolution, while C keeps one strict source. Startup focus: no pull beyond a console line, so do not widen this card."
    }
    ],
    "out_of_scope_findings": [
    "observation, not filed: LookupField in a draft-only object's Form Preview sends GET /meta/object/TARGET (404) for a draft-only lookup target and drops it silently (empty picker, no error) · evidence: after-projdraft-light-requests.txt on the evidence branch · carrier: none · dedupe words: LookupField getObjectSchema draft-only 404, form preview lookup target, preview=draft overlay adapter"
    ],
    "deviations": [
    "os-dev.md has the dev open the draft PR and post the os-dev-report comment through the fleet-write relay. The dispatch's degraded channel says that relay is refused (403) from this container and forbids both writes, so neither was done: pr is null and the PM opens the PR from pr_body_draft. The file normally wins over the dispatch, but its write path is unavailable here, so the dispatch's channel was followed.",
    "AGENTS.md points the verification lock at /home/user/objectstack/scripts/pm/os-verify-lock.sh. That path does not exist in this container, so the read-only clone's copy at /home/user/objectstack-ai/objectstack/scripts/pm/os-verify-lock.sh was used (OS_VERIFY_LOCK_SLOT=issue-12515).",
    "Commit trailers follow AGENTS.md's model-free pair (Claude-Session and Co-authored-by: Claude) instead of the harness reminder's model-named Co-Authored-By; the reminder defers to repo rules.",
    "objectui has no scripts/ablation-replace.mjs or scripts/pm/dispatch-gates.mjs. Ablation used the objectstack clone's ablation-replace.mjs against objectui paths (no build: the test imports the source directly). The gate list was derived by hand.",
    "The full @object-ui/app-shell suite was not run locally; see gates.",
    "One 404 remains in the unpublished Preview, from LookupField reading a draft-only lookup target; see open_questions."
    ],
    "files_changed": [
    ".changeset/12515-form-draft-preview.md",
    "packages/app-shell/src/views/metadata-admin/i18n.ts",
    "packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (DataPillar: module-scope formFieldNames and formPreviewSource beside it; previewSource, publishedFormFields and the Form tab preview branch)",
    "packages/app-shell/src/views/studio-design/DataPillar.formDraftPreview-12515.test.tsx (new)"
    ],
    "file_surface": "Within the claim. The two module-scope helpers sit directly above DataPillar in the same file and serve only its preview branch. ObjectFormDesigner.tsx and the renderer host (ObjectForm in packages/plugin-form) are unchanged.",
    "screenshots": [
    "https://github.com/objectstack-ai/objectui/blob/4b1b3222035d776048d438cfa3e46e8e17f7ff42/docs/design/studio-redesign/findings/12515/before-unpublished-light.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/4b1b3222035d776048d438cfa3e46e8e17f7ff42/docs/design/studio-redesign/findings/12515/before-published-light.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/4b1b3222035d776048d438cfa3e46e8e17f7ff42/docs/design/studio-redesign/findings/12515/after-unpublished-light.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/4b1b3222035d776048d438cfa3e46e8e17f7ff42/docs/design/studio-redesign/findings/12515/after-unpublished-dark.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/4b1b3222035d776048d438cfa3e46e8e17f7ff42/docs/design/studio-redesign/findings/12515/after-published-light.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/4b1b3222035d776048d438cfa3e46e8e17f7ff42/docs/design/studio-redesign/findings/12515/after-published-dark.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/4b1b3222035d776048d438cfa3e46e8e17f7ff42/docs/design/studio-redesign/findings/12515/after-published-published-toggle-light.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/4b1b3222035d776048d438cfa3e46e8e17f7ff42/docs/design/studio-redesign/findings/12515/after-published-published-toggle-dark.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/4b1b3222035d776048d438cfa3e46e8e17f7ff42/docs/design/studio-redesign/findings/12515/before-light-requests.txt?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/4b1b3222035d776048d438cfa3e46e8e17f7ff42/docs/design/studio-redesign/findings/12515/after-light-requests.txt?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/4b1b3222035d776048d438cfa3e46e8e17f7ff42/docs/design/studio-redesign/findings/12515/after-projdraft-light-requests.txt?raw=true"
    ],
    "line_budget": "n/a",
    "cleanup": "Backend (:4615) and console (:5615) stopped by their recorded PID trees. The evidence worktree was removed after its push. The feature worktree ../objectui-issue-12515 is kept because no PR is open yet (the os-dev cleanup step follows the PR opening).",
    "pr_title_draft": "feat(app-shell): Form tab Preview renders the draft definition, with a Draft preview chip and a Draft / Published toggle (objectui#12515)",
    "pr_body_draft": "(elided by the seat: opened verbatim as the body of PR #12576, read back identical)"
    }

    Relayed verbatim by seat domain:ui#4 (session session_01SJn1GEkrbbBQkhGC26wEDw) from the cloud session's final message, the degraded write channel. The seat opened the draft PR #12576 from pr_title_draft and pr_body_draft, with assignee os-sales. "pr": null above is the session's own value at report time.


    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 portaldomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions