Initial commit: OpenSpec setup and stock-deep-evaluation change

Set up OpenSpec spec-driven workflow and fully specify the first change,
stock-deep-evaluation: a Next.js/TS app for thorough single-stock
evaluation (valuation reasoning, macro factors, entry/exit points,
stop-loss) with a pluggable data layer and Claude analysis agent.

Includes proposal, design, specs (market-data, equity-evaluation,
analysis-agent, evaluation-app), tasks, and the DE gold-standard example.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-21 15:35:54 -04:00
co-authored by Claude Opus 4.8
commit 73e93e7cb4
30 changed files with 4631 additions and 0 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-08-21
@@ -0,0 +1,112 @@
## Context
This is a greenfield Next.js + TypeScript web app that turns a single NYSE/Nasdaq
ticker into a thorough, agent-written evaluation (valuation, macro, entry/exit,
stop-loss). The target output shape is captured concretely in
`examples/de-reentry-2026-08-21.md` and encoded as requirements in the four spec
files. Constraints: bring-your-own API keys, free-tier market data by default,
rate limits, and no persistence in v1. The design must keep data-provider and
model-provider choices swappable so cost/quality decisions don't ripple into the
evaluation or UI code.
## Goals / Non-Goals
**Goals:**
- One typed pipeline: `resolve ticker → fetch data → compute evaluation → agent narrative`.
- Provider-agnostic boundaries: `DataProvider` and `AnalysisAgent` interfaces are
the only seams consumers see.
- Deterministic, testable evaluation math separated from the non-deterministic
agent prose. The structured evaluation must stand on its own even with no agent key.
- Secrets stay server-side only.
**Non-Goals:**
- Persistence, accounts, watchlists, alerts, real-time streaming, backtesting.
- Multi-ticker dashboards. (Deferred to later changes.)
- Trade execution or brokerage integration.
## Decisions
### D1 — App structure: Next.js App Router, server-side data/agent calls
Route handlers (or server actions) under `app/api/*` run the pipeline server-side;
the client is a thin report view. Rationale: keeps API keys off the browser
(satisfies the app-config spec), and lets data + agent calls share one request.
Alternative considered: client-side fetching — rejected because it would leak keys
and duplicate rate-limit handling.
### D2 — `DataProvider` interface with a free default
A single interface returns normalized models: `CompanyProfile`, `Fundamentals`
(TTM + per-FY, optional segments), `PriceHistory`, `TechnicalContext` (computed),
`AnalystCoverage`, `Estimates`. Default implementation targets a free tier
(candidate: Financial Modeling Prep or Finnhub; final pick during tasks). Each
model carries an `asOf` timestamp and `delayed|realtime` flag. Alternative:
code directly against one vendor — rejected for lock-in and testability.
### D3 — Technical indicators computed in-house, not taken from the provider
Moving averages (20/50/200), swing highs/lows, 52-week distance, volume multiple,
and realized volatility are computed from OHLCV in a pure `technicals` module.
Rationale: providers expose these inconsistently; in-house math is deterministic
and unit-testable, and it is the same input the entry/exit/stop logic needs.
### D4 — Evaluation engine is pure and provider-free
`evaluate(inputs) → Evaluation` is a pure function over normalized data. It emits
a typed `Evaluation` object (one field per spec section) with explicit
`unavailable` markers — never fabricated or zero-filled values. All entry/exit/
stop levels, implied multiples at each level, and valuation reasoning are computed
here. Rationale: the spec requires the structured object to be consumable without
the agent, and pure functions make the many numeric requirements testable.
### D5 — `AnalysisAgent` interface; Claude default via `@anthropic-ai/sdk`
The agent takes the `Evaluation` object and returns narrative sections. Default
impl calls a current Claude model, instructed to use ONLY the supplied figures,
preserve any flagged caveats/discrepancies, and include the disclaimer. Structured
output (tool/JSON schema) is preferred so the UI can render narrative per section.
Alternative: free-text prompt with the raw data — rejected because grounding and
per-section rendering are weaker. When no key is set, the pipeline returns the
`Evaluation` with `narrative: unavailable`.
### D6 — Typed results end-to-end; errors are values
Data, evaluation, and agent layers return typed results/errors (not thrown
exceptions across boundaries). A data failure, rate-limit, or agent failure each
degrade to a partial result the UI can render. Rationale: the specs require honest
partial states and readable errors.
### D7 — Caching and rate limiting at the provider boundary
An in-memory (v1) cache keyed by ticker+dataset with short TTLs sits inside the
provider layer, with retry/backoff for transient/rate-limit errors. Rationale:
free tiers are tightly limited; caching one evaluation's repeated reads avoids
burning quota. Persistence-backed cache is a later change.
## Risks / Trade-offs
- [Free-tier data is delayed/incomplete — segments, estimates, or history may be
missing] → Normalized models mark fields unavailable; evaluation and UI render
honestly; provider is swappable for a paid tier without consumer changes.
- [Agent may hallucinate numbers] → Agent receives only the structured object,
is instructed to cite nothing outside it, and prose is rendered alongside the
computed tables so drift is visible; consider a post-check that every cited
figure exists in the input.
- [Rate limits during development/demo] → Caching + backoff; a fixture/mock
provider for tests and offline work.
- [Numeric correctness of valuation/technical math] → Pure modules with unit tests
seeded from the DE example's known figures.
- [Not financial advice / liability] → Mandatory disclaimer enforced in both the
evaluation object and the agent narrative.
## Migration Plan
Greenfield — no data migration. Deployment: run locally (`localhost:3000`) with
`.env.local` holding the market-data and Anthropic keys. Rollout is incremental by
capability (see tasks): scaffold → data layer + technicals → evaluation engine →
agent → UI. Rollback is trivial (no persisted state). Keys are provided via env;
absence degrades gracefully rather than failing the build.
## Open Questions
- Which free market-data provider is the default (coverage of segments + forward
estimates varies materially)? Resolve early in tasks by spiking 2 providers on `DE`.
- Source of options-implied expected move and forward consensus EPS on free tiers —
may need a secondary source or graceful omission.
- Preferred charting library (Recharts vs. lightweight-charts) for overlaying
entry/exit/stop markers on price history.
- Whether to add an automated "every cited figure exists in inputs" guard on agent
output in v1 or defer to a later hardening change.
@@ -0,0 +1,69 @@
## Why
Retail and semi-professional investors lack a single tool that turns raw market
data into a clear, defensible thesis on whether an NYSE/Nasdaq-listed company is
over- or undervalued, why, and how to act on it. Existing screeners show numbers
but not judgment; existing chat tools give judgment but aren't wired to live
fundamentals, technicals, and macro context. This change delivers the foundation:
a web app that, given a single ticker, produces a thorough, agent-written
evaluation covering valuation drivers, macro factors, entry/exit points, and
stop-loss levels — with a data layer and agent interface designed to grow.
## What Changes
- Introduce a **Next.js + TypeScript web app** where a user searches a single
NYSE/Nasdaq ticker and receives a full evaluation report.
- Introduce a **pluggable market-data layer**: a `DataProvider` interface plus a
default free-tier provider, returning normalized company fundamentals, price
history, and technical indicators. Paid providers can be swapped in later with
no changes to consumers.
- Introduce an **equity-evaluation engine** that computes and explains: valuation
(the specific reasons a company looks over- or undervalued), relevant macro
factors affecting the stock, candidate entry and exit points, and suggested
stop-loss levels.
- Introduce a **pluggable analysis-agent layer** backed by **Claude via the
Anthropic SDK** (bring-your-own API key) that synthesizes the structured data
into a written investment thesis and the reasoning behind each recommendation.
- Scope v1 to **single-ticker deep evaluation**. Watchlist monitoring, alerts,
and multi-ticker dashboards are explicitly deferred to later changes.
## Capabilities
### New Capabilities
- `market-data`: A provider-agnostic data layer. Defines the `DataProvider`
interface and normalized data models (company profile, fundamentals/financials,
price history, computed technical indicators), plus a default free-tier
implementation and configuration for selecting a provider.
- `equity-evaluation`: The core analysis engine. Derives valuation signals and
the reasons behind over/undervaluation, identifies macro factors affecting the
stock, and computes candidate entry/exit points and stop-loss levels from price
and volatility data. Produces a structured evaluation object consumed by the
agent and UI.
- `analysis-agent`: A provider-agnostic agent interface with a default Claude
(Anthropic SDK) implementation. Takes the structured evaluation as context and
produces a written thesis: the over/undervalued argument, macro narrative, and
entry/exit/stop-loss rationale. Handles API-key configuration and graceful
degradation when no key is present.
- `evaluation-app`: The Next.js web application shell and UI. Ticker search,
request orchestration (data → evaluation → agent), and the report view that
presents fundamentals, valuation reasoning, macro factors, a price chart with
marked entry/exit/stop-loss levels, and the agent's written thesis.
### Modified Capabilities
<!-- None — this is a greenfield project; no existing specs to modify. -->
## Impact
- **New project scaffold**: Next.js + TypeScript app, Tailwind for UI, a charting
library (e.g. Recharts) for price/technical visualization.
- **New dependencies**: `@anthropic-ai/sdk` for the analysis agent; an HTTP client
and one free-tier market-data provider SDK/endpoint for the default provider.
- **Configuration/secrets**: environment variables for the market-data API key(s)
and the Anthropic API key; both treated as bring-your-own and never committed.
- **External services**: one market-data API (rate-limited free tier by default)
and the Anthropic API. Both isolated behind interfaces so cost/provider choices
can change without touching evaluation or UI code.
- **Not affected / deferred**: persistence, user accounts, watchlists, real-time
streaming, alerting, and backtesting are out of scope for this change.
@@ -0,0 +1,74 @@
## ADDED Requirements
### Requirement: Provider-agnostic analysis-agent interface
The system SHALL define an `AnalysisAgent` interface that accepts a structured
evaluation object and returns a written analysis. Consumers MUST depend only on
this interface so the underlying model provider can change without affecting the
evaluation engine or UI.
#### Scenario: Agent invoked through the interface
- **WHEN** an evaluation object is passed to the configured analysis agent
- **THEN** the agent returns a written analysis produced through the interface
#### Scenario: Alternate implementation can be registered
- **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
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.
#### 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: Key sourced from configuration
- **WHEN** the app reads its configuration
- **THEN** the Anthropic API key is loaded from environment/config, not source code
### 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.
#### Scenario: Narrative grounded in provided data
- **WHEN** the agent writes the analysis
- **THEN** every figure it cites is present in the supplied evaluation object
#### Scenario: Data caveats preserved
- **WHEN** the evaluation object flags a discrepancy or one-time item
- **THEN** the written analysis surfaces that caveat rather than omitting it
#### Scenario: Disclaimer preserved in narrative
- **WHEN** the agent returns its analysis
- **THEN** the analysis-not-advice disclaimer is present
### Requirement: Graceful degradation without an API key
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.
#### Scenario: No key configured
- **WHEN** an evaluation is requested and no agent API key is configured
- **THEN** the structured evaluation is returned
- **AND** the response indicates the written analysis is unavailable pending a key
### Requirement: Agent error handling
The system SHALL handle agent failures (auth errors, rate limits, timeouts) by
returning a typed error and the underlying structured evaluation, without losing
the data already computed.
#### Scenario: Agent call fails
- **WHEN** the agent call errors after retries
- **THEN** the system returns the structured evaluation plus a typed agent error
- **AND** the computed data is not discarded
@@ -0,0 +1,189 @@
## ADDED Requirements
### Requirement: Current standing summary
The system SHALL produce a current-standing summary for the ticker containing:
last price, absolute and percent change on the day, today's volume as a multiple
of average, percent distance from the 52-week high and low, market capitalization,
and trailing P/E.
#### Scenario: Standing summary is produced
- **WHEN** an evaluation is run for a resolved ticker with price and fundamentals
- **THEN** the output includes price, day change (abs and %), volume multiple,
distance from 52-week high and low, market cap, and trailing P/E
### Requirement: Earnings recap when a recent report exists
The system SHALL, when the most recent quarterly report falls within a
configurable recency window, produce an earnings recap comparing reported EPS to consensus
(beat/miss and magnitude), net income and its year-over-year change, and any
changes to management guidance.
#### Scenario: Recent earnings summarized
- **WHEN** the latest earnings report falls within the recency window
- **THEN** the output includes EPS actual vs consensus, the beat/miss magnitude,
net income with YoY change, and guidance changes when available
#### Scenario: No recent earnings
- **WHEN** no report falls within the recency window
- **THEN** the earnings recap is omitted and the evaluation proceeds
### Requirement: Quality-of-earnings caveats
The system SHALL surface quality-of-earnings caveats when the data supports them,
including one-time items (e.g. tax or tariff refunds), price-driven versus
volume-driven revenue changes, and headline metrics that compare against the
wrong baseline (e.g. an equipment-sales figure presented as total revenue).
#### Scenario: One-time item flagged
- **WHEN** a reported result includes a disclosed one-time benefit or charge
- **THEN** the evaluation notes the item and its approximate EPS impact when known
#### Scenario: Price-vs-volume distinction made
- **WHEN** segment or company data separates price realization from volume change
- **THEN** the evaluation states how much of a revenue or profit move came from
price versus units
### Requirement: Financial and segment breakdown
The system SHALL present a financial summary comparing the current period to the
prior-year period (revenue, operating profit, margins, diluted EPS, operating
and free cash flow) and, where segment data exists, a per-segment breakdown of
revenue, year-over-year change, operating profit, and operating margin versus the
prior-year margin.
#### Scenario: Current-vs-prior financials presented
- **WHEN** current and prior-year period data are available
- **THEN** the output includes a side-by-side comparison of the listed metrics
#### Scenario: Segment breakdown presented when available
- **WHEN** the provider supplies segment data
- **THEN** the output includes per-segment revenue, YoY, operating profit, and
margin versus the prior-year margin
### Requirement: Valuation analysis with over/undervalued reasoning
The system SHALL compute a valuation view (TTM diluted EPS, trailing P/E, forward
EPS and forward P/E from consensus, net-income and revenue growth, FCF yield,
dividend yield) and compare current multiples against the company's own history.
It SHALL state explicit, data-grounded reasons the company appears overvalued or
undervalued, distinguishing multiple expansion from earnings growth and noting
whether a high multiple sits on trough or peak earnings.
#### Scenario: Valuation metrics computed
- **WHEN** fundamentals and consensus estimates are available
- **THEN** the output includes trailing P/E, forward P/E, growth rates, FCF yield,
and dividend yield, plus a comparison to prior fiscal-year multiples
#### Scenario: Explicit valuation reasoning produced
- **WHEN** the valuation view is produced
- **THEN** the output states specific reasons for the over/undervalued conclusion
(e.g. "paying 29x a forecast recovery year before units confirm it")
#### Scenario: Conflicting estimate feeds are reconciled
- **WHEN** two estimate sources disagree on a forward figure
- **THEN** the evaluation discloses the discrepancy and states which figure it used
### Requirement: Macro and sector factor analysis
The system SHALL identify macro and sector factors affecting the stock, such as
tariffs and their year-over-year trajectory, interest-rate sensitivity, commodity
or input-cost pressure on customers, and read-throughs from peer companies.
#### Scenario: Macro factors surfaced
- **WHEN** an evaluation is run
- **THEN** the output lists the material macro/sector factors and their direction
of impact on the stock
### Requirement: Timing and volatility context
The system SHALL provide timing context: how the stock has historically behaved
after earnings prints, today's move versus the options-implied expected move,
recent monthly trading ranges, and whether a post-earnings gap has been filled.
#### Scenario: Post-earnings behavior characterized
- **WHEN** historical prices around prior earnings dates are available
- **THEN** the output summarizes the typical post-earnings move and how the current
move compares to the implied expectation
#### Scenario: Gap-fill status reported
- **WHEN** the latest session gapped from the prior close
- **THEN** the output states whether the gap was filled intraday
### Requirement: Entry points
The system SHALL produce a ranked set of candidate entry levels derived from
technical structure (moving averages, swing lows, pre-earnings shelves), each
annotated with what the level represents, its percent distance below the current
price, and the valuation multiple implied at that price. It SHALL group nearby
levels into practical entry bands.
#### Scenario: Entry levels table produced
- **WHEN** technical context and valuation are available
- **THEN** the output includes candidate entry levels with their meaning, distance
below current price, and implied multiple at that price
#### Scenario: Entry bands recommended
- **WHEN** multiple levels cluster within a narrow range
- **THEN** the output groups them into a band and identifies a starter versus a
high-conviction tranche
### Requirement: Exit points and price targets
The system SHALL produce candidate exit levels and price targets, incorporating
analyst target average/median/range and technical resistance such as prior highs.
#### Scenario: Exit targets produced
- **WHEN** analyst targets and price history are available
- **THEN** the output includes exit/target levels with their basis and upside from
the current price
### Requirement: Stop-loss levels
The system SHALL recommend stop-loss levels grounded in technical structure and
realized volatility (e.g. below a key moving average or swing low, or a
volatility-based distance), stated as concrete prices with rationale.
#### Scenario: Stop-loss recommended
- **WHEN** an entry band is identified
- **THEN** the output states a concrete stop-loss price for that entry and the
technical/volatility basis for it
### Requirement: Bull-versus-bear synthesis and actionable plan
The system SHALL synthesize a bull case and a bear case as explicit lists, and
produce an actionable plan: tranche sizing across entry bands, the next dated
catalyst, conditional logic tying action to observable levels/dates, and the
single most important metric to watch.
#### Scenario: Bull and bear cases produced
- **WHEN** an evaluation is run
- **THEN** the output includes distinct bull and bear point lists grounded in the data
#### Scenario: Actionable plan produced
- **WHEN** entry, exit, and stop levels are available
- **THEN** the output includes tranche guidance, the next dated catalyst, at least
one conditional rule, and the key metric to monitor
### Requirement: Not-advice disclaimer
Every evaluation SHALL include a clear disclaimer that the output is analysis and
not investment advice.
#### Scenario: Disclaimer present
- **WHEN** any evaluation is produced
- **THEN** the output includes an analysis-not-advice disclaimer
### Requirement: Structured evaluation object
The system SHALL emit the evaluation as a typed, structured object (not only prose)
so the UI and the analysis agent can consume individual sections. Missing inputs
SHALL be represented explicitly rather than fabricated.
#### Scenario: Structured object emitted
- **WHEN** an evaluation completes
- **THEN** a typed object containing each section is available to consumers
#### Scenario: Missing data is not fabricated
- **WHEN** a required input for a section is unavailable
- **THEN** that section marks the value unavailable rather than inventing one
@@ -0,0 +1,85 @@
## ADDED Requirements
### Requirement: Ticker search entry point
The web app SHALL present a search input where a user enters an NYSE/Nasdaq ticker
to request an evaluation. Invalid or unresolvable symbols SHALL produce an inline
error without navigating away.
#### Scenario: User searches a valid ticker
- **WHEN** a user enters a resolvable ticker and submits
- **THEN** the app initiates an evaluation for that ticker
#### Scenario: User searches an invalid ticker
- **WHEN** a user submits a symbol that does not resolve
- **THEN** the app shows an inline not-found message and stays on the search view
### Requirement: Evaluation request orchestration
The app SHALL orchestrate the pipeline for a request: fetch market data, run the
equity-evaluation engine, then invoke the analysis agent, returning both the
structured evaluation and the written analysis to the client.
#### Scenario: Full pipeline succeeds
- **WHEN** a valid ticker is evaluated with data and an agent key available
- **THEN** the app returns the structured evaluation and the written analysis
#### Scenario: Partial pipeline (agent unavailable)
- **WHEN** market data succeeds but the agent is unavailable
- **THEN** the app returns the structured evaluation and indicates the narrative is
pending
### Requirement: Evaluation report view
The app SHALL render the evaluation as a report with clearly delineated sections:
current standing, earnings recap and quality-of-earnings caveats, financials and
segments, valuation and over/undervalued reasoning, macro factors, timing, entry
levels, exit/targets, stop-loss, bull-versus-bear, the actionable plan, and the
disclaimer. Tabular data SHALL render as tables and unavailable values SHALL be
shown as such rather than as zero.
#### Scenario: Report sections rendered
- **WHEN** an evaluation result is available
- **THEN** the report view displays each populated section in order
#### Scenario: Unavailable values shown honestly
- **WHEN** a section contains an unavailable value
- **THEN** the view displays it as unavailable rather than as a zero or blank number
### Requirement: Price chart with marked levels
The app SHALL render a price chart with the computed moving averages and overlay
markers for the recommended entry bands, exit/target levels, and stop-loss levels
so the user can see them against price history.
#### Scenario: Levels overlaid on chart
- **WHEN** the report renders with computed levels
- **THEN** the chart shows price history with entry, exit, and stop-loss markers
### Requirement: Loading and error states
The app SHALL show progress while an evaluation runs and SHALL present typed
errors (data unavailable, rate-limited, agent failed) as user-readable messages
without blank screens.
#### Scenario: Loading indicator during evaluation
- **WHEN** an evaluation is in progress
- **THEN** the app shows a loading state until results or an error return
#### Scenario: Error surfaced to user
- **WHEN** the pipeline returns a typed error
- **THEN** the app displays a readable message describing what failed
### Requirement: API key configuration in the app
The app SHALL provide a way to configure the market-data and Anthropic API keys
via environment/config, SHALL NOT expose secret keys to the browser, and SHALL
indicate when a required key is missing.
#### Scenario: Keys read server-side only
- **WHEN** the app calls external providers
- **THEN** secret keys are used only in server-side code and never sent to the client
#### Scenario: Missing key indicated
- **WHEN** a required key is absent
- **THEN** the app indicates which capability is unavailable until the key is set
@@ -0,0 +1,99 @@
## ADDED Requirements
### Requirement: Provider-agnostic data interface
The system SHALL define a `DataProvider` interface that all market-data access
goes through. Evaluation and UI code MUST depend only on this interface and its
normalized data models, never on a concrete provider SDK or response shape. The
active provider SHALL be selectable via configuration without code changes in
consumers.
#### Scenario: Default free provider is used when none configured
- **WHEN** the app starts with no market-data provider explicitly configured
- **THEN** a default free-tier provider implementation is selected
- **AND** all normalized data models are populated from that provider
#### Scenario: Provider can be swapped via configuration
- **WHEN** an operator sets the provider configuration to a different implementation
- **THEN** the system routes all data requests through the new provider
- **AND** no changes to evaluation or UI code are required
### Requirement: Ticker resolution for NYSE and Nasdaq
The system SHALL accept a ticker symbol, validate that it resolves to an
NYSE- or Nasdaq-listed equity, and return a normalized company profile
(name, exchange, sector/industry, currency, shares outstanding).
#### Scenario: Valid listed ticker resolves
- **WHEN** a user submits a ticker listed on NYSE or Nasdaq (e.g. `DE`)
- **THEN** the system returns a company profile with name, exchange, and sector
#### Scenario: Unknown or unlisted ticker is rejected
- **WHEN** a user submits a symbol that does not resolve to an NYSE/Nasdaq equity
- **THEN** the system returns a not-found result with a clear message
- **AND** no evaluation is attempted
### Requirement: Company fundamentals and financial statements
The system SHALL provide normalized fundamentals sufficient for valuation and
earnings analysis: TTM and per-fiscal-year revenue, operating profit, margins,
net income, diluted EPS, operating cash flow, free cash flow, dividend per share,
and total/net debt. Where the provider exposes it, per-segment revenue and
operating profit SHALL be included.
#### Scenario: Fundamentals returned for a resolved ticker
- **WHEN** fundamentals are requested for a resolved ticker
- **THEN** the system returns TTM and at least the last three fiscal years of the
listed metrics
- **AND** each metric carries the fiscal period it belongs to
#### Scenario: Missing metric is represented explicitly
- **WHEN** the provider does not supply a given metric
- **THEN** the normalized model marks that metric as unavailable rather than zero
### Requirement: Price history and computed technical indicators
The system SHALL provide daily OHLCV price history and compute technical context
used for timing: 20/50/200-day moving averages, recent swing highs and lows,
distance from 52-week high and low, average daily volume and today's volume as a
multiple of it, and realized volatility (e.g. 60-day annualized).
#### Scenario: Technical context computed from price history
- **WHEN** price history is requested for a resolved ticker
- **THEN** the system returns the moving averages, 52-week high/low, volume ratio,
and realized volatility computed from that history
#### Scenario: Insufficient history degrades gracefully
- **WHEN** fewer than 200 trading days of history are available
- **THEN** longer-window indicators (e.g. 200-day average) are marked unavailable
- **AND** shorter-window indicators are still returned
### Requirement: Analyst coverage and consensus estimates
The system SHALL provide, where available, analyst rating counts (bullish /
neutral / bearish), average and median price targets, target range, and forward
consensus estimates (next fiscal-year EPS and revenue).
#### Scenario: Analyst data returned when available
- **WHEN** analyst coverage exists for a ticker
- **THEN** the system returns rating counts, average/median/target range, and
forward EPS/revenue estimates
#### Scenario: No coverage is handled
- **WHEN** no analyst coverage exists for a ticker
- **THEN** the system returns an empty coverage result the evaluation can note
### Requirement: Rate limiting, caching, and data-freshness disclosure
The system SHALL respect provider rate limits, cache responses to reduce calls,
and expose each dataset's freshness (as-of timestamp and whether it is delayed
or real-time) so downstream output can disclose it.
#### Scenario: Rate-limit and transient errors are handled
- **WHEN** the provider returns a rate-limit or transient error
- **THEN** the system retries within limits and, if still failing, returns a typed
error rather than throwing an unhandled exception
#### Scenario: Data freshness is surfaced
- **WHEN** any dataset is returned
- **THEN** it includes an as-of timestamp and a delayed/real-time flag
@@ -0,0 +1,73 @@
## 1. Project scaffold
- [ ] 1.1 Initialize Next.js (App Router) + TypeScript project at the repo root
- [ ] 1.2 Add Tailwind CSS and a base layout/theme (light + dark)
- [ ] 1.3 Add a charting library (Recharts or lightweight-charts) and confirm it renders
- [ ] 1.4 Set up `.env.local` handling and `.env.example` for `MARKET_DATA_API_KEY` and `ANTHROPIC_API_KEY`; ensure secrets never reach the client bundle
- [ ] 1.5 Configure lint/format/test tooling (ESLint, Prettier, Vitest/Jest) and a passing sample test
- [ ] 1.6 Define shared TypeScript types module (normalized data models + `Evaluation` object skeleton with `unavailable` markers)
## 2. Market-data layer (`market-data` spec)
- [ ] 2.1 Define the `DataProvider` interface and normalized models (`CompanyProfile`, `Fundamentals` incl. optional segments, `PriceHistory`, `AnalystCoverage`, `Estimates`), each with `asOf` + `delayed|realtime`
- [ ] 2.2 Spike two free providers (e.g. FMP, Finnhub) against `DE`; pick the default based on segment + forward-estimate coverage; record the choice in design Open Questions
- [ ] 2.3 Implement the default free-tier provider behind the interface
- [ ] 2.4 Implement ticker resolution with NYSE/Nasdaq validation and typed not-found result
- [ ] 2.5 Implement a fixture/mock provider seeded from the DE example for tests and offline dev
- [ ] 2.6 Add provider-boundary caching (in-memory, TTL, keyed by ticker+dataset) and retry/backoff for rate-limit/transient errors returning typed errors
- [ ] 2.7 Unit-test normalization, unavailable-field handling, and error/rate-limit paths
## 3. Technicals module (`market-data` spec)
- [ ] 3.1 Implement pure functions: 20/50/200-day moving averages, 52-week high/low distance, average volume + today's volume multiple
- [ ] 3.2 Implement swing high/low detection and realized (e.g. 60-day annualized) volatility
- [ ] 3.3 Handle insufficient-history cases (mark long-window indicators unavailable)
- [ ] 3.4 Unit-test all indicators against known values from the DE example
## 4. Evaluation engine (`equity-evaluation` spec)
- [ ] 4.1 Implement current-standing summary (price, day change abs/%, volume multiple, 52-wk distance, market cap, trailing P/E)
- [ ] 4.2 Implement earnings recap (EPS vs consensus, beat/miss, net income YoY, guidance changes) gated by a configurable recency window
- [ ] 4.3 Implement quality-of-earnings caveats (one-time items + EPS impact, price-vs-volume, wrong-baseline headline metrics)
- [ ] 4.4 Implement financial summary (current vs prior-year) and per-segment breakdown when available
- [ ] 4.5 Implement valuation view (TTM EPS, trailing/forward P/E, growth, FCF & dividend yield, vs own history) with conflicting-estimate reconciliation
- [ ] 4.6 Implement explicit over/undervalued reasoning (multiple-expansion vs earnings-growth, trough/peak earnings)
- [ ] 4.7 Implement macro/sector factor analysis (tariffs trajectory, rates, input-cost pressure, peer read-throughs)
- [ ] 4.8 Implement timing/volatility context (post-earnings behavior, implied vs actual move, monthly ranges, gap-fill status)
- [ ] 4.9 Implement entry levels (ranked levels with meaning, % below price, implied multiple at each) grouped into bands with starter/high-conviction tranches
- [ ] 4.10 Implement exit/targets (analyst avg/median/range + technical resistance) and stop-loss levels (technical/volatility-based, concrete prices + rationale)
- [ ] 4.11 Implement bull-vs-bear synthesis and actionable plan (tranche sizing, next dated catalyst, conditional rules, one metric to watch)
- [ ] 4.12 Emit the typed `Evaluation` object with explicit unavailable markers (no fabrication) + mandatory disclaimer
- [ ] 4.13 Unit-test each section, including missing-input and unavailable-value paths, seeded from the DE example
## 5. Analysis agent (`analysis-agent` spec)
- [ ] 5.1 Define the `AnalysisAgent` interface (input: `Evaluation`; output: narrative sections)
- [ ] 5.2 Implement the Claude default via `@anthropic-ai/sdk` (current model), key loaded server-side from config
- [ ] 5.3 Design the prompt + structured/JSON output so narrative maps to spec sections and uses ONLY supplied figures
- [ ] 5.4 Preserve input caveats/discrepancies and enforce the disclaimer in the narrative
- [ ] 5.5 Implement graceful degradation when no key is set (return structured evaluation, mark narrative unavailable)
- [ ] 5.6 Implement typed agent error handling (auth/rate-limit/timeout) that retains the computed evaluation
- [ ] 5.7 Test grounding (every cited figure exists in input), no-key, and error paths with a mock agent
## 6. Pipeline + API (`evaluation-app` spec)
- [ ] 6.1 Implement server-side route/action orchestrating resolve → data → evaluate → agent, returning `{ evaluation, narrative | error }`
- [ ] 6.2 Handle partial results (data ok / agent unavailable) and typed errors end-to-end
- [ ] 6.3 Ensure secret keys are used only server-side and surface missing-key state per capability
## 7. Web UI (`evaluation-app` spec)
- [ ] 7.1 Build the ticker search entry point with inline invalid/not-found handling
- [ ] 7.2 Build the report view rendering every section in order, tables as tables, unavailable values shown honestly
- [ ] 7.3 Build the price chart with moving averages and overlay markers for entry bands, exit/targets, and stop-loss levels
- [ ] 7.4 Implement loading state and readable error states (no blank screens)
- [ ] 7.5 Surface missing-key indicators and a settings/config affordance for keys
## 8. Verification
- [ ] 8.1 End-to-end run on `DE` (with keys) producing a report structurally matching the example; note any data gaps from the free tier
- [ ] 8.2 End-to-end run with no agent key confirming structured evaluation still renders
- [ ] 8.3 Run the full test suite and lint; confirm green
- [ ] 8.4 Update README with setup, env vars, provider choice, and run instructions
- [ ] 8.5 Run `openspec validate stock-deep-evaluation` and archive the change when complete