Repository navigation
feat(spec,ui)!: retire the record page's slots.tabs; a page that needs its own strip is kind: 'full' - #27219
Conversation
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzff3QiP6kmtajVnKnq
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzff3QiP6kmtajVnKnq
…DR-0133 amendment, QA pins, skills bullet, changeset Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzff3QiP6kmtajVnKnq
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzff3QiP6kmtajVnKnq
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzff3QiP6kmtajVnKnq
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzff3QiP6kmtajVnKnq
…rebuild; preview slot fixture Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzff3QiP6kmtajVnKnq
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzff3QiP6kmtajVnKnq
… avoid the reserved word Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzff3QiP6kmtajVnKnq
📓 Docs Drift CheckThis PR changes 3 package(s): 60 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 16 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 148 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 3dfd02d0e764224d37973c01646bd498370525e3 && git checkout 3dfd02d0e764224d37973c01646bd498370525e3
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 1e8e5296f31742a614395d4267fb7de5172a852c 9573871084ddd8e1b72193a39ee6529df0e64af9 && git checkout -B drift-repro 1e8e5296f31742a614395d4267fb7de5172a852c && git merge --no-ff 9573871084ddd8e1b72193a39ee6529df0e64af9
node scripts/docs-audit/affected-docs.mjs --json 1e8e5296f31742a614395d4267fb7de5172a852c
|
Contract reviewServed-tier: Inputs: card #27053 (body; claim 6465037594; os-dev-report 6467336687), epic #26676 round 3 (6459899198), PR #27219 body + 71-file list, the net diff against ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgmentThe narrowing, read against the published spec on (1) Faithfulness of the four
(2) D2 honesty. Disclosed (①.4), idempotent, copy-on-write, order unique, (3) Tombstone and aliases — ①.1–2: text matches the card's prescription, aliases refuse by name with the same remedy (pinned: tombstone for one component, an array and empty; alias guidance; six live slots parse; a full page with (4) Changeset / ADR-0087 / BREAKING — ②. (5) ADR-0133 amendment and the skills bullet. The amendment is one line, dated, after the paragraph it corrects, and says exactly what moved and what did not. (6) No must-fix. Two should-fixes: the header-action drift pins (④.1) and the ruling trace on the card (③). One fixture nit (①.11). Implemented-by: VERDICT: PASS |
…ection-coverage fixture is a full page Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzff3QiP6kmtajVnKnq
席位核对 · ACCEPT ·
|
|
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U Contract-review-claim: Triage seat, under the gap rule (#27062) condition (b): no record and no claim on this head after one round. The review runs at Generated by Claude Code |
Contract reviewServed-tier: Inputs: card #27053 (body; claim 6465037594; os-dev-report 6467336687; seat ruling 6467656574), PR #27219 body + 72-file list, the net diff against The moved head — delta
|
The D3 entry judges the strip that page-slots-tabs-removed applies, so it names that conversion in conversionIds. The skills bullet about the retired tabs slot moves from the source-pages section to Templates & Regions, beside the kind: 'full' rules it qualifies. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzff3QiP6kmtajVnKnq
席位核对 · ACCEPT ·
|
席位核对 · armed ·
|
|
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U Contract-review-claim: Triage seat, under gap rule (b) (#27062): this head is over 60 minutes old with no record and no claim; a delta re-review from triage's PASS on Generated by Claude Code |
Contract reviewServed-tier: Inputs: card #27053 (body; claim 6465037594; os-dev-report 6467336687; seat ruling 6467656574), PR #27219 body + 72-file list, the net diff against The moved head — delta
|
Conflicts: - ui/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts: main retired the `slots.tabs` slot (#27219) while this branch rewrote the `discussion` slot to the timeline stream and deleted `rightRail`; the resolution keeps main's no-tabs-slot doc and branch, this branch's timeline-stream `discussion` doc, and no `rightRail`. - ui/packages/app-shell/src/views/RecordDetailView.tsx: the `@object-ui/plugin-detail` import line takes the union of main's queue claim imports (#27264) and this branch's timeline/arrangement imports. Claude-Session: https://claude.ai/code/session_cdb7a717def74e719988f089fbaa18ff Co-Authored-By: Claude <noreply@anthropic.com>
…etirement on main made dead main retired `slots.tabs` (#27219) and pins the stray-slot case itself ("reads no `tabs` slot"); this branch's case that a `discussion` slot beside an authored `tabs` slot stays under the strip pins a path that no longer exists. The timeline-stream `discussion` slot stays pinned by "discussion slot overrides even when hideDiscussion is true". Claude-Session: https://claude.ai/code/session_cdb7a717def74e719988f089fbaa18ff Co-Authored-By: Claude <noreply@anthropic.com>
Requested by Yibo Wang · project thread
Fixes #27053
What changes
The record page's
slots.tabsis retired under thespec-property-retirementkit. A slotted page now fills six slots (header,actions,alerts,highlights,details,discussion); a page that needs its own tab strip iskind: 'full'.Spec (
@objectstack/spec)slots.tabsis aretiredKey()tombstone carrying the card's prescription: the record page composes its tabs and columns from the object's roles and relationship flags; setrelatedList/relatedList: 'primary'on the child's reference field to change which related lists appear or their order; authorslots.detailsto replace the Details body; a page that needs its own strip iskind: 'full'. It ends with the houseos migrate meta --from 17sentence and carries no issue ids.related/relatedListsaliases leave with the slot. They are nowguidanceentries that refuse by name with the same remedy, instead of being read astabs.checkPageSlotPair(thedetails+tabsrefusal) andpage-slot-pair.test.tsare removed, and so is its@objectstack/spec/uiexport. The check-exports pin now asserts that it has zero declarations and zero attachments.page-slots-tabs-removedconversion (retiredFromLoadPath,retiredAfter: '18.2.0', order 78) dropsslots.tabsfrom a stored page. Whentabswas the only slot, the page is left as an empty slotted page, which renders the synthesized default.page-slots-tabs-retiredentry covers the judgement the conversion cannot make, which is whether such a page should becomekind: 'full'. It absorbspage-slots-details-beside-tabs-refused, because the pair no longer exists. TheSTEP18_RATIONALEfragment moves with it (order 112). The retired-key entry isui/Page:slots.tabs.retired-key-removal-version.pin.test.ts, the livenessslotsnote, and the regenerated api-surface, export-origins and references.The four in-repo producers, rebuilt as
kind: 'full'. Each rebuild is faithful: the same nodes in the order the synthesizer drew them (header, then the actions/alerts slot, highlights, the strip, then discussion). Nothing is redesigned. Header actions are the object'srecord_header/record_moreactions in declaration order, which is exactly what the synthesized header drew; the host still appends Edit/Share/Delete.sys_organization_detail@objectstack/platform-objectspage:header(4 actions) ·record:highlights(slug) · Members / Invitations / Teams strip (unchanged) ·record:discussionsys_user_detail@objectstack/platform-objectspage:header(11 actions) · therecord:alertfrom itsalertsslot · highlights · its curated strip · no discussion (itsdiscussion: [])sys_approval_request_detail@objectstack/plugin-approvalspage:header·record:approval_decision· highlights · Details / Timeline strip · no discussion (itsdiscussion: [])showcase_project_detailexamples/app-showcase(private)page:header· highlights · Details / Tasks grid / Related strip ·record:discussionConsole (
@object-ui/*)buildDefaultPageSchemacomposes from the six slots only, and its tabs branch is removed.RecordDetailView'spageColumnsEligibledrops theslots.tabsarm, so the one gate line is now!assignedPage && !namedPageBlocked.@object-ui/typesremoves both.superRefine(checkPageSlotPair)attachments and typesPageSlotMap.tabsasnever.SLOT_ORDER) lists six slots.Docs
ui/content/docs/guide/slotted-pages.md: the slot menu no longer hastabs, and the guide says how to shape the strip instead.content/docs/ui/pages.mdx(merged from main during this branch): the same change.skills/objectstack-ui/rules/pages.md: one bullet. It is paid for by a deletion in the same file (−23 tokens net).ADR-0133 and QA
identity-auth.jsonsource pin moves with it (revision 6).studio-authoring.jsonfollows the retired pair: the step now PUTsslots.tabs, which is refused withinvalid_type. The pin file, the source anchor and revision 4 are updated to match.Why
An authored
tabsslot replaced the whole synthesized strip. A page that used it lost every related list, approval, attachment and history entry the platform composes from the object, and stayed a tab strip at every width instead of taking the record page's columns. The maintainer ruled the slot out on epic #26676; the card carries that ruling.Acceptance notes
slots.tabs("HotCRM never uses tabs"). Re-measured on main at0f1045bc, four in-repo pages authored it: the table above. Seat 1 confirmed moving all four tokind: 'full'with identical behaviour.tabs, it parses unchanged. If it does, its stored row is converted on read by the D2 conversion, and its source is listed byos migrate meta --from 17.safeParseoftabs/related/relatedListsfails with the prescription, and the six live slots parse.page-slots-tabs-retirement.test.tshas 18 cases:page:tabsparses;#and the migrate sentence;@ts-expect-errorondefinePage;checkPageSlotPair.tabsreplays through the conversion:applyConversionsToStoredItem('page', …), the tabs-only page becomesslots: {}, the conversion is idempotent, and it is retired from the load path. The registry fixture has three pages and expects two notices.packages,examples,skills,content,scripts) refuses aslotsframe holdingtabs,relatedorrelatedListsin.ts,.json,.yamland.mdfences. It excludes the conversion fixtures, the json-schema output, release notes and changelogs.details) or reads the full page's region:i18n-resolver.test.ts(two fixtures),page-component-filter-record-to-rule-array.test.ts,object-refinement-check-exports.test.ts,retired-key-removal-version.pin.test.ts(new JOIN row).page-slot-pair.test.tsis deleted.page-walk,validate-page-field-bindings,validate-visibility-predicatesandpage-envelope-audittests.i18n-section-coverage(its fixture is now akind: 'full'page whose region authors its ownpage:tabs, keeping the nesting under test),platform-page-i18n-parity(the boundary pin now expectskind: 'full', noslots, every component reached, and none addressed).sys-user-details-tab,sys-user-security-tab-own-record,sys-user-two-factor-display,setup-nav-per-user-storesandcanonical-expression-envelopes(the control's path is nowregions[0].components[N].visibleWhen); newrecord-page-header-actions.test.ts(round 2, review should-fix ④.1: forsys_organization_detailandsys_user_detail, thepage:headeraction ids equal the object'srecord_header∪record_moredeclarations in declaration order, with a non-vacuous guard); comments ininvite-entry-toolbar.test.tsandsys-member.object.ts.sys-approval-request-page.test.ts, which pins the page body in order.task-detail.page.tsandrecord-action-location-hosts.test.ts.buildDefaultPageSchema.test.ts(a straytabskey is ignored anddetailsapplies),recordPageColumns.test.ts,slots-canvas.test.ts,PagePreview.test.tsx,spec-object-refinements-7715.test.ts(the retired slot is refused at both objectui doors),imported-defaults-8317.test.ts, and the ten console served-approvals-page copies (approvalRequestsDataSource.servedPage*.test.tsx,ApprovalsInboxPage.opensServedPage-12484.test.tsx), which now copy the full page whole.Verification
Head
ca5556e06, with main merged atb322b5da(11 commits, no conflicts). Runs below are local, underos-verify-lock.--project localhas 22219 passed. The 3 reds from the first run were fixed and their files re-run green (166 passed): a conversion fixture moved todetails, the new JOIN row, and the export-origins regeneration.test:repohas 82 files / 1343 passed, including the tree-scoped absence pin, which is now listed invitest.repo-tests.json.organization-record-page-option, 3 passed.plugin-detail: 2941 passed.RecordDetailViewrecord-page tiers and named-page tests: 13 passed.PagePreview: 8 passed.turbo run typecheckover spec, platform-objects, plugin-approvals, lint, cli, example-showcase,@object-ui/types,plugin-detail,app-shelland console: 104 of 104 tasks pass. This includes the test-layer typecheck ledgers.dispatch-gates --commandslists 126 commands, and 121 exit 0. Of the other five:check:role-wordandcheck:cross-package-test-inputswere real findings. Both were fixed and now exit 0.check-plugin-teardown-shape --self-testexited 3 because the clone is shallow. After fetching its pinned fixture commit it passes all 48 cases.check:skill-examplesandcheck:dual-build-cjs-loadsexit 3 because they need a full repo build. That is a prerequisite miss, and nothing was measured.check:generated --fixregenerated three artifacts (api-surface, export-origins and references), and each re-checks green.check-platform-checklist,check-skills-token-ratchet(pages.md5669/5692) andcheck-adr-0087-registration --base origin/mainare green.Clause-②: no (narrowing)
Metadata-protocol: narrowed
Skills-docs: follow-up #27059
Keep one value on each of the two lines above, each line starting with its key.
Human Minimum
item 5 says what they mean.
The changeset carries
Clause-②: no (narrowing),Metadata-protocol: narrowed, the BREAKING banner, a FROM → TO. line and<!-- adr-0087: registered page-slots-tabs-removed, page-slots-tabs-retired -->. The packages bump minor: spec, platform-objects, plugin-approvals,@object-ui/types,@object-ui/plugin-detail,@object-ui/app-shelland skills.Governed surfaces (
docs/adr/**,skills/**, Tier H): this PR is a draft and is not queued or armed. It needs a governed approver's review before the seat lands it.Human Minimum
Each item is one rule from
CONTRIBUTING.md › Human Minimum,
which links the AGENTS.md text that states it.
packages/specholds no runtime logic.pnpm lintpasses.main, one pull request.packages/spectouched: its generated artifacts are regenerated and committed.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_01WGufzff3QiP6kmtajVnKnq