Repository navigation
Description
domain:server#2 · os-tesla · session_01L9qibzuTqmB5hqFYmMATiY
立卡门:② 只有维护者能做的决定 + ③ 维护者直派。维护者原话(2026-11-07,项目线程):「立一张 cloud 车道的决策卡」。前一问原话:「read_file 这个服务端转换需要消耗很多算力吗?比如我们是共享云」。
- 业务理由:共享云上所有租户共用同一批服务进程。MCP cannot read or attach files: no tool downloads an attachment (e.g. a policy PDF to analyse) and none attaches one (e.g. a photographed invoice) to a record #30892 / PR feat(mcp): read_file and create_upload_link read and attach a record's files #31009 让 AI 助手通过 MCP
read_file读记录上的 PDF,文字抽取在服务进程里同步完成;抽取期间同一进程的其他请求全部等待。不定上限,一个租户的助手连续读大 PDF 就会拖慢其他租户的页面和 API。 - 动手的读者:cloud PM 席(
repo:cloud,[PM seat] repo:cloud · seat 2 — 🟢 os-zhuang #24145)按裁定定共享云的取值;平台代码由 server 席位 2 执行(feat(mcp): read_file and create_upload_link read and attach a record's files #31009 合并前写进该 PR,或紧随其后一张 server 卡)。 - 查重(含已关):
read_file PDF is:issue→ 1(MCP cannot read or attach files: no tool downloads an attachment (e.g. a policy PDF to analyse) and none attaches one (e.g. a photographed invoice) to a record #30892 本卡源);pdf extraction concurrency is:issue→ 8,均为 QA 轮报与已关附件卡,无同题;MCP rate limit tenant is:issue→ 117,无同题;label:domain:cloud label:needs-user-decision is:issue→ 0。
维护者速读
- 要裁什么:共享云上
read_file的 PDF 抽取怎么限量,以及这件事在 feat(mcp): read_file and create_upload_link read and attach a record's files #31009 合并前做还是合并后做。 - 推荐 B:平台给每次抽取定一个 CPU 时间预算和全进程并发上限(取值由宿主配置,cloud 定自己的值),第二期把抽取移出请求线程。第一期写进 feat(mcp): read_file and create_upload_link read and attach a record's files #31009 合并前。
- 不裁的话:照现状合并,
read_file上线后没有任何限量,靠事后观测。
背景
read_file(packages/mcp/src/file-content.ts,PR #31009 head da6a24cb)的上限今天全是单次上限:文件超过 10 MiB 不读;PDF 最多 200 页或 10 万字;Word 解压后最多 32 MiB;图片原样转交、不转换。没有并发上限、没有时间预算、没有按租户限流。
实测(本机 4 核,unpdf 1.9.1,与 extractPdfText 同参数,每例 3 次取稳定值):
| 文件 | 大小 | 读到 | CPU | 期间事件循环被占住 |
|---|---|---|---|---|
| 200 页、每页少量文字 | 0.14 MiB | 200 页 / 8.7 万字 | 约 80 ms | 全程(约 75 ms) |
| 200 页、大量绘图指令 + 少量文字 | 9.25 MiB | 200 页 / 2.9 万字 | 约 320 ms | 全程(约 300 ms) |
| 200 页、密排文字 | 0.64 MiB | 35 页即到 10 万字上限 | 约 65 ms | 全程(约 50 ms) |
「全程」的读法:抽取期间一个 1 ms 的定时器一次都没能触发,即同一进程的其他请求在这段时间里全部排队。单次不重,但它是串行独占的:同一进程同时来 10 个大 PDF,就是 3 秒左右谁都动不了。
a security item is with the maintainer.
Governing text
docs/adr/0102-sandbox-cpu-budget-and-engine-variant.mdD1:租户提供的脚本按每次调用的 CPU 时间预算计费,墙钟只作单独的上限。这是平台对「租户提供的输入在共享进程里跑」的既有口径。- 检索
grep -rlniE "event loop|worker_threads|concurrency (cap|limit)|noisy neighbo" docs/adr content/docs→ 只命中 ADR-0102;文件抽取没有专门条文。
协议声明:Metadata-protocol: none。四个选项都不改 spec、不改 /meta。
前提(带复核命令)
- 抽取没有并发上限和时间预算:
grep -cE "concurren|semaphore|timeout|AbortSignal|deadline" packages/mcp/src/file-content.ts→ 0(headda6a24cb)。 - 抽取在请求线程上同步占住事件循环:上表最后一列。复测:照
extractPdfText的参数调unpdf.getDocumentProxy+ 逐页getTextContent,同时挂一个 1 mssetInterval计触发次数。 - 仓内没有 worker 线程池先例:
grep -rln "worker_threads\|new Worker(" packages --include=*.ts | grep -v test→ 1 个无关文件。
具体问题
共享云上,一个租户的助手读文件,会不会、以及允许多大程度上,拖慢别的租户?
选项
| 选项 | 做什么 | 客户能感到的后果 | 工作量 |
|---|---|---|---|
| A | 平台加两道闸:每次抽取的 CPU 时间预算(到时停,返回已读部分 + "其余请下载")和全进程并发上限(满了答"稍后再试")。取值由宿主环境变量配置 | 普通文件无感;极端文件只拿到部分文字;高峰时偶尔要重试。别的租户不再被长时间卡住,但每次抽取仍会占住进程几百毫秒 | server · 1 PR(可并入 #31009)· 无同形先例 |
| B | A 的两道闸 + 第二期把抽取移到独立 worker 线程池,请求线程不再被占 | 同 A,且读文件完全不拖慢同进程的其他请求 | server · 2 PR(第一期同 A,第二期 worker 池)· 无先例 |
| C | 平台不动,cloud 控制面按租户限 read_file 次数或计量 |
限住"量",限不住"单次多重";同一进程里的别人仍会被卡 | cloud · 1 PR · 无先例 |
| D | 维持现状,上线后看监控再定 | 出事之前无感,出事时是全进程变慢,客户看到的是"系统卡" | 无 |
业务含义直译:
- A:给每台复印机装一个"单次最多印多久"的计时器,加一个排队号。
- B:A 加上把复印机搬出前台,排队的人不再挡住柜台。
- C:每家公司每天限印几次,但一家印一本厚书时柜台照样被堵。
- D:先不管,等有人投诉再说。
四棱
- ① 项目长远合理性:两年后该能力的样子是:文件抽取跑在请求线程之外、每次有 CPU 预算、取值由宿主配置,和 ADR-0102 的沙箱同一口径。主流平台(Salesforce 的 Apex governor limits、Cloudflare Workers 的每请求 CPU 上限)都是"平台定机制、按次计 CPU"。B 收敛到这一个口径;A 是 B 的一半;C 把平台该有的机制挪到应用仓,扩大特例;D 不收敛。
- ② 实际业务拉动:今天没人撞上(
read_file未上线)。但共享云是默认部署形态,上线即每个开了 MCP 的租户都能触发,拉动来自上线本身。 - ③ 防 AI 犯错:AI 助手会照用户的话连读多份文件,不会自己节流。A/B 出错时是响亮的("稍后再试"或"只读了一部分,请下载");D 出错时是静默的(别的租户变慢,没人知道原因)。
- ④ 创业阶段不扩散:A/B 各新增 1–2 个宿主环境变量,是永久义务;C 新增一套 cloud 配额模型,义务更大;D 零新增。
Prior rulings read: read_file PDF / pdf extraction concurrency / MCP rate limit tenant / domain:cloud+needs-user-decision → 1 / 8 / 117 / 0 hits; ADR-0102 D1; thread: 项目线程(本卡来源)
推荐
B,分两期:第一期(时间预算 + 并发上限)写进 #31009,合并前落地,这样 read_file 从上线第一天就有闸;第二期 worker 线程池另立 server 卡,在第一期之后。
- 不取 A:它解决"卡多久",不解决"卡住"本身;作为 B 的第一期已全部包含。
- 不取 C:应用仓不自建平台该有的机制;按租户计量可以以后在 B 之上加,不替代它。
- 不取 D:出事时的症状是全进程变慢,排查成本远高于现在加两道闸。
置信缺口:第二期 worker 池的工作量无先例,我的估计是 1 个 PR;实测只在本机 4 核做了,生产机型的数字会不同,但"全程占住事件循环"这一点与机型无关。
自检行:只看①选 B;②③④ 是否翻转:否(②只影响时序,已体现在分期;④的新增环境变量 A 与 B 相同)。
Analysis-tier: seat (Opus), not the ceiling tier.
裁后执行
- 裁 B 或 A:server 席位 2 在 feat(mcp): read_file and create_upload_link read and attach a record's files #31009 上加第一期(每次抽取的 CPU 预算 + 全进程并发上限,两个宿主环境变量,默认值写进
content/docs/ai/connect-mcp.mdx),带消融测试;cloud PM 席在 cloud 部署配置里定共享云的取值。裁 B 时 server 席位 2 同笔另立第二期 worker 池卡,Blocked-by:feat(mcp): read_file and create_upload_link read and attach a record's files #31009。 - 裁 C:feat(mcp): read_file and create_upload_link read and attach a record's files #31009 照现状合并;cloud PM 席在 cloud 仓立配额卡。
- 裁 D:feat(mcp): read_file and create_upload_link read and attach a record's files #31009 照现状合并,本卡关闭为 not_planned。
相关
- MCP cannot read or attach files: no tool downloads an attachment (e.g. a policy PDF to analyse) and none attaches one (e.g. a photographed invoice) to a record #30892(卡源)· PR feat(mcp): read_file and create_upload_link read and attach a record's files #31009(
read_file/create_upload_link,待经 os-zhuang 批准)· ADR-0102 · cloud PM 席 [PM seat] repo:cloud · seat 2 — 🟢 os-zhuang #24145
Activity
objectstack-fleet commentedon Nov 7, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: grade · p1 ·
domain:cloud· 2026-11-07T07:54Z⛔ Not a claim.
read_file's PDF extraction is bounded on the shared cloud, and whether the first bound lands before PR feat(mcp): read_file and create_upload_link read and attach a record's files #31009 (MCP cannot read or attach files: no tool downloads an attachment (e.g. a policy PDF to analyse) and none attaches one (e.g. a photographed invoice) to a record #30892, p1) merges.domain:cloud, as the maintainer named it; the platform code stays with the server seat.needs-user-decisionstays. Triage adds no recommendation; the card's options and the 维护者速读 are the seat's.Generated by Claude Code
objectstack-fleet commentedon Nov 7, 2026
domain:server#2 · os-tesla · session_01L9qibyvxbrLP4jm4PargoH
Status · 2026-11-07T08:28Z · PR #31009 merged 2026-11-07T08:08Z as
704efef8; the maintainer enqueued it before this card was ruled. Soread_file's PDF extraction is onmainwithout a CPU budget or a concurrency cap. Option B's phase 1 can no longer ride #31009. If B (or any bound) is chosen, it needs its owndomain:serverPR againstmain. The server seat 2 lane is signing off, so that PR goes to the online server seat (seat 1, mailbox #31077).objectstack-fleet commentedon Nov 7, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Ruling: batch #T962 item 2 · letter B · maintainer 「同意」 2026-11-07T14:47Z
Path: none
Presented in the triage seat's session as batch 1 item 2. The maintainer answered 「同意」 to B, in two phases. PR #31009 had already merged (08:08Z), so phase 1 now follows it instead of landing inside it.
What binds:
Execution:
domain:serverfiles phase 1 as its own card now. Its defaults are documented incontent/docs/ai/connect-mcp.mdx, with ablation tests.Blocked-by:phase 1.Generated by Claude Code