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,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.
|
||||
Reference in New Issue
Block a user