Review: Late-Game Lock: event dispatch wiring + dual-trigger evaluator
Verdict: READY
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Sub-ticket of #4, first of 3
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- As a trader, dual-trigger evaluation
- [x] Context -- PriceUpdateJob/TimeUpdateJob stubs, pattern reference to PregameThresholdJob
- [x] File Targets -- 6 files (2 modify, 4 create) + 2 files NOT to touch
- [x] Feature Flag -- none (correct, no flag infra in codebase)
- [x] Acceptance Criteria -- 5 criteria, all testable
- [x] Test Expectations -- Unit and job tests, run command provided
- [x] Constraints -- Queue, pattern, error handling, additivity
- [x] Checklist -- PR, tests, no unrelated changes
- [x] Related -- project, parent #4, #40, #29
Traceability
- [x] story:watchdog-trading label -- Watchdog Trading story
- [x] story note verified -- found in project-prediction-assistant user-stories section (key: watchdog-trading, role: Trader)
- [x] arch:rails label -- Rails architecture component
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-rails for component Rails. Note: arch:rails is used across 15+ tickets on this board as foundational infrastructure. This is a project-level hygiene item, not specific to this ticket.
- [x] Forgejo issue -- #66, open
File Targets
- [x] app/jobs/price_update_job.rb -- verified: exists, contains stub with correct parameters (ticker, series_ticker, yes_bid, yes_ask, last_price, previous_price), comment says "Consumers (Sprint 4): Late-Game Lock, Edge Learner"
- [x] app/jobs/time_update_job.rb -- verified: exists, contains stub with correct parameters (ticker, series_ticker, event_start_time, captured_at), matching comment
- [x] app/services/late_game_lock_evaluator.rb -- does not exist yet (to be created), correct
- [x] test/jobs/price_update_job_test.rb -- does not exist yet (to be created), correct
- [x] test/jobs/time_update_job_test.rb -- does not exist yet (to be created), correct
- [x] test/services/late_game_lock_evaluator_test.rb -- does not exist yet (to be created), correct
- [x] app/jobs/market_scanner_job.rb -- verified: NOT to touch, event emission already correct (emit_price_update, emit_time_update)
- [x] app/models/late_game_lock_config.rb -- verified: NOT to touch, has time_remaining_threshold validation with presets [last_5_pct, last_10_pct, last_15_pct, last_quarter], sport_filters, price_threshold range 0.5-1.0
Repo Placement
OK -- Forgejo issue filed on ldraney/prediction-assistant, all file targets are in the same repo. Single-repo change.
Dependencies
- Parent #4 (board item 1689) -- "Late-Game Lock bot -- dual-trigger consumer" in todo column. This ticket is the first of 3 sub-tickets from decomposing #4.
- #68 (board item 1749) -- "Late-Game Lock: entry logic + OrderService integration" in backlog. Downstream sibling: needs the evaluator from this ticket before entry logic can be wired.
- #70 (board item 1751) -- "Late-Game Lock: exit management + PositionTracker integration" in backlog. Downstream sibling: depends on #68.
- #29 (board item 1716) -- "Edge Learner bot" in backlog. Also consumes PriceUpdateJob/TimeUpdateJob in Sprint 6. Ticket correctly preserves Edge Learner stub comments.
- #40 (board item 1723) -- "Sport-specific game clock integration" in backlog. Correctly identified as separate concern for real-time clock; this ticket uses elapsed-time ratio from event_start_time as a simpler proxy.
No blockers: nothing in in_progress blocks this ticket. Dependency ordering is clear: #66 -> #68 -> #70.
Acceptance Criteria
5 criteria, all verifiable by an agent:
- AC 1-2: Job dispatch to evaluator -- standard job test pattern, matches existing pregame_threshold_job_test.rb structure
- AC 3: Dual-trigger logic -- unit-testable with mock config and event data. Note: the evaluator will need to query MarketSnapshot for the "other half" of the dual trigger (price data on time events, time data on price events). This is an implicit implementation detail but follows naturally from the existing MarketSnapshot model.
- AC 4: Sport filter matching -- references PregameStackerBot#qualifies? pattern (verified: lines 85-103 of pregame_stacker_bot.rb). Pattern is clear and copyable.
- AC 5: Fault tolerance -- rescue per-config, log and continue. Matches PregameStackerBot pattern (lines 48-54).
Test command is valid: rails test test/services/late_game_lock_evaluator_test.rb test/jobs/price_update_job_test.rb test/jobs/time_update_job_test.rb
Blast Radius
- PriceUpdateJob and TimeUpdateJob are shared event jobs consumed by multiple bots. The ticket correctly preserves Edge Learner stub comments for Sprint 6 (#29).
- MarketScannerJob emission is NOT changed -- the scanner already emits both PriceUpdateJob and TimeUpdateJob on every scan cycle.
- SweepEligibleJob follows the same fan-out pattern (delegates to BulkSweepJob), confirming architectural consistency.
- No other consumers of PriceUpdateJob/TimeUpdateJob exist currently beyond the stubs.
Decomposition Assessment
6 file targets in 1 repo, 5 acceptance criteria, estimated agent work under 5 minutes. The pattern is well-defined (follow PregameThresholdJob -> PregameStackerBot). No decomposition needed.
Recommendation
- [SCOPE] Create architecture note arch-rails for the Rails component. This is a project-wide hygiene item affecting 15+ board items, not specific to this ticket. Does not block implementation.