Per-wallet lot tracking: end-to-end wiring, IRS FAQ tests, and LTCG fix#155
Open
macanudo527 wants to merge 13 commits into
Open
Per-wallet lot tracking: end-to-end wiring, IRS FAQ tests, and LTCG fix#155macanudo527 wants to merge 13 commits into
macanudo527 wants to merge 13 commits into
Conversation
gain_loss.py: change >= to > in is_long_term_capital_gains() so that exactly 365 days is correctly classified as short-term. IRS defines long-term as "more than one year" (IRC §1222), not "one year or more". test_gain_loss.py: four new tests covering IRS Digital Assets FAQ scenarios that had no unit-level coverage: - test_ltcg_boundary: 365 days = STCG, 366 = LTCG, leap-year edge case - test_earn_type_income_recognition: HARDFORK, AIRDROP, MINING, STAKING, WAGES, INCOME all produce ordinary income at FMV with zero cost basis (Rev. Rul. 2019-24, Notice 2014-21, Rev. Rul. 2023-14, FAQ Q57-61) - test_donate_gift_disposal_gain_loss: DONATE/GIFT disposals use the same proceeds-minus-basis formula as SELL (FAQ Q75-78) - test_holding_period_resets_after_exchange: received asset holding period starts fresh on exchange date regardless of prior lot age (Q74) - test_fee_out_transaction_gain_loss: FEE-typed disposal recognises gain/loss on crypto used purely to pay a network fee (FAQ Q97) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CLAUDE.md: new codebase guide for Claude Code covering architecture, design conventions, common commands, and a per-test IRS authority map for test_gain_loss.py. user_faq.md: added IRS rule citations and guidance notes to seven sections — airdrops (Rev. Rul. 2019-24), hard forks (Q103-107), mining (Notice 2014-21 Q8), staking (Rev. Rul. 2023-14), wages (FAQ Q57-61), crypto-to-crypto swaps (Q74 holding period reset), and intra-transaction fees (Q81/Q97). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three new tests in test_gain_loss.py covering IRS rules not previously exercised: purchase fee increases cost basis (Q8/Q56), earned crypto carries FMV-at-receipt as basis for subsequent sale (Q13/Q59), and crypto-to-crypto exchange triggers gain/loss on the disposed asset (Q16-Q17/Q64-Q66). Each test links directly to the relevant IRS FAQ anchor. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add compute_tax_per_wallet to tax_engine.py: runs TransferAnalyzer to split universal InputData into per-wallet InputData objects, computes gain/loss for each wallet (passing in_transaction_2_actual_amount so partial lot amounts are respected), and merges results into a single ComputedData. Also fix _create_unfiltered_gain_and_loss_set to forward in_transaction_2_actual_amount to the accounting engine so per-wallet partial amounts are honoured in the universal path too. Wire into rp2_main.py with a -w/--per-wallet CLI flag; transfer semantics default to the first loaded accounting method. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Document the per-wallet data flow alongside the existing universal path, expand the key classes table with Account/PerWalletTransactions/ TransferAnalyzer/GlobalAllocator, list the new per-wallet test files, and add known-limitations entries for artificial InTransactions, cost_basis_timestamp LTCG behaviour, TransferAnalyzer ordering requirements, and the incomplete state of GlobalAllocator. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GitHub URLs rate-limit the link checker with 429 responses; retrying resolves the false positives without needing to ignore the links. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Apply black reformatting to 12 files, fix a line-too-long in global_allocation.py, move a pylint disable to the def line in abstract_accounting_method.py, and add W0222/W0511 to .pylintrc (RP2Decimal operator narrowing and TODO markers are intentional project patterns). Pylint now exits 0 at 10.00/10. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ini section - global_allocation.py: use 'not in' instead of 'not x in' (flake8 E713) - rp2_main.py: replace assert with explicit RP2RuntimeError raise (bandit B101), remove duplicate ComputedData type annotation on else branch (mypy no-redef), add RP2RuntimeError import - mypy.ini: remove stale [mypy-rp2.per_wallet_tax_engine] section for file that no longer exists (was causing mypy warn_unused_configs note) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…w_any_expr for test_input_parser - mypy.ini: remove show_none_errors (dropped in mypy >= 1.0, now unrecognized option) - mypy.ini: add [mypy-test_input_parser] disallow_any_expr = False — zip over TransactionSet yields Union[T, Any] which fires disallow_any_expr throughout the loop body; same pattern as other test files in this project - test_input_parser.py: remove 6 now-redundant # type: ignore comments that warn_unused_ignores was flagging once disallow_any_expr was suppressed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ator '2025-01-01 00:00:00 +0000' (space-separated tz offset) raises ValueError on Python 3.10; support for that form was added in 3.11. Use the standard ISO 8601 form '2025-01-01T00:00:00+00:00' which works on Python 3.8+. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Investopedia returns 402 for automated link checkers. Replace all four affected links in supported_countries.md with stable Wikipedia articles: - fifo.asp / lifo.asp / hifo.asp → FIFO_and_LIFO_accounting - averagecostmethod.asp → Average_cost_method Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Collaborator
Author
|
I took the work that was already done and set Claude Code to it to fix the remaining issues. I asked for it to use the IRS for guidance on digital assets taxes and build out the test cases. It should cover all the major cases, and there are links to the rules that the test cases are testing. Everything looks sound to me, but I'd like to hear your opinions on it of course. Hopefully you'll have time over the next few months to work through everything. Let me know if you have questions. |
jayr0d
reviewed
Jun 7, 2026
jayr0d
reviewed
Jun 7, 2026
jayr0d
reviewed
Jun 7, 2026
Address PR eprbell#155 review comments and expand jargon throughout: - Fix gift basis rules (IRC §1015): restructure around appreciated vs. depreciated property rather than sale-price comparisons - Add &edition=prelim to all uscode.house.gov URLs - Expand FICA/FUTA acronyms on first use - Define "lot" and "lot fraction" on first use - Replace get_long_term_capital_gain_period() function reference with plain English - Expand "Rev. Rul." to "Revenue Ruling" on first use - Clarify "out-currency"/"in-currency" with plain-English definitions - Expand 501(c)(3), annual gift tax exclusion, carry-over basis, impermanent loss, LP tokens, collectibles, CME, BSC/BNB - Rewrite mark-to-market, open positions, and loss carryback in plain English - Add opening explanations for DeFi bridging and reflexive tokens - Fix circular "dominion and control" explanation in staking section - Replace all "RP2 primitives" with "RP2's basic transaction types" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
compute_tax_per_walletend-to-end via a new-w/--per-walletCLI flag: runsTransferAnalyzerto split universalInputDatainto per-walletInputDataobjects, computes gain/loss per wallet (respectingin_transaction_2_actual_amountpartial lot amounts), and merges results into a singleComputedData. Also fixes_create_unfiltered_gain_and_loss_setto forward partial amounts to the accounting engine.is_long_term_capital_gains()now uses>(strictly greater than 365 days) instead of>=, and usescost_basis_timestampso the original acquisition date survives wallet-to-wallet transfers. A holding period of exactly 365 days is short-term per the IRS "more than one year" rule (IRC §1222).test_gain_loss.pycovering rules not previously exercised:CLAUDE.mdwith per-wallet architecture documentation: data flow diagrams for both universal and per-wallet paths, expanded key-classes table, per-wallet test file descriptions, and known-limitations entries for artificial InTransactions,cost_basis_timestampLTCG behavior,TransferAnalyzerordering requirements, and the incomplete state ofGlobalAllocator.Test plan
pytest --tb=native --verbose)-wflag accepted; correctly errors on input data missing explicit intra-transactions between wallets (expected behavior — per-wallet mode requires all transfers to be recorded)-m fifowithout-w) unchanged🤖 Generated with Claude Code