Files
fa-agent/docs/remaining-issues-2026-09-26.html
T
2026-09-26 01:12:10 +08:00

78 lines
23 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>财务 Agent:剩余问题与修复清单 · 2026-09-26</title>
<style>
:root{color-scheme:light;--ink:#202925;--muted:#57635d;--line:#d7dfda;--green:#17664f;--red:#a52b40;--amber:#875408}*{box-sizing:border-box}body{margin:0;background:#f7f9f8;color:var(--ink);font:15px/1.8 system-ui,-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;letter-spacing:0}header{background:#fff;border-bottom:3px solid var(--green);padding:32px 22px}header>div,main,footer{max-width:1120px;margin:auto}main{padding:0 22px 40px}h1{font-size:30px;line-height:1.4;margin:8px 0}h2{font-size:23px;margin:0 0 14px}h3{font-size:18px;margin:0 0 10px}p{margin:8px 0}small,.muted{color:var(--muted)}nav{display:flex;flex-wrap:wrap;gap:10px 22px;padding:18px 0}a{color:var(--green);text-underline-offset:3px}section{padding:25px 0;border-bottom:1px solid var(--line)}article{padding:18px 0;border-top:1px solid var(--line)}article:first-of-type{border-top:0}.notice{padding:16px 20px;border-left:4px solid var(--amber);background:#fff4de;margin:20px 0}.critical{border-color:var(--red);background:#fff0f1}.ok{color:var(--green)}.p0{color:var(--red)}.p1{color:var(--amber)}.tag{font-size:13px;font-weight:700}table{width:100%;border-collapse:collapse;background:#fff}th,td{padding:11px;border:1px solid var(--line);text-align:left;vertical-align:top;overflow-wrap:anywhere}th{background:#eaf0ed}ul,ol{padding-left:23px}li{margin:6px 0}code{font-size:13px;overflow-wrap:anywhere}pre{white-space:pre-wrap;background:#edf1ef;padding:14px;overflow-wrap:anywhere}.table-wrap{overflow-x:auto}footer{padding:24px 22px;color:var(--muted)}@media(max-width:640px){h1{font-size:25px}h2{font-size:21px}main{padding-inline:16px}th,td{padding:8px;font-size:13px}.table-wrap table{min-width:650px}}@media print{body{background:#fff}nav{display:none}section,article{break-inside:auto}h2,h3{break-after:avoid}.table-wrap{overflow:visible}a{color:inherit}header{padding:10px 0}main{padding:0}.notice{border:1px solid #777}}
</style>
</head>
<body>
<header><div><small>TRACEIQ / 工程现状与发布门禁 / 2026-09-26 / Asia/Singapore</small><h1>财务 Agent:剩余问题与修复清单</h1><p>面向下一轮开发、财务验收及生产部署。按当前源码和最近完成的测试记录整理,不将历史计划或测试通过等同于商用准入。</p></div></header>
<main>
<nav aria-label="报告目录"><a href="#summary">结论</a><a href="#baseline">已完成与测试</a><a href="#bugs">需要修复的代码问题</a><a href="#gaps">剩余功能</a><a href="#gates">外部门禁</a><a href="#sequence">推荐顺序</a><a href="#acceptance">验收清单</a></nav>
<section id="summary"><h2>一、结论与阅读方式</h2>
<div class="notice critical"><strong>目前不能认定达到生产环境商用标准。</strong><p>公式导出、说明页、对话追问、新增公式列、个人定义保存复用与证据分页已经实现;仍有需要修复的安全/交互边界、未完成的产品能力,以及必须在目标 Excel、数据库、基础设施和业务审批环境关闭的门禁。</p></div>
<p><strong>本次交付仅新增本报告,不修改业务代码、不执行新的数据库迁移。</strong>以下“已完成”包括此前连续开发完成的改动;“静态确认”指源码可直接看出的行为,尚未新增专项复现测试,不能冒充测试复现结果。</p>
<ul><li><strong>P0:</strong>影响敏感文件安全、核心财务正确性或生产准入,正式上线前必须关闭。</li><li><strong>P1:</strong>影响日常操作可靠性、可解释性、协作和可维护性,应在受控试用前或紧接其后完成。</li><li><strong>P2:</strong>扩展能力,按合同范围和真实业务优先级开发,不因存在依赖或设计稿就视为已实现。</li></ul>
</section>
<section id="baseline"><h2>二、当前已经完成什么</h2>
<div class="table-wrap"><table><thead><tr><th>能力</th><th>已完成状态</th><th>不能据此推断的内容</th></tr></thead><tbody>
<tr><td>公式工作簿</td><td>版本 3,流式生成计算明细、汇总、使用说明、参数口径、人数去重、原始证据、对账;有自定义列时增加自定义指标页。</td><td>不是任意 Excel 模板生成器;不是全部输入/结构变化都能正确重算。</td></tr>
<tr><td>对话新增列</td><td>描述不全时追问,补充后确认;服务端校验表达式树及数据映射可用性。支持既有指标、常数、加减乘除。</td><td>真实外部模型未完成联调;自然语言适用范围不等于执行任意筛选、聚合规则。</td></tr>
<tr><td>个人定义库</td><td>按用户与数据集隔离,保存、同名更新、列出、载入、删除;保存和导出时校验;迁移文件 0004 已存在,隔离测试库已执行。</td><td>不是团队共享定义库;没有草稿续聊、版本审批、并发编辑冲突保护。非测试环境是否迁移仍需核对。</td></tr>
<tr><td>证据与文件导出</td><td>本期/基期切换、每页 50 条及翻页;CSV/XLSX 证据以临时文件和 FileResponse 分块发送;金额文本和公式注入防护保留。</td><td>前端仍用 Blob 接收完整下载文件;临时磁盘/tmpfs、并发容量尚无生产 SLA。</td></tr>
<tr><td>导出可靠性</td><td>任务专属路径、0600 文件与 0700 目录、失败状态恢复、随机临时文件、授权范围检查、过期清理。</td><td>并非所有符号链接异常路径都安全,见 F01;也未完成磁盘故障及生产崩溃恢复演练。</td></tr>
</tbody></table></div>
<h3>最近完整测试记录</h3>
<ul><li><strong>后端:65 passed,95.12 秒;finance 覆盖率 87.63%,85% 门槛通过。</strong>SQLite 测试,包含定义库及导出回归。</li><li><strong>真实公式重算:4 项 LibreOffice 测试通过。</strong>覆盖自定义汇总、变化率、金额编辑联动、零成本、缺基期和 direct/lookup 毛利。不能替代 Microsoft Excel 实机。</li><li><strong>浏览器:3 passed,1 skipped,24.7 秒。</strong>新隔离数据库,覆盖追问、保存定义、关闭重开、复用后生成,另含桌面、手机、证据翻页及下载。AI 响应采用 mock;分页第 51 条交互使用 mock 响应,后端分页另有 API 测试。</li><li>跳过项:未设置 <code>REFERENCE_DATASET_NAME</code> 的原附件全量 UI 用例,不属于通过项。</li><li>此前已通过 Ruff lint/format、TypeScript/Vite、Django check、迁移一致性检查;2026-09-24 的 npm 生产依赖审计与 pip-audit 为零已知漏洞。这些不是本报告生成时重新运行的结果。</li><li>历史合成容量基准:100,000 行生成 25.96 秒,产物约 16.22 MB,峰值 RSS 约 136.4 MB;单机单次、非并发、非目标 Excel 重算性能。</li></ul>
<p class="muted">现有 acceptance.md / improvement-roadmap.html 仍存在 61 项测试、“没有定义库”等旧表述;历史 Excel 计划也有相互矛盾的状态提示。当前状态以本报告与最近完成的实测为准,后续应统一维护单一验收入口。</p>
</section>
<section id="bugs"><h2>三、需要继续修复的代码问题</h2>
<article><div class="tag p0">F01 · P0 · 静态确认 · 文件安全</div><h3>失败清理可能沿符号链接父目录删除非任务文件</h3><p><strong>位置:</strong><code>finance/exporting.py → process_formula_export()</code>。先设置 target,再检查 target.parent 是否为符号链接;拒绝后进入异常分支,仅检查 path.is_symlink(),未检查父目录。父目录为链接而最终文件本身为普通文件时,unlink 会跟随父目录删除链接目标下同名文件。</p><p><strong>影响:</strong>需要本地存储目录被操纵这一前提,不能描述为普通远程用户已可利用;但违背“异常清理只删除自己创建的文件”的边界。</p><p><strong>推荐修复:</strong>路径完整验证前不要将目标登记为可清理文件;只清理本次实际创建、且位于受控目录中的文件,必要时用目录描述符及不跟随链接的文件操作。不要用失败清理代替旧孤儿文件回收。</p><p><strong>验收:</strong>父目录链接到受保护目录,预置同名文件;执行必须失败且受保护文件字节不变,任务为 failed;覆盖根目录链接、目标链接、写盘失败与正常重试。</p></article>
<article><div class="tag p1">F02 · P1 · 静态确认 · 故障清理</div><h3>清理失败被忽略,敏感孤儿文件缺少回收路径</h3><p><strong>位置:</strong><code>finance/exporting.py</code> 与 <code>cleanup_formula_exports.py</code>。异常清理吞掉 OSError 后清空 job.path;清理器主要处理已成功且过期的文件及旧 .tmp,失败任务残留 .xlsx 可能不再被追踪。</p><p><strong>修复:</strong>记录不含敏感数据的清理失败日志及任务编号,为安全范围内的孤儿 .xlsx 制定保留期与回收规则;不要删除仍处于活动任务的文件。</p><p><strong>验收:</strong>注入 unlink 权限错误,任务失败状态仍保存;可观察到告警,恢复权限后回收成功,其他任务文件不受影响。</p></article>
<article><div class="tag p1">F03 · P1 · 静态确认 · 证据弹窗</div><h3>重复点击当前期间可能让已加载列表停在“加载中”</h3><p><strong>位置:</strong><code>frontend/src/dialogs.tsx → EvidenceDialog.selectSide()</code>。第 0 页点击当前已选期间会清空 result,但 side/page 没变化,依赖这些值的 effect 不会重新请求。</p><p><strong>修复:</strong>同期间同页直接返回,或明确触发刷新;补加载、空集、失败重试状态。</p><p><strong>验收:</strong>当前期间重复点击、快速本期/基期切换、第二页切期间、空列表和请求失败均不显示过期数据或永久加载。</p></article>
<article><div class="tag p1">F04 · P1 · 静态确认 · 定义复用后的对话</div><h3>载入已保存定义后追问,没有把原定义带给模型</h3><p><strong>位置:</strong><code>FormulaExportDialog.loadDefinition()/send()</code>。载入定义会清空 messages,随后只发送新增描述;“把刚才公式改成乘以 100”之类指代不能可靠关联已载入表达式。</p><p><strong>修复:</strong>在可见、经同意的对话上下文中明确附带原定义,或建立服务端定义引用;仍要求重新确认,不让旧定义静默覆盖新解释。选择空选项也应同步清理当前定义,避免选择状态与预览不一致。</p><p><strong>验收:</strong>保存 A、重开载入 A、发送依赖 A 的修改,检查模型请求实际包含 A;未发送补充时禁止生成,修改后生成的公式符合新定义。</p></article>
<article><div class="tag p1">F05 · P1 · 静态确认 · 定义库并发与审计</div><h3>50 条上限不是原子约束,同名更新没有冲突检测</h3><p><strong>位置:</strong><code>finance/formula_views.py → formula_definitions()</code>。先 count 再 update_or_create,并发不同名字可能突破上限;同名更新采用最后写入覆盖,未携带 revision。保存/删除与审计也不在同一外层事务内。</p><p><strong>修复:</strong>事务内锁定稳定的用户/数据集所属行,原子检查配额;引入 revision 和 409 冲突响应;变更和审计一同提交,保存增加合理限流。前端明确同名更新行为。</p><p><strong>验收:</strong>PostgreSQL 并发保存不能产生第 51 条;两个标签页更新不静默丢失;模拟审计写入失败后定义变更回滚。</p></article>
<article><div class="tag p1">F06 · P1 · 静态确认 · 工作簿可解释性</div><h3>“产品毛利率可编辑”说明与实际公式引用不一致</h3><p><strong>位置:</strong><code>finance/exporting.py → 参数与口径 / GrossCalc</code>。参数页毛利率写成字典文本并标为可编辑,实际明细公式引用每行 MarginRate,修改参数页文本不会联动。说明页还提到“本页分组维度”,但没有完整的维度键与显示名称字典。</p><p><strong>推荐:</strong>近期明确参数页为只读快照,写清需要修改计算明细的哪类输入;如必须按产品统一模拟,则实现真实产品毛利率参数表与 lookup 依赖,并验证 direct 毛利不受影响。</p><p><strong>验收:</strong>每个标为可编辑的输入都对应真实依赖;收入、成本、原价、直接毛利、lookup 毛利率分别改值重算,说明页列出字段、单位、来源、缺失含义和固定结构边界。</p></article>
<article><div class="tag p1">F07 · P1 · 静态确认 · 财务校验范围</div><h3>对账采用统一 0.01 阈值,自定义公式没有独立服务器参考</h3><p><strong>位置:</strong><code>finance/exporting.py → 对账检查</code>。人数、金额、比率共享差异阈值;对小数形式的比率,0.01 是一个百分点,未必适用业务。自定义列标记“需业务验收”,不是自动对账通过。</p><p><strong>修复:</strong>财务批准后按指标配置比较规则:人数严格相等、金额按币种和舍入精度、比率独立阈值;用 Decimal 白名单表达式解释器计算自定义指标参考,不能执行任意代码。保持原始金额文本不变。</p><p><strong>验收:</strong>阈值边界、大数、抵消、极小值、除零、缺失和多层表达式独立黄金样例通过;不得为消除报错而放宽容差。</p></article>
<article><div class="tag p1">F08 · P1 · 验证缺口 · 权限撤销与任务生命周期</div><h3>执行/下载阶段需要覆盖角色撤销、超时与崩溃恢复</h3><p>当前有组织、任务所有者、科室范围检查,但 worker 不重新要求 admin/analyst 角色;下载接口也未声明同创建接口的角色白名单。是否允许被降为 viewer 的账号下载旧导出,需要明确政策,不能默认授权语义已完整。</p><p><strong>推荐:</strong>敏感公式工作簿在申请、执行、下载时统一核验角色、组织、账户有效性和科室;补任务超时、重复请求、过期下载、worker 发布后崩溃的测试及运维告警。</p><p><strong>验收:</strong>排队后撤权、成功后撤权均按签署政策处理;半成品不能下载;重启不重复发布或无限停留 processing。生产 PostgreSQL 锁语义单独验证。</p></article>
</section>
<section id="gaps"><h2>四、尚未完成的功能与产品边界</h2>
<div class="table-wrap"><table><thead><tr><th>优先级 / 功能</th><th>当前缺口</th><th>建议与完成标准</th></tr></thead><tbody>
<tr><td>P1 · 新列出现在网页汇总表</td><td>当前新增指标主要进入导出的自定义指标页,并未成为主分析表持久化可计算列。</td><td>若原需求包含网页表格,需新增受控服务器计算、列选择与展示;网页结果、导出公式、Decimal 参考使用同一语义,缺失不转零。</td></tr>
<tr><td>P1 · 多列编辑与定义生命周期</td><td>API 最多 10 列,但对话弹窗生成时仅提交当前单列;未完成草稿续聊、版本历史、团队共享和审批。</td><td>先做当前数据集的多列列表与显式确认,后做草稿。个人定义保存复用已完成,不应重复开发。团队共享另设权限和版本策略。</td></tr>
<tr><td>P1 · 适用范围与表达式能力</td><td>scope 为说明文本,实际按当前分组、本期/基期计算;不能表达任意条件、跨明细新聚合、任意 Excel 函数、维度列或其他缺失策略。</td><td>模型明确拒绝不支持范围,不用自然语言说明冒充已执行规则。扩展时结构化范围并加入服务端白名单及黄金测试。</td></tr>
<tr><td>P1 · Excel 编辑防误操作</td><td>人数辅助表、期间、身份、维度为固定快照;追加/删除明细不能保证全部汇总与去重同步。输入验证、公式保护、完整字段字典未全部实现。</td><td>首版推荐固定结构、明确可编辑金额列并防误操作;结构改变需重新导出。表保护不是加密或真正权限控制。</td></tr>
<tr><td>P1 · 原附件 332,830 行导出</td><td>当前产品仍限制 100,000 行 / 200 组;不能一次完整导出原附件。</td><td>推荐可审计分卷并保留全局汇总/去重口径,不能把分卷人数简单相加。备选是正式提高上限后验收内存、并发、Excel 首开和改值重算,不能仅改常量。</td></tr>
<tr><td>P1 · 结果缓存与大文件下载</td><td>openpyxl 不执行公式;未重算文件的预览/缓存读取可能为空。浏览器 Blob 下载完整驻留内存;生产 /tmp 为 tmpfs,临时文件仍计入容器内存。</td><td>明确必须由目标引擎重算;如需要服务器生成已缓存副本,独立评估计算引擎。大文件直接附件下载及临时存储配额需实测。</td></tr>
<tr><td>P1 · 高基数与可访问性</td><td>聚合分组全量返回;缺高基数结果窗口、平板专项、键盘/屏幕阅读器专项。浏览器自动测试不等于人工可访问性验收。</td><td>先测真实高基数与并发,再决定分页或 SSRM;补 focus、Esc 关闭、错误提示、表头关联与触控专项。</td></tr>
<tr><td>P2 · 扩展业务能力</td><td>多收入字段口径、消费比率、生效期毛利率、退款策略、结构占比、历史阈值、告警渠道和团队调查分派未完整实现。</td><td>先冻结业务定义,再逐项开发,不擅自以现有收入字段替代不同含义。</td></tr>
<tr><td>P2 · 跨平台与高级网格</td><td>已有响应式 Web,没有原生客户端;AG Grid SSRM/Pivot/Tree Data/Master-Detail 未完整接入。</td><td>Web 是复用基础,不等于原生交付。按真实需求和商业授权选择 PWA/桌面封装或高级网格。</td></tr>
</tbody></table></div>
</section>
<section id="gates"><h2>五、必须外部完成的发布门禁</h2>
<div class="table-wrap"><table><thead><tr><th>门禁</th><th>现状 / 责任方</th><th>关闭证据</th></tr></thead><tbody>
<tr><td>P0 · Microsoft Excel 实机</td><td>历史只读 Excel 仅确认公式可见,无法保存重算;样例分组也与预期不符。财务、QA、目标终端负责人。</td><td>在可编辑 Windows/Mac Excel 用受控样例打开、强制重算、保存;读取公式和结果缓存,改值后依赖链正确,无非预期错误与修复提示。</td></tr>
<tr><td>P0 · 财务签字与精度政策</td><td>原附件收入/实收定义有歧义,成本全缺;财务负责人。</td><td>签署收入、退款、原价、成本归属、毛利、ROI、自营、升单和容差。缺成本 ROI 保持不可用;不以技术测试替代业务认可。</td></tr>
<tr><td>P0 · AI 真实联调及隐私</td><td>外部响应主要以 mock 验证;对话文本与筛选标签可能包含敏感信息。合规、数据负责人、AI 服务负责人。</td><td>审批数据处理/出境、模型版本、留存策略;真实验证超时、拒答、限流、非法输出、复杂 schema 接受度。批准前保持 AI 关闭。</td></tr>
<tr><td>P0 · 目标基础设施</td><td>历史 Docker daemon 不可用、真实 .env 不存在;配置已交付,不等于构建和运行已验收。运维、安全。</td><td>目标镜像构建、迁移 0004、非 root/卷权限、TLS、代理、数据库认证、队列、备份恢复、日志脱敏、安全扫描与许可证通过。</td></tr>
<tr><td>P1 · 当前版本 PostgreSQL 与 SLA</td><td>最近 65 项全量是 SQLite;历史 PostgreSQL 对账/测试不能替代本版并发和锁语义。</td><td>在独立 PostgreSQL 执行当前测试、并发定义保存、worker 恢复、导出压力;记录 P95、资源预算、备份恢复 RPO/RTO。</td></tr>
<tr><td>P1 · 安全运营和许可</td><td>没有完整 SSO/MFA、自助找回、数据库 RLS、不可变审计和外部告警;并非所有产品必须全选,但必须作安全决策。</td><td>风险评估明确必需项;验证加密存储、密钥轮换、权限回收和安全审查;启用 Enterprise 前取得对应商业许可。</td></tr>
</tbody></table></div>
</section>
<section id="sequence"><h2>六、推荐修复顺序</h2>
<ol><li><strong>安全收尾:</strong>先 F01、F02、F08,明确文件清理边界与撤权政策,添加失败注入和越权回归。</li><li><strong>日常交互:</strong>修 F03、F04;补定义库删除、空选项、失败重试、快速切换和重复点击 E2E。</li><li><strong>持久化可靠性:</strong>修 F05,做 PostgreSQL 事务、配额和冲突测试;迁移验证应覆盖既有数据库。</li><li><strong>工作簿真实性:</strong>修 F06,完善输入/参数字典与保护;F07 的容差需先由财务确认,再增加独立数值对账。</li><li><strong>补齐原始用户目标:</strong>确认网页主汇总表也需要新列后,实现网页计算、多列选择与导出一致性;完成草稿续聊。</li><li><strong>发布前:</strong>解决原附件范围,执行 Excel、真实 AI、财务、安全、基础设施和并发验收。任何一项未关闭都保留明确限制,不标记“全功能商用完成”。</li></ol>
<p>没有给出未经测量的工期承诺。前三项主要由工程承担;财务口径、数据处理审批和目标环境依赖必须明确责任人,不能通过延长本地编码替代。</p>
</section>
<section id="acceptance"><h2>七、下一轮验收与交付清单</h2>
<ul><li>为每个修复加入“修复前失败、修复后通过”的专项断言;全量后端覆盖率不低于 85%,同时保留财务黄金样例。</li><li>安全回归包含父目录链接、文件权限、清理失败、撤权后执行/下载、同名定义并发更新与配额边界。</li><li>LibreOffice 和目标 Excel 分别记录版本、输入样例、公式、缓存结果与修改后差异,不合并为笼统的“Excel 测试通过”。</li><li>运行桌面/手机 E2E;指定隔离原附件数据集后执行目前跳过的用例。不得用真实生产账号或生产数据环境运行写入型测试。</li><li>Ruff、格式、TypeScript、构建、Django、迁移一致性、依赖审计通过;Docker/PostgreSQL 等环境受限项明确记录未执行原因。</li><li>交付更新后的测试记录、迁移说明、部署/回滚步骤、问题状态及新 HTML。保留历史基准,但标题应明确“历史”,消除多个文档的冲突状态。</li></ul>
<h3>源码与相关材料</h3>
<p><a href="../finance/exporting.py">公式生成与任务发布</a> · <a href="../finance/formula_views.py">定义库与导出 API</a> · <a href="../finance/views.py">证据导出与分页</a> · <a href="../frontend/src/dialogs.tsx">网页对话与证据交互</a> · <a href="../tests/">测试目录</a></p>
<p><a href="acceptance.md">既有验收记录(部分状态待同步)</a> · <a href="improvement-roadmap.html">历史路线图</a> · <a href="excel-formula-export-plan.html">最初 Excel 实施方案(历史设计,不代表现状)</a></p>
</section>
</main><footer>本报告不包含患者明细、凭据或真实财务原值。源码静态判断、已完成自动化测试、产品范围选择和正式生产验收分别记录;本报告不是上线授权。</footer>
</body>
</html>