Build stock-deep-evaluation v1: single-stock equity evaluation app

Next.js 15 + TypeScript app implementing the fully-specced first change.
Pipeline: resolve -> market data -> pure evaluation engine -> budget guard
-> analysis agent -> report.

- market-data: DataProvider interface, offline FixtureProvider (DE/SPY seeded
  from the reference example), FmpProvider (FMP free tier), TTL cache + retry.
- technicals: pure MA/volatility/swing/52-week math.
- evaluation: instrument-aware pure engine; equity branch built, ETF gated to
  "not yet supported". Reproduces the DE example (P/E 34.5, fwd 29.3, $167.6B).
- agent: AnalysisAgent interface; default Claude Code CLI transport (headless,
  subscription-backed, web-grounded), Anthropic API alternate via config.
- cost-controls: price table, spend store, monthly budget guard.
- UI: ticker search + deep-dive toggle, report view, price chart with marked
  entry/exit/stop levels, cost/budget display, ETF/not-found states.

31 vitest tests, typecheck, production build, and lint all pass. Verified
end-to-end via the API for DE, SPY, and an unknown ticker. Live Claude CLI
agent test is the documented pick-up point (see README).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-21 17:03:04 -04:00
co-authored by Claude Opus 4.8
parent 73e93e7cb4
commit 902758ce67
44 changed files with 12425 additions and 91 deletions
@@ -15,33 +15,74 @@ evaluation engine or UI.
- **WHEN** a different agent implementation is configured
- **THEN** the system uses it without changes to evaluation or UI code
### Requirement: Claude default implementation via Anthropic SDK
### Requirement: Default agent via Claude Code CLI; API as swappable alternate
The system SHALL ship a default `AnalysisAgent` backed by Claude through the
`@anthropic-ai/sdk`, targeting a current Claude model. The API key SHALL be
supplied by the user (bring-your-own-key) via configuration and never hard-coded
or committed.
The system SHALL ship a default `AnalysisAgent` that invokes the local **Claude
Code CLI** in headless mode (`claude -p --output-format json`), which runs on the
operator's existing Claude authentication (e.g. subscription) rather than a metered
API key. The system SHALL also ship an alternate implementation backed by the
Anthropic API (`@anthropic-ai/sdk`), selectable via configuration without changes
in consumers. Either way, the default model SHALL be **Claude Opus 4.8** (CLI alias
`opus`) and a per-request "deep dive" option SHALL escalate to **Claude Fable 5**
(CLI alias `fable`); the model SHALL be selectable per evaluation. Structured
narrative output SHALL be requested via the CLI `--json-schema` option (or the
equivalent structured-output mechanism on the API alternate). Any API key used by
the alternate SHALL be loaded from configuration and never hard-coded or committed.
#### Scenario: Claude produces the written thesis
- **WHEN** a valid Anthropic API key is configured and an evaluation is submitted
- **THEN** the default agent calls Claude and returns the written thesis
#### Scenario: Claude Code CLI produces the written thesis
- **WHEN** the CLI agent is configured and an evaluation is submitted
- **THEN** the system runs `claude -p` with model alias `opus` and returns the
written thesis parsed from the CLI JSON output
#### Scenario: Key sourced from configuration
- **WHEN** the app reads its configuration
#### Scenario: Deep-dive escalates to Fable 5
- **WHEN** an evaluation is requested with the deep-dive option enabled
- **THEN** the agent runs the CLI with model alias `fable` for that request
- **AND** requests without the option continue to use `opus`
#### Scenario: API alternate selected via configuration
- **WHEN** the agent transport is configured to the API alternate with a valid key
- **THEN** evaluations are served through `@anthropic-ai/sdk` instead of the CLI
- **AND** no changes to evaluation or UI code are required
#### Scenario: Secrets sourced from configuration
- **WHEN** the API alternate reads its configuration
- **THEN** the Anthropic API key is loaded from environment/config, not source code
### Requirement: Live web grounding
The agent SHALL be able to retrieve current information via its web search and
web fetch capability — the Claude Code CLI's `WebSearch`/`WebFetch` tools for the
default transport, or Anthropic's server-side web tools for the API alternate — to
source macro and news-driven facts the structured data layer does not provide:
tariff/rate developments, analyst rating and price-target changes, management
commentary, peer read-throughs, and dated catalysts. Facts drawn from the web SHALL
carry their source so the output can attribute them, and grounding SHALL be scoped
to the ticker under evaluation.
#### Scenario: Web-sourced facts are attributed
- **WHEN** the agent uses a web-sourced fact in the analysis (e.g. an analyst
target change or a catalyst date)
- **THEN** the output attributes that fact to its source
#### Scenario: Grounding degrades gracefully
- **WHEN** web search or fetch is unavailable or returns an error
- **THEN** the agent still produces the analysis from the structured evaluation
- **AND** notes that live macro/news grounding was unavailable
### Requirement: Grounded, structured written analysis
The agent SHALL base its narrative only on the supplied evaluation data and
SHALL NOT invent figures. It SHALL produce the narrative sections reflected in the
example evaluation: current standing, earnings recap and quality-of-earnings
caveats, valuation with explicit over/undervalued reasoning, macro factors, timing,
entry/exit/stop-loss rationale, bull-versus-bear, and an actionable plan. When a
data caveat or discrepancy is present in the input, the agent SHALL preserve it.
The agent SHALL base its narrative on the supplied evaluation data plus attributed
web-sourced facts, and SHALL NOT invent figures. It SHALL produce the narrative
sections reflected in the example evaluation: current standing, earnings recap and
quality-of-earnings caveats, valuation with explicit over/undervalued reasoning,
macro factors, timing, entry/exit/stop-loss rationale, bull-versus-bear, and an
actionable plan. When a data caveat or discrepancy is present in the input, the
agent SHALL preserve it.
#### Scenario: Narrative grounded in provided data
- **WHEN** the agent writes the analysis
- **THEN** every figure it cites is present in the supplied evaluation object
- **THEN** every figure it cites is either present in the supplied evaluation
object or attributed to a web source it retrieved
#### Scenario: Data caveats preserved
- **WHEN** the evaluation object flags a discrepancy or one-time item
@@ -51,16 +92,18 @@ data caveat or discrepancy is present in the input, the agent SHALL preserve it.
- **WHEN** the agent returns its analysis
- **THEN** the analysis-not-advice disclaimer is present
### Requirement: Graceful degradation without an API key
### Requirement: Graceful degradation without an available agent
When no analysis-agent key is configured, the system SHALL still return the full
structured evaluation and SHALL clearly indicate that the written narrative is
unavailable until a key is provided.
The system SHALL, when no analysis agent is available (the Claude Code CLI is not
installed or not authenticated, or the configured API alternate has no key), still
return the full structured evaluation and clearly indicate that the written
narrative is unavailable and how to enable it.
#### Scenario: No key configured
- **WHEN** an evaluation is requested and no agent API key is configured
#### Scenario: Agent unavailable
- **WHEN** an evaluation is requested and no agent transport is available
- **THEN** the structured evaluation is returned
- **AND** the response indicates the written analysis is unavailable pending a key
- **AND** the response indicates the written analysis is unavailable and how to
enable it (authenticate the CLI, or configure an API key)
### Requirement: Agent error handling