Files
market/agents/invoice-organizer
Yige 406bc10bcc fix(invoice-organizer): 钉死三个索引文件的顶层结构 / pin the index file schemas (#127)
## 问题 / Problem

真机对比同一个 Agent 两个版本产出的索引文件:

```
v1.0.0  ledger.json  {schemaVersion, updatedAt, records:[…]}                              数组
v1.0.1  ledger.json  {schemaVersion, invoices:{…}, suspectedDuplicates, quarantined}      字典

v1.0.0  files.json   {schemaVersion, updatedAt, files}      emails.json  {schemaVersion, updatedAt, emails, note}
v1.0.1  files.json   {schemaVersion, files}                 emails.json  {schemaVersion, emails}
```

技能原文只写了一句「`ledger.json` 发票主键 → 记录(主索引)」——**容器键名从未钉死**,于是同一个 Agent
在不同轮次产出了两种不兼容结构,`updatedAt` 也时有时无。

台账、报告、幂等判据**全部从索引派生**,键名一漂,跨轮次和外部工具就都对不上。这与已修的归档路径那条同源:**规格没说死的地方就会漂**。

The skill only said "`ledger.json` maps invoice key to record" — the
container key was never pinned, so the same agent produced two
incompatible shapes across runs. Everything (ledger spreadsheet, report,
idempotency) derives from these index files.

## 改动 / Changes

- 把三个索引文件的顶层形状写成 jsonc 范例,**容器键名与嵌套形态钉死**(`invoices` / `files` /
`emails` 都是字典,外加 `schemaVersion` 与 `updatedAt`;`ledger.json` 另有
`suspectedDuplicates` 与 `quarantined`)
- 明确 **「读到旧形态时不要重写容器」**:顶层出现 `records` 就一路沿用
`records`,只增改里面的条目。理由写进技能——容器一换,旧版写过、当前规格没覆盖的字段会**静默丢掉**,而用户毫无察觉
- 判据给成一句可照做的话:`records` → 沿用 `records`;`invoices` → 用 `invoices`;新建才用
`invoices`

## 为什么不做自动迁移 / Why no auto-migration

升级路径已实测(v1.0.0 目录被 v1.0.1 接手):Agent
**读得懂旧结构并原样保留**,台账记录数不变、幂等成立,还顺手修正了历史上错误的归档路径。既然读兼容已经成立,把容器强行规范化只会带来「丢字段」风险而没有收益。本
PR 把这个已被验证正确的行为**写成规则**,而不是引入新行为。

The upgrade path was verified in a real run: v1.0.1 reads the legacy
shape and preserves it, with zero duplicate ledger entries. This PR
codifies that verified behavior instead of introducing migration.

## 版本与 pin / Version and pin

同 #120 / #121 的两步发布约束:本 PR 只改技能内容,**不动版本号与 `contentSource.ref`**——pin
必须指向已合并的 commit,那个 SHA 在本 PR 合并前不存在。版本号、pin 与 changelog 留到后续 PR。

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 02:57:31 -04:00
..