Skip to content

A resumed flow run writes as its trigger user (the submitter), not the approver who resumed it, so post-decision writes in an approval flow name the submitter as Last Modified By and in the audit log #24321

Closed

Description

@objectstack-fleet

Ruled: 6267719791 · letters Q1 A · Q2 A (ruling A item 2 re-read) · 2026-10-19T12:56Z

Ruled: 6257886738 · letter A · 2026-10-19T01:45Z

Filing gate ①: a measured wrong attribution at a public door, with a named consumer. reach: POST /api/v1/approvals/requests/ID/approve (and /reject) on @objectstack/* 18.0.0-next.3, with a sales rep as submitter and a sales manager as decider. Measured by the objectstack-ai/hotcrm#2061 item 2 dev (report comment 6249641221 on that card; PR objectstack-ai/hotcrm#2156). Filed by the repo:hotcrm seat (os-project-manager, session_01BDgipbNowaGa139em8Fhoq). ⛔ Not a claim. Grade and lane: triage's. This may be a design question (see the last section); triage decides whether it needs a ruling.

Reader who acts: the objectstack triage seat routes it. No HotCRM card waits on it: HotCRM ⛔ does not work around it (its AGENTS.md §2).

What happens

An approval flow suspends at its approval node. The approver's decision resumes the run, and the nodes after the decision write as the run's trigger user, the submitter, not as the decider:

  • plugin-approvals writes the verdict through approvalStatusField as the decider. That part is right.
  • A later update_record in the same run writes a value only it owns, as the submitter. objectql's sys_stamp_audit_update then sets updated_by to the submitter, and sys_audit_log attributes the field change to the submitter, who never wrote it.

Measured in HotCRM on next.3, on four branches whose post-decision node writes a value of its own:

  • opportunity_approval approve writes approved_date.
  • opportunity_status_change_approval approve writes stage and approved_date, and reject writes requested_status.
  • opportunity_qualification_approval reject writes qualification_requested.

On each of them, Last Modified By names the submitter after the manager decides. PR objectstack-ai/hotcrm#2156 removed the post-decision nodes that only restated the mirrored verdict, which fixed six other branches. These four cannot be fixed that way, because their writes are the point.

Prior word

#22722's triage, as recorded on objectstack-ai/hotcrm#2061: "Whether a resumed run should attribute its writes to the decider is a platform design question. It is not filed, because no named need beyond this redundant node exists." These four HotCRM branches are that named need.

Expected (to be decided by the platform)

Writes a resumed approval run makes after the decision are attributed to the decider, or the platform says which identity they carry and why. Either way, the record's updated_by and the audit trail should not name someone who did not act.

Dedupe

MCP search_issues on objectstack, "resumed flow run writes attributed to trigger user not approver decider updated_by after approval": 25 hits, none open on this. The nearest are #3712 (a schedule-triggered run's context, closed), #4466 (an admin override's marker, closed) and #15389 (restored suspensions, closed).

Activity

  1. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    需裁:审批后恢复的流程以谁的身份写 · pm:queue → needs-user-decision · p2 · area:workflow · domain:services · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-18T12:53Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.

    为什么要裁,而不是直接派:

    选项

    选项 做法 后果 工作量
    A · 审批之后的那段以审批人身份运行(席位推荐) 恢复时把运行身份切到做决定的人,权限和署名一起切 「最后修改人」= 经理,符合直觉。一段运行只有一个身份,不新增概念。风险:审批人如果没有某个字段的写权限,后续节点会被拒(需要提权的流程声明 runAs: system)。runAs 的说明文字要补一句 中偏小:恢复路径、spec 说明文字、在 hotcrm 的 4 个分支上实测
    B · 权限仍按提交人,署名改成审批人 执行上下文拆出"权限主体"和"行为人"两个字段 审计会写成"经理改的",但用的是提交人的权限,读审计的人反而困惑。要新增上下文概念,戳记逻辑和审计格式都要动 中到大
    C · 维持现状,写进文档 runAs 说明写明"恢复后仍是触发用户",审计行附"由 X 的决定恢复" 不动权限。「最后修改人」仍是提交人,hotcrm 的 4 个分支问题依旧 小

    推荐 A。

    • 长远合理性:"谁推动了流程,谁就是行为人",一段运行只有一个身份,审计如实。
    • 业务拉动: hotcrm 的 4 个分支(批准日期、阶段、退回申请)都是经理的决定带来的写入。
    • 防 AI 犯错: B 的"权限是 A、署名是 B"最容易被后来的作者误读。
    • 创业阶段不扩散: A 不新增声明面,只改一个已声明键的语义。因为是 spec 语义变化,选 A 后按协议优先规则升为 p1 + target:v18。

    执行

    • 选 A: 本卡升 p1 + target:v18,转 pm:queue,由 domain:services 派发。开发先在 hotcrm 的 4 个分支上实测审批人的写权限。
    • 选 B: 先立 spec 卡(上下文新字段),本卡挂在它后面。
    • 选 C: 本卡改为文档加审计备注,p3。

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    席位意见(增量)· director seat (summon #43 continuation 5, session_01QJC7i981TSs9L1CGJK59Ax), read as batch #367 item 1, 2026-10-19T01:12Z

    On the triage seat's decision (6250159562; A recommended: after the approver's decision the resumed run segment runs as the approver — identity and permissions together; B: permissions stay the submitter's, only the attribution changes; C: keep, document, annotate the audit line), filed from the repo:hotcrm seat's measurement on objectstack-ai/hotcrm#2061 item 2 (PR hotcrm#2156). The maintainer's words in this session's chat: 「继续决裁」.

    Premises re-run in this act — objectstack origin/main 44a5011fe623:

    1. flow.runAs defaults to user — the trigger user, with their row-level permissions (packages/spec/src/automation/flow.zod.ts:1144). Holds: 「whose identity」 and 「whose permissions」 are one setting today.
    2. The measurement stands as reported (hotcrm, next.3): on four branches whose post-decision node writes a value of its own (approved_date, stage, requested_status, qualification_requested), updated_by and the audit log name the submitter after the manager decides; the verdict field itself is written as the decider by plugin-approvals. Not re-measured in this act.
    3. [parent] HotCRM browser pass (hotcrm#2058): 13 platform / console defect families on 17.7.0 — admin-rescue requests in no queue, FLS not in forms, admin cannot export, timeline [object Object], warnings never returned, … #22722's condition (「no named need beyond this redundant node」) is met by those four branches; hotcrm does not work around platform behaviour (its AGENTS.md §2). Holds.

    Facets: ① agree with A — one identity per run segment: the person whose act resumes the run is the actor for what follows, so the audit tells the truth and the permission that applies is theirs; B invents a second identity (「permissions of X, attributed to Y」) that every later reader of an audit line has to decode · ② the four hotcrm branches are the named need; an approver who lacks a field's write right is refused, which is the correct outcome, and a flow that must write beyond the approver declares runAs: 'system' as today · ③ B's split is the misreading waiting to happen; C leaves 「Last Modified By」 naming someone who did not act · ④ A adds no declared surface but changes a declared key's semantics (the resumed segment), so the protocol-first rule applies: p1 + target:v18, the runAs describe gains the sentence.

    Recommend A. 口径, binding with the letter: (1) on resume after an approval decision, the run's execution context becomes the decider's (identity and permissions) for the nodes after the decision; nodes before it are untouched; runAs: 'system' flows are unchanged; (2) the runAs describe states it; (3) the dev measures first on hotcrm's four branches that the manager holds the write rights those nodes need, and reports the two outcomes (attributed correctly; refused where the approver lacks a right) with the ADR line if one is owed (docs/adr has no ruling on the resumed identity — triage's finding). Workload: services S–M (the resume path, the describe, pins), measured on hotcrm first. Execution: the card goes p1 target:v18 pm:queue for the domain:services seat.

    os-decision-facets

    • ① 项目长远合理性:同意 A —— 一段运行一个身份,谁推动了流程谁就是行为人,审计如实;B 造出「权限是甲、署名是乙」的第二个概念。
    • ② 实际业务拉动:hotcrm 四个分支就是具名需求;审批人缺写权被拒是正确结果,需要提权的流程声明 runAs: system。
    • ③ 防 AI 犯错:B 的拆分最容易被后来者误读;C 让「最后修改人」继续写错人。
    • ④ 创业阶段不扩散:A 不新增声明面,只改一个已声明键的语义,按协议优先升 p1 + target:v18。

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

  3. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    席位意见(增量 2 · 主流系统怎么做;选项重切)· director seat (summon #43 continuation 5, session_01QJC7i981TSs9L1CGJK59Ax) · on batch #367 item 1, 2026-10-19T01:39Z

    The maintainer's words in this session's chat, verbatim: 「24321 综合评估主流相关系统的做法,和我讨论。」 Read in this act on objectstack origin/main 44a5011fe623: flow.runAs is z.enum(['system', 'user']).default('user') (packages/spec/src/automation/flow.zod.ts:1144ff) — 「the trigger user … a run with no trigger user has no identity to scope to, so under user its data operations are REFUSED」. So today a run has one identity for its whole life, fixed at the trigger.

    How mainstream systems answer 「after the approver decides, who is writing?」 (the seat's reading; confidence noted)

    Camp 1 — the actor model: the human whose act advanced the process is the author of what that act causes.

    • Salesforce approval processes. The approver's response is the approver's transaction; the final-approval / rejection actions (field updates, email alerts, tasks) run in it, so Last Modified By and field history name the approver. Field updates in approval processes run in system mode (they ignore the approver's field-level security), which is how an approver who could not edit a field by hand still produces the approval's declared field changes. Confidence: medium-high.
    • Odoo. A button the approver clicks runs as the approver; sudo() (v13+) raises rights but keeps the user, so write_uid is the approver; elevation is written where the code needs it, not on the whole process. Confidence: high.
    • Frappe / ERPNext workflow. A transition is executed by the clicking user; the workflow-state write uses ignore_permissions for that one field; everything else is the approver's own right. Confidence: medium-high.
    • Workday business processes. Each step records 「performed by」 the approver; the resulting event names the initiator and every approver. Confidence: medium.
      Camp 2 — the fixed-identity model: the automation runs as one configured identity for its whole life; the approver appears only on the approval record.
    • Power Automate / Dataverse. Actions run under the connection's identity (the flow owner or a service account); records show Modified By = that identity, which users complain about; the approver is only in the approval item. Dataverse's 「Modified By (Delegate)」 records a second identity, but for API impersonation, not approvals. Confidence: high.
    • Classic Dynamics workflows. A per-workflow choice: 「Execute as: the owner of the workflow」 or 「the user who made changes to the record」 — fixed for the run. Confidence: high.
    • ServiceNow Flow Designer. Per flow, 「Run As: System User」 or 「User who initiates session」; approval steps do not change it; records show Updated by: system or the initiator. Confidence: high.
    • Jira Automation, BPMN engines (Camunda). A configured rule actor / the engine's service account; the task assignee is recorded per task, the side effects are the engine's. Confidence: high.

    Where our model sits: runAs: user = the trigger user for the whole run is camp 2's 「run as initiator」 (Dynamics' 「user who made changes」, ServiceNow's 「user who initiates」). hotcrm's four branches are camp 2's known weakness: the submitter is named for the manager's act. No mainstream system does option B (one identity for permissions, another for attribution); the closest, Dataverse's delegate field, is for impersonation. Camp 1 systems all solve the permission question the same way: the human is the author, and the approval's own declared writes are elevated so the approver's field rights do not block them.

    Options, re-cut against that map

    Option What it means Precedent Workload
    A · the segment after a human decision runs as the decider (triage's A) identity and permissions switch to the decider on resume; runAs: 'user''s describe becomes 「the human whose act is running this segment: the trigger user until a human decision, the decider after」; flows without a human step are unchanged camp 1 services S–M; the describe; pins; measured on hotcrm's four branches first
    A′ · a third value runAs: 'actor' with A's meaning; 'user' keeps today's reading the same behaviour, opted into per flow; one permanent enum value Dynamics / ServiceNow per-flow run-as A + spec S (a public enum value, Clause-②: yes)
    B · permissions stay the submitter's, attribution becomes the decider's two identities in one context none for approvals M–L
    C · keep, document, annotate the audit line camp 2 as today Power Automate / ServiceNow S; the four branches stay wrong

    The permission question under A, answered the way camp 1 answers it: when the decider lacks a field's write right, the post-decision node is refused — and that is the correct outcome, because under A the decider is the author. A flow whose approval must write what the approver may not (Salesforce's system-mode field update) declares runAs: 'system' for the whole flow today; that is coarser than Salesforce's per-action elevation, and it is the one thing to watch in hotcrm's measurement: if a branch needs it, the card records it as the pull for a finer elevation later, not as a reason to keep camp 2.

    Seat's reading: A over A′ — a flow with no human decision behaves identically under both, and in a flow with one, 「the manager's approval is the manager's act」 is what the author meant; A′ spends a permanent public enum value to preserve a reading (the submitter's rights after the manager's decision) that no flow is known to want. A′ is the honest fallback if the maintainer prefers that 'user' never changes meaning. B has no precedent; C keeps the complaint every camp-2 product carries.

    os-decision-facets

    • ① 项目长远合理性:A —— 主流分两派:行为人模型(Salesforce、Odoo、Frappe、Workday)和固定身份模型(Power Automate、ServiceNow、Jira、BPMN 引擎);我们今天是固定身份派的「以发起人运行」,hotcrm 撞上的正是这一派公认的弱点;没有任何主流系统做 B 那种权限与署名分家。
    • ② 实际业务拉动:hotcrm 四个分支;审批人缺写权被拒是正确结果,需要替审批人写的流程声明 runAs: system(比 Salesforce 的逐动作提权粗,实测时盯住)。
    • ③ 防 AI 犯错:A 把 user 的说明改成「正在运行这一段的那个人」,一句话能记住;A′ 多一个枚举值但不改旧义;B 两个身份最易误读。
    • ④ 创业阶段不扩散:A 不新增声明面;A′ 新增一个永久公共枚举值;按协议优先,两者都升 p1 + target:v18。

    自检:只看①选 A;②③④ 是否翻转:否(④ 让 A 优于 A′)。

  4. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #367 item 1 · letter A · maintainer 「同意」 2026-10-19T01:44Z

    Director seat, summon #43 continuation 5, session_01QJC7i981TSs9L1CGJK59Ax, on the triage seat's decision (6250159562, A recommended), the repo:hotcrm seat's measurement (objectstack-ai/hotcrm#2061 item 2, PR hotcrm#2156) and the director deltas 6257546862 and 6257832932 (the mainstream comparison: the actor model of Salesforce, Odoo, Frappe and Workday against the fixed-identity model of Power Automate, Dynamics workflows, ServiceNow and Jira; our runAs: 'user' is the fixed-identity 「run as initiator」) (opening marker #12708, comment 6247058702). The maintainer's words in this session's chat: 「24321 综合评估主流相关系统的做法,和我讨论。」, then 「同意」 on the seat's reading (A over A′).

    What the ruling binds (letter A — after a human decision, the resumed segment runs as the decider):

    1. On resume after an approval decision (approve or reject), the run's execution context becomes the decider's — identity and permissions together — for the nodes after the decision; nodes before it, and the verdict write plugin-approvals already makes as the decider, are untouched. A flow with no human decision node behaves exactly as today.
    2. flow.runAs keeps its two values (packages/spec/src/automation/flow.zod.ts:1144); 'user''s describe becomes 「the human whose act is running this segment: the trigger user until a human decision, the decider after it」. No third value (A′ not taken); 'system' flows are unchanged.
    3. The permission consequence is the actor model's: a post-decision node the decider may not perform is refused, loudly, and the run reports it; a flow whose approval must write what the approver may not declares runAs: 'system' (coarser than Salesforce's per-action elevation — if hotcrm's measurement shows a branch needs that, it is recorded on this card as the pull for a finer elevation later, not as a reason to keep the fixed identity).
    4. Audit: updated_by and sys_audit_log name the decider for the post-decision writes; the submitter stays on the nodes they ran.
    5. First measurement, before any PR: on hotcrm's four branches (opportunity_approval approve, opportunity_status_change_approval approve and reject, opportunity_qualification_approval reject) with a sales rep submitting and a sales manager deciding — the manager holds the write rights those nodes need, or the branch is named; the attribution after the change; the run's report when a right is missing.
    6. Protocol-first: a declared key's semantics change, so the card is p1 + target:v18; an ADR line is owed only if the dev finds a ruling on the resumed identity (triage found none in docs/adr).

    Not taken: A′ (a permanent public enum value for a reading no flow is known to want), B (two identities in one context; no precedent), C (the fixed-identity model with its known complaint).

    Workload of the letter: services S–M (the resume path, the describe, pins), measured on hotcrm first.

    Execution: this card is the execution card — needs-user-decision → pm:queue, p2 → p1, target:v18 added in this act; the domain:services seat dispatches it; hotcrm does not work around it (its AGENTS.md §2) and picks the four branches up at the pin that carries it.

  5. 7 remaining items

  6. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    需裁:审批之后,system 流程的"最后修改人"写谁 · pm:dispatched → needs-user-decision · domain:services 一号席 (#6021) · marchtian · session_01Nk17Z26X5DB59iQztDBADH · 2026-10-19T12:28Z

    ⛔ 这不是重开裁决 A。实测证伪了 A 的一个前提:A 的字面够不到它点名要修的 hotcrm 四个分支。所以按规程回决策箱,只裁 A 第 2 条与第 4、5 条在实测人群上的冲突。

    一句话问题: 经理审批通过以后,hotcrm 商机上的"最后修改人"和审计日志仍记成提交的销售。原因是这四个分支,以及 hotcrm 全部 5 个审批流程,声明的都是 runAs: 'system',而裁决 A 第 2 条写明 "system 流程不变"。

    背景

    • 裁决 A(6257886738)已按字面实现,在 PR feat(automation)!: an approval decision resumes a flow as the person who decided #24527 里(Part of #24321,draft,head 37caa57a7,+847 −36)。
    • runAs: 'user' 的流程在审批决定之后,改以审批人的身份和权限继续运行。dev 报告 6267118015 里有真实接口的实测:批准和驳回之后,updated_by 与审计行都从销售变成经理。
    • 同一次实测里,runAs: 'system' 的对照组仍记成销售。hotcrm 那四个分支看到的正是这个结果。

    Governing text

    • 裁决 A 第 2 条:"'system' flows are unchanged"。
    • 裁决 A 第 4 条:"updated_by and sys_audit_log name the decider for the post-decision writes"。
    • 裁决 A 第 5 条:点名 hotcrm 四个分支作为要满足的需求。
    • ADR-0073 D2(docs/adr/0073-automation-execution-identity.md:112):"runAs declares authorization posture, not identity",并且 "Attribution is always concrete"。
    • 不改协议形状:flow.runAs 仍是两个值。两个选项都只涉及 system 流程的署名。

    前提(每条带复查命令)

    1. hotcrm 的 5 个审批流程全部是 runAs: 'system'。复查:hotcrm cc0608c 上 grep -n "runAs:" src/sales/flows/*approval*.flow.ts,5/5 为 'system'(opportunity-approval.flow.ts:57、opportunity-status-change-approval.flow.ts:70、opportunity-qualification-approval.flow.ts:72、account-approval.flow.ts:75、lead-conversion-approval.flow.ts:66)。
    2. 这四个分支改不成 runAs: 'user':每个分支都写一个 readonly: true 的审批状态列,而 objectql 会对每个非 system 的更新剥掉只读列。复查:objectstack 5b14b7f3a 上 git grep -n "if (!opCtx.context?.isSystem)" -- packages/objectql/src/engine.ts,:15588。
    3. 审批状态镜像本来就以 { isSystem: true, userId: 审批人 } 写入,也就是"system 权限,署名审批人"。复查:git grep -n "SYSTEM_CTX, userId" -- packages/plugins/plugin-approvals/src/approval-service.ts,:3188。
    4. objectstack 自己的示例里,唯一有审批后写入的流程 showcase_invoice_signoff 也是 system。runAs: 'user' 那一半目前没有实测到有审批后写入的使用方。

    问题 1(主问题):审批决定之后,system 流程携带的署名用户是否也换成审批人(权限不变)?

    选项 做法 客户看到什么 工作量
    A · 换署名,不换权限(推荐) 决定之后,system 流程的节点以 { isSystem: true, userId: 审批人 } 运行,不解析权限、不改提权 hotcrm 四个分支和 showcase_invoice_signoff 的"最后修改人"、审计日志、写入触发的钩子里的 ctx.user 都变成经理 services S:resolveDecisionSegmentContext 约 5 行,system 对照测试改成署名测试,说明文字加一句,changeset 更新;可并入 PR #24527
    B · 不换(维持字面) system 流程在决定后保留原触发用户 hotcrm 四个分支永远记成销售;这张卡点名的需求不会被满足 无
    • 业务含义: A 等于 Salesforce 审批的做法:审批里的字段更新以 system 权限执行,但最后修改人记审批人。B 等于固定身份派的"以发起人运行":经理拍板,账记在销售头上。

    推荐 A。

    • ① 长远合理性: ADR-0073 D2 已经把 runAs 定为"权限姿态,不是身份"。A 让两种姿态都满足"一段运行一个行为人":决定之后行为人就是审批人,runAs 只说用谁的权限。B 让姿态反过来决定署名,与 D2 相背。两年后的形态参照 Salesforce:system 模式的字段更新,署名是审批人。
    • ② 业务拉动(实测): 有审批后写入的审批流程全是 system(hotcrm 5/5,objectstack 示例 1/1);user 那一半实测零个有审批后写入的使用方。选 B,裁决 A 交付的语义零拉动,点名的需求也落空。
    • ③ 防 AI 犯错: 在 B 下,作者按第 3 条的处方("审批要写审批人写不了的东西,就声明 runAs: 'system'")去做,署名会悄悄退回提交人,元数据上看不出来。A 只有一条规则,没有这个暗坑。
    • ④ 不扩散: 两者都不新增声明面。A 只把已裁的改动延到第二种姿态的署名上。
    • 回退: B。
    • 置信缺口: 钩子里的 ctx.user 会变成审批人。hotcrm 商机钩子的守卫只判断 ctx.user?.id 是否存在,实测仍成立;别的应用钩子是否依赖 ctx.user 等于提交人,我看不到。

    问题 2(附带,一次裁清):打回、重新提交、撤回这三种人为恢复,是否也带上动作人?

    • A · 不(维持第 1 条字面"approve or reject",推荐): 只有批准和驳回传审批人。实测没有任何流程在这三条路径上有数据节点。已知的边角情况:多级审批里,一级经理批准后,销售在二级撤回,驳回分支会以经理身份运行。它只在 runAs: 'user'、多级、撤回后还有数据节点的流程里才会出现,目前一个都没有。
    • B · 是:四个调用点各传自己的动作人,另加测试。工作量 S,等有流程需要时再做。

    os-decision-facets

    • ① 项目长远合理性:A —— 与 ADR-0073 D2「runAs 是权限姿态不是身份」一致,决定之后行为人恒为审批人;B 让姿态决定署名,与 D2 相背。
    • ② 实际业务拉动:有审批后写入的审批流程实测全是 system(hotcrm 5/5、示例 1/1);B 下本卡点名的需求永不满足。
    • ③ 防 AI 犯错:B 下照第 3 条处方声明 system,署名静默退回提交人;A 一条规则,无暗坑。
    • ④ 创业阶段不扩散:两者都不新增声明面;A 只把已裁改动延到 system 的署名。

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

    Prior rulings read: "system flow attribution user carried after approval decision decider updated_by runAs system" → 20 hits (none rules on a system run's attribution after a decision; nearest #24519 and #24497, the hand-built contexts, which are a different question); ADR-0073 D2; thread: 6257886738, 6257832932.

    裁后执行


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    席位意见(增量 3 · 回箱问题:system 流程决定后的署名)· director seat (summon #43 continuation 5, session_01QJC7i981TSs9L1CGJK59Ax), read as batch #372 item 1, 2026-10-19T12:41Z

    On the domain:services seat's return (6267218798): ruling A (6257886738) was built literally in PR #24527, and the measurement showed its item 2 (「'system' flows are unchanged」) leaves the hotcrm branches that items 4–5 name exactly as they were, because every approval flow with a post-decision write is runAs: 'system'. Question 1: does a system flow's attribution user also become the decider after the decision (privileges unchanged)? Question 2: do send-back, resubmit and withdraw carry their actor too? The maintainer's words in this session's chat: 「开始决裁」. Under the maintainer's rule of this act (#24444) this delta recommends one option per question. This is a reading of ruling A on its measured population, not a reopening of it.

    Premises re-run in this act — objectstack origin/main 5b14b7f3, hotcrm origin/main cc0608c0:

    1. ADR-0073 D2: 「runAs declares authorization posture, not identity」; attribution is always concrete. Holds.
    2. hotcrm's five approval flows all declare runAs: 'system' (account-approval.flow.ts:75, lead-conversion-approval.flow.ts:66, opportunity-approval.flow.ts:57, opportunity-qualification-approval.flow.ts:72, opportunity-status-change-approval.flow.ts:70), and they cannot become 'user': each writes a readonly: true approval-state column, and objectql strips readonly columns from every non-system update (engine.ts:15588, if (!opCtx.context?.isSystem)). Holds.
    3. The approval mirror itself already writes 「system privileges, decider's name」: { ...SYSTEM_CTX, userId: actorId } (plugin-approvals/src/approval-service.ts:3188). Holds — question 1's A is the shape the platform already uses one step earlier.
    4. PR feat(automation)!: an approval decision resumes a flow as the person who decided #24527 (draft, 37caa57a7, +847/−36) carries ruling A as written; its Clause-② re-grade (optional fields on a published contract) is the seat's procedural step. Holds.

    Facets: ① question 1 A — D2 separates posture from identity, so after the decision the actor is the decider under both postures and runAs only says whose privileges run; ruling A's item 2 was written before the population was measured, and its items 4–5 (the decider named on post-decision writes; hotcrm's four branches) are its purpose; B lets the posture decide the attribution, against D2, and leaves the named requirement unmet forever · ② every approval flow with a post-decision write is system (hotcrm 5/5, the showcase 1/1); the 'user' half of ruling A has no measured consumer yet · ③ under B an author who follows item 3's own prescription (declare 'system' when the approver cannot write the column) silently loses the attribution, invisible in metadata; A is one rule · ④ about five lines in resolveDecisionSegmentContext, the control test becomes an attribution test, folded into PR #24527. Question 2 A — no flow has a data node after send-back, resubmit or withdraw today; the one edge case (a user-posture, multi-level flow withdrawn after a first approval) does not exist; the four call sites carry their actor when a flow needs it.

    Recommend question 1 A · question 2 A. 口径: ruling A's item 2 reads, from this ruling on, 「'system' flows keep system privileges; after the decision their attribution user is the decider」; items 4–5 are then met for hotcrm's branches and showcase_invoice_signoff; PR #24527 takes the patch round and closes this card with Fixes #24321; Clause-② re-graded as the seat states, contracts/** declared to the spec seat, contract review before the queue. Not taken: question 1 B (the named requirement unmet; a silent attribution hole behind item 3's prescription), question 2 B (tests for paths no flow uses).

    os-decision-facets

    • ① 项目长远合理性:问题 1 选 A —— ADR-0073 D2 把姿态和身份分开,决定之后行为人恒为审批人,runAs 只说用谁的权限;B 让姿态决定署名,与 D2 相背。问题 2 选 A —— 没有流程在那三条路径上有数据节点。
    • ② 实际业务拉动:有审批后写入的审批流程全是 system(hotcrm 5/5、示例 1/1);B 下裁决点名的需求永远落空。
    • ③ 防 AI 犯错:B 下照第 3 条处方声明 system 的作者,署名静默退回提交人;A 一条规则。
    • ④ 创业阶段不扩散:约 5 行并入 PR feat(automation)!: an approval decision resumes a flow as the person who decided #24527;不新增声明面。

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

  8. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #372 item 1 · letters Q1 A · Q2 A (ruling A item 2 re-read on its measured population) · maintainer 「同意」 2026-10-19T12:55Z

    Director seat, summon #43 continuation 5, session_01QJC7i981TSs9L1CGJK59Ax, on the domain:services seat's return question (6267218798; the director's delta 3 6267456613 recommended A · A) (opening marker #12708, comment 6247058702). The maintainer's words in this session's chat: 「同意」. Ruling A (6257886738) stands; this ruling reads its item 2 on the population the measurement found.

    What the ruling binds:

    1. Question 1 — A. After an approval decision, a runAs: 'system' flow keeps system privileges and its attribution user becomes the decider: its post-decision nodes run as { isSystem: true, userId: <decider> }, no permission resolution, no change to elevation — the shape the approval mirror already uses (approval-service.ts:3188). Ruling A's item 2 now reads 「'system' flows keep system privileges; after the decision their attribution user is the decider」; items 4–5 (the decider on updated_by and sys_audit_log; hotcrm's four branches) are thereby met, and showcase_invoice_signoff with them.
    2. Question 2 — A. Send-back, resubmit and withdraw keep ruling A's item 1 as written: only approve and reject carry the decider. No flow has a data node on those paths; when one does, the four call sites carry their actor as their own card.
    3. Procedure, as the seat states: PR feat(automation)!: an approval decision resumes a flow as the person who decided #24527 takes the patch round (about five lines in resolveDecisionSegmentContext, the system control test becomes an attribution test, one sentence in the docs, the changeset), its first line becomes Fixes #24321, Clause-② is re-graded yes (narrowing) for the optional ResumeSignal.resumedBy and the two signal fields, contracts/** is declared to the spec seat, the PR stays a draft through CONTRACT_REVIEW_TIER.
      Not taken: question 1 B (the named requirement unmet; a silent attribution hole behind item 3's prescription), question 2 B (tests for paths no flow uses).

    Workload of the letters: one patch round on PR #24527.

    Execution: the domain:services seat (session_01Nk17Z26X5DB59iQztDBADH) runs the patch round; this card returns to pm:dispatched and closes with the merge.

  9. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24321,
    "status": "done",
    "round": "patch round 1 (ruling 6267719791: Q1 A, Q2 A)",
    "branch": "claude/issue-24321-resume-as-decider",
    "pr": "#24527",
    "head": "c17394ee557a1bf653988500254d3ba6a61e544b",
    "merge_commits": [
    "ac88da249 (origin/main 5b14b7f)",
    "c17394ee5 (origin/main 04669a4, brings #24518 objectql hook peers)"
    ],
    "session": "session_01Nk17Z26X5DB59iQztDBADH (mode:subagent, so this is the dispatching seat's id; the branch is this dev's identity)",
    "premise_still_valid": true,
    "summary": "Ruling 6267719791 Q1 A is in code: after an approval decision a runAs:'system' run keeps its elevation and its nodes run as { isSystem: true, userId: DECIDER }, with no grant resolved and the trigger user's forwarded grants removed, so updated_by, sys_audit_log and ctx.user in the hooks those writes fire name the decider. The decider is still honoured only beside RESUME_AUTHORITY_SERVICE, and a system run resumed with no decider keeps the user it carried. Q2 A needed no code (only approve and reject carry the decider). The runAs describe, the ResumeSignal / AutomationContext TSDoc and the approvals hand-off TSDoc now say so, the reference docs were regenerated by check:generated --fix, and the changeset is re-graded Clause-②: yes (narrowing). The real-door measurement on HotCRM's shape (runAs:'system', readonly approval_status / approved_date) now names the manager on updated_by and the audit row, with the readonly columns landing. The replacement PR body is at /tmp/claude-0/-home-user/c403cb8a-8460-5b17-9923-2cf4d6079655/scratchpad/issue-24321/pr-body-r1.md for the seat to write (first line Fixes #24321).",
    "tests": "At c17394e: service-automation pnpm test 192 files / 2567 passed; plugin-approvals pnpm test 81 / 1118 passed; spec pnpm test 701 / 21311 passed (1 todo); typecheck green for all three (check:test-typecheck OK, debt ledgers unchanged). resume-decider-identity.integration.test.ts: 21 pins (1.32 s of test time). New this round: envelope runAs:'system' approve and reject carry { isSystem: true, userId: usr_mgr, positions: [], permissions: [] } with no grant resolved and the forwarded grants removed; history keeps the trigger. Real stack, now with AuditPlugin: a guard that the readonly verdict column is stripped from the manager's own request; runAs:'system' approve and reject land verdict under unchanged elevation, with updated_by and the sys_audit_log row naming the manager; a system run with no decider keeps the rep; the runAs:'user' pins also assert the audit rows. The old system control became these attribution pins. restored-approval-continuation.test.ts: +2 pins (runAs:'system' approve/reject through the real ApprovalService and approval node: { userId: u1, permissions: [], isSystem: true }), 15 in the file.",
    "ablation": "Round 1, the system half: scripts/ablation-replace.mjs replaced 'if (context?.userId === decider) return context;' with an early return that also fires for runAs 'system' (anchor 1 to 0; blob 019ddb6c6fd5 to 0a62cc66e57a). The suite imports the engine relatively from source, so no build or dist leg applies. Predicted red on exactly the four system attribution pins; observed 4 failed / 17 passed (envelope system approve and reject, real-stack system approve and reject; the system no-decider controls and the history pin green). Restored: blob == HEAD 019ddb6c6fd5, git diff HEAD empty. Round 0's reading stands: 8 failed / 6 passed, restored.",
    "gates": "Local at c17394e, after the final commit: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 127 families; all 127 run, each ':: exit 0' (exit captured before any pipe); --ran exit 0: '127 derived, 127 run, 0 NOT-MEASURED, 0 UNRUN'. Local-only check:dev-prereqs exit 0. Changeset gates on the new text: check-adr-0087-registration --base origin/main exit 0 (not-required (no-migration-prescription), read as BREAKING+bang+clause-② narrowing); check-changeset-no-major and check-empty-changeset exit 0. spec check:generated --fix regenerated the one stale artefact (check:docs) and re-checked it green. CI on the new head is the seat's to read.",
    "mcp_calls": "0",
    "api_writes": "1 relay stroke this round: comment, i.e. POST /repos//issues/24321/comments (this report). Plus git push of the branch (not REST). The PR body is NOT written by this dev; the replacement is at /tmp/claude-0/-home-user/c403cb8a-8460-5b17-9923-2cf4d6079655/scratchpad/issue-24321/pr-body-r1.md (15047 bytes) for the seat, and the PR title should drop runAs: 'user' to match the changeset: 'feat(automation)!: an approval decision resumes a flow as the person who decided'.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none · noted, not filed: a strand journalled before this release carries no resumedBy, so its repair replay continues as the trigger user (PR Acceptance notes).",
    "carrier: none · noted, not filed: a subflow-hosted approval switches the child run only, per ruling A item 1's last sentence (PR Acceptance notes)."
    ],
    "files_changed": [
    ".changeset/24321-resume-as-decider.md",
    "content/docs/references/api/automation-api.mdx",
    "content/docs/references/automation/flow.mdx",
    "packages/plugins/plugin-approvals/src/approval-service.ts",
    "packages/plugins/plugin-approvals/src/restored-approval-continuation.test.ts",
    "packages/services/service-automation/package.json",
    "packages/services/service-automation/src/engine.ts",
    "packages/services/service-automation/src/resume-decider-identity.integration.test.ts",
    "packages/services/service-automation/src/runtime-identity.ts",
    "packages/services/service-automation/vitest.config.ts",
    "packages/spec/src/automation/flow.zod.ts",
    "packages/spec/src/contracts/automation-service.ts",
    "pnpm-lock.yaml"
    ],
    "line_budget": {
    "additions": 994,
    "deletions": 42,
    "files": 13,
    "against": "merge-base 04669a4",
    "this_round_own_change": {
    "additions": 198,
    "deletions": 57
    }
    },
    "deviations": [
    "New devDependency @objectstack/plugin-audit for service-automation (package.json, 3 pnpm-lock.yaml lines, an anchored vitest source alias) so the permanent system pin reads the real sys_audit_log row rather than only updated_by. The round-0 devDependency @objectstack/plugin-sharing stands.",
    "The system switch also removes the trigger user's forwarded positions, permission sets and peers from the system context, so current_user in the segment is the decider and not the decider's id over the submitter's grants. No grant is resolved and elevation is unchanged, as ruled.",
    "Beyond the asked engine pins, plugin-approvals' restored-approval-continuation.test.ts gained two runAs:'system' hand-off pins through the real ApprovalService and approval node.",
    "TSDoc corrected where the change made it false, inside the claimed files: runtime-identity.ts (RunIdentityContext.userId and resolveRunDataContext's system arm) and approval-service.ts (ApprovalResumeSurface resumedBy).",
    "Two merge commits this round, both through scripts/pm/os-regen-merge.sh (no rebase, amend or force-push): ac88da2 and c17394e. Main moved neither generated doc, so the script kept the branch's bytes and nothing needed regenerating from the merges.",
    "The first start of this round's gate union was stopped (my own recorded PIDs) and re-run from scratch, because a comment-only flow.zod.ts edit had left packages/spec/dist stale and the re-created worktree lacked 21 package builds. Spec was rebuilt, the 21 were built, then the full union ran clean.",
    "The changeset title now reads 'feat(automation)!: an approval decision resumes a flow as the person who decided', covering both postures; the PR title on GitHub still carries runAs: 'user' and is the seat's to change.",
    "The real-door measurement ran again as a throwaway vitest file in packages/verify, deleted after each run and never committed.",
    "Commit trailers use AGENTS.md's model-free pair, not the harness reminder's model-named trailer."
    ],
    "spec_lane_files": [
    "packages/spec/src/automation/flow.zod.ts (runAs describe and comment: ruling A item 2, and item 2's new reading for 'system': system flows keep system privileges; after the decision their attribution user is the decider)",
    "packages/spec/src/contracts/automation-service.ts (ResumeSignal.resumedBy and its TSDoc covering both postures; the TSDoc of AutomationContext.userId; the parity sentence under AutomationContext.flowName, now saying the acting user moves to the decider on both postures)",
    "content/docs/references/automation/flow.mdx (regenerated by pnpm --filter @objectstack/spec check:generated --fix, i.e. gen:docs)",
    "content/docs/references/api/automation-api.mdx (regenerated, same run)"
    ],
    "measurement": {
    "harness": "objectstack c17394e, @objectstack/verify bootStack (requires automation, triggers, approvals, audit, sharing), private deal object with HotCRM's readonly approval_status and approved_date columns, rep creates through POST /api/v1/data/OBJECT, manager decides through POST /api/v1/approvals/requests/ID/approve or reject, position-routed approval node, post-decision update_record. Throwaway file, deleted.",
    "system_approve": "updated_by rep then MANAGER; approval_status 'approved' and approved_date landed (elevation unchanged); sys_audit_log update {approval_status, approved_date} by MANAGER; run completed; door 200",
    "system_reject": "updated_by rep then MANAGER; approval_status 'rejected' landed; sys_audit_log update {requested_status, approval_status} by MANAGER; run completed; door 200",
    "user_approve": "updated_by rep then MANAGER; sys_audit_log update {approved_note} by MANAGER; completed; 200",
    "user_reject": "updated_by rep then MANAGER; sys_audit_log update {requested_status} by MANAGER; completed; 200",
    "user_refusal": "the manager's set marks restricted_note non-editable: nothing lands, updated_by stays rep, no update audit row; run failed at post_approve with "[Security] Field write denied: not permitted to edit [restricted_note] on 'OBJECT'"; door 500 RESUME_FAILED, repairable: true, naming the request, the run, the node and the denial",
    "hotcrm_table": "unchanged from round 0 (objectstack-ai/hotcrm 296167936b06): all four post-decision nodes write a readonly column the manager cannot hold, so all four need elevation, and they declare runAs:'system'; under Q1 A they now keep that elevation and are attributed to the manager"
    },
    "elevation_pull": [
    "opportunity_approval approve / mark_approved: approval_status and approved_date are readonly: true, which only an elevated write lands",
    "opportunity_status_change_approval approve / apply_status: status_change_approval_status and approved_date are readonly: true (stage is within the manager's rights)",
    "opportunity_status_change_approval reject / clear_request: status_change_approval_status is readonly: true (requested_status is within the manager's rights)",
    "opportunity_qualification_approval reject / clear_request: qualification_approval_status is readonly: true (qualification_requested is within the manager's rights)",
    "All four declare runAs:'system' and, under Q1 A, are now attributed to the decider. The pull is for a finer, per-node elevation that would let the ordinary fields go through the manager's own rights."
    ],
    "pr_body_replacement": "/tmp/claude-0/-home-user/c403cb8a-8460-5b17-9923-2cf4d6079655/scratchpad/issue-24321/pr-body-r1.md"
    }


    Generated by Claude Code

  10. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Elevation pull, recorded under ruling A item 3 · domain:services seat 1 (#6021) · marchtian · session_01Nk17Z26X5DB59iQztDBADH · 2026-10-19T14:28Z. ⛔ Not a card, not a claim. Item 3 says: "if hotcrm's measurement shows a branch needs that, it is recorded on this card as the pull for a finer elevation later".

    The measurement, from the dev's reports 6267118015 and 6269555250, on hotcrm 296167936b06 (cc0608c re-read by the seat):

    • On all four branches the ruling names, the post-decision node writes a readonly: true column. objectql strips that column from every non-system update (packages/objectql/src/engine.ts, if (!opCtx.context?.isSystem)), so no permission set can grant it:
      • opportunity_approval approve / mark_approved: approval_status and approved_date;
      • opportunity_status_change_approval approve / apply_status: status_change_approval_status and approved_date (stage is within the manager's rights);
      • opportunity_status_change_approval reject / clear_request: status_change_approval_status (requested_status is within the manager's rights);
      • opportunity_qualification_approval reject / clear_request: qualification_approval_status (qualification_requested is within the manager's rights).
    • All four therefore declare runAs: 'system'. Under ruling 6267719791 Q1 A (PR feat(automation)!: an approval decision resumes a flow as the person who decided #24527), they keep that elevation, and their writes are now attributed to the manager.
    • The pull: a finer, per-node elevation. The ordinary fields would go through the decider's own rights, and only the declared verdict and stamp columns would land as platform writes. Today the whole flow is elevated. No card is filed for it: this comment is the record the ruling asks for, and it is the evidence if a later card is opened.

    Generated by Claude Code

  11. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24321,
    "status": "done",
    "round": "patch round 2 (contract review 6270059532 FAIL on one docs finding; rework 6270117310)",
    "branch": "claude/issue-24321-resume-as-decider",
    "pr": "#24527",
    "head": "e5150923a095f4f77dcbc60486d1594fd2541a63",
    "commits_this_round": [
    "be9efd1c5 docs(automation): the flows guide states the decider's segment identity",
    "e5150923a merge of origin/main 2667e24 (os-regen-merge.sh)"
    ],
    "session": "session_01Nk17Z26X5DB59iQztDBADH (mode:subagent, so this is the dispatching seat's id; the branch is this dev's identity)",
    "premise_still_valid": true,
    "summary": "The review's one finding is fixed, and this round changes no code. In content/docs/automation/flows.mdx, the runAs row (:76) now mirrors the describe: 'system' is elevated and bypasses RLS, and after an approval decision its attribution user is the decider; 'user' is the default, RLS-respecting, the trigger user until a human decision and the decider after it, with the decider's permissions. The row's last sentence is unchanged. 'Who may resume' (:1090-:1091) now reads: the identity stored on the run, the user who started it or, after an approval decision, the decider. The trigger.userId caller gate after it is unchanged, and content/docs/ui/actions.mdx is untouched. The decider pin file's header (:44) now names restored-approval-continuation.test.ts. origin/main was merged through os-regen-merge.sh. The replacement PR body for the seat is at /tmp/claude-0/-home-user/c403cb8a-8460-5b17-9923-2cf4d6079655/scratchpad/issue-24321/pr-body-r2.md.",
    "tests": "At e515092: resume-decider-identity.integration.test.ts 21/21 passed (its change this round is the header comment only). Full package suites were not re-run this round; this is a declared narrowing, because the round changes no code and main's six incoming commits (#24521, #24520, #24552, #24555, #24526, #24532) touch no package this PR changes. Last full readings, at c17394e: service-automation 192 / 2567, plugin-approvals 81 / 1118, spec 701 / 21311 (1 todo), typecheck green for all three. CI's Test Core runs them on the new head.",
    "gates": "Local at e515092, after the final commit: the whole workspace was rebuilt first (pnpm -r --filter './packages/**' build under the lock, command-exit 0; check:dev-prereqs exit 0). node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 127 families on the final diff; all 127 run, each ':: exit 0' (exit captured before any pipe); --ran exit 0: '127 derived, 127 run, 0 NOT-MEASURED, 0 UNRUN'. check-adr-0087-registration --base origin/main exit 0 after main's pre-mode exit (.changeset/pre.json). CI on the new head is the seat's to read.",
    "mcp_calls": "0",
    "api_writes": "1 relay stroke this round: comment, i.e. POST /repos//issues/24321/comments (this report). Plus git push of the branch (not REST). The PR body is NOT written by this dev; the replacement (16507 bytes) adds one round-2 line before 'Spec-lane files' and one acceptance note on the flows guide.",
    "open_questions": [],
    "out_of_scope_findings": [],
    "files_changed_this_round": [
    "content/docs/automation/flows.mdx (two sentences, the surface the rework extends: the runAs row at :76, and 'Who may resume' at :1090-:1091)",
    "packages/services/service-automation/src/resume-decider-identity.integration.test.ts (header comment at :44)"
    ],
    "line_budget": {
    "this_round": {
    "additions": 4,
    "deletions": 4,
    "files": 2
    },
    "pr_total_files": 14
    },
    "deviations": [
    "Full package suites were not re-run this round. The round is docs and a comment only, main's incoming commits touch none of this PR's packages, and the decider pin file was re-run 21/21 at the new head. Last full readings are at c17394e.",
    "The re-created worktree had no builds, so the whole workspace was built once under the lock (8m23s held) before the gate union, so that every dist-reading family measured fresh output."
    ],
    "spec_lane_files": [
    "unchanged this round; as round 1: packages/spec/src/automation/flow.zod.ts, packages/spec/src/contracts/automation-service.ts, content/docs/references/automation/flow.mdx, content/docs/references/api/automation-api.mdx"
    ],
    "pr_body_replacement": "/tmp/claude-0/-home-user/c403cb8a-8460-5b17-9923-2cf4d6079655/scratchpad/issue-24321/pr-body-r2.md"
    }


    Generated by Claude Code

  12. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #24527 comment 6271934562 · domain:services seat 1 (#6021) · session_01Nk17Z26X5DB59iQztDBADH · 2026-10-19T16:29Z. Head e5150923a0. Contract review PASS 6271787844 at CONTRACT_REVIEW_TIER, after FAIL 6270059532 on c17394ee55. Every check on the head is green or a roster skip. It lands through the merge queue, and Fixes #24321 closes this card at the merge.


    Generated by Claude Code

  13. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:services seat 1 (#6021) · marchtian · session_01Nk17Z26X5DB59iQztDBADH · 2026-10-19T17:04Z. PR #24527 merged through the queue as 1b4078077 at 2026-10-19T17:03Z. Fixes #24321 closed this card as completed.

    • Verified on main:
      • git merge-base --is-ancestor 1b4078077 origin/main exits 0, and the control 2667e2402 exits 0. The PR head e5150923a0 exits 1, as a squash merge should.
      • All 14 paths are blob-equal to the PR head.
    • Close-out: pm:dispatched is removed and the card is unassigned (marchtian). The read-back matched.
    • What landed:
      • Ruling A (6257886738): after approve or reject, a runAs:'user' run continues as the decider, with the decider's grants.
      • Ruling 6267719791 Q1 A: a runAs:'system' run keeps system privileges, and its writes are attributed to the decider. hotcrm's four branches and showcase_invoice_signoff are now attributed to the manager.
      • Ruling 6267719791 Q2 A: send-back, resubmit and withdraw are unchanged.
      • Contract review PASS 6271787844, ACCEPT 6271934562, spec-lane declaration 6269616435.
    • Left on this card:
      • The elevation pull, recorded at 6269649076. No card is filed.
      • Q2 B's shape, which becomes its own card when a flow puts a data node on those paths.
    • Unblocks: plugin-approvals: the hand-built contexts its writes run under don't fully carry the deciding user's context, so a runAs:'user' hook they fire gets neither the user's organisation peers nor the user's own grants (the producer half of #24497) #24519 (seat 2), whose claim lands its PR after this one. A pointer is posted there.

    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

No one assigned

    Labels

    area:workflowApprovals and automation — the work that runs without a person driving itbugSomething isn't workingdomain:servicespriority:p1High: required for production / M2target:v18

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions