Repository navigation
Description
范围与执行约束
2026-11-10 默认分支代码审计。以下报告含基线、证据、复现边界、价值排序和详细计划。首批事项经过独立复核后按 sub-issue 实施,其他事项保留研究计划。协作检查只覆盖已推送工作,实施前再次核对。
FastWrite 代码审计与候选实施计划
审计日期:2026-11-10;仓库:FastR-D/FastWrite(公开);目录:Q:/FullStack/fastrd/fast-write。
1. 结论与价值排序
本阶段仅研究、复现和编写报告,没有修改仓库、创建 issue、提交或推送。开始及复核时工作树均干净,分支为 main,基线及远端 main 均为 d63d0ef14683684b508fecc7d713191354c5325e。
| 顺序 | 编号 | 问题 | 优先级 / 证据 | 实施决定 |
|---|---|---|---|---|
| 1 | W1 | A 项目重命名文件会改写 B 项目的 workspace evidence 路径 | P1,跨项目持久数据污染;真实服务方法复现 | 首选,限 ClaimService 与独立回归文件 |
| 2 | W2 | 小数点被当作句末,论断 10.5% 被保存为 10. |
P1,常见论文数字被截断;真实 scan 方法复现 | 首选,与 W3 顺序实施 |
| 3 | W3 | 自动重锚只更新原文,不更新类型、数值与规范化文字 | P2,前后语义矛盾;真实 refresh/list 方法复现 | 首选,复用 W2 的语义提取逻辑 |
| 4 | W5 | 中文 Review 标题归一化为空,独立意见被合并 | P1,意见丢失;生产函数复现 | 保留,Review 文件已有远端工作,需协调 |
| 5 | W4 | 同一论断的不同 workspace evidence 被错误当作重复 | P2,第二条关联静默丢弃;真实 link 方法复现 | 保留,主要是 API 能力,当前 UI 没有新增 workspace link 入口 |
P1/P2 是本次影响评估,不是已创建的 GitHub 标签。没有把空格、压行、命名偏好列为问题。没有证据支持“全库无其他问题”的结论;完整阅读清单和未审范围见第 7 节。
2. 架构、依赖及原设计
2.1 已读设计与实际路径
README.md:3-42,54-79:Bun 1.3+、Git、单服务/单数据目录;编辑、权限、协作、历史恢复和备份的用户契约。docs/DESIGN.md:5-32,45-67,108-175:Workspace 是正文真相;版本绑定;用户确认 ChangeSet;Git history 与 GitHub staging 分离;失败不能伪装成功。docs/DEV.md:15-19,25-98,114-154:React/Monaco → relative HTTP API → 工作流服务 → Provider/JSON database/Workspace。该文包含历史“当前缺口”,不能直接当作当前源码缺陷。package.json:6-16,53-73:Bun workspace;TypeScript;Yjs/y-protocols;AWS S3 SDK;现有 overrides 和 Monaco patch。apps/web/package.json:13-32:React 19、Monaco、PDF.js、y-indexeddb、Vite。apps/server/package.json:12-28:FastCAS SDK、内部 Harness 包、OpenAI SDK、fflate、fast-xml-parser、PDF.js、nodemailer。
沿用户入口深入核对的路径:
- 文献与证据 → 扫描稿件:
ResearchDialog.tsx:210-235,316-333→app.ts:919,928,981-989→ClaimService.scan/list/link/update。扫描使用 service 自己的正则,并没有调用另一个analyzeClaims。 - 文件重命名 → 同步论断/证据:
app.ts:1209-1220在项目锁内 flush 协作、重命名 workspace、重命名协作,再调用claims.renamePath;跨项目污染发生在最后一步。 - 编辑后保留论断身份:
app.ts:1189-1195保存后 refresh;ClaimService.refresh:90-115读当前正文后重锚并核查 support;ResearchDialog.tsx:322-330显示原文、类型和支持状态。 - Review:
review-service.ts:22-151读取源码及可选 PDF 文本、执行 domain/venue passes、合成机械检查/证据/论证意见并保存;222-230执行去重。 - 参考论文写作:
references/importer.ts:15-48,60-89校验公共 HTTPS、逐跳固定 DNS、限大小/超时;references/service.ts:52-158,179-227,270-341保存隔离来源、带 revision 的解析任务、范围选择、分块风格提取与缓存。该路径原文属于写法参考,不当作当前论文事实。
2.2 保持原设计的修复原则
保留现有 ClaimAnchor、PaperClaim、ClaimEvidenceLink、项目锁、数据库 mutation 和 API 形状。项目归属从 paperClaims 推导;文本语义从当前 anchor.exactText 推导;不让前端传项目归属补丁、不增加新的同步任务或重试机制。database.ts:185-207 已提供串行 mutation 和持久化回滚,应复用它。
3. 协作工作与冲突排查
3.1 GitHub 与远端观察
实际使用 gh issue list、gh pr list(字段包含 files)、gh pr view 2/3(包含完整 files)、git ls-remote --heads origin、git branch -a、git for-each-ref --no-merged=HEAD 及每条未合入分支的 git diff --name-only HEAD...<branch>。
- open issue:科研绘图导出接口路径错误,下载的都是 HTML #4「科研绘图导出接口路径错误,下载的都是 HTML」,2026-10-28 更新。正文指向线上旧 diagrams bundle / 重复
/write/路径。当前apps下未找到*Diagram*文件;未访问线上或验证部署,不重复报一个“已复现的当前源码导出 bug”。 - open PR:0,查询返回
[],因此开放 PR 的 files 集为空。 - 最近 PR:feat: add bilingual anti-defensive writing task skills #5 已合并;feat: add editable scientific diagrams with native exports #1 已合并;fix: connect API writing workflow and versioned PDF reviews #2、Fix authenticated paper imports, source exports, and startup loading #3 是 CLOSED 且未合并,仍有远端分支,不能认定无人在继续使用。
- 本地远端引用 60 个(包含
origin/HEAD),实际分支 59 个;20 个分支对 main 有未合入提交。审计末尾再次确认 main SHA 及 open issue/PR 状态未变。
3.2 20 条未合入分支及处理
分支(省略 origin/) |
观察到的工作范围 / 本次处理 |
|---|---|
20260927 |
API-key auth,app/config/database/App;避开 |
codex/fastwrite-minimum-usability |
PR #3;导入、导出、启动、app/http/workspace、前端 base URL、shared models;避开这些入口 |
codex/functional-loop-fixes |
PR #2;Review/Provider 校验、编译、PDF UI、CI;W5 暂缓协调 |
fix/agent-audit-permissions |
AI audit、context、claims 入口外层权限相关 app;避开 |
fix/agent-rereview-permissions |
re-review/AI 权限及集成修复;避开 |
fix/ai-context-permissions |
completion/revise context 与 app 权限;避开 |
fix/changeset-path-permissions |
ChangeSet path 权限及 app;避开 |
fix/collaboration-group-permissions |
session groups、collaboration 授权;避开 |
fix/collaboration-recipient-revocation |
广播接收人复核及协作修复;避开 |
fix/experiment-process-isolation |
实验运行进程与 artifact;避开 |
fix/fourth-scan-validation |
多轮修复集成与测试,最新 head f4df79d;避免触碰其整组文件 |
fix/github-sync-permissions |
同步 merge/publish 前复核;避开 |
fix/harness-profile-ownership |
Harness profile 归属;避开 |
fix/memory-source-permissions |
Memory 源文件权限;避开 |
fix/offline-draft-identity |
按账号隔离浏览器草稿;避开 |
fix/project-transfer-ownership |
项目所有权转移;避开 |
fix/research-adapter-destinations |
研究适配器目的地址限制;避开 |
fix/research-source-permissions |
引用/研究源权限;避开 |
fix/rest-collaboration-synchronization |
REST 写入与协作文档同步;避开 |
fix/third-scan-validation |
协作/离线等修复和回归集成;避开 |
其余远端引用没有对本地 HEAD 的独有未合入提交,不因分支名中含 fix/ 就重新认领工作。完整分支名/SHA 已在终端枚举;无需复制大量已合入分支历史。
候选无文件重叠的实际检查:对所有 20 条分支运行以下限定 diff,输出为空:
git for-each-ref --no-merged=HEAD --format='%(refname:short)' refs/remotes/origin | ForEach-Object {
$branch = $_
$hits = @(git diff --name-only "HEAD...$branch" -- apps/server/src/claims apps/server/src/references apps/web/src/components/workspace/ResearchDialog.tsx)
if ($hits.Count) { "$branch`t$($hits -join ', ')" }
}以上命令实际 workdir 为 Q:/FullStack/fastrd/fast-write。W1/W2/W3 方案刻意不编辑 app.ts、app.test.ts、数据库结构或 shared models;用新的局部测试文件隔离。这里的“无冲突”指当前已观察的远端文件范围,不代表已获得分支作者未来工作的承诺。
4. 首选问题与详细最小实施计划
W1 — 文件重命名跨项目改写证据路径
定位:apps/server/src/claims/claim-service.ts:118-126,特别是 124;生产入口 app.ts:1209-1220;关联模型 packages/shared/src/models.ts:1109-1112。
失败条件:两个项目都含同名路径(如 main.tex),B 的 claim 有 workspace evidence 指向该路径。A 的编辑者把 A 的 main.tex 重命名为 renamed.tex。对 claim 本体的循环有 item.projectId === projectId,紧接着对 state.claimEvidenceLinks 的循环却只判断 kind + path,没有通过 claimId 限定归属。B 的 link 和 link.anchor 路径也被修改。B 下一次 list/refresh 找不到新路径,将原来有效的支持标为 stale;若原 claim 是 supported,还会降级 needs-review。无需 A 获得 B 的编辑权。
实际复现:生产 ClaimService(只替换数据库/Workspace I/O)调用 renamePath('A',...),断言 B link 已变成 renamed.tex;再调用 B 的 list,断言 stale=true。不是通过 HTTP/auth 的全链路测试。
缺陷类 / 规则:共享关联表的写入缺少父实体作用域;所有项目级 mutation 必须只修改该项目拥有的实体及关联。
最小计划:
- 在同一个
database.mutate回调内从当前 state 推导该项目所有 claim ID 的 Set。 - 用该 Set 同时限制 workspace link 的重命名;保留现有目录前缀替换规则和
anchor.path更新。 - 不在 link 上新增冗余
projectId,不从 API 接收额外归属信息;只补正确的作用域谓词。 - 新增
apps/server/src/claims/claim-service.test.ts的跨项目场景,使用临时数据库/Workspace;不改共享大型app.test.ts。
文件范围:claim-service.ts、上述新增回归文件。预计成本:小;无需迁移。已经污染的 link 不应按文件名猜测批量回填,历史数据恢复需另拿可信原记录。
验收:A 本项目的 claim、workspace link、anchor.path 正确更新;B 同名文件及目录子项全部逐字段不变;B supported 状态不降级;目录前缀不会误匹配 main.tex.bak;不存在的项目仍按原规则报错。
验证命令(实施阶段):bun test apps/server/src/claims/claim-service.test.ts;随后 bun run test、bun run typecheck。额外 HTTP 回归可通过现有 testApplication 创建 A/B 并 PATCH A /files,GET B /claim-links,避免改生产路由。
冲突:20 条未合入分支均无 claims 目录差异;外层 rename/app/Workspace 有他人工作,修复不得扩展到那里。
W2 — 句子扫描把小数截断为错误数值
定位:claim-service.ts:23-42,句子正则 26;同类扫描 claim-analyzer.ts:11,14,18;入口 app.ts:919;用户显示 ResearchDialog.tsx:316-324。
失败条件与结果:正文为 Our method improves accuracy by 10.5%.,POST claim-scans 会保存一条 anchor.exactText = "Our method improves accuracy by 10.",numbers=[{raw:"10",normalized:10}];剩余 5%. 不足 20 字而丢弃。原文、选择定位、数值和单位均不完整。这是实际 scan 路径,不只是单独演示正则。
缺陷类 / 规则:文本边界拆分破坏词法 token;句边界不能落在数字内部。
最小计划:
- 在 claims 目录使用一个小型、保留 offset 的句子遍历函数;点号位于两位数字之间时作为数值内部字符,其余句末行为先保持现有规则。
- 将 service 和 analyzer 的相同句界处理接入该函数。避免再造完整 LaTeX parser 或引入 NLP 依赖;不在全文先替换成占位符,以免偏移错位。
- service 原有最短长度、候选判定、stable ID、支持关联合并规则保持;analyzer 的 caption/table/ref 特殊入口保持。
- 在独立 service 回归和已有 analyzer 测试增加一段真实 TeX 输入,包含
10.5%、负小数、两个句子及 LaTeX\%。先确认该实际输入的完整 anchor/offset,再断言数值。
文件范围:claim-service.ts、claim-analyzer.ts、一个必要的小型纯函数文件(若两处共享,且确实删去重复代码)、claim-service.test.ts、claim-analyzer.test.ts。
验收:完整原文 10.5%. 和 % 单位保留;start/end offset 能在原文件精确 slice 回同一句;重复扫描不新增重复 claim、不丢 evidence link;两个句子不合成一条。该最小修复不声称解决所有缩写/TeX 语法边界。
验证命令:bun test apps/server/src/claims;bun test apps/server/src/app.test.ts --test-name-pattern "Claim|claim|citation";bun run typecheck。
冲突:没有当前远端文件交集;与 W3 共用 service,按 W2→W3 串行实施,避免同仓库并行修改。
W3 — 原文变化后,论断的派生语义仍是旧值
定位:claim-service.ts:216-235,尤其 227-233;生成派生值的另一处为 28-51,265-271。实际 reader:ResearchDialog.tsx:322 显示 type,agent-task-service.ts:27 按 result 类型评分,argument-graph.ts:8 按类型生成候选关系。
失败条件:原 claim 的前后 40 字上下文保留,中间论断文字改变,contextCandidate 成功重锚。该分支只更新 anchor、anchorStatus 和 reviewStatus,不重算 type/surface/normalizedText/numbers。
实际复现:10% 改成 20% 后 list 返回新 anchor,但 numbers/normalizedText 仍为 10%;另一输入把 result 改为 This limitation shows no accuracy benefit.,返回仍是 type=result 且保留已经从原文消失的 10%。当前 UI 主要消费类型/原文;未找到前端直接用 numbers 做数值运算的 reader,故不把这个问题夸大成已证实的计算结果污染。
缺陷类 / 规则:同一实体内原文与派生语义来自不同版本;所有文本派生字段必须来自当前 anchor 原文。
最小计划:
- 复用/抽取现有文本语义提取函数,在新扫描和 contextual reanchor 两处调用,产生当前 type、surface、normalizedText、numbers。
- 重锚成功且原文变化后一次性更新这些派生字段;新句无数值时必须删除旧 numbers,不能把空提取结果与旧对象简单 spread。
- 保留 claim ID、证据关联、createdAt、createdBy;继续将 supported 降为 needs-review,禁止自动继承旧支持结论。
- 精确文本只移动位置的分支不重置人工审阅状态;不要增加“用户传入新类型”字段。
文件范围:claim-service.ts、与 W2 共用的最小提取函数(如确有必要)、claim-service.test.ts。不扩大到 agent 调度、关系 UI 或存储 schema。
验收:10→20、数字删除、result→limitation 均与当前文本一致;纯位置变化不改变支持状态;ID/evidence link 保留;重复 GET/list 结果稳定;后续 scan 不复制同一 claim。
验证命令:bun test apps/server/src/claims;现有 app.test.ts 的 keeps Claim identity anchored across edits... 场景;bun run typecheck。本次已读该现有测试 2128-2163,它用 ten/eleven 文本但只检查 anchor/状态,未覆盖派生值。
冲突:当前无远端 claims 文件交集;依赖 W2 共用抽取逻辑确定后再实施,避免两套解析规则。
三项首选的 minimal-design-gate
| 检查 | W1 | W2 | W3 |
|---|---|---|---|
| Structural? | 从父 claim 推导所有 link 的项目作用域 | 修正句界,不逐数值打补丁 | 写入当前原文时同步派生字段 |
| Burden? | 不新增调用者参数 | 不新增选项 | 不新增用户字段 |
| Determinable? | 项目归属由 state 推导 | 字符上下文可确定数字内点号 | 类型/数值由原文推导 |
| Gratuitous? | 一条归属限制即可 | 共用现有规则,不建通用 NLP 平台 | 两个写入点复用一个提取逻辑 |
| Overfitted? | 所有项目/文件/目录相同规则 | 所有小数相同规则 | 所有 contextual reanchor 相同规则 |
更小的“只改 UI 显示”“让客户端自己给 projectId”“只更新一次数字”无法修复持久化对象的不一致,因此不选。当前实施净代码变化为 0;将来交付时按 service/helper/tests 分别报告净行数,共享 helper 应替换旧重复逻辑。
同类形状 sweep(研究结果,尚未修复)
本次使用专用 Grep 工具而非只依赖文件名;可按下列正则/范围重查:
| 搜索正则与范围 | 命中及处置 |
|---|---|
| `claims.(renamePath | deletePath |
claim\.numbers|\.normalizedText|claim\.surface|claim\.type,apps/**/*.{ts,tsx} |
type 有 UI/agent/argument reader;numbers 未找到直接计算 reader,W3 限定为对象语义及类型问题;不凭字段存在推断额外数值计算影响 |
逐行对照 claim-service.ts:26,42 与 claim-analyzer.ts:11,14,18 |
两处句界都排除点号,均属 W2 的计划范围;caption/table/ref 额外提取不属句界截断,不改其专用规则 |
以上查询在工具中以正则 alternation | 运行;表内反斜杠转义仅用于 Markdown 显示。所有命中保持“待实施”或明确非实例,没有声称已修复。
5. 保留发现与具体后续计划
W5 — 非 ASCII 审稿标题被错误去重(高价值,但先协调)
- 定位:
apps/server/src/agent/review-service.ts:222-230;key 在 225 用/[^a-z0-9]+/g删除中文。 - 条件:两个标题
方法缺少定义、实验缺少基线都得到空 key。第二条被并入第一条 rationale,自己的 ID、分类、严重级别、建议和独立生命周期丢失。已用原函数断言 2 条变为 1 条。 - 最小修复:Unicode 字母/数字规范化保留中日韩文字;空 key 不作为相等依据。若归一化后仍有碰撞,应至少按现有明确身份/完整标题处理,不引入模型判断相似度。增加中文独立问题、同一标题重复、纯符号标题三个边界验收,检查 severity/建议不丢。
- 文件:
review-service.ts、独立局部回归文件;命令bun test apps/server/src/agent、bun run typecheck。 - 冲突证据:PR fix: connect API writing workflow and versioned PDF reviews #2 已关闭未合入;其远端分支改同一个文件 77-81 附近的 Provider 校验。已读实际 diff,未修 dedupe;是文件级重叠而非同 hunk。考虑到本次要避开他人工作,先保留,复核作者状态后可成为下一批首选。
- Gate:Unicode 是数据本身可确定的属性,无新增用户参数/依赖/通用相似度框架。
W4 — workspace evidence 去重键过粗
- 定位:
claim-service.ts:161-182,特别是 177。 - 条件:同一 claim 先关联
main.tex,再关联results.tex的有效 anchor。两次返回同一个 link ID,数据库仍只有第一条。literature 按 evidenceId 去重,workspace 却只有 claimId+kind。 - 最小修复:按现有 workspace
path + anchor的有效定位身份判重,相同 link 重试仍幂等,不同文件/不同区间允许并存;review-waiver 保持现有单项语义,除非另有产品需求。 - 文件:
claim-service.ts、局部测试;命令bun test apps/server/src/claims。验收两个不同有效 anchor 能共存、重复同一 anchor 不新增、删除其中一个不移除另一项,support 正确重算。 - 无远端文件重叠;优先级低于 W1/W2,因为当前 UI 只提供 literature/waiver 的新增操作,workspace 类型主要由 API 使用。Gate 不新增 link-kind 或新 schema 字段,只纠正已有身份。
设计文档一致性(低价值,保留)
docs/DESIGN.md:11,77 与 docs/DEV.md:90 说新 Review 不持久化 ReviewSnapshot,但 review-service.ts:43-54,133,143,151 实际创建、绑定并保存 snapshot。这里确认的是文档/源码契约不一致,不声称存了 PDF 原始文本(snapshot 只有文件 digest 等元数据)。最小计划:由所有者确认当前已交付源码快照契约后修正文档相应段落和 README;若必须取消持久化,则需另审所有 snapshotId consumer,不在本轮擅自删除能力。验收文档、API 返回及实际 state 一致;验证 bun test apps/server/src/agent。与 Review 远端分支同领域,暂缓。Gate 不创建第二种快照格式。
6. 实际验证、证据强度与阻碍
已执行
git status --short --branch、git rev-parse HEAD、git remote -v、git branch -a、最近 8 条 log;复核 status/SHA/diff,无仓库改动。- 第 3 节 gh 与分支查询;所有 shell 均指定绝对 workdir。
- Node
v22.23.4;bun --version报 command not found;pnpm10.33.0在另一个仓库独立确认(最初&&链在 Bun 失败后未执行 pnpm)。 - 本地只读源码探针,命令在本仓库 workdir 执行多轮,最后增加 W3 类型变体后再次复核:
node --experimental-strip-types "D:/Temp/opencode/audit-fastwrite-probe.mjs"探针读取当前生产 ClaimService,去掉模块 import 并用 Node stripTypeScriptTypes(mode=transform) 转译;使用生产 normalizeWorkspacePath 和 ApiError 类;Bun SHA-256 用 Node 同算法桥接;仅数据库/Workspace 采用内存 I/O 夹具。W5 直接提取原 dedupeIssues 函数。断言观察的是缺陷存在,不是修复已通过。脚本位于本机临时目录,仓库没有新增测试文件。
未验证 / 阻碍
- 缺 Bun、仓库无已安装的完整工作区依赖,未安装运行时或依赖;没有执行完整
bun test / typecheck / build / security:check / e2e。这些不是绿色验证。 - 未启动真实服务器、HTTP 权限会话、浏览器、LaTeX、数据库/磁盘、邮件、S3、真实 LLM 或 GitHub 同步流程。
- 探针没有证明 HTTP 中间件、数据库事务/持久化故障、协作实时广播的端到端行为;实施时必须使用上述生产入口验收补齐。
- 未下载其他分支到工作树;远端用 ls-remote 只读观察,本地已有 refs 用于 diff。实施前再检查 heads 是否变化,特别是当前候选文件。
7. 阅读台账与后续顺序
逐行读完:根 README/package、server/web package、DESIGN/DEV;claims/claim-service.ts 全 273 行、claim-analyzer.ts 全 24 行及测试、argument-graph/adversarial-memo;references/importer.ts 全 90 行、references/service.ts 全 347 行;agent/review-service.ts 全 231 行;ResearchDialog.tsx 全 349 行;http.ts 全 105 行、shared/path 全 49 行。
逐行读的局部:app.ts:900-1005,1170-1249;app.test.ts:2090-2244;database.ts:160-259;shared/models.ts:1-80,1030-1129。agent-task-service.ts:27 本次为定位 reader 的搜索证据,未完整审查该文件。远端 Review diff 是逐行检查;其余分支核对提交主题和完整 changed-file 集,未把其全部补丁标成已审。
未完整阅读:认证/协作/编译/历史/全部编辑器/所有 Harness 包/依赖源/参考 parser/其余测试,故不对这些领域给出全量正确性或安全背书。此报告是这两个仓库专项审计中的 FastWrite 部分,不是其他 12 个组织仓库的总审计。
建议复核后顺序:W1 → W2 → W3,同一仓库串行、每项独立验收;W5 与 Review 工作作者协调后再排;W4 保留。复核及所有者确认后才创建对应仓库 issue,并在实施前重新核对 open PR、分支 heads 和工作树。当前没有创建任何 issue。
独立复核
FastWrite 首批修复计划独立复核
复核日期:2026-11-10。对象:AUDIT-fast-write.md 的 W1 / W2 / W3;仓库 FastR-D/FastWrite,目录 fast-write/。本文批准的是实施范围与验收方案,不代表修复已经交付。
1. 决定
| 项目 | 真实性 | 决定 | 本批允许范围 |
|---|---|---|---|
| W1 跨项目 rename evidence | 独立调用生产 service 复现;B 的路径、stale、supported 均受影响 | 批准 | 在现有 mutation 内从项目全部 claim 推导归属,仅补 link 作用域;局部回归 |
| W2 小数句界 | scan 保存 10. 而非 10.5%.,独立复现 |
修订后批准 | 修正线上 service 的数字内部句界与 offset;不强制同步改 analyzer、引入共享文件或修改单位语法 |
| W3 重锚派生字段 | contextual reanchor 后原文新、类型/数值/规范化文本旧,独立复现 | 修订后批准 | service 内抽取既有派生逻辑,扫描与原文变化的重锚共用;清除过期 numbers |
建议顺序仍为 W1 → W2 → W3,逐项验收。W3 与 W2 同文件,串行可避免碰撞,但不存在必须先建设共用句界/语义框架的技术依赖。本批暂缓 W4、W5、历史污染修复和 Review 文档调整,不附带实施。
2. 基线与远端冲突:已重新查证
- 本地 HEAD 与实时
git ls-remote --heads origin的 main 都是d63d0ef14683684b508fecc7d713191354c5325e,与审计一致。开始、验证后工作树均干净。 - 实时 open PR 返回
[];open issue 仅 科研绘图导出接口路径错误,下载的都是 HTML #4「科研绘图导出接口路径错误,下载的都是 HTML」,不是本批 claim 问题。 - 实时远端为 59 条 heads;本地 origin refs 与所展示远端 heads 的 SHA 一致,故本次用已有 refs 比较未落后于本次查询。不需要切分支或合入其他工作。
git for-each-ref --no-merged=HEAD ... refs/remotes/origin返回 20 条未合入分支。逐条git diff --name-only HEAD...<branch> -- apps/server/src/claims,全部无输出。- 20 条为:
20260927、codex/fastwrite-minimum-usability、codex/functional-loop-fixes、fix/agent-audit-permissions、fix/agent-rereview-permissions、fix/ai-context-permissions、fix/changeset-path-permissions、fix/collaboration-group-permissions、fix/collaboration-recipient-revocation、fix/experiment-process-isolation、fix/fourth-scan-validation、fix/github-sync-permissions、fix/harness-profile-ownership、fix/memory-source-permissions、fix/offline-draft-identity、fix/project-transfer-ownership、fix/research-adapter-destinations、fix/research-source-permissions、fix/rest-collaboration-synchronization、fix/third-scan-validation。 - 另查外围文件:这 20 条均改
app.ts;20260927还改database.ts;minimum-usability 还改app.test.ts、shared models。gh pr view 2/3 --json state,mergedAt,headRefName,files确认两 PR 都 CLOSED、mergedAt=null,分支仍在。
因此审计的 claims 文件无当前可见远端交集成立;它不能扩写成整个入口链无冲突。新增独立局部测试可避开 app.test.ts。若写 HTTP 回归,放独立文件并使用生产应用工厂;不要为调用该工厂而改生产 API 或重构大测试文件。实施前重新查 heads / open PR / status 即可,无需新增协调机制。
本次关键查询(均在 fast-write/ 工作目录):
git status --short --branch
git rev-parse HEAD
git ls-remote --heads origin
gh issue list --repo FastR-D/FastWrite --state open --limit 200 --json number,title,updatedAt
gh pr list --repo FastR-D/FastWrite --state open --limit 200 --json number,title,headRefName,files,updatedAt
git for-each-ref --no-merged=HEAD --format='%(refname:short)' refs/remotes/origin | ForEach-Object {
$b = $_
git diff --name-only "HEAD...$b" -- apps/server/src/claims
}3. W1:批准,归属集合必须取项目全部 claim
真实链路与独立证据
app.ts:1209-1220 的 PATCH files 在项目锁内执行 workspace rename → collaboration rename → claims.renamePath。权限检查作用于 A,不能约束 service 内对共享关联表的无范围写入。
claim-service.ts:118-126:claim 循环有 projectId,link 循环 124 只有 kind=workspace 与 path 条件。models.ts:1109-1112 的 workspace link 只有 claimId,需经父 claim 推导项目归属。refresh:96-113、links:83-87 已这样做;database.ts:228-233 删除项目也从 claim IDs 限定 link,原设计已有现成范式。
独立探针从当前源码转译 ClaimService,A/B 均经 scan → link(workspace) → update(supported) 建立对象,再模拟 A 的文件系统 rename 并调用真实 renamePath:
B link.path:main.tex → renamed.tex
B link.anchor.path:main.tex → renamed.tex
B list 后:stale=true,reviewStatus=needs-review
这证明关联数据污染与后续降级;HTTP 权限链本次为源码核对,未运行真实登录请求。B 降级的条件是它依赖被污染的支持且没有其他有效支持,不能表述成所有 B claim 必然降级。
最小修复与验收修订
- 同一个
database.mutate回调中取 A 的全部 claim IDs,给 workspace link rename 增加 membership 条件。不能只收集“anchor 路径本身被 rename 的 claims”:A 的intro.texclaim 可能引用本次改名的results.texevidence,仍须更新。 - 沿用 source 相等或
source/前缀及 anchor.path 更新规则;不新增 link.projectId、参数、迁移、跨项目锁或修复队列。 - 不按文件名猜测修复历史污染。已经污染的数据恢复另需可信记录,不是本批前置工作。
- 最小验收包含:A claim 位于另一文件但 evidence 在被改名路径;A/B 同名文件与目录子项;B 全对象不变且有效 support 不受影响;
dir.bak不被 renamedir误匹配。使用真实临时 JsonDatabase/Workspace,执行后重新读取持久化结果。 - 现有
getProject的不存在项目错误保持即可,不为这次谓词修复新增一套错误矩阵。
4. W2:问题成立,收缩共享化和 TeX 单位要求
真实证据
线上 POST claim-scans 在 app.ts:919 调 ClaimService.scan。claim-service.ts:26 用 /[^.!?\n]+[.!?]/g,在小数点终止;42 的数值正则虽支持小数,拿到的句子已经被截断。
独立输入 Our method improves accuracy by 10.5%. 得到:
anchor.exactText = Our method improves accuracy by 10.
numbers = [{raw: "10", normalized: 10}]
余下 5%. 被长度阈值丢弃。claim-analyzer.ts:11,14 有相同形状问题,另用较长前缀输入也复现到 10.;但其候选门槛、ID 与 surface 规则并不等同 service。
必须调整原计划的两点
- 不以两个相似实现为由强制建设共享扫描层。 全仓
*.{ts,tsx,js,mjs,json}搜索analyzeClaims|claim-analyzer,本次仅见定义与 analyzer 自身测试;生产 scan 明确走 service。首批修正 service 的句界足够覆盖已证实用户入口。analyzer 同形命中记录为暂缓同步修改,不据搜索结果删除该文件或推断全部外部调用。若之后确要一并修,先证明候选选择契约保持,再决定是否真的需要共享文件;不要把 verb 前最少字符数悄悄变成整句长度。 - 把
\%单位识别从句界验收拆开。 独立输入无小数的...10\%.,当前也提取不到%unit,根因是 42 的数字/单位正则不接受反斜杠。单改句界不会修好它。W2 本批可以要求10.5\%.原文与 slice 完整、小数 normalized 正确;不要求它凭空得到%unit,也不为了让测试绿而修改候选/类型/所有单位规则。未转义的10.5%.应保留现有%提取能力。TeX 单位识别如要排期,需单独明确范围。
收缩后的最低交付
- 一个局部、保留原文件 offset 的句界调整:两位数字之间的点号不终止句子;其余
.!?、换行与既有尾句规则保持。局部正则或小遍历均可,无强制 helper 文件。 - 不改候选判定、stable ID、最短长度、既有 claim 合并/证据保留、caption/table/ref 入口;不加入缩写词典、占位符替换、NLP 或 TeX parser。
- 验收:正/负小数、两个独立句子、真实换行和 TeX 字符;每个 anchor 用
content.slice(startOffset,endOffset)得到原文;重复扫描 ID/数量/link 不变。负号和 TeX 转义在测试输入里必须确实存在,不能把字符串\\n当成换行。 - 用修复后新建数据验证;旧版已截断 claim 再扫描可能涉及旧 claim 保留策略,本批不承诺自动合并/迁移这些历史记录。
5. W3:问题成立,用 service 本地派生函数即可
真实证据与影响
claim-service.ts:216-235 的 exact 分支只移动 anchor;contextual 分支用前后文找到新原文,229-232 更新 anchor/状态却遗漏 type、surface、normalizedText、numbers。scan:29,42,48-51 已有生成逻辑。
独立探针保留前后文,经生产 scan 建立 The evaluated result improves accuracy by 10%.,加 waiver、标 supported,再分别编辑并调用 list:
| 新 anchor 原文 | 实际返回的旧字段 |
|---|---|
The evaluated result improves accuracy by 20%. |
normalizedText 仍是 10%;numbers 仍是 10% |
This limitation shows no accuracy benefit. |
type 仍 result;numbers 仍是已消失的 10% |
两例保持原 ID、进入 reanchored / needs-review。语义矛盾确凿。ResearchDialog.tsx:322 读取 type,agent-task-service.ts:27 对 supported result 评分;当前重锚已降级 needs-review,所以不能直接声称本次编辑立即触发错误 result 调度。未发现 numbers 的前端直接算术用途,本批不扩成数值计算链修复。
最小修复与精确验收
- 在 同一 service 文件抽取现有派生逻辑,由 scan 与 contextual 成功且原文变化的分支调用,明确返回/赋值 type、surface、normalizedText、numbers。surface 还取决于路径(如 caption),不能只传 text 后丢失路径语义。
- 无数字时显式清除旧 numbers;仅
{...old,...只有非空 numbers 的新结果}会保留旧值,不能验收。没有必要增加 schema 字段、保存派生版本、语义修复任务或引入 analyzer 的另一套分类规则。 - 保留 ID、createdAt/createdBy、link;沿用 supported→needs-review。exact text 仅移动时不额外重置人工状态。
- “纯位置变化 supported 不变”应以支持仍有效为条件:用 literature/waiver 作 fixture;若 workspace evidence 版本本来变旧,现有 refresh 正当标 stale,不能为满足此验收而关闭证据检查。
- 最低验收为 10→20、去数字、result→limitation、citation surface 改变;重复 list 稳定;随后 scan 同一句不复制 claim,保留 ID/link。重锚数字用整数百分比即可独立验证,无需等 W2 helper。
app.test.ts:2128-2163已覆盖 identity/状态但没覆盖派生值,是现有场景的明确缺口;扩展独立服务/HTTP 行为场景即可,不必重构关系图或 Agent 测试。
6. 五问最小性门禁
| 问题 | Structural | Burden | Determinable | Gratuitous | Overfitted |
|---|---|---|---|---|---|
| W1 | 共享关联写入遵循父实体项目域 | 无新调用参数 | state 可推导归属 | 只增加 membership;最小 | 所有项目/文件/目录统一适用 |
| W2 修订版 | 句界不切数字 token | 无新开关 | 邻接字符可确定 | 先改线上单一路径,不强制跨模块抽象 | 不是只替换 10.5 |
| W3 修订版 | 原文与派生字段同次更新 | 无用户类型字段 | text/path 可推导 | 两写入点共用本地函数即可 | 所有 contextual 原文变化统一适用 |
比上述更小的 UI 补丁不能修复存储对象;比上述更大的通用解析/迁移/同步层没有本批证据支持。计划门禁按修订版通过;实际 diff 尚不存在,交付后仍需读完改动并分别报告生产代码、测试净行数。
7. 验证记录、可行性与范围
本次独立写并执行(没有复用审计作者探针):
node --experimental-strip-types D:/Temp/opencode/review-fastwrite-independent.mjs退出 0,全部“缺陷存在”断言通过。脚本只读当前源码,Node stripTypeScriptTypes(mode=transform) 转译生产 ClaimService 与 analyzer;使用生产 normalizeWorkspacePath、Node SHA-256 桥接 Bun hasher,数据库/Workspace 是内存夹具,ApiError 为形状替身。这是 service 逻辑复现,未证明真实数据库落盘、HTTP/auth、项目锁并发或广播。临时探针不作为仓库回归测试交付。
本机 Node v22.23.4;Get-Command bun 未找到运行时。本次未安装 FastWrite 依赖,未运行 Bun test/typecheck/build。原报告缺 Bun 的阻碍仍在,不能把本次探针当作那些命令通过。
实施验收可行:先用临时真实 JsonDatabase/Workspace 的局部场景跑 bun test apps/server/src/claims,再用生产应用工厂覆盖 rename、save→GET claims、scan 的最短 HTTP 路径;最后 bun run typecheck 与项目正常测试门禁。安装 Bun/工作区依赖属于环境准备,不是要新增产品机制。全量基线失败需单独记录,不把无关修复塞进这三个提交。
形状复查:全仓查 analyzeClaims|claim-analyzer;apps 查 claimEvidenceLinks|claim\.numbers|claim\.surface|normalizedText 及 agent 的 claim\.type。rename link 是已证实例;refresh/list/unlink 与数据库 deleteProject 已用 claim 归属;W2 analyzer 同形实例暂缓;W3 reader 仅按实际用途评估。没有把其他 evidence 去重或 Review 工作顺手纳入。
完整逐行复核:两份 AUDIT(本报告裁决仅 FastWrite 首批)、claim-service、claim-analyzer 及测试、shared/path、根 package。局部核对 DESIGN:1-175、app:912-997/1170-1259、app.test:2090-2269、database:160-244、shared/models:1050-1129;reader 用搜索定位。远端检查覆盖分支 heads 与文件集合,不声称读完各分支全部补丁。
交付范围:本 REVIEW 文档;FastWrite 产品/测试源码、锁文件均未改,无 issue、提交或推送。
Activity
HsukqiLee commentedon Nov 10, 2026
本地实施与最终独立评审记录
基线:
d63d0ef14683684b508fecc7d713191354c5325e;本地分支:audit/2026-11-reviewed-fixes。源码已在隔离工作树完成首批实现与评审,尚未 commit/push/提交 PR。 因此以下是本地验证交付,不代表已合入、部署或远端 CI 通过;issues 保持开放。后续审计项仍按父报告计划排队。
FastWrite issues #7 / #8 / #9 实施记录
日期:2026-11-10。工作树:
Q:/FullStack/fastrd/worktrees/fast-write;本地分支:audit/2026-11-reviewed-fixes;HEAD:d63d0ef14683684b508fecc7d713191354c5325e。1. 交付结论
三项修复已完成,相关回归、类型检查和构建通过;独立只读评审未发现 P1/P2 阻断问题。全量测试已运行两轮,仍非全绿,具体失败与环境限制见第 5 节。
接续时先检查 status、完整工作区 diff 与暂存区 diff,并全文读取根
AUDIT-fast-write.md、REVIEW-fast-write.md。当时没有生产源码 diff,唯一已有任务改动是未跟踪的 159 行claim-service.test.ts;本次完整保留,没有删除或重写。所有源码、测试及本文档编辑均使用apply_patch,shell 均使用绝对 workdir。已重新核对 issues #7/#8/#9 正文、open PR(空)、实时远端 heads(main 与 HEAD 一致),以及本地 20 条未合入远端分支对 claims 目录的 diff(均无交集)。没有 commit、push、创建 PR 或修改 issue。
2. 实现与验收
#7:项目 rename 作用域
缺陷类是关联表写入遗漏父实体作用域;规则是项目级写入只能影响该项目的实体及关联。
claim-service.ts在现有 mutation 中从项目全部 claim 推导 ID 集,约束 workspace evidence rename。claim 本体路径不在被改名目录、但 evidence 位于其中的关联也能更新。精确路径、目录前缀、anchor.path 同步规则保持。真实 JsonDatabase/Workspace 回归覆盖 A/B 同名文件与目录子项、A main claim 引用另一 evidence 文件、相似前缀不匹配、B 全对象与 supported 不变,并重新打开数据库核对落盘结果。新增 HTTP 场景经生产
createApplication → PATCH files → GET claim-links/claims验收文件重命名。#8:小数句界
缺陷类是句界拆开词法 token;规则是数字内部点号不能终止句子。
service 本地句子遍历保留原文件 offset,只在点号两侧均为数字时跳过终止。其他
.!?、换行、未终止尾句、最短长度、候选条件、stable ID、occurrence 与合并流程保持。未增加 parser、依赖或共享扫描层。回归覆盖
10.5%.、-2.75 ms!、3.25\%?、实际换行、同一行两句、TeX 字符、原文 slice、准确 start offset、重复扫描 ID/数量与 evidence 保留。转义百分号仍按既有数值规则提取数值,不新增 unit 语法。#9:重锚语义更新
缺陷类是同一对象的原文与派生字段来自不同版本;规则是写入当前原文时同步派生语义。
在同一 service 中抽取原有
claimSemantics(text, path),扫描与 contextual reanchor 共用。更新 type、surface、normalizedText、numbers;无数值时显式覆盖并删除旧 numbers。path 继续参与 caption surface 判定。保留 ID、createdAt、createdBy、evidence link;文字变化继续使 supported 降为 needs-review。精确文本仅移动的分支保持原人工状态,既有 workspace evidence stale 校验保持。
回归覆盖 10→20、去数字、result→limitation、citation/caption surface、重复 list 稳定、后续 scan 不复制、身份/关联与持久化一致,以及有效 waiver 支持下纯位置移动保持 supported。HTTP 场景覆盖 scan 小数后经 PUT save→GET claims 改为 limitation/citation 并清除 numbers。
3. 净行数与最小性
以下相对 HEAD,包括未跟踪测试;不能只用
git diff --stat漏算新增文件。apps/server/src/claims/claim-service.tsapps/server/src/claims/claim-service.test.tsapps/server/src/claims/claim-http.test.ts文档位于仓库外的总根目录:本文 +95 行,
REVIEW-fast-write-implementation.md+33 行,文档合计净 +128 行,不计入产品/测试净行数。五问门禁:修复一般作用域、数字边界与派生一致性;调用者没有新字段/选项;归属与语义均从 state/text/path 推导;仅 service 内两个小函数;没有按项目名、数值或特定句子打补丁。模型、API、数据库结构、锁文件与依赖声明均无变更。
4. 红绿测试与环境准备
安装 Bun 到工具目录:
npm install --prefix D:/Temp/opencode --no-save bun,实际版本 1.4.4 (38afee6c8)。执行bun install --frozen-lockfile:检查 163 installs / 218 packages,无锁文件变更。命令通过进程 PATH 加入D:/Temp/opencode/node_modules/bun/bin。bun test apps/server/src/claimsbun test apps/server/src/claims/claim-http.test.tsEPERM;类型检查发现新代码的可选 normalizedText 与测试泛型错误,已修正bun test apps/server/src/claimsbun test apps/server/src/app.test.ts --test-name-pattern 'Claim|claim|citation'bun run typecheckbun run buildbun test apps/server/src/sync/github-sync-service.test.ts --timeout 30000git diff --check生产测试使用真实临时数据库/Workspace,HTTP 使用生产应用工厂;没有替换内部模块或增加测试专用生产接口。HTTP 回归沿用现有 testApplication 默认的非登录模式,未新增双账号鉴权验证。
5. 全量结果与限制
bun run test的工具调用在长运行后返回Unknown: ChildProcess.kill,未拿到可信完整结果;检查后无遗留 Bun 进程。随后使用日志保留完整输出重新执行。bun run test:453 pass / 5 fail / 4 errors,458 tests / 95 files,242.00 秒。完整日志:D:/Temp/opencode/fast-write-full-test.log。失败为:未构建的 SPA 邀请入口返回 404、两份缺失 evaluation JSON、两个 Git sync 用例超过默认 5000ms。超时后的清理另触发 EBUSY、writer guard 与临时 remote 不存在错误。bun run test --timeout 30000:452 pass / 6 fail / 2 errors,458 tests / 95 files,275.12 秒。日志:D:/Temp/opencode/fast-write-full-test-prepared.log。SPA 与 Git sync 已通过;仍缺evaluation/social-research-skills/integrations.json、evaluation/agent-writing-skills/integrations.json。git ls-tree -r HEAD -- evaluation/agent-writing-skills evaluation/social-research-skills为空,证实这些 fixture 在当前基线也未跟踪。\%unit、历史污染/截断 claim 迁移、W4 workspace 去重、W5 Review 去重。没有浏览器、真实 LaTeX、真实 LLM 或外部 GitHub 同步的端到端验证。6. 同类形状复查
使用专用 Grep,对 apps 的
*.ts搜索claimEvidenceLinks|claim\.numbers|claim\.surface|normalizedText|analyzeClaims|claim-analyzer,独立评审另外覆盖*.ts*与claim\.type。7. 独立评审
实现完成后另启 OpenCode
plan只读会话,模型heyi/gpt-6.1-sol,会话ses_e3cef3caeffeTM1s70C0jnNGWB。要求独立全文读取批准报告、原版与当前 service、完整 diff、两份测试,未提供实施者的测试结论。评审返回:无有证据的 P1/P2 阻断问题,最小性通过;记录非阻断余量:候选-only 输入的显式覆盖、workspace evidence 失效下纯位置移动的专门用例,以及目录测试仅证明 service 前缀契约。评审未修改文件、未执行测试。详情见根
REVIEW-fast-write-implementation.md。本次产品 diff 在评审后未再更改。最终独立评审
FastWrite issues #7 / #8 / #9 独立交付评审
日期:2026-11-10。独立只读 OpenCode
plan会话:ses_e3cef3caeffeTM1s70C0jnNGWB,模型heyi/gpt-6.1-sol。本文由实施会话整理该评审实际返回的结论;评审本身未写文件或运行测试,动态结果见IMPLEMENTATION-fast-write.md。决定
未发现本次修复中有证据支持的 P1/P2 阻断问题。 三项实现符合
REVIEW-fast-write.md收缩后的交付范围,关键回归场景已有对应测试。最小性通过。核对证据(路径相对 worktrees/fast-write)
apps/server/src/claims/claim-service.ts:119-122在同一次 mutation 从项目全部 claim 推导 claimIds,再限定 workspace link。没有误缩为自身 anchor 位于改名路径的 claim。精确路径/目录前缀与双 path 更新保持。claim-service.test.ts:32-75覆盖另一文件 claim 的 evidence、相似前缀、B 全对象不变、持久化重读;claim-http.test.ts:30-49经生产 PATCH 路由验收。claim-service.ts:238-247仅数字两侧的点号不终止,其他标点、换行、尾句契约保持;:26-33仍使用整句长度和原候选谓词。stable ID、occurrence、合并及关联保留未改。claim-service.test.ts:78-103使用真实换行/负号/反斜杠,验证正负小数、独立句子、slice/offset、重复扫描 ID/link。claim-service.ts:225-232,250-257扫描与 contextual 重锚共用本地语义函数,surface 接收 path。无数字返回显式 undefined,覆盖后删除旧 numbers。保留身份/创建信息/关联,继续 supported→needs-review;exact 分支不新增状态重置,workspace stale 校验保留。claim-service.test.ts:108-159覆盖数值替换/删除、类型/surface、重复 list/scan、有效 waiver 下移动;HTTP 覆盖见claim-http.test.ts:52-79。非阻断覆盖余量
最小性
生产仅
claim-service.ts:+32/-10,净 +22。保留 service 测试 159 行,新增 HTTP 测试 80 行。没有新依赖、schema、配置或调用参数;两个本地函数分别承载句界修正和两写入点共用派生逻辑,未发现不必要的机制扩张。评审实际阅读范围
全文:根
AUDIT-fast-write.md、REVIEW-fast-write.md;当前与 HEAD 原版claim-service.ts;claim-service.test.ts、claim-http.test.ts;claim-analyzer.ts及其测试;packages/shared/src/path.ts;根 package.json;完整工作区与暂存区 diff。局部逐行:
app.ts:245-389,900-1009,1145-1264;app.test.ts:2090-2269;storage/database.ts:100-264;workspace/workspace-service.ts:80-124,200-324;packages/shared/src/models.ts:1040-1139。另搜索关联写入和 reader,搜索命中不计作文件全文已审。限制与评审完整性
评审未运行 Bun test、typecheck、build,没有动态验证并发、鉴权会话与磁盘落盘。analyzer 小数问题是前置批准报告明确暂缓项;历史数据恢复未验证。
git diff --check通过;评审前后 status 相同。全程未改文件、未 commit/push/PR,shell 使用指定绝对 workdir。评审完成后生产代码和测试未再改动。