Skip to content

Per-wallet application: draft integration from upstream PR #138#1

Merged
tobomobo merged 84 commits into
mainfrom
pr138-finish
Apr 21, 2026
Merged

Per-wallet application: draft integration from upstream PR #138#1
tobomobo merged 84 commits into
mainfrom
pr138-finish

Conversation

@tobomobo

Copy link
Copy Markdown

Summary

Pulls eprbell's bottom-up per-wallet pieces from upstream PR #138 (transfer_analyzer, global_allocation) and adds the integration layer the maintainer sketched in the design doc and in issue #135. Upstream's author paused the PR in Feb 2026 citing workload. This branch:

  • Merges upstream eprbell/main into the PR branch (clean).
  • Fixes the one outstanding lint from upstream (global_allocation.py long line).
  • Adds the country-plugin + config plumbing ([application_methods] / [transfer_methods], parallel to [accounting_methods]).
  • Adds per_wallet_tax_engine.compute_tax_per_wallet that partitions universal InputData via TransferAnalyzer, runs compute_tax per wallet with a fresh AccountingEngine, and merges the per-wallet TransactionSets and GainLossSet back into a single ComputedData so report generators run unchanged.
  • Wires rp2_main to route to the per-wallet path when [application_methods] selects per_wallet for any year. Transfer semantics falls back to the accounting method of the earliest configured year (eprbell's "option 2" from USA to drop universal application: implement per-wallet application eprbell/rp2#135).
  • Merges bitcoinaustria/main (Austrian fork phases 1-8). One conflict in accounting_engine.py where upstream's per-wallet refactor added get_acquired_lot_for_timestamp and the Austrian fork added unit_cost_basis_override / taxable_event kwarg plumbing for pool-based methods; resolved by keeping both — get_acquired_lot_for_taxable_event forwards the pool override, get_acquired_lot_for_timestamp stays taxable-event-free for global_allocation.

Default behavior is unchanged: if the config omits [application_methods], Application method: universal is logged and the universal path runs exactly as before.

What is not in this PR

These still need upstream maintainer design input before being safe to implement:

  • GlobalAllocator is not wired in. It belongs at the universal → per_wallet boundary year (e.g. US 2024 → 2025); that needs a year-scoped switch and a call on how the allocation folds into 2025's opening lots.
  • Transfer semantics is a single method for the whole run. Per-year [transfer_methods] is parsed but TransferAnalyzer takes a single method today.
  • Fee-split TODOs in transfer_analyzer.py:117,119,190 and spot_price=1 in global_allocation.py:117 are untouched — these are eprbell's own # TODOs flagging open design questions.

Test plan

  • pytest — 200 passed, 108 subtests passed (previously 165, +35 from Austrian phases, +2 new per-wallet smoke tests)
  • mypy src/ tests/ — no issues in 96 source files
  • pylint -r n src tests/*.py — 9.99/10 (only pre-existing fixme TODOs)
  • bandit -r src/ — clean
  • CLI round-trip: rp2_us with [application_methods] 2020 = per_wallet against test_data.ods emits all 3 reports and logs Application method: per_wallet (transfer semantics: fifo)
  • Backwards compat: same CLI without [application_methods] logs Application method: universal

🤖 Generated with Claude Code

eprbell and others added 28 commits February 3, 2025 18:16
Extracts the missing-accounts set to a local variable so the error
message fits under 160 chars (the project's line-length cap). Behavior
is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wires the PR's bottom-up per-wallet pieces (transfer_analyzer,
global_allocation) into rp2_main by introducing the integration layer
eprbell sketched in the design doc and in issue eprbell#135:

 - AbstractCountry gains get_default_application_method /
   get_application_methods and the parallel pair for transfer_methods.
   US opts in to {"universal", "per_wallet"}; all other countries stay
   universal-only, preserving behavior.
 - Configuration parses two new INI sections, [application_methods] and
   [transfer_methods], reusing the year->method shape of
   [accounting_methods].
 - New per_wallet_tax_engine.compute_tax_per_wallet partitions the
   universal InputData via TransferAnalyzer, runs compute_tax once per
   wallet with a fresh AccountingEngine, and merges the per-wallet
   TransactionSets and GainLossSet back into a single ComputedData so
   report generators run unchanged (matches the wiki: "easy to join
   before they are passed to generators").
 - rp2_main routes to the per-wallet path when [application_methods]
   selects per_wallet for any year; transfer semantics falls back to the
   accounting method of the earliest configured year when the user
   doesn't specify [transfer_methods] (eprbell's option 2).
 - Smoke tests: per-wallet == universal when there are no transfers;
   per-wallet runs end-to-end with transfers and preserves every
   original out/intra transaction in the merged output.

Not included (still requires maintainer design input):
 - GlobalAllocator is not wired in. It belongs at the
   universal->per_wallet boundary year (e.g. US 2024 -> 2025), which
   needs a year-aware switch that this draft does not implement.
 - Transfer semantics is a single method for the whole run. Per-year
   transfer semantics and strict country-enforced year constraints are
   deferred.
 - Fee-split TODOs in transfer_analyzer.py remain untouched; the
   spot_price=1 TODO in global_allocation.py remains untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Conflicts:
#	src/rp2/accounting_engine.py
@tobomobo tobomobo merged commit 1cf6cab into main Apr 21, 2026
34 checks passed
tobomobo added a commit that referenced this pull request Apr 21, 2026
README's per-wallet warnings were verbatim upstream and didn't mention
this fork's draft PR eprbell#138 integration or Austrian support. CHANGELOG
tracked phases 1-9 but not the (non-phase) per-wallet work from PR #1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants