Skip to content

[Decision] Restriction profile vocabulary: which flow nodes a hosted environment can list (ADR-0031 containers, the Team approval pair), and whether allowCode splits off sandboxed lifecycle hooks #31354

Closed

Description

@objectstack-fleet

triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

Filing gate: ② a decision only the maintainer can make (a protocol vocabulary key, under cloud#3659 ruling A). It collects three forks that already wait on the maintainer:

⛔ Not a claim.

维护者速读

  • 一句话问题: 环境用「限制档案」声明自己能跑哪些流程节点、能不能跑代码,os validate --target 按它预检作者的应用。现在档案写不出托管环境的真实能力,导致在 Team 上本来能跑的东西被预检拒掉。
  • 三个缺口:
    • ① parallel / try_catch:引擎自带的容器节点,每个环境都能跑;
    • ② approval / approval_revise:只有 Team 套餐的托管引擎能跑(cloud#3497),别的环境不一定能跑;
    • ③ allowCode 只有一个开关,托管内核上已发布包里的沙箱钩子照常绑定,但 allowCode: false 把所有钩子都拒了。
  • 选项:
    • D(推荐):分开处理。
    • B: 容器和审批节点全部进入可列举词表,环境要把容器节点也写上才放行。最统一,但每个档案都得列一遍到处都能跑的东西。
    • C: 容器和审批节点全部始终放行。最省事,但审批节点在没有审批引擎的环境里也会被放行,部署后才失败。
    • ③ 的另一种答法: 把沙箱钩子算作"非代码",读取方直接豁免,不新增键。省一个键,但"沙箱里跑的东西算不算代码"就成了隐含规则,而这正是安全边界。
  • 不裁的后果: os validate --target 会继续把 Team 环境能跑的审批流程和沙箱钩子判成违规;cloud 的限制档案(cloud#3713)也无法如实发布。

Four facets

  • ① Long-term soundness: D lets each capability be declared where it varies. Engine built-ins are structural; plan-dependent nodes and a sandbox tier are listed. B over-declares invariants; C under-declares a plan-gated capability.
  • ② Business pull: now. cloud#3713 (publishing the profile) is in flight, and it is the cloud#3659 ruling A execution, 「全部立卡并p1」. Team customers' approval flows are what the profile currently refuses.
  • ③ AI-error resistance: an author or agent runs os validate --target and trusts its verdict. Under C, an approval flow passes on an environment that cannot run it, a false green. An implicit "sandboxed is not code" rule is one an agent cannot read off the schema; D's explicit key is.
  • ④ Startup-stage scope: D adds two protocol entries, the approval pair and one boolean key. Both are p1 under 「协议新增定 p1」. No new gate.

Confidence gap: whether cloud intends to gate sandboxed hooks per plan. If it never will, ③ could be the "not code" reading instead.

Prior rulings read: cloud#3659 ruling A; #26368 ruling A (protocol additions are p1); the reader rule in review 6710350208 (a type outside FlowNodeAction is governed by allowCode).

After the ruling


Generated by Claude Code

Activity

  1. added
    priority:p1High: required for production / M2
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    domain:specDomain lane — seat card indexed by label:pm:seat
    on Nov 8, 2026
  2. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2eAG5J8aqAyPZif4BJ

    Ruled · D, refined: ① C · ② B2 · ③ allowSandboxedJs · 2026-11-08T04:14Z

    Ruling, verbatim (the maintainer, in this account's project, analysis thread for this card): 2026-11-08T04:13:01Z 「同意」 — to the analysis' recommendation (project file issue-31354/decision-analysis.md, §5 recommendation, §6 execution).

    1. ADR-0031 containers parallel / try_catch → C. Structural: always allowed, their inner nodes are judged. PR fix(cli): os validate --target allows the ADR-0031 parallel / try_catch containers, and the restriction profile docblocks state the reader rules #31277 (spec: a restriction profile cannot list the ADR-0031 containers (parallel, try_catch), devPlugins counts as code under allowCode, and the allowedFlowNodeTypes docblock omits the reader rules #31239) stays as built. Owed there: drop the "pending the maintainer's pick" note and reword "outside FlowNodeAction = code plugin" to "outside the profile's vocabulary". Then it may be readied.
    2. Approval pair approval / approval_revise → B2. packages/spec exports a profile-own DERIVED vocabulary = FlowNodeAction.options ∪ the spec-declared plugin node contracts (APPROVAL_NODE_TYPE, APPROVAL_REVISE_NODE_TYPE); allowedFlowNodeTypes uses it. ⛔ Not added to FlowNodeAction (the boot seed set, which lint reads). Reader rule 2 becomes "a type the vocabulary does not name is governed by allowCode"; the CLI test asserting approval → allowCode flips; a spec test pins the derivation. The structural set and the vocabulary stay disjoint.
    3. allowCode split → a new REQUIRED boolean allowSandboxedJs (⛔ not …Hooks). It governs every L2 language: 'js' body: hooks[].body, actions[].body, jobs[].body (the reader ignores actions today; that is fixed too). allowCode keeps in-process code: handler-form hooks and jobs, functions, plugins, runtimeModule and the other code keys, the script node. L1 expression bodies: neither key. A hosted profile is allowCode: false, allowSandboxedJs: true. It must land before cloud#3732 publishes the first profile (a required key is breaking after that).
      • Recorded, not changed: loop stays in the enum and is judged by the list while parallel / try_catch pass structurally; the asymmetry is noted in the docblock only.

    Execution: #31344 carries items 2 and 3 (pm:blocked → pm:queue with this comment; spec minor changeset, Fable review of the spec diff before merge). #31239's seat is notified on its mailbox that PR #31277 may be readied after the two wording edits. cloud follow-up (cloud#3713 Team profile lists the approval pair, writes allowCode: false, allowSandboxedJs: true, waits for #31344) stays with the cloud seat.

    Closed completed, needs-user-decision removed.

  3. removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Nov 8, 2026
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

    domain:specDomain lane — seat card indexed by label:pm:seatpriority:p1High: required for production / M2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions