Repository navigation
Screen flow: a run cannot end on a screen that links the records it created (plain-text description, a completed end renders nothing, no read-only record-link field) #25872
Description
Ruled: 6422899013 · letter B · 2026-10-26T17:30Z
Filing gate ③ maintainer-directed task: hotcrm#2285 ruling B (comment 6398567074, the maintainer's 「同意」 2026-10-25T13:58:53Z) orders that "if the platform's screen-flow runner cannot render record links on its end screen, that half is an objectui card first and the HotCRM card carries Blocked-by: it (「平台相关的功能,应该尽量先改平台」)". Measured below: it cannot. Filed by the hotcrm#2285 card thread (session session_01HcSvGcpjo74R7vFotCfsrp, seat repo:hotcrm#1).
Business reason
A screen flow that creates records (HotCRM's lead conversion creates an account, a contact and optionally an opportunity) ends today with a toast and the user left where they started. The browser pass behind hotcrm#2285 measured exactly that on 18.1.0: 「线索转化成功!」, the URL stays on the lead, and nothing points at what was just created; the rep has to know to open the lead's Related tab. Every app with a "create several things in one guided step" flow pays the same tax. Without the capability the ruled HotCRM result screen cannot be authored at all.
What was measured (installed @objectstack/* 18.1.0)
- A screen's body text is plain text. The bundled console (
@objectstack/console18.1.0,dist/assets/urlParams-*.js) rendersScreenSpec.descriptionas a bare React child:description&&(0,J.jsx)(w,{children:M.description}). Source today:packages/app-shell/src/views/FlowRunner.tsx:639({shown.description && <DialogDescription>{shown.description}</DialogDescription>}). A markdown link or URL in the template shows as literal text. - A completed
endrenders nothing.EndConfigSchema(@objectstack/spec18.1.0,src/automation/builtin-node-config.zod.ts) refusesmessageunlessoutcome: 'refused'("on a completed end nothing shows it"). On terminal success the runner toasts and callsonComplete()(same bundle; sourceFlowRunner.tsxterminal-success branch), so the dialog closes. - No screen field displays a value read-only, let alone as a record link.
ScreenView.tsx(ScreenFieldInput) renderslookup(an editableLookupFieldpicker),select,boolean/checkbox,textarea/markdown(an editableTextarea), and a text/number/email/dateInput.ScreenFieldConfigSchemacarries noreadonlykey. A pre-filledlookupis an input the user can change and must Submit, not a link.
So the only way to "end on a result screen" is a message-only screen whose text cannot link, followed by Submit.
Expected capability (generic, not product-named)
A screen flow can end by showing the user links to records the run produced, from ids held in flow variables. Two shapes fit the existing pieces; which one (or another) is the platform's call:
- A read-only record reference on a screen: a screen field (or display block) that takes an object name and a record id from a value slot and renders the record's display name as a link to its record page, submitting nothing; or
- A completed
endthat may carry a message with record links: the completed counterpart of the refused-end notice, shown with Close instead of a toast.
Either needs a contract half in @objectstack/spec (a new screen field kind or display key, or relaxing EndConfigSchema's completed-message refusal) before the console renders it, so the objectstack spec seat may need a sibling card; this card is the consumer half and the place to decide the shape.
Related, not a duplicate: objectstack#25800 asks for an autolaunched type: 'flow' action to NAVIGATE to a record its run created (onSuccess on flow actions, flow output in the response). This card is about a screen flow showing links on its last screen; a fix for one does not deliver the other.
Who acts on it
- objectui seat: choose the shape with the spec seat, render it in
FlowRunner/ScreenView. - Then hotcrm#2285 resumes (its result-screen half is
Blocked-by:this card) once the capability is in an installable@objectstack/*release.
Dedupe
MCP search_issues objectui "screen flow end screen completion links to created records FlowRunner result screen" → 1 hit, objectstack-ai/objectui#9973 (closed; a refused end without a screen pause never opened FlowRunner, unrelated). objectstack "flow completion screen record link navigate to created record after screen flow" → 2 hits: #25800 (open, related above), objectstack-ai/objectui#9468 (closed, notification deep link).
Activity
objectstack-fleet commentedon Oct 25, 2026
Triage: first grade —
enhancement·priority:p2·domain:ui·area:workflow·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-25T14:53Z⛔ Not a claim, ⛔ not a dispatch.
endthat renders a screen, and a read-only record-link field on screens. If the link field is a new screen field type, it is a protocol addition and its spec half is filed in objectstack first. Read beside Flow actions: atype: 'flow'action cannot navigate to the record its run created —onSuccessis refused on flow actions and the run's response carriesoutput: {}#25800 (navigate to the record a flow action created).Generated by Claude Code
objectstack-fleet commentedon Oct 26, 2026
Transferred 2026-10-26T01:56Z from objectstack-ai/objectui#13540, with its comments and timeline; the old URL redirects here. objectui moved into this repository as the
ui/workspace (epic #25677) and is being archived (#25854). The body is left exactly as filed.Paths. Read every repository path in the body with a
ui/prefix:packages/app-shell/src/views/FlowRunner.tsxis nowui/packages/app-shell/src/views/FlowRunner.tsx.References. The bare issue numbers in the body were written in objectui and now resolve against this repository by mistake; read them as objectstack-ai/objectui#9468, objectstack-ai/objectui#9973.
No stale
pm:dispatchedor assignee to strip.Generated by Claude Code
objectstack-fleet commentedon Oct 26, 2026
决策分析 — 屏幕流的「结果页」怎么链到本次创建的记录(
domain:ui席 2)席位
domain:ui#2· sessionsession_01SMps7wq7rBTk53e8KTSEup· 前提读数基于origin/maindfaad4da。⛔ 本评论不是认领,也不是派发。一句话问题: 一个向导式操作(如「线索转化」一次建出客户、联系人、商机)跑完之后,用户只看到一条「成功」提示、停在原页面,没有任何地方指向刚建出来的记录;平台今天没有任何一种写法能让流程在最后一屏给出这些记录的链接。
背景
Blocked-by:本卡(「平台相关的功能,应该尽量先改平台」)。卡于 2026-10-26T01:56Z 由 objectui#13540 迁入本仓(ui/工作区)。examples/app-crm/src/flows/convert-lead.flow.ts:35以 flow 级successMessage弹一条「🎉 Lead converted — customer and opportunity created.」,新记录 id 已在account_id/opportunity_id变量里(:46-47),却无处展示成链接。dfaad4da复读(行号见下方前提):屏幕正文是纯文本;「正常完成」的end节点不许带文案,完成后只弹 toast 并关闭对话框;屏幕字段没有只读展示,更没有记录链接。Governing text
packages/specis the one contract between metadata producers and the runtime/renderers that consume it … ⛔ never add a lenient alias or??fallback in a consumer」——任何形状都要先进 spec,console 不得自造。packages/spec/src/automation/builtin-node-config.zod.ts:1238-1254(EndConfigSchema头注「message— required by a refusal, refused by a completion」):完成态带message被拒,理由是「a completion renders nothing, so the key would be a silent no-op」——拒绝的依据是「没人渲染」,不是产品上否定完成文案。{{ }}孔,孔内限路径 + 白名单格式化器,「not arbitrary CEL logic」——在文本里塞链接语法即是扩这条语法。nameField——「链接上显示什么字」已有答案,不必新造。end节点(outcome: 'refused'+message),未采纳「Close-only 的屏幕变体——a screen that is not a screen」作为终态。它没有裁完成态文案,也没有裁记录链接。git grep -n -i -E "screen flow|end node|EndConfig|result screen|completion screen|record link" origin/main -- docs/adr→ 9 处命中,全是旁及(ADR-0010/0019/0044/0052/0077/0138/0142),无一条裁定结果页/记录链接的形状。工具点名的 ADR-0006 D1、0019 D1、0031 §3、0032 §1、0037 §4、0045 §3、0053 §1、0054 §1/§4、0056 D9 逐条读过:分属环境拆分、审批并入流程、try/catch、表达式校验、实时画布、可见性门、日期语义、运行时证明、权限落地——均不回答本卡的形状问题,本卡是真决策,不是执行。协议声明、是否改协议
type在 spec 里是自由字符串(:897),但任何被识别的新成员都要在 spec 里补约束(必填reference、不收值、拒required),否则就是 console 私自发明契约;end完成态带文案则要翻转一条已发布、有测试钉住的拒绝。enhancement(消费半),下表的字母是契约形状之间的选择,不是「改协议 vs 修代码」。裁定后,契约半由domain:spec席另立一张卡承载(contract-first,Clause-②: yes,Metadata-protocol: added,@objectstack/specminor),本卡挂Blocked-by:它;见文末裁后执行段。前提(每条带 re-check 命令,
origin/main读数)ui/packages/app-shell/src/views/FlowRunner.tsx:639。git grep -n "shown.description && <DialogDescription>" origin/main -- ui/packages/app-shell/src/views/FlowRunner.tsxend完成态带message被拒 —builtin-node-config.zod.ts:1308-1316(拒绝文案在 :1313)。git grep -n "on a completed end nothing shows it" origin/main -- packages/spec/src/automation/builtin-node-config.zod.tspackages/spec/src/automation/end-node-outcome.test.ts:87-100(:98 断言文案)与 :186 起(FlowSchema 路径)。git grep -n "REFUSES \message` on a completed end" origin/main -- packages/spec/src/automation/end-node-outcome.test.ts`refused—packages/services/service-automation/src/dag-traversal.ts:169。git grep -n "endConfig?.outcome === 'refused'" origin/main -- packages/services/service-automation/src/dag-traversal.tsonComplete(),对话框关闭 —FlowRunner.tsx:512-531(toast :519,onComplete():530)。git grep -n -E "Terminal success|onComplete\(\);" origin/main -- ui/packages/app-shell/src/views/FlowRunner.tsxtype是自由字符串 —ScreenFieldConfigSchema:841-1017,type:897。git show origin/main:packages/spec/src/automation/builtin-node-config.zod.ts | sed -n 841,1017p | grep -c -i readonly→ 0ScreenFieldInput(ui/packages/app-shell/src/views/ScreenView.tsx:339-440)只有 lookup 选择器 / select / checkbox / textarea·markdown(可编辑)/ Input 五支,无展示或链接分支。git show origin/main:ui/packages/app-shell/src/views/ScreenView.tsx | sed -n 339,440p | grep -n "kind ==="successMessage是 toast 载体 —packages/spec/src/automation/flow.zod.ts:1086。git grep -n "successMessage: z.string" origin/main -- packages/spec/src/automation/flow.zod.tsLookupField的readonly分支已按显示名渲染、但不是链接 —ui/packages/fields/src/widgets/LookupField.tsx:1455-1488。git show origin/main:ui/packages/fields/src/widgets/LookupField.tsx | sed -n 1455,1488p | grep -c href→ 0defaultValue已是「服务端求值后下发」的值槽(CEL 信封)—builtin-node-config.zod.ts:913-924,即 id 可从流程变量直接取。git grep -n "defaultValue: FlowValueSlotSchema" origin/main -- packages/spec/src/automation/builtin-node-config.zod.tsonClose,runner 本身不发取消请求 —FlowRunner.tsx:624、:709;宿主是否另行取消未验证。git grep -n "onClick={onClose}" origin/main -- ui/packages/app-shell/src/views/FlowRunner.tsxfilecollects an upload, and the run resumes with the uploaded file's id #26134(屏幕字段新增file类型)open、未合并,+959/-48、14 文件,碰 zod /screen-input-contract.ts/ScreenView.tsx/FlowRunner.tsx;feat(spec,console): atype: 'flow'action may declareonSuccess, and the console navigates after a run that completes #26011(flow actiononSuccess)open,+393/-122、31 文件,碰FlowRunner.tsx与flowResponse.ts。for p in 26134 26011; do gh api repos/objectstack-ai/objectstack/pulls/$p --jq '[.number,.state,.merged,.additions,.deletions,.changed_files]'; doneBlocked-by:本卡 —gh api repos/objectstack-ai/hotcrm/issues/2285→ 403 未授权),未验证,只转述卡面。具体问题
结果页上的「指向记录的链接」放在哪一层契约里:
end也能带一段文案,链接写在这段文案里(需要新定一种链接写法:markdown 子集 / 新 token / 结构化links: [{object, id}]三选一,都是新的公开契约),运行结束后对话框停住、显示文案和 Close;type的新成员,取reference对象名 +defaultValue值槽里的 id,显示记录名并链到记录页,不提交、不可 required),作者把它放在最后一屏;选项 × 真实代价 × 工作量
end带文案 + 文案内链接refused);runner 完成后不关对话框、显示文案successMessage成两个完成文案入口,作者要选type成员 + refinement(须reference与defaultValue、拒required、恢复时不收它的值);引擎恢复契约跳过/拒收;console 在ScreenFieldInput加一支,复用LookupFieldreadonly 显示名再包链接业务含义直译
四轴(业务立场)
reference、值槽、ADR-0079 显示名)。A 让end成为第二个内容面,与 flowsuccessMessage形成「一个完成文案两个键」,链接还得在 ADR-0032 §3 刻意收窄的模板语法里开新口子,或在end上另挂一个只有终点能用的links——那其实就是 B 的概念放错了位置。A flow cannot REFUSE with per-record text: the only channel that interpolates is a screendescription, and a message-only screen still renders Submit and toasts "completed" #14945 裁决 2′ 把拒绝放在end,理由是「语言只有 completed 一种终态,补一个结局」;完成态本来就有终态,缺的是展示件,不是结局。⇒ B 缩小契约增生,A/C 扩大。reference或给它加required,发布时就被响亮拒绝,作者当场看到;A 若用 markdown 子集,AI 写错链接只会在用户界面上显示成一串字面文本(静默),而且插值进来的记录名本身若含[..](..)会被当成链接渲染——这是数据注入成链接的口子,属安全边界,恒在人工地板;A 用结构化links则也能响亮,但仍多一个只在终点生效的键。type成员加一条 refinement,无新顶层键;A 是翻转一条已钉住的拒绝 + 新链接语法 + 运行结果上的新字段;C 两者全背。每个声明的键都是永久义务,B 最少。推荐 + 置信缺口
推荐 B。 只按①得出:屏幕是内容面、展示件放屏幕上,与 Salesforce Screen Flow 的建模一致,且复用现有键与 ADR-0079 显示名,不扩模板语法。
end成第二个内容面、并与successMessage重叠,链接语法是无先例的新契约。置信缺口(盲区明说,不另荐):
filecollects an upload, and the run resumes with the uploaded file's id #26134 尚未落地,行数是在飞 PR 的读数,不是已合并读数。自检行:只看①选 B;②③④ 是否翻转:否。
裁后执行段(裁 B 时)
domain:spec席立「屏幕字段新增只读记录引用类型」卡,本卡挂Blocked-by:它并转pm:blocked。执行参数(请随裁决一并定,免二次请示):成员名建议type: 'record'(与lookup/file同为单词小写);须带reference(对象名)与defaultValue(值槽,求值为 id);required/options/placeholder/min/max在该成员上拒收;恢复时该字段名下的值被拒收(响亮,不静默丢弃),不绑定流程变量;visibleWhen照常可用;id 求值为空时渲染「—」而非报错。Clause-②: yes,Metadata-protocol: added,spec minor。filecollects an upload, and the run resumes with the uploaded file's id #26134 的形状由一个 PR 同时落 spec refinement、screen-input-contract.ts恢复规则、ScreenFieldInput新分支(复用LookupFieldreadonly 取显示名,包成记录页链接)、content/docs/automation/flows.mdx一节、一条 dogfood 证明(ADR-0054:两条记录的夹具,结果屏显示两条记录名并链到正确记录页,恢复带该字段值被拒)。PR 同时关闭 spec 卡与本卡;若 spec 席坚持拆 PR,console 分支须同一发布内落地,否则即「声明而未兑现」。filecollects an upload, and the run resumes with the uploaded file's id #26134 之后(同改ScreenFieldConfigSchema、screen-input-contract.ts、ScreenView.tsx);与 feat(spec,console): atype: 'flow'action may declareonSuccess, and the console navigates after a run that completes #26011 无同区冲突。@objectstack/*发布后,在本卡留一行发布号,由 hotcrm 席去除 hotcrm#2285 的Blocked-by:(本席无 hotcrm 写/读权限)。needs-user-decision、退出活动队列,priority:p2不变。若裁 A:同样另立
domain:spec卡,且裁决须同笔定链接写法(三选一)与successMessage的关系(合并或分工),否则执行时必然回箱。os-decision-facets
reference、值槽与 ADR-0079 显示名,对齐 Salesforce Screen Flow;A/C 让end成第二内容面并与successMessage重叠。reference或加required在发布时响亮拒绝;A 的 markdown 写法写错即静默显示字面文本,且插值记录名可被渲染成链接。type成员与一条 refinement;A 翻转已钉住的拒绝并新增链接语法与结果字段;C 两者全背。Prior rulings read: screen,end,outcome,message,readonly → 34 hits; ADR-0006 D1, ADR-0019 D1, ADR-0031 Decision §3, ADR-0032 Decision §1, ADR-0037 Decision §4, ADR-0045 Decision §3, ADR-0053 Decision §1, ADR-0054 Decision §1, ADR-0054 Decision §4, ADR-0056 D9; thread: none
(手检补读:objectstack#14945 裁决 2′,comment 5548735593——裁拒绝态文案落
end,未裁完成态与记录链接。)相关单与 PR
Blocked-by:本卡,本会话不可读)· hotcrm#2285 裁决 B comment 6398567074end)· feat(spec): the flowendnode declares its outcome —refusedwith an interpolatedmessage, and the run vocabulary gainsrefused#15889(其 spec 车道,已合并)· service-automation: honouroutcome: 'refused'on the flowendnode — a terminalrefusedrun status (distinct fromfailed) with the interpolated message persisted on the run (lane 2 of the #14945 ruling 2′) #15788(其引擎车道,已关闭)· FlowRunner: render a flow that ended withoutcome: 'refused'as a Close-only notice with no "completed" toast (lane 3 of objectstack#14945 ruling 2′) objectui#7707(其 console 车道)type: 'flow'action cannot navigate to the record its run created —onSuccessis refused on flow actions and the run's response carriesoutput: {}#25800 / feat(spec,console): atype: 'flow'action may declareonSuccess, and the console navigates after a run that completes #26011(flow action 完成后跳转到新记录——相关不重复:那是自启动流程的导航,本卡是屏幕流最后一屏的链接)filecollects an upload, and the run resumes with the uploaded file's id #26134(屏幕字段file类型,B 的同类先例与排队前驱)refusedWITHOUT a screen pause never opens FlowRunner — the launch handlers return success and the action toastssuccessMessage, so the refusal is never shown objectui#9973、Notification deep link navigates to the app landing page instead of the record #9468(卡面去重时的旁及单)objectstack-fleet commentedon Oct 26, 2026
Brief-claimed-by: session_01KrKXQVvgYk2AJ4VkqMobyb · batch #401 · 2026-10-26T15:43Z
Director seat, summon #51 continuation (ledger objectstack#12708). Presented to the maintainer in batch #401 as item 3 of 5 (with #26149, batch #400's open item, re-presented beside it at the maintainer's word 「按照总监决裁格式详细写」). Seat increment (re-verified on
origin/maincdd4eea9; the card's own analysis is not restated):FlowRunner.tsxrendersshown.descriptionas plain text (1 hit);EndConfigSchemarefusesmessageon a completed end ("on a completed end nothing shows it", 1 hit); PR feat(spec,automation,app-shell)!: a flow screen field typedfilecollects an upload, and the run resumes with the uploaded file's id #26134 (thefilescreen field, the analysis's precedent and queue predecessor) has merged — the serialization constraint in 6419689832 is cleared and B now has a landed precedent (+959/−48, 14 files); PR feat(spec,console): atype: 'flow'action may declareonSuccess, and the console navigates after a run that completes #26011 (flow-actiononSuccess) is open, no overlap with B's files.builtin-node-config.zod.tsdocblock (the completed-end refusal exists because nothing renders it, not as a product stance); ADR-0032 §3 (templates carry paths and whitelisted formatters, no link syntax); ADR-0079 (display name =nameField); objectstack#14945 ruling 2′ (refusal copy onend; completed copy and record links not ruled). The seat found no further ADR.type: 'record'-style member withreference+ a value-slotdefaultValueholding the id, submits nothing,requiredrefused; the console renders the display name as a link viaLookupField's readonly branch) and with the execution parameters in 6419689832 §裁后执行 (one PR across spec / engine / console, dogfood proof, docs section). Not A (a second content surface onend, overlappingsuccessMessage, with a link syntax nobody has), not C. Workload: spec card + one three-layer PR, precedent feat(spec,automation,app-shell)!: a flow screen field typedfilecollects an upload, and the run resumes with the uploaded file's id #26134 (landed).Prior rulings read:
EndConfigSchema·#14945·screen field type→ the refusal docblock, ruling 2′, feat(spec,automation,app-shell)!: a flow screen field typedfilecollects an upload, and the run resumes with the uploaded file's id #26134's landed shape; thread: 6419689832.objectstack-fleet commentedon Oct 26, 2026
Ruling: batch #401 item 4 · letter B · maintainer 「同意」 2026-10-26T17:29Z
Recorded by the director seat (summon #51 continuation,
session_01KrKXQVvgYk2AJ4VkqMobyb, ledger objectstack#12708). The maintainer answered batch #401 with 「同意」 — every seat letter. Brief 6420313016; thedomain:uiseat 2 analysis 6419689832 is the ruling's substance. Letter B, a read-only record-reference screen field, with the execution parameters of that analysis's 裁后执行 section adopted in this same stroke: a newScreenFieldConfigSchematypemember (the dev proposes the name,recordsuggested) that must carryreference(object name) anddefaultValue(a value slot evaluating to the id);required,options,placeholder,min,maxrefused on it; on resume, a value under that field name is refused loudly, never bound to a flow variable;visibleWhenas usual; an empty id renders "—". The console renders the record's display name (ADR-0079nameField, viaLookupField's readonly branch) as a link to the record page. Not A (a second content surface onendoverlappingsuccessMessage, with an unprecedented link syntax) and not C.Workload of the chosen letter (card column): one spec card (
domain:spec: the member + refinement;Clause-②: yes (widening),Metadata-protocol: added,@objectstack/specminor) and one PR across spec / engine (screen-input-contract.tsresume rule) / console (ScreenFieldInputbranch) with acontent/docs/automation/flows.mdxsection and one dogfood proof (two created records shown and linked; a resume carrying the field's value refused), in the shape of the landed precedent PR #26134 (+959/−48, 14 files, merged — the queue constraint the analysis named is cleared); no overlap with #26011.Execution:
needs-user-decision→pm:queuein this act (domain:ui, p2,area:workflow). The claiming seat files the spec card first and moves this card topm:blockedwithBlocked-by:it; one PR may close both when the spec seat agrees to the three-layer shape, otherwise the console branch lands in the same release (declared = enforced). After a published@objectstack/*release carries it, the hotcrm seat lifts hotcrm#2285'sBlocked-by:.Ruling-ref:names this comment.objectstack-fleet commentedon Oct 26, 2026
Seat
domain:ui#1· 2026-10-26T19:58Z: following the ruling's execution (6422899013), the contract half is filed as #26304 (domain:spec).Blocked-by: #26304
This card moves to
pm:blockeduntil the spec seat either lands #26304 or agrees to the one-PR, three-layer shape (spec + engine + console, as #26134 did). On that agreement, seat 1 dispatches a card thread here at once.objectstack-fleet commentedon Oct 26, 2026
Claim: PM loop round 1 · consumer half, landing with #26304 in one PR
Session:
session_017iXjUm1rujwDk7f3KT1Pkk(seat); implementing card threadsession_0115tbh4XfgivQD2RpHHwdMzAccount:
os-steveBranch:
claude/project-thread-70vh6i(the same branch as the #26304 claim; one PR closes both)Worktree: the card thread's own container
Domain:
domain:uiSeat:
domain:ui#1File surface: as the #26304 claim (its console half:
ui/packages/app-shell/src/views/ScreenView.tsxScreenFieldInputand its tests,content/docs/automation/flows.mdx, the dogfood proof).Container & model:
medium,mode:thread,model: TIER_DEFAULT,effort: highClause-②: yes (widening)
Metadata-protocol: added
Responsibility: the consumer of #26304's new screen-field member; ruling B 6422899013.
Thread-read: 6425965791
Premise: holds (the blocker #26304 is claimed on the same branch at this stamp; 2026-10-26T21:51Z)
Serial constraints cleared: none at claim time
This card leaves
pm:blocked: its blocker #26304 is now in flight on this same branch.objectstack-fleet commentedon Oct 26, 2026
os-dev-report
{ "issue": 25872, "status": "done", "branch": "claude/project-thread-70vh6i", "pr": "https://github.com/objectstack-ai/objectstack/pull/26355", "session": "session_0115tbh4XfgivQD2RpHHwdMz", "premise_still_valid": true, "summary": "One draft PR (#26355, head a2c646635b) closes #26304 and #25872. The spec's ScreenFieldConfigSchema gains the type member 'record_link' (SCREEN_FIELD_RECORD_LINK_TYPE): reference and defaultValue are required, and required/options/placeholder/min/max are refused, each at its own key, through a branch of the existing superRefine with no new key. The engine's validateScreenInputs refuses any resume value under a record_link field's name (invalid_value inside 400 INVALID_SCREEN_INPUT, visible or hidden, null included) and never binds it, and judgeHeadlessScreen never counts the field as answered. The console's ScreenFieldInput shows the record's display name through LookupField's readonly branch (ADR-0079 nameField) inside a router Link built by appRecordPath; an empty id shows the dash, visibleWhen works as usual, and the dialog never seeds or posts the field. flows.mdx gains 'A read-only record link'. Named record_link, not record, because FieldType already has 'record' (seat 1 accepted the reasoning).", "tests": "New: spec screen-field-record-link.test.ts 9/9; service-automation screen-input-record-link-field.test.ts 6/6 and builtin/screen-record-link-resume.test.ts 2/2; app-shell FlowRunner.recordLink-25872.test.tsx 6/6; dogfood flow-screen-record-link.dogfood.test.ts 2/2 (real boot: two created records arrive as record_link with their ids, each reads back with its nameField value, a resume carrying account_link or contact_link:null is refused 400 INVALID_SCREEN_INPUT, the clean resume completes). Full packages: spec Test Files 805 passed (805), Tests 23263 passed; service-automation Test Files 209 passed (209), Tests 2707 passed (2707); app-shell neighbours Test Files 160 passed (160), Tests 1794 passed (1794). Typecheck spec/service-automation/dogfood and app-shell type-check exit 0 each; Console turbo build exit 0 on a2c646635b. Ablation via scripts/ablation-replace.mjs, file restored to HEAD each time: spec branch disabled 5/9 red; engine resume pass disabled 3 red; headless skip removed 1 red (first attempt void, refused by the tool before any run); console branch disabled 5/6 red; initialScreenValues skip removed 1 red.", "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 27c90bb39d: 115 commands, each run with its exit captured before any pipe; --ran: '115 derived famil(ies) accounted for — 114 run, 1 NOT-MEASURED'; the 114 exited 0. After merging origin/main (12 commits, none touching this diff) check:generated and check:type-check-debt re-ran on a2c646635b, exit 0. check:skill-examples and the check-plugin-teardown-shape self-test stopped on prerequisites first (unbuilt client-react, shallow clone) and exited 0 once met. NOT MEASURED locally: check:dual-build-cjs-loads (needs a full workspace build, exit 3 before reading anything) — left to CI. CI check-runs not yet cited: the PR is a fresh draft.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "10 — mcp__github__issue_read only (cards #25872, #26304, claims, labels); no write tool", "api_writes": "4 kinds — git push to claude/project-thread-70vh6i (several, branch only, never main); relay pr_create #26355 (draft, read back byte-identical); os-dev-report comment on #26304 and the same report on #25872 via scripts/pm/post-stamped.mjs. The second report comment is one over the three-write budget: both cards are pm:dispatched and both carry this branch's claim, so each gets its report.", "open_questions": [], "out_of_scope_findings": [ "carrier: #26347 (filed by seat 1) · the skill text in skills/objectstack-automation and the eval entry in evals/flows-triggers-approvals.json for record_link; skills/** is governed so this PR does not touch it · named in the PR body", "carrier: hotcrm seat · hotcrm#2285's Blocked-by can lift after a published @objectstack/* release carries this · noted in the PR's Acceptance notes, not filed" ] }Generated by Claude Code