Repository navigation
Description
范围与执行约束
2026-11-10 默认分支代码审计。以下报告含基线、证据、复现边界、价值排序和详细计划。首批事项经过独立复核后按 sub-issue 实施,其他事项保留研究计划。协作检查只覆盖已推送工作,实施前再次核对。
cc-switch-simple 独立审计
日期:2026-11-10。目录:Q:/FullStack/fastrd/cc-switch-simple;远端:FastR-D/cc-switch-simple。复核:REVIEW-cc-switch-simple.md。
1. 结论和基线身份
当前应优先审阅已有 PR #1,并在该 PR 内反馈目标配置目录忽略客户端环境变量的问题。旧版 YAML 读取、配置覆盖等已由该 PR 改写的行为不再另立修复任务。
| 项目 | 本次观测 |
|---|---|
HEAD / master / origin/master / 远端 master |
a2f6fa33e2d3609bf487262f69ccb97d3d65714d |
PR #1 / origin/yaml-switch-and-fingerprint-check / 远端 head |
1723725f86779843cd8bdf4cbeaadaff484a1304 |
| PR base | a2f6fa33e2d3609bf487262f69ccb97d3d65714d |
| PR 状态 | OPEN、MERGEABLE;标题“支持本地 YAML 配置切换与模型指纹检测” |
| PR 规模 | 14 文件,+1165/-296;核心入口几乎重写,另增模块、文档、测试、打包/CI |
| 开放 issue / PR | issue [];开放 PR 仅 #1 |
| 工作树 | 审计前后 status 为空;工作树、暂存区 diff 为空 |
基线 master 与待审 PR 是两个不同版本。下文 cc_simple.py 及 tests/ 行号全部指 PR head 1723725;master 中并不存在这些文件。没有 checkout 或创建本地分支。
2. 架构与实际阅读范围
master 为单文件 ConfigManager:导入本地配置,生成 Codex TOML 并备份/切换。cc-simple.py:25–34 实际读 key=value;145–176 生成并整体写配置。这些是旧设计事实,不能忽略 PR 后重复报修。
PR 将原入口改成兼容调用 cc_simple.main;新模块提供 add/list/use/check:
YAML / 旧 key=value → read_config → 配置目录中保存 / 列表
use → resolve_target + client_base_url → TOML/JSON 合并 → 备份 + atomic_write
check → resolve_target + endpoint → ModelTrace.check_api → 归因结果
PR 的 pyproject.toml 声明 PyYAML、tomlkit 与 CLI 入口;ModelTrace 在 check 时加载。目录解析发生在写文件和备份之前,因此错误目录会同时影响输出和备份位置。
实际阅读:
- master 完整:
cc-simple.py:1–238、README.md:1–58。 - PR head 完整:
cc_simple.py:1–354、兼容入口cc-simple.py、tests/test_review_regressions.py:1–165、pyproject.toml、.github/workflows/tests.yml。 - PR head 定位搜索:
tests/test_cc_simple.py、test_library_integration.py及回归测试的 target-dir/客户端目录;README.md、docs/USAGE.md的目录环境变量与 target-dir 说明。未逐行读完整基础测试、集成测试和使用文档。 - 远端:开放 issue/PR、PR 元数据、checks、分支 heads;本地 PR diffstat/numstat。没有逐行阅读所有 14 文件 diff。
gh pr checks 1 返回 12 条成功记录,来自两个 run、各含 Ubuntu/Windows × Python 3.10/3.12/3.14。它们是远端历史 CI,不是本机重新跑出的结果。
3. CS-1:PR 的目标目录解析忽略客户端环境变量
优先级 P2;适用于设置自定义客户端目录的用户。缺陷类别是配置生产者与配置消费者对同一资源位置的解析规则不同。规则:切换器应遵循被切换客户端的有效配置目录,用户显式目录覆盖该默认解析。
证据
PR cc_simple.py:191–195:
def switch(config, target_dir=None, target=None, dry_run=False):
target = resolve_target(config, target)
config = dict(config, base_url=client_base_url(config["base_url"], target))
directory = Path(target_dir).expanduser() if target_dir else Path.home() / (".codex" if target == "codex" else ".claude")
path = directory / ("config.toml" if target == "codex" else "settings.json")make_parser:289 已提供 --target-dir,main:323 传入 switch。对 PR 核心、测试和目录文档执行 Git 搜索,未发现 CODEX_HOME 或 CLAUDE_CONFIG_DIR 的处理;测试大量使用显式 --target-dir,因而没有覆盖默认路径偏离客户端目录的情况。
独立复现:从 Git object 读取真实 PR 源码,用 AST 提取 switch 的前四条语句(192–195)并执行,输入两个目标;上游 target/URL 归一化以恒等函数隔离,未执行后续文件读写。只在进程内设置:
CODEX_HOME=D:/Temp/opencode/audit-codex
CLAUDE_CONFIG_DIR=D:/Temp/opencode/audit-claude
实际目录结果:
| 目标 | 无 target_dir | 显式 target_dir=D:/Temp/opencode/explicit |
|---|---|---|
| codex | 当前用户 home 下 .codex |
D:/Temp/opencode/explicit |
| claude | 当前用户 home 下 .claude |
D:/Temp/opencode/explicit |
这是 PR 实际目录表达式的执行证据,确认环境变量不参与解析;不是完整 CLI 写入或真实客户端读取验证。尝试加载完整 PR 模块运行 dry-run 时,本机缺少 tomlkit,在 import 阶段失败,未安装依赖、未运行完整 switch;不能将 AST 探针升级为集成通过。
影响与边界
在使用这些客户端目录环境变量的环境中,切换器可向 home 默认目录写入并报告成功,而客户端仍读取另一个目录。用户显式指定对应 --target-dir 可规避。没有实际写入用户配置,也没有证明数据已丢失或凭证泄漏。客户端具体版本对配置路径的契约,应在补丁集成验收中记录版本并核对;本次没有运行 Codex/Claude 客户端。
4. 最小实施计划:在 PR #1 内收敛
- 将本发现作为 PR #1 的审阅反馈,引用 head SHA、
cc_simple.py:194、复现和规避方法。此次仅把反馈草案写入本地 REVIEW,未发布评论或提交 review。 - 直接调整
switch的目录选择:显式target_dir> 对应目标的非空CODEX_HOME/CLAUDE_CONFIG_DIR> 当前 home 默认目录。沿用Path(...).expanduser(),不增加参数、配置键、目录注册表或磁盘猜测路径。 - 只读取当前 target 的环境变量。Codex 的环境不影响 Claude,反之亦然;空值回到现有默认。
--config-dir是切换器的配置条目存储目录,不应混同为客户端配置目录。不要在check中增加无用途的配置目录解析。 - 在现有 CLI 测试内用隔离 home/环境和临时目录,运行真实
use ... --dry-run,验证回显 path 与优先级;再执行真实 use,验证仅预期目录变化、已有配置字段保留、备份位于相同有效目录且含原始字节。 - 对两个客户端验证显式目录覆盖环境、环境覆盖默认、空/未设置回退、另一客户端变量不串用;CLI 接收的所有输入仍经原
read_config/resolve_target。补丁不需要重写 YAML、URL 或原子写入实现。 - 在有 PR 依赖及 ModelTrace 的受控环境跑基础/回归/集成测试及现有 CI 打包验证,标明任何 skip。远端通过记录不能代替新增目录用例的红→绿结果。
这是最小修复:目录已由一个表达式集中选择,已有显式 override 足够表达用户意图;只让默认选择与客户端契约对齐。仅更新文档要求每人重复传目录,会把可确定的信息留给调用者;增加 profile/环境解析框架则超出问题规模。
5. 已修问题的处置与冲突判断
| master 的旧行为 | PR head 的处理证据 | 本次处置 |
|---|---|---|
| YAML 实为 key=value 解析 | cc_simple.py:36–97 使用安全 YAML loader、字段校验并兼容旧文件 |
不重复开 YAML 修复任务 |
| use 整体生成配置、覆盖原内容 | switch:199–231 解析既有 TOML/JSON,合并受管理字段;234–239 备份与原子写入 |
不在 master 另做一套合并器 |
| 目标/协议和地址归一化 | resolve_target/client_base_url:99–133;回归测试覆盖 URL/YAML 既有反馈 |
保持 PR 范围,不把旧缺陷重新计为待修 |
这些是具体处理路径存在的源码结论,不等于全部组合均独立验证通过。PR #1 对核心文件的改写程度很高;CS-1 与其 switch 同文件同逻辑,另从 master 开补丁会重做实现并制造合并冲突。应在 PR head 内做小修、随后复核新 head。ModelTrace 已合的库/API工作也不需要在这里重新实现。
6. 验收与实际验证记录
- 两目标的真实 CLI 用例在原 PR head 默认路径断言失败,修复后通过。
-
--target-dir> 本目标环境变量 > 默认 home;空环境值与目标隔离符合预期。 - dry-run 只报告有效目标路径、无文件变化;use 的输出 path、实际写入和备份目录一致。
- 实际文件内容合并保留不相关 TOML/JSON 字段;备份字节正确;默认 home 在环境指定时无变化。
- 现有 YAML、URL、密钥输出、ModelTrace 集成和打包测试仍通过;真实客户端版本/目录契约验证已记录。
实际执行:Git 身份/status/diff、远端 heads、开放协作项、PR 元数据和 checks;PR 文件读取和目标目录搜索;AST 目录前缀内存执行;完整模块 dry-run 尝试因缺 tomlkit 失败。没有执行本机 PR unittest、wheel 构建或真实 use,也没有更改全局环境或用户配置。
实施后在具备依赖的 PR head 工作区 建议:
python -B -m unittest discover -s tests -v
python -m build不可直接在当前 master 运行并称其验证了 PR:master 没有相应模块、测试或 pyproject。跨包 wheel 验证依 .github/workflows/tests.yml 的现有流程执行;其中 ModelTrace checkout 未固定 SHA,复跑时应记录实际依赖提交,不能把一次 CI 绿外推到任意未来 ModelTrace。
7. minimal-design-gate
| 五问 | 答案 |
|---|---|
| 结构性? | 在单一目录选择点遵循两个客户端的有效目录契约。 |
| 调用负担? | 沿用现有 target/target-dir,不增加新字段或用户选择。 |
| 可推导? | 从 target 和进程环境确定路径,无需用户重复提供已设置的目录。 |
| 额外复杂度? | 仅调整现有优先级;不增 helper 层级、目录发现或回退扫描。 |
| 过拟合? | 按客户端既有契约处理目标,不按供应商名称、某台机器或配置条目特判。 |
生产数据结构不变。实施目标为局部目录选择、测试及必要文档,不能为此扩展 14 文件重写。当前没有源码补丁,不能给整个 PR 出具“无过度设计”结论;未逐行读取的文件仍未审。实际交付阶段应报告生产/测试/文档净行数,并检查重复状态、未用配置、单调用抽象和新兼容分支。
本次产品源码/测试/依赖净变化 0 行;文档本 AUDIT +134 行、REVIEW +73 行,合计 +207 行,用于证据、复现和 PR 反馈移交。未开 issue/branch、未修改 PR、未发远端反馈。
独立复核
cc-switch-simple:独立复核与 PR 反馈草案
日期:2026-11-10。master:a2f6fa33e2d3609bf487262f69ccb97d3d65714d;待审 PR #1 head:1723725f86779843cd8bdf4cbeaadaff484a1304。主报告:AUDIT-cc-switch-simple.md。
裁决
- 沿用 PR 支持本地 YAML 配置切换与模型指纹检测 #1。 14 文件 +1165/-296 的改动已处理旧 YAML、配置合并和既有 URL/YAML 反馈;不能再以旧 master 为依据重做整套切换器。
- 新增反馈 CS-1 成立。 PR
switch:194无条件在未提供显式目录时使用 home,忽略CODEX_HOME、CLAUDE_CONFIG_DIR。 - 验证级别有限。 路径表达式已独立执行;完整模块因缺 tomlkit 未加载,CLI/客户端集成尚未执行。远端 CI 成功不代表覆盖该环境变量边界。
可复现探针
在当前仓库执行 Python(建议 python -B),从 Git 读取 PR 文件,提取真实函数前四语句:
import ast
import os
import subprocess
from pathlib import Path
from unittest.mock import patch
source = subprocess.check_output(
["git", "show", "origin/yaml-switch-and-fingerprint-check:cc_simple.py"],
text=True, encoding="utf-8",
)
function = next(node for node in ast.parse(source).body
if isinstance(node, ast.FunctionDef) and node.name == "switch")
print([(node.lineno, node.end_lineno) for node in function.body[:4]])
probe = ast.FunctionDef(
name="directory_probe", args=function.args, decorator_list=[],
body=function.body[:4] + [ast.Return(ast.Name(id="directory", ctx=ast.Load()))],
)
module = ast.fix_missing_locations(ast.Module(body=[probe], type_ignores=[]))
namespace = dict(
Path=Path,
resolve_target=lambda config, target: target or config["target"],
client_base_url=lambda url, target: url,
)
exec(compile(module, "PR-head-directory-prefix", "exec"), namespace)
with patch.dict(os.environ, {
"CODEX_HOME": "D:/Temp/opencode/audit-codex",
"CLAUDE_CONFIG_DIR": "D:/Temp/opencode/audit-claude",
}):
for target in ("codex", "claude"):
config = dict(target=target, base_url="https://example.invalid")
print(target, namespace["directory_probe"](config))
print(target, namespace["directory_probe"](
config, target_dir="D:/Temp/opencode/explicit"))本次执行得到语句行号 192、193、194、195。Codex 默认仍为当前用户 home 的 .codex,Claude 默认仍为 .claude;两个显式目录均正确返回 D:/Temp/opencode/explicit。探针只执行目录选择,未读写个人配置,路径无需实际存在。
隔离的上游函数只让测试到达路径计算,不替代路径表达式;后续 TOML/JSON、备份、原子写入全部未执行。另一次尝试 import 完整模块并 dry-run,因 ModuleNotFoundError: No module named 'tomlkit' 在导入阶段失败,未安装依赖。AST 输出不能代替完整 CLI 回归。
PR #1 反馈草案(本地,未发布)
在 head
1723725f的cc_simple.py:194,未传--target-dir时始终选Path.home()/.codex或.claude。已有CODEX_HOME/CLAUDE_CONFIG_DIR的用户会切换另一个目录,客户端仍读原目录;显式--target-dir可以规避。建议在同一目录选择点采用:显式目录 > 对应客户端的非空环境变量 > 原默认目录,复用现有 expanduser。请补两个目标的真实use --dry-run/use 优先级及备份位置用例,确认另一客户端变量不串用。无需增加新配置项,也无需重做 YAML、配置合并或 ModelTrace 集成。
反馈前应重新确认 PR head 及客户端目录契约,并附实际 CLI 红→绿结果。此次没有调用 gh pr comment 或 gh pr review。
已执行的协作检查与限制
gh pr list:仅 支持本地 YAML 配置切换与模型指纹检测 #1 开放;gh issue list:[];PR base/head 与本地/远端 refs 一致;MERGEABLE 是当前 GitHub 状态。gh pr checks 1:12 条 pass,两个 run 各 6 个 OS/Python 组合。只记录历史 CI,没有本机重新跑过 tests。- 完整阅读了 master 单文件与 README;PR 的 354 行核心模块、165 行 review_regressions、入口、pyproject、workflow。其余基础/集成测试与文档为定向搜索;全部 14 文件 diff 未逐行审查。
git grep在 PR 生产模块/测试中搜索目标目录和两个环境变量,只有硬编码 home 与显式 target-dir 路径,没有两变量命中。详细证据位置见 AUDIT。- 初始/结束 status、工作树 diff、暂存区 diff 均为空;未 checkout PR、未创建 branch,未写个人配置或更改仓库源码。
minimal-design-gate 复核
最小方案只修共用目录选择,已有 override 保留;路径从 target/环境推导,不增加用户字段、配置对象、目录注册器或另一套 switch。生产数据结构保持原样。五问答案和真实 CLI 验收在 AUDIT 第 4、6、7 节。
对整个 PR 的设计裁决仍保留未阅读范围;不能把这一局部小修建议当成整仓重写批准。交付时必须重新看完整实际补丁,按生产/测试/文档报告净行数,确认没有为环境路径添加磁盘猜测、双实现或多余兼容层。本次产品代码、测试、依赖净变化 0 行,仅新增两份文档。
Activity