Repository navigation
[17.0-rc2验收] sales_home_page / app_launcher_page / utility_bar_page 多个组件渲染为「Component Placeholder」,首页欢迎语用户名插值为空 #734
Description
Activity
- addedbugSomething isn't workingSomething isn't workingmetadataDeclarative metadata — schema, security posture, UI surfacesDeclarative metadata — schema, security posture, UI surfaces
on Aug 5, 2026 同页补测:Sales Home 上还有两张只有标题、没有 body 的空卡片
发现于 #771 的浏览器验证(dev server + Chromium,
@objectstack17.0.0-rc.2,基线 7667c9b)。不另开 issue —— 同一个页面、同一个"用户看到脚手架"症候族,落在本单的完成范围里,所以把实测证据补在这里。本单已记的
nav:menu → Component Placeholder、Welcome back,人名为空,两条都复现了。除此之外,sales_home_page上还有两张卡片渲染成只有标题的空盒子——机理和本单表格里那几个不同:不是"组件类型没有渲染器",而是容器组件没有 body,所以渲染器正常工作、只是没东西可画。组件 源码 实际渲染 my_recent_items(左栏)home.page.ts的page:card,只有title: 'Recent Items'+bordered: true,无body一张带边框的空卡片,卡面只有 "Recent Items" upcoming_events(右栏)同上, title: "Today's Schedule"一张带边框的空卡片,卡面只有 "Today's Schedule" 页面正文的 innerText 里,这两处就是两个孤零零的标题串,后面什么都没有:
… Key Performance Indicators Revenue (Won) 1,290,000.00 Deals Won 8 Pipeline Value 3,775,000.00 Open Leads 21 My Leads My Opportunities My Tasks Quick Create nav:menu Component Placeholder Recent Items Ask the Sales Copilot Today's Schedule(同一批测量里,
ai_briefing卡片是好的——它带description,所以有内容可渲染;四个object-metric也都取到了真实数据。)参考修法:这两张卡片要么绑上数据源(
Recent Items有平台侧的近期记录来源可用则用之;Today's Schedule指向crm_event的my_events视图是最自然的落点),要么按本单"或这些 demo 页面不随 app 发布"的第二条路一并处理。#771 没有顺手改这两张卡:那一单的不变量是"标签页名字承诺内容却渲染空白",范围严格限定在home_tabs的三个标签页(已改为内嵌list-view,实测 21 / 10 / 6 行真实数据);把侧栏卡片一起改会越界,而把守卫扩到侧栏会让规则在本单尚未修的东西上变红——那种规则最后会被抑制,不会被修。所以新增的no page tab renders an empty container守卫只覆盖 tab 子节点,侧栏卡片留给本单。
Generated by Claude Code
huangyiirene commented
on Aug 11, 2026 CollaboratorMore actionsPM note — deliberately deferred one round, with the known trap recorded (so this card is not picked up on stale premises):
- Why deferred: chore(deps): upgrade @objectstack/* 17.0.0-rc.5 → 17.0.0-rc.6 (maintainer order), and re-measure tracked upstream-mirror behavior #1059 (in flight this round) bumps
@objectstack/*rc.5 → rc.6. This card's fix direction depends on which component types the console implements: if rc.6's console ships renderers fornav:menu/global:search/global:notifications/app:launcher, the right fix shrinks to (possibly) nothing plus the two empty side-bar cards; if not, the fix is replace-or-unpublish as the body proposes. Dispatching before the bump risks building the wrong fix against a dying baseline. - Trap for the eventual dev: the scope now includes the 2026-08-05 addendum — two
page:cardcontainers with nobody(my_recent_items,upcoming_events) render as empty titled boxes; that half is a metadata fix regardless of what rc.6's console implements. Theno page tab renders an empty containerguard added by 同 #758 缺陷类:activities.mdx 的「标准列表视图」清单与「主页活动小部件」都对不上 src/views/task.view.ts,且 Sales Home 的三个标签页是空壳 #771 deliberately excludes side-bar cards; extending it is part of this card, not a rider elsewhere. - Re-measure first: all reproductions in this card were taken on rc.2. Re-verify on rc.6 (post-chore(deps): upgrade @objectstack/* 17.0.0-rc.5 → 17.0.0-rc.6 (maintainer order), and re-measure tracked upstream-mirror behavior #1059
main) before implementing; chore(deps): upgrade @objectstack/* 17.0.0-rc.5 → 17.0.0-rc.6 (maintainer order), and re-measure tracked upstream-mirror behavior #1059's report will carry a one-line probe verdict for the sibling upstream cards but NOT for this one.
Generated by Claude Code
- Why deferred: chore(deps): upgrade @objectstack/* 17.0.0-rc.5 → 17.0.0-rc.6 (maintainer order), and re-measure tracked upstream-mirror behavior #1059 (in flight this round) bumps
PM premise re-check on 17.0.0 GA — the body's 落点分析 is wrong on both halves, in opposite directions
Still
pm:queue, still not dispatched. The 2026-08-11 deferral note asked for a re-measure on rc.6 before implementing; the repo has since gone past that to@objectstack/* 17.0.0GA (package.jsononmain), so every reproduction here is now two baselines stale, not one. Before spending a live rig on the re-measure, I checked the two static questions that decide where the fix lands — and both answers contradict the body.Half 1 — the four placeholder component types are spec-blessed, so this is not an app-side authoring error
The body proposes fixing HotCRM: 「替换为已实现组件、或将这三个 demo 页面从发布元数据中移除/标注」. That presumes the app is naming component types it had no business naming. It isn't. On framework
main, all four are first-class members of the closedPageComponentTypeenum:packages/spec/src/ui/page.zod.ts:65 // Navigation 'app:launcher', 'nav:menu', 'nav:breadcrumb', // Utility 'global:search', 'global:notifications', 'user:profile',and each has a deliberate no-props row in
ComponentPropsMap:packages/spec/src/ui/component.zod.ts:2197 'app:launcher': emptyProps('app:launcher'), 'nav:menu': emptyProps('nav:menu'), 'global:notifications': emptyProps('global:notifications'),The doc block above
emptyPropsnames these exact components and states the point of the class: "these components take no configuration." So HotCRM authoringnav:menuin a card is the spec's sanctioned spelling, not scaffolding left in by accident.If the GA console still renders them as
Component Placeholder, the gap is a renderer missing for a type the protocol declares — an upstream card, not a HotCRM one. Deleting these pages or swapping in different components would be suppressing the only reproduction of an upstream hole, which is the failure mode the platform's own rules-that-get-suppressed argument warns about.⚠️ What I could not verify statically: whether the 17.0.0 GA console renders them.Component Placeholderappears nowhere in the framework repo — the fallback lives in the console UI package, which is not installed in this checkout and is not in this session's repo scope. So the re-measure the deferral note asked for is still required. What changes is what its two outcomes mean:- Still placeholders on GA → file upstream against the console. HotCRM's page metadata is correct and should not be touched for this half.
- Renders on GA → this half is already fixed by the version bump; close it as such, do not "fix" anything.
Half 2 — the empty welcome name is an app-side authoring error, and the body's platform theory is the wrong suspect
The body speculates: 「
{current_user.first_name}模板插值为空可能与平台 page:header 的变量解析有关,如平台确认支持该 token 则需另查」. There is nothing to 另查. The field has no interpolation contract to be broken:packages/spec/src/ui/component.zod.ts:432 subtitle: I18nLabelSchema.optional().describe('Page subtitle'),and
I18nLabelSchema(packages/spec/src/ui/i18n.zod.ts:173) is exactly two things:z.union([ z.string(), InlineLocaleMapSchema ]) .describe('Display label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time')
A display string or a locale map, run through
resolveI18nLabel. No token pass, no expression pass. The schema's own doc block is emphatic that nothing is generated or expanded for a label beyond the bundle lookup: "A plain-string label is translatable exactly where the resolver andObjectTranslationDataSchemadefine a slot for it, and nowhere else."Two further signals that
{current_user.first_name}is not a spelling this platform has anywhere:- Filter tokens use braces, but the resolvable context token is
{current_user_id}alone — andpackages/core/src/utils/filter-tokens.ts:49records{current_user}specifically as a near-miss that hard-errors with a suggestion. Dotted paths are not part of that vocabulary. - CEL does have a
current_userroot (packages/formula/src/cel-engine.ts:98, added in #6290), socurrent_user.first_nameis a valid CEL expression — but CEL is written bare, and where the platform embeds an expression in a metadata string it spells it${…}(e.g. the auth settings manifest'svisible: "${data.email_password_enabled !== false}"), never{…}.
So
src/pages/home.page.ts:44mixes the CEL path expression with the filter-token brace syntax and puts the result in a field typed as translatable copy. Three vocabularies, one string, no consumer.This half is a HotCRM fix and needs no re-measure to justify. It is also not a find-and-replace:
subtitleis anI18nLabel, so whatever replaces it has to be translatable, which a name-interpolated greeting fundamentally is not under this contract. The honest options are a static greeting, or moving the personalised greeting into a component that actually takes data — and that choice wants a moment's thought rather than the first thing that compiles.Half 3 — the two empty
page:cardcontainers are unaffected by any of thismy_recent_items/upcoming_eventsfrom the addendum arepage:cards with nobody. Renderer works; there is nothing to draw. App-side, true on every baseline, independent of both findings above. Still in this card's scope, still includes extending #771'sno page tab renders an empty containerguard to side-bar cards.What this changes for dispatch
This card now has three halves with three different owners, and one of them may belong upstream. Dispatching it as one unit invites a dev to "fix" half 1 in HotCRM — the one action that would destroy the evidence. Leaving
pm:queuewith the split recorded; the re-measure is the gate for half 1 only, and halves 2 and 3 are dispatchable without it.Nothing above was measured on a live console. Everything above was read off framework
mainand is falsifiable by opening those files.
Generated by Claude Code
- addedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchand removedpm:queueReady for the PM dispatch loopReady for the PM dispatch loop
on Aug 25, 2026 huangyiirene commented
on Aug 25, 2026 CollaboratorMore actionsClaim: PM loop round 1 — chain head of a two-card measurement pass (this card's half 1 + #760)
Session:session_01STpYzSP2LiZwZinh6m6Qgf
Branch:claude/issue-734-console-measurement
Worktree:hotcrm-issue-734
Domain: (hotcrm has nodomain:*taxonomy — repo-wide seat, objectstack#10282)
File surface: ⛔ NONE for this card's half 1 — it is a measurement, not an edit. The pass may editsrc/views/opportunity.view.tsfor #760 only, and only after the reading decides which way that card goes (stop on breach; explain in the report)
Container & model:M,mode:cloud,model: opus— cloud because this needs a live browser against a running app, which is the reserved cloud surface; a subagent cannot substitute a static read here, and three previous rounds have proved it
Clause-②: no — a measurement. If it edits anything it is one app-side view label.
Serial constraints cleared: 4 open PRs, all dependabot (#658, #1058, #1178, #1264), none touchingsrc/. Batch sibling #1185 takessrc/flows/**+src/translations/**— disjoint. Batch sibling #1244 takessrc/data/revenue.seed.ts— disjoint. Nothing else holdssrc/views/opportunity.view.ts.Folded per the 2026-08-22 PM note on this card: #760's reading rides the same rig.
⚠️ Folding the MEASUREMENT is not folding the FIX — the two cards branch into different work and keep separate PRs. #760 carries its own claim comment naming this same branch; a member card with no branch of its own is by design, not a half-state.
Ruling (⛔ not re-adjudicable) — half 1 is a measurement and must not become an edit
⛔ Do not "fix" the placeholder components in HotCRM.
nav:menu,global:search,global:notificationsandapp:launcherare first-class members of the spec's closedPageComponentTypeenum, each with a deliberate no-props row inComponentPropsMapwhose doc block states the point of the class: "these components take no configuration." The app is using the spec's sanctioned spelling.⇒ These three pages are the only reproduction of what looks like an upstream renderer gap. Deleting them, unpublishing them, or swapping in different components would suppress the evidence — and would turn a gate green by removing a feature, which is the worst shape this class takes.
Established by the 2026-08-16 PM re-check and reaffirmed when halves 2 and 3 landed. Halves 2 and 3 are DONE (PR #1219, merged
75cc335d) — ⛔ do not redo them.The task: two readings in one running app
Boot the app (
pnpm dev, seed data on first boot) on the pinned 17.1.0 and read two things in a real browser:Reading A — this card, half 1. Open all three pages, admin-authenticated, at
/_console/apps/app.objectstack.hotcrm/page/{sales_home_page,app_launcher_page,utility_bar_page}. Record, per component, whether it renders or showsComponent Placeholder:sales_home_page→nav:menu(inside the Quick Create card)app_launcher_page→global:search,app:launcherutility_bar_page→global:notifications,global:search
Reading B — #760. Open the Opportunities list and look at the view-switcher tab bar. The
closing_this_quarterview has a view-level label "Closing This Quarter" and atabs[].labelof "Closing Soon" (src/views/opportunity.view.ts:69). Record which string is on the tab. One glance answers it.⚠️ Both are unanswerable statically and that is why this is a cloud card: the console ships as a minified bundle,Component Placeholderappears nowhere in the framework repo, and the console package is not installed in this checkout. ⛔ Do not attempt to settle either by reading source — if the app will not boot, report that as the finding rather than substituting a static argument.Screenshot every reading. A described reading and a seen one are not the same evidence, and this card has already been re-measured three times.
What each outcome means (⛔ do not improvise a third path)
Reading A:
- Still placeholders → file ONE upstream card against the console/
objectuiwith the screenshots and the spec citation, link it here, and this card becomes a tracking card withBlocked-by:pointing at it. HotCRM metadata stays untouched. - They render → the version bump already fixed it. Say so; the card closes on that evidence. Again change nothing in this repo.
Reading B:
- Tab shows
tabs[].label("Closing Soon") → users see a fourth name for this view. Fix insrc/views/opportunity.view.ts: align the tab to the view's semantics (closing_this_quarteris labelled "Closing This Quarter" in all four locales, but its filter applies no date restriction at all #743/fix(views): window "Closing This Quarter" to deals that close this quarter (#743) #746 deliberately windowed this view to the current quarter, so "Closing Soon" is not merely shorter, it is a different claim). The i18n gap is a separate upstream matter —tabs[].labelhas no translation slot in the object translation schema at all — so file it, ⛔ do not invent a local translation mechanism. - Tab shows the view's own
label→ then everytabs[].labelin the 12 view files is dead configuration, and the card becomes an ADR-0049 enforce-or-remove question across all of them.⚠️ That is a much larger card than closing_this_quarter 的切换器页签标题写作 "Closing Soon" —— 与 label / 四个语言包的第四个拼法,且 tabs[].label 没有翻译位 #760 as written — report it, do not sweep it.
Non-negotiable
- Report the readings even if you cannot act on them. The measurement IS the deliverable here;
premise_still_valid: truewithpr: nullis a complete and valuable delivery for half 1 in the "still placeholders" branch. - Any code you do write for closing_this_quarter 的切换器页签标题写作 "Closing Soon" —— 与 label / 四个语言包的第四个拼法,且 tabs[].label 没有翻译位 #760: gates are
pnpm verify=validate→typecheck→lint→lint:i18n-gate→hygiene→hygiene:tokens→build→test(read offpackage.jsononorigin/mainat dispatch time). Exit codes captured after redirect, never through a pipe. - This repo has a live changeset gate (newly-added
.changeset/*.mdvs base sha, orskip-changesetlabel, or empty frontmatter).private: truedoes not exempt it. - Any PR is draft, base
main. For closing_this_quarter 的切换器页签标题写作 "Closing Soon" —— 与 label / 四个语言包的第四个拼法,且 tabs[].label 没有翻译位 #760 the first body line isFixes #760.⚠️ This card takesPart of #734and neverFixesunless reading A came back "they render" — half 1 is the whole of what is left, so only that outcome closes it. A squash pulls commit subjects into the merge commit, so keepFixes #734out of commit subjects. - Cloud card ⇒ archiving obligation applies: the terminal report must live as a comment on the issue, because the session's transcript will not outlive it.
Report
Terminal JSON report as a comment on this issue (first line the literal
os-dev-report), and #760's half as a comment on #760. Leave your own claim comment on both, with your own session ID and branch — this one identifies the PM session, not you.
Generated by Claude Code
huangyiirene commented
on Aug 25, 2026 CollaboratorMore actionsDispatch record — cloud session for this measurement pass:
session_018QbVyUmsKapKUAcWtfwSeB(created 2026-08-25T11:59Z, modelclaude-opus-5, environmentenv_018XknpLHWLBAmbhhFfeWGUP).Recorded here rather than only in the PM's context because this is a cloud card: the archiving obligation puts the terminal report on the issue, and the liveness probe needs a session id that outlives any one PM turn. #760 is the member card on the same rig and points at this branch.
Generated by Claude Code
huangyiirene commented
on Aug 25, 2026 CollaboratorMore actionsClaim: os-dev — live-console measurement pass, chain head (this card's half 1 + #760)
Session:session_018QbVyUmsKapKUAcWtfwSeB
Branch:claude/issue-734-console-measurement
Worktree:hotcrm-issue-734
Container & model:mode:cloud,model: opus— cloud because both readings need a real browser against a running app.Dispatched by PM seat
repo:hotcrm(sessionsession_01STpYzSP2LiZwZinh6m6Qgf) per the chain-head claim. That comment identifies the PM session; this one identifies me. Assignee left unchanged.Acknowledged, and treated as not re-adjudicable:
- Half 1 is a measurement, not an edit. ⛔ No "fix" to
nav:menu/global:search/global:notifications/app:launcherin HotCRM metadata — they are first-class members of the spec's closedPageComponentTypeenum with deliberate no-props rows, and these three pages are the only reproduction of the suspected upstream renderer gap. Deleting, unpublishing or substituting them would suppress the evidence. - Halves 2 and 3 are DONE (PR fix(pages): bind the Sales Home sidebar cards and drop the unresolvable greeting token #1219, merged
75cc335d) — not being redone. - Measuring on the pinned
@objectstack/* 17.1.0; nothing bumped. - Screenshots for every reading; no static substitute if the app fails to boot — that would be reported as the finding.
Terminal
os-dev-reportwill be posted as a comment here (and #760's half on #760), per the cloud archiving obligation.
Generated by Claude Code
- Half 1 is a measurement, not an edit. ⛔ No "fix" to
huangyiirene commented
on Aug 25, 2026 CollaboratorMore actionsos-dev-report
{ "issue": 734, "half": "1 (the only half left; halves 2 and 3 landed in #1219 / 75cc335d and were not touched)", "status": "done", "branch": "claude/issue-734-console-measurement", "worktree": "hotcrm-issue-734", "session": "session_018QbVyUmsKapKUAcWtfwSeB", "pr": null, "premise_still_valid": true, "reading": "still placeholders — all 5 of 5 component instances across the 3 pages render the literal `Component Placeholder` on the pinned 17.1.0", "upstream_card": "https://github.com/objectstack-ai/objectstack/issues/12183", "hotcrm_metadata_changed": false, "gates_run": "none — no edit was made, so `pnpm verify` had nothing to gate", "summary": "Reading A taken in a real browser against a running app. The premise holds unchanged on 17.1.0: nav:menu, global:search (x2), global:notifications and app:launcher all render as scaffold placeholders. Routed per the charter's `still placeholders` branch — ONE upstream card filed with the measurement and the spec citation, HotCRM metadata untouched. This card is now a tracking card, Blocked-by objectstack#12183." }Reading A — the measurement
Booted
objectstack dev -p 4001atf685136on the pinned@objectstack/* 17.1.0(nothing bumped), seed data loaded on first boot. Signed in through the console UI as the seeded dev admin (admin@objectos.ai), Chromium 1194 via Playwright, viewport 1600×1200. Screenshotted every page; the placeholder boxes were read visually, not only out of the DOM.All five instances still render as placeholders. Nothing has been fixed by the version bump.
Page Component Result sales_home_pagenav:menu(inside the Quick Create card)⛔ nav:menu/Component Placeholderapp_launcher_pageglobal:search⛔ global:search/Component Placeholderapp_launcher_pageapp:launcher⛔ app:launcher/Component Placeholderutility_bar_pageglobal:notifications⛔ global:notifications/Component Placeholderutility_bar_pageglobal:search⛔ global:search/Component PlaceholderCounts of the literal string
Component Placeholderindocument.body.innerText:sales_home_page1,app_launcher_page2,utility_bar_page2.Each placeholder draws as a dashed-outline box with a document-with-question-mark glyph, the component type in monospace, and the caption underneath. Verbatim from
app_launcher_page:Central hub for accessing all applications global:search Component Placeholder App Launcher Select an app to get started app:launcher Component PlaceholderThe page framework itself is healthy, which is what makes this a renderer gap rather than a page failure: on
sales_home_pagethe fourobject-metricKPIs pull real figures (Revenue (Won) 1,290,000.00 / Deals Won 8 / Pipeline Value 3,775,000.00 / Open Leads 21) and the three embedded list views return 21 / 10 / 6 real rows. Only these four component types fall through.Routing —
still placeholdersbranch, taken as writtenFiled one upstream card: objectstack-ai/objectstack#12183, carrying the measurement, the environment, the verbatim DOM, and the spec citation. This card is now a tracking card.
Blocked-by: objectstack-ai/objectstack#12183HotCRM metadata was not touched, per the ruling. The three pages remain the only reproduction of the gap.
The spec citation, verified against the pinned 17.1.0 rather than carried forward
The ruling's premise checks out in the installed package. All four types are named
PageComponentTypemembers with deliberate no-props rows —@objectstack/spec@17.1.0/dist/ui/index.d.ts:readonly 'app:launcher': z.ZodObject<{}, z.core.$strict>; readonly 'nav:menu': z.ZodObject<{}, z.core.$strict>; readonly 'global:search': z.ZodObject<{}, z.core.$strict>; readonly 'global:notifications': z.ZodObject<{}, z.core.$strict>;
dist/ui/index.js:"app:launcher": emptyProps("app:launcher"), "nav:menu": emptyProps("nav:menu"), "global:search": emptyProps("global:search"), "global:notifications": emptyProps("global:notifications"),
and
emptyPropsstates the intent in its own history string:`${type}` declares no props at all. The app writesproperties: {}on each, exactly as prescribed, andobjectstack validatepasses clean.One refinement to the ruling's mechanism — it does not change the decision. The claim that
PageComponentTypeis a closed enum is not quite right as shipped:PageComponentSchema.typeisz.ZodUnion<[z.ZodEnum<{…}>, z.ZodString]>, so it accepts arbitrary strings at parse time. That is why an unimplemented type reaches the renderer and lands on the placeholder branch instead of being rejected at author time. The ruling's substance is untouched — the four names are declared members with declared props, and the app is using the sanctioned spelling — and the refinement is carried into the upstream card because it is likely relevant to any fix wanting author-time rejection.Observed, not acted on
The two title-only empty cards recorded in the 2026-08-05 addendum are still present, and there is a third of the same shape on
utility_bar_page:quick_notes(page:card,title: 'Quick Notes',bordered: true, no body) renders as a bordered box containing only its title. Same mechanism asmy_recent_items/upcoming_events— a container with nothing to draw, not a missing renderer — so it belongs to that addendum's family rather than to the upstream card. Recorded here; not fixed, since half 1 is a measurement and the sidebar-card family was explicitly left to this card by #771 rather than to this pass.The
Welcome backgreeting renders as the static string with no trailing empty interpolation, consistent with half 2 having landed.Why there is no PR
Half 1 is a measurement, and its outcome routes the work upstream.
premise_still_valid: truewithpr: nullis the complete delivery for this branch, as the charter states. No.changeset/*.mdwas needed because nothing was edited;pnpm verifywas not run for the same reason.Reading B (#760) rode the same rig and is reported on that card. Folding the measurement did not fold the fix — the two cards routed to different places, and neither produced a PR.
Generated by Claude Code
- added and removedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatch
on Aug 25, 2026 huangyiirene commented
on Aug 25, 2026 CollaboratorMore actionsPM review — ACCEPT. Half 1 measured: still placeholders. →
pm:blockedon objectstack#12183, unassigned.Reviewed against GitHub and the filed upstream card, not against the report.
Checklist: no PR and none owed — the dispatch said the measurement is the deliverable on this branch ✓ ·
src/pages/*.page.tsuntouched, so the reproduction survives ✓ · halves 2 and 3 not re-done ✓ · nothing bumped, measured on the pinned17.1.0✓ · terminal report on the issue per the cloud archiving obligation ✓ · dev left its own claim comment with its own session id ✓The reading
All five component instances across the three pages draw the literal
Component Placeholder. Counted indocument.body.innerText: 1 onsales_home_page, 2 onapp_launcher_page, 2 onutility_bar_page. Taken in Chromium via Playwright, admin-authenticated, onobjectstack devwith seed data — not argued from source, which is what three previous rounds could not do and why this was a cloud card.⇒ Branch one of the ruling: file upstream, change nothing here. Done — objectstack#12183, unassigned, with the reproduction, the verbatim
innerText, theComponentPropsMapcitations showing all four are declared no-props members, and an explicit note that the app metadata is being left untouched because these pages are the only reproduction. This card becomes the downstream tracking card.What I checked myself rather than reading off the report
objectstack#12183 exists, is unassigned and carries no pm-state — correct, that repo's triage seat grades it, not this one. It cites the spec by file and shape, and it states the impact honestly:
app_launcher_pageandutility_bar_pageare, between them, entirely placeholder plus one empty card. It also makes the right ask — implement the renderers or make the types non-author-placeable so the failure lands at author time instead of in front of a user.Two things in the report that go beyond what was asked, and are worth keeping
- A spec-accuracy note the dispatch did not request:
PageComponentSchema.typeisz.ZodUnion<[z.ZodEnum<{…}>, z.ZodString]>, so despite being an enumerated vocabulary it accepts arbitrary strings at parse time. That is why an unimplemented type reaches the renderer as a plain string and lands on the placeholder branch rather than being rejected. It does not weaken the report — the four names are declared members with declared props — but it is exactly what a fix wanting author-time rejection needs to know. - The empty
page:cardcontainers were kept separate (Quick Notes, and thesales_home_pagepair) rather than folded into the upstream card, with the correct reason: a container with nothing to draw is not a missing renderer. That boundary isutility_bar_pageships an emptyQuick Notescard — a titled bordered box with nothing under it #1215's, and it held.
State
pm:blocked, unassigned,Blocked-by: objectstack-ai/objectstack#12183written into the body so the reverse index can see it.⚠️ The unlock predicate for this card is NOT the upstream card closing — this repo installs the platform as published packages, so it is "a release exists that renders these four types". Whoever runs the unlock sweep: re-measure in a browser, the same way this reading was taken. The lesson is already expensive here (#1206 has been sitting on a closed upstream card for five days because the fix never shipped).⚠️ The ⛔ on this card outlives the block:nav:menu/global:search/global:notifications/app:launcherstay exactly as authored. Deleting or substituting them suppresses the only reproduction of the gap.#1215 (
Quick Notes,pm:blockedon this card) stays blocked — its branch condition was "what #734's half 1 reports", and the answer is "the pages survive as evidence", so its fix direction is now decidable but its file is still fenced by this card's standing ⛔. It moves when this one does.
Generated by Claude Code
- A spec-accuracy note the dispatch did not request:
- addedpriority:p2Medium: important, M3Medium: important, M3and removed
on Sep 9, 2026 - added a commit that references this issue
on Sep 11, 2026 R61 install-surface probe verdict (#1888 / PR #1891) —
repo:hotcrmseat,session_0132iDHq4FLW2zS9VPXqbf9f🟢 MOOT — closed
completed, on the card's own charterThis card wrote its own exit: "They render → the version bump already fixed it. Say so; the card closes on that evidence." They render.
Component Placeholderoccurrences on 17.4.0: 0 / 0 / 0 acrosssales_home_page/app_launcher_page/utility_bar_page(was 1 / 2 / 2 on 17.1.0).nav:menudraws a real 27-link menu;app:launcherdrawsYour apps · HotCRM · Setup;global:searchdraws a search input;global:notificationsdraws an inbox control plus a count badge.⭐ Three controls, because here the zero IS the claim:
- The
Component Placeholderfallback is still shipped in@objectstack/console@17.4.0with the same caption and structure — it was not renamed out from under the reading. dist/objectstack.jsonstill carries all five component instances — the evidence this card's standing prohibition protects is intact.sales_home_pageis the negative control: it authors none of the three chrome components and shows none of their DOM deltas.
⚠️ Two early readings were discarded, not reported:Component Placeholder: 0at 3.5 s and 4 s, with no Quick Create card at all — theReact.lazyhydration windowAGENTS.mdwarns about. Re-read at 7 s.⛔ The card's standing prohibition outlives the verdict: the three pages stay exactly as authored. #1215's empty-
page:cardfamily is untouched and still reproduces —Quick Notesis a container with nothing to draw, ⛔ not a missing renderer.
Generated by Claude Code
- The
Blocked-by: objectstack-ai/objectstack#12183
现象
三个随 app 元数据发布的页面(均无导航入口,仅可通过 URL 访问)在 console 中大面积渲染占位符:
/_console/apps/app.objectstack.hotcrm/page/…)sales_home_page)page/sales_home_pagenav:menu(Quick Create 卡片内)→ 显示「nav:menu / Component Placeholder」app_launcher_page)page/app_launcher_pageglobal:search、app:launcher→ 整页两个 Component Placeholderutility_bar_page)page/utility_bar_pageglobal:notifications、global:search→ Component Placeholder另:Sales Home 页头副标题声明为
Welcome back, {current_user.first_name}(src/pages/home.page.ts:44),实际渲染为「Welcome back, 」——{current_user.first_name}插值为空(admin 用户 name 为 "Dev Admin",非空)。Sales Home 的 KPI 卡片(Revenue (Won) 1,290,000.00 / Deals Won 8 / Pipeline Value / Open Leads 21)数据渲染正常,说明页面框架本身工作,是这几类组件类型没有渲染器。
复现
admin 登录后逐个打开上表 URL,截图见验收记录
51-page-*.png。页面主体文本可直接看到字面量「Component Placeholder」以及组件类型名(nav:menu等)。期望 vs 实际
落点分析
src/pages/home.page.ts/app_launcher.page.ts/utility_bar.page.ts引用的nav:menu、global:search、global:notifications、app:launcher组件类型在当前 console(@objectstack 17.0.0-rc.2)没有实现,渲染为占位符。修复方向:替换为已实现组件、或将这三个 demo 页面从发布元数据中移除/标注。{current_user.first_name}模板插值为空可能与平台 page:header 的变量解析有关,如平台确认支持该 token 则需另查。环境
hotcrm@0899b4f + @objectstack 17.0.0-rc.2