Skip to content

chore(release): 0.7.1, with the review follow-ups to #266 - #267

Merged
eaitbrahim merged 1 commit into
mainfrom
release/0.7.1
Aug 13, 2026
Merged

chore(release): 0.7.1, with the review follow-ups to #266#267
eaitbrahim merged 1 commit into
mainfrom
release/0.7.1

Conversation

@eaitbrahim

Copy link
Copy Markdown
Contributor

Bumps all six distributions to 0.7.1 and closes the findings from reviewing #266 after it merged. Per docs/RELEASING.md, the release workflow refuses to set the version itself — that decision belongs in a reviewed PR.

Why the fixes ride along

#266 merged before its review findings were applied. Releasing 0.7.1 without them would bake a known-weak guard into a live-trading build, so they are here rather than in a follow-up.

Follow-ups to #266

  • test_broker_strict_flags_match_mypy_strict failed badly in its own headline case. Re-collapsing the broker block to strict = true — the exact regression the test exists to catch — made it die with a bare StopIteration from an exhausted generator, the least legible failure pytest renders. It now asserts, and the message points at the pyproject comment explaining why the block is expanded.
  • That test's warn_redundant_casts exclusion was implicit. The flag is missing from the default-vs-strict diff only because it is currently mypy's default. If that default ever flips, the flag enters expected, the test demands it in a per-module section, and mypy rejects it there as global-only — leaving the config unsatisfiable. Now excluded by name.
  • TradeOutcome used the PEP 695 type statement. get_type_hints() leaves such an alias as a TypeAliasType whose get_origin() is None, whereas the assignment form resolves through to Literal. commands.rules._declared_choices validates operator-supplied rules add --params by testing precisely get_origin(hint) is Literal. No impact today — TradeOutcome appears in no rule constructor — but it introduced the spelling that silently disables that validation, right beside the modules whose --params safety depends on the other one. Reverted to the form StopMethod/TargetMethod already use.

Tests for behaviours #266 shipped uncovered

Three new user-visible behaviours had zero coverage — all three mutations survived the entire suite. Each new test was verified to fail when its guard is removed:

  • summarize() rejecting a closed trade with no realised P&L, asserting the outcome appears in the message. The named diagnostic is the whole reason for raising: unguarded this surfaced as TypeError: unsupported operand type(s) for +: 'Decimal' and 'NoneType' from inside a generator, with no way to tell which trade caused it.
  • Both _human_dt(None) guards in the TUI. These never raised — time.localtime(None) means now — so a missing timestamp rendered the current instant as fact. Each test asserts the text says unknown and does not contain the rendered current time.

Deliberately not added: a test pinning cli.avg_hold_hours's exit_ts filter. Both SimTrade producers set outcome and exit_ts together, so outcome != "open" implies exit_ts is not None and the filtered denominator provably cannot differ from the old one. Covering it would mean fabricating a state the code cannot reach, pinning an arbitrary choice rather than a behaviour.

Version bump

All 12 version strings across 6 pyproject.toml files, plus uv.lock. The == sibling pins move too — tests/test_packaging.py fails the build if one is left behind.

Verification

  • mypy — clean, 224 source files
  • ruff check keel tests packages — clean
  • pytest2726 passed, 1 skipped (2723 + the 3 new tests)

After merge

Actions → Release → Run workflow, input 0.7.1.

🤖 Generated with Claude Code

Version bump across all six distributions (`tests/test_packaging.py` fails the
build if a sibling pin is left behind), plus the findings from reviewing #266
after it merged. Shipping a release with those still open would have baked a
known-weak guard into a live-trading build.

Follow-ups to #266:

* `test_broker_strict_flags_match_mypy_strict` died with a bare `StopIteration`
  in exactly the case it exists to catch -- someone re-collapsing the broker
  block to `strict = true`. It now asserts, and the message points at the
  pyproject comment explaining why the block is expanded.
* That test's `warn_redundant_casts` exclusion was implicit: the flag is absent
  from the default-vs-strict diff only because it is currently mypy's default.
  Were that default to flip, the test would demand the flag in a per-module
  section where mypy refuses to accept it -- unsatisfiable. Excluded by name.
* `TradeOutcome` was spelled with the PEP 695 `type` statement. `get_type_hints`
  leaves such an alias as a `TypeAliasType` whose `get_origin()` is `None`,
  while the assignment form resolves to `Literal` -- and
  `commands.rules._declared_choices` validates operator-supplied `rules add
  --params` by testing precisely `get_origin(hint) is Literal`. No effect today
  (`TradeOutcome` is in no rule constructor), but it planted the spelling that
  silently disables that validation beside the modules whose `--params` safety
  depends on it. Reverted to the assignment form used by `StopMethod`/
  `TargetMethod`.

Three new user-visible behaviours from #266 shipped untested; all three
mutations survived the whole suite. Now covered, and each verified to fail
when its guard is removed:

* `summarize()` rejecting a closed trade with no P&L, asserting the outcome
  appears in the message -- the named diagnostic is the entire point of raising.
* Both `_human_dt(None)` guards in the TUI. These never raised:
  `time.localtime(None)` means "now", so a missing timestamp rendered the
  current instant as fact. Each test asserts the text says "unknown" AND does
  not contain the rendered current time.

Not added: a test pinning `cli.avg_hold_hours`'s `exit_ts` filter. Both
`SimTrade` producers set `outcome`/`exit_ts` together, so `outcome != "open"`
implies `exit_ts is not None` and the filtered denominator provably cannot
differ. Covering it means fabricating a state the code cannot reach, which
would pin an arbitrary choice rather than a behaviour.

2723 -> 2726 tests. mypy, ruff clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@eaitbrahim
eaitbrahim merged commit 02bc86d into main Aug 13, 2026
1 check passed
@eaitbrahim
eaitbrahim deleted the release/0.7.1 branch August 13, 2026 16:28
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.

1 participant