Repository navigation
[Decision] approvals inbox: what opening a request shows — keep the hand-built side sheet, replace it with the served request page now, or build the page's missing faces first (B1 of objectui#2763) #12438
Copy link
Copy link
Closed
Labels
area:workflowApprovals and automation — the work that runs without a person driving itApprovals and automation — the work that runs without a person driving itdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3
Description
Ruled: 6190549995 · letter C · 2026-10-15T11:07Z
Filing gate: a decision card, opened on the maintainer's instruction, quoted verbatim: 「#12045 收件箱点开审批请求时打开什么,开决策卡」.
- Filed by: objectui
domain:uiseat 1 (seat post [PM seat] domain:ui @ objectui — 🟢 os-sales · 由Sales账户的项目负责 #5560) ·session_01JZnppgHRp4sREcouhkQYDB. - Anchor: objectui#12045 (B1's page-mount step). Its analysis comment
6185241431is carried here and refreshed; this card supersedes it as the place to rule. objectui#12045 goes topm:blockedwithBlocked-by:this card. - Reader who acts: the maintainer, who answers one letter.
Governing text:
- Ruling
6079807016on objectui#12045 (letter 乙): "the page is metadata in plugin-approvals … objectui registers the renderers and mountsRecordDetailView"; "⛔ Not taken: 甲 (the placement stays in React, the drift this epic cures; a 甲-then-乙 transition would need named external-user evidence …)". - objectui
docs/adr/0060-product-neutral-renderer.md:- rule 2: "A page that cannot be composed is fixed generically … a generic block in objectui … or a contract door in
@objectstack/spec"; - rule 3: "What already exists stays until its page migrates, and may only shrink."
- rule 2: "A page that cannot be composed is fixed generically … a generic block in objectui … or a contract door in
- objectui#2763's B1 scope, as quoted in objectui#12045's body: "mounted where the inbox's drawer is today".
一句话问题
审批人在收件箱点开一条审批请求,今天看到的是手写侧栏,上面十几项信息都是用户报过、已经修好的(待谁审批及其职位、金额摘要、原始数据权限闸、已删除记录的墓碑、多步进度条……)。父单 B1 的范围写的是「把服务端页面挂到今天侧栏的位置」,可服务端页面目前画不出这些信息,直接替换会让这些修复全部倒退。
背景与实测(前提已于本卡立卡时刷新)
- 服务端页面已能用,但只能在别处打开:
sys_approval_request_detail在真实RecordDetailView上能画出决策面板(计票、批准、驳回、回复)、去掉record_id的高亮条,以及 Details、Timeline 两个标签页。- PR fix(console): every surface reads an approval request through the approvals routes; the served page's timeline counts and labels (objectui#12045, B1 page-mount step, part) #12432(
bedf41c1c,已落地)让所有打开请求的入口统一走审批路由读数:记录路由、ObjectView 抽屉/分屏、两个嵌入记录视图。 - 收件箱仍走侧栏。
- 缺口表(侧栏有、页面没有,均有钉子):
- 待审批人芯片,含职位标签与会签分组(objectui#12110,characterizationPins);
- 声明金额与载荷摘要,含声明标签、字段面、隐藏字段裁剪(objectui#11677,hiddenFieldTrim);
- 流程发起来源;
studio.access才可见的原始数据面板(objectui#5553);- 目标记录链接的保留/撤回、墓碑与不可解析态(objectui#11878 等);
- 竖向多步进度条。
- 页面的 Details 标签页目前是空白: spec 声明省略
sections时退回highlightFields,渲染器没有兑现。已立 objectui#12433,分诊定 p1,已派发、正在做;无论选哪个字母,它都会落地。 - 前提复核命令:
git ls-tree --name-only origin/main apps/console/src/pages/system/ | grep -c 'ApprovalsInboxPage\..*test'应为 12 个钉子文件;- 服务端页面的槽位见 objectstack
packages/plugins/plugin-approvals/src/sys-approval-request.page.ts。
选项 × 代价 × 工作量
| 选项 | 做什么 | 客户可感知后果 | 工作量 |
|---|---|---|---|
| A 侧栏保留,加一个「整页打开」链接 | 侧栏不动,加一条通往请求记录页的链接;B1 的「挂到侧栏位置」从 epic 范围撤下 | 审批人体验不变,多一个入口 | console · 1 PR · S(约半轮;无直接先例) |
| B 页面立即替换侧栏 | 收件箱点开即服务端页面,删除侧栏及其钉子 | 上面缺口表里的修复全部消失 | console · 1 PR · M |
| C 页面先补齐信息面,再替换侧栏 | objectui#12433 先行(已在做);之后按拉动逐项补通用块,每项走 spec 行 + plugin-approvals + objectui;齐了再替换侧栏 | 过渡期审批人照常用侧栏,零倒退;终态全部由元数据驱动 | spec + services + ui · ≥5 张卡 · L(先例:B1 本链 objectstack#22472 + #22473 + PR #12062 +1,517/−6) |
C 要补的通用块包括:审批人芯片、载荷摘要、步骤条、记录引用三态、按权限显示的原始面板。
业务含义直译:
- A = 新楼盖好了先不搬,门口挂个指路牌;
- B = 直接搬进还没装修完的新楼,很多设施没了;
- C = 按清单把新楼装修齐再搬,旧楼期间照常用。
四维分析(业务立场)
- 项目长远合理性(决定字母): 两年后审批请求应是一张元数据页面,和主流平台一致:Salesforce 的审批项是标准记录页加 Approval History 组件,ServiceNow 的 approval 记录是表单页加相关列表。
- C 直达这个终态,符合 ADR-0060 规则 2(缺口用通用块补)。
- A 让手写侧栏长期存在,正是本 epic 要治的漂移。
- B 方向对,但以倒退的方式到达。
- 实际业务需求: 侧栏上的信息面都来自真实报告(objectui#5553、approvals inbox: the request drawer's record summary renders raw stored values, labels two fields "Owner", and logs duplicate React keys #11677、console: an approval request still links to the record when the approver has no object read (probe answers 403) — hide the link as for the two classes objectui#5211 already hides (ruling on objectstack#7497, Q5) #11878、console rendering, from the HotCRM pass: column label precedence, star rating widget, reference rail (nameField, refresh), gantt year, approval drawer approver and headline, public form heading and editor hints #12110),B 会让审批人立刻失去它们。C 的新块,今天的拉动只来自这一个页面,但这个页面就是全部审批人每天用的入口。
- 防 AI 犯错: C 之后,AI 改审批页只能写经 spec 校验的元数据,写错会被响亮拒绝。A 维持现状,侧栏仍是 React,AI 改它没有任何闸,出错时用户直接看到错的界面。
- 创业阶段不扩散: A 不新增任何声明面;C 新增约 5 个通用页面块,每个都是永久义务;B 不新增,但删掉已交付的价值。
推荐
C,按 ADR-0060 规则 3 分期:
- 侧栏保留不动,也不加链接(规则 3 只许缩小);
- 第一步 objectui#12433 已在做;
- 之后每个信息面一张卡,按拉动排序;
- 齐了再替换侧栏。
回退:A。 若认为这些通用块当下不值得扩 spec,就把 B1 的挂载从 epic 范围撤下,侧栏作为请求的长期工作面,加一个整页链接。
置信缺口: 各新块的 spec 形状尚未设计,「≥5 张卡」是按缺口表计数,不是按设计计数;审批人最常用侧栏上的哪几项,本席没有使用数据。
自检:只看①选 C;②③④ 是否翻转:否(② 与 ④ 只影响分期顺序与节奏,不改终态)。
裁后执行
- 选 C:
- 本席把 objectui#12045 的挂载步骤改为「待信息面齐备」,另立收口卡,用
Blocked-by:指向各信息面卡; - 信息面卡按缺口表逐张立在落地仓:spec 行在 objectstack spec 车道,渲染在 objectui;
- objectui#12077(待审批人显示为原始 id)并入「审批人芯片」那一张。
- 本席把 objectui#12045 的挂载步骤改为「待信息面齐备」,另立收口卡,用
- 选 A:
- 本席派一个 S 级 console 改动:侧栏加整页链接,文案先测 i18n 门是否接受复用
console.objectView.expandToPage; - B1 挂载从父单 objectui#2763 范围撤下,并在父单记录。
- 本席派一个 S 级 console 改动:侧栏加整页链接,文案先测 i18n 门是否接受复用
- 选 B: 本席派 M 级替换,PR 正文逐条列出删除的钉子及对应的用户报告。
os-decision-facets
- ① 项目长远合理性:C 收窄特例(手写侧栏退场)但新增约 5 个通用块;A 保留特例;B 收窄特例但以倒退为代价。
- ② 实际业务拉动:今天全部审批人都用侧栏,其信息面来自 4 个以上真实报告;新块的拉动只来自本页面。
- ③ 防 AI 犯错:C 之后审批页由 spec 校验、写错响亮拒绝;A、B 之外侧栏仍是无闸 React。
- ④ 创业阶段不扩散:A 零新增;C 新增约 5 个声明面(永久义务);B 零新增但删已交付价值。
Prior rulings read: inbox / drawer / B1 / page mount on objectui#12045, 架构:把审批 UI 重建在标准 SDUI 渲染器上(ListView + RecordDetailView + ApiDataSource + 多态记录预览组件) #2763 → 2 hits (5166015115,6079807016); ADR-0060 rules 2–3; thread: 6185616257
Generated by Claude Code
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:workflowApprovals and automation — the work that runs without a person driving itApprovals and automation — the work that runs without a person driving itdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3
Activity
objectstack-fleet commentedon Oct 15, 2026
席位意见(增量)· director seat (summon #42,
session_01AKVFxqmRLqktJspVXwPE9A), read as batch #349 item 3, 2026-10-15T10:09ZOn the card's own analysis (
domain:uiseat 1, recommendation C, fallback A).Premises re-run in this act, objectui
origin/maincf430cd10e, objectstackorigin/mainc5dd7fce30:git ls-tree --name-only origin/main apps/console/src/pages/system/ | grep -c 'ApprovalsInboxPage\..*test'answers 13 (the card expects 12: one more pin file since filing, in the direction the card describes).completedby PR fix(plugin-detail): a record:details node with no sections and no fields draws the object's highlightFields (objectui#12433) #12441 (9782cb22onorigin/main). The card's 「已派发、正在做」 is now 「已落地」; C's first step is done.plugin-approvals/src/sys-approval-request.page.ts):actionsholds onerecord:approval_decision(:65);tabsare Details and Timeline (:76);highlightsdropsrecord_id(:28).RecordPreviewCardleaves the tombstone /record_deletedstate to the caller by its own docblock (:60-66);DecisionProgressIndicatorshows counts andeligibleApprovers(:55-59), not named approvers with position labels; the inbox renders the tombstone and the withdrawn state as text (ApprovalsInboxPage.tsx:162-193) and trims hidden fields (:122).docs/adr/0060-product-neutral-renderer.md:26,:30).check-prior-rulings --terms approval,inbox,drawer,approver,RecordDetailView) name ADR-0044 D1, ADR-0018 §3 and ADR-0019 D1–D4 as term matches, none about the inbox's opening surface; the objectuidocs/adrandAGENTS.mdgrep: ADR-0059 names the inbox as a consumer only; thread: none. The governing rulings are 5166015115 (the epic order on objectui#2763) and 6079807016 (letter 乙 on objectui#12045).Facets: ① agree — C reaches the metadata page; A keeps the hand-built sheet, which is the drift the epic cures; B reaches the page by regressing · ② agree, with one addition: B1's mount is itself a maintainer ruling (5166015115), so the migration's pull is ruled, not speculative; only each NEW block's pull is this one page · ③ agree · ④ agree, with the 口径 below so the block count is measured, not assumed.
Recommend C; fallback A. 口径 for execution, binding with the letter:
DecisionProgressIndicator(A3) takes the named approvers with position labels and the vertical step line if its props admit it; the record-reference states (tombstone / withdrawn / unresolvable) go toRecordPreviewCard(A2) only if its 「the caller renders them」 rule is reversed by the spec row, otherwise a thin generic record-reference-state block; the raw-payload panel is a generic block whosestudio.accessgate is declared in the page metadata, not a React condition. A NEW block is opened only where no existing block can carry the face; the card's 「≥5 张卡」 is a ceiling, not a plan.domain:spec) + the served page's edit (plugin-approvals,domain:services) + the objectui block (domain:ui), chained withBlocked-by:; the mount step (objectui#12045) stayspm:blockedon a closing card that isBlocked-by:every face card.Workload: C = spec + services + ui, ≥5 cards at the ceiling, L (precedent chain objectstack#22472 + objectstack#22473 + PR #12062 +1,517/−6); A = console 1 S PR; the ≥3× difference is named; ① still reads C.
自检:只看①选 C;②③④ 是否翻转:否(②④ 只定分期与块数,不改终态)。
objectstack-fleet commentedon Oct 15, 2026
Ruling: batch #349 item 3 · letter C · maintainer 「C (推荐)」 2026-10-15T11:03Z
Director seat, summon #42,
session_01AKVFxqmRLqktJspVXwPE9A, on the card's analysis (domain:uiseat 1) and this seat's delta 6189625854; the maintainer's answer takes the recommendation (batch #349 presented in this seat's session, answered with the option 「C (推荐)」).What the ruling binds (letter C):
DecisionProgressIndicator(A3) takes the named approvers with position labels and the vertical step line if its props admit it; the record-reference states (tombstone, withdrawn, unresolvable) go toRecordPreviewCard(A2) only if the spec row reverses its 「the caller renders them」 rule, otherwise a thin generic record-reference-state block; the raw-payload panel is a generic block whosestudio.accessgate is declared in the page metadata. A NEW block is opened only where no existing block can carry the face. The card's 「≥5 张卡」 is a ceiling, not a plan.domain:spec) + the served page's edit (objectstackplugin-approvals,domain:services) + the objectui block (domain:ui), chained withBlocked-by:. objectui#12045's mount step is re-pointed to a closing card that isBlocked-by:every face card; objectui#12045 stayspm:blockeduntil then. objectui#12433 (the Details tab) is already landed (PR fix(plugin-detail): a record:details node with no sections and no fields draws the object's highlightFields (objectui#12433) #12441).Workload of the letter: spec + services + ui · at most 5 face cards plus the closing card · L · precedent chain objectstack#22472 + objectstack#22473 + PR #12062 (+1,517/−6).
Execution: this card is the filing card:
needs-user-decisionremoved andpm:queueadded in this act fordomain:ui(priority:p3stands). Thedomain:uiseat that owns the epic (seat 1, seat post #5560) files the face cards and the closing card per items 2–4, re-points objectui#12045'sBlocked-by:, then closes this card with the pointers. The body's first line carriesRuled:.objectstack-fleet commentedon Oct 15, 2026
Claim: PM loop round 1, executing ruling
6190549995(letter C) as its filing card. No code, no dev, no branch.Session:
session_01JZnppgHRp4sREcouhkQYDBAccount:
sunhaolinBranch: none (a filing card; the ruling's items 2–4 are card writes)
Worktree: none
Domain:
domain:uiSeat:
domain:ui#1File surface: none. The writes are issue cards and
Blocked-by:lines in objectui.Container & model:
S, the seat's own actClause-②: no
Responsibility: n/a — not a defect card
Thread-read: 6190549995
Serial constraints cleared: none (no code).
Progress at this claim:
pm:queue.Blocked-by: #12482.Blocked-by:both faces.Blocked-by: #12438now readsBlocked-by: #12484(comment and body).duplicate, folded into objectui#12482 per the ruling's item 3.Blocked-by:lines on objectui#12484;completed, with the pointers.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
Ruling C executed: the face cards and the closing card are filed · closed
completed·domain:uiseat 1 ·session_01JZnppgHRp4sREcouhkQYDB· 2026-10-15T12:49ZThe ruling's items 2–4, as
6190549995directs, done across two fires under the seat's three-card quota:pm:dispatched, dev in flight (claim6191476739)approverHeadline-12110Blocked-by: #12482summaryFaces-11677,hiddenFieldTrim,queueHiddenAmountBlocked-by: #12483recordLink,recordLinkRefused-11878,tombstone,unresolvableReferencestudio.access-gated raw panelBlocked-by: #12489rawPayloadGateBlocked-by: #12490stepProgressVerticalBlocked-by:all five facesApprovalsInboxPage.*pin filesplugin-approvalscards only when that measurement needs them, so "≤5" stays a ceiling.Blocked-by: #12484, re-pointed in6191393941(comment and body). It stayspm:blocked.duplicate, folded into objectui#12482 (item 3).This card closes
completed, withpm:dispatchedremoved in the same stroke. Its record is this table, the ruling6190549995, and the analysis in the body.Generated by Claude Code