{"assessments":[],"deployments":[],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"71795ef5-5b6d-4920-874f-4d9602433609","kind":"skill:build-website","nodes":[{"acceptedSubmissionHash":"bc9c2ab2295a4fe2c05cffd20d02c8120a1f3ccec99dcc071921b20ea3a2649d","dependsOn":[],"execution":{"mustProduce":["dist/index.html"],"network":true,"optionalTools":["browser"],"profile":"none","requires":["network"],"skillHash":"a60bc8b42446c13d993341179fe13c712a5addb118fc532fb2d15e71f912efc8","skillId":"build-website","tools":[]},"key":"build_website","kind":"code","role":"implement","skillHash":"a60bc8b42446c13d993341179fe13c712a5addb118fc532fb2d15e71f912efc8","skillId":"build-website","state":"accepted"},{"acceptedSubmissionHash":"587e9182f7def788139bb1d2ce75233daf463642e451c191f2787d95d6e3f648","dependsOn":["build_website"],"execution":{"network":true,"optionalTools":["browser"],"profile":"none","requires":["network"],"skillHash":"fd33b6741366d364a55a4c0ba2bc4f5d329cec0b62f27a83289dc5b30ab03575","skillId":"design-critic","tools":[]},"key":"design_critic","kind":"code","role":"review","skillHash":"fd33b6741366d364a55a4c0ba2bc4f5d329cec0b62f27a83289dc5b30ab03575","skillId":"design-critic","state":"accepted"}],"objective":"# 开发 Crypto 个人投资记账网页应用\n\n## 1. 项目目标与范围\n\n开发一个可长期使用的个人 Crypto 投资记账网页应用，适配电脑和手机，中文界面。参考现有飞书记账本的业务逻辑，实现以下 5 个相互关联的板块：\n\n投资记录、持仓、法币出入金、仪表盘、币价更新。\n\n必须交付能够实际录入、保存、修改、查询和自动计算的应用，不接受仅有界面或固定示例数据的原型。\n\n## 2. 核心业务模型\n\n主要持仓固定为 BTC、ETH、BNB、SOL、USD。前四种接入行情，USD 为美元计价资金账户及统一价值展示单位。\n\n其他代币、NFT、空投、打新等均作为投资项目，只统计投入、回收、占用和未结算估值，不要求逐个追踪行情或建立代币持仓。\n\n例如用 2 SOL 投资某个短期代币，最终收回 2.6 SOL：记录项目投入和回报，SOL 持仓相应减少、增加，不需要管理该短期代币的实时价格。\n\n必须区分：\n\n- 实际成本：已经花出的核心资产，应扣减余额。\n- 占用资金：仍属于核心持仓，但暂时不可用；不扣减总余额，仅减少可用余额。\n- 未结算估值：已投入项目剩余权益的手动估值，不能当作已到账资金。\n- 实际回收：已经收到的核心资产，包括返还本金和利润，应增加余额。\n\n同一笔本金不能同时按实际成本扣减，又按仍在持仓中的占用资金重复处理。\n\n## 3. 投资记录\n\n基础字段：项目名称、分类、进行中／已结束、投入日期、结束日期、账户／地址标签、关联项目、备注。\n\n资金字段：\n\n- 成本币种、成本数量。\n- 回收币种、回收数量。\n- 占用币种、占用数量。\n- 估值币种、剩余未结算估值。\n- 手续费币种、数量。\n\n资金字段的币种从 5 个主要持仓币种中选择。账户／地址仅作分类标签，不要求自动读取钱包。\n\n回收数量指实际到账总额，不是净利润。例如投入 500 USD、收到 650 USD，应填写回收 650，由系统计算盈利 150。\n\n支持新增、编辑、撤销、搜索、排序，以及按项目、分类、状态、日期、币种和账户筛选。修改或撤销历史记录后，自动重算所有关联数据；删除前确认并保留恢复或追溯能力。\n\n同一项目支持多次投入、分批回款、代币释放和部分退出。项目详情汇总所有关联流水，但关联本身不能重复记账。\n\n部分结算时，需要指定本次结转成本，剩余成本留给未结算部分。实际到账回款立即进入持仓，不受整个项目是否结束影响；预期回报只能放在估值中。\n\n全部结算后，项目剩余估值及占用应清零；存在未处理余额时提示用户。没有估值与估值为零必须区分。\n\n## 4. 持仓与计算规则\n\n按 5 个币种分别展示：当前数量、占用数量、可用数量、当前价格及价值、剩余项目估值、已结算盈亏、浮动盈亏。\n\n每个币种的基础公式：\n\n当前数量＝期初余额＋净外部入金＋实际回收－实际投入－额外手续费＋余额调整＋兑换净流入。\n\n可用数量＝当前数量－占用数量。\n\n当前价值＝当前数量×当前币价。\n\n占用／可用价值＝对应数量×当前币价。\n\n含项目估值的总资产＝核心持仓当前价值＋未结算项目剩余估值的 USD 折算值。\n\n占用资金已经包含在当前持仓中，不能再次加到总资产；已到账回款不能继续保留在未结算估值中。手续费必须明确采用单列或包含在净额中的方式，不能重复扣减。\n\n支持期初余额和带日期、原因的余额调整，调整不算投资盈利。余额异常或可用数量为负时，提示并提供来源明细。\n\n支持核心币种之间的手动兑换，一次操作同时记录换出和换入数量、日期、费用。例如 USD 换 ETH，只改变两边余额，不算外部入金，也不能将整笔换入金额当成利润。\n\n## 5. 盈亏口径\n\n同币种项目可直接计算币本位结果，例如投入 2 SOL、回收 2.6 SOL，收益为 0.6 SOL。\n\n跨币种不能直接相减，必须折算到共同单位。区分：\n\n- 历史结算盈亏：实际回收按结算时价格折算，减去对应历史成本及费用；保存价格快照，结算后不随当前行情改变。\n- 当前价值折算：使用当前行情展示资产或币本位结果今天的价值，明确标注口径。\n- 未结算浮动盈亏：剩余估值减去对应剩余成本，采用一致的折算规则。\n\n历史成本或价格缺失时标记待补充，不能默认为零。项目收益、外部入金和核心币种自身涨跌必须区分，不能将资产增长全部称为项目盈利。\n\n## 6. 法币出入金\n\n支持 CNY、HKD 与 USD 资金账户之间的出入金。\n\n字段：日期、入金／出金、法币类型、法币金额、对应 USD 金额、实际汇率、手续费、备注。\n\n每条记录选择一种法币。用户输入正数金额并选择方向，由系统处理增减：\n\n- 入金增加 USD 余额及净投入本金。\n- 出金减少 USD 余额及净投入本金。\n- 出入金不计为投资盈利。\n\n按实际成交金额计算并保存历史汇率，明确报价方向。CNY、HKD 分别统计，不能直接相加。\n\n展示累计入金、累计出金、净入金，支持日期筛选。同一笔出入金只影响余额一次，不能再通过投资记录重复入账。\n\n若实际使用 USDT／USDC，可保留实际支付币种，并明确折算为 USD 的规则。\n\n## 7. 币价更新\n\n仅自动更新 BTC、ETH、BNB、SOL 的 USD 价格，USD 计价单位为 1。\n\n使用可靠行情接口，说明来源；支持分钟级自动更新、手动刷新、可配置频率，展示更新时间和状态。\n\n接口失败时保留上次成功价格并提示过期，不得将空值或失败结果写为零。支持带标记的手动备用价格。\n\n价格变化自动更新持仓价值、占用／可用价值、项目估值折算及仪表盘；不改变实际数量、历史流水或已锁定的历史结算盈亏。\n\n其他项目不接行情，由手动估值和实际回款管理。\n\n## 8. 仪表盘\n\n汇总卡片：核心持仓总价值、可用资金、占用资金、未结算项目估值、含项目估值的总资产、已结算盈亏、浮动盈亏、净入金。\n\n图表：当前资产配比、可用资金配比、占用资金配比、含项目估值的资产配比、浮动盈亏、已结算盈亏。\n\n资产配比可用环形图，正负盈亏使用能正确表示亏损的条形图。点击币种或统计数字可查看来源项目和流水。\n\n盈亏按结算日期筛选，出入金按发生日期筛选；当前持仓明确标为当前数据。缺少估值、成本或最新价格时提示统计不完整。\n\n首版不强制历史资产曲线；如实现，必须使用真实历史快照或可靠重算，不能拿当前价格伪造历史表现。\n\n## 9. 板块联动\n\n法币出入金改变 USD 余额与净本金；项目投入扣减对应余额；资金占用只减少可用余额；实际回款增加回收币种余额并结转成本；项目估值只影响估值和浮动盈亏；币价更新只影响当前价值。\n\n上述操作以及历史记录修改、撤销，均须同步更新持仓和仪表盘。所有页面使用统一计算逻辑，一笔资金只记一次，每个汇总数字可追溯。\n\n## 10. 数据、界面与交付\n\n界面简洁，以表格和便捷录入为主，手机可正常操作。不需要 K 线、自动交易、钱包签名或社交功能。\n\n数据持久保存，刷新或重启不丢失。支持备份恢复及 CSV 导入导出，导入具备字段映射、预览、错误提示和去重。现有飞书数据可整理导入，首版不要求双向实时同步。\n\n联网部署需身份验证。禁止收集私钥、助记词或交易权限；接口密钥保存在服务端。公开演示使用虚构数据。\n\n交付完整源代码、可运行应用、数据结构与计算规则、安装部署说明、行情配置、备份恢复说明、示例数据、账务测试结果及已知限制。\n\n技术栈不限，优先易维护、可本地运行的方案。付费接口或云资源须提前说明费用。\n\n## 11. 必须通过的验收案例\n\n以下均使用虚构数据，金额为 USD 时无币价变化，无额外手续费。\n\nA．入金：期初为零，入金 1000 USD。余额与净入金均为 1000，项目盈利为零。\n\nB．投入与估值：从上述余额投入 400，剩余项目估值 450。现金余额 600，含项目估值总资产 1050，浮动盈利 50，估值不能用于支付。\n\nC．全部结算：上述项目实际回收 500。现金余额 1100，项目估值归零，已实现盈利 100，不能再次加上原估值。\n\nD．占用：另一个独立案例，期初 5 ETH，锁定其中 2 ETH，未实际花出成本。总量仍为 5，可用 3、占用 2；解锁后可用恢复 5，不产生虚假利润。\n\nE．部分退出：投入 1000，首次回收 600、结转成本 500，剩余估值 550。已实现盈利 100，剩余成本 500，浮动盈利 50；后续不能再次扣除全部原始成本。\n\nF．跨币种：投入 1000 USD，回收 0.6 ETH，结算价格为每 ETH 2000 USD。USD 减少 1000，ETH 增加 0.6，历史结算盈利 200 USD；以后 ETH 涨跌不改变该历史结果。\n\nG．兑换：USD 换 ETH，同时减少 USD、增加 ETH，不增加外部净入金，不把换入金额当利润。\n\nH．异常与修正：行情失败不归零；修改或撤销记录后，持仓与仪表盘一致更新，不发生重复扣款、重复回款或已结束项目残留估值。\n\n首版优先级：账务准确、五大板块联动、录入方便、数据可靠保存，其次是视觉美化。","parentJobId":null,"planHash":"0330a7e645e9178fb658dbd24d0a784a236c244ec86728f6f30986f9a74afae0","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"71795ef5-5b6d-4920-874f-4d9602433609","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1963-crypto"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51044","feedbackHash":"efdaebfc02211b60116b807cd280bff1fc3ff6c63982c5d0f277ac563e94ab9e","nodeKey":"build_website","submissionHash":"bc9c2ab2295a4fe2c05cffd20d02c8120a1f3ccec99dcc071921b20ea3a2649d","tag1":"verification:structural","tag2":"acceptance-v2","value":1},{"agentId":"51029","feedbackHash":"8b50444f51b245624a9a0a262f205d848052c34b630fce87cafd9a180bc0d2c8","nodeKey":"build_website","submissionHash":"ab9a7b2307b9be0926cf04e22d4eef21dc143b993452b3cea3002c1ef7ff0bb1","tag1":"verification:structural","tag2":"acceptance-v2","value":1},{"agentId":"51248","feedbackHash":"d9ecaafcf9289c61407b431042267f43d8ab01c198fd15a731106ed9e67710e5","nodeKey":"design_critic","submissionHash":"eae21aee234277ab65973bfe812fa843036b9c0c3f984c3d4a6ce873a1e5c921","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51347","feedbackHash":"d443ad293bac95db7eb34fa460c0a3f058380b5604c7d6c598cee37b7754cad3","nodeKey":"design_critic","submissionHash":"587e9182f7def788139bb1d2ce75233daf463642e451c191f2787d95d6e3f648","tag1":"review:submission","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"1df07434d1ce6b736e51a61c566fc2b3d13a73637092cbdfff50f1062ea26693","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"af9a875696459139","findings":[],"hash":"587e9182f7def788139bb1d2ce75233daf463642e451c191f2787d95d6e3f648","nodeId":"57b9fff5-7761-4bb2-922c-346ba400bd38","outcome":"completed","summary":"All five findings are confirmed fixed and nothing new reproduced. The findings file holds an empty list.\n\n| Area | Last review | This review |\n|---|---|---|\n| Brief requirements met / missing / faked | 42 / 0 / 0 | 42 / 0 / 0 |\n| Broken features | 4 | 0 |\n| Product on first screen at 390 | yes | yes |\n| taste@1 checks passed | 16 / 16 | 16 / 16 |\n| Copy findings | 1 | 0 |\n| Share card | present | present |\n\n**Verdict on each earlier finding**\n\n- **CSV dedup dropping distinct-ID rows (high): fixed.** The import now dedups by ID when one is supplied and falls back to content only for ID-less rows, at `src/csv.ts:445`. I ran the engine tests myself: two same-amount deposits with different IDs export and import as 2 entries, USD balance and net deposit 2000, and a second import adds 0 and skips 2. The author's browser run through download, preview and confirm gave the same numbers.\n- **Stale tab password change overwriting saved entries (high): fixed.** The change-password path now carries the unlocked session's own stored version into the lock-guarded write, at `src/app.ts:573`. In my own two-page Chromium reproduction, tab A persisted 3 entries and 2300 USD, the stale tab B's password change was refused with the \"changed in another tab\" error, the dialog stayed open, the stored ciphertext bytes were unchanged, the old password still decrypted 3 entries and 2300 USD, and the new password did not. Stale vault creation is also refused.\n- **Project hint not following the selected project (medium): fixed.** Both first render and the change handler call the same helper, at `src/app.ts:970`. At 390 wide the demo form shows 6 SOL by default, switching to the ETH project shows cost 0 and 2 ETH occupied, and \"new project\" hides the hint with no gap left behind. Screenshot confirms the layout closes up.\n- **Saves resetting the price timer (medium): fixed.** The timer is rebuilt only when the book ID, auto flag or interval changes, at `src/app.ts:197`. The virtual-clock run shows requests of 0, 1, 2, 3 at 45, 90, 135 and 180 seconds with a save at each point, and still 3 at 239 seconds.\n- **Dashboard slogan (medium taste): fixed.** The subtitle at `src/views.ts:99` is now the requested data-scope sentence. At 390 the total, the \"记一笔\" button and the subtitle are all on the first screen, with no horizontal scroll.\n\n**Requirements**\n\nThe list from the previous round stands unchanged. All 42 explicit requirements remain met with the same elements: the five sections, the cost / reserve / valuation / recovery distinction, partial settlement with transferred cost, cross-currency snapshots, fiat ledger with per-currency totals, price refresh that keeps the last good price, dashboard cards and charts, drill-down, encrypted persistence, backup and CSV with mapping, preview, errors and dedup, and acceptance cases A through H in the engine tests. Hosting and authentication deployment are after review. Nothing is faked.\n\n**Idea.** A quiet local ledger whose one visual idea is the single total-asset figure with its core-versus-valuation split beneath it.\n\n**Caveat.** WebKit could not launch on this machine because system libraries are missing, so the WebKit pass was not repeated this round. The changes are logic and copy only, with no new CSS, so I judged them on the Chromium runs.","treeHash":null,"usage":{"cachedInputTokens":671529,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":10180,"runtime":"claude","turns":25,"wallClockMs":213066}},{"artifacts":[],"attempt":1,"bundleHash":"88e795666dc207ff3a1b1b32478c7516646c22034ecf0be773e940de677e4332","device":"a11a254856120206","findings":[],"hash":"ab9a7b2307b9be0926cf04e22d4eef21dc143b993452b3cea3002c1ef7ff0bb1","nodeId":"6130ab8a-3f59-4255-ad8f-641c00b1893f","outcome":"completed","summary":"已完成应用，包含五大板块联动、本地加密保存、历史记录重算、CSV 导入导出及备份恢复。\n\n运行：`npm run preview`\n\n验证通过：29 项自动化测试、21 项浏览器检查、16 项设计检查。交付约 1.14 MiB。\n\n[使用与部署说明](README.md) · [验证记录](VALIDATION.md) · [设计文档](DESIGN.md)\n\n数据仅保存在本机；Safari 尚未实测。\n\nNot delivered: artifacts/validation.json, artifacts/validation.md. Under artifacts/, only this step's named outputs leave the machine.","treeHash":"1808b3ab9001ff2bafb3dc53fb3563f03c2dc38f","usage":{"cachedInputTokens":7088000,"inputTokens":215560,"model":"gpt-6-astra","outputTokens":117763,"runtime":"codex","turns":8,"wallClockMs":3351017}},{"artifacts":[],"attempt":1,"bundleHash":"a9b9b53fea148a0559d1313f15d2fe3a614c0e56b21b1bae23a387665ca29ef2","device":"42423bf7250e09c0","findings":[],"hash":"bc9c2ab2295a4fe2c05cffd20d02c8120a1f3ccec99dcc071921b20ea3a2649d","nodeId":"6130ab8a-3f59-4255-ad8f-641c00b1893f","outcome":"completed","summary":"已复现并修复全部 5 项报告，保留现有实现并重建 `dist/`。\n\n验证通过：35 项单元测试、21 项浏览器流程、10 组修订回归、taste@1 全部 16 项，以及构建和类型检查。交付约 1.16 MiB。\n\n逐条结论已写入 `.imd-responses.json`，测试与限制记录在 `VALIDATION.md`。Safari 因 WebKit 不可用，尚未验证。","treeHash":"ad382cc04612b50964b9bd04956c8c056341d5af","usage":{"cachedInputTokens":2920704,"inputTokens":139252,"model":"gpt-6-astra","outputTokens":22736,"runtime":"codex","turns":7,"wallClockMs":646864}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"468e1f512c9ac6ca","findings":[{"citation":"resolved","description":"Now: 导入对所有记录都按去掉 ID 和创建时间后的内容指纹去重，连明确带不同流水 ID 的真实交易也会跳过。\nChange to: CSV 提供流水 ID 时仅按该 ID 检查重复及内容冲突；只有未提供 ID 的行才回退到内容去重。保留两个不同 ID 的交易，并确保再次导入同一文件新增 0 条。\nWhy: 需求要求可靠保存、CSV 导入导出与去重；去重不能删除真实交易。当前应用自己的导出文件不能无损恢复到新账本。","line":443,"path":"src/csv.ts","reproduction":"1440×1000，Chromium，两个独立浏览器上下文。空账本录入两笔 2026-01-01 CNY 入金，各 7000 CNY、1000 USD、手续费 0，账户与备注留空；应用生成不同流水 ID。数据管理→导出全部 CSV；另一空账本→导入 CSV→确认导入。实测导出前 2 条，USD 余额/净入金均 2000；预览“新增 1 条 · 重复跳过 1 条”“账务校验通过”，导入后只剩 1 条、余额/净入金均 1000。预期保留不同 ID 的两笔交易、余额/净入金 2000；再次导入才应新增 0 条。引擎独立往返检查得到同一结果。","severity":"high","snippet":"      if (old || fingerprints.has(fp)) {","title":"bug: CSV 去重丢弃 ID 不同的合法同额流水，迁移后余额缩水"},{"citation":"resolved","description":"Now: 更改口令从旧标签页的 s.book 取账本，却把新 session.previous 设置成存储中的最新密文，绕过 saveVault 的并发版本检查；成功提示掩盖了已保存交易的丢失。\nChange to: 更改口令须保留当前已解锁 session.previous 作为比较基准，在保存锁内确认存储仍为该版本；发现差异就保留现有账本并要求重新解锁，禁止以旧 s.book 覆盖。创建账本也须检查创建前仍不存在账本。\nWhy: 需求要求长期可靠保存；更改口令只应改变加密凭据，不能删除已经保存的真实流水或改写余额。","line":565,"path":"src/app.ts","reproduction":"1440×1000，Chromium。标签 A 建立账本并保存两笔各 1000 USD 入金；标签 B 打开同源应用并解锁，此时两页均 2000 USD。A 再保存一笔 300 USD 入金（2026-01-02，2100 CNY，手续费 0），持久账本实测 3 条、2300 USD。B 已显示“另一个标签页已修改账本”，仍可在数据管理→更改口令输入两次新口令并保存。保存成功后以新口令解密，实测只剩 2 条、2000 USD，A 的 300 USD 交易消失。预期阻止旧页更改或重新读取最新账本再更改口令，保留 3 条及 2300 USD。","severity":"high","snippet":"  newSession.previous = localStorage.getItem(VAULT_KEY);","title":"bug: 旧标签页更改口令会覆盖另一标签页已保存的流水"},{"citation":"resolved","description":"Now: “所属项目”变化只控制新建项目字段显隐，不更新由 entryForm 最初项目生成的成本与占用提示。\nChange to: 将该提示绑定到当前 projectId；每次选择变化时使用同一 calculate 结果更新剩余成本和占用，选“新建项目”时移除旧提示并让后续字段上移。\nWhy: 录入与部分结转必须依据所选项目的真实成本，不能用另一项目的数据指导记账。","line":956,"path":"src/app.ts","reproduction":"390×844，Chromium，首次打开虚构演示→投资记录→记一笔。默认“Solana 生态探索”提示“项目剩余成本：6 SOL；占用 0”。将所属项目改为“ETH 节点计划”，实测提示完全未变；该项目详情实际是剩余成本 0、占用 2 ETH。预期选择后立即显示“项目剩余成本：0；占用 2 ETH”，选择新建项目不保留 6 SOL。","severity":"medium","snippet":"    if (group) group.hidden = input.value !== \"new\";","title":"bug: 切换所属项目后仍显示上一项目的剩余成本和占用"},{"citation":"resolved","description":"Now: 每次 commit 都调用 setupPriceTimer，先 clearInterval 再重新计时。因此频繁保存与行情无关的流水会一直推迟下一次刷新。\nChange to: 只在切换账本或实际更改自动更新设置时重建定时器，普通流水、项目和价格保存保持原有刷新计划。\nWhy: 需求要求按可配置的分钟频率自动更新；是否继续录入交易不应影响行情更新时间。","line":218,"path":"src/app.ts","reproduction":"1440×1000，Chromium，前台可见标签，Playwright 虚拟时钟。演示账本→币价更新→启用自动更新、间隔 1 分钟并保存；切到持仓，在约第 45、90、135、180 秒分别保存一条 USD 期初 1、原因“定时器审查”的流水。拦截行情接口计数：各次保存后请求数均为 0，到约第 239 秒仍为 0，最后一次保存满约 60 秒后才产生第 1 次请求。预期约第 60、120、180 秒已有定时请求，不能因普通保存持续重置。","severity":"medium","snippet":"    setupPriceTimer();","title":"bug: 保存流水会重置行情计时器，持续记账时自动更新被无限推迟"},{"citation":"resolved","description":"Now: 资产一览下写“投入有记录，收益有依据。”，这是宣传口号，没有说明当前数据与日期筛选的关系。\nChange to: 用“持仓与估值为当前数据；已结算盈亏和净入金可按日期筛选。”替换该副标题，沿用原段落样式，不增加区块。\nWhy: design-critic 的工具与仪表盘文案要求说明任务，不使用品牌口号；这里需要帮助用户理解统计口径。","line":99,"path":"src/views.ts","reproduction":"390×844 与 1440×900，首次打开 #dashboard。标题“资产一览”和“记一笔”下方均可直接看到“投入有记录，收益有依据。”；实测副标题框顶端在 390px 宽时为 y=253.58px，1440px 宽时为 y=218.39px。这是人工文案审查结果，taste@1 的 slogans 检查虽通过，未覆盖中文工具页的这条口号。预期同一位置提供具体统计说明。","severity":"medium","snippet":"title(\"资产一览\", \"投入有记录，收益有依据。\", \"new\", \"记一笔\")","title":"taste: 仪表盘标题下的口号没有说明用户正在查看的数据"}],"hash":"eae21aee234277ab65973bfe812fa843036b9c0c3f984c3d4a6ce873a1e5c921","nodeId":"57b9fff5-7761-4bb2-922c-346ba400bd38","outcome":"completed","summary":"| 审查区域 | 结果 |\n|---|---|\n| Requirements | **111 项：106 met、3 missing、0 faked、1 after review、1 needs the requester** |\n| Broken features | **4 项：2 high、2 medium** |\n| First screen，390px | **是**：资产总额与“记一笔”均可见 |\n| taste@1 | **16/16 通过** |\n| Copy | **1 项 medium / taste** |\n| Share card | **1 张 SVG；5/5 元数据齐全**，外部分享展开未验证 |\n\n发现两处会覆盖或遗漏已保存流水的问题，建议修复后再发布。完整复现、修复建议和源码证据已写入 [.imd-findings.json][findings]；应用文件未修改。\n\n| 编号 | 严重性与发现 | 实测证据及修复方向 |\n|---|---|---|\n| F1 | **high · bug：CSV 去重误删不同 ID 的合法流水** | 1440px，两笔各 1000 USD 入金导出后导入空账本，仅恢复一笔、余额变为 1000。有 ID 时应按 ID 去重。 |\n| F2 | **high · bug：旧标签页更改口令覆盖最新流水** | 1440px，另一页新增 300 USD 后，旧页更改口令使余额从 2300 回退到 2000。更改口令必须保留版本冲突检查。 |\n| F3 | **medium · bug：切换项目后成本与占用提示不更新** | 390px，从 Solana 项目切换至 ETH 节点，仍显示“剩余成本 6 SOL；占用 0”，实际应为成本 0、占用 2 ETH。 |\n| F4 | **medium · bug：保存流水不断推迟自动行情刷新** | 1440px，设置一分钟更新，每隔约 45 秒保存流水；约 239 秒内请求仍为零。普通保存不应重置行情计时器。 |\n| F5 | **medium · taste：仪表盘副标题使用口号** | 390/1440px 均显示“投入有记录，收益有依据。”；替换为“持仓与估值为当前数据；已结算盈亏和净入金可按日期筛选。” |\n\n验证结果：29/29 账务与安全测试通过；Chromium、WebKit 均完成主要录入、修改、撤销恢复、兑换与备份流程；六页 axe 检查无违规；真实行情请求成功返回四币种价格。上述边界缺陷由额外测试复现。\n\n以下逐项列出需求。`missing` 表示存在已复现的未满足情况，并非整个功能不存在。\n\n| # | 需求摘录 | 状态 | 实现或缺口证据 |\n|---|---|---|---|\n| 1 | “适配电脑和手机，中文界面” | met | [视图][views]、[样式][style]；四种宽度、双内核检查 |\n| 2 | “5 个相互关联的板块” | met | 五个业务页面，共用 [引擎][engine] |\n| 3 | “录入、保存、修改、查询和自动计算” | met | [应用][app]：表单、保存、筛选与重算 |\n| 4 | “BTC、ETH、BNB、SOL、USD”，USD 统一计价 | met | [模型][model]：`ASSETS`；[引擎][engine] |\n| 5 | 其他代币、NFT、空投、打新作为项目 | met | `Project`、分类、手动估值与回款 |\n| 6 | “2 SOL…收回 2.6 SOL”联动持仓 | met | [引擎][engine]；币本位收益测试 |\n| 7 | 实际成本扣减余额 | met | `calculate()` 的成本分支 |\n| 8 | 占用不扣总余额，只减少可用余额 | met | `reserved/available`；案例 D |\n| 9 | 未结算估值不能作为到账资金 | met | 独立 `valuationUSD`；案例 B |\n| 10 | 实际回收包含本金与利润，并增加余额 | met | 回收分支；案例 C |\n| 11 | 同一本金不得同时作为成本与占用 | met | [表单][forms] 提示及独立资金确认 |\n| 12 | 名称、分类、状态、投入与结束日期 | met | 项目表单；`status/start/end` |\n| 13 | 账户标签、关联项目、备注 | met | `Project/BaseEntry`；项目表单 |\n| 14 | 成本、回收、占用、估值、手续费币种及数量 | met | `Investment`；录入表单 |\n| 15 | 资金币种限定五种核心资产 | met | `assetOptions`；[校验][validate] |\n| 16 | 地址仅作标签，不要求读取钱包 | met | 文本标签字段，无钱包读取 |\n| 17 | 回收填实际总额，650 不是净利润 150 | met | 回收字段说明；历史成本独立结转 |\n| 18 | 新增、编辑、撤销、搜索、排序 | met | [应用][app]；`filteredEntries` |\n| 19 | 项目、分类、状态、日期、币种、账户筛选 | met | [视图][views]：`filter-form` |\n| 20 | 修改、撤销历史后自动重算 | met | `commit/calculate`；案例 H |\n| 21 | 删除前确认，保留恢复或追溯 | met | `toggleDeleted`、撤销列表、审计记录 |\n| 22 | 多次投入、分批回款、释放、部分退出 | met | 多条流水、`release[]`、FIFO |\n| 23 | 项目详情汇总流水，关联不重复入账 | met | `projectDetail`；关联字段仅为标签 |\n| 24 | 部分结算指定成本，保留剩余成本 | met | 成本批次与结转；案例 E |\n| 25 | 回款立即进入持仓，不等待项目结束 | met | 回收立即 `apply()`；部分退出测试 |\n| 26 | 预期回报只能放在估值中 | met | 表单说明；禁止未来实际流水日期 |\n| 27 | 全部结算后估值、占用清零 | met | `closed` 分支；案例 C |\n| 28 | 未处理余额提示用户 | met | 剩余成本校验与关闭确认 |\n| 29 | 未估值与零估值必须区分 | met | `null` 与 `\"0\"`；缺失值测试 |\n| 30 | 五币种数量、占用、可用、价格、价值、估值及盈亏 | met | `holdingsTable(full)` |\n| 31 | 当前数量的完整余额公式 | met | [引擎][engine] 各流水分支；A–H |\n| 32 | 可用数量＝当前数量－占用数量 | met | `h.available` |\n| 33 | 当前价值＝数量×当前币价 | met | `toUSD(h.qty)` |\n| 34 | 占用、可用价值按数量乘当前价格 | met | `reserveValue/availableValue` |\n| 35 | 总资产＝核心价值＋剩余项目估值 | met | `total`；案例 B/C |\n| 36 | 占用不能再次加到总资产 | met | 总资产公式；案例 D |\n| 37 | 已回收资金不能继续计入估值 | met | 回款要求更新估值或关闭项目 |\n| 38 | 手续费口径明确，不重复扣减 | met | 单列说明；费用扣款及分摊测试 |\n| 39 | 期初、带日期和原因的余额调整 | met | 调整表单；必填原因校验 |\n| 40 | 调整不算投资盈利 | met | 调整分支不计入结算 |\n| 41 | 异常、负可用余额提示及来源 | met | `issues`、`sourceDetail` |\n| 42 | 一次兑换记录双边数量、日期、费用 | met | `ExchangeEntry`、兑换表单 |\n| 43 | 兑换不是外部入金或项目利润 | met | 兑换分支；案例 G |\n| 44 | 同币种计算币本位结果 | met | `Settlement.native`、项目详情 |\n| 45 | 跨币种折算共同单位 | met | `recoveryUSD/costUSD`；案例 F |\n| 46 | 历史结算使用价格快照，后续行情不改变结果 | met | `HistoricalMoney.price`；案例 F |\n| 47 | 当前价值折算明确标注口径 | met | “今日折算（非历史盈亏）”及当前数据标记 |\n| 48 | 浮动盈亏按一致规则比较估值与剩余成本 | met | `valuationUSD − basis`；口径说明 |\n| 49 | 缺少历史成本、价格时待补充，不当零 | met | `nullableSum`、缺失值展示与测试 |\n| 50 | 区分项目收益、外部入金、核心币价变化 | met | 独立收益、净入金、当前价值指标 |\n| 51 | CNY、HKD 与 USD 账户出入金 | met | `CashEntry`、出入金页面 |\n| 52 | 日期、方向、法币及 USD 金额、汇率、费用、备注 | met | 出入金模型及表单 |\n| 53 | 一条一种法币，正数金额配合方向 | met | 现金校验与符号处理 |\n| 54 | 入","treeHash":null,"usage":{"cachedInputTokens":3946368,"inputTokens":150442,"model":"gpt-6-astra","outputTokens":29758,"runtime":"codex","turns":9,"wallClockMs":966480}}],"verification":[{"checks":[],"detail":"paths and tree verified; no suite was run for this kind of work","evaluation":"structural","profile":"none","status":"accepted","submissionHash":"ab9a7b2307b9be0926cf04e22d4eef21dc143b993452b3cea3002c1ef7ff0bb1","verifiedTreeHash":"1808b3ab9001ff2bafb3dc53fb3563f03c2dc38f","verifierVersion":"0.1.0+d952fceb"},{"checks":[],"detail":"paths and tree verified; no suite was run for this kind of work","evaluation":"structural","profile":"none","status":"accepted","submissionHash":"bc9c2ab2295a4fe2c05cffd20d02c8120a1f3ccec99dcc071921b20ea3a2649d","verifiedTreeHash":"ad382cc04612b50964b9bd04956c8c056341d5af","verifierVersion":"0.1.0+d952fceb"}]}