From 0b0b27946fa2ddb57ed06d241acf2f9b3991eaf2 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 04:53:19 +0000 Subject: [PATCH] docs(spec): retire stale renderViaSchema forward-reference + browser-verify ADR-0085 detail shapes (#2548) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to objectui#2546 (ADR-0085 PR4), which removed the legacy monolith detail renderer and the `detail.renderViaSchema` kill-switch and flagged two follow-ups for #2548: - Comment cleanup: the ObjectSchema source comment forward-referenced `renderViaSchema` retiring "together with the legacy monolith render path". That path is now gone; the comment records the completed state with a breadcrumb to objectui#2546. Comment-only — no type/runtime change. - Real-backend browser verification: drove the running app-showcase backend plus the objectui Console (post-#2546 source) in a headless browser across the four detail-page shapes (grouped / ungrouped / stageField:false / related-heavy). All render correctly through the single SchemaRenderer path, and stageField:false correctly suppresses the record:path stepper. Results + repro runbook in docs/audits/2026-07-adr-0085-detail-shapes-browser-verify.md. No regressions; no objectui follow-up required. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_016wpaFMPowSn4nAWsjeGZib --- ...r-0085-pr4-renderviaschema-comment-2548.md | 14 +++ ...7-adr-0085-detail-shapes-browser-verify.md | 103 ++++++++++++++++++ packages/spec/src/data/object.zod.ts | 4 +- 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 .changeset/adr-0085-pr4-renderviaschema-comment-2548.md create mode 100644 docs/audits/2026-07-adr-0085-detail-shapes-browser-verify.md diff --git a/.changeset/adr-0085-pr4-renderviaschema-comment-2548.md b/.changeset/adr-0085-pr4-renderviaschema-comment-2548.md new file mode 100644 index 0000000000..8d7a6cc76a --- /dev/null +++ b/.changeset/adr-0085-pr4-renderviaschema-comment-2548.md @@ -0,0 +1,14 @@ +--- +'@objectstack/spec': patch +--- + +docs(spec): retire the stale `renderViaSchema` forward-reference now that objectui#2546 landed (ADR-0085 PR4 follow-up, #2548) + +The `ObjectSchema` source comment forward-referenced `renderViaSchema` +retiring "together with the legacy monolith render path" — a promise about +work that had not yet shipped. That path, and the `detail.renderViaSchema` +kill-switch that was its only steering wheel, were removed in objectui#2546 +(ADR-0085 PR4). The comment now records the completed state with a breadcrumb +to that PR instead of a forward reference, closing the cleanup #2546 flagged. + +Comment-only change; no type, schema, or runtime behavior is affected. diff --git a/docs/audits/2026-07-adr-0085-detail-shapes-browser-verify.md b/docs/audits/2026-07-adr-0085-detail-shapes-browser-verify.md new file mode 100644 index 0000000000..f7ff92011e --- /dev/null +++ b/docs/audits/2026-07-adr-0085-detail-shapes-browser-verify.md @@ -0,0 +1,103 @@ +# Audit: ADR-0085 PR4 — real-backend browser verification of the four detail-page shapes + +**Date**: 2026-07-16 · **Scope**: objectui `RecordDetailView` rendering after the +legacy monolith detail renderer + `renderViaSchema` kill-switch were removed +(objectui#2546, ADR-0085 PR4). **Method**: drive the running `app-showcase` +backend + the objectui Console (post-#2546 source) in a real headless browser. +**Tracked as**: #2548 (the verification objectui#2546 deferred: "Exercising the +four detail-page shapes … against real data needs a running `@objectstack` +backend, which the CI/agent environment doesn't have. Deferred to #2548 with a +repro runbook.") + +## Why this is a separate pass + +objectui#2546 deleted the non-schema-driven `DetailView` monolith branch, so +`RecordDetailView` now has exactly **one** path: an authored +`PageSchema(pageType='record')` when assigned, else `buildDefaultPageSchema()` +synthesis — both rendered through ``. Unit + DOM suites and the +served-metadata proof (`packages/dogfood/test/semantic-roles.dogfood.test.ts`) +cover parse and serialization, but neither renders a page in a browser against a +live backend. This pass closes that gap for the four shapes the PR called out. + +## Fixtures (all in `examples/app-showcase`) + +| Shape | Object / record | Role posture | +|---|---|---| +| **grouped** | `showcase_semantic_zoo` | `fieldGroups: [basics, money(collapsed)]`, `stageField: 'status'`, `highlightFields: [name,status,amount]` | +| **ungrouped** | `showcase_account` (Details tab) | no `fieldGroups` → flat auto-columns | +| **stageField:false** | `showcase_semantic_zoo_legacy` | `stageField: false` with a `status`-named field (must NOT get a stepper) | +| **related-heavy** | `showcase_account` = "Contoso" | inbound lookups from contact / invoice / project / field_zoo | + +`showcase_semantic_zoo{,_legacy}` are the ADR-0085 runtime fixtures; the +`showcase_account` seed provides the ungrouped + related-heavy record (Contoso: +2 contacts, 2 invoices, 2 projects). + +## Repro runbook + +```bash +# 1. Backend — showcase on a private port + DB, seeded dev admin. +pnpm --filter @objectstack/example-showcase... build # or: pnpm build +node packages/cli/bin/run.js dev \ + -p 4600 -d file:/tmp/showcase-verify.db --seed-admin --compile \ + --cwd examples/app-showcase +curl -s localhost:4600/api/v1/health # -> {"status":"ok"} + +# 2. Console — objectui source (post-#2546) pointed at the backend. CORS is +# enabled in dev, so the cross-origin :5180 -> :4600 calls are allowed. +cd ../objectui +VITE_SERVER_URL=http://localhost:4600 pnpm --filter @object-ui/console dev # :5180 + +# 3. Auth + fixtures (better-auth Bearer). Sign in, grab the set-auth-token +# header, POST the two semantic-zoo records (not seeded), then drive the +# detail URLs with Playwright: +# /apps/showcase_app//record/ +# inject localStorage['auth-session-token'] = before app boot. +``` + +The exact Playwright driver + JSON report used for this pass are attached to the +#2548 PR discussion. + +## Results — all four shapes render correctly through the schema-only path + +| Shape | Observed | Verdict | +|---|---|---| +| **grouped** (`Zoo Grouped Alpha`) | Highlight strip `name / Active / 4,200` (= `highlightFields`); `record:path` stepper **Draft → Active → Done** (from `stageField:'status'`); ungrouped `notes` in the "More details" bucket. | ✅ renders | +| **ungrouped** (Contoso · Details) | Flat two-column field layout (owner / website / HQ / tax / billing) with the "Show 4 empty fields" toggle — no section headers. | ✅ renders | +| **stageField:false** (`Zoo Legacy Beta`) | Highlight strip `name / 99`; the `status` field renders as an ordinary **"STATUS: Green"** field with **no `record:path` stepper** (`[aria-label="Record path"]` absent). The `false` correctly suppresses the heuristic. | ✅ suppressed | +| **related-heavy** (Contoso) | Tab strip **Details · Invoices (2) · Projects (2) · Related (2)** — primary related lists promoted to their own tabs, the rest collapsed into "Related" (ADR-0085 prominence rule); lists lazy-fetch on tab show. | ✅ renders | + +`hasRecordPath` matched the expectation for every case (true for grouped + +related-heavy, **false** for stageField:false). No page-render errors, no error +boundaries, no missing-data states. + +### Note on the "grouped" fixture + +`showcase_semantic_zoo`'s grouped fields (`status` ∈ basics, `amount` ∈ money) +are *also* its `highlightFields`, so they surface in the highlight strip and the +`record:details` derivation correctly drops the now-empty Basics/Money groups, +leaving only the ungrouped `notes` ("More details"). This is the intended +"one curated list, every surface" behavior — the same reason Contoso's +highlighted `status/industry/revenue` do not repeat in its Details body. The +`fieldGroups → section` derivation itself (declared order, collapse, trailing +untitled bucket) is separately proven over the served pipeline in +`semantic-roles.dogfood.test.ts`. + +## Out-of-scope observations (not defects in the detail path) + +- `502 /api/v1/runtime/config` and `502 /api/v1/dev/metadata-events` are + **same-origin** requests the Console makes to its own origin (`:5180`); in the + split-origin verify harness the Vite server has nothing there. `initRuntimeConfig` + absorbs the failure by design and the app boots + renders regardless. Not seen + in the normal same-origin (`--ui` / vendored console) deployment. +- `401 /api/v1/approvals/requests?…` (the header approvals badge) is a peripheral + poll unrelated to record rendering; the detail pages loaded their data fine. + Left for separate triage. + +## Conclusion + +The removal of the legacy monolith renderer (objectui#2546) leaves all four +detail-page shapes rendering correctly through the single `SchemaRenderer` / +`buildDefaultPageSchema` path against a real `@objectstack` backend. **No +regressions found; no objectui follow-up required.** The framework-side cleanup +#2546 flagged (the stale `renderViaSchema` source comment) ships alongside this +note. diff --git a/packages/spec/src/data/object.zod.ts b/packages/spec/src/data/object.zod.ts index 386beb97af..28e06518f5 100644 --- a/packages/spec/src/data/object.zod.ts +++ b/packages/spec/src/data/object.zod.ts @@ -970,7 +970,9 @@ const ObjectSchemaBase = z.object({ // control is an assigned Page. The passthrough block bred silently-inert // keys (9 read by renderers vs 3 typed; the typed `hideReferenceRail` was // itself a no-op for spec authors) — see the ADR for the full inventory. - // `renderViaSchema` retires together with the legacy monolith render path. + // `renderViaSchema` — the block's last-surviving key, kept only as the + // legacy monolith detail renderer's kill-switch — retired with that + // renderer in objectui#2546 (ADR-0085 PR4). /** * Object Actions