opencodex PR 173「Storage 存储诊断页」深度评审实录:只读扫描器、immutable SQLite 读取与 approve-after-ci 判定
发布时间:2026/9/25 5:22:05来源:尧图网络
【免费下载链接】opencodexUniversal provider proxy for OpenAI Codex Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code项目地址https://gitcode.com/gh_mirrors/ope/opencodex点击查看免费下载导读本文基于 opencodex 仓库评审工作流对 PR #173Storage 诊断页面仓库首个外部贡献 PR的完整深度评审记录评审原文档展开讲解该 PR 的核心技术实现——只读存储扫描器scanStorage、GET /api/storage管理端点、GUI Storage 页面以及评审团队如何通过「源码审查 测试运行 真实环境 Activation」三条赛道得出approve-after-ci结论。读完本文你将掌握如何设计一个对 CODEX_HOME 零写入的只读存储诊断工具、SQLite WAL 模式下的 immutable 只读连接技巧、以及一套可复用的 PR 深度评审与合并风险评估方法。一、PR 背景与变更清单12 个文件PR #173 是 opencodex 收到的第一个外部贡献first-time contributorPR为 Storage 页面大史诗epic对应 devlog/_fin/500_storage-page-session-cleanup交付 Phase 1 的存储诊断能力扫描 CODEX_HOME 目录树按业务桶聚合占用字节数、文件数与数据库行数并在 GUI 中以可读方式呈现。按评审文档的变更清单12 个文件分为新增与修改两组新增5 个src/storage/scanner.ts只读扫描器、gui/src/pages/Storage.tsx诊断页面、gui/src/format-bytes.ts字节格式化、tests/storage/api-storage.test.tsAPI 测试、tests/storage/storage-scanner.test.ts扫描器测试。修改7 个src/server/management-api.ts新增/api/storage路由、gui/src/App.tsx导航与路由挂载、gui/src/icons.tsx以及 4 个 i18n 语言文件。注评审文档按 PR head 目录写作tests/api-storage.test.ts、tests/storage-scanner.test.ts合并入 main 后两个测试文件位于tests/storage/子目录下。二、核心实现一只读存储扫描器scanStoragescanner.ts 是整个 PR 的骨架。它对外暴露scanStorage(codexHome resolveCodexHomeDir()): StorageReport一次调用即产出完整的存储快照报告。2.1 桶bucket划分模型扫描器把 CODEX_HOME 下的内容划分为 7 类业务桶StorageBucketKeykey含义归属规则sessions活动会话根目录sessions/含日期分区的子目录树archived_sessions归档会话根目录archived_sessions/logs_db日志数据库匹配logs_(\d)\.sqlite含-wal/-shm伴生文件state_db状态数据库匹配state_(\d)\.sqlite含-wal/-shm伴生文件attachments附件根目录attachments/deletion_manifests删除清单根目录deletion_manifests/other其他未归入上述任何桶的根级文件与目录核心映射逻辑在DIR_BUCKETS记录与STATE_DB_FILE/LOGS_DB_FILE两个正则中目录型内容按目录名路由根级 sqlite 文件按带版本后缀的文件名路由其余全部落入other。2.2 纯测量的目录遍历walkFiles使用readdirSync(dir, { withFileTypes: true })递归遍历对每个文件执行statSync取size与mtimeMs。两个值得注意的设计决策对竞态树容忍读取失败的条目扫描中消失的文件、损坏的符号链接、无权限目录一律跳过绝不致命化——诊断工具在“树正在变化”的活目录上必须能给出部分结果而非崩溃。.trash隔离区不计入Phase 2 的隔离目录在根级被continue跳过避免污染other桶与总量统计对应的测试 storage-scanner.test.ts 专门验证了加入.trash后 total 与other均不变。2.3 immutable 只读 SQLite 行数统计本 PR 最关键的技巧countRowsReadonly是技术上最讲究的部分。CODEX_HOME 中的state_5.sqlite/logs_2.sqlite是带版本后缀的WAL 模式数据库运行期间有活跃的-wal/-shm伴生文件。诊断扫描器对这类 DB 统计行数时面临一个矛盾普通SQLITE_OPEN_READONLY在首次打开并查询一个已 checkpoint 的 WAL 库时仍可能实体化出新的-wal/-shm伴生文件从而违反「对 CODEX_HOME 零写入」的硬性约束。解决方案是immutable1const IMMUTABLE_READONLY_FLAGS constants.SQLITE_OPEN_READONLY | constants.SQLITE_OPEN_URI; const uri ${pathToFileURL(dbPath).href}?immutable1; const db new Database(uri, IMMUTABLE_READONLY_FLAGS);immutable1告知 SQLite 该文件在本次连接生命周期内绝不会变化于是 SQLite 完全跳过 WAL/SHM 协议——代价是读取最后一次 checkpoint 的快照而不是阻塞在活跃写者上。对一个必须永不写入的被动诊断扫描而言这是正确的取舍。同时pathToFileURL对 URI 保留字符空格、#、?、%做百分号编码防止朴素的file:${dbPath}字符串拼接把路径解析成 URI 的 fragment/query/escape对应的 URI 保留字符测试 专门覆盖此场景。任何异常损坏、扫描中消失、未来 schema 变更一律降级为null——即“unknown”绝不抛出异常、绝不崩溃。行数只从最新版本后缀的 DB 主文件统计newestVersionedDb选取版本号最大者-wal/-shm伴生文件永不入选但旧版本 DB 与过期 WAL 伴生文件仍计入桶的字节数与文件数。2.4 报告结构StorageReport包含codexHome、generatedAtepoch 毫秒、total { bytes, fileCount }与buckets[]。每个StorageBucket聚合bytes、fileCount、oldest/newestmtime 边界空桶缺省、largest按字节排序取前 5 的大文件路径为CODEX_HOME 相对路径且跨平台统一用/分隔以及仅 sqlite 桶才有的rows可为number | null。边界语义也很明确CODEX_HOME缺失ENOENT是全新机器的正常状态报告全零但CODEX_HOME指向一个文件ENOTDIR则是坏配置必须抛出异常让调用方以scan_failed回退 envelope 呈现而非静默渲染成空主页。三、核心实现二GET /api/storage端点与回退 envelopemanagement-api.ts 新增管理端点直接把扫描报告序列化输出。两个状态由 api-storage.test.ts 精确锁定正常路径GET /api/storage返回 200body 含codexHome、generatedAt 0、buckets数组与total且error字段不存在测试还对照文件系统逐文件盘点含.opencodex-native-main.claim.sqlite等协调库及其-journal/-wal/-shm伴生文件归属other的断言。失败路径当CODEX_HOME被指向普通文件导致根readdir抛 ENOTDIR 时端点必须返回200 { error: scan_failed, total: 0, buckets: [] }的回退 envelope而不是 500——错误通过结构化的error字段传达给 GUI 渲染层。四、核心实现三GUI Storage 页面Storage.tsx 是评审的「レーン ALane A」重点评审要求逐行审查 179 行PR 版聚焦四个点error envelope 渲染分支识别scan_failed回退并渲染诊断提示而不是把空 buckets 误当成“存储为 0”。rows undefined与null的区分undefined表示“本桶不是 sqlite未扫描”null表示“是 sqlite 但锁定/不可读”。评审文档指出当前实现未进一步区分 lock / corruption / missing schema 三种成因建议返回 reason code 或展示「unavailable」措辞P2 发现。locale 格式化字节数与文件数需按当前语言环境格式化评审指出 bucketfileCount列Storage.tsx:72与 sub-KB 的formatBytesformat-bytes.ts 第 5 行的bytes 1024分支遗漏了 locale 处理P3 发现 ×2。disclosure 与表格可访问性largest-file 表缺theadStorage.tsx:97属于可访问性缺陷P2 发现。页面在 App.tsx 中以{ id: storage, tkey: nav.storage, Icon: IconHardDrive }注册进导航并在page storage时渲染Storage apiBase{sharedBase} /。此外页面还承载了 Phase 2 的清理策略面板、隔离区管理面板等StorageWorkspace组件体系但这些不属于 #173 的评审范围。五、测试验证read-only 不变量与行数降级评审的「レーン BLane B」要求本地真实运行两个测试文件PR head 检出后执行验证“8 个扫描器测试 API 测试”的声称属实且通过。当前仓库的 storage-scanner.test.ts 实际包含 9 个scanStorage用例评审据此记录 P3PR body 声称 82 与实际 92 不符元数据陈旧覆盖聚合正确性构造合成 CODEX_HOME fixture日期分区 sessions、扁平 archived_sessions、带 WAL 伴生的版本化 sqlite、plugins 缓存与 config.toml逐一断言各桶 bytes/fileCount/mtime 边界及 total 与各桶之和相等。largest 排序每桶前 5 大文件路径为 home 相对、/分隔。只读行数对最新版本 sqlite 统计threads/logs表行数state3, logs5。URI 保留字符weird#namewith%percent目录下行数统计不被 URI 解析破坏。不可读 DB 降级 null写入state_9.sqlite垃圾文件 shadow 住state_5断言 rows 为null且不抛异常。活跃写者下瞬时完成BEGIN EXCLUSIVE锁住 state 库后扫描仍能读回快照行数且扫描前后目录快照逐键一致不产生新文件。空/缺失 home全零报告。坏 home 抛出home 是文件时scanStorage抛错供端点回退。CODEX_HOME 环境变量覆盖默认参数走resolveCodexHomeDir()。零写入不变量扫描前后snapshotTree全量比对keys 与每个文件的 size/mtime 完全一致。评审对第 10 条read-only invariant 测试给出的 P2 缺陷是测试只比较了size mtime未验证 inodestorage-scanner.test.ts:68与 PR body 声称的“mtimeinode 快照”不一致——因为某些平台/文件系统上 mtime 粒度有限理论上存在扫描产生同尺寸、同 mtime 的新文件的盲区。六、真实环境 Activation对 ~/.codex 的实战验证评审文档「ActivationC-ACTIVATION-GROUNDING-01直接执行」要求把 PR head 检出到 scratch worktree 后不仅跑测试还要对真实 CODEX_HOME 执行扫描器git fetch origin pull/173/head git worktree add /tmp/ocx-pr173 FETCH_HEAD --detach cd /tmp/ocx-pr173 bun install bun test tests/storage-scanner.test.ts tests/api-storage.test.ts # 实机 activation在 PR head 上对真实 ~/.codex 运行扫描器 bun -e import { scanStorage } from ./src/storage/scanner.ts; const r scanStorage(/Users/jun/.codex); console.log(JSON.stringify({ total: r.total, buckets: r.buckets.map(b ({ key: b.key, bytes: b.bytes, files: b.fileCount, rows: b.rows })) }, null, 1)); git worktree remove --force /tmp/ocx-pr173评审对实机运行还预设了两条判据A-gate fold #6期望state_db.rows与logs_db.rows返回数值若活 WAL 下返回 null 即为发现项、total.bytes 0「扫描前后 ~/.codex 无改动」由 fixture 测试的 read-only 不变量覆盖实机如需额外确认可在/tmp保存find ~/.codex -printf %p %s %T\n前后快照做 diff。Activation 实测结果真实 25GB hometotal.bytes: 26,827,894,984 (25GB) total.fileCount: 25,621 state_db.rows: 4,886 (数值 ✓) logs_db.rows: 1,009,585 (数值 ✓)两个 rows 均返回数值「全部为 null」的 worst-case 场景不成立approve-after-ci条件满足。这也直接验证了「immutable 连接在活跃 WAL 写者环境实际有 100 万行 logs下仍能瞬时读回 checkpoint 快照」的设计假设。七、评审发现与 Verdict 决策7.1 判定规则评审预设本地测试 Activation 全绿 GUI 无 blocker →approve-after-ciCI 放行/执行后建议合并。Activation 中 rows 全为 null活库不可读→ 非功能致命但「DB rows」列恒为 unknown 会损害方案价值部分数值则approve-after-ci注明残余风险全 null 则needs-work要求 immutable1 回退。7.2 Verdictapprove-after-ci4 条 non-blocking 发现评审者Archimedesgpt-5.6-sol priority确认11/11 targeted 3142/3142 全量测试套件通过tsc、GUI build、lint、i18n lint、privacy scan 全绿。P1 一条Phase 1 不阻塞但必须记录同步扫描阻塞事件循环在 25K 文件的 home 上实测首次扫描 1.12 秒重跑 501 毫秒评审文档标注management-api.ts:407、scanner.ts:79。规划文档计划书 31以“Phase 1 每次扫描都便宜cheap”为由接受同步实现但实测证明并不便宜。Phase 2 建议改为异步执行或引入缓存。就 Phase 1 只读诊断的目的而言不视为合并 blocker。P2 三条nullrows 不区分 lock / corruption / missing schemaStorage.tsx:76、scanner.ts:128——建议返回 reason code 或「unavailable」文案。largest-file 表缺theadStorage.tsx:97——可访问性。read-only 不变量测试未验证 inodestorage-scanner.test.ts:68仅比较 sizemtime与 PR body 的“mtimeinode 快照”声称不符。P3 三条bucketfileCount列缺失 locale 格式化Storage.tsx:72。sub-KB 的formatBytes未应用 localeformat-bytes.ts:5。测试数量声称 82、实际 92——元数据陈旧。另注规划文档拟用moderoimmutable1实现改为{ readonly: true }——评审判定为有意的设计偏离与既有 secondary-reader 模式一致实测工作正常予以接受。7.3 CI 未执行风险verdict 必备项这是仓库首个外部贡献 PR因此在 maintainer 批准 Actions 前检查数为 0。虽然本地已确认全量套件 3142/3142 tsc GUI build lint privacy scan 通过但合并前置条件仍为二选一maintainer 批准 Actions 后确认完整矩阵绿或本地检出 PR head 后执行bun run prepush等价命令。此外该 PR 的 commit co-author 为 Claude Fable 5——按仓库的 AI 贡献政策这是独立于代码质量之外的 maintainer 裁量事项评审文档明确将其单列提请决策。八、从本次评审沉淀的可复用方法论PR #173 的评审流程040_wp4_review_173.md展示了 repo 评审工作流的完整范式值得借鉴三条并行评审赛道Lane A 前端逐行审查渲染分支、数据语义、可访问性、路由、Lane B 测试声称的可验证性检出 PR head 本地实跑、Lane C 底层实现残余风险同步阻塞、WAL 活库下的 null 概率。Activation 优先于纸面推断把 scanner 直接跑到真实 ~/.codex 上用 100 万行 logs 的真实环境验证 immutable 只读设计而不是只信 fixture。分级发现P1/P2/P3 显式判定规则先写清「什么条件 approve、什么条件 needs-work」再按实测结果套用避免主观摇摆。风险外溢项单独成段CI 未执行、AI co-author 政策等「代码质量之外」的合并前置条件与代码发现分开记录避免被淹没。对任何「必须先扫描、后决策」的本地诊断工具而言immutable1只读连接 异常降级 null 零写入不变量测试这套组合是可以直接迁移复用的工程模板而「本地全绿 ≠ 可合并」的 first-time contributor 门禁意识则是评审纪律的一部分。赞分享【免费下载链接】opencodexUniversal provider proxy for OpenAI Codex Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code项目地址https://gitcode.com/gh_mirrors/ope/opencodex点击查看免费下载相关推荐opencodex 外部 PR 评审与合入实践Storage 只读扫描 immutable 打开与 Alibaba Token Plan baseUrl 覆盖保留opencodex 外部 PR 评审与合入实践Storage 只读扫描 immutable 打开与 Alibaba Token Plan baseUrl 覆盖LifeOS Vitals 技能详解macOS 系统性能诊断的只读 CLI 与判定式解读LifeOS Vitals 技能详解macOS 系统性能诊断的只读 CLI 与判定式解读 导读 Vitals 是 LifeOS 提供的一个 macOS 系统性AI 技能人工智能AI 应用Voyager 提示词管理器Prompt Manager实战指南捕获、归类、斜杠调用的个人指令宝库Voyager 提示词管理器Prompt Manager实战指南捕获、归类、斜杠调用的个人指令宝库 Voyager 扩展内置的 提示词管理器PromptAI 应用前端上一篇Tink Python JWT 签名示例实战密钥生成、Token 签发与 JWK Set 验证全流程下一篇SAM 3.1在视频分析中的应用从单帧到连续追踪的完整流程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网