Review: Late-Game Lock: exit management + PositionTracker integration

review-1751-2026-07-04 Review

review ready

Verdict: READY

Re-review: Previous review was NEEDS_REFINEMENT due to missing arch-rails note. That note now exists (id 2347, status active). All checks pass.

Template Completeness

  • [x] Type -- Feature
  • [x] Lineage -- Sub-ticket of #4, third of 3 sub-tickets
  • [x] Repo -- ldraney/prediction-assistant
  • [x] User Story -- As a trader, exit management for profit/loss
  • [x] Context -- Explains PositionTracker integration and auto_sell_vs_hold
  • [x] Architecture -- References arch-rails note (extra section, not required)
  • [x] File Targets -- 2 modify + 2 do-not-touch
  • [x] Feature Flag -- none (acceptable, no flag infra exists)
  • [x] Acceptance Criteria -- 5 criteria
  • [x] Test Expectations -- unit + edge cases + integration, run command provided
  • [x] Constraints -- 4 constraints
  • [x] Checklist -- PR, tests, no unrelated changes
  • [x] Related -- project, parent, dependencies

Traceability

  • [x] story:watchdog-trading label -- Watchdog Trading
  • [x] story note verified -- found in project-prediction-assistant user-stories section (key: watchdog-trading, role: Trader)
  • [x] arch:rails label -- Rails architecture component
  • [x] arch note verified -- arch-rails note exists in pal-e-docs (id 2347, note_type: architecture, status: active, title: "Rails Architecture: Prediction Assistant")
  • [x] Forgejo issue -- #70, open

File Targets

  • [x] app/services/late_game_lock_bot.rb -- does not exist yet; correctly depends on #68 (entry logic) which will create this file. Issue says "extend" which is accurate given the sequencing dependency.
  • [x] test/services/late_game_lock_bot_test.rb -- does not exist yet; same dependency on #68. Correct sequencing.
  • [x] app/services/position_tracker.rb (NOT touch) -- verified: exit_candidates(bot:) at line 138, exit_signal at line 273, STOP_LOSS_THRESHOLD at line 32, TAKE_PROFIT_THRESHOLD at line 33 all present.
  • [x] app/services/order_service.rb (NOT touch) -- verified: place_order(bot:, ticker:, side:, ...) at line 72, accepts side: "sell".

Repo Placement

OK. Issue filed on ldraney/prediction-assistant, all file targets are in this repo. Single-repo scope.

Dependencies

  • #4 (parent, board item 1689) -- in todo column
  • #66 (sibling, board item 1747) -- in todo: event dispatch wiring + dual-trigger evaluator. Transitive dependency.
  • #68 (sibling, board item 1749) -- in backlog: entry logic + OrderService integration. Direct dependency documented in Lineage. This ticket creates late_game_lock_bot.rb that #70 extends.
  • #24 PositionTracker (board item 1711) -- in validation (merged). Provides exit_candidates/exit_signal.
  • #23 OrderService (board item 1710) -- in validation (merged). Provides place_order.
Dependency chain: #66 -> #68 -> #70. Predecessors correctly sequenced. Merged dependencies (#24, #23) confirmed in codebase.

Acceptance Criteria

5 criteria, all testable by an agent:
  • process_exit calls PositionTracker.exit_candidates -- verifiable via unit test mock
  • Stop-loss sell via OrderService -- verifiable
  • Take-profit sell (auto_sell_vs_hold = "sell") -- verifiable
  • Take-profit hold (auto_sell_vs_hold = "hold") -- verifiable, logs signal but no sell
  • Idempotency: no duplicate sell orders -- verifiable via pending trade check
Test expectations align with criteria. Run command: rails test test/services/late_game_lock_bot_test.rb.

Blast Radius

  • No existing bot implements exit management via PositionTracker -- this is the first consumer of exit_candidates/exit_signal.
  • PregameStackerBot has zero exit logic. BulkSweepBot has no exit logic either.
  • Pattern established here will likely be reused by other bots, but scope is correctly limited to Late-Game Lock.
  • auto_sell_vs_hold config key validated in LateGameLockConfig (line 26), accepts "hold" or "sell" -- aligns with AC.

Decomposition Assessment

2 file targets in 1 repo, 5 acceptance criteria (at threshold), estimated agent time ~3-5 minutes. No decomposition needed.

Recommendation

No action needed.