You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
flow-runas-unscoped's "the default runAs:'user'" wording is unreachable on the CLI surface — the parse materializes the default, so an author who declared nothing is told they declared it #5693
Found while implementing #5633. Filed unassigned, observation-class (no pm:queue): nothing is blocked and the remedy in the hint is correct either way — the defect is that a deliberate distinction in the diagnostic is dead on the surface that matters.
What
packages/lint/src/lint-flow-patterns.ts branches the message on whether runAs was authored or defaulted:
The rule is wired input: 'parsed' (authoring-rules.ts), and the flow schema supplies 'user' as runAs's default — so by the time the rule runs on the CLI, flow.runAs is the string 'user' whether the author wrote it or not. The 'the default …' arm is therefore never taken on os validate / os build / os lint.
Measured
A real example flow (examples/app-todo/src/flows/task.flow.ts, overdue_escalation) with its runAs line deleted entirely — the author declared nothing — through os validate:
x Author-time rules failed (1 issue)
- flow 'overdue_escalation' - runAs: schedule-triggered flow runs as `runAs:'user'`, but a
schedule run has no trigger user - so its data node 'update_priority' (update_record), in
loop 'loop_overdue' body, has no identity to scope to and will be REFUSED at run time.
rule: flow-runas-unscoped
runs asrunAs:'user' — the explicit arm, for a flow with no runAs key. The unit tests take the other arm (the default runAs:'user') only because they pass raw, unparsed stack literals straight to lintFlowPatterns, so the test suite proves the branch works while no shipped surface can reach it.
Why it is worth recording rather than shrugging at
It reads as an accusation the author can disprove by looking at their file. Someone who wrote no runAs is told their flow "runs as runAs:'user'", which invites the reading "I never wrote that — the tool is confused", exactly when the tool is right and the fix is one line away. The author-vs-default distinction is real and useful (it separates "you wrote something incoherent" from "you inherited a default that does not fit a user-less trigger"), and it is currently invisible where it would help.
It is also a small instance of a shape this repo has paid for before: a branch that is exercised only by tests whose input shape differs from production's. Cf. #4984 (fixtures spelling rejected aliases kept tests green while the rule was dead) — same mechanism, much lower stakes.
Possible directions (a maintainer's call — not proposed here)
Read the authored value. Have the rule consult the pre-parse stack for runAs presence, so the distinction survives. Costs a second input to a rule that is otherwise cleanly parsed.
Drop the distinction. Delete the dead arm and always print runAs:'user', keeping the message honest about what it can actually know. Cheapest; loses a genuinely useful nuance.
Re-word so it is true either way — e.g. "runs under runAs:'user' (the default when none is declared)" — one sentence, no new input, no dead branch.
(3) looks like the best value for the size of the problem, but this is a diagnostic-wording contract and the person who wrote the distinction may have wanted (1).
Pre-existing: #5633 only widened where this rule looks for its evidence node and left the declared branch untouched. The behaviour above reproduces identically on origin/main at 414395b9a. Confirmed with real os validate output in both directions.
范围裁定:默认修向为方向 (3)(把措辞改成两向皆真的一句,如 "runs under runAs:'user' (the default when none is declared)")—— 一行、无新输入、无死支;同批把「production 形状(parsed 输入)下 explicit 支为唯一可达支」的事实用测试钉住,不再让死支只被 raw literal 喂绿(死支按 (3) 一并删除或收编)。⛔ 方向 (1)(rule 增读 pre-parse stack)改规则输入面,若认领 dev 认为 (1) 才对,升级决策箱而不是径直做。
flow-runas-unscoped 的 authored-vs-defaulted 三元删除,换 RUNAS_EFFECTIVE_IDENTITY 常量:「runs under runAs:'user' (the default when none is declared)」—— 两读皆真,沿用仓内同机制先例 flow-draft-status-ambiguous 的措辞形状,无需升级决策。
Activity
os-zhuang commentedon Aug 6, 2026
发现分诊:持有(
finding保留,补domain:devx)。packages/lint/src/lint-flow-patterns.ts,input: 'parsed'+ schema 物化默认值使the default runAs:'user'分支在全部 shipped 面(os validate/os build/os lint)不可达,正文有实测输出;单测只因喂的是未 parse 的裸字面量才走到该分支 —— validateOrgAxisRedLines 读的 sharing-rule 键是 spec 拒收的:ADR-0105 D6 ① 在 criteria 路径上从不触发 #4984 同机制、低一档。flow-runas-unscoped(severity error) still searches only top-level nodes — a scheduled flow whose data ops all live in aloopbody passes the build and is refused at run time #5633 在飞面上(该单正在改同一规则的取证逻辑),同文件跨轮串行;重启条件 =flow-runas-unscoped(severity error) still searches only top-level nodes — a scheduled flow whose data ops all live in aloopbody passes the build and is refused at run time #5633 落地(合入 main)后晋级pm:queue。本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
os-zhuang commentedon Aug 6, 2026
发现分诊(finding 轮):晋级 —— 摘
finding,入pm:queue(域domain:devx已在)。flow-runas-unscoped(severity error) still searches only top-level nodes — a scheduled flow whose data ops all live in aloopbody passes the build and is refused at run time #5633 落地;PR fix(lint):flow-runas-unscoped跨区域搜索它的数据节点证据 (#5633) #5695 已合入 main(HEADeb26126),按预记晋级。runAs:'user'(the default when none is declared)")—— 一行、无新输入、无死支;同批把「production 形状(parsed输入)下 explicit 支为唯一可达支」的事实用测试钉住,不再让死支只被 raw literal 喂绿(死支按 (3) 一并删除或收编)。⛔ 方向 (1)(rule 增读 pre-parse stack)改规则输入面,若认领 dev 认为 (1) 才对,升级决策箱而不是径直做。itemVar, a keyLoopConfigSchemarejects — the nested-region tests describe aloopno author can write #5700(同轮晋级)同文件家族(rule 源lint-flow-patterns.ts+ 同一测试文件),由 devx 车道跨轮串行,不挂 Blocked-by。本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
hotlong commentedon Aug 6, 2026
认领:PM 循环第 3 轮(devx 车道)
会话:
session_01BDmDsu2575gDxeMCxXhDE3分支:
claude/issue-5693-runas-wording-two-way-trueWorktree:
objectstack-issue-5693域:
domain:devx文件面:
packages/lint/src/lint-flow-patterns.ts及其测试文件(越界即停,报告说明)按分诊预裁方向 (3):措辞改为两读皆真 + 死支删除/收编 + 用 parsed 形状测试钉住「explicit 支为唯一可达支」;⛔ 方向 (1)(增读 pre-parse)若 dev 判定才是对的,STOP 升级不径做。⚠️ 与 #5700 同文件家族,#5700 本轮不派、跨轮串行。
Generated by Claude Code
hotlong commentedon Aug 6, 2026
验收(devx 车道,会话
session_01BDmDsu2575gDxeMCxXhDE3):ACCEPT → PR #6060,已转 ready 并挂 auto-merge(required 集绿即自动入队;ESLint 属平台级不可运行态 —— main 自身同 job 同窗口起不来的对照证明在案 —— 真绿前不会落地,闸门自恰)。交付摘要(裁方向 3):
flow-runas-unscoped的 authored-vs-defaulted 三元删除,换RUNAS_EFFECTIVE_IDENTITY常量:「runs underrunAs:'user'(the default when none is declared)」—— 两读皆真,沿用仓内同机制先例flow-draft-status-ambiguous的措辞形状,无需升级决策。os lint不 Zod-parse 却仍拿到 parsed stack(defineStack定义时已 parse)—— explicit 支在三条命令上都是唯一可达支;而 default 支在 runtime publish gate(逐字原文 body)可达 —— 缺陷实为「两个 shipped 面对同一 flow 说两句话」。四路输出(2 输入 × 2 命令)改后逐字收敛,实测留档。flow-runas-unscoped(severity error) still searches only top-level nodes — a scheduled flow whose data ops all live in aloopbody passes the build and is refused at run time #5633 未发布 changeset 的旧句样例(同发布窗口防 release notes 自相矛盾,最小 rider 有理)。defineStackparses at definition time, so the authoring registry'snormalized(pre-parse) tier may never actually be pre-parse for a TS config — the tier's whole reason for existing #6073(defineStack 定义时 parse 使 normalized tier 可能名不副实 —— 机制已测、推论待测、步骤已列;finding 持有)。Three pre-existing flow-lint fixtures bind the loop item withitemVar, a keyLoopConfigSchemarejects — the nested-region tests describe aloopno author can write #5700 按令未触碰。Generated by Claude Code