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:
@@ -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
|
||||
Reference in New Issue
Block a user