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_atandrefs.analysis_resultwhenkindisstock-analysis.latest-snapshot-pointerdata_mode(enhanced / standard)output_mode(A / B / C / D)rr_scoreverdict
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.jsonexists - [ ] If pointer format, confirmed
refs.analysis_resultexists - [ ] 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
Prompt Engineering
Data & AI
Prompt engineering best practices and templates to maximize AI outputs.
Data Visualization
Data & AI
Generates data visualizations and charts tailored to your data.
RAG Architecture Setup
Data & AI
Setup guide for RAG (Retrieval-Augmented Generation) architectures.