**Role**: Step 0 — Evaluate whether existing snapshot data is fresh enough to reuse, or whether new data collection is required. **Triggered by**: CLAUDE.md at the start of Workflow 1 (Single Stock Analysis) and Workflow 3 (Watchlist Scan) **Reads**: `output/data/{ticker}/latest.json`, staleness rules from this file **Writes**: Nothing (read-only evaluation; result is reported inline to orchestrator) **References**: `references/staleness-rules.md` ---
Scanned 6/5/2026
Install via CLI
openskills install kipeum86/stock-analysis-agent# Staleness Checker — SKILL.md
**Role**: Step 0 — Evaluate whether existing snapshot data is fresh enough to reuse, or whether new data collection is required.
**Triggered by**: CLAUDE.md at the start of Workflow 1 (Single Stock Analysis) and Workflow 3 (Watchlist Scan)
**Reads**: `output/data/{ticker}/latest.json`, staleness rules from this file
**Writes**: Nothing (read-only evaluation; result is reported inline to orchestrator)
**References**: `references/staleness-rules.md`
---
## Instructions
### Step 0.1 — Check for Existing Snapshot
Check if `output/data/{ticker}/latest.json` exists. New files are pointer-only documents; legacy full-snapshot files may still appear and must remain readable.
```
IF file does not exist:
→ Routing decision: FRESH_COLLECTION (no cached data)
→ Proceed to Step 1 (query-interpreter)
```
If file exists, read it and extract:
- `analysis_date` (YYYY-MM-DD)
- `expires_at` and `refs.analysis_result` when `kind` is `stock-analysis.latest-snapshot-pointer`
- `data_mode` (enhanced / standard)
- `output_mode` (A / B / C / D)
- `rr_score`
- `verdict`
If `latest.json` is a pointer, verify that `refs.analysis_result` exists before routing to REUSE or DELTA_FAST. If the pointer is missing, expired, or points to a missing file, route to FRESH_COLLECTION.
### Step 0.2 — Calculate Staleness
Calculate `days_since_analysis = today - analysis_date`. For pointer files, treat `expires_at` as the primary 24-hour reuse boundary; `analysis_date` remains the coarser fallback for older files and user-facing explanations.
**Mode E hard override (OD-F1)**: When the orchestrator has set
`pipeline_state.mode_override == "E"` (because earnings-window-detector
returned `window in {preview, review}` at CLAUDE.md Step 0.5, or the
user passed `--mode E` / `--earnings-mode preview|review`), **skip the
staleness table entirely and route to FRESH_COLLECTION**. Mode E should
never reuse a stale snapshot — implied moves, options chains, and
consensus EPS shift fast in the D-7~D+3 window.
```
IF pipeline_state.mode_override == "E":
→ Routing decision: FRESH_COLLECTION
→ Reason: Mode E (earnings window) per OD-F1
→ Skip Step 0.2 / 0.3 / 0.4 staleness rules
→ Proceed to Step 1 (query-interpreter)
```
Otherwise apply the standard staleness rules:
| Days Since Analysis | Data Mode | Routing Decision |
|--------------------|-----------|-----------------|
| ≤ 1 day (same day) | Any | REUSE — skip Steps 1–5, proceed directly to output generation |
| 2–6 days | Enhanced | DELTA_FAST — re-collect price only (Step 3 minimal), regenerate output |
| 2–6 days | Standard | DELTA_FAST — run web search Step 4 only (skip full re-research) |
| 7–29 days | Any | STALE — full re-collection required (Steps 1–9) |
| ≥ 30 days | Any | VERY_STALE — full re-collection + flag STALE_30D in watchlist |
### Step 0.3 — Earnings Detection (Override Staleness Rules)
Regardless of staleness, check if an earnings event occurred since `analysis_date`:
**Enhanced Mode check**: Call `get_company_news(ticker, limit=5)`. If any news title contains earnings keywords, flag EARNINGS_OVERRIDE.
**Standard Mode check**: Search `"{ticker}" earnings results Q{N} 2026`. If results dated after `analysis_date` contain earnings data, flag EARNINGS_OVERRIDE.
Earnings keywords: `earnings`, `quarterly results`, `Q1`, `Q2`, `Q3`, `Q4`, `revenue beat`, `EPS beat`, `revenue miss`, `실적`, `분기`, `매출`, `영업이익`
```
IF EARNINGS_OVERRIDE:
→ Routing decision: FULL_COLLECTION regardless of days_since_analysis
→ Reason: earnings data fundamentally changes valuation inputs
```
### Step 0.4 — Delta Analysis Detection (Auto Delta Mode, default ON)
Auto Delta Mode (Phase B) defaults ON. Whenever a previous snapshot exists for
the ticker the orchestrator must auto-run the delta comparator regardless of
keyword detection. Keyword detection is retained only as a manual fallback for
older single-snapshot states (treat it as advisory, not gating).
**Auto trigger rule**:
```
IF previous snapshot exists for {ticker} (latest pointer or snapshots dir):
→ Set auto_delta = true (unless orchestrator received --no-delta)
→ After Step 10 persists the new snapshot, the prior snapshot becomes the
"old" side and the new one becomes the "new" side.
→ Run:
python .claude/skills/data-manager/scripts/delta-comparator.py compare \
--ticker {ticker} --old-date latest --new-date latest --format html
→ Capture stdout into pipeline state as `auto_delta_payload.html`.
Also capture --format markdown into `auto_delta_payload.markdown` for
Mode D / chat-summary surfaces.
→ Renderers (Mode A/B/C/D) prepend the banner above their first content
section. Empty stdout = no banner (graceful skip / single snapshot /
--no-delta).
```
Keyword triggers (manual fallback only):
**English**: "compare", "vs last time", "since last analysis", "what changed", "update", "delta", "difference from before", "how has it changed"
**Korean**: "이전이랑", "지난번이랑", "비교해줘", "달라진 것", "바뀐 것", "업데이트", "뭐가 달라졌어", "전이랑 비교"
When `--no-delta` is passed by the orchestrator (CLAUDE.md Workflow 1 Step 0),
set `auto_delta = false` and skip the comparator call. The renderers must
still tolerate a missing banner (no fallback content required).
### Step 0.5 — Session Context Check
Before any file checks, verify session context:
```
IF ticker was analyzed in the current session:
→ Use session-cached validated data (skip Steps 3–5)
→ Only regenerate output if different output_mode requested
→ Log: "Using session-cached data for {ticker} from {session_time}"
```
Session context keywords: "same stock", "same company", "just analyzed", 같은 종목", "방금 분석한"
### Step 0.6 — Report Routing Decision
Output a concise routing decision block:
```
=== Staleness Check: {TICKER} ===
Snapshot found: {YES/NO}
Analysis date: {date or N/A}
Days since: {N or N/A}
Earnings override: {YES/NO}
Mode E override: {YES/NO} # set when CLAUDE.md Step 0.5 detected window
Earnings window: {preview/review/none/—}
Delta mode: {YES/NO}
→ Routing: {REUSE / DELTA_FAST / STALE / FRESH_COLLECTION / EARNINGS_OVERRIDE}
→ Action: {brief description of what will happen next}
```
When `Mode E override = YES`, the routing block must always read
`Routing: FRESH_COLLECTION` and the action must mention "Mode E
(earnings preview/review) — fresh collection per OD-F1". Auto-delta is
also applicable to Mode E (Section 0.4 still runs after Step 10) so
that Review reports can show the price/EPS delta against the prior Mode
C snapshot — but the staleness table itself is bypassed.
---
## Watchlist Scan Mode
When called from Workflow 3 (watchlist scan), apply these rules per ticker:
| Condition | Action |
|-----------|--------|
| Pointer `expires_at` still valid, or legacy `latest.json` age < 24 hours | SKIP — reuse existing data |
| Pointer expired but `analysis_date` < 7 days, or legacy `latest.json` age 24h–7 days | QUICK_UPDATE — price + news only |
| `latest.json` age > 7 days | FULL_SCAN — abbreviated pipeline (Steps 3+4+simplified 5) |
| No `latest.json` | FRESH — full pipeline |
For watchlist scan, do NOT run full Steps 6–9 (analysis generation). Only collect data and update alert flags.
---
## Completion Check
- [ ] Confirmed whether `output/data/{ticker}/latest.json` exists
- [ ] If pointer format, confirmed `refs.analysis_result` exists
- [ ] **If `mode_override=="E"`: forced FRESH_COLLECTION (OD-F1) and skipped staleness table**
- [ ] Calculated days_since_analysis if snapshot exists (skipped for Mode E)
- [ ] Applied staleness rules to determine routing (skipped for Mode E)
- [ ] Checked for earnings override condition
- [ ] Checked for delta analysis trigger in user query
- [ ] Checked session context for recently analyzed tickers
- [ ] Reported routing decision with clear action statement
No comments yet. Be the first to comment!