# 原生内核工作区 English: [native-kernel.md](native-kernel.md). `dsh-ops-worker` 仍然是唯一的可执行文件。每次调用都经过 DSH 的 subprocess 和权限沙箱, 重新核实权限,读取一次有大小上限的 JSON 请求,再输出一个 JSON 结果。拆分内核不会引入常驻进程。 | crate | 职责 | 内核依赖 | | --- | --- | --- | | `ops-protocol` | 请求、错误、作业记录、凭据路径和归属校验 | 无 | | `ops-files` | 禁止跟随链接的句柄、读取、CAS 发布、元数据、树操作、目录同步 | protocol | | `ops-search` | 基于受保护文件原语的 glob、grep 和替换编排 | protocol、files | | `ops-results` | 有界的代际存储、结果分页和只读作业审计访问 | protocol、files | | `ops-documents` | 有界 CSV/TSV 行、DOCX 正文段落及 PDF 文本观察 | protocol、files | | `ops-batch` | 计划、预写状态转移和保守恢复 | protocol、files、results | 根 crate 负责分派请求,仅为 batch/result 能力打开审计存储。作业归属校验与协议记录放在一起, 避免结果模块依赖批处理执行模块。Windows 和 Darwin 元数据 crate 仍是独立 FFI 边界;内核 crate 禁止 unsafe Rust。替换操作保留观察锁直到发布完成;批处理在产生文件系统副作用前持久化 unknown 状态。只读文件调用不会创建审计存储。 使用 `cargo test --workspace --locked --manifest-path native/Cargo.toml`,确保迁入各 crate 的 测试全部执行。`npm run build:ptc` 的 worker 输出路径保持不变。发布包包含 `native/crates/` 及两个元数据适配器,支持安装后的源码构建。基准测试预检检查整个工作区的构建输入,并排除 Cargo 的 target 目录。 ## 单次请求协议 新的宿主桥接发送 `{ version: 1, requestId, component, budget, request }`。`request` 保留严格的 能力参数和宿主权限字段;`component` 为 `file` 或 `ptc`,不会授予权限。桥接生成新的 UUID, 填入真实会话、根路径和策略,并在启动进程前再次核实权限。普通成功字段保留原有语义;可选引用字段见下文。 `budget.timeoutMs` 为兼容信封仍接受 1..2147483647 毫秒;宿主默认值和硬上限均为 30000 毫秒,并保留宿主取消机制。 进程内的看门狗也会约束直接调用;超时退出码为 124,桥接将副作用报告为 unknown。 `budget.maxBytes` 范围为 1024..131072,默认 131072,计算序列化 JSON 与末尾换行的总字节数。 下限保证结构化错误有足够空间。没有可信存储的读取输出超限返回 `OUTPUT_LIMIT` 且无副作用;修改回执丢失则 报告 unknown,除非已有错误携带更精确的副作用状态。不会自动重试。 完整请求仍以 2 MiB 为上限。为兼容 0.3.x 基准对比,显式保留旧版无版本请求,采用相同权限检查和 有界默认传输预算。只要出现任一信封字段,就严格按 v1 解析;缺字段、未知字段、非法 ID、 不支持的组件或版本、无法使用的预算,均在文件系统副作用前被拒绝。请求 ID 不改变结果哈希。 自动输出溢出见下文。 ## 会话快照引用(6a/16) worker 接受可选的可信信封元数据 `storage: { root, authorityId, allowedTools, windowsWriteSid? }`。 工具参数和内层 request 均不能注入这些字段。宿主提供已存在的绝对缓存根目录、64 位小写 SHA-256 权限身份,以及当前规范化生产工具白名单。权限身份必须绑定本次会话随机标识、当前策略和凭据 边界;知道引用不等于获得权限。每次访问仍核实会话、选定的规范化根路径及目录身份、生产工具和 当前凭据边界。可信缓存根目录是独立的缓存专用授权,不随操作根目录选择而改变,也不受业务 write_roots 限制; 绝不将缓存位置加入业务修改白名单。 带此上下文的 result put 返回 `ref://<编码会话>/<工具>/`,并提供 `reference` 元数据: refId、createdAt(Unix 毫秒)、ttlMs、schemaVersion、producerTool、totalItems、totalBytes (实际序列化快照字节数),以及最多十行、512 字符的预览。默认 `ttlMs: 0` 表示会话生命周期; 显式正数 TTL 最多七天。宿主须在会话结束时使引用失效,重新打开会话时更新权限身份。单个快照 最多 10 MiB,每会话缓存最多 100 MiB/4096 项;崩溃暂存和未知文件也计入配额。写入者通过同一 进程间锁串行作出配额/LRU 决策。只淘汰规范 UUID 快照名;不可变审计记录永不参与 LRU。 分页返回 sourceTotal、筛选后的 total、items、nextOffset、omitted、complete;complete 仅表示 选定的已存储行全部展示,不意味着原始业务扫描完整。512..65536 字节分页预算计入 JSON 转义、 引用元数据和末尾换行。单行过大时必须选择更少字段或增大页预算;引用分页不会生成另一层引用。 拒绝嵌套引用对象,普通字符串中的 URI 仍是普通数据。只读分页仅打开已有共享锁,不创建文件、 不更新 LRU 时间。丢失、过期、释放或淘汰的快照返回 `REFERENCE_EXPIRED`。旧 r-/j- 访问保持 原有协议和持久审计位置。 Windows 宿主提供受限调用实际的私有 `--temp` 和 `--temp-write-sid`,并为只读访问保留该位置。 受保护缓存 DACL 仅授予当前用户及这个私有临时能力,且该能力必须已存在于持有的父目录句柄上。 拒绝公共组、登录组和工作区能力 SID。真实只读及其他会话令牌无法写入这些对象。POSIX 文件和 目录归当前用户所有且权限私有。缓存父目录、子目录、快照和稳定锁均拒绝链接或 reparse point; 文件只允许单一硬链接。缓存操作不会修改业务文件权限。 宿主生命周期清理使用相同可信上下文发送 `result { action: "purge" }`,不接受其他参数。仅删除 该会话范围内已验证的快照/暂存名,保留锁 inode、目录以及未知/审计名称。结果包含 removed、 retained、complete、effectState;部分清理失败会明确已有副作用。只读模式拒绝 purge。宿主必须 先在逻辑上使引用失效,再等待活动调用结束;清理被拒绝或中断时延后清理,绝不能重跑业务操作。 宿主生命周期钩子由宿主集成切片接入。 ## 过大输出的自动有界缓存(6b/16) 提供可信存储时,普通文件、搜索和批处理输出超出序列化内联预算后,保留有界开头并返回 reference 与 referenceRoot(原始操作的规范根目录)。cwd 改变后分页仍须传入该原始根目录。 显示 complete 为 false;原始状态、修改数量/副作用和扫描覆盖事实保持不变。小结果不创建缓存。 worker 仅捕获请求的范围或页,不会把查询静默扩大成整棵目录树。 引用页包含 source:原始非 items 执行事实,以及 root、itemEncoding: "tagged-json-v1"、 capturedItems(逻辑条目数量)和 captureComplete。原始 scanComplete/matchedTotal、版本、范围 及 continuation 语义保留其中。page.complete 仅表示存储记录已显示完毕,不证明扫描或捕获完整。 read_files 的一个逻辑条目是完整逐文件回执,包括行、版本、范围及错误;逐文件失败仍为结果值。 小条目编码为 `{ kind: "item", index, value }`;大条目编码为一串有界的 `{ kind: "item-json-chunk", index, chunk, byteOffset, text, complete }`。index 和 chunk 从零开始; byteOffset 计算逻辑 JSON 序列化后的 UTF-8 字节。按 chunk 顺序连接 text,仅在最后一块的 complete=true 后 JSON.parse;须验证连续索引、偏移及结束标记。StorageReference.totalItems 计算物理记录数,source.capturedItems 计算重建后的逻辑条目数。分块发生在显示裁切前,因此 被检查行的 Unicode、控制字符与行尾内容均可恢复。 捕获预算小于 10 MiB 实际快照配额。若某个逻辑条目放不下,其全部块会回滚,仅存储此前完整 条目;source.captureComplete 为 false,storageError 报告 QUOTA_EXCEEDED。缩小查询以获取 缺失范围。捕获完整性独立于原始扫描完整性;引用页绝不会再次溢出为引用。 缓存失败附加有界的 `storageError: { code, message, effectState }`,其中 effectState 仅描述 缓存副作用,与业务 status/changed/effectState 分开。只读观察不能创建引用。缓存拒绝时保留 不完整的有界开头,并提示范围/十六进制恢复;已完成的修改不能重跑。发布前先验证引用元数据 能否放进头部预算,避免因预算过小而留下无法取得的快照。没有可信存储时保留旧传输契约, 由宿主在存储不可用时补充恢复指导。 ## CSV/TSV worker 观察(15a/16) 新增 ops-documents crate,在同一个单次 worker 内处理 read_table。该能力不进入默认工具 schema: Native 经 `ops_discover_tools`、PTC 经 `ops_load_sdk` 选择 read_table 后,于代理下一步骤生效;兄弟及 子代理必须独立选择。表格切片没有新增外部包:serde/serde_json 与 sha2 复用既有锁定依赖。 下文已实现的 DOCX 与 PDF 切片,其依赖审查记录见[文档解析依赖.md](文档解析依赖.md)。 参数为 `{ path, format?, encoding?, header?, offset?, limit? }`。宿主先相对于当前 cwd 解析 path,再发送绝对路径。format 为 csv/tsv;仅 .tsv 扩展名(忽略大小写)推断为 tsv,否则为 csv。 encoding 默认 utf-8,也可明确指定 utf-16le/utf-16be。匹配的 BOM 被消费,矛盾 BOM 和非法 Unicode 被拒绝,绝不使用替代字符解码。无 BOM 时以明确指定的编码为准,不做不可靠的字节猜测。 header 默认 true;重复或空列名按原位置保留。header=false 返回空 columns 数组,并从首条记录 确定 columnCount。数据行为 `{ row, cells: string[], lineStart, lineEnd }`:row 从 1 开始且 不含标题;lineStart/lineEnd 按实际 LF 计数,包含标题及引号内的多行。单元格始终保留字符串, 不猜测数字、日期或布尔类型。引号字段支持分隔符、双写引号和原样嵌入的 LF/CRLF。记录分隔符 为 LF/CRLF;引号外单独 CR、闭合引号后的多余文本、未加引号字段中的引号以及列数不一致均报错。 空记录含一个空单元格;末尾换行不产生多余记录,空文件为零行。 offset 为不含标题的 1..100000 数据行,默认 1;limit 为 1..1000,默认 200。每次调用流式执行 有界物理扫描,只保留所请求的行,并分别报告 rowsObserved、bytesRead(含有界预读)、 scanComplete 和 pageComplete。只有正常 EOF 且文件元数据观察未改变时,才返回 rowCount/total 和原始字节 SHA-256 revision。complete 还要求所请求页之后没有剩余行。即使目标页已观察完整, 非法后缀仍保留此前有效行、返回 status=partial/error,且不编造总数。元数据变化使 scanComplete 与 pageComplete 均失效。 skipped 只统计请求范围之前实际观察到的行数;请求偏移超过 EOF 时也不虚增。 硬上限:32 MiB 输入、100000 条数据记录(另加一次有界 EOF 探测)、1 MiB 解码后记录、1024 列、 8192 字节序列化标题,以及记录间检查的 30 秒截止时间;宿主/worker 请求截止时间仍同时适用。 提前停止时明确返回 scan-budget/time 和恢复指导;行分页不能绕过这些物理扫描限制,更大的输入 应使用专门的流式表格读取器。错误包括 TABLE_PARSE_ERROR、ERR_INVALID_ENCODING、OUTPUT_LIMIT、 FILE_CHANGED、DEADLINE_EXCEEDED;预检权限拒绝沿用原有策略错误码。 凭据和禁止跟随链接检查复用 ops-files。只读观察不创建审计或缓存对象。请求行过大时在显示 裁切前使用既有有界捕获器:引用保留可精确重建的类型化行 JSON,source 保留表格/覆盖事实, captureComplete 独立于 scanComplete。分页须使用原 referenceRoot。缓存副作用不代表业务写入; 即使会话可写,read_table 也按只读操作分类。 Native 用带物理 LF 行范围的原位置 JSON 单元格展示,并明确提示扫描缺口不完整。PTC 的生成 声明保留 `string[]` 单元格。只有稳定完整扫描且仍有后续行时提供只读前进续取;跨调用组合页面 须比较 revision。非法输入、文件变化和物理扫描上限保留前缀数据与恢复提示,不提供会重复 原缺口的续取。Native/PTC 引用页均区分原表格覆盖率与已存记录分页;既有排队、实时权限、 凭据检查、取消与存储绑定继续适用。 新安装的 PTC bundle 行从已实现目录生成允许池;已保存的显式 allowedTools 数组在刷新和重启后 仍然有效。文档 API 仍须由所属作用域请求后才加载。 ## 有界 DOCX 正文观察(15b/16) `read_docx` 仅按需发现:Native 经 `ops_discover_tools`、PTC 经 `ops_load_sdk` 选择,于所属代理下一步骤启用。参数 `{path, offset?, limit?}`: path 由宿主按当前会话 cwd 解析为绝对路径;offset 为从 1 开始的段落序号(1-100000,默认 1), limit 为 1-1000(默认 200)。每项为 `{block,type:"paragraph",text}`;表格内段落另有从 1 开始的 table/row/cell 坐标。保留空段落、制表符、换行、Unicode、实体字符及原文本空白。明确排除格式与 渲染布局、页眉页脚、脚注尾注、批注和包元数据;`scope:"main-body-paragraphs"` 与 excludedContent 显示该范围。complete 仅表示该范围完整,不表示整个渲染文档;无 Office 自动化或 外部关系抓取。 支持标准内部 word/document.xml 正文、存储/Deflate ZIP、严格 UTF-8 或 BOM 标记 UTF-16,以及 过渡/严格 Word 命名空间。二进制 DOC、宏、加密/多磁盘/ZIP64、嵌套表格、正文绘图、域、修订、 未知/外部命名空间内容和结构错误均明确拒绝。整个原包中的歧义 ZIP 尾记录签名字节也会在构造器恢复 逻辑之前保守拒绝。后段失败保留此前完整段落,返回 partial、 scanComplete:false、恢复指引,不给出全量 total/revision。XML 不解析 DTD 或自定义/外部实体。 限制在库分配/解压之前施加:原包 32 MiB;中央目录 1 MiB/4096 条目;每个 OPC 元数据部分 1 MiB; 正文 XML 实际解码字节 8 MiB;单段落 UTF-8 1 MiB;100000 段;XML 深度 128、每元素 64 属性、 作用域内 512 命名空间绑定;解析事件之间 30 秒期限并有传输 watchdog。固定 XML 部分有界解压后 完整校验 CRC;预检 ZIP 本地/中央头一致性、唯一性及不重叠;不解压到磁盘,仅保留所请求的段落页。 blocksObserved、scanComplete、pageComplete 和 complete 分别描述已观察段落、扫描、所请求页和 剩余段落。仅稳定完整扫描后才有 total、原包 SHA-256 revision 及 omitted;nextOffset 从 1 开始。 分页会重新扫描同一文件,合并观察前需比较 revision;分页不能绕过物理扫描上限。既有 spill 在内联 裁剪前捕获请求的完整段落,包括长 Unicode 文本。引用页保留范围、覆盖率与 captureComplete;页本身 complete 仅表示存储记录分页结束。按 referenceRoot 读取。每次读取重复权限、nofollow 与凭据检查; 只读会话不创建产物,传输或缓存失败不暗示业务写入。 精确依赖、发布日期、理由与原始许可记录见[文档解析依赖.md](文档解析依赖.md)。 Native 显示段落序号、表格坐标以及明确的 scope/excludedContent 范围提示,并在解析错误旁保留 安全前缀。PTC 在 Outcome 中返回类型化段落;物理缺口不生成循环续取。稳定完整扫描且尚有后续 段落时可只读前进分页,跨调用须比较 revision。skipped 不超过实际观察的 blocksObserved, FILE_CHANGED 始终使所请求页不完整。引用页生成的 source 类型保留正文范围,独立于存储记录分页。 ## PDF 解析基础(15c/16) 内部 PDF 容器解析器仅接受受限的 PDF 1.0–1.7 子集:单个传统 xref 表、 准确的末尾 startxref/EOF、唯一字典键及对象标识,以及直接整数形式的流长度。 每个有效 xref 偏移必须准确指向对象头;对象不可重叠,间隙只能包含空白或注释。 增量更新、加密、对象流/xref 流、恢复扫描及重复歧义数据均被拒绝,名称转义后 仍会检查不支持的结构名称。 在索引分配前实施边界:输入 16 MiB、xref 条目 10,000、元数据值 100,000、 嵌套深度 64、每字典 4,096 个键、名称/词元 256 字节、字符串及编码/解码流 各 1 MiB。间接引用检查循环及深度。流仅支持无过滤或单个 FlateDecode; 外部流、过滤链及 DecodeParms 被拒绝。解压按实际输出限制加一字节停止, 并核验校验和、zlib 结束标记及完整输入消费;文档声明长度不能绕过实际边界。 本切片不暴露工具,也不宣称提取了完整文本。页面树、支持的字体/编码子集、 部分结果及 worker 权限检查已在下文的 PDF 提取切片中一并实现。 ## PDF 文本 worker(15d/16) 单次 worker 接受严格的 read_pdf { path, offset?, limit? }。宿主从当前目录 解析路径。offset 为 1 起始页码(1–32,默认 1),limit 为 1–32 页(默认 10)。 该能力默认不出现在 schema;经发现或 SDK 选择后,在所属代理下一步骤启用。 每项为 { page, text, runs: string[] }。runs 保留各 PDF 显示文本操作; TJ 的间距数字不当作字符。text 仅以换行连接各 run 供展示。范围明确为 page-text-layer-content-order,并非渲染阅读顺序。每次结果列出排除内容: 布局、图片/OCR、注释/表单、附件/元数据及结构树替代文本。页面实际调用 不支持的表单/图片、标记内容或外部图形状态时,整页视为缺口,即使该页也有 可读文本。缺失/null/空白/仅注释内容可返回空页;有图形但无支持文本层时 明确拒绝,不执行 OCR。 文本子集限于 PDF 1.3–1.7、基础切片支持的传统 xref,以及标准 Helvetica/Courier/Times Type1 字体。支持内建 StandardEncoding 的可打印字符 (含弯引号映射)或命名 WinAnsiEncoding,并明确处理后者项目符号/空格/连字符 别名。未知/控制编码不替换解码;嵌入/自定义字体、ToUnicode/CID 及编码差异表 均拒绝。更早 PDF 编码不擅自重新解释。映射与操作语义依据 [Adobe 托管的 ISO 32000-1 第 9.4/9.6 节及附录 D](https://developer.adobe.com/document-services/docs/assets/35e4369068f86065372c18787171a17e/PDF_ISO_32000-1.pdf)。 物理扫描限制为 32 页、30 秒、每页解码内容 1 MiB/64 个流、每页文本 1 MiB/10,000 个 run,以及累计解码 16 MiB 和累计处理流字节 16 MiB。 共享流只解压一次,但每次复用均计入处理预算。既有 16 MiB 文件和单流边界 仍然适用,页码偏移无法绕过这些限制。 scanComplete 表示整个有界文本范围的扫描完整性,pageComplete 表示请求页范围, 文件变化时必为 false。pagesObserved/skipped 只统计实际观察页。仅稳定完整扫描 附带 total、omitted 和原文件 SHA-256 revision。后续页不支持时仅保留先前完整页, 返回错误/恢复指引,不生成总数或 revision;组合重扫分页前必须比较 revision。 共享引用接收器在展示裁剪前捕获完整页并保留范围、扫描/捕获事实;引用分页完成 不等于源文档缺口已恢复。只读、凭据拒绝、nofollow 及无业务副作用沿用统一权限边界。 PDF 能力不进入默认 schema:Native 经 `ops_discover_tools`、PTC 经 `ops_load_sdk` 选择,在所属代理下一 步骤启用。Native 显示页码、转义文本与明确的文本层范围/排除内容;PTC 生成类型保留 page、text 和 string[] runs。不支持或非法页面在失败 Outcome 内保留此前规范数据,不生成循环页续取; 仅稳定完整扫描可前进分页,组合前须比较 revision。引用保留原页面覆盖率、解码/处理工作量、 范围与捕获事实;每次读取复用文件工具的实时权限、凭据、nofollow、共享预算和取消路径。 ## 类型化运行时归属(16/16) worker 选择与 Native 运行时生命周期改为严格 TypeScript。解析结果区分成功路径与失败原因, 配置及 Native 工具名在编译时检查。未初始化运行时在创建调用状态前返回不可用值。发布路径仍为 .js,来源校验、作用域与取消行为保持一致。 Native worker 桥也使用严格 TypeScript,采用宿主权限、文件系统及执行类型,输入/输出先按未知值 检查。非对象参数在启动前拒绝;进程返回非法 JSON 或非对象值时报告未知副作用,不记录成功读取。 写入回执观察保留宿主版本事实,固定 Native 子进程路径、权限校验及独立 PTC 限制路径保持一致。 PTC 桥复用类型化输入/输出检查,并采用宿主限制执行与 runner 失败契约。非对象参数在批任务启动前 拒绝;启动后的非法 JSON 回执保留未知副作用与生成的审计标识。只有已识别的 runner 失败证据才可 声明 worker 未运行;每次权限复查与限制 argv 保持必需,不增加无限制回退或缓存/业务权限。 源码构建辅助模块也采用严格 TypeScript。Cargo 解析返回可执行文件、来源、版本与环境;构建必须 提供已解析工具链及 crate 目录,流式输出文本诊断并返回数字退出码和收集输出。CLI 仍显式执行锁定 依赖的 release 构建并暂存原有来源回执;此类型迁移不改变依赖、安装、发布路径或自动构建行为。 可选 TUI 的活动、提醒、渲染辅助模块及 HTML 模板读取器采用严格 TypeScript。只读快照仅保留 有界计数和诊断元数据,运行中记录没有完成事实;注入 React/UI 的边界保留宿主节点类型,不加载 TUI 或 React 依赖。提醒、会话隔离、分页及 HTML 资源行为保持一致;非法结果形状保持未确认, 不保留原始正文。