Repository navigation
レシートの差額を「調整行」でなく各品目へ金額比で配分する - #16
Conversation
税別レシート(品目が税抜表記、合計だけ税込)を実運用したところ、差額を 「調整(税・割引等)」1行にまとめる方式に2つの問題が出た。 1. その行の負担区分が既定の折半になるため、片方の個人品目(酒・化粧品など) に掛かった消費税まで折半されてしまい、毎回手で直す必要があった 2. 1行にまとまっているので「いくらを誰に寄せれば正しいのか」を判断できず、 直すには自分で按分を計算するしかなかった 要件定義に代替案として書いていた TBD-003 の「品目金額比での自動按分」へ 切り替える。差額を各品目の金額比で配分して価格に上乗せするので、税はその 品目の負担区分にそのまま従う(酒が自分100%なら酒の税も自分100%)。 - withAdjustmentItem を distributeDifference に差し替え。端数は累積の目標値 から逆算するので、配分後の品目合計は必ずレシートの金額と一致する - マイナスの差額(総額からの値引き)も配分できるようになった。調整行では 「マイナスの品目」が作れず諦めていたケース - 品目が増えないので AI 由来の品目の上限を99件から100件に戻す - AIプロンプトの「税込金額を返す」指示をやめ、印字どおり返させる。税別レシート には税込が印字されておらず、AIが自分で税を計算しようとして不安定になるため - 配分したときは画面に「消費税などの差額を各品目に配分しました」と一言出す (品目の金額がレシート表記と変わるため) 既知の限界として、金額比の按分は税率が一律である前提のため、軽減税率8%と 標準税率10%が混在するレシートでは食品側に税が数円〜数十円多く乗る。従来の 「税を全部折半」よりは不公平が小さいので、税率別按分は残課題とした。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
Warning Review limit reached
Next review available in: 24 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
Walkthroughレシートの品目価格を印字金額として扱い、合計との差額を既存品目へ金額比で配分する処理へ変更しました。配分状態を正規化結果と画面通知に反映し、テストと仕様文書を更新しました。 Changesレシート差額配分
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant ReceiptAI
participant normalizeParsedReceipt
participant distributeDifference
participant ReceiptClient
ReceiptAI->>normalizeParsedReceipt: 抽出した品目と支払額
normalizeParsedReceipt->>distributeDifference: 品目と合計金額
distributeDifference-->>normalizeParsedReceipt: 配分済み品目と状態
normalizeParsedReceipt-->>ReceiptClient: 正規化済みレシート
ReceiptClient-->>ReceiptClient: toneに応じた通知表示
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/`(app)/expenses/new/receipt/receipt-client.tsx:
- Around line 438-441: Update the notice element rendered near NOTICE_TONE_CLASS
to expose dynamic messages to assistive technology: assign role="alert" for warn
notices and role="status" for info notices, preserving the existing styling and
notice.text rendering.
In `@docs/implementation-plan.md`:
- Around line 888-895: docs/implementation-plan.md
の実地確認記録で、現在の金額比配分方式と矛盾する「調整(税・割引等)」行の自動追加という記述を更新してください。該当する実物レシート確認記録は、品目への金額比配分結果を期待結果として記載するか、旧方式の履歴であることを明示し、現行仕様と誤認されないようにしてください。
In `@docs/requirements.md`:
- Around line 187-194:
要件定義でAI抽出値とreceipts.parseの正規化後レスポンスを明確に分離し、items[].priceがrawでは印字額、正規化後は配分結果の価格を示すことを記載してください。API(SR-001)のレスポンス契約にdistributed、distributionSkipped、sourceItemCountを追加し、配分後の価格の意味と品目合計がtotal_amountに一致する条件を明記してください。distributeDifferenceでV-403の上限超過により配分を省略した場合もdistributionSkipped等で記録する仕様に合わせ、normalizeParsedReceiptおよびreceipt-client.tsxのproducer-consumer契約と整合させてください。
- Line 526: docs/requirements.md の「TBD-003 の決着」見出しを、親見出し「8.
未確定事項一覧」の直下に適切な階層となるよう `###` レベルへ変更し、他の内容は変更しないでください。
- Around line 520-535: Synchronize the TBD-003 status and evidence across
docs/requirements.md lines 520-535, docs/implementation-plan.md lines 895-895,
and docs/verification-checklist.md lines 224-230: if the tax-exclusive receipt
was not actually verified, remove the 2026-08-02 completion date and operational
results from all three documents; otherwise, retain them only with the same
verification basis and date recorded consistently in each document.
In `@docs/verification-checklist.md`:
- Around line 224-230:
docs/verification-checklist.md内で精算端数処理に付与されているTBD-003を、未使用の別IDへ変更し、同項目を参照する関連文書のリンクや記載も新しいIDに更新してください。レシート差額配分の完了済みTBD-003は変更せず、各未解決事項が一意の識別子で追跡できる状態を保ってください。
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: fb6d57da-b072-4fb6-9043-45761d69f786
📒 Files selected for processing (9)
app/(app)/expenses/new/receipt/receipt-client.tsxconvex/ai/schema.tsconvex/ai/types.tsconvex/receipts.tsdocs/implementation-plan.mddocs/requirements.mddocs/verification-checklist.mdlib/receipt.test.tslib/receipt.ts
| <p | ||
| className={`rounded-lg border p-3 text-sm ${NOTICE_TONE_CLASS[notice.tone]}`} | ||
| > | ||
| {notice.text} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
差額通知を支援技術にも通知してください。
notice は編集画面への遷移後に挿入されますが、<p> にライブ領域がありません。スクリーンリーダー利用者が、金額の変更や確認要求を受け取れない可能性があります。warn は role="alert"、info は role="status" などの役割を設定してください。
修正例
<p
+ role={notice.tone === "warn" ? "alert" : "status"}
className={`rounded-lg border p-3 text-sm ${NOTICE_TONE_CLASS[notice.tone]}`}
>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <p | |
| className={`rounded-lg border p-3 text-sm ${NOTICE_TONE_CLASS[notice.tone]}`} | |
| > | |
| {notice.text} | |
| <p | |
| role={notice.tone === "warn" ? "alert" : "status"} | |
| className={`rounded-lg border p-3 text-sm ${NOTICE_TONE_CLASS[notice.tone]}`} | |
| > | |
| {notice.text} |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/`(app)/expenses/new/receipt/receipt-client.tsx around lines 438 - 441,
Update the notice element rendered near NOTICE_TONE_CLASS to expose dynamic
messages to assistive technology: assign role="alert" for warn notices and
role="status" for info notices, preserving the existing styling and notice.text
rendering.
| 6. **AI由来の品目数(`sourceItemCount`)が0なら**「レシートを読み取れませんでした」(レシート以外・不鮮明な画像)。成功ログもこの判定の後に出す | ||
| - [x] `lib/receipt.ts`(**純粋関数。AI呼び出しと切り分けてテストする**。`lib/settlement.ts` と同じ方針): | ||
| - AIの返り値を `expenses.save` の制約(V-402 / V-403)に均す(名前50字・金額1〜9,999,999の整数・数量1〜999、保存できない行は捨てる、品目は99件まで) | ||
| - AIの返り値を `expenses.save` の制約(V-402 / V-403)に均す(名前50字・金額1〜9,999,999の整数・数量1〜999、保存できない行は捨てる、品目は100件まで) | ||
| - **数量は品目名に畳み込んで `quantity` は常に1にする**(「牛乳 ×3」)。理由: (1) `price` は「その行の合計金額」なので `price × quantity` にすると数量ぶん二重に効く、(2) 仕分けUIに数量の入力欄が無く(Phase 5の設計)、残すと画面に出ない値が合計に効いてユーザーが読み取り誤りを確認・修正できない | ||
| - AIが `price` を単価で返してしまった場合の救済: 行合計として足すと `total_amount` に合わず、`price × quantity` なら一致するときは単価とみなして行合計に直す(どちらとも判定できなければ指示どおり行合計として扱い、ズレは調整行が吸収する) | ||
| - 品目合計 ≠ `total_amount` のとき、差額を品目 `調整(税・割引等)` として追加(負担区分の初期値は画面側の既定=折半) | ||
| - ⚠️ **差額がマイナス(品目合計 > 合計金額)のとき、または上限9,999,999円を超えるときは調整行を作らない**。金額は「1円以上9,999,999円以下の整数」(V-403)で、そのままでは `expenses.save` が必ず弾くため。代わりに `adjustmentSkipped: true` を返し、画面が「金額を確認してください」と促す(TBD-003で運用しながら見直す) | ||
| - AIが `price` を単価で返してしまった場合の救済: 行合計として足すと `total_amount` に合わず、`price × quantity` なら一致するときは単価とみなして行合計に直す(どちらとも判定できなければ指示どおり行合計として扱い、ズレは差額の配分が吸収する) | ||
| - 品目合計 ≠ `total_amount` のとき、差額を**各品目へ金額比で配分**する(`distributeDifference`)。端数は「累積の目標値との差」で決めるので、配分後の品目合計は必ず `total_amount` と一致する | ||
| - ⚠️ **配分すると1円未満に潰れる品目が出るときは配分しない**。金額は「1円以上9,999,999円以下の整数」(V-403)で、そのままでは `expenses.save` が必ず弾くため。代わりに `distributionSkipped: true` を返し、画面が「金額を確認してください」と促す | ||
| - 📌 **当初は差額を「調整(税・割引等)」1行にまとめる実装だった**(要件の初版)。税別レシートの実運用でこの行の負担区分が既定の折半になり、個人品目に掛かった税まで折半されてしまうことが分かったため、TBD-003 の代替案「金額比の自動按分」へ変更した(2026-08-02)。詳細と既知の限界(軽減税率の混在)は `docs/requirements.md > TBD-003 の決着` を参照 |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
旧方式の実地確認記録を新しい配分方式に合わせて更新してください。
Line 888-895は調整行方式を削除したと記録しています。しかしLine 927は、実物レシートで「調整(税・割引等)」行が自動追加されたと記録しています。この文書は旧方式を現在の期待結果として扱う状態です。Line 927を金額比配分の結果へ更新するか、変更前の履歴として明記してください。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/implementation-plan.md` around lines 888 - 895,
docs/implementation-plan.md
の実地確認記録で、現在の金額比配分方式と矛盾する「調整(税・割引等)」行の自動追加という記述を更新してください。該当する実物レシート確認記録は、品目への金額比配分結果を期待結果として記載するか、旧方式の履歴であることを明示し、現行仕様と誤認されないようにしてください。
| | items[].price | int | 必須 | レシートに印字された金額(円)。税抜表記ならそのまま税抜。値引きはその品目に反映 | | ||
| | items[].quantity | int | 必須 | 数量(既定1) | | ||
|
|
||
| **処理フロー**: | ||
| 1. ユーザーが画像を撮影/選択 → クライアントで縮小・圧縮 | ||
| 2. 画像を Convex File Storage へアップロード(アップロードURLはサーバー関数で発行) | ||
| 3. API(SR-001)がAIプロバイダへ画像+抽出プロンプト(JSONスキーマ指定)を送信 | ||
| 4. 応答JSONをスキーマ検証。品目合計 ≠ total_amount の場合、差額を「調整(税・割引等)」品目として自動追加(初期負担区分: 折半) | ||
| 4. 応答JSONをスキーマ検証。品目合計 ≠ total_amount の場合、差額(税別レシートの消費税、総額からの値引きなど)を**各品目へ金額比で配分**する。配分後の品目合計は total_amount と必ず一致する。配分すると1円未満に潰れる品目が出る場合のみ配分せず、画面で金額の確認を促す |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
AI抽出値とreceipts.parseのレスポンス契約を分離してください。
Line 187-188はitems[].priceをレシート印字額として定義しています。一方、convex/receipts.tsはnormalizeParsedReceiptの結果を返し、distributeDifferenceがitems[].priceを変更します。API仕様のLine 208はレスポンスを「上記出力項目のJSON」とだけ記載しています。
この記述では、正規化後の価格を印字価格として扱う実装が発生します。raw AIレスポンスと正規化後のレスポンスを分離し、distributed、distributionSkipped、sourceItemCount、配分後の価格意味を明記してください。V-403上限超過による配分省略も記録してください。
提供されたconvex/receipts.ts、lib/receipt.ts、receipt-client.tsxのproducer-consumer契約に基づきます。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/requirements.md` around lines 187 - 194,
要件定義でAI抽出値とreceipts.parseの正規化後レスポンスを明確に分離し、items[].priceがrawでは印字額、正規化後は配分結果の価格を示すことを記載してください。API(SR-001)のレスポンス契約にdistributed、distributionSkipped、sourceItemCountを追加し、配分後の価格の意味と品目合計がtotal_amountに一致する条件を明記してください。distributeDifferenceでV-403の上限超過により配分を省略した場合もdistributionSkipped等で記録する仕様に合わせ、normalizeParsedReceiptおよびreceipt-client.tsxのproducer-consumer契約と整合させてください。
| | ~~TBD-003~~ | F-003 | ~~税・割引の「調整行」方式(デフォルト折半)で実運用上問題ないか。代替案: 品目金額比での自動按分~~ **決着(2026-08-02)**: 税別レシートの運用で問題が出たため代替案(金額比の自動按分)へ変更。理由は下記 | 二人で運用確認 | 完了 | | ||
| | TBD-004 | F-010 | iOSアプリ化の方式(PWA止まり / Capacitor / ネイティブ)と時期 | 開発者 | 公開検討時 | | ||
| | TBD-005 | F-008 | 仕分けAI提案の実装時期(MVP後の最初の改善候補) | 開発者 | MVP完成後 | | ||
| | TBD-006 | 6.1 | Gemini切り替え時のプロンプト・スキーマ互換性検証(構造化出力の指定方法がプロバイダ間で異なる) | 開発者 | 切り替え時 | | ||
| | TBD-007 | F-002 | 世帯からの退出・世帯削除・アカウント削除のフロー詳細(MVPでは設定画面に最小限の導線のみ) | 開発者 | 実装時 | | ||
|
|
||
| #### TBD-003 の決着(2026-08-02) | ||
|
|
||
| 税別レシート(品目が税抜表記、合計だけ税込)を実運用したところ、調整行方式に2つの問題が出た。 | ||
|
|
||
| 1. **手直しが毎回発生する** — 差額(消費税ぶん)が「調整(税・割引等)」1行になり、その負担区分が既定の折半になる。片方の個人品目(酒・化粧品など)が金額の大半を占めるレシートでは、その品目に掛かった税まで折半されてしまうため、毎回この行の負担区分を手で変える必要があった | ||
| 2. **正しい値を判断できない** — 1行にまとまっているので「いくらを誰に寄せれば正しいのか」がユーザーには分からず、直すには自分で按分を計算するしかなかった | ||
|
|
||
| 代替案の**金額比による自動按分**に切り替えた。差額を各品目の金額比で配分して品目価格に上乗せするので、税は**その品目の負担区分にそのまま従う**(酒が自分100%なら酒の税も自分100%)。手直しも判断も不要になる。 | ||
|
|
||
| **既知の限界**: 金額比の按分は税率が一律であることを前提とするため、軽減税率(8%)と標準税率(10%)が混在するレシートでは、食品側に税が数円〜数十円多く乗る。「税を全部折半」だった従来より不公平は小さいが、完全に正確ではない。正確にするにはAIに品目ごとの税率も返させて税率グループごとに按分する必要があり、AIスキーマ・プロンプトの変更を伴うため見送った(必要になれば再検討する)。 |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== repo files likely relevant =="
git ls-files | rg '(^|/)(package\.json|README\.md|README\.html|docs/(requirements|implementation-plan|verification-checklist)\.md)$' || true
echo
echo "== docs/requirements around TBD-003 =="
sed -n '505,550p' docs/requirements.md 2>/dev/null || true
echo
echo "== docs/implementation-plan around TBD-003 =="
sed -n '885,900p' docs/implementation-plan.md 2>/dev/null || true
echo
echo "== docs/verification-checklist around TBD-003 =="
sed -n '218,235p' docs/verification-checklist.md 2>/dev/null || true
echo
echo "== search for PR purpose and receipt verification text =="
rg -n "税別|税別レシート|実機確認|TBD-003|実運用|2026-08-02|検証|PR" -i README.md docs package.json 2>/dev/null | head -200 || trueRepository: yamk12nfu/warikapp
Length of output: 30409
🌐 Web query:
github.com yamk12nfu warikapp docs requirements TBD-003 2026-08-02
💡 Result:
There is no public evidence or authoritative technical documentation linking a repository named "warikapp" under the GitHub account "yamk12nfu" to a requirements document designated as "TBD-003" for August 2, 2026. An analysis of the provided terms indicates that "TBD-003" is a generic placeholder or identifier used in unrelated contexts, including: - Chinese group standard T/TBD 003-2024 for fertilizer product sampling specifications [1][2]. - An OEM part number for Honda Accord vehicle components [3]. - A medical product code for antibiotic sensitivity discs [4]. - A track identifier for record labels [5][6]. - A placeholder reference within NASA flight software documentation [7]. The GitHub user "yamk12nfu" exists and manages various repositories related to AI agents, automation, and development utilities [8], but none of these repositories are publicly titled "warikapp," nor is there any associated "TBD-003" documentation linked to this user's profile [8][9][10][11].
Citations:
- 1: https://www.biaozhuns.com/archives/20240603/show-376622-108-1.html
- 2: https://kpt-bj.com/t-tbd-003-2024-fertilizer-product-sampling-specifications-1589131601.html
- 3: https://www.tongshirad.com/goods/detail/5033.htm
- 4: https://hospitalshop.com/product/tm-media-anti-microbial-sensitivity-disc-amoxiclav-5-x-50-discs-tbd-003
- 5: https://musicbrainz.org/label/d3d789cd-7031-4232-8d3f-fb8ac6a51572
- 6: http://www.fonorama.cz/firmy/T/TBD%20Sound.htm
- 7: https://www.nasa.gov/wp-content/uploads/2025/06/foia-msfc-slspdr-42-sls-vdd-177-slsp-flight-software-build-content-definition.pdf?emrc=5545a7
- 8: https://github.com/yamk12nfu
- 9: https://zenn.dev/yamk
- 10: https://github.com/yamk
- 11: https://github.com/yamksoft
TBD-003 の完了日と実機確認結果を同期させてください。
文書全体に 2026-08-02 の決着・実運用結果が書かれていますが、PRの説明では税別レシートの実機確認を未実施にしています。この差異は運用記録を信用できなくします。確認結果がないなら 2026-08-02 の完了日時・実運用経過を削除し、確認済みの場合は、その根拠や確認日時を3文書で揃えてください。
docs/requirements.md#L520-L535docs/implementation-plan.md#L895-L895docs/verification-checklist.md#L224-L230
🧰 Tools
🪛 markdownlint-cli2 (0.23.1)
[warning] 526-526: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4
(MD001, heading-increment)
📍 Affects 3 files
docs/requirements.md#L520-L535(this comment)docs/implementation-plan.md#L895-L895docs/verification-checklist.md#L224-L230
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/requirements.md` around lines 520 - 535, Synchronize the TBD-003 status
and evidence across docs/requirements.md lines 520-535,
docs/implementation-plan.md lines 895-895, and docs/verification-checklist.md
lines 224-230: if the tax-exclusive receipt was not actually verified, remove
the 2026-08-02 completion date and operational results from all three documents;
otherwise, retain them only with the same verification basis and date recorded
consistently in each document.
| | TBD-006 | 6.1 | Gemini切り替え時のプロンプト・スキーマ互換性検証(構造化出力の指定方法がプロバイダ間で異なる) | 開発者 | 切り替え時 | | ||
| | TBD-007 | F-002 | 世帯からの退出・世帯削除・アカウント削除のフロー詳細(MVPでは設定画面に最小限の導線のみ) | 開発者 | 実装時 | | ||
|
|
||
| #### TBD-003 の決着(2026-08-02) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
見出しレベルを###に修正してください。
Line 526の#### TBD-003 の決着は、## 8. 未確定事項一覧の直下で見出しレベルを2段階増やしています。markdownlintのMD001違反です。
修正例
-#### TBD-003 の決着(2026-08-02)
+### TBD-003 の決着(2026-08-02)静的解析(markdownlint-cli2のMD001)に基づきます。
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #### TBD-003 の決着(2026-08-02) | |
| ### TBD-003 の決着(2026-08-02) |
🧰 Tools
🪛 markdownlint-cli2 (0.23.1)
[warning] 526-526: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4
(MD001, heading-increment)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/requirements.md` at line 526, docs/requirements.md の「TBD-003
の決着」見出しを、親見出し「8. 未確定事項一覧」の直下に適切な階層となるよう `###` レベルへ変更し、他の内容は変更しないでください。
Source: Linters/SAST tools
| - [x] ~~`[!!]` 税・割引の「調整行(既定:折半)」方式が実運用で妥当か(TBD-003)~~ → **妥当でなかったので金額比の自動按分に変更した(2026-08-02)**。経緯は `docs/requirements.md > TBD-003 の決着` | ||
| - [ ] `[!!]` 軽減税率が混在するレシートで按分のズレが許容範囲か(TBD-003の残課題) | ||
| - 仕様参照: `docs/requirements.md > TBD-003 の決着`「既知の限界」 | ||
| - 実装: `lib/receipt.ts > distributeDifference` | ||
| - 観測事実: 金額比の按分は税率が一律である前提。食品8%と酒・日用品10%が混ざると、食品側に税が数円〜数十円多く乗る | ||
| - 前提条件: 軽減税率対象(食品)と標準税率(酒・日用品)が混在する税別レシートで運用する | ||
| - 期待結果: ズレが二人にとって気にならない範囲に収まっている。気になるならAIに品目ごとの税率を返させて税率グループごとに按分する(AIスキーマ・プロンプトの変更が必要) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
TBD-003 の識別子重複を解消してください。
Line 224はレシート差額配分のTBD-003を完了にしています。しかしLine 217は精算端数処理にもTBD-003を使用しています。精算端数処理の項目を別IDへ変更し、関連文書の参照も更新してください。同じIDでは未解決事項を正しく追跡できません。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/verification-checklist.md` around lines 224 - 230,
docs/verification-checklist.md内で精算端数処理に付与されているTBD-003を、未使用の別IDへ変更し、同項目を参照する関連文書のリンクや記載も新しいIDに更新してください。レシート差額配分の完了済みTBD-003は変更せず、各未解決事項が一意の識別子で追跡できる状態を保ってください。
## 端数のテストが何も検証していなかった 「端数が出ても合計が合う」テストに `[101,101,101] → 333円` を使っていたが、 333 × 101 ÷ 303 = 111 でちょうど割り切れるため、繰り上がりが1回も起きて いなかった。`[1,1,1] → 10円` に差し替え、`[3,4,3]` になることを直接確かめる (品目ごとに丸めると3円ずつで9円にしかならないケース)。 品目10件での誤差の散り方、上限9,999,999円ちょうど、上限超過の各境界も追加。 ## 配分の入力ガード - 合計金額が整数でないときは配分しない。累積の目標値を丸める前提が崩れ、 配分後の合計が totalAmount と一致しなくなるため(呼び出し元は整数に丸めて から渡すが、関数単体の契約としても保証する) - 品目合計が Infinity になる入力を弾く。あわせて配分後の判定を 「範囲内か」から「整数かつ範囲内か」に変える。比較演算は NaN に対して常に false を返すので、範囲だけを見ていると NaN の金額が素通りしていた - 上記の検査を「差額0なら何もしない」より前に置く。後ろに置くと、0円どうし・ NaN どうしのような壊れた入力を「正常」として通してしまう いずれも normalizeParsedReceipt 経由では到達しない入力だが、 distributeDifference は export しているので単体で成立させる。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codexレビュー対応指摘6件をトリアージし、このPRのスコープ内の2件(#1・#2・#6)を ced20e4 で対応した。 対応したテストの穴(指摘#6) — これが一番効いた指摘。「端数が出ても合計が合う」テストに
入力ガード(指摘#1・#2) — どちらも
テストは 205件 → 211件。 別issueに切り出したいずれもこのPRが持ち込んだ挙動ではなく以前から存在するものなので、スコープを分けた。
指摘の評価按分ロジックそのものは問題なしと判断。Codexも「production inputs では配分後の合計が |
差額0の場合の早期リターンが、合計だけを見て各品目の妥当性を見ていなかった。 1.5円 + 0.5円 = 2円 のような保存できない品目が「差額0だから正常」として 素通りし、distributed も skipped も false で返っていた。 品目1件ずつを検査する isSavableItem を足し、入力の検査でも配分後の検査でも 使う(金額 V-403: 1円以上9,999,999円以下の整数 / 数量: 1以上の整数)。 Number.isInteger を含むので NaN も弾ける。 あわせて、検査が「差額0なら何もしない」より前にあることを固定するテストを 追加した。前回のレビューで「順序を戻しても通ってしまう」と指摘された穴で、 差額0のケースを使わないと順序を検証できない。 テストが実際に効いていることを変異で確認した: - isSavableItem の検査を外す → 2件失敗 - 検査を等価判定の後ろに移す → 2件失敗 いずれも normalizeParsedReceipt 経由では sanitizeItem が先に均すので到達 しないが、distributeDifference は export しているので単体で成立させる。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codex再レビュー対応 (6395d37)指摘#4(新規)と#2の残り: 等価判定の抜け道差額0の早期リターンが合計だけを見て各品目の妥当性を見ていなかった。 品目1件ずつを検査する 指摘#3: テストが特定のガードを分離できていない「非整数の totalAmount」のテストは正当な指摘。 追加したテストが実際に効いていることを変異で確認済み:
NaN/Infinity のテストについては指摘のとおりで、 指摘#2: 退行なし
テストは 211件 → 212件( |
`receipts.parse ok ... items=4` までしか出しておらず、税別レシートで差額の 配分が走ったかどうかを後から確認する手段が無かった。保存された品目を見ても、 品目合計と合計金額がたまたま一致していると「配分が走った」のか「差額0だった」 のか区別が付かない。 distributed と skipped を足す。真偽値だけなのでレシートの中身は漏れない (要件 5.4「レシートの中身はログに出さない」)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
実機で税別レシートを読ませたところ、注記は出ていたが読み飛ばされた。原因は2つ。 1. 枠線と灰色の文字だけで背景色が無く、画面上部の常設の説明文 「レシートを撮影すると、品目と金額をAIが読み取ります。」と同じ見た目に なっていた。「このレシートで今起きたこと」を伝える一言が案内文に見える 2. 文言だけで金額が無く、ユーザーがレシートと突き合わせて確認できない 背景色を敷いて文字色を強め、配分した金額と合計を文言に入れる。 消費税などの差額 ¥354 を各品目に上乗せしました。 合計 ¥1,557 がレシートの支払額と一致していれば大丈夫です 差額が負(総額からの値引き)のときは「差し引きました」に切り替える。 金額を渡すため NormalizedReceipt に distributedAmount を足した。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
背景
税別レシート(品目が税抜表記、合計だけ税込)を実運用したところ、差額を「調整(税・割引等)」1行にまとめる方式に2つの問題が出た。
要件定義に代替案として書いていた TBD-003「品目金額比での自動按分」 へ切り替える。
変更内容
差額を各品目の金額比で配分して価格に上乗せする。税はその品目の負担区分にそのまま従う(酒が自分100%なら酒の税も自分100%)。
牛肉600円(自分100%) + にんじん400円(折半)、税込1,100円のレシートの場合:
withAdjustmentItemをdistributeDifferenceに差し替え。端数は累積の目標値から逆算するので、配分後の品目合計は必ずレシートの支払額と一致する(品目ごとに割合を掛けて丸めると1円ずれる)adjustmentSkippedで諦めていたケースexpenses.saveの上限)に戻したdocs/3点を更新し、TBD-003 を経緯ごと「決着」として記録既知の限界
金額比の按分は税率が一律である前提のため、軽減税率8%と標準税率10%が混在するレシートでは食品側に税が数円〜数十円多く乗る。従来の「税を全部折半」よりは不公平が小さいので、税率別按分(AIに品目ごとの税率を返させる)は残課題として
docs/verification-checklist.mdに確認項目を残した。確認
npx tsc --noEmitnpx vitest run— 205件パスnpx eslint .— エラーなしnpx next build🤖 Generated with Claude Code
Summary by CodeRabbit
新機能
改善