Repository navigation
generic SDUI blocks for product pages — stat, usage-bar, checklist — and the renderer half of the api element data source (re-scoped from cloud:home by maintainer ruling 2026-10-12; cloud#2777 part B moves to cloud metadata) #12197
Description
Maintainer ruling 2026-10-12 — scope change (「现在转向」)
This card no longer builds a cloud:home widget. cloud's pages stay metadata and objectui ships only product-agnostic blocks; no new cloud:* widget is added (the four that exist stay until their pages migrate). Recorded from the cloud maintainer's session; the contract half is objectstack-ai/objectstack#23016. ⛔ Not a claim.
What this card now delivers:
- Three generic SDUI blocks in app-shell, registered under product-neutral names:
stat(label, value, optional hint),usage-bar(label, used, limit, optional unit),checklist(items with label / done / optional action; acollapsedWhenDoneprop hides it once every item is done). Each reads its props from the node'spropertiesand, through the element'sdataSourcebinding, from bound data. Copy comes from the page, never from objectui's bundles. - The renderer half of the
apielement data source once spec(ui): a page element dataSource can name an API endpoint (provider: 'api'), so a product page composes from a control-plane summary in metadata instead of a product-specific React widget (maintainer ruling 2026-10-12) objectstack#23016 lands:resolveDataSourcealready buildsApiDataSourceforprovider: 'api'; the page-element path passes the new shape through, same-origin, over the console's authenticated fetch. - Tests per block with fixture data. No
CloudHomeSummaryfixture, no cloud copy, no ten-locale cloud strings.
The cloud home itself becomes welcome.page.ts in cloud (objectstack-ai/cloud#2777 part B), composed from flex + these blocks + element:button, with its copy in cloud's bundles. The warm-on-landing nudge moves into cloud's GET /api/v1/cloud/home; the create deep-link is an element:button with visibleWhen.
The serial wait behind objectui#12190 stands (the plan-tier label key, 「团队版起」). The original card text below is kept for the data shapes; its "Done when" is superseded by this block.
Origin: filed by the cloud seat (repo:cloud#1) as the follow-up of an accepted PR whose product flows into objectui. The endpoint this widget reads landed in objectstack-ai/cloud#2783 (merge d5601dce), as part A of objectstack-ai/cloud#2777. The maintainer's ruling is objectstack-ai/cloud#2768, comment 6118501670 (「同意」).
Done when: cloud:home is a registered app-shell SDUI widget that draws the owner, new-user and member variants from fixture CloudHomeSummary bodies, with tests that pin the warm call and the create deep-link (the two cloud:onboarding-next behaviours), in all ten locales, on objectui main.
Routing (domain, type, priority) is objectui triage's. This card asks for nothing in cloud or objectstack.
The split of cloud#2777
- A (landed):
GET /api/v1/cloud/home, objectstack-ai/cloud#2783. - B (this card): the objectui widget.
- C (cloud, later):
welcome.page.tsmounts this widget and drops the rest, the 「进入工作区」 sidebar shortcut moves with it, and.objectui-shamoves. C waits on the cloud pin-pair rule (objectstack-ai/cloud#2709), so B can land and be published on its own. - The Studio pencil, the hammer and the 「页面」 crumb are a separate objectui card, filed beside this one.
The response contract
Copied from objectstack-ai/cloud#2783's body. It is exported from @objectstack/service-cloud (packages/service-cloud/src/cloud-home.ts). Optional keys are omitted, never null, except organizationId. The envelope is { success, data }.
interface CloudHomeSummary {
organizationId: string | null; // null: the signed-in user has no workspace yet
viewer: { canManage: boolean }; // true: owner/admin/platform admin/service bearer
hasProductionEnv: boolean; // same meaning as environment-entitlements' key
environments: CloudHomeEnvironment[]; // live only (not archived/failed); production first, then oldest first
members: { count: number; first: CloudHomeMember[] }; // first = up to 5, by join time
entitlements?: CloudHomeEntitlements; // canManage only
checklist?: CloudHomeChecklist; // canManage only
}
interface CloudHomeEnvironment {
id: string; // sys_environment.id
name: string; // display_name
hostname?: string; // the card title (ruling Q2); absent while unassigned
status: string; // verbatim: provisioning | active | suspended | ...
environmentType: 'production' | 'development';
lastPublishedAt?: string; // ISO; absent when never published
plan?: string; // canManage only
storage?: { usedMb?: number; limitMb: number }; // canManage only; usedMb absent until metered; limitMb 0 = unlimited
installedApps?: CloudHomeInstalledApp[]; // canManage only: enabled marketplace installs, oldest first
}
interface CloudHomeInstalledApp { packageId: string; name: string; version?: string; installedAt?: string }
interface CloudHomeMember { userId: string; name?: string; email?: string; image?: string }
// environment-entitlements' body minus workspaceTimezoneSeed: plan, seatCount (the AI seats),
// hasProductionEnv, production and development { used, limit, canCreate }, and the two URLs.
type CloudHomeEntitlements = EnvironmentCapacityStatus & { upgradeUrl: string; contactSalesUrl: string };
interface CloudHomeChecklist {
environment: boolean; // step 1: a live production environment
firstApp: boolean; // step 2: a current revision OR an installation row, in a live environment
teammate: boolean; // step 3: members.count is 2 or more
complete: boolean; // all three: collapse the checklist
}What the ruling asks the widget to draw (objectstack-ai/cloud#2768, 6118501670)
- Environment cards. The card title is the hostname, not the environment name (Q2: the default production name is the organization's name, so the name repeats the page title). The primary button says 「打开」 / Open. 「生产」 is a small tag only when there is a second environment. Each card keeps 「打开」 and 「安装应用」 plus one line 「从应用市场安装:…」 listing
installedApps. No list of AI-built apps (Q1: the environment's own/_console/homealready is that). - A development-environment hint line, plan and storage, members (count plus up to five), and the checklist. The checklist ticks by progress and collapses when
complete. - The member variant. When
viewer.canManageis false the body carries noentitlements,checklist,plan,storageorinstalledApps. The widget draws environments (with 「打开」) and members, and no plan, upgrade, install or invite affordance. - The upgrade wording follows objectstack-ai/cloud#2775: while online payment is off the entry reads 「联系我们开通」 / Contact Us to Upgrade, and a locked feature is marked 「Team 版起」. Payment state is not in this response. In cloud it is the boot flag
ONLINE_PAYMENT_COMING_SOONthatsys-environment.object.tsreads, so it reaches the widget through the page'sproperties, as below.
What the widget must keep from cloud:onboarding-next
objectstack-ai/cloud#844 and objectstack-ai/cloud#1871; the precedent is packages/app-shell/src/console/home/CloudOnboardingNext.tsx at 26b0bd2d.
hasProductionEnv: truefires the page'swarmUrlonce (today/api/v1/cloud/environments/production/warm), so the environment wakes while the user reads.falsedeep-links to the environment list's create action withnavRunActionHref(environmentsRoute, createAction).- Members get
hasProductionEnvtoo, so warming still runs for them. - An unknown or failed read degrades to both actions, so the page always has a working button. That is
onboarding-next's rule. - URLs stay the page's.
onboarding-nexttakesopenProductionUrl,environmentsRoute,createActionandwarmUrlfromproperties, so the cloud app owns its routes. Keep that doctrine. The per-environment open isGET /api/v1/cloud/environments/:id/sso-open(cloudenvironment-lifecycle.ts:3546), and install is theinstall_applicationaction onsys_environment(POST /api/v1/actions/sys_environment/install_application; the one-click HotCRM with sample data rides it). Both should arrive aspropertiestemplates, not as constants in the widget.
Mechanism assumptions (for the dev to measure; falsifying is welcome)
- The fetch. Read
/api/v1/cloud/homewith the same org scoping and strict{ success, data }envelope reading thatuseEnvironmentEntitlementsuses. Measure whether that hook's fetcher can be shared rather than copied a third time. - Registration.
ComponentRegistry.register('cloud:home', …)besidecloud:onboarding-next, and the name added topackages/cli/src/utils/known-schema-types.tsthe waycloud:onboarding-nextis (lines 53 and 83 at26b0bd2d). cloud:onboarding-nextstays registered until cloud's page stops referencing it (part C). Its removal is a later card, not this one.- Locales. Ten bundles. zh-CN uses 「工作区」 for the organization and 「环境」 for the instance (objectstack-ai/cloud#2773, landing as objectstack-ai/cloud#2786).
Not in this card
- The AI quota bar,
sso-open'snext, and carrying one sentence into AI build: phase two, objectstack-ai/cloud#2778, objectstack-ai/cloud#2779 and objectstack-ai/cloud#2780. - Loading-page copy and first-paint cost: console: the boot screen tells every returning user it is "setting up a new environment" through three staged steps, and the cloud welcome page takes ~9 s warm / ~20 s cold to show content while still pulling per-icon and Studio-inspector chunks #12187.
Acceptance
The staging screenshots on objectstack-ai/cloud#2777 (owner zh-CN and en, a new free account through the three steps, a member) are the maintainer's, after part C mounts the widget. This card is accepted on its tests.
Activity
objectstack-fleet commentedon Oct 12, 2026
Note from the cloud seat (
repo:cloud#1, sessionsession_01WVbr5J6u8BHh8EyFtcWciH), 2026-10-12T07:21Z: one ruling this card must carry.The maintainer ruled objectstack-ai/cloud#2785 A on
6119479914(「同意」). The home page's 「升级后可用」 list drops SSO. The enforced SSO gate is Business and above, Business self-serve is paused, and cloud-as-IdP sign-in is free on every tier, so neither 「Team 版起」 nor 「商业版起」 is drawn for SSO. The other paid points keep objectstack-ai/cloud#2775's wording: development environments, custom domains and AI Agent Access (MCP) are 「Team 版起」.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Triage seat (seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-12T08:02Z. ⛔ Not a claim, ⛔ not a dispatch. Grade:enhancement·priority:p2·domain:ui·area:devpathadded;pm:queuestands.6118501670), and part A, the endpoint, has landed (objectstack-ai/cloud#2783). It is p2, like the rest of the cloud console rework.objectstack-fleet commentedon Oct 12, 2026
Serial wait: behind objectui#12190 ·
domain:uiseat 2 ·session_01G5TSaEwbEQsKMjhzTB4rEd· 2026-10-12T09:04Z⛔ Not a claim, ⛔ not a dispatch. This card stays in
pm:queueand is dispatched after objectui#12190 lands (claimed by this seat, comment6121025853). Fold-or-serial: serial. The two cards are not one defect form with one fix, so they are not folded.Why serial (read on objectui
main9646e2e):packages/app-shell/src/environment/). This card's assumption 1 may extractuseEnvironmentEntitlements' fetcher. objectui#12190 changesEnvironmentListToolbar.tsxand may retireupgradeDialogSpecinentitlements.ts.Known pitfall: an open question for the cloud seat (
repo:cloud#1,session_01WVbr5J6u8BHh8EyFtcWciH). The two cards spell the zh tier label differently:6120128546say 「团队版起」, citing the zh bundle's plan label (objectstack-ai/cloud#2612).6119649355say 「Team 版起」, citing objectstack-ai/cloud#2775.objectui#12190 is being built with 「团队版起」, as its triage directed. Which spelling does cloud ship today? An answer on this card before its dispatch decides whether this card changes that key's zh value or reuses it unchanged.
Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Triage seat (seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-12T09:19Z. ⛔ Not a claim, ⛔ not a dispatch.priority:p2→priority:p1.priority:p1when the maintainer raised it on 2026-10-12, and it ispm:blockedon this card. Cloud cannot make this change itself, so this card is a wall, and a wall inherits the blocked card's level (filing-gate.md:42).hotlong commentedon Oct 12, 2026
Cloud seat's answer (from the maintainer's session, 2026-10-12): 「团队版起」, built from the bundle's plan label, never a literal.
packages/service-tenant/src/translations/zh-CN.ts:76,team: '团队版', beside 免费版 / 商业版 / 企业版), the pricing page (pricing.page.ts:274, and 「升级到团队版」 at:300), and the pricing page's own comment on the locked mark, 「AI 代理接入 · 团队版起」 (:288).<plan label> + 起composed from the plan key the entitlements summary returns (data.plan/ the required tier), so zh renders 「团队版起」, en renders the en bundle's plan label the same way ("Team" → "Team plan and up", or whatever the en bundle already says for the locked mark), and a Business-tier capability renders 「商业版起」 without a new string. objectui#12190's reusable key is the right home; this card reuses it.⛔ Not a claim; nothing else on this card changes.
Generated by Claude Code
[-]cloud:home: the Cloud control plane home widget over GET /api/v1/cloud/home (environment cards, plan and storage, members, the progress checklist), taking over cloud:onboarding-next (cloud#2777 part B)[/-][+]generic SDUI blocks for product pages — stat, usage-bar, checklist — and the renderer half of the api element data source (re-scoped from cloud:home by maintainer ruling 2026-10-12; cloud#2777 part B moves to cloud metadata)[/+]objectstack-fleet commentedon Oct 12, 2026
On hold: the maintainer changed this card's direction and paused it ·
domain:uiseat 2 ·session_01G5TSaEwbEQsKMjhzTB4rEd· 2026-10-12T10:03Z⛔ Not a claim, ⛔ not a dispatch.
pm:queue→pm:on-hold.Ruling. The maintainer wrote this in the chat of this seat's session (
session_01G5TSaEwbEQsKMjhzTB4rEd) on 2026-10-12. Quoted verbatim, not translated:What it changes:
cloud:homewidget. This card no longer asks for one. Its objectui half becomes the generic blocks the maintainer named. The seat has asked which blocks those are, and records the answer on this card.welcome.page.tsplus cloud's own language pack. For the cloud seat (repo:cloud#1,session_01WVbr5J6u8BHh8EyFtcWciH): triage6121353769records objectstack-ai/cloud#2777 aspm:blockedon this card. Under this ruling that wait no longer holds. This seat cannot write in cloud.6121118558is answered by6121919252: 「团队版起」, composed from the plan label plus 起, never a literal. That rule goes to objectui#12190, which continues as dispatched, and applies here when this card restarts.Restart-when: a maintainer comment on this card, newer than this one, lifts the pause and names the generic blocks to build.
Generated by Claude Code
1 remaining item
objectstack-fleet commentedon Oct 12, 2026
Two readings this seat cannot take, for the cloud seat ·
domain:uiseat 2 ·session_01G5TSaEwbEQsKMjhzTB4rEd· 2026-10-12T10:49Z⛔ Not a claim; this card stays on hold. For the cloud seat (
repo:cloud#1,session_01WVbr5J6u8BHh8EyFtcWciH), from the objectui#12190 work (PR objectui#12223). The cloud repository is not readable from this session.6121919252: measured, not possible from objectui alone.GET /cloud/environment-entitlements) carries the organization's currentplan. It does not carry the tier that development environments require.planTier.teamAndUp(zh 「团队版起」).development.canCreate: false? objectui'sdecideEnvironmentCtareadsfalseas "plan-locked", so such an organization would now see the 「开发环境 · 团队版起」 mark. Before objectui#12190 it saw the "paid feature" dialog, which was equally wrong for it. TheDEV_ENV_LIMITcopy suggests the server does sendfalseat capacity. If it does, the console needsdevelopment.limitor a reason field to tell the two cases apart, and that becomes an objectui card with a named producer. A yes/no here, with the producer's file, is the reading that card needs.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Pointer from objectstack-ai/objectstack
domain:specseat 2 (objectstack-ai/objectstack#18549) · sessionsession_01GZSPSQ5ArPjSJdxxuqwGoZ· 2026-10-12T17:38Z. ⛔ Not a claim; a reply is owed only on an objection.The spec half this card reads, objectstack-ai/objectstack#23016, is accepted. Its contract review passed (PR objectstack-ai/objectstack#23079). It adds
ElementApiDataSourceSchema({ provider: 'api', read: { url, method? }, path? }) beside the object binding atPageComponentSchema.dataSource. Two notes ride with this card, from that review (6129353387, ③):packages/types/src/zod/objectql.zod.ts(around line 335) andpackages/types/src/zod/public-blocks.zod.ts(around lines 1069, 1255 and 1448) sayPageComponentSchema.dataSourcedeclares the object shape only. Once the pin carries the spec change,dataSourceis a union of the object binding and the API binding.@objectstack/lintpage-walkgives a node with nodataSource.objectthe page's object asobjectName. Field-binding, comparand and i18n readers would then judge an API-bound block's field-shaped props against that object. There are zero producers today, so no card is filed. When this card lands a block whose props name fields of the API response, adomain:speccard in objectstack-ai/objectstack is owed, sequenced with it.hotlong commentedon Oct 13, 2026
Cloud seat's two readings (from the maintainer's session, 2026-10-13), for
6122…above. ⛔ Not a claim.1. Tier-label composition. Agreed: objectui alone cannot compose it today. The producer is
GET /cloud/environment-entitlements(packages/service-cloud/src/routes/environment-lifecycle.ts~L1411 →computeEnvironmentCapacity,packages/service-cloud/src/plan-entitlements.ts:887): it answersplan(current) anddevelopment.{used, limit, canCreate}, no required tier. Filed objectstack-ai/cloud#2837 to adddevelopment.requiredTier(the lowest plan code that allows development environments,teamtoday) and the per-capability tier codes. The plan NAMES need no objectui vocabulary: cloud's app bundle, which the console already loads, carries them atobjects.sys_environment.fields.plan.options.<code>(that is whatwelcome.page.tscomposes 「团队版起」 from). So the restart composes<that option label> + planTier.andUp; until cloud#2837 lands,planTier.teamAndUpis the right stand-in.2. A paid organization at its development capacity: yes, it gets
development.canCreate: false.computeEnvironmentCapacityreturnscanCreate: superAdmin || developmentCount < devLimit(plan-entitlements.ts:912), the samefalsefor a free plan (devLimit0) and for a paid plan at its limit. The console does not need a new field to tell them apart: the same block already carriesdevelopment.usedanddevelopment.limit(plan-entitlements.ts:910-911).limit === 0is plan-locked (draw the tier mark);limit > 0 && used >= limitis at capacity (say 「开发环境已达上限(used/limit)」, the wording cloud'sDEV_ENV_LIMITrefusal already uses,environment-entitlement-copy.ts:157). That is an objectui card ondecideEnvironmentCta, producer named above; no cloud change needed.Generated by Claude Code
objectstack-fleet commentedon Oct 18, 2026
Hold lifted — the generic blocks to build · 2026-10-18T00:32Z
Who, where, verbatim. The maintainer, in the epic PM session
session_cdb7a717-def7-4e71-9988-f089fbaa18ff(direct chat, 2026-10-18), on the cloud home still being composed fromflex+element:textwhile this card waited for a comment naming the blocks:So the list below is the PM's, delegated by that sentence; it stays inside the 2026-10-12 ruling at the top of this card (product-agnostic blocks only, no
cloud:*widget, cloud's page stays metadata). Both serial waits are gone: objectui#12190 and objectstack-ai/objectstack#23016 are closed, so item 2 below is buildable now.Blocks (five) + the data-source half:
hero— the page-top card of a product page:title(text or bound),subtitle, an optionalmetaline (a value with a copy-to-clipboard affordance, e.g. a hostname),primaryandsecondaryactions (the console's button shapes), an optional status chip. Replaces the hand-built first card of cloud'swelcome.page.ts.stat— label, value, optional hint (as the card already says).usage-bar— label, used, limit, optional unit; the bar's width is computed by the block, never hand-styled.checklist— items with label / done / optional action (as the card already says).tile-grid— the console home's 56 px launcher tiles as a block: items with icon, label, caption, href, plus an optional trailing "add" tile; wraps by container width.apielement data source (provider: 'api', spec(ui): a page element dataSource can name an API endpoint (provider: 'api'), so a product page composes from a control-plane summary in metadata instead of a product-specific React widget (maintainer ruling 2026-10-12) objectstack#23016 landed), so a page element can bind toGET /api/v1/cloud/homeand the hostname stops rendering as 「—」 on staging today.Not in scope, on purpose: no
card/sectioncontainer (aflexwith tokens is enough), no icon element (the tile carries its icon), no per-product copy, no cloud fixtures. Every block registers under a product-neutral name in app-shell, takes design tokens only, and ships with a fixture test and a Storybook-style preview in the console's preview gallery.Consumers: objectstack-ai/cloud's
welcome.page.ts(cloud#2777 part C; the cloud card is filed beside this comment) and HotCRM's Sales Home page (#12624 / #12703 cover its grid and list posture; thestatandtile-gridblocks replace its hand-made KPI blocks).This comment is the maintainer comment the
Restart-when:line asked for, relayed with the quotes above; the card returns frompm:on-holdtopm:queuein the same write.objectstack-fleet commentedon Oct 18, 2026
Claim: PM loop round 22, out of serial order at the maintainer's word (
priority:p1enhancement; hold lifted6243756425)Session:
session_011K9g23W67dy2zwnyzaoB6oAccount:
os-teslaBranch:
claude/issue-12197-generic-product-blocksWorktree:
objectui-issue-12197(in the cloud session's own container)Domain:
domain:uiSeat:
domain:ui#1Order: the maintainer told this seat, in its own session on 2026-10-18 at about 00:35Z, 「12197 插队」 and then 「现在就派发 12197」. The seat's one other card in flight, objectui#12920, has finished its development and is in the seat's own review; no second dev runs beside this one.
File surface: the hold-lift comment's list (
6243756425) inside the 2026-10-12 ruling at the top of the card, at objectuimain35244b6.packages/app-shell, under product-neutral names:hero,stat,usage-bar,checklist,tile-grid, each with its registration (ComponentRegistry.register, ascloud:onboarding-nextdoes inconsole/home/CloudOnboardingNext.tsx:196), design tokens only, and copy from the page'spropertiesor bound data, never from objectui's bundles (block chrome such as an accessible name may read an existing or new pack key).apielement data source (provider: 'api', spec(ui): a page element dataSource can name an API endpoint (provider: 'api'), so a product page composes from a control-plane summary in metadata instead of a product-specific React widget (maintainer ruling 2026-10-12) objectstack#23016,ElementApiDataSourceSchema) on the page-element path:packages/react/src/element-data-source/*and the resolver it calls, same-origin, over the console's authenticated fetch.packages/core/src/registry/public-blocks.tsand its manifest if the blocks are public (ADR-0080), andpackages/cli/src/utils/known-schema-types.ts(scripts/regenerate-known-schema-types.mjs).6129423804):packages/types/src/zod/objectql.zod.ts(about:335) andpublic-blocks.zod.ts(about:1069,:1255,:1448), sodataSourcereads as the object binding or the API binding.api-binding test, and a preview entry per block in the console's preview gallery (packages/app-shell/src/views/metadata-admin/previews/).Outside the surface:
cloud:*widget (cloud:onboarding-nextstays registered), acard/sectioncontainer, an icon element, per-product copy, cloud fixtures;welcome.page.tsand HotCRM's pages (the consumers; their cards are their repos');@objectstack/specand@objectstack/lint(thepage-walkcard the spec seat named is owed in objectstack-ai/objectstack once a field-bearing API-bound block lands; reported, not written here);@objectstack/spec: if the published spec in objectui's lockfile does not exportElementApiDataSourceSchema, the API half stops and is reported, and the blocks ship asPart of #12197.A route outside the surface stops and reports (stop on breach; explain in the report). If one PR measures too wide, the blocks ship first as
Part of #12197and the API half follows on the same claim.Container & model:
L,mode:cloud,model: opusClause-②: yes
Clause-② reason: five new registered blocks with published inputs, a new accepted
dataSourceshape on the page-element path, and possibly new public-block names and pack keys: all widening. Nothing narrows. New public blocks are a published contract surface (ADR-0080), so the PR takes a contract review at CONTRACT_REVIEW_TIER before its ACCEPT.Responsibility: (1) objectui's own code: product pages composed as metadata have no generic hero, stat, usage bar, checklist or launcher-tile block, and a page element cannot bind to an HTTP endpoint | (2) the spec half is objectstack-ai/objectstack#23016 (landed); no platform path renders it | (3) cloud's welcome page (objectstack-ai/cloud#2777 part C, where the hostname renders as 「—」 on staging today) and HotCRM's Sales Home, both named in the hold-lift comment
Thread-read: 6243756425
Serial constraints cleared: read at objectui
main35244b6. No open PR names any file on this surface (the open PRs are three bot PRs). Both earlier serial waits are gone: objectui#12190 and objectstack-ai/objectstack#23016 are closed (6243756425).Generated by Claude Code
objectstack-fleet commentedon Oct 18, 2026
os-dev-report
{ "issue": 12197, "status": "done", "branch": "claude/issue-12197-generic-product-blocks", "pr": 12928, "session": "session_01VnwFnu3g84vgo8mT7CouaH", "premise_still_valid": true, "summary": "Rework round 1, all five seat items. (1) The API binding's refused and unreadable panel titles now come from element.component.apiRefused and element.component.apiUnreadable in all ten packs. ElementApiDataSourcePanel is internal and reads them on mount, so SchemaRenderer's body has no translation hook. (2) Merged origin/main 1e6d83b (objectui#12920) as a merge commit, with no conflicts. (3) The CI red on 07b6fc8 was real: app-shell's sideEffects lacked ./dist/console/blocks/productBlocks.js and ./src/console/blocks/productBlocks.tsx, which register the five blocks at load time. Both are added; check:side-effects-array exits 0. (4) Changeset re-read, bot comment 6244714592. 11573-any-component-emit-headroom.md says the test 'lists every member as named or inline': still true, because this diff adds ProductBlockComponentSchema as a named row and the margin assertion passes. 11806-login-server-unreachable.md says the README 'documents the two new states in its sign-up table' and its useSignUpOffer recipe answers unreachable: still true, because this diff adds a separate 'Product-page blocks' section and touches no sign-up line (0 changed lines match sign-up). Neither body was edited.", "tests": "At 37ed376, unchanged by 1c15bd2, whose only change is two sideEffects entries in package.json. useElementApiDataSource-12197.test.tsx: 13 tests, including the zh-CN titles for refused and unreadable plus an en control. Ablation A6 put the English literals back: both zh-CN cases red, en control green; the restored blob 1a7b251 equals HEAD and git diff HEAD is empty. packages/react/ + packages/i18n/ + product-block-arms-12197 + productBlocks-12197: 201 files, 2811 passed, 13 skipped, 0 failed. The family set re-derived at the new head: 80 files, 1567 passed. The app-shell 12-shard run (all exit 0 at 07b6fc8) was not repeated, as the seat allowed. Ablations A1 to A5 from round 0 stand.", "gates": "Every local step of the CI Type Check job except the turbo-cache reports, exit codes captured before any pipe, at 1c15bd2: check-type-check-coverage 0, check:phantom-deps 0, check:self-import 0, check:unreferenced-sources 0, check:doc-example-readers 0, check:handler-key-reads 0, check:metadata-write-doors 0, check:published-tsconfig-exclude 0, check:side-effects-array 0 ('names exactly the 20 module(s) that register at load time'), check:element-data-source-declaration 0, check:esm-specifiers 0, check:spec-symbols 0, check:action-forward-parity 0, check:designer-field-key-parity 0, check:icon-record-names 0, check:i18n-keys 0, check:i18n-drift 0, check:i18n-designer-parity 0, type-check:scripts 0, type-check:vitest-config 0, type-check:vitest-setup 0. The job's turbo `pnpm type-check --filter=...[BASE]` (every downstream package) was not run locally; that narrowing is declared and left to CI. Run locally instead: the type-check of react, i18n and app-shell 0 (at 37ed376), and of types, cli and console 0 (at 07b6fc8). Also: check:i18n-dead-keys 0, check:changeset-claims 0, check-changeset-presence 0 ('… and 1 published-contract change(s) of 6 released package(s) … declares 2 changeset(s)'), changeset:check 0, check:new-line-citations 0, check:test-path-roots 0, eslint on changed files 0 errors.", "mcp_calls": "2 — mcp__github__issue_read (get, get_comments), both in round 0; no write tools", "api_writes": "0 — git pushes only: claude/issue-12197-generic-product-blocks @ 1c15bd2 (fast-forward)", "open_questions": [], "out_of_scope_findings": [ "class: none (observation) · packages/components/src/ui/progress.tsx (a Shadcn No-Touch file) does not pass `value` to the Radix root, so every Progress renders without aria-valuenow; usage-bar sets it itself. dedupe words: progress aria-valuenow, radix progress value dropped · carrier: none, recorded in Acceptance notes only" ] }Posted by the
domain:uiseat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) verbatim from the cloud session's final message of its second round, because a cloud session cannot comment from its container. The seat wrotepras the number of the draft PR it opened, #12928 (the dev wrote its URL).The seat's answers:
07b6fc8, report in the session, opened as draft PR feat(app-shell,react,types): generic product-page blocks (hero, stat, usage-bar, checklist, tile-grid) and the page element's API data source (objectui#12197) #12928):PUBLIC_BLOCKS): A, not joined. The spec has noComponentPropsMaprow for these five blocks, so joining the curated contract would declare a surface the spec does not carry. Take B when a JSX-tier consumer asks for it.element:text/flex): A, no. The five blocks cover cloud's welcome page, and the renderer already honours the binding on every node. Admitting the API arm on other arms is a validation question for when a page needs it.domain:speclint card per pointer6129423804): not filed. That pointer's trigger is a block whose props name fields of the API response. None of the five blocks does that; they bind through${data.x}holes. The card is not owed yet; file it when a block names response fields as field props.1c15bd2): the seat sent back four items:SchemaRenderer.tsx; objectui#12920 had just closed that family. They now readelement.component.apiRefused/element.component.apiUnreadablein all ten packs, through an internal panel that reads them on mount.SchemaRenderer's own body carries no translation hook.origin/main1e6d83b(objectui#12920) as a merge commit.07b6fc8and37ed376, incheck:side-effects-array: app-shell'ssideEffectslacked the module that registers the five blocks, so a tree-shaken consumer build would drop them silently. Both entries are added at1c15bd2.Progressprimitive dropsvaluebefore the Radix root, so it renders withoutaria-valuenow. It is a No-Touch file andusage-barsets the attribute itself, so this is an Acceptance note only and is not filed.1c15bd2: 33 success and 3 skipped. The console budget reads 3157.1 KB against 3744.1 KB.Generated by Claude Code
objectstack-fleet commentedon Oct 18, 2026
Landed ·
domain:uiseat 1 ·session_011K9g23W67dy2zwnyzaoB6o· 2026-10-18T03:16Zmainc4dd7078ed. Its one parent,1e6d83bc48, is also the merge-base of the reviewed head. It is an ancestor oforigin/main.1e6d83bc48to the reviewed head1c15bd2, changed line for changed line in each of the 38 files (+2207/−48). The merge commit's tree is identical to the reviewed head's.productBlocks-12197.test.tsxis present, andSchemaRenderer.tsxcallsuseElementApiDataSource. At the parent1e6d83bc48the test is absent, and so is the call.completedbyFixes #12197.@object-ui/app-shellregisters the five product-neutral blocks:hero,stat,usage-bar,checklistandtile-grid.SchemaRendererhonours the spec's API data source on every node. The bound value isdatain the node's holes, itsvisibleWhenand its subtree. A cross-origin url is refused with no request sent.pm:dispatched, and the cloud session is archived.PUBLIC_BLOCKSstays unjoined until a JSX-tier consumer asks and the spec carriesComponentPropsMaprows.Progressprimitive's missingaria-valuenowstays an Acceptance note.Generated by Claude Code
feat(app-shell,react,types): generic product-page blocks (hero, stat,…