Repository navigation
app-shell: export resolveHostAppSegment from the package root — apps/console carries a documented local subset that must become a pure deletion #4280
Description
Activity
CLAIM — session
session_017Qqyix2QcnpUC9XeYVDzx3(objectui whole-repo PM seat),dispatching now。Branch:claude/issue-4280-resolver-root-export。派发范围 = 本卡的机械去重半件:app-shell 包根导出
resolveHostAppSegment家族(一行 barrel)+ 纯删apps/console/src/components/createdRecordPath.ts的本地子集(改 import 共享 resolver,其测试转为钉共享 resolver 在该调用点的行为,含此前文档化的分歧点——本地版实现步骤 1–2 且返回 null 而非上游的setup兜底;收敛后语义取上游完整版,该分歧正是本卡要消灭的)。可选 rider(ConsoleLayout 侧栏)本次不派、不裁——按卡片原文留给维护者,卡片保持 open 到该决定落地或明确放弃。
闸门:PR #4293/#4311 已落/armed,createdRecordPath 面已由 #4292 交付释放;dev 动工前 git 自检 #4311 落地(同目录相邻文件)。互斥:不碰 #4265(useObjectActions/ActionConfirmDialog)、#4235(useHomeInbox/sharedUserFeeds/home)、#4234(components sidebar)持有面;app-shell
src/index.tsbarrel 只加导出行。
Generated by Claude Code
ACCEPT(机械去重半件) — PM review of record (session
session_017Qqyix2QcnpUC9XeYVDzx3)。PR #4318 验收要点:
- 纯删成立且更进一步:
createdRecordPath.ts的三个本地实现全删,只留 URL 形状;HostAppLike改为从 resolver 自身签名派生(Parameters<typeof resolveHostAppSegment>)——字段集的复述本来就是重复的一部分,派生让调用点无从漂移。名称与含义保留,FormPage/InternalFormRoute 零改动。 - null→setup 差量测出两支而非一支(空列表+preferred ⇒ preferred 不检查;其余不可解 ⇒ setup),四个红先 pin + PR 正文表格——这是卡片裁定的有意语义对齐,零 openable app 的用户从确认屏改落 setup 记录页,写入本身从未受影响。
- 导出面在 built dist 上验证(删 d.ts 一行 ⇒ console tsc 预测红),证明消费方读的是发布面不是源码;barrel 只发布三个有外部消费者的名字,不过度发布。
- 反向验证一处方向对但模式不对(Vite SSR 把缺失命名导出降级为 undefined,15/16 TypeError 而非 link 失败)——照实测报告,不硬凑预言。
- FormPage: the FORM_RECORD_ID_PARAM comment cites a resolver unreachability that PR #4318 removed #4319(本 PR 自己造成的一处过期注释交叉引用,位于被围栏的 FormPage)不越界顺手改、立 finding 记录——纪律正确。
- CI 20 项收敛零失败;changeset minor×2 合规。
Part of #4280,卡保持 open:剩余的 ConsoleLayout 侧栏 rider 按 #4109 裁决留给维护者,decision inbox 挂账不变。
Generated by Claude Code
- 纯删成立且更进一步:
State correction:
pm:dispatched→needs-user-decision(restored) — theme PM for objectstack#8668 (Seat B), sessionsession_018x7oGZF6qqdUD1Km4e9n5a.The dispatched half is delivered: PR #4318 (
Part of) was ACCEPTed and merged 2026-08-11, exporting theresolveHostAppSegmentfamily from the app-shell package root and deletingapps/console's local subset outright (with the null→setup divergence pinned in both directions). The label was never flipped back at merge, so the card has read as in-flight for three days with no agent on it.What remains is the ConsoleLayout sidebar rider, reserved to you by the card's own text and confirmed by the Q1 ruling on #4109 — which accepted the shipped shape and moved this question here rather than deciding it. It has been the open half since 2026-08-11.
The concrete question: should the internal
/forms/:nameroute mountUnifiedSidebar? The measured obstacle is thatConsoleLayoutis app-scoped by construction — it takes anactiveAppNameand publishes it as the shell's current app — while/forms/:namenames no app. On a cold deep link that resolves to whichever app happens to be first, wrapping the form in an arbitrary app's sidebar and writing that guess into shared navigation state. The exported resolver now makes an honest implementation possible; whether the page should have a sidebar at all is the part no measurement settles.Full orphan re-verification: objectstack#8668.
Generated by Claude Code
Maintainer ruling (delegated adjudication; delegation 2026-08-15 verbatim 「决策你直接帮我做」, batch confirmed 「同意」)
Ruled: the ConsoleLayout sidebar rider is declined. The internal
/forms/:nameroute keepsDefaultHomeLayout. Card closed.The mechanical half — exporting the
resolveHostAppSegmentfamily from the app-shell package root and deletingapps/console's local subset — was delivered and merged in PR #4318 (2026-08-11), with the null→setup divergence pinned in both directions. What remained was the rider, and the measured obstacle to it stands:/forms/:namenames no app, so on a cold deep link host-app resolution would pick an arbitrary app, wrap the form in that app's sidebar, and write the guess into sharedNavigationContext— silent-wrong-chrome, exactly the silent-wrong class this platform refuses. Measured pull for a sidebar on this internal route is zero, andDefaultHomeLayoutis the same chrome/homeand/organizationsalready use, so declining is the coherent zero-cost answer.Reopen condition, named: a real user or agent reports the form page lacking navigation, and the proposed design carries app context on the route (an explicit app segment or equivalent) rather than guessing it — at which point this becomes a new card, not a reopening of this one.
Closing as completed: delivered half merged, rider adjudicated.
Generated by Claude Code
HOLD (
pm:on-hold; seat sessionsession_01RnQd8iMMUwXQEV1crFmQiQ, 2026-08-15; seat-graded under the maintainer's in-session adjudication delegation). The main deliverable (exportresolveHostAppSegment, PR #4318) is MERGED; the remainder is the ConsoleLayout sidebar rider explicitly reserved to the maintainer (per the Seat B orphan re-verification of 2026-08-14). Parking it changes nothing about who decides — it removes a non-v17 item from the active inbox per the objectstack#8668 regime. Named restart: the maintainer takes up the reserved rider (one line here), or a PR touches ConsoleLayout's sidebar region (names this card pre-dispatch).
Generated by Claude Code
- added a commit that references this issue
on Aug 17, 2026
Follow-up from #4109 / PR #4279, filed per the PM ruling there (2026-08-11). Unassigned — queued, not started.
Fact
resolveHostAppSegment/appRouteSegment/filterActiveAppslive inpackages/app-shell/src/utils/appRoute.ts(landed via #4074), butpackages/app-shell/package.jsonpublishes only the.export andsrc/index.tsre-exports./utilsnowhere — soapps/consolecannot reach the resolver.Consequence, disclosed in PR #4279 rather than smuggled:
apps/console/src/components/createdRecordPath.tsimplements only steps 1–2 of that resolver (preferred-app re-checked against the live openable list, else first openable app) and returnsnullinstead of the upstreamsetuplast resort. The divergence and its reason are documented in that module's docblock and pinned by tests.Why this is worth a card
The resolver's own docblock argues its resolution order is one hard-won definition. A console-local subset is the "two readers of one prose contract" failure shape this repo repeatedly pays for (#3367 / #3842 family): the next change to the resolution order lands on one copy. The fix is mechanical:
createdRecordPath.tsand import the shared resolver — a pure deletion of the duplicated logic; its tests move to pin the shared resolver's behavior at this call site.Optional rider — maintainer decision, explicitly NOT ruled
With the export in place, mounting
ConsoleLayout(sidebar + breadcrumb) on the internal/forms/:nameroute becomes a small change (option B of the #4109 ruling). It was deliberately NOT shipped: on a cold deep-link nothing has published a current app, so host-app resolution picks an arbitrary app, wraps the form in that app's sidebar, and writes the guess into sharedNavigationContext— a silent-wrong-chrome failure mode. If the sidebar is wanted there, this card is where that decision lands; the default remainsDefaultHomeLayout(the chrome/homeand/organizationsuse).Surface
packages/app-shell/src/index.ts(barrel line),apps/console/src/components/createdRecordPath.ts(+ its tests). Coordinate with any in-flight holder of app-shell surfaces at dispatch time.Refs #4109, PR #4279, #4074, #3367, #3842.