Skip to content

fix(sandbox): 尊重调用方超时 + cd 前缀只读命令不再武装 1200s 墙钟 - #7

Merged
tall-1997 merged 1 commit into
mainfrom
fix/shell-timeout-honored
Oct 13, 2026
Merged

tall-1997 merged 1 commit into
mainfrom
fix/shell-timeout-honored

Conversation

@tall-1997

Copy link
Copy Markdown
Owner

用户报告

修复执行 shell 命令时老是卡住 1200s,上轮就出现好几次卡住情况。

复现与根因(证据在源码 + 本会话工具日志)

本会话自己的工具日志就是现场:给命令传了 timeout=60,慢命令(大仓库 grep/find)照样跑满 1200 秒才被看门狗杀掉(exit 124)。三个叠加根因:

  1. [T-cd-readonly] cd 不在只读白名单:cd repo && grep … | head 这种最自然的命令形态,因 cd 缺席 READ_ONLY_TOKENS → 判非只读 → isHeavy → HEAVY 强制升 BATCH → 墙钟 1200s。
  2. [T-timeout-honored] 调用方超时被显式忽略:三条执行路径(ExecutionCoordinator / PersistentShell / ShellExecutor)都打着 caller timeout ignored 日志直接丢弃 timeout 参数。工具 schema 承诺 "Timeout in seconds (default: 900)",实现却完全不用。
  3. [T-quote-aware-split] 分段切分不识别引号:grep -n "a\|b" 里引号内的 | 被当管道切出幻影段,垃圾首 token 过不了白名单 → 只读管道被判重负载。

修复

  • cd/pushd/popd 补入 READ_ONLY_TOKENS 与 INTERACTIVE_TOKENS——纯导航内建命令,cd X && grep 与裸 grep 分类一致(INTERACTIVE,快速失败)。
  • 超时契约改为 min():armed = min(requested, class wall)。类墙钟仍是上限(旧的 maxOf 扩展 bug 不复活),但调用方可以把等待收短。guest 看门狗同步拿到同一生效墙钟,宿主 withTimeoutOrNull 与 guest sleep 一致触发。
  • GuestWorkloadPolicy 与 BudgetClassifier 的分段切分先抹掉引号段再切(与 hasWriteSyntax 同技法)。
  • 工具描述同步改为诚实表述:超时是上限,不能超过类墙钟。

验证

  • 37 项逻辑模拟全过(新行为 + 全部既有用例保持绿)
  • 新单测钉死:现场命令形态(INTERACTIVE、非重负载、60s 墙钟、30s 请求生效)、缩短不扩展契约、引号感知切分
  • 旧契约测试 callerTimeoutIsNotAnInput 更新为 callerTimeoutShortensButNeverExtends

行为变化说明

  • 不传 timeout 的调用(默认 600s):BATCH 类命令墙钟从 1200s 收到 600s,SERVICE 从 1800s 收到 600s——与文档默认一致
  • MCP shell_exec / DebugRPC 传的 timeout 现在真正生效(以前被丢弃)
  • git clone 等长命令不受影响(默认 600s = NORMAL 类墙钟)

…ing 1200s

Field report: shell commands 'always hang at 1200s'. Reproduced from
this session's own tool log — a grep requested with timeout=60 ran the
full 1200s and died with exit 124. Three stacked root causes:

[T-cd-readonly] 'cd' was missing from READ_ONLY_TOKENS (and from
INTERACTIVE_TOKENS), so the most natural agent command shape —
'cd repo && grep … | head' — failed the read-only check, isHeavy
escalated it to forced BATCH, and the wall clock armed at 1200s.
cd/pushd/popd are pure navigation builtins; they now classify exactly
like the pipeline without the cd prefix (INTERACTIVE, fail fast).

[T-timeout-honored] All three execution paths (ExecutionCoordinator,
PersistentShell, ShellExecutor) explicitly IGNORED the caller's
timeout — each logged 'caller timeout ignored' and armed the class
wall. The tool schema promised 'Timeout in seconds (default: 900)'
while the implementation discarded it. The class ceiling stays the
authority (the old maxOf(requested, minimum) bug must not return),
but the caller may now SHORTEN the wall:
armed = max(setup floor, min(requested, class wall)) — the floor
survives because a minis-dev-setup-full killed by a short request
leaves a broken rootfs (setupFloorSurvivesAShortRequest). The guest
watchdog gets the same effective wall so the in-guest sleep and the
host withTimeoutOrNull agree on when to fire.

[T-quote-aware-split] Segment splitting was quote-blind in both
GuestWorkloadPolicy (isObviouslyReadOnly / isDiskRelief) and
BudgetClassifier.classify: a '|' inside quotes ('grep -n "a\|b"')
cut a phantom segment whose garbage leading token failed the
whitelists — read-only pipelines classified as heavy/NORMAL. Quoted
spans are blanked before splitting, the same technique
hasWriteSyntax already used.

Verified: 43-point logic simulation (new behavior + every existing
test case kept green, including the setup floor); new unit tests pin
the reported command shape (INTERACTIVE, not heavy, 60s wall, 30s
request honored), the shorten-never-extend contract, the floor, and
the quote-aware split. findIsNormalAndACallerTimeoutDoesNotChangeIt
is updated to the new contract (find stays NORMAL; a caller may
shorten).
@tall-1997
tall-1997 force-pushed the fix/shell-timeout-honored branch from 4a38251 to 786c288 Compare October 13, 2026 11:55
@tall-1997
tall-1997 merged commit 22c8570 into main Oct 13, 2026
1 check passed
@tall-1997
tall-1997 deleted the fix/shell-timeout-honored branch October 13, 2026 12:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant