Skip to content

feat: wire monthly income reinvest — recommendation-only default (S6-001)#101

Merged
lwalden merged 2 commits into
mainfrom
feature/s6-001-income-reinvest-wiring
Jun 11, 2026
Merged

feat: wire monthly income reinvest — recommendation-only default (S6-001)#101
lwalden merged 2 commits into
mainfrom
feature/s6-001-income-reinvest-wiring

Conversation

@lwalden

@lwalden lwalden commented Jun 11, 2026

Copy link
Copy Markdown
Owner

What / Why

Wires the IncomeSleeve_MonthlyReinvest timer to a new IIncomeReinvestService pipeline. Without this, the income sleeve (70% of the portfolio) would never produce gate evidence during the paper-validation run — the timer existed but did nothing. The first real firing is July 1, 2026 (first trading weekday of the month), ahead of the sprint deadline.

  • First-trading-weekday gate lives in code (Default D3) — NCRONTAB day-of-month/day-of-week semantics are never trusted.
  • Recommendation plan goes through the existing IncomeSleeveManager (issuer/category caps reused, never duplicated).
  • Best-effort Discord plan report via DiscordIncomeReportService (named client, 8s timeout); report failure can never fail the run.
  • S5-003 operational-alert pattern on broker-connect failure and orchestration failure.

Locked posture

IncomeSleeveConfig.OrderPlacementEnabled defaults to false — recommendation-only. The run produces a plan + Discord report and places no orders unless the owner explicitly flips the flag. This PR does not change that default, and the review fixes were deliberately constrained to comments/strings/one additive log field so the verified flag-off invariant needs no re-proof.

Test plan

  • Primary invariant test: flag off ⇒ IExecutionService is never called.
  • 36 new tests; full suite 632/632 passing locally after review fixes.
  • Host-boot smoke (this item touches Program.cs/DI): passed locally on port 7188 against a throwaway Azurite — all 4 timer functions registered, no failure signatures.
  • CI host-boot-smoke job must pass before merge.

Notes

Judge verdict: PASS with 5 fix-now items (comment/string/log-field clarity), applied in fix(review): log clarity + triage pointers for the reinvest path (S6-001). The judge-deferred A2 pattern question — optional-null ctor dependencies vs fail-fast boot failure — is recorded for DECISIONS.md Known Debt and will be added in a later item, not this PR.

🤖 Generated with Claude Code

lwalden and others added 2 commits June 10, 2026 19:34
…default (S6-001)

The reinvest timer was a TODO stub logging "complete" — its first live
firing 2026-07-01 would have silently done nothing. It now delegates to a
new IIncomeReinvestService (S5-001 thin-timer shape, null-tolerant resolve
per ADR-024) that reuses the existing IncomeSleeveManager plan generator —
the 10%/40% caps stay enforced in one place, never duplicated.

Locked decision 1 is the contract: IncomeSleeve:OrderPlacementEnabled
defaults FALSE in code, example config, and tests — the default run
computes the plan and sends a neutral Discord digest (own named client
DiscordIncomeReport, 8s bound) but NEVER touches IExecutionService. The
first-trading-weekday gate lives in code (Default D3) because NCRONTAB
DOM/DOW semantics cannot be trusted to fire exactly once. Broker connect
failure reuses the S5-003 operational-alert degrade; report failure can
never fail the run. Empty sleeve still reports "no buys proposed" as proof
the timer ran (Default D8).

Suite: 632 passing (596 -> 632, 36 RED-first). Host-boot smoke: PASS on
port 7188 with throwaway Azurite — all 4 timers register, no
TypeLoadException (the new bare IncomeConfig/ExecutionConfig factory
registrations are the S5-004r boot-crash class this gate exists for).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@lwalden lwalden merged commit 038633e into main Jun 11, 2026
5 checks passed
@lwalden lwalden deleted the feature/s6-001-income-reinvest-wiring branch June 11, 2026 02:52
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