feat: cloud 门禁/超时/成本/沙箱收敛为单一判定源

- 新增标准库叶子层 timeouts/gates/quota/sandbox_policy:
  审批 3600 与单轮 600 各有名常量与环境覆盖层,已建项
  expires_at 永不重算;目录/控制/合并状态门禁统一判定,
  目录违规无任何覆盖参数;配额取数与比较唯一来源
  (USD 先于无价、命中均为 >=、无价只计 actual 行);
  /tmp 隔离矩阵与失联清理判定纯函数化。
- 调用点委托:server/worker/automations/auto_memory 的
  配额 SQL 与比较、server/tree/marker 的目录解析、
  marker 的控制门、sandbox 的任务容器名正则、两处 300 秒
  陈旧阈值默认值均收敛,别名与错误文案不变。
- 统一两个 P0 口径分歧:服务端无价计数由全部 usd IS NULL
  行改为 actual-only;显式不限额用户在服务端准入亦不受
  无价上限约束(与 worker 运行时一致)。
- 不新增门禁种类与 record 模式(主线无此实现);不改
  skill_seed/skills/SKILL.md;不改 v1.1 契约与分支保护。
- 新增 test_arch_converge.py 18 项。
This commit is contained in:
host committed 2026-11-04 20:54:50 +00:00
1 parent 17fa493da7
commit facc2a249a
16 files changed
+1070 -301

No files matched your search

+23 -54
View File
@@ -125,7 +125,8 @@ docs/marker-tools.md 新增的两节。
同创建人-only 的目标一律拒绝,并把原因写进报告——绝不
在查不到权限时静默放宽。
本模块只依赖标准库,不 import cloud 其它模块,避免循环
本模块只依赖标准库与同为标准库叶子的 cloud.gates /
cloud.timeouts,不 import 其他 cloud 模块,避免循环
import。DB 助手函数只用 ? 占位符,与 peer_messages 同款写法。
"""
@@ -137,6 +138,13 @@ import uuid
from datetime import datetime, timedelta, timezone
from typing import Any
from cloud.gates import RETRYABLE_STATUSES as _GATE_RETRYABLE
from cloud.gates import TERMINAL_STATUSES as _GATE_TERMINAL
from cloud.gates import decide_control as _gate_decide_control
from cloud.gates import is_goal_task as _gate_is_goal_task
from cloud.gates import resolve_inside as _gate_resolve_inside
from cloud.timeouts import LONG_TIMEOUT_SECONDS as _LONG_TIMEOUT
# ZoneInfo 在极老 Python 上不存在:先声明为 Any 再 try import,
# 这样 except 分支的 None 赋值不再是“给 type 赋值”(mypy
# misc + assignment),运行时仍是“有则类、无则 None”,
@@ -164,12 +172,13 @@ MAX_SPAWN_DEPTH = 3
MAX_DIRECT_CHILDREN = 20
DEFAULT_POLL_INTERVAL_SECONDS = 5
DEFAULT_POLL_TIMEOUT_SECONDS = 300
MAX_POLL_TIMEOUT_SECONDS = 3600
# 轮询上限与状态集收敛到 cloud/gates.py / cloud/timeouts.py
#(别名保留,调用点与测试 import 的名字不变)。
MAX_POLL_TIMEOUT_SECONDS = _LONG_TIMEOUT
DEFAULT_SNAPSHOT_CHARS = 2000
MAX_SNAPSHOT_CHARS = 8000
TERMINAL_STATUSES = ("completed", "failed", "interrupted", "merged",
"merge-failed")
RETRYABLE_STATUSES = ("failed", "interrupted", "merge-failed")
TERMINAL_STATUSES = _GATE_TERMINAL
RETRYABLE_STATUSES = _GATE_RETRYABLE
EFFORTS = ("low", "medium", "high", "xhigh", "max")
EXECUTORS = ("local", "docker", "cloud")
TODO_STATUSES = ("pending", "in_progress", "blocked", "completed",
@@ -619,21 +628,10 @@ def extract_task_files(text):
def safe_worktree_path(worktree, rel):
"""worktree 内相对路径的安全解析:与服务端
_safe_worktree_path 同款——绝对路径、.. 逃逸、符号链接
逃逸一律返回 None;空串返回 worktree 本身。"""
if not rel:
return worktree
if os.path.isabs(rel):
return None
base = os.path.realpath(worktree)
target = os.path.realpath(os.path.join(base, rel))
try:
if os.path.commonpath([base, target]) != base:
return None
except ValueError:
return None
return target
"""worktree 内相对路径的安全解析:判定收敛到 cloud/gates.py
(与服务端 _safe_worktree_path 同款;绝对路径、.. 逃逸、
符号链接逃逸一律返回 None;空串返回 worktree 本身)。"""
return _gate_resolve_inside(worktree, rel)
_SPAWN_SUBJECT_ZH = ("新建的任务", "派生任务", "新建任务",
@@ -1123,45 +1121,16 @@ def ancestry_relation(conn, sender, target):
def is_goal_task(task):
"""goal 任务判定:verify_command 非空或 goal_mode 为真。
与 worker run_one 的 goal 分支同款(verify_command 或
goal_mode);goal 字段本身是 goal_mode=1 时 prompt 的副本,
不单独当判定条件,避免把普通任务的 goal 文本误判。"""
if not task:
return False
return bool(task.get("verify_command") or task.get("goal_mode"))
"""goal 任务判定:薄壳,判定在 cloud/gates.py。"""
return _gate_is_goal_task(task)
def check_control_gate(target, sender, relation, kind):
"""task-cancel / task-retry 的纯函数门禁,返回 (ok, reason)。
kind 只能是 "cancel" 或 "retry",其它值一律拒绝。权限层
不在这里:worker 侧另查 create_task / approve_merge,见
模块头;本函数只管目标状态与关系,单测不需要 AuthStore。"""
if kind not in ("cancel", "retry"):
return False, "未知的控制操作"
if target is None:
return False, "目标任务不存在"
if (target.get("project_id") is not None
and sender.get("project_id") is not None
and target.get("project_id") != sender.get("project_id")):
return False, "跨项目任务不可操作"
if target.get("id") == sender.get("id"):
return False, "不能操作自己"
if is_goal_task(target):
return False, "goal 任务不可取消或重试(goal 循环自有轮次)"
status = target.get("status")
if kind == "cancel":
if status in TERMINAL_STATUSES:
return False, "目标已终态(%s),不可取消" % status
else:
if status not in RETRYABLE_STATUSES:
return False, ("仅 failed / interrupted / merge-failed"
" 可重试,当前状态为 %s" % status)
if relation not in ("descendant", "same_creator"):
return False, "目标不在发送方派生链上且创建人不同"
return True, ""
薄壳:判定在 cloud/gates.py(权限层仍在 worker 侧,
本函数只管目标状态与关系,单测不需要 AuthStore)。"""
return _gate_decide_control(target, sender, relation, kind)
def _heartbeat_age_text(snapshot, now=None):