L11 · 维护者视角
学习指南 / 实战课程 / 第 11 课
Lesson 11 · 模块 D · 维护

维护者视角:
上游如何运转。

毕业不是终点,换个座位再坐一次。这一次你坐在维护者的位置上,回答四个上游运转问题: 远程客户端怎么调到 Host 服务、一个仓库为什么要两份 TypeScript 世界、持久日志怎么安全升级、 版本怎么发出去;再把 benchmarks、llm-retry、token-meter 三个仪表盘 和 Agent Notes 的正规读法一并补齐。

精读 20 分钟 练习 10 分钟 · 6 题 前置 L6 · L10
学完你将能够
  • 讲清 Remote API 的四层分层、@Remote/@RemoteScope 编程模型,以及「活对象不穿线」的 lookup 设计
  • 说出仓库必须拆成 Host/Client 双 aggregate 的原因,以及三条不可破的纪律
  • 按 cookbook 走通加一条 Session 格式迁移的完整动作:迁移包 manifest、catalog 门、release/* 集成分支、验证命令
  • 描述三条互不等待的发布线与「本地 bump → 人工 tag → CI 彩排 → 人工发布」的节奏
  • 会用 benchmarks 预算门、llm-retry 策略、token-meter 投影回答性能与成本问题
  • 按 lifecycle/class 路径查 Agent Notes,讲清 Alternatives considered 为什么是强制的
01 · Remote API & api-gateway

Remote API:给远程客户端开的点菜窗口

前十课里你的插件都跑在本地 Host 进程内。维护者要回答的下一个问题是: Web UI、SDK、ACP 这些远程客户端,怎么调用 Host 里的业务服务? 答案是 Remote API——注意这个词在上游专指 Typert Remote 的 unary 调用, 一请求一结果;流式会话数据不在其列(本节末尾细说)。

编程模型一句话:Host 服务继承 TypertRemoteService,用 @Remote('方法名')@RemoteScope(key) 自己挑选暴露面。 没标装饰器的方法不进生成物、经 ctx.remote 根本调不到—— 不是运行时权限拦截,而是构建期生成器根本看不见它们。 Typert 生成器读 Host 源码,为每个标了 @Remote 的方法生成两端的严格契约: Host 面的调用描述符,和 Client 面的类型化调用桩。

客户端 · ctx.remote.notes.list() api-remotes 挂载 Typert 生成契约 严格描述符 + JSON 参数 connection · RPC 传输层 packages/client/connection POST /api/notes/list gateway · 按 <ns>/<method> 派发 packages/api/gateway agentId → Agent 由 lookup 还原 Host 服务 · @Remote('list') 执行 继承 TypertRemoteService 只做 unary RPC id · 取消 · 信任检查 未分类异常兜底为 gateway/internal 调用侧按 result.ok 与 error.code 分支 四层各管一段,谁也不越界。
图 11-1 · 一次 ctx.remote 调用的四层旅程:remotes 出契约、connection 管传输、gateway 管派发、Host 方法执行;活对象以 id 过线、由 lookup 还原。

活对象不穿线

Agent 这样的活对象不能作为参数直接穿越 HTTP。声明 agent: Agent 参数时,Typert 把它映射成一个 agentId wire 字段, 运行时经 TypertLookupMap 注册的提供者还原成真对象; @RemoteScope 的上下文同样走 ctx.typert.contexts 还原。 agent/session 的标准解析策略(冷启动恢复、并发 resume 去重、拒绝 subagent 身份, 错误码 session/not-foundsession/agent-busy) 统一收在 api-session-controller 里,Host 方法拿到的永远是已解析好的对象。

生成管线的硬顺序

# Typert 生成器只在 Host 的 tsdown 阶段跑,以 Host aggregate 为唯一 ts.Program seed tsc -b tsconfig.host.json # ① Host 类型检查 tsdown --env.DSH_BUILD_FACE host # ② 这里生成 typert.host.js / typert.remote-client.js tsc -b tsconfig.client.json # ③ Client 类型检查(消费 ② 的产物) tsdown client && pnpm run build:web # ④ Client 打包 + Web 构建

两个产物落进各业务包的 lib/typert.host.js(Host 面运行时反射与严格描述符) 和 typert.remote-client.js(Client 面可挂载的调用桩,含 declaration merge 与 source map 回指 Host 源码)。改了签名、码表、namespace 或导出名,必须重跑 pnpm run build:lib,否则两端契约不同步。 生成器还做严格分析:@Remote 方法必须公有、非静态、非泛型,参数必须有名字, 禁解构/默认值/rest/可选参数——契约要能从源码唯一确定,就没有「猜」的余地。

错误模型:一个类,一张码表

Remote 只有一种错误:RemoteError,配一张 <domain>/<reason> 格式的码表 (由各包 declaration merging 汇总)。单包独有的码放生产者包里,多包共用的放最低公共域包; gateway/bad-requestgateway/cancelledgateway/internal 是基础设施码,不许复制仿造;未分类异常一律兜底成 gateway/internal。 调用侧按 result.okerror.code 分支,不用 instanceof 错误家族—— 一条线、一张表,比一树错误类好维护得多。

Client 侧的装配只挂 dsh-api-remotes 一个门面:它挑选本应用要暴露的 Host 能力 (Commands、credentials、settings、Goal、动态 Cordis、文件与 Session 引用、插件清单、 Session/Workspace Controller 等),经 ctx.remote.$mount() 逐个挂载并 re-export 类型词汇; 调用方插件自己声明 inject: ['remote', 'remote.<ns>']

记忆锚点 · unary 之外没有 Remote

Remote API 只做 unary(一请求一结果)。流式、增量、分页必须另立数据协议或走精确的 Connection Fetch 路由,不许伪装成 Remote 方法。面试里把「会话流」说成 Remote 方法,维护者会立刻皱眉。

02 · Host / Client Dual Aggregate

双 aggregate:一个仓库为什么要两份 TypeScript 世界

打开仓库根目录,你会看到 tsconfig.host.jsontsconfig.client.json 两份配置(docs/development.md 的 contributor reference 是权威文本)。 原因藏在 Cordis 里:Host 侧和 Client 侧都要给 cordis 的 Context 接口做 declaration merging,同名 key(比如 sessionsloader) 在两侧挂的是不同的服务。TypeScript 不允许一个 ts.Program 里出现两份同名合并—— 于是切成两个互不相见的编译世界。

精妙之处在于:这个冲突只活在 ts.Program 内部,模块解析根本不会触发它。 所以根 solution tsconfig.json 可以同时 reference 两个 aggregate (它自己是 files: [] 的空壳,也是 tsserver 的发现入口), tsc 挨个构建时各自独占一个世界,互不打架。

三条纪律

  • tsconfig.base.json 永不include/files——否则两个世界被迫看见同一批文件,冲突复活。
  • 要建仓库级 ts.Program 的脚本,必须显式 seed host 或 client aggregate,绝不 seed 根 solution。
  • 新包只登记进一个 aggregate;少数两边都要检查的,走共享 leaf 或拆分包机制(见下)。

共享 leaf 与拆分包

有三个包两侧都引用:packages/host/webserver、packages/compaction/compaction、 packages/typert/registry——两侧必须 type-check 同一份源码的共享叶子。另有六个两头都有代码的包(api/remotes、api/gateway、 api/session-controller、api/workspace-controller、client/connection、 session-query/session-log-export)各带 host/client 两份 leaf config: 包根 tsconfig 只是 solution,聚合与直接消费方必须点名 leaf—— constraints 门沿 Project Reference 图逐个检查,指错脸直接拒绝。

测试文件也要分脸:命名 *.client.* 的归 Client aggregate, *.host.spec.ts 的归 Host,两个 aggregate 互相 exclude 对方脸的文件。 一份测试属于哪个编译世界,从文件名一眼可读。

记忆锚点

判断一个文件属于哪边:它 import 的服务挂在哪个 Context 合并上,就是哪张脸。 谁也不挂的纯算法,才能进共享 leaf。

03 · Session Format Migration

Session 格式迁移:亲手加一条世代边

第 06 课讲过版本闸门与不可变世代:旧日志靠相邻迁移链升级到当前代, 已落盘的 generation 永不移动、覆盖、删除。这一节讲轮到你动手时的完整动作—— 权威手册是 docs/cookbook/adding-a-session-format-version.md, 固定范例是 packages/session/session-format-v2-to-v3/README.md

记忆锚点 · 两个权威

「writer 现在写哪个版本」的权威是代码常量 SESSION_FORMAT_VERSION (packages/core/session/src/types.ts);「哪个版本已随产品发布」的权威是 docs/session-format-status.md 的 release record。写文档引用版本号时指向这两个权威, 不要把数字抄死在自己的页面里。

先问要不要 bump

版本是单调整数,没有 major/minor。bump 判据只有一条: 旧运行时能否对新日志做全语义正确的读取。只有结构性变化 (header、envelope、核心事件语义、surface 机制)才值得 bump; 新增一种普通事件不动版本——给事件信封标 ignorable: true 即可, 默认不标就是必需事件,旧读取器遇到不认识的必需事件宁可拒绝也不静默跳过。

迁移包:一个包一条边

每个世代步由一个独立包负责:packages/session/session-format-v0-to-v1-v1-to-v2-v2-to-v3,包与版本边一一对应。 邻接关系声明在包的 package.json 里,v2→v3 的真实 manifest 长这样:

// packages/session/session-format-v2-to-v3/package.json —— 一个包恰拥有一条 vN → vN+1 边 "dsh": { "sessionFormatMigration": { "from": 2, "to": 3, "export": ".", "migration": "sessionFormatV2ToV3", "sourceCodec": "releasedV2SessionFormatCodec", // 复用前一边的 codec,不复制 "targetCodec": "releasedV3SessionFormatCodec", "targetHeaderValidator": "assertReleasedV3Header", "targetRestorer": "restoreReleasedV3Artifact" } }

迁移实现 migrateHeader / validateTargetHeader / createStage(每次调用独立状态),Stage 内用 transformEvent / transformRun / finishcontext.emitEvent / emitRun 同步发出事件—— 一进可出零或多个。继承 cut 是逻辑事件数不是物理行数,未知 cut 绝不用 0 顶替。 目录结构由 scripts/gen-session-format-catalog.ts 把关: 0 到 writer 版本之间每步必须恰有一个相邻包,缺口、重复、多余边都拒绝; generated.ts 禁止手改。

发布节奏:release/* 集成分支

N+1 的开发用一条共享的 release/* 集成基分支承载基础变更 (writer、codec、catalog 接线、identity 迁移、验证),每个独立子分支从它切出、 做一项结构变换、PR 打回 release 分支;评审合并后整体验证发布。 发布后该相邻边冻结:后续结构变化必须开新边,不得修改已发布的边; release 分支受 force-push 与删除保护。

陷阱 · release/* 不是发版分支

release/* 只服务于 Session 格式集成。npm 发版走 master + dsh-v<version> tag(下一节), 把两者混成「release/dsh-* 分支发版节奏」是本课最容易写错的一句话。

动手试 · 5 分钟

不用真加一个版本,把迁移链的验证网跑一遍(在上游仓库源码 checkout 里):

pnpm run verify-session-format-catalog

再跑快照基线——迁移改动的语义不变性全靠它兜底:

pnpm run test:snapshot scripts/session-snapshot-corpus.corpus.ts

测试未发布版本时用一次性隔离 home(N+1 中间文件已带目标版本,事后改版本不会再迁移它们),绝不重写已提交世代、绝不复用真实用户 home。

04 · Release Process

发布流程:三条版本线,CI 只彩排不发布

上游发版不是按一个按钮跑流水线,而是三条互不等待的版本线 (权威记录在 Agent Note 2026-08-10-npm-release-sequences.md): 发 dsh 不会重发 vendor,发 vendor 不会重发 native。

dsh 产品线 · 全家一个版本 非实验 packages/*/* + apps/* · tag dsh-v<version> · release.yml / release-publish.yml vendor 框架线 · 每包独立版本 vendor/ 下九个包 · tag vendor-<package>-v<version> · release-vendor*.yml native 原生线 · 独立版本 native/system · tag node-addon-system-v<version> · node-addon-system-*.yml 三条泳道互不共享版本、触发与等待;但每一条都要走完同一条五步节奏 ↓ ① 本地 bump 落仓库 ② merge 后 人工打 tag ③ 每个 PR 无凭证彩排 ④ 手动触发 npm-publish 审批 ⑤ 拓扑序 publish 上架
图 11-2 · 三条互不等待的发布线,与每一条都要走的五步:版本只在本地命令中落仓库,tag 人工打,CI 只彩排不发布。

第一步 · 版本在本地命令里落仓库

pnpm run release:dsh -- <major|minor|patch|显式版本>scripts/release/bump.ts)把发布家族、全部私有包、workspace root 写成同一版本并连 lockfile 一起提交;人 merge 之后手工打 tag。 CI 永不写仓库。预发布排序 alpha < canary < rc < stable, dist-tag 映射:alpha/canary → 同名,rc → next,stable → latest

第三步 · 无凭证彩排,每个 PR 都证明还能打包

# release.yml 在每个 PR 与 master push 上依次执行: pnpm run release:verify --family dsh # 版本基线 + 打印完整 publishOrder + 发布时校验 tag pnpm run build:official # 本地等价的 CI/发布产物构建 pnpm run release:pack --family dsh --out dist/npm # 打包,无任何凭证 pnpm run release:verify-packed-install --family dsh --from dist/npm ... # tarball 装进一次性消费者,纯 Node 跑 dsh --version

第四五步 · 人工发布与 registry 三态判断

真正的发布只在 release-publish.yml 里发生:workflow_dispatch-only、 从 dsh-v* tag 运行,先重新打包再按 publishOrder (npm 安装关系 + peer 声明的拓扑序)逐个发布,全程置于 npm-publish 环境的人工审批之后。 发布脚本对 npm registry 做三态判断:

  • registry 没有该版本 → 正常发布;
  • 有,且 tarball 的 sha512 与已记录 integrity 一致 → 跳过(这是同一次发布的重跑);
  • 有,但 integrity 不同 → 失败:内容变了却没升版本。

连「代码变了忘升版本」都会被 integrity 对比抓住。另有两道护栏: verify-application-entrypoints 强制所有受支持的 Node 应用都从 dsh CLI + named profile 启动(包 bin、可执行源码、根 demo 全部白名单分类, 绕过 dsh 的启动路径一律拒绝);FIXME 注释按约定应阻断发版。 发布成功的最后一项义务:核对 Session writer 与 release record, 发了更高格式就更新 docs/session-format-status.md 的双语记录与证据链接。

坑位提示

release 工作流必须 fetch-depth: 0——release 脚本靠读历史 tag 判断各包是否变更, 浅克隆会把 vendor 的变更判断退化成「全部重新发布」。本地验收发布链前三个命令即可, 第四步永远属于 GitHub Actions。

动手试 · 5 分钟

在上游仓库把彩排链跑起来,看维护者发布前的自检长什么样:

pnpm run release:verify --family dsh

输出里的 publishOrder 就是即将发布的完整拓扑序;有兴致再跑 pnpm run release:pack --family dsh --out dist/npm 摸一摸产物。

05 · Edge Packages

三个仪表盘:benchmarks · llm-retry · token-meter

仓库边缘有三个不直接做产品功能的包,它们是维护者回答日常问题的仪表盘: 多快(benchmarks)、挂了怎么办(llm-retry)、这次请求多挤(token-meter)。

benchmarks:仓库级性能红线

  • 被测用户路径组织——session-open、agent-continuation、conversation-fold、active-stream-reconnect、long-session-browser——不镜像包树;Host 用 *.bench.ts,Client 用 *.bench.client.tsbenchmarks/AGENTS.md)。
  • 预算是代码内评审常量,环境变量不得覆盖;输入一律合成固定数据,绝不录 Session、用户素材或网络。
  • CI 必需基准在标准 ubuntu-24.04 hosted runner 上独立跑(不受 selfhosted failover 影响),整个 job 15 分钟超时;session-open 的 open 端点预算按 50ms CI 期望 × 1.25 余量定为 63ms。
  • 维护者介入点:改了被测路径的性能相关代码;预算门变红需要实测校准(阈值变更要求实测数据 + 正负对照);换 runner 必须先跑一次真实 hosted 基准验证超时可信。

llm-retry:模型请求挂了怎么办

llm-retry 自己没有配置——重试策略长在每个 provider adapter(dsh-llm-deepseek、dsh-llm-pi-ai) 的 retryPolicy 里。不配置时是 normal 模式:针对 EMPTY_RESPONSE / RATE_LIMIT / SERVER / TIMEOUT / TRANSPORT 重试 5 次,500ms → 10s 有界指数退避加 10% jitter;always 模式无上限, 直到成功、取消或插件卸载。两条边界要背下来:只有 agent turn 是重试边界, 直接 ctx.llm.stream() 没有重试;重试对模型完全不可见 (事件、延迟、失败都不进模型上下文),而 每次重试都是又一次计费请求—— llm/retry-started 还会结束 token-meter 的 usage 替换域,让重试计入用量。

token-meter:这次请求有多挤

ctx.tokenMeter.measure(session) / estimateMessage(message) 通过重放持久日志做估算:确定性、零模型调用,compaction、占用率 UI、遥测共享同一个答案。 文本用「字符数 + 结构开销」的固定启发式(CJK 与 JSON schema 在四字符一 token 的启发式下会明显低估), 有定价声明的图像走 provider 精确视觉 token;provider 自报 usage 只在请求 envelope 完全一致时复用。 会话投影可用时它注册三个 units:tokenUsagecontextPressurecontextBreakdown,插件卸载即移除。定位要摆正:参考值,不是账单—— harness 里没有任何决策依赖它。

记忆锚点 · 三个仪表盘

benchmarks 回答「多快」,红线红了拿实测数据重新校准; llm-retry 回答「挂了怎么办」,策略在 provider 手里,费用在用户账上; token-meter 回答「多挤」,重放日志零模型调用,但它是估计不是计费。

06 · Reading Agent Notes

Agent Notes 读法:从「必须写」到「读出门道」

第 10 课讲过「每个非琐碎改动必须同 PR 带一篇 Agent Note」。 这一课补全读法与格式细节——权威手册是 .agents/notes/README.md

路径即检索

.agents/notes/{lifecycle}/{class}/yyyy-mm-dd-topic.md: lifecycle 是 proposed / implemented / rejected, class 是 feature / bug-fix / simplification / architecture / process / testing闭集scripts/agent-note-tree.ts 是权威,分类门拒绝其他文件夹)。 组织全在路径里,三个人生阶段乘六个决策领域;没有集中 INDEX.md—— 有专门的决策删掉了它,交叉引用一律用相对 markdown 链接(verify-md-links 检查)。

implemented 骨架与 Alternatives considered

  • 骨架## Problem## Decision → 自由技术节 → ## Alternatives considered## Consequences。spec-speak(## Proposal## Migration plan 等)在 implemented 里会被门拒绝。
  • Alternatives considered 强制:每个真实备选写一段「它是什么、为何落败」。动机很直白——不记下被击败者,半年后就有人把它当新点子重提。
  • proposed → implemented:把提案重写成现在时的决策陈述,验收标准与风险折进 Consequences;移动文件夹必须同一变更内更新 Status 行并满足目标骨架。
  • archived 冻结:理由不再指导未来工作的 implemented 笔记移入 archived/,只许整组移动(英/中/sidecar 三件套)、插 Archived 日期行、修入链;此后永不可编辑、不得当现状权威。
  • 中文 .zh.md 逐节镜像:header token(# Agent Note:Status: 行)保持英文,由配对门校验。

写作本身也有门:一段一物理行verify-md-wrap)、 文档里的 ts 块必须真实编译(doc-typecheck)、根文档有字数预算、 禁止叙述历史与手抄目录。docs 分层口诀一条记牢: bug → postmortem、理由 → Agent Notes、流程 → cookbook、类型 → subsystems、 包契约 → README、常驻命令 → 根 AGENTS.md——一个事实一个家。 postmortem 的触发标准是三条同时成立:机制不显然(subtle)、因测试/工具/惯例缺口而逃逸 (systemic)、重新发现代价高(costly to rediscover)。

记忆锚点 · 账本分工

Agent Note 记「为什么这样设计」,postmortem 记「流程为什么漏了这个 bug」。 读笔记时先看 Status 与路径——implemented 是现行依据,archived 只是冻结的历史。

07 · Quiz · 10 分钟

课堂练习

2 单选 + 2 多选 + 2 问答。选择即时批改,问答先写下你的答案再对照。成绩保存在本地浏览器。
单选
客户端调用 ctx.remote.notes.list() 时,请求实际经过的路径是?

正文第 01 节图 11-1:调用路径是 ctx.remote.<ns>.<method>()connection.rpc.call('/api', '<ns>/<method>', {args})POST /api/<ns>/<method>,由 Gateway 派发。Connection 管传输/RPC id/取消/信任检查, Gateway 只管 Remote 数据协议与 dispatch——各层职责不互换。

单选
Host 服务里一个没有标 @Remote 的公有方法会怎样?

正文第 01 节:暴露面由 @Remote/@RemoteScope 显式挑选, Typert 生成器构建期读源码生成两端契约——没标的方法根本不进生成物。 这不是运行时权限拦截(D),也不报错(B),更不会自动暴露(A): 白名单哲学,缺省即不可达。

多选
关于 Host/Client 双 aggregate,哪些说法正确?(选出所有正确项)

D 错:tsconfig.base.json 永不加 include/files,否则两个世界被迫看见同一批文件、冲突复活。 E 错:测试文件命名是分脸机制——*.client.* 归 Client、*.host.spec.ts 归 Host, 两个 aggregate 互相 exclude 对方脸的文件。A、B、C 分别是第 02 节的冲突根源、解法精髓与拆分包纪律。

多选
要给 Session 日志加一条新的格式版本,哪些动作符合上游纪律?(选出所有正确项)

C 错:世代不可变——已提交的 generation 永不重命名/覆盖/删除,迁移结果另存新世代。 E 错:release record 发布后凭证据追加更新,历史条目不改写;而且发布中的相邻边随即冻结, 后续结构变化必须开新边。A、B、D 分别是第 03 节的 bump 判据、迁移包纪律与 release/* 集成节奏。

问答描述一次 dsh 发版从代码合并到 npm 上线的完整流程:三条版本线怎么分工?版本号、tag、彩排、发布各在哪一步、由谁完成?写下答案后点击对照

参考要点:① 三条线互不等待——dsh(非实验 packages/*/* + apps/*,单一版本,tag dsh-v<version>)、vendor(九个包各自独立版本,tag vendor-<package>-v<version>)、native(node-addon-system);② 版本由维护者本地命令 pnpm run release:dsh -- <major|minor|patch|显式版本> 写进仓库提交,merge 后人工打 tag,CI 永不写仓库;③ release.yml 在每个 PR 与 master push 上无凭证彩排:release:verify(基线 + publishOrder + tag 校验)→ build:official → release:pack → release:verify-packed-install(tarball 装进一次性消费者跑 dsh --version);④ 真发布在 release-publish.yml:workflow_dispatch-only、从 dsh-v* tag 运行、npm-publish 环境人工审批后按拓扑序 publish;⑤ registry 三态:无该版本→发布;sha512 一致→跳过;integrity 不同→失败(代码变了没升版本)。加分项:发布后核对 Session writer 与 session-format-status.md 的 release record。

问答你决定给 Session 日志引入一个结构性格式变化(v3 → v4)。列出要动的每一处、要过的每一道门、以及发布后的义务。写下答案后点击对照

参考要点:① 先过 bump 判据:只有结构性变化才值得动 SESSION_FORMAT_VERSION;普通事件新增用 ignorable: true;② 在 release/* 集成基分支上提交基础变更(writer、codec、catalog 接线、identity 迁移、验证),独立子分支做结构变换、PR 打回 release 分支;③ 新建 packages/session/session-format-v3-to-v4 迁移包:package.json 声明 dsh.sessionFormatMigration(from/to/export/migration/sourceCodec/targetCodec/targetHeaderValidator/targetRestorer),复用 v3 codec 不复制,Stage 实现里继承 cut 用逻辑事件数、未知 cut 不用 0 顶替;④ 过 pnpm run verify-session-format-catalog(每步恰一条边、禁手改 generated.ts)+ 迁移包测试 + test:snapshot 语料基线;测试用一次性隔离 home,绝不重写已提交世代;⑤ 发布后该边冻结——后续结构变化开新边;发布操作员更新 docs/session-format-status.md 的 release record(latestReleasedVersion 与 evidenceTag),中英双语同步。

本课小结

维护者视角补齐了五块拼图:Remote API 的四层分层与显式暴露(unary 之外没有 Remote)、 双 aggregate 的冲突根源与三条纪律、Session 格式迁移的完整动作 (一个包一条边、release/* 集成、世代不可变)、三条互不等待的发布线 (版本本地落仓库、CI 只彩排、人工审批发布)、三个仪表盘 (多快 / 挂了怎么办 / 多挤),以及 Agent Notes 的路径检索法与骨架门。 到 deep-dive.html 完成 42 题终面, 你就已经从使用者一路走到了维护者的座位。