78 lines
23 KiB
HTML
78 lines
23 KiB
HTML
<!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>
|