Skip to content

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

Closed

Description

@objectstack-fleet

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)

  1. A screen's body text is plain text. The bundled console (@objectstack/console 18.1.0, dist/assets/urlParams-*.js) renders ScreenSpec.description as 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.
  2. A completed end renders nothing. EndConfigSchema (@objectstack/spec 18.1.0, src/automation/builtin-node-config.zod.ts) refuses message unless outcome: 'refused' ("on a completed end nothing shows it"). On terminal success the runner toasts and calls onComplete() (same bundle; source FlowRunner.tsx terminal-success branch), so the dialog closes.
  3. No screen field displays a value read-only, let alone as a record link. ScreenView.tsx (ScreenFieldInput) renders lookup (an editable LookupField picker), select, boolean/checkbox, textarea/markdown (an editable Textarea), and a text/number/email/date Input. ScreenFieldConfigSchema carries no readonly key. A pre-filled lookup is 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 end that 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

  1. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    ContributorAuthor

    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.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    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.tsx is now ui/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:dispatched or assignee to strip.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    决策分析 — 屏幕流的「结果页」怎么链到本次创建的记录(domain:ui 席 2)

    席位 domain:ui#2 · session session_01SMps7wq7rBTk53e8KTSEup · 前提读数基于 origin/main dfaad4da。⛔ 本评论不是认领,也不是派发。

    一句话问题: 一个向导式操作(如「线索转化」一次建出客户、联系人、商机)跑完之后,用户只看到一条「成功」提示、停在原页面,没有任何地方指向刚建出来的记录;平台今天没有任何一种写法能让流程在最后一屏给出这些记录的链接。

    背景

    • 本卡由 hotcrm#2285 的卡线程依维护者对该卡裁决 B(comment 6398567074,「同意」于 2026-10-25T13:58Z)立出:平台屏幕流跑不出「结果页带记录链接」时,先在平台立卡,HotCRM 卡挂 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

    • AGENTS.md 第 12 条 Contract-first:「packages/spec is 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 不得自造。
    • AGENTS.md 第 10 条:「never advertise or demo a capability the runtime doesn't actually deliver (declared ≠ enforced)」——新键必须与运行时兑现同版落地。
    • spec docblock 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」——拒绝的依据是「没人渲染」,不是产品上否定完成文案。
    • ADR-0032 Decision §3:文本模板只有 {{ }} 孔,孔内限路径 + 白名单格式化器,「not arbitrary CEL logic」——在文本里塞链接语法即是扩这条语法。
    • ADR-0078 §6:一条规则只随使它为真的运行时那一行一起发货——新类型成员的约束须与渲染/恢复路径同笔。
    • ADR-0079:记录显示名的唯一指针是 nameField——「链接上显示什么字」已有答案,不必新造。
    • 既有裁决 objectstack#14945 裁决 2′(comment 5548735593,2026-09-05T02:27Z):拒绝类终态的文案放在 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、表达式校验、实时画布、可见性门、日期语义、运行时证明、权限落地——均不回答本卡的形状问题,本卡是真决策,不是执行。

    协议声明、是否改协议

    • 三个形状都改协议,没有「只改 console」的选项:屏幕字段的 type 在 spec 里是自由字符串(:897),但任何被识别的新成员都要在 spec 里补约束(必填 reference、不收值、拒 required),否则就是 console 私自发明契约;end 完成态带文案则要翻转一条已发布、有测试钉住的拒绝。
    • 按「改协议单独立卡,⛔ 不作缺陷卡的选项」:本卡是 enhancement(消费半),下表的字母是契约形状之间的选择,不是「改协议 vs 修代码」。裁定后,契约半由 domain:spec 席另立一张卡承载(contract-first,Clause-②: yes,Metadata-protocol: added,@objectstack/spec minor),本卡挂 Blocked-by: 它;见文末裁后执行段。

    前提(每条带 re-check 命令,origin/main 读数)

    1. 屏幕正文按纯文本渲染 — ui/packages/app-shell/src/views/FlowRunner.tsx:639。
      git grep -n "shown.description && <DialogDescription>" origin/main -- ui/packages/app-shell/src/views/FlowRunner.tsx
    2. end 完成态带 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.ts
    3. 该拒绝有两处测试钉住 — packages/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`
    4. 引擎只读 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.ts
    5. 正常完成 = toast + onComplete(),对话框关闭 — FlowRunner.tsx:512-531(toast :519,onComplete() :530)。
      git grep -n -E "Terminal success|onComplete\(\);" origin/main -- ui/packages/app-shell/src/views/FlowRunner.tsx
    6. 屏幕字段无只读键,type 是自由字符串 — 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 → 0
    7. ScreenFieldInput(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 ==="
    8. 已有的流程级完成文案 successMessage 是 toast 载体 — packages/spec/src/automation/flow.zod.ts:1086。
      git grep -n "successMessage: z.string" origin/main -- packages/spec/src/automation/flow.zod.ts
    9. 可复用件:LookupField 的 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 → 0
    10. 屏幕字段的 defaultValue 已是「服务端求值后下发」的值槽(CEL 信封)— builtin-node-config.zod.ts:913-924,即 id 可从流程变量直接取。
      git grep -n "defaultValue: FlowValueSlotSchema" origin/main -- packages/spec/src/automation/builtin-node-config.zod.ts
    11. 关闭对话框只调 onClose,runner 本身不发取消请求 — FlowRunner.tsx:624、:709;宿主是否另行取消未验证。
      git grep -n "onClick={onClose}" origin/main -- ui/packages/app-shell/src/views/FlowRunner.tsx
    12. 在飞冲突:feat(spec,automation,app-shell)!: a flow screen field typed file collects 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): a type: 'flow' action may declare onSuccess, and the console navigates after a run that completes #26011(flow action onSuccess)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]'; done
    13. 消费方拉动 hotcrm#2285(结果页)按本卡正文挂 Blocked-by: 本卡 — ⚠️ 本会话对 hotcrm 无读权限(gh api repos/objectstack-ai/hotcrm/issues/2285 → 403 未授权),未验证,只转述卡面。

    具体问题

    结果页上的「指向记录的链接」放在哪一层契约里:

    • A 让「正常完成」的 end 也能带一段文案,链接写在这段文案里(需要新定一种链接写法:markdown 子集 / 新 token / 结构化 links: [{object, id}] 三选一,都是新的公开契约),运行结束后对话框停住、显示文案和 Close;
    • B 新增一种只读「记录引用」屏幕字段(type 的新成员,取 reference 对象名 + defaultValue 值槽里的 id,显示记录名并链到记录页,不提交、不可 required),作者把它放在最后一屏;
    • C 两者都做。

    选项 × 真实代价 × 工作量

    选项 做什么 客户可感知后果 工作量
    A 完成态 end 带文案 + 文案内链接 翻转 :1308-1316 的拒绝及两处测试钉;定链接语法;引擎在完成态渲染并把文案带上结果(:169 今只读 refused);runner 完成后不关对话框、显示文案 跑完后对话框停住显示「已建出 X / Y」及链接,点 Close 离开;与 flow 级 successMessage 成两个完成文案入口,作者要选 spec · services · ui 三车道 3 PR;实测先例只有同族的拒绝态 spec 车道 #15889(已合并,+695/-37,22 文件),引擎与 console 两车道当时在另一仓,未测;链接语法无先例
    B 只读记录引用屏幕字段 spec 增 type 成员 + refinement(须 reference 与 defaultValue、拒 required、恢复时不收它的值);引擎恢复契约跳过/拒收;console 在 ScreenFieldInput 加一支,复用 LookupField readonly 显示名再包链接 最后一屏列出「客户:某某公司 →」等可点链接;按钮仍是 Cancel/Submit,点 Submit 才结束、弹完成 toast;中途点链接离开时,run 停在 paused(与今天点 Cancel 同,前提 11) 一 PR 跨 spec/engine/console;先例 #26134(同类:屏幕字段新类型穿三层)+959/-48、14 文件——在飞未落地,非已落地先例;须排在 #26134 之后(同区域)
    C A + B 两者全做 两种写法都能做结果页,作者面前有两条路 A + B 之和,≥ 4 PR,链接语法仍无先例
    不做 本卡关闭 hotcrm#2285 结果页无法编写,维持 toast;应用仓按「应用仓推荐序特例」只能等,⛔ 不许自建 0

    业务含义直译

    • A = 在「收据打印机」上加一行可点的字——结账完成后打一张带链接的回执;但回执的排版语言要我们新发明。
    • B = 在表单最后一页放几张「已建档案卡片」,点卡片进档案——用的是现成的「档案名」规则,不发明新排版语言。
    • C = 两样都上,同一件事给作者两种写法。
    • 不做 = 告诉 HotCRM「转完你自己去相关列表里找」。

    四轴(业务立场)

    • ① 项目长远合理性(领起,权重 ≥50%):两年后的样子——屏幕是唯一的「内容面」,往屏幕上放展示件(文本、记录引用、以后可能的摘要卡),终点节点只记结局。主流参照:Salesforce Screen Flow 的结果页就是一张普通屏幕,上面放 Display Text 等只读组件,作者用合并字段拼出记录链接;它的 End 元素本身不带任何界面。B 正是这条路:一个可复用的只读展示件(中途屏幕也能用,比如「你正在转换线索 X」),键全复用(reference、值槽、ADR-0079 显示名)。A 让 end 成为第二个内容面,与 flow successMessage 形成「一个完成文案两个键」,链接还得在 ADR-0032 §3 刻意收窄的模板语法里开新口子,或在 end 上另挂一个只有终点能用的 links——那其实就是 B 的概念放错了位置。A flow cannot REFUSE with per-record text: the only channel that interpolates is a screen description, and a message-only screen still renders Submit and toasts "completed" #14945 裁决 2′ 把拒绝放在 end,理由是「语言只有 completed 一种终态,补一个结局」;完成态本来就有终态,缺的是展示件,不是结局。⇒ B 缩小契约增生,A/C 扩大。
    • ② 实际业务拉动:今天撞上的是 HotCRM 线索转化(维护者裁定级拉动,hotcrm#2285;本会话未能直读,见前提 13);本仓参考应用 app-crm 的 convert-lead 是同一形状(前提背景),说明「建完给链接」是通用需求而非单家。拉动只要求「最后一屏能给出链接」,B 足够;A 额外带来的「完成后停住对话框」没有被点名要求。
    • ③ 防 AI 犯错(出错时谁看到什么):B 是闭合成员 + refinement——AI 漏写 reference 或给它加 required,发布时就被响亮拒绝,作者当场看到;A 若用 markdown 子集,AI 写错链接只会在用户界面上显示成一串字面文本(静默),而且插值进来的记录名本身若含 [..](..) 会被当成链接渲染——这是数据注入成链接的口子,属安全边界,恒在人工地板;A 用结构化 links 则也能响亮,但仍多一个只在终点生效的键。
    • ④ 创业阶段不扩散:B 是一个 type 成员加一条 refinement,无新顶层键;A 是翻转一条已钉住的拒绝 + 新链接语法 + 运行结果上的新字段;C 两者全背。每个声明的键都是永久义务,B 最少。

    推荐 + 置信缺口

    推荐 B。 只按①得出:屏幕是内容面、展示件放屏幕上,与 Salesforce Screen Flow 的建模一致,且复用现有键与 ADR-0079 显示名,不扩模板语法。

    • 不取 A:让 end 成第二个内容面、并与 successMessage 重叠,链接语法是无先例的新契约。
    • 不取 C:为同一件事给作者两条路,④ 直接反对,且拉动只需要 B。
    • 不取「不做」:有维护者裁定级拉动,且参考应用同形状。

    置信缺口(盲区明说,不另荐):

    自检行:只看①选 B;②③④ 是否翻转:否。

    裁后执行段(裁 B 时)

    1. 契约半单独立卡: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。
    2. 一 PR 跨三层,同版兑现:按 feat(spec,automation,app-shell)!: a flow screen field typed file collects an upload, and the run resumes with the uploaded file's id #26134 的形状由一个 PR 同时落 spec refinement、screen-input-contract.ts 恢复规则、ScreenFieldInput 新分支(复用 LookupField readonly 取显示名,包成记录页链接)、content/docs/automation/flows.mdx 一节、一条 dogfood 证明(ADR-0054:两条记录的夹具,结果屏显示两条记录名并链到正确记录页,恢复带该字段值被拒)。PR 同时关闭 spec 卡与本卡;若 spec 席坚持拆 PR,console 分支须同一发布内落地,否则即「声明而未兑现」。
    3. 排队约束:排在 feat(spec,automation,app-shell)!: a flow screen field typed file collects an upload, and the run resumes with the uploaded file's id #26134 之后(同改 ScreenFieldConfigSchema、screen-input-contract.ts、ScreenView.tsx);与 feat(spec,console): a type: 'flow' action may declare onSuccess, and the console navigates after a run that completes #26011 无同区冲突。
    4. 下游:含该能力的 @objectstack/* 发布后,在本卡留一行发布号,由 hotcrm 席去除 hotcrm#2285 的 Blocked-by:(本席无 hotcrm 写/读权限)。
    5. 状态:本卡挂 needs-user-decision、退出活动队列,priority:p2 不变。

    若裁 A:同样另立 domain:spec 卡,且裁决须同笔定链接写法(三选一)与 successMessage 的关系(合并或分工),否则执行时必然回箱。

    os-decision-facets

    • ① 项目长远合理性:B 缩小契约增生——展示件住在屏幕这一个内容面,复用 reference、值槽与 ADR-0079 显示名,对齐 Salesforce Screen Flow;A/C 让 end 成第二内容面并与 successMessage 重叠。
    • ② 实际业务拉动:今天撞上的是 HotCRM 线索转化结果页(维护者裁定级,hotcrm#2285,本会话未直读),本仓 app-crm convert-lead 同形状;拉动只需「最后一屏给链接」,B 足够。
    • ③ 防 AI 犯错:B 是闭合成员 + refinement,漏 reference 或加 required 在发布时响亮拒绝;A 的 markdown 写法写错即静默显示字面文本,且插值记录名可被渲染成链接。
    • ④ 创业阶段不扩散:B 只加一个 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

  4. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    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/main cdd4eea9; the card's own analysis is not restated):

  5. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    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; the domain:ui seat 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 new ScreenFieldConfigSchema type member (the dev proposes the name, record suggested) that must carry reference (object name) and defaultValue (a value slot evaluating to the id); required, options, placeholder, min, max refused on it; on resume, a value under that field name is refused loudly, never bound to a flow variable; visibleWhen as usual; an empty id renders "—". The console renders the record's display name (ADR-0079 nameField, via LookupField's readonly branch) as a link to the record page. Not A (a second content surface on end overlapping successMessage, 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/spec minor) and one PR across spec / engine (screen-input-contract.ts resume rule) / console (ScreenFieldInput branch) with a content/docs/automation/flows.mdx section 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:queue in this act (domain:ui, p2, area:workflow). The claiming seat files the spec card first and moves this card to pm:blocked with Blocked-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's Blocked-by:. Ruling-ref: names this comment.

  6. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    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:blocked until 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.

  7. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · consumer half, landing with #26304 in one PR
    Session: session_017iXjUm1rujwDk7f3KT1Pkk (seat); implementing card thread session_0115tbh4XfgivQD2RpHHwdMz
    Account: os-steve
    Branch: claude/project-thread-70vh6i (the same branch as the #26304 claim; one PR closes both)
    Worktree: the card thread's own container
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: as the #26304 claim (its console half: ui/packages/app-shell/src/views/ScreenView.tsx ScreenFieldInput and its tests, content/docs/automation/flows.mdx, the dogfood proof).
    Container & model: medium, mode:thread, model: TIER_DEFAULT, effort: high
    Clause-②: 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.

  8. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:workflowApprovals and automation — the work that runs without a person driving itdomain:uienhancementNew feature or requestpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions