Skip to content

Claude/optimistic mendel g1xjts - #176

Open
jkirkmannz wants to merge 4 commits into
ed-donner:mainfrom
jkirkmannz:claude/optimistic-mendel-g1xjts
Open

Claude/optimistic mendel g1xjts#176
jkirkmannz wants to merge 4 commits into
ed-donner:mainfrom
jkirkmannz:claude/optimistic-mendel-g1xjts

Conversation

@jkirkmannz

Copy link
Copy Markdown

No description provided.

jkirkmannz and others added 4 commits September 12, 2026 14:43
…80985157

Add Claude Code GitHub Workflow
Consolidates the unified MarketDataSource interface, GBM simulator,
and Massive API client into one canonical design doc reflecting the
as-built implementation in backend/app/market/, including fixes
applied during code review (top-level massive import, public
GBMSimulator.get_tickers(), corrected SSE generator typing).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GAiyqJ7iF92GJvyR5FtPYD
Copilot AI lite review requested due to automatic review settings September 12, 2026 03:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

An unresolved critical workflow permission issue and multiple correctness findings remain.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds market-data design documentation and updates Claude PR-review workflows to support inline comments.

Changes:

  • Documents market-data architecture, lifecycle, SSE, APIs, and testing.
  • Enables Claude inline review comments.
  • Updates the Claude CLI permission example.
File summaries
File Summary and findings
planning/MARKET_DATA_DESIGN.md Adds the market-data design reference. Findings: Moderate (3 votes): ticker removal must advance _version; timestamp=0 must be preserved; empty snapshots must be emitted; and in-flight polling must not re-add removed tickers. Moderate (1 vote): gate cache mutations after simulator shutdown. Moderate (3 votes): create a fresh router per factory call. Moderate (2 votes): normalize simulator tickers at the API boundary. Nit (1 vote): preserve held positions when removing tickers; initialize _client in the polling example; mark missing app wiring as pending or implement it. Nit (2 votes): update the test count from 17 to 19.
.github/workflows/claude.yml Updates the commented CLI permission example. Nit (1 vote): retain the documented Bash(gh pr:*) matcher form.
.github/workflows/claude-code-review.yml Enables inline review comments. Critical (3 votes): grant pull-requests: write; read permission causes comment creation to fail with 403.
Review details

Suppressed comments (6)

.github/workflows/claude.yml:49

  • This changes the Claude Code permission matcher from Bash(gh pr:*) to Bash(gh pr *). The Claude Code command definitions use the command:* form for prefix matches; the space form is not the documented matcher and may fail to allow gh pr subcommands when this example is uncommented. Keep the colon form or use an exact command rule.
          # claude_args: '--allowed-tools Bash(gh pr *)'

planning/MARKET_DATA_DESIGN.md:305

  • This contract is not met by the implementations shown below: after SimulatorDataSource.stop() leaves _sim set, add_ticker() can still call cache.update(), and both implementations' remove_ticker() still mutate the cache after stop. A request after shutdown can therefore change the cache. Gate mutators on a running state (or clear/disable it) and add a regression test.
        Safe to call multiple times. After stop(), the source will not write
        to the cache again.

planning/MARKET_DATA_DESIGN.md:1148

  • This route example unconditionally calls source.remove_ticker() after deleting the watchlist row, but the next section says held positions must remain tracked for valuation. Following this earlier snippet would remove prices for open positions. Include the position check here too, or clearly mark this as pseudocode that must not be copied.
    await source.remove_ticker(ticker)

planning/MARKET_DATA_DESIGN.md:1280

  • _poll_once() returns immediately when _client is None, but this example never assigns source._client; it will leave the cache empty and make both assertions fail. Add the same source._client = MagicMock() setup used by the actual test before calling _poll_once().
        source = MassiveDataSource(api_key="test-key", price_cache=cache, poll_interval=60.0)
        source._tickers = ["AAPL", "BAD"]

planning/MARKET_DATA_DESIGN.md:1068

  • This section is presented as implemented, but the checkout has no backend/app/main.py or other FastAPI app wiring: nothing creates the lifespan, starts the source, or mounts this router. As written, /api/stream/prices and the background feed are not exposed despite the status claiming the design is complete; either mark this integration as pending or add the application wiring before making that claim.
## 13. FastAPI Lifecycle Integration

The market data system starts and stops with the FastAPI app via the `lifespan` context manager.

**In `backend/app/main.py`:**

planning/MARKET_DATA_DESIGN.md:1002

  • The stream sends full snapshots, but this guard suppresses the event when the snapshot is empty. Even after a removal increments the cache version, deleting the last ticker will therefore never send {} and clients cannot clear their stale entry. Serialize and yield the empty snapshot whenever the version changes.
                if prices:
                    data = {ticker: update.to_dict() for ticker, update in prices.items()}
                    yield f"data: {json.dumps(data)}\n\n"
  • Files reviewed: 3/3 changed files
  • Comments generated: 7
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

plugins: 'code-review@claude-code-plugins'
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
prompt: '/code-review:code-review --comment ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
claude_args: '--allowedTools "mcp__github_inline_comment__create_inline_comment"'
If this is the first update for the ticker, previous_price == price (direction='flat').
"""
with self._lock:
ts = timestamp or time.time()
Comment on lines +223 to +224
with self._lock:
self._prices.pop(ticker, None)
Comment on lines +838 to +842
try:
price = snap.last_trade.price
# Massive timestamps are Unix milliseconds -> convert to seconds
timestamp = snap.last_trade.timestamp / 1000.0
self._cache.update(ticker=snap.ticker, price=price, timestamp=timestamp)

- **`massive` is a top-level import**, not a lazy one. Since `massive>=1.0.0` is a core dependency in `pyproject.toml` (not optional), the module-level import is simpler and — importantly — makes `unittest.mock.patch("app.market.massive_client.RESTClient")` work directly in tests without `create=True`.
- **Error handling is deliberately resilient**, not defensive-for-its-own-sake: a bad ticker's snapshot is skipped and logged (`AttributeError`/`TypeError`), a wholesale poll failure (network error, 401, 429) is logged and the loop simply tries again next interval. The cache retains its last-known values in the meantime — stale data displayed is preferable to the feed dying.
- **Ticker normalization** (`.upper().strip()`) happens in `add_ticker`/`remove_ticker` so watchlist input from the UI or LLM chat doesn't need to pre-sanitize ticker casing.
This factory pattern injects the PriceCache without module-level globals.
"""

@router.get("/prices")
|---|---|---|---|
| `test_models.py` | 11 | 100% | `PriceUpdate` computed properties, `to_dict()` |
| `test_cache.py` | 13 | 100% | Update/get/remove, version counter, first-update-is-flat |
| `test_simulator.py` | 17 | 98% | GBM math correctness, add/remove ticker, Cholesky rebuild, edge cases |
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