Skill: sjt-at-revelata/revelata-deepkpi (version 1.0.21)

--- name: revelata-deepkpi description: > Financial and operational KPI research for US public companies using Revelata deepKPI. Pulls SEC metrics (10-K/10-Q/8-K): segments, unit KPIs (stores, comps, ARPU, users), statements, cash flow; filing markdown and verbatim quotes via retrieve-sec-filing; implied Q4/per-unit, seasonality, Excel. For "pull data", historicals, "find the KPI", seasonality, .xlsx, filing excerpts. Also: analyst-report-pressure-test (analyst PDF vs SEC HTML); peer-benchmark (peers, comps, benchmark, similar companies—operating, vertical-first); idea-generation-survey ("what should I invest in?", new ideas, interesting companies—no ticker); company-summary-segments (what cos do, segments, thematic discovery). OpenClaw: deepkpi-api. version: 1.0.0 homepage: https://www.revelata.com metadata: openclaw: emoji: "📊" requires: env: - DEEPKPI_API_KEY bins: - curl primaryEnv: DEEPKPI_API_KEY --- # deepKPI Financial Analysis and Research Tools Query structured KPIs extracted from SEC filings for US public companies. Powered by [Revelata](https://www.revelata.com). This skill suite covers different aspects of financial analysis workflows. This includes data access via MCP for Claude or REST API for OpenClaw, data retrieval, metric derivation, seasonality analysis, and Excel export. Sub-skills are organized so that each layer can be loaded independently — only read what the task requires. ## Data access — Claude vs. OpenClaw The deepKPI operations (`query_company_id`, `list_kpis`, `search_kpis`, `company_summary_search`, `get_company_summary`, `get_company_segments`, `list_sec_filing_markdowns`, `get_sec_filing_markdown`) are available two ways depending on the runtime: | Runtime | How to call deepKPI | |---------|---------------------| | **Claude** (MCP tools available) | Use the native MCP tools directly — no API key or `deepkpi-api` skill needed | | **OpenClaw** (no MCP) | Read `deepkpi-api/deepkpi-api.md` and call the REST endpoints using `$DEEPKPI_API_KEY` | `retrieve-kpi-data/retrieve-kpi-data.md` is the KPI metrics workflow; `retrieve-sec-filing/retrieve-sec-filing.md` is the SEC filing markdown workflow; `company-summary-segments/company-summary-segments.md` is **what companies do** (summary), **segment / geo structure**, and **thematic discovery** (`get_company_summary`, `get_company_segments`, `company_summary_search`). The `DEEPKPI_API_KEY` env var and `deepkpi-api` reference doc are only needed in OpenClaw (or as an env-var fallback when MCP is unavailable). ## Hard stop: deepKPI connection failures If deepKPI access fails (MCP connector not working, REST calls failing, auth errors, network issues, or you cannot retrieve data), you MUST STOP and ask the user: **“I can’t access deepKPI right now. Do you want to proceed without deepKPI?”** - If the user says **no**, stop. - If the user says **yes**, you may proceed using other sources (e.g. web), BUT you MUST NOT use deepKPI skill branding, templates, formatting conventions, or “Powered by Revelata deepKPI” framing for non-deepKPI data. Clearly label alternate sources. This rule applies to ALL sub-skills in this bundle. ## Sub-skill routing **Read the relevant reference doc(s) before doing any work.** Multiple docs may apply to a single request — load all that are relevant. | User need | File to read | |-----------|--------------| | No specific company or thesis — "what should I invest in?", "what stock should I buy?", **new ideas**, **interesting companies**, boredom / open exploration | `idea-generation-survey/idea-generation-survey.md` — interactive funnel + `company_summary_search` screen; then `retrieve-kpi-data` for deep pulls | | Pull historical KPIs / financials from deepKPI | `retrieve-kpi-data/retrieve-kpi-data.md` | | **What a company does**, **segments / geographies**, or **thematic** “who does X?” lists | `company-summary-segments/company-summary-segments.md` — named company: `get_company_summary` / `get_company_segments`; discovery: `company_summary_search` then hydrate as needed | | Pull **full filing markdown** into chat, **verbatim SEC text**, quotes, MD&A / risk-factor language, or “what did they say” | `retrieve-sec-filing/retrieve-sec-filing.md` — **before any web/SEC.gov**: `list_sec_filing_markdowns` (free) → `get_sec_filing_markdown` (10 credits). Return full markdown when they want the document; blockquoted excerpts for quote-style asks; no paraphrase as quotes | | Derive missing Q4 numbers, a segment remainder, or per-unit economics (ASP, ARPU, AUV, take rate) | `derive-implied-metric/derive-implied-metric.md` | | Split annual forecasts into quarterly estimates / seasonality patterns | `analyze-seasonality/analyze-seasonality.md` | | Produce an Excel workbook (.xlsx) from deepKPI data | `format-deepkpi-for-excel/format-deepkpi-for-excel.md` | | REST API calls (OpenClaw / env-var fallback only) | `deepkpi-api/deepkpi-api.md` | | Pressure-test a sell-side / analyst report against SEC filing data (HTML report, Chart.js, provenance links) | `analyst-report-pressure-test/analyst-report-pressure-test.md` | | **Peers / comps**, **benchmark** a company, **most similar** public companies, or operational comp sets | `peer-benchmark/peer-benchmark.md` — read `retrieve-kpi-data` first for KPI mechanics | **Default entry point:** For **metrics and modeling feeds**, start with `retrieve-kpi-data/retrieve-kpi-data.md` (it references `derive-implied-metric`, `analyze-seasonality`, and `format-deepkpi-for-excel` as needed). For **business description, segment structure, or thematic company lists**, start with `company-summary-segments/company-summary-segments.md`. For **filing markdown (full or excerpts) and verbatim quotes**, start with `retrieve-sec-filing/retrieve-sec-filing.md`. If a request mixes these, read **every** doc that applies. ## Sub-skill summary **`deepkpi-api`** — Raw REST access to deepKPI endpoints: `query_company_id`, `list_kpis`, `search_kpis`, `company_summary_search`, `get_company_summary`, `get_company_segments`, `list_sec_filing_markdowns`, `get_sec_filing_markdown`. **OpenClaw / env-var fallback only** — in Claude, use the native MCP tools instead. **`retrieve-kpi-data`** — Primary workflow for **structured KPIs** (company ID, `list_kpis` / `search_kpis`, gap handling including Q4 derivation), provenance rules, in-chat tables, and the mandatory post-pull Excel offer. **`company-summary-segments`** — **`get_company_summary`** (what they do) and **`get_company_segments`** (how they break out segments / geos); **`company_summary_search`** for **thematic** “who does X?” discovery. Not for KPI time series. **`retrieve-sec-filing`** — **SEC filing markdown** in chat: full filing or excerpts, verbatim quotes, MD&A / risk language. Tools: `list_sec_filing_markdowns` → `get_sec_filing_markdown`, source hierarchy (tool-first, not web), blockquote discipline for quote-style asks. Distinct purpose from KPI time series. **`derive-implied-metric`** — Compute metrics that deepKPI doesn't report directly from data that IS reported: Q4 = FY − (Q1+Q2+Q3), missing segment = total − known segments, per-unit economics (revenue per store, ARPU, ASP), take rates, penetration rates, and geographic mix percentages. **`analyze-seasonality`** — Compute each quarter's typical share of the full fiscal year from 2–3 years of actuals, then apply those ratios to split an annual projection into quarterly estimates. **`format-deepkpi-for-excel`** — Canonical layout and styling spec for any .xlsx export built from deepKPI data: wide layout with periods as columns (annual block → blank column → quarterly block), Calibri font, green input cells, clickable hyperlinks in cells, numeric date headers, freeze panes, column grouping, and no redundant Source rows. **`analyst-report-pressure-test`** — End-to-end workflow for uploaded analyst PDFs: extract 4–6 claims, pull granular deepKPI metrics per claim, build paired "supports" / "complicates" evidence with mandatory provenance hyperlinks, and emit a Revelata-branded interactive HTML report (`references/html-template.md`, `references/chart-patterns.md`). After the draft HTML exists, run the mandatory internal **draft HTML QA** rubric in `analyst-report-pressure-test/pressure-test-double-check.md`, then revise and re-check as needed before presenting the file. **Always** read `retrieve-kpi-data` for KPI mechanics; use `retrieve-sec-filing` when the test needs verbatim filing passages; use `company-summary-segments` for business description / segment structure / thematic lists when useful; use `derive-implied-metric` when filling Q4 or segment gaps. **`peer-benchmark`** — Curated **operational** benchmark sets (not trading multiples): `company_summary_search` for candidates, KPI fingerprint + alignment, diff-driven segment sub-benchmarks, chat 1-pager, optional HTML (`references/html-template.md`), Excel via `format-deepkpi-for-excel`. **Always** read `retrieve-kpi-data` first. **`idea-generation-survey`** — Onramp when the user has **no ticker and no thesis**: rapid interview (multiple-choice by default), `company_summary_search` for a 10–15 name screen with thesis-matched KPIs, then deep pulls on 1–2 chosen names per `retrieve-kpi-data`. `references/sector-kpi-map.md` for diagnostic KPI concepts. **No** default Excel offer. Not for users who already named a company or a specific metric — use `retrieve-kpi-data` instead.

path: retrieve-sec-filing/retrieve-sec-filing.md
content: ---
name: retrieve-sec-filing
description: >
  Retrieves SEC filing markdown from Revelata deepKPI for US public companies: full
  filing text in chat (10-K/10-Q/8-K as markdown) or verbatim excerpts — MD&A,
  risk factors, footnotes, management commentary, quotes. Use when the user wants
  the filing document to work with, "give me the 10-K", "what did they say", exact
  wording, or sections as markdown — NOT structured KPI time series (use
  retrieve-kpi-data for that). MUST call list_sec_filing_markdowns (free) then
  get_sec_filing_markdown (10 credits) before any web/SEC.gov search. For excerpt
  answers, lead with blockquoted contiguous text; do not paraphrase as quotes.
  Triggers: "full filing", "filing markdown", "quote the filing", "MD&A", "risk
  factors", "show me the 10-K", "verbatim", "management said".
---

# retrieve-sec-filing

**Purpose:** Pull **primary SEC filing text** as markdown so the user can **work with
the full document in chat** (search, copy, section pulls) or get **exact language**
via blockquoted excerpts. This is **not** the KPI / metrics skill — for revenue
series, segment tables, store counts, and other structured metrics, read
**`retrieve-kpi-data/retrieve-kpi-data.md`** instead.

## Data source (deepKPI)

| Context | How |
|---------|-----|
| **Claude (preferred)** | MCP — `query_company_id` · `list_sec_filing_markdowns` · `get_sec_filing_markdown` |
| **OpenClaw / env fallback** | `deepkpi-api/deepkpi-api.md` — `POST .../list_sec_filing_markdowns`, `POST .../get_sec_filing_markdown` with `X-API-Key` |

If none of the above applies, say so and ask the user how to proceed.

## Hard stop if deepKPI access fails

If the MCP connector or REST API calls fail (auth/network/credits/service errors)
and you cannot access deepKPI, STOP and ask the user whether they want to proceed
**without deepKPI**.

- If the user says **no**: stop.
- If the user says **yes**: continue with alternate sources (web, etc.), but DO NOT
  use deepKPI skill branding for that content. Label sources clearly.

Until the user opts in, **do not** use the web as a workaround for text that
`get_sec_filing_markdown` would cover.

## SEC filing text — source hierarchy (non-negotiable)

When the user wants **US public-company SEC primary text** (10-K, 10-Q, 8-K,
exhibits, MD&A, Risk Factors, footnotes, “what they said”, quotes, or “give me
the filing”), you MUST treat deepKPI’s filing markdown as the **first and default**
source.

**Order of operations (do not skip or reorder):**

1. **`list_sec_filing_markdowns`** — **free** (0 credits). Use it to pick the right
   `acc_no` / `seq_no` / form when the user didn’t specify them exactly.
2. **`get_sec_filing_markdown`** — **10 credits per call**. This is the intended way
   to get machine-readable filing text for quoting. **Do not avoid this tool to
   save credits** by browsing the web instead. If credits may be insufficient, say
   so and ask whether to proceed (or which filing to prioritize).
3. **Only if step 1–2 fail** after a genuine attempt, OR the user explicitly authorizes
   non-deepKPI sources: follow **Hard stop** above, then you may use web/SEC.gov —
   clearly labeled.

**Explicit prohibitions (while deepKPI is available and the user has not opted out):**

- Do **not** open SEC.gov, full-text search EDGAR, or use generic web search to
  substitute for `get_sec_filing_markdown`.
- Do **not** answer from memory, training data, or news articles for “what the
  filing says” — pull markdown and quote it.

**Credit transparency (say this when relevant):** Listing filings is free; retrieving
filing markdown costs **10 credits** per document pull. The correct behavior is to
**call the tool and disclose the cost**, not to route around it.

## Workflow

### 1. Resolve CIK

Call `query_company_id` with the **official registrant name** (not a brand). Same
brand→registrant hints as in `retrieve-kpi-data` (e.g. “Chipotle” → “Chipotle
Mexican Grill”). The returned `company_id` is the SEC CIK for `list_sec_filing_markdowns` / `get_sec_filing_markdown`.

### 2. List filings (free)

Call `list_sec_filing_markdowns` with `cik`, optional `form_type`, optional date
range. Pick the `acc_no` and `seq_no` that match the user’s request (e.g. latest
10-K, specific dated 8-K).

### 3. Fetch markdown (10 credits)

Call `get_sec_filing_markdown` with `cik`, `acc_no`, and `seq_no` (default `1`).

## Opening line

Before tool calls, say:

**"Let me pull the SEC filing markdown using deepKPI so you have the full filing text in context (and I can quote exact language where needed)."**

(If you are also pulling KPIs in the same turn, read `retrieve-kpi-data` for its
opening line for the metrics portion.)

## When users ask “what did they say?” (verbatim quotes required)

When the user asks for **exact language** from filings (“what did management say”,
“what comments were made”, “how did they describe…”, “quote the 10-K/10-Q”), you MUST:

- Use `list_sec_filing_markdowns` (if needed) to identify the right filing and `seq_no`.
- Call `get_sec_filing_markdown` to retrieve the markdown.
- Lead with **verbatim snippets** only: copy/paste **contiguous** text from the
  markdown into **Markdown blockquotes** (`>`). Minimum useful length: **at least
  one full sentence** per quote (prefer a short paragraph). Do not “tighten” wording.
- **Do not paraphrase** in the same breath as quoting. If you add interpretation,
  label it explicitly as **“Interpretation (not a quote):”** and only **after** the
  blockquoted passages.
- If you cannot find supporting language in the pulled markdown, say so and either
  pull a different `seq_no`/filing or ask a narrowing question — do not invent
  plausible filing language.

Avoid summarizing by default. Only summarize if the user explicitly asks for a
summary (and even then, prefer 1–2 blockquotes as anchors unless they asked for
summary-only).

## When users ask for “the filing” (return full markdown)

If the user asks for the **filing itself** (e.g. “give me the 10-K”, “show the
filing”, “send the filing”, “put the markdown in chat”), you MUST:

- Use `list_sec_filing_markdowns` (if needed) for `acc_no` / `seq_no`.
- Call `get_sec_filing_markdown`.
- Return the **full markdown** (not a summary) so they can scroll, search, and ask
  follow-ups against the same text. Use excerpts only if they asked for
  excerpts/snippets or a specific section.

## KPIs + filing text in one request

If the user wants **both** structured metrics and **verbatim filing language** (or
full filing markdown):

1. Read **`retrieve-kpi-data/retrieve-kpi-data.md`** for KPI discovery, search,
   provenance tables, and the mandatory Excel offer when you deliver data-pull tables.
2. Use **this doc** for `list_sec_filing_markdowns` / `get_sec_filing_markdown` and
   quote / full-markdown rules.

Do not satisfy a “what did they say?” request with KPI tables alone unless they
only asked for numbers.

## Common failure modes

- **Web first**: Browsing SEC.gov before calling `get_sec_filing_markdown`.
- **Paraphrase as quote**: Summarizing filing language without blockquoted source text.
- **Wrong `seq_no`**: Listing returns multiple documents per accession; confirm the
  intended exhibit/main document.
- **Skipping the free list**: Calling `get_sec_filing_markdown` without knowing
  `acc_no` when the user didn’t provide it.


path: company-summary-segments/company-summary-segments.md
content: ---
name: company-summary-segments
description: >
  Answer "what does this company do?" and segment / geography questions using deepKPI:
  get_company_summary (narrative summary) and get_company_segments (segment & operating
  structure). For discovery — "which companies do X", "who operates in Y" — use
  company_summary_search across summaries, then pull full summaries for names
  that need detail. NOT for numeric KPI time series (retrieve-kpi-data). 
  Triggers: what does X do, describe the business, segments, geographies,
  reportable segments, companies that make, firms in industry, thematic lists.
---

# company-summary-segments

**Purpose:** Ground answers in deepKPI’s **10-K-derived company summary** and **segment
breakdown** endpoints. Use **summary search** when the user is looking for **names**
that match a **theme** or **activity**.

For **historical metrics**, provenance tables, and Excel-style pulls, use
**`retrieve-kpi-data/retrieve-kpi-data.md`** instead.

## Data source (deepKPI)

| Context | How |
|---------|-----|
| **Claude (preferred)** | MCP — `query_company_id` · `get_company_summary` · `get_company_segments` · `company_summary_search` |
| **OpenClaw / env fallback** | `deepkpi-api/deepkpi-api.md` — `get_company_summary`, `get_company_segments`, `company_summary_search` with `X-API-Key` |

`query_company_id` resolves **name / brand → `company_id`** (SEC CIK for US issuers).
Use it whenever the user names a company and you do not already have `company_id`.

## Hard stop if deepKPI access fails

If MCP or REST calls fail and you cannot access deepKPI, follow the bundle rule in
root **`SKILL.md`**: stop and ask whether to proceed without deepKPI.

## Credits (budget consciously)

| Call | Cost |
|------|------|
| **`get_company_summary`** | **3 credits** on success (one company, latest 10-K narrative). |
| **`get_company_segments`** | **3 credits** on success (one company, structured segments / geos from latest 10-K). |
| **`company_summary_search`** | **1 credit per company returned** (`top_k_companies`, max **15**). Empty results: **0**. |

## Workflow A — Named company (default)

Use this when the user is asking about **one or more specific issuers** by name or
ticker.

### What does the company do? (business, model, strategy)

1. **`query_company_id`** if you need **`company_id`**.
2. **`get_company_summary`** — return the **narrative** from the response; that is the
   canonical answer to “what do they do?”, “describe the business”, “how do they
   make money at a high level?”, etc.

Do **not** substitute web summaries or training-data descriptions when this endpoint
is available.

### Segments, geographies, how they break out the business

1. **`query_company_id`** if needed.
2. **`get_company_segments`** — use for **segment structure**, **operating geographies**,
   **reportable segments**, and similar **organizational** questions (what lines /
   regions they disclose), as returned by the API.

For **segment revenue / margins over time**, follow **`retrieve-kpi-data`**
(`list_kpis` / `search_kpis`) after you have the segment names you care about.

### Both narrative and structure

Call **`get_company_summary`** and **`get_company_segments`** when the question needs
**prose plus** how they **slice** the business (same `company_id`).

## Workflow B — Thematic discovery (no single target company)

Use **`company_summary_search`** when the user wants a **set of companies** defined by
**what they do** or **where / how they operate**, e.g.:

- “Companies that **make** …”, “**operate in** …”, “**exposed to** …”
- “Who **reports** …”, “**US-listed** firms in …” (as natural language — tune the `query`)

Steps:

1. **`company_summary_search`** with a clear natural-language **`query`** and
   **`top_k_companies`** (often **10**; max **15**). **1 credit per row returned.**
2. Present the ranked list (names / `company_id` / ticker as returned).
3. If the user (or the task) needs **full narrative** for one or more hits — not just
   the fact they matched — call **`get_company_summary`** on those `company_id`s
   (**3 credits** each). Use **`get_company_segments`** on selected names if they ask
   how those companies **break out** operations.

If results are weak, **rephrase `query`** before giving up.

## Out of scope — benchmarking vs this skill

**Not covered here:** “**Companies most similar to [Target]**”, formal **peer sets**
for valuation comps, or **benchmark** workflows keyed off a **specific** company as
the anchor. A separate **company benchmarking** skill will own that. This skill’s
**`company_summary_search`** is for **theme / activity** discovery (“who does X?”),
not a drop-in replacement for target-based similarity benchmarking.

## Opening line

Pick one tone that matches the ask, e.g.:

- Named company: **"I'll pull their summary and segment breakdown if needed from deepKPI."**
- Thematic list: **"I'll search deepKPI’s company summaries for matches, then pull full summaries where we need detail."**

## Common failure modes

- **Answering “what do they do?” from memory** instead of **`get_company_summary`**.
- **Guessing segment names** instead of **`get_company_segments`** (or KPI search) when
  the user asked how the business is **broken out**.
- **Using `company_summary_search`** when the user named **one company** and only need
  summary/segments — use **Workflow A**.
- **Expecting full segment financial history** from **`get_company_segments` alone** —
  use **`retrieve-kpi-data`** for time series.


path: peer-benchmark/peer-benchmark.md
content: ---
name: peer-benchmark
description: >
  Operational peer / comp discovery for US public companies via deepKPI semantic search—not
  valuation multiples. Build KPI fingerprint from SEC data; company_summary_search (same-vertical
  first); align KPIs; diff gaps → segment sub-benchmarks. Outputs: tight chat 1-pager, optional
  Revelata HTML, optional Excel. Use when comparing to peers, finding comps or most-similar
  companies, benchmarking, comp sets, valuation peers, thematic "what's like X?", or segment
  pure-plays. Exclude unrelated verticals (e.g. gym vs car wash) except clear segment-to-segment,
  same customer + same need.
---

# peer-benchmark

Find comparable public companies ("benchmarks") for a target company or segment using deepKPI.
The output is not a mechanical list of industry peers — it's a curated set where every benchmark
adds a specific analytical lens, and where the gaps in coverage are as informative as the matches.

**Do not pair companies that do wildly different work** — different end customers, different
underlying need, different operating model — just because semantic search surfaced them together
(e.g. a gym chain and a car-wash operator). That is not a useful whole-company benchmark. The
only exception is when a **specific segment** of each business plausibly targets the **same
customers** with products that serve the **same job-to-be-done**; in that case, treat the match as
**segment-to-segment** (Step 3 sub-benchmarks, clearly labeled), not as "these two conglomerates
are comps."

**Vertical first, then wider.** Build the core benchmark set from companies in the **same
vertical** as the target's primary business (same industry, same customer job, same operating
shape) before you add names from **outside** that vertical. Broader or cross-vertical searches are
for filling gaps after same-vertical peers are in place, for a user-requested "outside the sector"
lens, or for Step 3 segment sub-benchmarks — not as the default first pass.

The workflow is explicitly iterative. Segment sub-benchmarks are not pre-assumed based on what
segments exist; they are discovered by diffing the target's KPI fingerprint against what the
whole-company benchmarks can actually explain. If something in the target's operations has no
counterpart in the whole-company set, that's the signal to go deeper.

## Dependencies

Before starting, read:
- `retrieve-kpi-data/retrieve-kpi-data.md` — retrieval workflow, provenance
  rules, scaling artifact handling, KPI search strategy. Required for all data pulls.
- `format-deepkpi-for-excel/format-deepkpi-for-excel.md` — only if user
  requests Excel output.

Every number displayed must have a `[value](provenance-url)` link. No exceptions.

## Output mode — ask first

**Before pulling any data**, ask the user which output format they want:

> "Would you like an **interactive HTML report** (opens in browser, clickable provenance links, Chart.js **time-series** charts) or **in-chat markdown** output? Or both?"

- If **HTML**: generate the full HTML report (dark Revelata branding, Chart.js line charts for KPI **trends over time**, fingerprint grid). Also produce the chat 1-pager as a compact summary.
- If **in-chat**: produce only the chat 1-pager with full markdown provenance links (see rules below). Offer the HTML at the end.
- If **both**: produce chat 1-pager first, then generate the HTML.

Offer Excel at the end regardless of which mode is chosen, unless the user already requested it.

## Outputs

| Format | When | Description |
|--------|------|-------------|
| Chat 1-pager | Always | Fingerprint pill rows + master table + KPI alignment + ≤5 notes — **all values hyperlinked** |
| HTML report | If user chose HTML or both | Dark Revelata-branded report with fingerprint grid, benchmark cards, and Chart.js **KPI trends over time** (line charts: target vs benchmarks on a shared period axis) |
| Excel workbook | User requests .xlsx | KPI alignment table, periods as columns per format spec |

### In-chat provenance link rules (non-negotiable)

Every numeric value shown in chat **must** be a markdown hyperlink to its source filing passage. No bare numbers.

Format: `[+4.9%](https://www.revelata.com/docviewer?pvid=11240)` — the pvid comes from the deepKPI response.

This applies everywhere in the chat output: fingerprint bullets, the KPI alignment table, notes, and the diff insight. If a value has no pvid (e.g. an estimate or derived metric), label it explicitly as `~$X est.` or `implied` with no link. Never omit the link for a directly sourced value.

Example of correct in-chat KPI alignment table row:
```
| TXRH | [+4.9%](https://www.revelata.com/docviewer?pvid=11240) | [$8.7M](https://www.revelata.com/docviewer?pvid=10061) | [714](https://www.revelata.com/docviewer?pvid=11537) |
```

---

## Workflow

The four steps below run in sequence. Steps 1–3 are analytical; Step 4 is output generation.
Run all deepKPI calls in parallel wherever possible to save time.

---

### Step 1: Build the target's KPI-enriched fingerprint

This is the foundation everything else builds on. Pull it from deepKPI — do not use general
knowledge for specific metrics.

**Calls:** `query_company_id` → `get_company_summary` → `get_company_segments` → `list_kpis`
→ `search_kpis` (for each segment's signature metrics)

**What to extract:**

**A. Narrative** — 2-3 sentences: business model, revenue drivers, customer type, go-to-market,
geography. Ground it in numbers where possible (unit count, revenue scale, market share if stated).

**B. Segment map** — For each reportable segment:
- Name and revenue share %
- One-sentence description of the economic model (how it makes money, who pays)
- 3-5 signature KPIs with actual values from deepKPI, each with provenance link

The segment KPIs are what make this fingerprint useful for diffing. For an airline: ASMs, load
factor, CASM, TRASM. For a refinery: capacity bpd, utilization %, gross margin per barrel.
For a restaurant segment: unit count, comp sales %, AUV. Pull the real numbers.

**C. KPI signature** — The 3-5 metrics that matter most for the consolidated company. These
become the columns in the KPI alignment table in the output.

**Output of Step 1:** An internal working document (not shown to user) with:
```
Target: [TICKER] — [Company] (CIK: NNNNNN, FY: DATE)
Primary vertical (for comp search ordering): [e.g. full-service restaurant, regional bank, SaaS HCM]
Narrative: ...
Segments:
  [Segment A] (XX% rev): [description] | KPIs: metric1=[val](url), metric2=[val](url), ...
  [Segment B] (XX% rev): [description] | KPIs: metric1=[val](url), ...
KPI signature: metric1, metric2, metric3 [, metric4, metric5]
```

---

### Step 2: Find candidates and align their fingerprints

**A. Search**

Run `company_summary_search` with 3-5 queries. Each query should describe a *business model*,
not just a sector name. The goal is semantic richness — describe what the company does, for whom,
how it earns money, and what drives its unit economics.

**Order matters — same vertical first.** At least **the first two queries** must stay tightly
inside the target's **primary vertical** (from Step 1: summary, segments, and the "Primary
vertical" line). Pull and KPI-align those results before you run looser or cross-vertical queries.
Use additional queries to go **outside** the vertical only **after** you have a credible
same-vertical candidate set, or when the user explicitly wants analogies from other sectors, or
when Step 3 needs a segment-specific search.

Examples of the contrast:
- Weak: `"airline"` → Strong: `"hub-and-spoke network carrier international domestic routes premium cabin loyalty co-brand revenue per ASM"`
- Weak: `"restaurant chain"` → Strong: `"multi-brand casual full-service dining operator franchised same-store sales average unit volume"`
- Weak: `"software company"` → Strong: `"B2B SaaS subscription recurring revenue net revenue retention enterprise mid-market"`

Use `top_k_companies: 10-12` per query. Deduplicate across queries. Target 6-12 candidates.

**B. KPI alignment**

For each candidate: call `list_kpis` (free), then `search_kpis` for the target's KPI signature
metrics (from Step 1C). This produces aligned rows — the target's metrics sitting next to each
candidate's equivalent metrics.

**Recency rule (do this from the start):** when the user’s question is about “current” / “latest”
comparability, prefer the **most recent quarterly periods** available (10‑Q-derived) for each KPI
over stopping at the last 10‑K annual figure. Use annual series for long-cycle context, but do not
ship a benchmark set that effectively says “data is old” if newer 10‑Q periods exist for the KPI.

The alignment reveals two things:
1. How close each candidate is on the dimensions that matter (similar range = structurally comparable)
2. Where candidates have no data or wildly different values (poor fit on that dimension)

Coverage coding:
- **Green**: metric present and plausible
- **Yellow**: metric present but value seems off (scaling artifact, possible cross-contamination)
- **Red**: no data

**C. Tier the candidates**

Based on the aligned KPI fingerprints (not just the description similarity), and only after
passing the **structural fit gate** below:

- **Tier 1**: Closest structural match — same business model and same customer/need, similar values on 3+ signature KPIs
- **Tier 2**: Useful comparators — same overall job-to-be-done; good match on some KPIs, different on others; adds a specific lens
- **Tier 3**: Same **kind** of business as the target, different scale, mix, or geography — still
  a coherent comp (e.g. regional vs national airline). **Not** unrelated verticals "for color."

**D. Structural fit gate (drop before the output table)**

Before anything appears in the chat 1-pager or HTML as a whole-company benchmark, ask: *Would
an investor reasonably describe this company as doing the **same job** for the **same type of
buyer** as the target?* If **no**, exclude it from Tier 1–3 for whole-company analysis — even if
a few metrics line up by coincidence. If there is a **real but narrow** overlap (same
wallet, same purchase occasion, same enterprise buyer for a specific product line), keep the
candidate **only** as a **segment** sub-benchmark in Step 3 with an explicit "Maps to: Segment …"
story, not as a peer for the consolidated company.

---

### Step 3: Diff — find what the whole-company benchmarks don't explain

This is the step that surfaces the most analytically valuable insights.

**The question:** After aligning KPI fingerprints in Step 2, which parts of the target's
operations have *no good coverage* in the whole-company benchmark set?

A "coverage gap" exists when:
1. The target has a reportable segment whose signature KPIs appear nowhere in the Tier 1/2 benchmark set, OR
2. The target reports KPIs that are structurally foreign to all benchmark candidates
   (e.g., `refinery throughput bpd` when all candidates are airlines), OR
3. A major segment has a fundamentally different economic model than what any whole-company
   benchmark represents

**For each gap identified:**

a. Build a **segment-specific fingerprint** using the segment's own KPIs from Step 1B
   ("this segment, if it were a standalone public company, would look like:")

b. Run a fresh `company_summary_search` describing that segment as a standalone business.
   Sub-benchmarks must still satisfy **same customer + same need** for that segment; do not
   pull unrelated verticals "for coverage."
   Use the segment's KPIs as the anchor — e.g., for a refinery segment:
   `"independent petroleum refiner crude oil throughput barrels per day capacity utilization refining margin per barrel crack spread"`.
   Not: `"refinery"`.

c. Pull KPI alignment for sub-benchmark candidates using the *segment's* KPI signature
   (not the parent company's consolidated metrics)

d. Tag all matches as `Maps to: Segment: [name]` in the master table

**Important framing:** The sub-benchmark tells you what that segment *would* look like as a
standalone profit-maximizing business. When the segment operates under a different economic logic
inside its parent (cost-center, captive supplier, hedge), say so explicitly — the gap between
the sub-benchmark's economics and the segment's implied economics *is the analytical insight*.

**Example of the diff in action:**
- Target: Delta (airline + refinery)
- Step 2 finds: UAL, AAL, LUV, ALK — all cover the airline KPIs (load factor, CASM, ASMs)
- Diff: `refinery throughput bpd`, `utilization %`, `gross margin/bbl` appear in Delta's segment
  map but in *none* of the airline benchmarks
- Step 3 triggers: build refinery segment fingerprint → search → find PBF, CVI, DINO as
  sub-benchmarks → align on throughput/utilization/margin
- Insight that emerges: Monroe's 200K bpd capacity is closest to CVI (207K bpd combined);
  PBF shares East Coast PADD 1 geography; but Monroe runs as a hedge, not a profit center —
  the merchant refiner margins ($8–16/bbl) represent the *opportunity cost* Delta pays to own it

The segment sub-benchmark logic is not limited to named segments. If the target has any
operational dimension that reads as structurally foreign to the whole-company comps —
a financial arm, a logistics network, a retail footprint embedded in a manufacturer —
ask whether a standalone pure-play exists in the S&P 1500 that illuminates it.

---

### Step 4: Build outputs

#### Chat 1-pager

Tight. No prose sidebars. Everything fits on one screen. In the **benchmark table** and **KPI
alignment** table, put **same-vertical** names first (clearest structural peers in the primary
vertical), then cross-vertical or segment-mapped comps, with `Maps to` spelling out any segment
story.

```
# Benchmarks for [Company] ([TICKER])

[TARGET FINGERPRINT — 2-3 sentences. Every sourced metric hyperlinked:
e.g. [+2.0% blended comps](https://www.revelata.com/docviewer?pvid=578),
[$12.1B revenue](https://www.revelata.com/docviewer?pvid=11442)]
Segments: [Segment A] XX% rev | [Segment B] XX% rev

## Benchmark table

| Ticker | Maps to | Similar on | Different on | Scale vs [TARGET] |
|--------|---------|------------|--------------|-------------------|

## KPI alignment — latest available period(s)

| Company | [metric1] | [metric2] | [metric3] | [segment metric] | Period |
|---------|-----------|-----------|-----------|-----------------|--------|
| [TARGET] | [val](pvid-url) | [val](pvid-url) | [val](pvid-url) | [val](pvid-url) | FY... or FY..-Q.. |
| BENCH1   | [val](pvid-url) | [val](pvid-url) | — | — | FY... or FY..-Q.. |

Column headers are plain text. Only the value cells carry hyperlinks.
Estimates/derived values: `~$X est.` with no link.

## Notes
- [≤5 bullets — only material caveats: scaling flags, cross-contamination, structural differences,
  coverage gaps, economic logic mismatches (cost-center vs. profit-maximizer)]

## Sources
[Ticker (CIK) — Green/Yellow/Red — FY end — any corrections]
```

If a section would be empty, omit it. If the KPI alignment table would exceed 10 rows, drop Tier 3
from it (keep Tier 3 in the benchmark table only).

#### HTML report

Read `references/html-template.md`. Key structure:

- **Hero fingerprint grid** (`table.fp-grid`): KPIs × benchmark columns only — **no prose inside the grid**
  (no "Why it matters", thesis blurbs, or `fp-context`-style rows). Put narrative in benchmark cards
  and diff insight. **`.legend-strip`** (color key) sits **below** the grid, not in the page header.
- **Benchmark cards** (one per company): order **same-vertical** peers before cross-vertical or
  segment-mapped names. Tier-colored top border, similar/different columns,
  key KPI values hyperlinked. Segment sub-benchmarks use purple border + "Segment:" badge.
- **KPI trends over time (charts + alignment table)**: This section is where deepKPI’s edge shows up—**filing-resolved time series** most vendors do not reconstruct at this depth. For the **2–3 most important** signature KPIs, pull **multi-period** values for the target **and every benchmark** (prefer quarterly where coverage is solid; otherwise annual—follow `retrieve-kpi-data` for period selection, scaling, and provenance). Render **Chart.js line charts** (not single-period grouped bars): **x-axis = time** (ordered FY/FQ labels), **one line per company** so the reader compares **trajectory, inflection, and pace** across competitors on the **same** metric. Put the full **KPI alignment** table (with hyperlinked values) **below** the charts as today. If a KPI truly has fewer than three comparable periods across the set, you may show a sparse line chart **or** a one-line caption pointing readers to the table—do not imply a cross-sectional bar is equivalent to the time-series view.
- **Chronology QA for every time-series chart (mandatory)**: Ensure the plotted points are in **chronological order** for every company series and the x-axis labels are in **ascending time**. **Do not rely on input order.** Sort by a real time key (prefer **period end date**; otherwise parse FY/FQ labels into a comparable key) before passing points to Chart.js. A zig-zagging line is almost always an ordering bug.
- **Y-axis QA for every time-series chart (mandatory)**: **Double-check** each chart’s **Y scale** before shipping HTML. The visible **min/max domain must include every non-null plotted point** across **all** series (target + benchmarks). **Do not** set fixed `min`/`max`, `suggestedMin`/`suggestedMax`, or `beginAtZero` unless those bounds are **recomputed from the union** of all series values—wrong bounds **clip lines off-canvas** so they look missing. Prefer automatic scaling plus **padding** (e.g. Chart.js `scales.y.grace` as a %) so tight clusters stay visible. For **log** scales, omit non-positive points or avoid log if that would drop the series; confirm lines still render. **Mentally verify each tab**: any ticker with data must show a **visible** polyline or points—not a legend entry with no trace.
- **Diff insight box** (cyan glow, same as synthesis in pressure test): 2 paragraphs on what
  the benchmark set reveals that whole-company analysis would miss.
- **Notes** and **Sources** footer.

#### Excel workbook

Follow `format-deepkpi-for-excel/format-deepkpi-for-excel.md`.
One sheet for whole-company benchmarks, one sheet per segment sub-benchmark group.
Annual periods as columns; green cells for target values; clickable provenance links.

---

## Failure modes

- **Assuming segment sub-benchmarks without doing the diff**: Don't pre-decide "this company
  has a real estate arm so I'll find REITs." Let the KPI gap analysis surface it. The diff step
  earns its keep precisely because the gaps are often surprising.
- **Narrative-only fingerprint**: If Step 1 doesn't pull actual KPI values, the diff in Step 3
  has nothing to work with. The fingerprint must have numbers.
- **Prose inside the HTML hero grid**: Do not add "Why it matters", thesis blurbs, or other
  commentary rows inside `table.fp-grid` — the grid is KPI labels and numbers only. Use benchmark
  cards and diff insight for narrative (`references/html-template.md`).
- **Skipping KPI alignment for candidates**: Checking description similarity is not enough.
  Pull the actual metrics — two companies can describe themselves similarly but operate very
  differently when you look at unit economics.
- **Treating all segments equally**: Not every segment warrants a sub-benchmark search.
  Focus on segments where: (a) the parent discloses separate KPIs, and (b) the KPIs are foreign
  to the whole-company benchmark set.
- **Time series plotted out of order**: If any chart line zig-zags “backward,” the points are not time-sorted. Sort each series by **period end date** (or FY/FQ key) before charting, and make sure the shared x-axis label list is in ascending order too.
- **Y-axis clips time series in HTML**: Hard-coded or guessed Y bounds, or `beginAtZero` used without checking the data band, often **hides entire lines** outside the drawable range. Always derive bounds from **all** series (or use defaults + `grace`) and re-check before delivery.
- **Too much prose in chat**: The 1-pager is a reference artifact. Cut until it hurts.
- **Skipping list_kpis**: Free call that prevents wasted credits on metrics that don't exist.
- **Unrelated verticals as comps**: A gym and a car wash are not whole-company benchmarks for
  each other unless you have a defensible segment-level story (same customers, same need). If you
  cannot write that one sentence without hand-waving, drop the name.
- **Cross-vertical before in-vertical**: Do not foreground or prioritize outside-the-vertical
  names until same-vertical peers are identified and KPI-aligned. If the first search pass drifts
  cross-vertical, reset with tighter in-vertical queries before presenting the table.


path: peer-benchmark/references/html-template.md
content: # Benchmarking HTML Report Template

Revelata dark-theme benchmark report. The design is **data-forward**: the primary element is a
fingerprint × coverage grid (KPIs as rows, companies as columns), not a prose fingerprint box.
Benchmark cards below the grid provide narrative context per company.

**Logo:** The Revelata wordmark is **inlined as SVG** in the header (same asset as Analysis Pressure
Test reports). No external image file. The logo link targets `https://www.revelata.com/for-ai-builders`.
**Header layout:** `.header` is a **single-column stack** — `.header-brand` row with SVG,
pipe divider, **Benchmark Analysis (GitHub)** link (no separate product label in that row);
then `h1` with cyan `.ticker` span; then `.header-meta`. **No legend in the header.**
**Legend placement:** `.legend-strip` is a **standalone** horizontal flex row placed **immediately
below** the fingerprint grid (after `</div><!-- grid-wrap -->`), not inside `.header`.
**Fonts:** Inter + Figtree (Google Fonts `@import`) plus JetBrains Mono for numeric cells.

---

## Design principles for benchmarking reports

- Fingerprint × coverage grid as hero
- **No commentary or prose inside the grid.** The hero table is **data only**: group-header rows,
  column headers, KPI label rows, numeric cells (with provenance links), and `—` for missing
  coverage. Do **not** add rows such as "Why it matters", thesis blurbs, `fp-context`, or any
  explanatory copy inside `table.fp-grid`. Put all narrative in **Benchmark Detail** cards and
  **Diff Insight** below the grid.
- Plain category dividers (lighter font, no tier numbers)
- **Tickers only** in column headers
- **White** = target column (amber/yellow means partial match)
- Corrected values shown silently
- `.bmark-row` compact row layout

**Ticker color coding (both column headers and card headings):**
- White `#fff` — target company
- Green `var(--green)` `#22c55e` — strong structural match
- Yellow `var(--yellow)` `#eab308` — partial match
- Purple `var(--purple)` `#a855f7` — segment sub-benchmark
- No "red" tickers — companies with no match simply aren't included

**Cell color coding in the grid:**
- `td.cell.target-col` — `background: transparent; color: #fff` (target text reads white; row hover adds a light wash — see **Fingerprint grid** CSS)
- `td.cell.match-strong` — `background: var(--green-mid); color: #86efac`
- `td.cell.match-partial` — `background: var(--yellow-mid); color: #fde68a`
- `td.cell.match-none` — transparent, `color: var(--text-dim)`, shows `—` or brief note
- `td.cell.seg-cell` — `background: var(--purple-dim); color: #d8b4fe`

---

## CSS variables (do not change)

```css
:root {
  --bg: #0a0d13; --surface: #111318; --surface2: #181c24;
  --border: #252b36; --border-light: #2e3647;
  --text: #dce4f0; --text-muted: #7a8799; --text-dim: #4e5a6a;
  --cyan: #4FEAFF; --cyan-dim: rgba(79,234,255,0.1); --cyan-glow: rgba(79,234,255,0.06);
  --amber: #f59e0b; --amber-dim: rgba(245,158,11,0.1); --amber-text: #fbbf24;
  --green: #22c55e; --green-dim: rgba(34,197,94,0.12); --green-mid: rgba(34,197,94,0.2);
  --yellow: #eab308; --yellow-dim: rgba(234,179,8,0.12); --yellow-mid: rgba(234,179,8,0.18);
  --red: #ef4444; --red-dim: rgba(239,68,68,0.1);
  --purple: #a855f7; --purple-dim: rgba(168,85,247,0.12);
  --blue: #3b82f6; --blue-dim: rgba(59,130,246,0.1);
}
```

---

## Page shell: fonts, body, and header (match Analysis Pressure Test)

The **top of every benchmark HTML file** uses the same `body` canvas as Analysis Pressure Test
(`padding: 2.5rem`, `max-width: 900px`, `font-size: 14.5px`). The **header chrome** matches the
pressure-test asset and links: **inlined Revelata SVG** in an anchor to
`https://www.revelata.com/for-ai-builders`, pipe divider, and **Benchmark Analysis (GitHub)** —
all inline in `.header-brand`. The header is a **single-column stack** (no legend inside it). The
color legend is a separate **`.legend-strip`** placed **after the fingerprint grid** (see **Grid skeleton** below).

Use the **complete** last `<path>` for the coin mark (inner strokes) — truncated copies omit detail
and look wrong. Title line: `h1` with `<span class="ticker">[TICKER]</span>` in cyan; metadata:
`.header-meta` with optional `.meta-dot` on the first item.

Merge this **after** the benchmark `:root` block. `.header h1` and `.header-meta` are scoped under
`.header` so they do not fight other headings if you add section titles later.

```css
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Figtree:wght@400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap');

* { box-sizing: border-box; margin: 0; padding: 0; }
body {
  font-family: 'Inter', system-ui, sans-serif;
  background: var(--bg); color: var(--text);
  line-height: 1.7; padding: 2.5rem;
  max-width: 900px; margin: 0 auto;
  font-size: 14.5px; -webkit-font-smoothing: antialiased;
}

/* Header — single-column stack, no legend */
.header {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-bottom: 1rem;
}
.header-brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.75rem;
  flex-wrap: wrap;
}
.header-brand .header-logo {
  display: block;
  height: 22px;
  width: auto;
  flex-shrink: 0;
}
.header-brand > a {
  color: inherit;
  text-decoration: none;
  line-height: 0;
}
.header-brand > a:hover { opacity: 0.9; }
.header-divider {
  color: var(--border-light);
  font-weight: 300;
  font-size: 1.25rem;
  line-height: 1;
  margin: 0 0.05rem;
}
.header-github a {
  font-family: 'Figtree', 'Inter', system-ui, sans-serif;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--cyan);
  text-decoration: none;
}
.header-github a:hover {
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 3px;
}
.header h1 {
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: #fff;
  margin-bottom: 0.35rem;
}
.header h1 .ticker { color: var(--cyan); }
.header-meta {
  margin-top: 0.15rem;
  font-size: 0.78rem;
  color: var(--text-muted);
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  align-items: center;
}
.header-meta span {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}
.meta-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--cyan);
  flex-shrink: 0;
}

/* Legend strip — standalone element BELOW the grid, not inside the header */
.legend-strip {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 1.4rem;
  align-items: center;
  font-size: 0.78rem;
  color: var(--text-muted);
  padding: 0.65rem 0.8rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  margin-top: 0.6rem;
  margin-bottom: 2.5rem;
}
.legend-strip .legend-item { display: flex; align-items: center; gap: 0.4rem; }
.legend-strip .legend-swatch {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  flex-shrink: 0;
}

@media (max-width: 700px) {
  body { padding: 1.2rem; }
}

```

### Header HTML (embedded SVG — required)

```html
<!-- ===== HEADER ===== -->
<div class="header">
    <div class="header-brand">
      <a href="https://www.revelata.com/for-ai-builders" target="_blank" rel="noopener noreferrer" aria-label="Revelata">
        <svg class="header-logo" width="159" height="34" viewBox="0 0 159 34" fill="none" xmlns="http://www.w3.org/2000/svg" aria-label="Revelata Inc">
          <path d="M42.4412 26.6676V7.28626H48.7539C50.0091 7.28626 51.1166 7.53545 52.0765 8.03382C53.0548 8.5322 53.8116 9.22439 54.3468 10.1104C54.9006 10.9964 55.1775 12.0116 55.1775 13.156C55.1775 14.3005 54.8821 15.3157 54.2915 16.2017C53.7008 17.0877 52.8979 17.7891 51.8826 18.3059C50.8674 18.8043 49.723 19.0535 48.4494 19.0535H44.7946V26.6676H42.4412ZM53.3778 26.6676L48.7263 18.7213L50.5813 17.503L55.9527 26.6676H53.3778ZM44.7946 16.8939H49.0862C49.7876 16.8939 50.4152 16.737 50.969 16.4232C51.5227 16.0909 51.9657 15.6479 52.298 15.0942C52.6487 14.522 52.824 13.8759 52.824 13.156C52.824 12.0485 52.4364 11.1533 51.6611 10.4703C50.9043 9.76891 49.9168 9.4182 48.6986 9.4182H44.7946V16.8939ZM65.1997 26.9999C63.8523 26.9999 62.6617 26.6953 61.628 26.0862C60.5944 25.4586 59.7822 24.6003 59.1915 23.5112C58.6193 22.4222 58.3332 21.167 58.3332 19.7457C58.3332 18.3244 58.6193 17.0692 59.1915 15.9802C59.7822 14.8911 60.5851 14.042 61.6004 13.4329C62.634 12.8053 63.8154 12.4915 65.1444 12.4915C66.4365 12.4915 67.5532 12.8146 68.4946 13.4606C69.436 14.0882 70.1651 14.9742 70.6819 16.1186C71.1987 17.263 71.4572 18.6105 71.4572 20.161H60.0222L60.5759 19.6903C60.5759 20.7978 60.7697 21.7484 61.1574 22.5421C61.5634 23.3359 62.1264 23.945 62.8463 24.3695C63.5662 24.7756 64.3876 24.9787 65.3105 24.9787C66.2888 24.9787 67.1102 24.7479 67.7747 24.2865C68.4577 23.825 68.9837 23.2159 69.3529 22.4591L71.2633 23.4281C70.9126 24.148 70.4419 24.7756 69.8513 25.3109C69.2791 25.8462 68.5961 26.2615 67.8024 26.5569C67.0271 26.8522 66.1596 26.9999 65.1997 26.9999ZM60.7144 18.7489L60.1329 18.3059H69.6851L69.1037 18.7766C69.1037 17.8906 68.9283 17.1246 68.5776 16.4786C68.2269 15.8325 67.7562 15.3341 67.1656 14.9834C66.5749 14.6327 65.8919 14.4574 65.1167 14.4574C64.3599 14.4574 63.64 14.6327 62.957 14.9834C62.2925 15.3341 61.748 15.8325 61.3235 16.4786C60.9174 17.1061 60.7144 17.8629 60.7144 18.7489ZM78.1355 26.6676L83.7838 12.8238H86.1095L80.3228 26.6676H78.1355ZM77.9971 26.6676L72.2103 12.8238H74.5084L80.1567 26.6676H77.9971ZM94.023 26.9999C92.6755 26.9999 91.485 26.6953 90.4513 26.0862C89.4176 25.4586 88.6055 24.6003 88.0148 23.5112C87.4426 22.4222 87.1565 21.167 87.1565 19.7457C87.1565 18.3244 87.4426 17.0692 88.0148 15.9802C88.6055 14.8911 89.4084 14.042 90.4236 13.4329C91.4573 12.8053 92.6386 12.4915 93.9676 12.4915C95.2597 12.4915 96.3765 12.8146 97.3178 13.4606C98.2592 14.0882 98.9883 14.9742 99.5052 16.1186C100.022 17.263 100.28 18.6105 100.28 20.161H88.8454L89.3992 19.6903C89.3992 20.7978 89.593 21.7484 89.9806 22.5421C90.3867 23.3359 90.9497 23.945 91.6696 24.3695C92.3894 24.7756 93.2108 24.9787 94.1338 24.9787C95.1121 24.9787 95.9335 24.7479 96.598 24.2865C97.2809 23.825 97.807 23.2159 98.1762 22.4591L100.087 23.4281C99.7359 24.148 99.2652 24.7756 98.6745 25.3109C98.1023 25.8462 97.4194 26.2615 96.6256 26.5569C95.8504 26.8522 94.9828 26.9999 94.023 26.9999ZM89.5376 18.7489L88.9562 18.3059H98.5084L97.927 18.7766C97.927 17.8906 97.7516 17.1246 97.4009 16.4786C97.0502 15.8325 96.5795 15.3341 95.9888 14.9834C95.3982 14.6327 94.7152 14.4574 93.9399 14.4574C93.1832 14.4574 92.4633 14.6327 91.7803 14.9834C91.1158 15.3341 90.5713 15.8325 90.1467 16.4786C89.7407 17.1061 89.5376 17.8629 89.5376 18.7489ZM103.074 26.6676V7.28626H105.289V26.6676H103.074ZM117.686 26.6676L117.575 24.3972V19.3581C117.575 18.269 117.455 17.3738 117.215 16.6724C116.975 15.9525 116.597 15.408 116.08 15.0388C115.563 14.6696 114.889 14.485 114.058 14.485C113.302 14.485 112.646 14.6419 112.093 14.9557C111.557 15.2511 111.114 15.731 110.764 16.3955L108.77 15.6202C109.121 14.9742 109.545 14.4204 110.044 13.959C110.542 13.4791 111.124 13.1191 111.788 12.8792C112.453 12.6207 113.209 12.4915 114.058 12.4915C115.351 12.4915 116.412 12.75 117.243 13.2668C118.092 13.7652 118.728 14.5127 119.153 15.5095C119.578 16.4878 119.781 17.706 119.762 19.1643L119.734 26.6676H117.686ZM113.532 26.9999C111.908 26.9999 110.634 26.6307 109.712 25.8923C108.807 25.1356 108.355 24.0927 108.355 22.7636C108.355 21.3608 108.816 20.2902 109.739 19.5519C110.681 18.7951 111.991 18.4167 113.671 18.4167H117.63V20.2718H114.169C112.877 20.2718 111.954 20.484 111.4 20.9086C110.865 21.3331 110.598 21.9422 110.598 22.736C110.598 23.4558 110.865 24.028 111.4 24.4526C111.936 24.8587 112.683 25.0617 113.643 25.0617C114.437 25.0617 115.129 24.8956 115.72 24.5633C116.31 24.2126 116.763 23.7235 117.076 23.0959C117.409 22.4499 117.575 21.6931 117.575 20.8255H118.516C118.516 22.7083 118.092 24.2126 117.243 25.3386C116.393 26.4461 115.157 26.9999 113.532 26.9999ZM128.477 26.9999C127.13 26.9999 126.087 26.6491 125.349 25.9477C124.61 25.2463 124.241 24.2588 124.241 22.9851V8.50451H126.456V22.7636C126.456 23.4651 126.641 24.0096 127.01 24.3972C127.397 24.7664 127.933 24.951 128.616 24.951C128.837 24.951 129.049 24.9233 129.252 24.8679C129.474 24.7941 129.76 24.6279 130.111 24.3695L130.969 26.1692C130.489 26.483 130.055 26.6953 129.668 26.806C129.28 26.9352 128.883 26.9999 128.477 26.9999ZM121.832 14.7896V12.8238H130.609V14.7896H121.832ZM142.183 26.6676L142.072 24.3972V19.3581C142.072 18.269 141.952 17.3738 141.712 16.6724C141.472 15.9525 141.094 15.408 140.577 15.0388C140.06 14.6696 139.386 14.485 138.556 14.485C137.799 14.485 137.143 14.6419 136.59 14.9557C136.054 15.2511 135.611 15.731 135.261 16.3955L133.267 15.6202C133.618 14.9742 134.042 14.4204 134.541 13.959C135.039 13.4791 135.621 13.1191 136.285 12.8792C136.95 12.6207 137.706 12.4915 138.556 12.4915C139.848 12.4915 140.909 12.75 141.74 13.2668C142.589 13.7652 143.226 14.5127 143.65 15.5095C144.075 16.4878 144.278 17.706 144.259 19.1643L144.232 26.6676H142.183ZM138.029 26.9999C136.405 26.9999 135.132 26.6307 134.209 25.8923C133.304 25.1356 132.852 24.0927 132.852 22.7636C132.852 21.3608 133.313 20.2902 134.236 19.5519C135.178 18.7951 136.488 18.4167 138.168 18.4167H142.127V20.2718H138.666C137.374 20.2718 136.451 20.484 135.898 20.9086C135.362 21.3331 135.095 21.9422 135.095 22.736C135.095 23.4558 135.362 24.028 135.898 24.4526C136.433 24.8587 137.18 25.0617 138.14 25.0617C138.934 25.0617 139.626 24.8956 140.217 24.5633C140.807 24.2126 141.26 23.7235 141.573 23.0959C141.906 22.4499 142.072 21.6931 142.072 20.8255H143.013C143.013 22.7083 142.589 24.2126 141.74 25.3386C140.891 26.4461 139.654 26.9999 138.029 26.9999Z" fill="#ffffff"/>
          <path d="M146.357 28.6888V26.6676H157.432V28.6888H146.357Z" fill="#4FEAFF"/>
          <path d="M5.08739 7.94839L16.9844 2.21909L28.8814 7.94839L31.8197 20.822L23.5868 31.1459H10.3821L2.14907 20.822L5.08739 7.94839Z" stroke="#4FEAFF" stroke-width="1.78606"/>
          <path d="M7.16529 15.9562L12.0207 8.8345L20.616 8.19038L26.4787 14.5088L25.194 23.0319L17.7294 27.3416L9.70589 24.1926L7.16529 15.9562Z" stroke="#4FEAFF" stroke-width="1.78606"/>
          <path d="M13.3317 14.5225L16.9857 12.7628L20.6398 14.5225L21.5423 18.4765L19.0136 21.6474H14.9579L12.4292 18.4765L13.3317 14.5225Z" stroke="#4FEAFF" stroke-width="1.78606"/>
          <path d="M31.9318 30.2429C31.6471 30.2429 31.3754 30.1885 31.1166 30.0798C30.863 29.9711 30.6405 29.821 30.449 29.6295C30.2575 29.438 30.1074 29.2155 29.9987 28.9619C29.89 28.7031 29.8356 28.4314 29.8356 28.1467C29.8356 27.8517 29.89 27.5774 29.9987 27.3238C30.1074 27.0702 30.2575 26.8476 30.449 26.6561C30.6405 26.4646 30.863 26.3145 31.1166 26.2058C31.3754 26.0971 31.6471 26.0428 31.9318 26.0428C32.2268 26.0428 32.5011 26.0971 32.7547 26.2058C33.0084 26.3145 33.2309 26.4646 33.4224 26.6561C33.6139 26.8476 33.764 27.0702 33.8727 27.3238C33.9814 27.5774 34.0357 27.8517 34.0357 28.1467C34.0357 28.4314 33.9814 28.7031 33.8727 28.9619C33.764 29.2155 33.6139 29.438 33.4224 29.6295C33.2309 29.821 33.0084 29.9711 32.7547 30.0798C32.5011 30.1885 32.2268 30.2429 31.9318 30.2429ZM31.9318 29.8081C32.2579 29.8081 32.5451 29.7382 32.7936 29.5985C33.042 29.4587 33.2361 29.2647 33.3758 29.0162C33.5156 28.7626 33.5854 28.4728 33.5854 28.1467C33.5854 27.8155 33.5156 27.5256 33.3758 27.2772C33.2361 27.0287 33.042 26.8347 32.7936 26.6949C32.5451 26.55 32.2579 26.4775 31.9318 26.4775C31.6109 26.4775 31.3262 26.55 31.0778 26.6949C30.8294 26.8347 30.6353 27.0287 30.4955 27.2772C30.3558 27.5256 30.2859 27.8155 30.2859 28.1467C30.2859 28.4728 30.3558 28.7626 30.4955 29.0162C30.6353 29.2647 30.8294 29.4587 31.0778 29.5985C31.3262 29.7382 31.6109 29.8081 31.9318 29.8081ZM31.1477 29.2491V26.9822H31.9629C32.1958 26.9822 32.3873 27.0494 32.5374 27.184C32.6875 27.3134 32.7625 27.4868 32.7625 27.7042C32.7625 27.8491 32.7211 27.9785 32.6383 28.0924C32.5607 28.2062 32.4546 28.2916 32.32 28.3486L32.8557 29.2491H32.3976L31.9318 28.4262H31.5514V29.2491H31.1477ZM31.5514 28.0535H31.9784C32.0819 28.0535 32.1673 28.0225 32.2346 27.9604C32.307 27.8931 32.3433 27.8077 32.3433 27.7042C32.3433 27.5955 32.307 27.5101 32.2346 27.448C32.1621 27.3807 32.0664 27.3471 31.9473 27.3471H31.5514V28.0535Z" fill="#4FEAFF"/>
        </svg>
      </a>
      <span class="header-divider">|</span>
      <span class="header-github"><a href="https://github.com/revelata/deepkpi-agents" target="_blank" rel="noopener noreferrer">Benchmark Analysis (GitHub)</a></span>
    </div>
    <h1><span class="ticker">[TICKER]</span> &mdash; [Company Name]</h1>
    <div class="header-meta">
      <span><span class="meta-dot"></span>[Sector / business description]</span>
      <span>FY [date]</span>
      <span>CIK [##########]</span>
      <span>[N] benchmarks &middot; [M] segment groups</span>
    </div>
</div>

<!-- NOTE: Legend is NOT in the header. Place it after the grid-wrap closes. See "Grid skeleton" below. -->
```

## Document structure

```
HEADER (.header — single-column stack; no legend inside)
  .header-brand: <a for-ai-builders> + inlined SVG | Benchmark Analysis (GitHub)
  h1: <span class="ticker">[TICKER]</span> — [Company Name]
  .header-meta: sector (with .meta-dot) · FY · CIK · benchmark / segment counts

FINGERPRINT × COVERAGE GRID   ← hero element (DATA ONLY — see design principles + Rules)
  (first content after .header closes — no extra title bar above the grid)
  fp-grid table:
    group-header row: "Target" | "Group A label" | "Group B label (seg, purple)"
    col-header row: ticker pills (target=white, strong=green, partial=yellow, seg=purple)
    KPI rows:
      row-header: kpi-name + kpi-sub (left-aligned text)
      cells: target-col | match-strong | match-partial | match-none | seg-cell (centered numbers)
    NO prose / commentary rows inside the table (no "Why it matters", no fp-context, no thesis copy)
    group-header separator rows for new KPI groups (e.g. segment-specific KPIs)

LEGEND STRIP (.legend-strip — immediately AFTER </div><!-- grid-wrap -->)
  Horizontal row: Target | Strong match | Partial match | Segment (.legend-swatch squares)

BENCHMARK DETAIL
  section-label: "Benchmark Detail"
  cat-divider: "[Group name]"    ← plain text, font-weight:500, color:var(--text-dim)
  bmark-list:
    bmark-row: (bmark-id with ticker+name) + (bmark-data with kpi-comp blocks + bmark-note)
  cat-divider (segment, purple): "[Segment] — segment sub-benchmarks"
  bmark-list: (segment benchmarks)

KPI TRENDS OVER TIME
  section-label: "KPI trends over time"
  section-intro (one line under the label, optional but recommended):
    "Same metric, multiple companies, filing-resolved periods—compare **trajectory**, not just a single snapshot."
  chart-tabs: tabbed interface — one tab per fingerprint KPI (typically 2–3)
    Tab nav: .tab-btn elements, active tab highlighted in var(--cyan)
    Tab panels: one canvas per tab, Chart.js **line** chart (`type: 'line'`)
    X-axis: ordered reporting periods (FY… and/or FQ…), aligned across tickers where data exists
    Y-axis: KPI value (unit in tab label or chart subtitle); **log scale** when ranges are extreme (e.g. energy GWh)
    Y-axis QA (mandatory): **Double-check** the Y domain **includes every plotted value** for **every**
      series. Wrong `min`/`max`, `suggestedMin`/`suggestedMax`, or `beginAtZero` **clips** lines so they
      vanish—derive bounds from the **union** of all series or rely on Chart.js auto scales plus **padding**
      (`scales.y.grace`, e.g. 5–15%). Log scale: drop or skip non-positive values; confirm remaining lines render.
      If any legend entry has data but **no visible line**, treat it as a **blocking bug** and fix the axis.
    Datasets: **one line per company** (target + each benchmark). Line / point colors match ticker tier colors
      (same palette as the fingerprint grid — see **Chart color conventions**)
    DRI target segments: separate **lines** (e.g. dashed vs solid) within the target white/gray palette,
      not separate bars
    Data: multi-period pulls per `retrieve-kpi-data` / `peer-benchmark.md` — this section showcases
      deepKPI **time series** competitors rarely get elsewhere; do not substitute a one-year grouped
      bar chart unless history is too sparse (&lt;3 shared periods); if forced, state the limitation in the chart caption

DIFF INSIGHT
  section-label: "Diff Insight"
  synthesis box (cyan left border): 2 paragraphs
    P1: what whole-company benchmarks reveal about the target
    P2: what the diff surfaced — segment gap or structural insight

NOTES
  section-label: "Notes"
  notes-list: ≤5 items (material caveats only — no scaling artifact explanations)

SOURCES
  section-label: "Sources"
  sources-table: Ticker | CIK | Coverage | FY end | Notes

FOOTER
  "Benchmark data sourced from SEC filings via Revelata deepKPI. All values link to source filing passages."
  Right: "FY[YEAR] · [Month YEAR]"

CLOSING CTA ("try it yourself")
  Same block as Analysis Pressure Test HTML: linked headline "Run this on any report with your agent:",
  two columns (Claude vs OpenClaw) with MCP URL, install.sh curl, and a final bullet (use the
  benchmark-specific prompts in the HTML skeleton below, not "Pressure test this report").

DISCLOSURES
  Same legal paragraphs as Analysis Pressure Test reports: Compensation, Third-Party Content,
  General, and the follow-on unlabeled paragraph (verbatim from pressure-test template).
```

---

## Key CSS classes

### Fingerprint grid

```css
.grid-wrap { overflow-x: auto; }
.fp-grid { border-collapse: collapse; width: 100%; font-size: 0.74rem; }

/* Sticky row label — KPI names only (left-aligned); grid has no prose rows */
.fp-grid th.row-header, .fp-grid td.row-header {
  position: sticky; left: 0; z-index: 2;
  background: var(--bg); min-width: 140px; max-width: 160px;
  text-align: left;
  vertical-align: top;
}

/* Group separator rows */
.fp-grid .group-header th {
  background: var(--bg); font-size: 0.56rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim);
  padding: 0.5rem 0.6rem 0.2rem; border-top: 1px solid var(--border);
}

/* Col header ticker pills */
.col-ticker { font-family: 'Figtree', monospace; font-weight: 700; font-size: 0.85rem; }
.col-ticker.target  { color: #fff; }
.col-ticker.match-strong { color: var(--green); }
.col-ticker.match-partial { color: var(--yellow); }
.col-ticker.seg { color: var(--purple); }

/* Data cells — tighter padding */
.fp-grid td.cell {
  padding: 0.35rem 0.55rem; border-bottom: 1px solid var(--border);
  text-align: center; vertical-align: middle; white-space: nowrap; min-width: 92px;
  font-family: 'JetBrains Mono', monospace; font-size: 0.71rem;
}

/* Row hover highlight */
.fp-grid tbody tr { transition: background 0.1s ease; }
.fp-grid tbody tr:not(.group-header):hover { background: rgba(255,255,255,0.035); }
.fp-grid tbody tr.group-header { background: var(--bg) !important; }

/* Cell states */
td.cell.target-col  { background: transparent; color: #fff; font-weight: 600; }
td.cell.match-strong { background: var(--green-mid); color: #86efac; }
td.cell.match-partial { background: var(--yellow-mid); color: #fde68a; }
td.cell.match-none   { background: transparent; color: var(--text-dim); }
td.cell.seg-cell     { background: var(--purple-dim); color: #d8b4fe; }

/* Delta sub-value */
.delta { display: block; font-size: 0.58rem; color: inherit; opacity: 0.65; margin-top: 0.08rem; }
```

### Benchmark cards

```css
.bmark-row {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 7px; display: grid; grid-template-columns: 100px 1fr; overflow: hidden;
}
.bmark-id {
  padding: 0.55rem 0.7rem; border-right: 1px solid var(--border);
  display: flex; flex-direction: column; justify-content: center;
  background: var(--surface2);
}
.bm-ticker { font-family: 'Figtree', monospace; font-weight: 700; font-size: 1rem; }
.bm-ticker.strong { color: var(--green); }
.bm-ticker.partial { color: var(--yellow); }
.bm-ticker.seg    { color: var(--purple); }

/* Category dividers — lighter than old tier labels */
.cat-divider {
  font-size: 0.6rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--text-dim); margin: 1rem 0 0.4rem; padding-bottom: 0.25rem;
  border-bottom: 1px solid var(--border);
}
/* Segment sub-benchmark group */
.cat-divider.seg { color: var(--purple); border-color: rgba(168,85,247,0.2); }
```

### Synthesis (Diff Insight)

```css
.synthesis {
  background: linear-gradient(135deg, rgba(79,234,255,0.04) 0%, transparent 60%);
  border: 1px solid rgba(79,234,255,0.15); border-left: 3px solid var(--cyan);
  border-radius: 7px; padding: 0.9rem 1.1rem; margin: 0.4rem 0 1.2rem;
}
.synthesis-title {
  font-size: 0.58rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.09em; color: var(--cyan); margin-bottom: 0.7rem;
}
```

### Page footer, closing CTA, and disclosures

Use the same rules as `analyst-report-pressure-test/references/html-template.md`: data
footer, then **closing CTA** (self-serve install), then **disclosures**. Copy the CSS below
into the report’s `<style>` block (merge with existing rules).

```css
/* Footer */
.footer {
  margin-top: 2.5rem; padding-top: 1.4rem;
  border-top: 1px solid var(--border);
  font-size: 0.75rem; color: var(--text-dim); text-align: center;
}
.footer a { color: var(--cyan); text-decoration: none; }
.footer a:hover { text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 3px; }

/* Disclosures */
.disclosures {
  margin-top: 1.5rem; padding-top: 1.2rem;
  border-top: 1px solid var(--border);
  font-size: 0.68rem; color: var(--text-dim);
  line-height: 1.6;
}
.disclosures p { margin-top: 0.7rem; }
.disclosures p:first-child { margin-top: 0; }
.disclosures strong { color: var(--text-muted); font-weight: 700; }

/* Closing CTA — plain on page background, between footer and disclosures */
.closing-cta {
  margin-top: 2rem;
  font-size: 0.82rem; color: var(--text-muted);
  line-height: 1.65;
}
.closing-cta .cta-setup-label {
  font-family: 'Figtree', 'Inter', system-ui, sans-serif;
  font-size: 1.15rem; font-weight: 700;
  margin-bottom: 1rem;
}
.closing-cta .cta-setup-label a {
  color: var(--cyan);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 0.15s ease;
}
.closing-cta .cta-setup-label a:hover {
  border-bottom-color: var(--cyan);
  text-decoration: none;
}
.closing-cta .cta-paths {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1.6rem;
  margin-top: 0.3rem;
}
.closing-cta .cta-path-label {
  font-size: 0.7rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--text); margin-bottom: 0.5rem;
  padding-bottom: 0.4rem; border-bottom: 1px solid var(--border);
}
.closing-cta strong { color: var(--text-muted); font-weight: 700; }
.closing-cta a:not(.cta-setup-label *) {
  color: var(--cyan); text-decoration: underline;
  text-decoration-style: dotted; text-underline-offset: 2px;
}
.closing-cta a:not(.cta-setup-label *):hover { text-decoration-style: solid; }
.closing-cta ol { padding-left: 1.3rem; margin-top: 0.3rem; }
.closing-cta ol li { margin: 0.35rem 0; }
.closing-cta code {
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 0.75rem; color: var(--text);
  background: var(--surface); padding: 1px 6px; border-radius: 3px;
  border: 1px solid var(--border);
}

@media (max-width: 700px) {
  .closing-cta .cta-paths { grid-template-columns: 1fr; gap: 1.2rem; }
}
```

---

## Footer, “try it yourself” CTA, and disclosures (HTML)

Place **after** the main benchmark content (e.g. after Sources). The **closing CTA** is the same
self-serve (“try it yourself”) install block as in `analyst-report-pressure-test/references/html-template.md`
(same headline link text, same steps 1–2). Step 3 must reference **benchmarking / peers / comps**
(see below), not pressure-testing an analyst report. The **disclosure** `<div class="disclosures">`
block matches the pressure-test template **word for word**.

```html
<!-- ===== FOOTER ===== -->
<div class="footer">
  Benchmark data sourced from SEC filings via
  <a href="https://www.revelata.com" target="_blank" rel="noopener noreferrer">Revelata deepKPI</a>.
  All values link to source filing passages.
</div>

<!-- ===== CLOSING CTA (try it yourself) ===== -->
<div class="closing-cta">
  <p class="cta-setup-label">
    <a href="https://github.com/revelata/deepkpi-agents" target="_blank" rel="noopener noreferrer">Try it yourself:</a>
  </p>
  <p>
    Installation and setup instructions live on GitHub:
    <a href="https://github.com/revelata/deepkpi-agents" target="_blank" rel="noopener noreferrer">deepkpi-agents</a>.
  </p>
</div>

<!-- ===== DISCLOSURES (same as Analysis Pressure Test template) ===== -->
<div class="disclosures">
  <p><strong>Compensation Disclosure:</strong> No part of the compensation of any Revelata personnel was, is, or will be directly or indirectly related to the specific views, conclusions, or recommendations expressed in this report, or to the coverage of any particular security or issuer herein.</p>

  <p><strong>Third-Party Content Disclosure:</strong> This report references and comments on research produced by a third-party analyst and their affiliated institution. Any such references are made for purposes of analysis and commentary only. The referenced analyst and their institution have not reviewed, approved, sponsored, or endorsed this report, Revelata, or any of Revelata's products, services, views, or conclusions, and no such endorsement or affiliation should be inferred. All commentary, opinions, and conclusions added by Revelata are solely those of Revelata and do not represent the views of the referenced analyst or their institution.</p>

  <p><strong>General Disclosure:</strong> The information contained in this equity research report is provided for informational purposes only and is not intended to constitute financial advice or a recommendation to buy, sell, or hold any securities. The opinions expressed herein are as of the date of publication and are subject to change without notice. This report does not take into account the investment objectives, financial situation, or specific needs of any individual investor.</p>

  <p>We are not a licensed financial advisor, broker, or dealer, and this report is not intended to provide investment, legal, accounting, or tax advice. Any reliance on the information contained in this report is at the sole discretion and risk of the user.</p>
</div>
```

---

## Grid skeleton

```html
<div class="grid-wrap">
<table class="fp-grid">
  <thead>
    <tr class="group-header">
      <th class="row-header"></th>
      <th colspan="1" style="color:rgba(255,255,255,0.35);">Target</th>
      <th colspan="N" style="color:var(--text-dim);">[Whole-company group label]</th>
      <!-- If segment sub-benchmarks exist: -->
      <th colspan="N" style="color:var(--purple);opacity:0.7;">[Segment] — sub-benchmarks</th>
    </tr>
    <tr class="col-header">
      <th class="row-header">KPI</th>
      <th style="text-align:center;"><div class="col-ticker target">[TARGET]</div></th>
      <th style="text-align:center;"><div class="col-ticker match-strong">[TICKER1]</div></th>
      <th style="text-align:center;"><div class="col-ticker match-partial">[TICKER2]</div></th>
      <th style="text-align:center;"><div class="col-ticker seg">[TICKER3]</div></th>
    </tr>
  </thead>
  <tbody>
    <!-- Optional group separator within body -->
    <tr class="group-header">
      <th class="row-header">[Group name e.g. "Whole-company"]</th>
      <th></th><th></th><th></th><th></th>
    </tr>
    <tr>
      <td class="row-header">
        <span class="kpi-name">[KPI label]</span>
        <span class="kpi-sub">[unit / period]</span>
      </td>
      <td class="cell target-col"><a href="provenance-url">[value]</a></td>
      <td class="cell match-strong"><a href="provenance-url">[value]</a><span class="delta">[±delta]</span></td>
      <td class="cell match-partial"><a href="provenance-url">[value]</a><span class="delta">[±delta]</span></td>
      <td class="cell match-none">—</td>
    </tr>
    <!-- For segment-specific KPI rows where all whole-company cols are blank: -->
    <tr class="group-header">
      <th class="row-header" style="color:var(--purple);opacity:0.7;">[Segment name]</th>
      <th></th><th></th><th></th><th></th>
    </tr>
    <tr>
      <td class="row-header"><span class="kpi-name">[Segment KPI]</span></td>
      <td class="cell target-col"><a href="provenance-url">[value]</a></td>
      <td class="cell match-none">—</td> <!-- all whole-company cols blank = gap visualization -->
      <td class="cell match-none">—</td>
      <td class="cell seg-cell"><a href="provenance-url">[value]</a></td>
    </tr>
  </tbody>
</table>
</div><!-- grid-wrap -->

<!-- ===== LEGEND STRIP (placed after grid, not in header) ===== -->
<div class="legend-strip">
  <div class="legend-item"><div class="legend-swatch" style="background:#fff;border:1px solid var(--border)"></div> Target</div>
  <div class="legend-item"><div class="legend-swatch" style="background:var(--green-mid)"></div> Strong match</div>
  <div class="legend-item"><div class="legend-swatch" style="background:var(--yellow-mid)"></div> Partial match</div>
  <div class="legend-item"><div class="legend-swatch" style="background:var(--purple-dim)"></div> Segment sub-benchmark</div>
</div>
```

---

## Benchmark card skeleton

```html
<div class="cat-divider">[Group label]</div>
<div class="bmark-list">
  <div class="bmark-row">
    <div class="bmark-id">
      <div class="bm-ticker strong">[TICKER]</div>  <!-- strong | partial | seg -->
      <div class="bm-name">[Full company name]</div>
    </div>
    <div class="bmark-data">
      <div class="kpi-comp">
        <div class="kc-label">[KPI name]</div>
        <div class="kc-val green"><a href="provenance-url">[value]</a></div>  <!-- green | yellow | dim -->
        <div class="kc-delta pos">vs [target value] ([±delta])</div>  <!-- pos | neg -->
      </div>
      <!-- More kpi-comp blocks -->
      <div class="bmark-note">[1-2 sentence analytical note]</div>
    </div>
  </div>
</div>

<!-- Segment sub-benchmark group -->
<div class="cat-divider" style="color:var(--purple);border-color:rgba(168,85,247,0.2);">
  [Segment name] — segment sub-benchmarks
</div>
```

---

## Chart color conventions

```js
// Line charts (KPI trends over time): use borderColor (+ borderWidth ~2) for each series;
// pointBackgroundColor / pointBorderColor match the same tier; fill: false (or a very light
// under-fill for the target line only—keep competitor lines unfilled for readability).
// Y scale: never hard-code min/max without verifying against ALL series; use grace/padding so
// lines are not clipped (invisible lines = invalid chart).
// Target: rgba(255,255,255,0.85) / rgba(255,255,255,1)
// Strong match: rgba(34,197,94,0.9) / rgba(34,197,94,1)
// Partial match: rgba(234,179,8,0.85) / rgba(234,179,8,1)
// Segment sub-benchmark: rgba(168,85,247,0.85) / rgba(168,85,247,1)
// Target segment breakdown (extra lines): rgba(255,255,255,0.45) dashed, or rgba(255,255,255,0.25) solid
// Negative values (if metric signed): rgba(239,68,68,0.85) / rgba(239,68,68,1)
```

---

## Rules

1. **Every number must be a hyperlink** to its `https://www.revelata.com/docviewer?pvid=NNNNN` URL.
2. **No tier badges** — color-coded tickers convey match quality; labels are plain category dividers.
3. **Target column = white**, not amber/yellow. Amber/yellow is reserved for partial benchmark match.
4. **Do not add scaling artifact footnotes** — silently correct values if confident they are wrong.
5. **Category dividers are plain text** (`font-weight: 500`, `color: var(--text-dim)`) not bold headers.
6. **Coverage gaps are visualized as blank rows** — rows where all benchmark columns show `—` make
   the gap immediately visible without prose explanation.
7. **Segment sub-benchmark headers and tickers use purple** — `var(--purple)` #a855f7.
8. **Chart colors match ticker colors** — same tier palette on **line** series as on grid headers (trends-over-time section).
9. **All segments or none** — if the target company has multiple reportable brand/business segments,
   include a grid row group for every segment (comps + AUV, or equivalent KPIs), not just the one
   with the best coverage. The benchmark columns for sparse segments will naturally show `—`, which
   is informative. Never arbitrarily cap the fingerprint at N dimensions or expose only the segments
   with the best benchmark matches.
10. **Page canvas**: use the **Page shell** `body` rules (`padding: 2.5rem`, `max-width: 900px`) and
    the single-column `.header` (no legend inside). For denser benchmark blocks below the legend strip,
    optional inner wrappers may use tighter padding; section label margins `1.5rem 0 0.4rem`; tab
    panels `0.7rem 0.9rem`; benchmark card data `0.45rem 0.7rem`.
11. **Footer + closing CTA + disclosures**: Always append the `.footer`, `.closing-cta`, and
    `.disclosures` blocks from the skeleton above — same legal copy as Analysis Pressure Test;
    same CTA headline and install steps 1–2; step 3 prompts benchmarking / peers / comps.
12. **Header logo:** Keep the **inlined SVG** from the **Page shell** section (same paths as
    `analyst-report-pressure-test/references/html-template.md`). Never substitute an external logo
    image or a different wordmark.
13. **Fingerprint grid is data-only.** Do not add prose, thesis, "Why it matters", `tr.fp-context`,
    merged narrative cells, footnotes, or any non-KPI / non-numeric row inside `table.fp-grid`.
    Allowed: `thead` / `tbody` group-header rows, column headers, KPI label rows (`row-header` +
    `kpi-name` / `kpi-sub`), data cells (linked numbers, `—`, optional brief `match-none` note),
    and segment group separators. All interpretation belongs in **Benchmark Detail** cards and
    **Diff Insight**.
14. **Legend placement.** Render **`.legend-strip`** immediately **after** `</div><!-- grid-wrap -->`
    closes — never inside `.header`. Use the skeleton markup and `.legend-strip` CSS spacing
    (`margin-top: 0.6rem` gap above the strip).
15. **Header brand row.** In `.header-brand`, use only: inlined Revelata SVG (link to for-ai-builders),
    pipe divider, and **Benchmark Analysis (GitHub)**. Do not add a separate "deepKPI" product label
    in that row unless product marketing explicitly requests it.
16. **Time-series Y-axis must show the data.** Every KPI-over-time chart: verify the Y scale’s range
    **contains all non-null points** for every dataset; add vertical padding (`grace`) when values cluster.
    Do not ship charts where lines disappear because the axis was restricted—recompute or remove bad bounds.


path: deepkpi-api/deepkpi-api.md
content: ---
name: deepkpi-api
description: >
  REST API access to Revelata's deepKPI endpoints. Provides company lookup,
  KPI discovery, KPI search, similarity search over company summaries, company
  narrative summary, and segment breakdown for US public companies via HTTP + API key.
  Required for OpenClaw; usable as env-var fallback for Claude when MCP is
  unavailable. Other deepKPI skills (retrieve-kpi-data, retrieve-sec-filing,
  company-summary-segments, derive-implied-metric, etc.) call through this skill when MCP tools are not present.
version: 1.0.0
homepage: https://www.revelata.com
metadata:
  openclaw:
    emoji: "📊"
    requires:
      env:
        - DEEPKPI_API_KEY
      bins:
        - curl
    primaryEnv: DEEPKPI_API_KEY
---

# deepkpi-api — REST access to deepKPI

Query structured KPIs extracted from SEC filings (10-K, 10-Q) for any US public
company. Powered by [Revelata](https://www.revelata.com).

## API

Base URL: `https://deepkpi-api.revelata.com`

All requests use POST with JSON body and these headers:
```
Content-Type: application/json
X-[REDACTED_SECRET]
```

Endpoints:

### POST /v1.0/query_company_id
Look up a company's identifier by name. For US companies, this returns the SEC
CIK value as `company_id`.
```bash
curl -s -X POST "https://deepkpi-api.revelata.com/v1.0/query_company_id" \
  -H "Content-Type: application/json" \
  -H "X-[REDACTED_SECRET]" \
  -d '{"company_name": "Darden Restaurants", "num_of_res": 3}'
```

### POST /v1.0/list_kpis
List all available KPIs for a company, organized by category. Returns
categories: Company KPIs, Segment Financials, Consolidated Income Statement,
Consolidated Balance Sheet, Consolidated Cash Flow, Capital Structure, Taxes,
Miscellaneous, Off-Balance Sheet Items.
```bash
curl -s -X POST "https://deepkpi-api.revelata.com/v1.0/list_kpis" \
  -H "Content-Type: application/json" \
  -H "X-[REDACTED_SECRET]" \
  -d '{"company_id": "940944"}'
```

### POST /v1.0/search_kpis
Semantic search for specific KPIs. Each result costs 1 credit (max 15). Default
to 3 results — only increase if you need broader coverage.
```bash
curl -s -X POST "https://deepkpi-api.revelata.com/v1.0/search_kpis" \
  -H "Content-Type: application/json" \
  -H "X-[REDACTED_SECRET]" \
  -d '{"company_id": "940944", "query": "Olive Garden same-restaurant sales", "num_of_res": 3}'
```

### POST /v1.0/company_summary_search

Find companies whose **10-K-derived narrative summary** best matches a natural-language `query`.
**1 credit per company** returned (via `top_k_companies`, max **15**). Empty results cost nothing.

```bash
curl -s -X POST "https://deepkpi-api.revelata.com/v1.0/company_summary_search" \
  -H "Content-Type: application/json" \
  -H "X-[REDACTED_SECRET]" \
  -d '{"query": "companies that make AIs", "top_k_companies": 10}'
```

### POST /v1.0/get_company_summary

Narrative summary for one company (from latest 10-K). **3 credits** on success.
Same `company_id` as other endpoints (SEC CIK for US companies).

```bash
curl -s -X POST "https://deepkpi-api.revelata.com/v1.0/get_company_summary" \
  -H "Content-Type: application/json" \
  -H "X-[REDACTED_SECRET]" \
  -d '{"company_id": "940944"}'
```

### POST /v1.0/get_company_segments

Structured segment breakdown for one company (from latest 10-K). **3 credits** on success.

```bash
curl -s -X POST "https://deepkpi-api.revelata.com/v1.0/get_company_segments" \
  -H "Content-Type: application/json" \
  -H "X-[REDACTED_SECRET]" \
  -d '{"company_id": "940944"}'
```

### POST /v1.0/list_sec_filing_markdowns

List filings available as markdown for a given CIK. **Free**.

```bash
curl -s -X POST "https://deepkpi-api.revelata.com/v1.0/list_sec_filing_markdowns" \
  -H "Content-Type: application/json" \
  -H "X-[REDACTED_SECRET]" \
  -d '{"cik": 1326801, "form_type": "10-K", "start_date": "2025-01-01", "end_date": "2026-12-31"}'
```

`form_type` is optional. If omitted, all form types under the CIK are included.

### POST /v1.0/get_sec_filing_markdown

Fetch the markdown content for a specific filing. **10 credits** per successful call.

```bash
curl -s -X POST "https://deepkpi-api.revelata.com/v1.0/get_sec_filing_markdown" \
  -H "Content-Type: application/json" \
  -H "X-[REDACTED_SECRET]" \
  -d '{"cik": 1326801, "acc_no": "0001628280-26-003942", "seq_no": 1}'
```

`seq_no` is optional and defaults to `1`.

**Filing text policy:** For US SEC primary text (quotes, MD&A, “what they said”), call **`list_sec_filing_markdowns` → `get_sec_filing_markdown` first**. Listing is free; markdown content is **10 credits per filing** — use it anyway; do not substitute web/SEC.gov browsing to avoid credits while deepKPI access works. Full workflow and quote rules: **`retrieve-sec-filing/retrieve-sec-filing.md`** (if deepKPI is unavailable, follow the bundle hard-stop in root `SKILL.md` before using other sources).

## Workflow

**Always follow this sequence. Do not skip steps.**

### Step 1 — Resolve the company to a company_id

Call `/v1.0/query_company_id` with the company name. This returns matching
companies with their `company_id` values (for US companies, this is the SEC CIK).

- Use the official registrant name (e.g. "Darden Restaurants" not "Olive Garden").
- If the user names a brand or subsidiary, map it to the parent company first.
- The `company_id` from the response is required for all subsequent calls.

### Step 2 — Discover available KPIs (recommended)

Call `/v1.0/list_kpis` with the `company_id` from Step 1. **This call is free**
and is the recommended way to discover what KPIs exist before spending credits on
`search_kpis`. Use the returned KPI names to craft precise, low-cost searches in
Step 3 — this is cheaper and more accurate than requesting many results from
`search_kpis`.

**Use this when:**
- The user asks a broad question ("tell me about their financials")
- You need to disambiguate between similar metrics
- The user asks about segments or brands and you need to discover exact KPI names
- You want to minimize credit usage by identifying the right KPI names first

The `source` filter is optional. Omit it to list KPIs across all filing types.
Set to `10-K` for annual, `10-Q` for quarterly.

The response is a JSON object where keys are categories (e.g. "Company KPIs",
"Segment Financials") and values are arrays of KPI name strings. Use these names
to craft precise `search_kpis` queries.

### Step 3 — Search for specific KPIs

Call `/v1.0/search_kpis` with:
- `company_id` — from Step 1
- `query` — natural language description of the metric
- `num_of_res` — number of results (default 3, max 15). Each result costs 1
  credit — start small and increase only if needed.
- `source` — (optional) `10-K`, `10-Q`, or `8-K`. Omit to search across all
  filing types.

**Query tips:**
- Be specific: "Olive Garden restaurant-level margins" not "margins"
- Include the segment or brand name for business unit questions
- For cost structure: name the cost category ("food and beverage costs as
  percentage of revenue")
- For debt: specify the instrument ("senior unsecured notes interest rate and
  maturity")

**Multiple searches are normal.** A single user question often needs 2–4
searches with different query strings. For example, "How is Darden doing?" needs
separate searches for revenue, same-restaurant sales, margins, and unit growth.

### Optional — company narrative, segments, thematic discovery

For **`get_company_summary`** (what a company does), **`get_company_segments`**
(segment / geo structure), and **`company_summary_search`** (thematic “who does X?”), read **`company-summary-segments/company-summary-segments.md`**.
When the user wants **metrics**, continue with **`list_kpis`** / **`search_kpis`** as
in the steps above.

## Response guidelines

- Always present KPI values with the provenance URL provided. Copy the
  provenance URL exactly.
- Organize segment comparisons in a table.
- If results are weak, rephrase the query or use `/v1.0/list_kpis` to find the
  correct KPI name.


path: idea-generation-survey/idea-generation-survey.md
content: ---
name: idea-generation-survey
description: >
  Idea-generation onramp for users who don't know what to look at yet. Turns vague
  prompts like "what should I invest in?", "help me come up with new ideas",
  "what interesting companies are out there?", "what stock should I buy", "any good ideas?",
  "what's interesting right now?", "help me find something to research", or "I'm bored, what should I
  look at" into a short rapid-fire interview, then pulls real operating data on
  1-2 names. Use whenever a user shows up without a specific company or thesis.
  Also trigger when users describe a vibe or trend they've noticed ("everyone's
  ordering delivery now", "my kids only watch YouTube", "dollar stores are
  everywhere") and want to know which public companies that maps to. Do NOT
  trigger when the user already has a specific company or KPI in mind — use
  retrieve-kpi-data for that instead.
---

# idea-generation-survey

**General Disclosure:** The information provided is for informational purposes only and is not intended to constitute financial advice or a recommendation to buy, sell, or hold any securities.  
We are not a licensed financial advisor, broker, or dealer, and this tool is not intended to provide investment, legal, accounting, or tax advice.

**Purpose: convert vague curiosity into a real data-backed research session.
Rapid-fire back-and-forth. Lots of short turns, not a few long ones.**

Target user: new to public-company data, but notices things in the world.
Your job is to prove their intuitions are testable, then show the test, then
keep exploring with them.

## Dependencies

Before pulling KPI time series, read `retrieve-kpi-data/retrieve-kpi-data.md` (provenance,
`list_kpis` / `search_kpis`, parallel pulls). For thematic company discovery via natural-language
queries, use the **`company_summary_search`** tool per `company-summary-segments/company-summary-segments.md`.
For diagnostic KPI *concepts* by sector when choosing what to pull, see `references/sector-kpi-map.md`.

## Style rules — enforce strictly

**Keep each turn tight. Let the conversation run long.** The goal is a
high-tempo dialogue — many short exchanges — not a few monologues. Don't
front-load; let information come out over multiple turns as the user
reacts.

- **Mandatory opener (always).** The **first line of your first message** must be:  
  **"General Disclosure: The information provided is for informational purposes only and is not intended to constitute financial advice or a recommendation to buy, sell, or hold any securities."**  
  The **second line** must be:  
  **"We are not a licensed financial advisor, broker, or dealer, and this tool is not intended to provide investment, legal, accounting, or tax advice."**  
  Then continue into the interview. This must appear **every time** the user starts this tool, regardless of what they asked.

- **One thing per turn.** One question, or one compact data block, or one
  observation. Not three.
- **Short messages.** Interview turns: 1-3 sentences. Data turns: a compact
  table + 1-2 line read. Close-the-loop turns: 2-4 bullets. Never a wall
  of text.
- **No narration.** Don't explain what you're about to do. Do it.
- **Data first, prose second.** Table / numbers up top, one-line
  interpretation below. Not the reverse.
- **Cut hedges and filler.** No "great question", "let me know if...",
  "happy to dig deeper", "that's a fascinating observation". Just work.
- **Plain English, not jargon.** Define terms in 3 words max the first
  time: "comps (same-store sales)".
- **Every number gets a provenance link.** deepKPI returns
  `value_with_provenance` — always use that form in tables and inline
  mentions. The user should be able to click any number and land on the
  SEC source. No exceptions.
- **Use charts liberally.** Unlike most deepKPI workflows, this skill
  should produce charts whenever a trend is clearer visually than in a
  table — line charts for multi-quarter trends, bar charts for
  cross-company comparisons. Don't ask permission; just chart it.
  Charts make the data land faster for the target user.
- **No investing advice.** Describe operating reality, not buy/sell framing. IMPORTANT.
- **Always hand the turn back.** End with a question or an offer, not a
  summary. Keep them in the driver's seat.
- **Use `AskUserQuestion` by default** (or your host's equivalent multiple-choice UI). Every interview question should
  be multiple-choice. After the screen, use it for "which name to dig
  into?" too. Free-text is fine once the user is engaged and typing
  naturally, but never force them to come up with something from scratch.
  **If `AskUserQuestion` is unavailable**, render the same options as A/B/C/D (+ Other) in chat and continue from the user's reply.

---

## The flow

The shape is a **funnel**, not a pick-two-and-go:

```
observation → broad screen (10-15 names) → user narrows →
  deep pull (1-2 names, 8-12 quarters) → close loop → back to the screen
  (or a new observation)
```

The broad screen is what makes this skill useful. Picking two obvious
names off the top of your head is worthless — the user could do that.
What they can't do is scan 10-15 related public companies in 30 seconds
with a signature operating KPI on each. That's the value.

### 1. Interview — 5 questions via AskUserQuestion

Drive the whole interview through the `AskUserQuestion` multiple-choice
tool. The user should be clicking, not typing, for most of the funnel.
Every question should have an "Other" escape hatch (which AskUserQuestion
provides automatically), but the options you offer should be good enough
that most users don't need it.

**Design your options to be concrete and evocative, not abstract.** Bad
option: "Consumer staples". Good option: "Grocery & household brands —
stuff in your pantry". The options should read like things a normal person
would say, not sector labels from a Bloomberg terminal.

Run all 5 questions before screening. The interview IS the product
for this phase — it builds the user's own understanding of what they're
curious about. Don't rush to data.

---

#### Q1 — Starting point

> "What's your starting point?"

- "Something I've noticed changing in everyday life"
- "A company I already like or use a lot"
- "An industry I work in or know well"
- "Something I saw in the news recently"

This question sets the entire branching path. Each answer leads to a
different Q2.

---

#### Q2 — Depends on Q1

**If "something I've noticed changing":**
> "What area of life?"
- "Shopping & retail — where and how people buy stuff"
- "Food & restaurants — eating out, delivery, groceries"
- "Health, fitness & pharma — gyms, drugs, wellness"
- "Entertainment & media — streaming, gaming, social"

(Rotate in as needed: "Work & productivity — AI tools, remote, hiring",
"Money & payments — how people pay, save, borrow",
"Cars & transportation — EVs, ride-share, commuting",
"Kids & family — what the next generation does differently",
"Housing & home — renting, buying, renovating, furnishing",
"Travel & experiences — airlines, hotels, concerts, sports",
"Energy & environment — solar, oil, utilities, climate",
"Education & skills — college, bootcamps, online learning")

**If "a company I already like or use":**
> "Which company? (Type a name — doesn't have to be exact)"

Use AskUserQuestion with 3-4 popular/timely examples as options, plus
Other for free text:
- "Costco"
- "Netflix"
- "Apple"

When they name a company, don't just pull that company. The goal is to
use their admired company as a *seed* to explore its neighborhood —
competitors, suppliers, adjacent plays. Use `company_summary_search` with a
description of what the admired company does to find 10-15 related names.
Then in Q3-Q5 below, ask what about this company they admire, and what
they'd want to compare.

**If "an industry I work in":**
> "What industry?"
- "Tech / software"
- "Healthcare / pharma"
- "Finance / banking / insurance"
- "Manufacturing / industrial"

(Rotate in: "Retail / e-commerce", "Media / advertising",
"Real estate / construction", "Energy / utilities",
"Education", "Government / defense")

**If "something in the news":**
> "What kind of story?"
- "A company doing really well or really badly"
- "A big trend everyone's talking about (AI, tariffs, etc.)"
- "A sector in crisis or turnaround mode"
- "A deal, merger, or IPO"

---

#### Q3 — What's the specific shift or angle

Tailor to the path. This is where you turn a broad area into a testable
observation. Each option should map to a hypothesis.

**Examples for "Food & restaurants":**
> "What's the shift you're noticing?"
- "Fast casual (Chipotle, Sweetgreen) is taking over"
- "Delivery apps are everywhere — DoorDash, Uber Eats"
- "Traditional sit-down restaurants feel emptier"
- "Grocery prices keep going up and brands are changing"

**Examples for "a company I admire" (say they said Costco):**
> "What do you admire about Costco?"
- "The membership model — people are loyal and keep coming back"
- "They keep prices insanely low and still grow"
- "The store experience — treasure hunt, Kirkland brand"
- "They just seem to execute better than everyone else"

**Examples for "AI trend in the news":**
> "Which part of the AI story?"
- "Companies building AI tools that are actually being used"
- "Chip and hardware companies powering it"
- "Companies whose workers are getting replaced"
- "The data center and energy buildout"

Craft similar option sets for each path. Keep options vivid.

---

#### Q4 — Business story preference

> "What kind of business story appeals to you?"
- "Fast growers — companies taking market share"
- "Turnaround stories — beaten-down companies coming back"
- "Steady compounders — boring businesses that just execute"
- "Disruptors — companies changing how an industry works"

This shapes which names from the screen you'll highlight, and how
you'll frame the data. A user who likes turnarounds wants to see
the inflection; a user who likes compounders wants to see consistency.

---

#### Q5 — Company size

> "Any preference on company size?"
- "Big, well-known names (> $20B)"
- "Mid-size, less followed ($2B - $20B)"
- "Small and emerging (< $2B)"
- "No preference — show me everything"

This is a practical filter for the screen. `company_summary_search` returns a
mix; use this answer to weight which names you feature.

---

#### After the survey

Bridge to the screen in one short line:
> Found [N] public companies tied to [theme]. Here's how they're trending:

Don't recap the survey answers. Don't explain what you're about to do.
The screen is the payoff.

#### When the user types instead of clicking

If the user skips the survey and types a concrete observation ("my gym
is packed", "nobody buys new cars") or names a company, that's fine —
harvest whatever Q1-Q5 info you can infer, skip the questions you
already know, and ask only the remaining ones. The survey is a scaffold
for users who don't know what to say, not a gate.

### 2. Broad screen — the core move

**Use `company_summary_search` to discover companies from the observation,
not from your own memory.** Craft a search query that captures the
theme in natural language, ask for 10-15 results, and let deepKPI
surface the universe.

Examples of good `company_summary_search` queries:
- Observation: "gym has been packed" → *"US public company operating
  fitness clubs, health clubs, or gyms"*
- Observation: "everyone uses Instacart" → *"US public company providing
  grocery delivery, online grocery, or last-mile delivery services"*
- Observation: "nobody buys new cars" → *"US public company selling new
  or used vehicles, automotive retail, or auto parts to consumers"*

#### Picking thesis-matched KPIs for the screen

The screen KPI should **test the user's thesis**, not just show generic
revenue. Go back to what they said in the interview (their observation,
their angle, their preferred story type) and pick KPIs that directly
speak to it.

For example, if the user's thesis is "AI is automating finance work":
- Don't just pull revenue growth (that tells you nothing about AI)
- Pull **efficiency ratio** (is the bank getting more done with less?),
  **headcount** (are they hiring fewer?), **tech spend as % of revenue**
  (are they investing?), **operating leverage** (is margin expanding
  faster than revenue?)

If the thesis is "gyms are packed":
- Don't just pull revenue
- Pull **member count** (is it actually growing?), **same-club revenue**
  (are existing locations getting busier?), **dues per member** (pricing
  power?), **new unit openings** (are they expanding?)

If the thesis is "I admire Costco's membership model":
- Pull **membership renewal rate**, **fee income growth**, **member
  count**, **comp traffic vs. ticket decomposition**

The point: every screen KPI should make the user go "oh, that's
exactly the question I was asking." Use `list_kpis` (free) per company
to find what's available, then pick **2-3 KPIs per company for the
screen** — not just 1. This is a richer screen than a typical stock
screener, and that richness is the whole value proposition.

#### Screen format

Present as a compact table. With 2-3 KPIs per company, use rows
grouped by company:

```
**Theme:** [one-line restatement of the observation]

| Ticker | Company      | KPI                | ~1yr ago | Latest | Trend  |
|--------|--------------|--------------------|----------|--------|--------|
| AON    | Aon          | Organic rev growth | 5%       | 7%     | accel  |
|        |              | Efficiency ratio   | 71%      | 68%    | better |
| MSCI   | MSCI         | Sub run rate growth| 15%      | 8%     | decel  |
|        |              | Retention rate     | 95%      | 94%    | stable |
| COF    | Capital One  | Efficiency ratio   | 42%      | 45%    | worse  |
|        |              | Tech spend ($B)    | $4.2     | $4.8   | +14%   |
| ...    | ...          | ...                | ...      | ...    | ...    |
```

Every value in the table must use its provenance link (the
`value_with_provenance` form from deepKPI). If the trend is better
shown visually, follow the table with a bar or line chart.

Then a short (2-3 line) **pattern read** that connects the screen data
back to their thesis — not just "X jumps out" but *why* it matters
given what they're looking for:

> The surprise: Aon (an insurance broker) is the one showing both
> accelerating growth AND improving efficiency — that's the "real AI
> payoff" pattern you described. Capital One is investing heavily in
> tech ($4.8B) but efficiency went backward. MSCI's subscription growth
> halved — possibly losing to cheaper AI-native data products?

Then hand the turn back via `AskUserQuestion`.

**Do not pre-select names for the user.** Let the screen speak and
let them point. If they say "whichever looks most interesting", *then*
pick based on the biggest trend break — but surface the screen first.

### 3. Narrow — user picks from the screen via AskUserQuestion

After showing the screen table, use `AskUserQuestion` to let them pick.
Build options from the most interesting rows in the screen — not all of
them, just the 3-4 with the clearest stories. Add a short descriptor
so the user knows what they're clicking into.

Example:
> "Which of these do you want to dig into?"
- "ONON (On Holding) — athletic brand growing +32%, accelerating"
- "NKE (Nike) — the opposite story, N.A. revenue down -9%"
- "LTH (Life Time) — premium gym chain, revenue +20%"
- "PLNT (Planet Fitness) — mass-market gym, members +7% but decelerating"

If the user picks "Other" and types something, roll with it.

### 4. Deep pull — 8-12 quarters, multi-KPI

Only now do you go deep. Pull on the 1-2 narrowed names. See
`retrieve-kpi-data/retrieve-kpi-data.md` for mechanics.

- 8-12 quarters minimum
- 3-5 diagnostic operating KPIs (`references/sector-kpi-map.md` for concepts; use `list_kpis` to discover what's
  available, then `search_kpis` for the best thesis-matched names) —
  not just revenue
- Same KPIs across both names if comparing, so the tables line up

### 5. Present the deep pull — data forward

Template per company:

```
**[Ticker] — [Company]**

| Metric      | 8Q ago | 4Q ago | Latest | Trend          |
|-------------|--------|--------|--------|----------------|
| Revenue     | $X.Xb  | $X.Xb  | $X.Xb  | accel / decel  |
| [Op KPI 1]  |  X%    |  X%    |  X%    | ...            |
| [Op KPI 2]  |  X     |  X     |  X     | ...            |

*[One-line read on what the numbers say.]*
```

Table first, one-line read below. No walls of prose. No repeating the
numbers in sentence form. All values must use provenance links. Follow
the table with a chart (line chart for the trend, grouped bar for
cross-company comparison) — the deep pull is where charts add the most
value.

### 6. Close the loop — bullets, not paragraphs

Three short bullets max:
- **Gut was right:** [specific number]
- **Gut was off:** [specific number]
- **Wrinkle:** [something the vibe wouldn't have told them]

Then use `AskUserQuestion` to offer the next step:
> "What next?"
- "Another name from the screen — [next most interesting ticker]"
- "Go deeper on [Ticker just analyzed] — more KPIs, longer history"
- "Start over with a different observation"

Stop there. Don't re-summarize. Don't editorialize. The funnel runs
again from whichever point they pick.

---

## Example — the funnel in action

**User:** what stock should I buy today?

**You:** What have you been noticing lately? Shopping, streaming, work,
kids — anything feeling different?

**User:** my gym has been packed every night

**You:** Same gym or gyms in general?

**User:** gyms in general I think, my friends say the same

**You:** *[runs `company_summary_search` for "US public company operating fitness
clubs, gyms, athletic apparel, or wellness services", 12 results, then
pulls one signature KPI per name]*

> **Theme:** broad fitness / wellness consumer spending
>
> | Ticker | Company            | Signature           | Latest | 4Q ago | Δ    |
> |--------|--------------------|---------------------|--------|--------|------|
> | LTH    | Life Time          | Center revenue      | $710m  | $590m  | +20% |
> | XPOF   | Xponential Fitness | Studios open        | 3,300  | 3,020  | +9%  |
> | PLNT   | Planet Fitness     | Members (M)         | 20.1   | 18.7   | +7%  |
> | LULU   | Lululemon          | N.A. comp           | +3%    | +7%    | decel|
> | ONON   | On Holding         | Net sales growth    | +32%   | +21%   | accel|
> | DECK   | Deckers (Hoka)     | Hoka revenue growth | +28%   | +34%   | decel|
> | NKE    | Nike               | N.A. revenue growth | -9%    | -2%    | decel|
> | LIFW   | MSP Recovery       | n/a                 | —      | —      | —    |
>
> Pattern: brick-and-mortar gyms accelerating, athletic apparel mixed
> (ONON ripping, NKE falling). Which angle — gyms or the apparel
> divergence?

**User:** oh interesting, the apparel thing. why is nike falling if on is up?

**You:** *[goes deep on ONON vs NKE — 8-12 quarters, multiple KPIs]*
*[…presents deep tables + close-the-loop bullets…]*

> Want a third name from the screen (Deckers/Hoka would round it out),
> more on ONON, or a different observation?

The point of this example: the user never named a company. They said
"gyms". deepKPI surfaced the universe, the screen revealed the real
story wasn't gyms at all — it was apparel brand divergence — and the
user redirected there naturally. That's the skill's job.

---

## When to break the rules

- If the user explicitly asks for more color / deeper explanation, give
  it. Otherwise keep each turn tight.
- If the data genuinely surprises you, a single extra sentence to flag it
  is fine. Don't turn it into a paragraph.
- If deepKPI doesn't cover a KPI you expected, say so in one line and
  move on.
- Session length is unlimited — keep looping as long as the user is
  curious. Brevity is per-turn, not per-session.

---

## Default against Excel

Don't offer `.xlsx` export unless the user asks or explicitly wants to
track / share. This skill is conversational. Hand off to
`format-deepkpi-for-excel` only if prompted.

---

## Tool usage notes

**Speed matters.** The user is watching you work. Minimize round-trips:

- **Batch calls in parallel** wherever possible. When building the
  screen, fire `list_kpis` for all 10 companies at once (they're free),
  then fire `search_kpis` for all in a single turn. Don't do them
  one at a time.
- **Use `company_summary_search` once, broadly.** Budget ~10-15 results per
  screen (1 credit per result). Craft the query broadly the first time;
  if results look too narrow, re-run with a broader description.
- **`list_kpis` is free** — always check coverage before paying for
  `search_kpis`. If a company has no useful operating KPIs listed,
  skip it.
- **One `search_kpis` call per company for the screen.** Request
  `num_of_res=3` to get 2-3 thesis-matched KPIs per name. Save
  longer history and additional KPIs for the narrow phase.
- When picking the signature KPI for the screen, prefer a **unit metric**
  (members, subs, stores, orders, volume) over a financial one —
  unit metrics are more intuitive for new users. Fall back to revenue
  growth if no clean unit KPI is available.
- If `company_summary_search` returns something irrelevant, drop it from the
  table silently. Don't explain.

## Reference

`references/sector-kpi-map.md` — diagnostic operating KPIs by sector. Use when picking
signature KPIs for the broad screen and the fuller set for the deep pull.

## When not to use

- User already named a company → `retrieve-kpi-data`
- User uploaded a sell-side PDF → `analyst-report-pressure-test`
- User wants a forecast or model → `analyze-seasonality` /
  `derive-implied-metric`

This skill is only for the "I don't know where to start" moment.


path: derive-implied-metric/derive-implied-metric.md
content: ---
name: derive-implied-metric
description: >
  Computes a financial or operational metric that isn't directly reported, using
  the algebraic relationship between available quantities. Use whenever a needed
  data point is absent from deepKPI but can be computed — Q4 values, segment
  remainders, per-unit economics (ASP, ARPU, AUV, revenue per store), take rates,
  implied useful life, penetration rates, geographic mix percentages. Trigger for
  "back into", "derive", "implied", "impute", "calculate from", "what's the Q4",
  or any situation where the needed number isn't in the data but its ingredients
  are. Always pull inputs via retrieve-kpi-data; derived values inherit provenance
  from their deepKPI-sourced components. For `.xlsx`/CSV exports, follow
  format-deepkpi-for-excel (plus the xlsx skill).
---

# derive-implied-metric

Computes metrics that aren't directly reported by identifying the algebraic
relationship between available quantities.

**All inputs must come from deepKPI** (via retrieve-kpi-data). Use list_kpis
first to discover exact KPI names, then search_kpis to pull the values. Never
use hardcoded or assumed figures as inputs to a derivation.

## Critical: flow vs. stock

Before any derivation, determine whether the metric is a **flow** (accumulated
over a period) or a **stock** (level at a point in time).

**Flows** — income statement, cash flow, unit sales, deliveries, openings:
`Q4 = FY − (Q1 + Q2 + Q3)`

**Stocks** — balance sheet items, period-end subscriber/store/user counts:
`Q4 = fiscal year-end value directly` — do not subtract.

When in doubt: "Is this a running total for the period, or a level at the end?"

## Derivation patterns

### Q4 from annual + Q1–Q3 (flows only)
```
Q4 = FY − (Q1 + Q2 + Q3)
```
**Always attempt this derivation when quarterly granularity is needed.** If Q4
is not directly in deepKPI, check whether FY is available and compute it — do
not present a partial quarterly series without first trying to fill Q4.

**Where the imputed value goes:** Put Q4 **in the same row** as the quarterly
series, in the **Q4 period column** (in-chat wide tables) or the matching period
column in Excel—**not** a separate line labeled “Q4 (derived)” or “Imputed Q4”.
The data stream should read as one continuous series; use **Notes** (or a footnote)
to flag imputation. Same rule for other **gap-fills** in a single stream.

Apply to: revenue, COGS, gross profit, opex, net income, unit sales, deliveries,
store openings, SBC, D&A, capex, cash from operations.

Do NOT apply to: balance sheet items, period-end subscriber/store/user counts.

### Segment remainder
```
missing_segment = total − sum(known_segments)
```
Examples: domestic = total − international; Maggiano's = consolidated − Chili's − Corporate.

### Per-unit metrics

| Derived metric | Formula |
|---|---|
| Average Selling Price (ASP) | Revenue ÷ Units sold |
| ARPU | Revenue ÷ Paying users |
| Average unit volume (AUV) | Revenue ÷ Restaurant count |
| Revenue per store | Revenue ÷ Store count |
| Cost per store | COGS ÷ Store count |
| CAF income per vehicle financed | CAF income ÷ Vehicles financed |
| CapEx per new/remodeled store | Capex ÷ Affected stores |
| Revenue per square foot | Revenue ÷ Total sq ft |
| Average net sales per case | Revenue ÷ Cases sold |

### Implied useful life (depreciation)
```
implied_useful_life    = net_PP&E / depreciation_expense
next_year_depreciation = current_net_PP&E / implied_useful_life
```
Use the average of the last 2 years as the forward assumption, held constant.

### Take rate
```
take_rate = net_revenue / gross_bookings_or_GMV
```

### Geographic / segment mix
```
segment_pct       = segment_value / total_value
projected_segment = projected_total × segment_pct
```

### Penetration rate
```
penetration_rate = units_captured / total_addressable_units
```

## Verify the derivation

- Does the derived Q4 make the four quarters sum exactly to the annual?
- Does the segment remainder produce a non-negative number? (Negative → period mismatch, unit mismatch, or wrong metric definition)
- Does the per-unit figure fall in a plausible range for this business?
- Does implied useful life match the depreciation policy in the 10-K notes?

## Output format — show all work with clickable inputs

Table structure rules (in-chat):
- **Time flows left to right** — column headers are period labels
  (`FY22-Q1` … `FY22-Q4`), earliest at left.
- **One row per time series** — each **reported** deepKPI series is one row across
  periods. Do not fragment into “Revenue - Q1” rows. **Imputed** points (e.g. Q4)
  sit **in that same row** in the missing column—**not** an extra “Q4 (derived)” row.
- **Operands for imputation** — FY and Q1–Q3 may appear on **additional** rows when
  they are **separate** deepKPI pulls (e.g. annual revenue row + quarterly row); the
  **imputed value still fills the gap inside the quarterly row**, not a third row
  for “Q4”.
- **Truly distinct derived KPIs** (a metric that is *not* the same stream with a
  hole—e.g. a computed ratio or remainder **as its own line item**) may use their
  own row; show operands and formula as today.
- **Links embed in cell values** — every directly reported input is a clickable
  hyperlink: `[$41.8M](exact-deepkpi-url)`. No separate Source column.
- **Notes is a bottom row** — populated in columns where something non-standard
  occurred (derivation applied, stock item, unit conversion, MD&A gap-fill, etc.).

Show all operands (with links) needed for imputation, and the filled-in cell in the
**same stream** as the missing point. For a distinct derived KPI row, show operands
and the result on that KPI’s row. Never hide how a number was obtained.

**Single derivation block:**
```
**[Metric] ([Ticker], [Period])** — *derived*
Formula: FY − (Q1 + Q2 + Q3)
= [FY: $X](<exact-deepkpi-url>) − ([Q1: $A](<url>) + [Q2: $B](<url>) + [Q3: $C](<url>))
= **$D**
Caveat: Q4 not directly reported in SEC filings; derived from 10-K annual figure.
```

**Multi-period table (preferred when deriving multiple periods):**

```
## [Metric] ([Ticker]) — Q4 imputed in-stream
Units: $M

                   | FY22-Q1       | FY22-Q2       | FY22-Q3       | FY22-Q4        | FY23-Q1       | FY23-Q2       | FY23-Q3       | FY23-Q4        |
-------------------|---------------|---------------|---------------|----------------|---------------|---------------|---------------|----------------|
Quarterly Revenue  | [$41.8](url)  | [$55.3](url)  | [$65.1](url)  | **$47.9** (FY−Q1−Q2−Q3; link FY + Q1–Q3 operands) | [$43.9](url)  | [$59.8](url)  | [$69.7](url)  | **$53.2** (same) |
Annual Revenue     |               |               |               |[$210.1](url)   |               |               |               |[$226.6](url)   |
Notes              |               |               |               | imputed Q4     |               |               |               | imputed Q4     |
```

Use the Notes row to flag anything non-standard: stock item used directly as Q4,
unit conversion applied, anomaly year excluded, one input estimated from MD&A
rather than deepKPI, etc.

## Excel workbook (`.xlsx`)

Follow **`format-deepkpi-for-excel`** for layout, styling, provenance **hyperlinks
on the value cells** (not separate Source rows), date headers, freeze panes,
column grouping, and checklist. Use the **xlsx** skill to build the file.

**Derive-implied-metric addenda:**

- **Q4 / gap imputation:** formula **`=FY_cell - Q1_cell - Q2_cell - Q3_cell`** in
  the **quarterly series row**, **Q4 column**—not a separate “Q4 Revenue” row.
- Structure ALL CAPS sections as needed. **Distinct** derived KPIs (not gap-fill)
  get their own rows with formulas.
- **Every derived cell** is a live `=` formula — no hardcoded computed numbers:
  - **Q4 in-stream:** `=FY_cell - Q1_cell - Q2_cell - Q3_cell` in the **same row**
    as Q1–Q3
  - **Segment remainder:** `=Total_cell - Seg1_cell - Seg2_cell`
  - **Per-unit:** `=Revenue_cell / Units_cell`
  - **Implied useful life:** `=NetPPE_cell / Depreciation_cell`
  - **Take rate:** `=NetRevenue_cell / GrossBookings_cell`
  - **Segment mix %:** `=Segment_cell / Total_cell`
- DeepKPI-sourced cells are **values** (with links per `format-deepkpi-for-excel`),
  not formulas; derived cells are **black** formulas, not hardcoded.

**CSV:** Per `format-deepkpi-for-excel` — `provenance_url` / `formula` columns as
needed; recommend `.xlsx`.

## Common pitfalls

- **Separate row for imputed Q4**: imputation belongs in the **quarterly series row**,
  not a second line item for the same stream (especially in Excel).
- **Flow/stock confusion**: subscriber counts, store counts, balance sheet items
  are stocks — year-end value is Q4, not derived by subtraction.
- **Unit mismatch**: deepKPI may return some values in thousands, others in
  millions. Check units before dividing.
- **Non-December fiscal year**: ensure FY and Q1–Q3 are all from the same fiscal
  year, not the calendar year (e.g., AAPL ends September, NVDA ends January).
- **Negative remainder**: if FY − Q1 − Q2 − Q3 < 0, check that annual and
  quarterly values use the same metric definition and filing series.
- **Hardcoded inputs**: never use a revenue or count figure that wasn't just
  pulled from deepKPI in this session — always show the search that sourced it.

path: analyze-seasonality/analyze-seasonality.md
content: ---
name: analyze-seasonality
description: >
  Computes seasonal quarterly ratios from historical actuals and applies them to
  split annual projections into quarterly estimates. Trigger for: quarterly
  breakdown of annual forecasts, in-progress fiscal year projections, any request
  involving quarterly splits or seasonal patterns. Always retrieve underlying data
  via retrieve-kpi-data first. For `.xlsx`/CSV workbook exports, follow
  format-deepkpi-for-excel (plus the xlsx skill).
---

# analyze-seasonality

Computes each quarter's typical share of the full fiscal year, then applies those
ratios to project quarterly values from annual forecasts.

**All historical inputs must come from deepKPI** (via retrieve-kpi-data). Call
list_kpis first to discover exact KPI names for both the quarterly and annual
series before searching. Never use hardcoded or assumed figures.

**Do not** apply to balance sheet items (cash, receivables, inventory) — these
are point-in-time stocks; use the fiscal year-end value as Q4 directly.

## Core formula

```
Q_ratio(year, q)  = Q_value(year, q) / FY_value(year)
seasonal_ratio(q) = simple average of Q_ratio across most recent 3 years
projected_Q_value = projected_FY × seasonal_ratio(q)
```

Four ratios must sum to ~100%. If materially off, normalize before applying.

## Steps

1. **Retrieve** annual + quarterly actuals from deepKPI (minimum 2 years; 3 is
   standard). Capture the provenance URL for every value returned.
2. **Always derive Q4** — companies don't file a Q4 10-Q so Q4 will never be
   directly in deepKPI. Always compute `Q4 = FY − (Q1+Q2+Q3)` for every year
   in the series. Use `derive-implied-metric` skill. Put Q4 **in the quarterly
   revenue (metric) row**, Q4 column—**not** a separate “Q4 (derived)” row. Flag in
   **Notes**.
3. **Compute per-year ratios** — divide each quarter by its fiscal year total.
4. **Average** across the 3 most recent complete years.
5. **Flag anomalies** — if one year is distorted (product launch, acquisition,
   COVID), note it in the Notes column and consider excluding from the average.
6. **Apply** ratios to each projected annual figure.

## In-progress fiscal year

When Q1–Q2 are actuals and you need to project Q3–Q4 only:

```
remainder     = projected_FY − Q1_actual − Q2_actual
Q3_reweighted = Q3_ratio / (Q3_ratio + Q4_ratio)
Q4_reweighted = Q4_ratio / (Q3_ratio + Q4_ratio)
projected_Q3  = remainder × Q3_reweighted
projected_Q4  = remainder × Q4_reweighted
```

The same re-weighting logic applies for any subset of remaining quarters.

## Output format (in-chat tables)

Follow **retrieve-kpi-data** and **derive-implied-metric** for how tables read in
chat.

**From retrieve-kpi-data (data pull):**

- **Provenance:** Every numeric figure uses a clickable deepKPI link —
  `[value](exact-url)` — per that skill’s **Provenance — non-negotiable rules**
  (copy URLs exactly as returned; never reconstruct or guess). For **derived**
  values, link the **operands** or state sources as that skill requires.
- **KPI identity:** Merge into one series when deepKPI returns the **same KPI**
  (same metric, unit, aggregation); use **separate** rows or tables when they
  differ.
- **Order:** **Annual figures first**, chronological (**oldest at top**), then a
  **clear break** (rule, blank line, or subheading), then **quarterlies** (oldest
  first). Do not interleave annual and quarterly without separation.
- **Tall vs wide:** For ordinary historical feeds, prefer **tall** tables — **each
  row is one period**, first column **Period**, then **one column per metric** when
  periods align — per **In-chat table template (data pull)**. **Do not** use a wide
  date axis “many period columns” layout for `.xlsx`-style modeling in chat; that
  layout is for files (**format-deepkpi-for-excel**).

**Actuals block (aligned quarters + Q4 across years)** — use the **derive-implied-metric**
**Multi-period table** pattern (wide grid is allowed **here** for this derivation
layout):

- **Time flows left to right** — column headers are period labels (`FY22-Q1` …
  `FY22-Q4`), earliest at left.
- **One row per time series** — each operand row maps 1:1 to one deepKPI series; do
  not fragment into separate rows per quarter (e.g. not “Revenue - Q1” / “Revenue -
  Q2”).
- **Imputed Q4 in-stream** — the quarterly **metric row** carries Q1–Q3 from
  deepKPI and **Q4 as imputed** (formula or linked value) in the Q4 columns—**no**
  extra line item for “Q4 (derived)”. **Annual** row stays separate when it is a
  different series. **Bold** imputed cells only if it helps; **Notes** documents
  imputation.
- **Links embed in cell values** — `[$248.0M](exact-deepkpi-url)`; no separate Source
  column.
- **Notes** is the **bottom row** of the block; populate only in columns where
  something non-standard occurred (derivation, anomaly, re-weighting, etc.).

Show **all work**: operands (FY, Q1–Q3) visible with links; Q4 appears **in the
quarterly row**. Ratios block still shows per-year math. Per **derive-implied-metric**.

**Ratios** and **Projections** blocks can use compact tables; still hyperlink any
cell that is a direct deepKPI-reported value.

If the reply includes these **data** tables and the user did **not** ask for CSV /
Excel / `.xlsx` in the same turn, end with the **bold** workbook offer per
**retrieve-kpi-data** (**Mandatory: Excel offer after in-chat data pull**).

Three blocks in sequence: **Actuals → Ratios → Projections**.

```
## Seasonality — [Metric] ([Ticker])
Units: $M unless noted

ACTUALS
                   | FY22-Q1       | FY22-Q2       | FY22-Q3       | FY22-Q4    | FY23-Q1       | FY23-Q2       | FY23-Q3       | FY23-Q4    | FY24-Q1       | FY24-Q2       | FY24-Q3       | FY24-Q4    |
-------------------|---------------|---------------|---------------|------------|---------------|---------------|---------------|------------|---------------|---------------|---------------|------------|
Revenue (quarterly)| [$248](url)   | [$301](url)   | [$292](url)   | **$355** (FY−Q1−Q2−Q3) | [$267](url)   | [$325](url)   | [$297](url)   | **$495** (same) | [$248](url)   | [$301](url)   | [$292](url)   | **$715** (same) |
Revenue (annual)   |               |               |               |[$1,196](url)|              |               |               |[$1,384](url)|              |               |               |[$1,556](url)|
Notes              |               |               |               | imputed Q4 |               |               |               | imputed Q4 |               |               |               | imputed Q4 |

SEASONAL RATIOS
     | FY2022 | FY2023 | FY2024 | 3-yr avg |
-----|--------|--------|--------|----------|
Q1   | 20.7%  | 19.3%  | 15.9%  | 18.6%    |
Q2   | 25.1%  | 23.5%  | 19.3%  | 22.6%    |
Q3   | 24.4%  | 21.5%  | 18.8%  | 21.6%    |
Q4   | 29.7%  | 35.8%  | 45.9%  | 37.1%    |
Sum  | 100%   | 100%   | 100%   | 100%     |
Notes| Q4 from imputed quarter / FY | (same) | (same) | |

PROJECTIONS (FY20XXE = $X)
                  | FY2XE-Q1 | FY2XE-Q2 | FY2XE-Q3 | FY2XE-Q4 |
------------------|----------|----------|----------|----------|
Projected ($M)    |          |          |          |          |
Notes             |          |          |          |          |
```

The Notes row must be populated for: derived Q4 values, excluded anomaly years,
re-weighted in-progress quarter projections, stock items used as Q4 directly, or
any year where the ratio was estimated rather than computed from deepKPI data.

## Exporting to Excel or CSV

Use the **`format-deepkpi-for-excel`** skill for all spreadsheet layout,
styling, numeric date headers, freeze panes, column grouping, hyperlinks on
**value cells** (green, no underline — **no** separate Sources sheet/rows for
filings), number formats, and the pre-delivery checklist. Implement with the
**xlsx** skill.

**Seasonality model addenda (on top of that spec):**

- **Three ALL CAPS section blocks** in document order: **ACTUALS**, **SEASONAL
  RATIOS**, **PROJECTIONS**. Row semantics match the markdown template earlier in
  this skill; **period columns** follow **`format-deepkpi-for-excel`**
  (**annual block**, blank separator, **quarterly block** — not quarterlies-left as
  in legacy examples).
- **Every ratio and every projected quarter** is a live `=` formula. Do not
  hardcode seasonal ratios or projection numbers. Examples:
  - **Q4 actual (in the quarterly metric row, Q4 column):**
    `=FY_cell - Q1_cell - Q2_cell - Q3_cell` — **not** a separate “Q4 derived” row
  - **Per-year Q ratio:** `=Q_cell / FY_cell`
  - **Average ratio:** `=AVERAGE(ratio_year1, ratio_year2, …)`
  - **Projected quarter:** `=projected_FY_cell * avg_ratio_cell`
  - **In-progress re-weighting:** `=Q3_ratio_cell / (Q3_ratio_cell + Q4_ratio_cell)`
- The model must **recalculate** when FY projection assumptions change.
- **CSV:** Cannot store live formulas or real hyperlinks. Add `provenance_url` and
  `formula` (raw strings) as needed; warn the user and recommend `.xlsx`.

Run the **`format-deepkpi-for-excel`** pre-delivery checklist before sharing the
file; add seasonality-specific checks: all ratios/projections are formulas;
Notes row populated per this skill’s rules where applicable.

## Caveats to flag in Notes column

- **Imputed Q4**: flag in Notes every year where Q4 = FY − Q1 − Q2 − Q3 (not directly reported), even though the value sits **in the quarterly row**
- **Anomaly year excluded**: identify the year, the distortion, and that it was excluded
- **Shifting pattern**: if the quarterly mix is trending over time, note the direction
- **Non-December fiscal year**: match Q1–Q4 labels to the company's fiscal calendar
  (e.g., AAPL ends September, NVDA ends January)
- **In-progress re-weighting**: note which quarters are actuals vs. projected
- **Geographic/segment splits**: same technique applies; note the series used

path: analyst-report-pressure-test/pressure-test-double-check.md
content: # Pressure-test double-check (internal)

**Not a standalone skill.** This document is part of **`analyst-report-pressure-test`**
only. The authoring agent runs this pass after draft HTML exists and before presenting
the artifact to the user. It returns a structured review (findings only); the authoring
agent revises the HTML and may re-run this pass.

You are the **pressure-test double-check** pass used **only** inside the
`analyst-report-pressure-test` workflow. You catch the failure modes that
human reviewers have flagged in past pressure tests, *before* the
artifact reaches the end user.

You do **not** rewrite the artifact. You return a structured review.
The workflow that produced the HTML decides what to act on.

## What a pressure test looks like

The artifact is a dark-themed HTML report with a consistent structure.
You should expect (and look for) each of these:

- A **header** naming the company, ticker, and the source firm/action
  being pressure-tested (e.g., "CLX: Pressure-Testing the JPM Downgrade").
- A small **"Price since report"** box near the top with the report-date
  close, current close, and Δ%.
- 4–6 **argument sections**, each containing:
  - A **claim banner** that summarizes what the analyst argued in that
    section. Banners carry an amber source pill (= analyst/source report).
  - One or more **Chart.js charts** plotting SEC data relevant to the
    claim.
  - A set of **evidence cards** split into **Supports** (the thesis) and
    **Complicates** (the thesis).
    - **Layout is fixed:** **Supports is always the left column** and
      **Complicates is always the right column** (never swapped).
    - Cards carry cyan source pills (= SEC) and often `?pvid=` provenance
      links to the underlying filing passage.
- A concluding **Deeper Picture** (or equivalent synthesis) section that
  weaves the arguments into an integrated view.

If the artifact you are handed is not a pressure test — no claim banners,
no Supports/Complicates split, no Deeper Picture — stop and report that
this is the wrong pass for the artifact.

## Inputs

1. The path to the draft pressure-test HTML.
2. Optionally, the path to the analyst report (PDF) the pressure test was
   built from. When the source is provided, R1 and R8 are in scope;
   otherwise flag them as `not checked`.

If the artifact is missing or unreadable, stop and report — do not guess.

## Procedure

1. **Read the HTML end-to-end first**, including `<script>` blocks that
   carry Chart.js data. Do not flag anything until you have the whole
   picture.
2. **Extract the claim graph.** For each argument section, list:
   (a) the claim banner verbatim, (b) every quantitative or causal
   statement in the Supports cards, (c) every quantitative or causal
   statement in the Complicates cards, (d) every chart id and exactly
   what it plots (metric, entity, time window), (e) every cross-reference
   the prose makes ("the chart below", "as shown above", "scatterplot on
   page 2"), (f) every `?pvid=` provenance link, (g) whether **Supports
   renders left** and **Complicates renders right** in that section.
3. **Run each rule below** against the claim graph. Cite location
   (section name, chart id, card) and quote verbatim.
4. **Rank severity.** Critical = would mislead the reader, misrepresent
   the source report, or embarrass the author. Suggested = weakens the
   pressure test but isn't misleading. Optional = polish.
5. **Stay open-ended.** If something looks wrong but fits no rule,
   flag it as `Other`. These candidates feed future rule revisions.

---

## The rubric

Twelve rules, four buckets. Each rule is a mechanical check against the
pressure test's structure — claim banners, charts, Supports/Complicates
cards, Deeper Picture. Seed examples from past reviews live in the
appendix for calibration only; they are not the rules themselves.

### Bucket A — Claim banner framing

**R1. Banner faithful to the source report.** Every strong word in the
banner ("competitively", "cushion", "divergence", "largely", "driven
by") must appear in or clearly follow from the source analyst report.
No sharpening, no softening, no invented thesis label, no omission of
a rationale the report itself gave for why a number moved. *Check by
diffing banner language against the PDF; requires source.*

**R2. Banner correctly scoped.** Each section covers one coherent
claim. If the banner combines two report sections, the combination is
acknowledged in the banner itself. The section header matches what is
actually being argued. *Check: could a reader reconstruct the section
thesis from the banner alone?*

### Bucket B — Chart–claim alignment

**R3. Every claim is charted.** Every number, percent, or directional
statement in the banner and cards appears in a chart in the same section
— same **metric**, same **entity**, same **time window**. Every chart
the prose references actually exists in the HTML. *Check by listing all
numeric claims and ticking them off against chart ids.*

**R4. Charts are complete and diagnostic.** If the claim names N
segments, components, or periods, the chart includes all N. The metric
chosen can actually move the way the claim implies (e.g., do not use a
ratio dominated by a fixed denominator to test an efficiency claim).
Amber (source) and cyan (SEC) series are labeled and distinguishable.
*Check by comparing the claim's dimensions to the chart's series.*

### Bucket C — Supports / Complicates cards

**R5. Card fits its section.** Every data point in a Supports or
Complicates card can be attached to the section thesis with "this
matters because [thesis]" in one sentence, without twisting the logic.
Facts that have to "reach" to connect belong in a different section.
Additionally, the Supports/Complicates split must be **structurally
correct**:
- **Supports** must be the **left** column and **Complicates** the
  **right** column in every section (never swapped).
- The column labels must match the card content (no "Supports" heading
  above counter-evidence, etc.).
*Check card-by-card; apply the one-sentence test and the layout/label
check.*

**R6. Novelty per card.** Each card introduces at least one datum,
calculation, or cross-period comparison that is **not** already in the
analyst report and **not** already shown in the chart directly above
it. Pure paraphrase, pure chart-retelling, and self-graded commentary
("this is the cleanest claim", "directionally corroborated") fail.
*Check by subtracting the report's content and the chart's content from
the card; what remains must be substantive.*

**R7. Rationale with numbers.** Every metric is paired with a clause
explaining what drives it or why it matters for the section thesis.
Any metric that appears exactly once in the whole pressure test is
either given a "why it matters" sentence or cut. Strings of three or
more metrics in a card with no connective reasoning fail. *Check by
counting metrics in each card and matching each to a driver/meaning
clause.*

**R8. Supports vs Complicates are symmetric.** The Complicates side is
as rigorous as the Supports side — matching depth, matching citation
density, matching specificity.
- Causal adverbs ("largely", "primarily", "driven by", "almost
  entirely") are supported by data that distinguishes the named driver
  from the alternatives; otherwise soften or name the alternatives.
- When a Supports card uses a specific number (price target, normalized
  EBITDA, multiple, growth rate), the Complicates card either produces
  an alternative on the same basis or explicitly flags the asymmetry.
- Peers used in either side are drawn from the same sub-industry and
  business model, not just the same market-cap bucket or
  software/hardware tag.
- Accounting framework (GAAP vs non-GAAP) and valuation framework
  (P/E vs EV/EBITDA vs EV/Sales) match the claim; if the source's
  framework flatters the conclusion, show the alternative framework
  on the Complicates side.

### Bucket D — Language, consistency, synthesis

**R9. No filler, take a position.** Cut:
- Trivially true statements ("growth depends on traffic inflecting
  positive" — traffic is part of growth).
- Vague evaluative phrases ("structural break, not a rounding error",
  "the bleeding has at least paused").
- Self-evaluative commentary ("this is the cleanest of the five
  claims").
- "Mechanism is plausible" / "operationally achievable" hedges that
  don't commit.

When a card names a risk or dynamic, the reviewer's view on whether it
materializes is stated. Risk-listing without a view fails.

**R10. Defined and internally consistent.**
- Ambiguous terms ("earnings", "the dataset", "normalized") are defined
  on first use.
- Derived statistics ("X% below industry average") show the derivation
  or are cut.
- No typos in domain terms ("base case" not "bar case").
- No references to content that doesn't exist ("scatterplot on page 2"
  only if page 2 has a scatterplot).
- The same metric is not cited with two different values in two
  different sections.
- Source attribution is consistent: amber pill = analyst/source report,
  cyan pill = SEC. No mix-ups. Every `?pvid=` link resolves to a
  passage that actually supports the cited claim.

**R11. Recent baselines.** Temporal comparisons in the pressure test
use the closest relevant period. A current-quarter claim compared
against a trough three-plus years back while skipping the intervening
quarters fails unless a long-cycle view is explicitly what the section
is arguing. Cyberattack-era, pandemic-era, and other distorted base
periods are flagged when used as normal.

**Recency requirement (no avoidable staleness):**
- If the artifact suggests SEC data is "old" because it leans on an
  annual 10‑K while a **more recent 10‑Q period exists** for the same
  metric/claim, that is a failure. The pressure test must use the most
  up-to-date available filing periods so it doesn’t land on a "take it
  or leave it" stale-data posture.
- When mixing annual and quarterly views, the narrative must make clear
  which is being used for *current* evidence vs *long-cycle* context.

*Check by looking at the span of every comparison and asking whether a
closer comp was available, and whether a more recent quarterly filing
period should have been used instead of stopping at the last 10‑K.*

**R12. Deeper Picture weaves.** The Deeper Picture integrates multiple
argument sections into a nuanced take, states explicitly where the
source analyst is directionally right and where they over- or
understate, and does not contradict the evidence cards above it. Pure
recap, pure restatement, or a generic "investors should watch" sign-off
fails. *Check by reading the Deeper Picture after the cards and asking
whether it added integration.*

---

## Output format

Use this structure exactly.

```
Artifact: <filename>
Source report checked: yes | no
Overall: Pass | Needs Revision | Fail

Summary
<2–4 sentences on the biggest risks.>

Findings
1. [Critical] R3 chart–claim alignment — §<section>
   Claim: "<exact quote from banner or card>"
   Chart shown: <chart id + what it actually plots>
   Problem: <one sentence>
   Fix: <one sentence, actionable>

2. [Suggested] R6 novelty per card — §<section> <Supports|Complicates>
   Quote: "<exact quote>"
   Problem: <one sentence>
   Fix: <one sentence>

...

Passes
- R2 banner scoping: clean
- R10 consistency: clean
- ...

Not checked
- R1 banner fidelity: source report not provided
- R8 symmetry: source report not provided
```

## Quality bar for your own output

- Every finding cites a specific location (section name, chart id,
  Supports/Complicates, card number).
- Every finding quotes the problematic text verbatim where possible.
- Every finding offers an actionable fix, not "consider revising."
- Severity is justified. Critical = the reader is misled. Otherwise
  Suggested or Optional.
- Say "clean" for categories that pass. Do not invent issues to fill
  space.
- When the source report isn't provided, list R1 and R8 under
  `Not checked`.

## What you are not

- Not a rewriter. No replacement HTML, prose, or charts.
- Not a fact-checker against the outside world. Internal consistency
  against the artifact's own data and (when provided) against the
  source analyst report.
- Not a style critic. Tone and word choice are in-scope only when they
  create a framing problem (R1, R8, R9).

---

## Appendix: seed examples from past pressure tests

Case library for calibration, not a second set of rules. Each example is
tagged with the rule it illustrates, drawn from reviews of CLX, HP,
EXPE, PLNT, AXON, and CMG pressure tests. Append here as more reviews
arrive — do not grow the rubric unless a genuinely new failure mode
appears.

### R1 — Banner faithful to the source report

- **Fail:** Banner says lodging supply "positions EXPE competitively";
  the source report called it a long-term tailwind but did not claim it
  closed the gap with peers.
- **Fail:** Banner says valuation "provides downside cushion"; the source
  called the valuation attractive but did not use cushion language.
- **Fail:** Banner reproduces JPM's FQ2 CLX numbers but drops the
  ERP-conversion rationale JPM gave for why shipments moved.
- **Fail:** A loyalty comment in the source was extrapolated into a full
  B2C-retention thesis in the banner.
- **Fail:** Section labeled "Segment Divergence" when the source was
  just listing segment beats and misses.

### R2 — Banner correctly scoped

- **Model:** AXON §1 combined "~29% CAGR" with "25–29% sensor growth"
  from two different parts of the report and flagged the combination.
- **Model:** CLX §3 correctly separated Household out as its own claim
  rather than folding it into a broader margin section.

### R3 — Every claim is charted

- **Fail:** Banner gives FQ2 -1% revenue / -2.8% volumes; charts show
  annual organic volume and segment-level quarterly volume — the total-
  company quarter print is nowhere.
- **Fail:** Supports card asserts "Lifestyle price/mix has been negative
  for four straight quarters"; the preceding chart shows Household
  price/mix, not Lifestyle.
- **Fail:** Supports card references "the scatterplot on page 2"; no
  scatterplot appears in the artifact.
- **Fail:** Valuation and GICS-rotation sections have no chart at all.

### R4 — Charts are complete and diagnostic

- **Fail:** Segment-margin chart covers only 2 of the 4 segments named
  in the claim.
- **Fail:** "SSS decomposed into transactions vs check" chart only shows
  total SSS and Transactions; check and price are missing.
- **Fail:** Lodging-supply chart is missing the most recent quarter that
  the +10% claim is anchored to.
- **Fail:** "Labor as % of revenue" used to test retrofit throughput;
  because labor is roughly fixed, the ratio mostly tracks revenue and
  can't isolate what the claim is arguing.
- **Model:** Contract backlog used as the forward-outlook proxy when
  forward outlook is hard to observe directly.

### R5 — Card fits its section

- **Fail:** Segment-divergence Complicates card ends with consolidated
  ad-spend (13% of US sales) — a company-level number that doesn't
  address divergence.
- **Fail:** Household section includes Glad JV / ERP commentary about
  broader gross margin — belongs in the gross-margin section.
- **Fail:** Valuation section includes R&D-margin commentary — belongs
  in profitability.
- **Fail:** AI-monetization section uses TAM-geography data as its
  Complicates evidence.
- **Fail:** SBC section leads with Adjusted EBITDA, which by definition
  excludes SBC.
- **Model:** Household Organic Volume overlaid with Price/Mix — both
  dimensions cleanly support the Household-deterioration thesis.

### R6 — Novelty per card

- **Fail:** Complicates card repeats the analyst's math verbatim
  ("Pre-deal debt $X / LTM EBITDA $Y = 2.1x…").
- **Fail:** Supports card retells the revenue chart directly above it.
- **Fail:** "This is the cleanest of the five claims" — self-graded
  commentary with no evidence.
- **Model:** Pulled RPO and tariff-cost disclosure data that were not
  in the source report.
- **Model:** Layered historical Black Card penetration with promotion
  events to create a new cross-period read.

### R7 — Rationale with numbers

- **Fail:** Run of three to four metrics in sequence with no driver
  clause between them.
- **Fail:** "ARR hit $1.30B" introduced without saying why ARR matters
  to the thesis being argued.
- **Fail:** Metric appears exactly once in the whole pressure test with
  no setup (Walmart concentration at 26%; GOJO 2023 sale attempt).
- **Model:** "-18% to -3%, a 15-point sequential acceleration" — datum
  paired with its magnitude and framing.
- **Model:** Household EBIT collapse data paired with the qualitative
  mechanism ("consumer shift to bulk/value packs is structural").

### R8 — Supports vs Complicates are symmetric

- **Fail:** Complicates card challenges analyst's $982M normalized
  EBITDA but doesn't compute an alternative.
- **Fail:** States B2C margins are "higher than B2B" without exact
  numbers.
- **Fail:** Implies non-GAAP P/E/g flatters the story but doesn't list
  the GAAP-inclusive P/E/g.
- **Fail:** "Cyberattack base-effect" cited as the *main* reason for
  volume recovery when underlying operational growth also contributed.
- **Fail:** Fortinet/CrowdStrike used as peers for a public-safety
  platform; QSR peers used for a fast-casual restaurant.
- **Fail:** P/E framing applied to a target built on EV/EBITDA.
- **Model:** Quick-and-dirty calculations used to verify or extend the
  analyst's leverage math.
- **Model:** Analyst's own optimistic framing challenged with the
  analyst's own data.

### R9 — No filler, take a position

- **Fail:** "Structural break, not a rounding error."
- **Fail:** "The bleeding has at least paused."
- **Fail:** "Whether +0.3% turns into +1% depends on traffic inflecting
  positive" (traffic is a component of the number).
- **Fail:** Card names TASER refresh-cycle risk without saying whether
  the reviewer thinks it slows.
- **Fail:** "Forced selling from index mechanics" asserted as the cause
  of a selloff with no flow data.
- **Model:** Stated directly where the analyst is directionally right
  and where they overstate.

### R10 — Defined and internally consistent

- **Fail:** "Earnings have declined for four straight quarters" —
  "earnings" undefined (EBIT? Net Income?) and the chart does not
  actually show four consecutive declines.
- **Fail:** "Trades at 50–65% below industry average" — derivation not
  shown.
- **Fail:** "RBC's own bar case" — should be "base case".
- **Fail:** "The sharpest quarterly deterioration in the dataset" — no
  date range.

### R11 — Recent baselines

- **Fail:** FQ2 FY26 margin compared directly against the FQ1 FY23
  trough, skipping the intervening quarters.
- **Fail:** Complicates card leans on a single cyberattack-distorted
  FQ1 FY25 number to carry the point.
- **Model:** Y/Y comparison uses the immediately preceding same-quarter
  period with all numerators and denominators visible.

### R12 — Deeper Picture weaves

- **Model:** Deeper Picture sections in CLX, CMG, and AXON were
  consistently praised — common pattern was naming where the analyst is
  directionally right, where they overstate, and where they understate,
  without re-fighting a single section.


path: analyst-report-pressure-test/analyst-report-pressure-test.md
content: ---
name: analyst-report-pressure-test
description: >
  Pressure-test any analyst report on a US public company. Upload a PDF of a sell-side
  report and say "Pressure test this" — the skill extracts the analyst's key arguments,
  pulls granular SEC filing data via deepKPI to build supporting and counter-evidence
  for each claim, then produces an interactive HTML report with Revelata dark branding,
  Chart.js visualizations (blue palette), source attribution (amber = analyst, cyan = SEC),
  and clickable provenance hyperlinks to the exact filing passages. Use whenever the user
  mentions "pressure test", "pressure-test", "critically analyze", "triangulate", "fact-check",
  or "challenge" in the context of an analyst report, research note, or investment thesis.
  Also triggers when the user uploads a PDF that looks like a sell-side report and asks
  for analysis, counterpoints, or a second opinion on it.
---

# Analyst report pressure test

Take an analyst report and rigorously test every argument against SEC filing data.
The output is an interactive HTML report that a portfolio manager can open in a browser
and use to form an independent view — every number is clickable back to its source.

## When this skill triggers

- User says "pressure test this" (or similar) with an uploaded analyst report
- User uploads a sell-side PDF and asks for critical analysis, counterpoints, or fact-checking
- User asks to "triangulate" or "challenge" an investment thesis

## Chat pacing and verbosity

Keep the **conversation** thin; put the depth in the **HTML report**.

- After reading the PDF, state the **4–6 main arguments** you will pressure-test
  (short titles or one line each — this is the roadmap for the user).
- Treat each request as self-contained: **do not reference, compare to, or borrow from any other analyst reports** you may have analyzed earlier in the same chat/session unless the user explicitly asks you to do so. Assume you are pressure-testing **only the report(s) uploaded with the current request**.
- Also state you'll pull **market reaction context** (price on report date vs today),
  then move straight into data pulls.
- Do **not** narrate every tool call, intermediate table, or reasoning step in chat.
  Avoid dumping raw deepKPI responses into the thread.
- While pulling data, use a **brief progress line per argument**, e.g.
  `Pulling SEC data for 2/5: [short argument title]…` then continue silently until
  the next argument or until the HTML is ready.
- **Automatically build and save the HTML report** when pulls and drafting are
  complete. Do **not** ask whether to generate the file unless the user explicitly
  asked for a non-HTML deliverable only.
- **Before presenting the HTML**, run the **pressure-test double-check** pass
  (see below). In chat, a single line is enough, e.g. `Running pressure-test QA on the draft HTML…`
- After the artifact is **double-checked** and any **Critical** issues are
  addressed (or explicitly accepted by you as the authoring agent): **present**
  the file (`present_files` or equivalent) and add **1–2 sentences** on the
  sharpest takeaway — no full recap.

## High-level workflow

1. **Read the report** — extract the analyst's 4-6 key arguments/claims
2. **Identify the company** — resolve the ticker/name to a CIK via deepKPI
3. **Pull SEC data** — for each argument, search deepKPI for the most granular
   metrics that can confirm or complicate the claim
4. **Build evidence pairs** — for each argument, write a "supports the thesis"
   card and a "complicates the thesis" card, grounded in specific numbers
5. **Write the synthesis** — 2 paragraphs that weave the evidence into a nuanced
   take the analyst didn't give you
6. **Generate the HTML** — an interactive, dark-themed report with Chart.js charts,
   source attribution, and provenance links (**default deliverable — produce it without asking**)
7. **Double-check the draft HTML** — mandatory QA pass before the user sees the file;
   structured review only (see **Step 7**)
8. **Revise and iterate** — you decide which findings to fix; re-run the double-check
   after material edits until **Overall: Pass** or remaining issues are only **Suggested** / **Optional**
9. **Deliver** — present the final HTML to the user (**short wrap-up only**)

Each of these steps is detailed below. Follow **Chat pacing and verbosity** for what to say in-thread vs. what belongs only in the HTML.

## Dependencies

This skill relies on **`retrieve-kpi-data`** for **KPI** retrieval and on
**`retrieve-sec-filing`** when you need **verbatim SEC filing passages** or **full filing markdown**
(not just structured metrics). Before starting, read
`retrieve-kpi-data/retrieve-kpi-data.md` for metrics workflow, provenance, and gaps;
read `retrieve-sec-filing/retrieve-sec-filing.md` when claims
must be checked against exact filing language. Use
`company-summary-segments/company-summary-segments.md` for **business description**,
**segment structure**, or **thematic** lists when helpful (not required for every run).
This skill
handles the analytical framework and HTML output.

For the mandatory QA rubric on the finished HTML, read **`pressure-test-double-check.md`**
in this same folder (internal to this skill — not a separate user-facing skill).

## Scope

This skill works for **US public companies** with SEC filings indexed in deepKPI.
If the report covers a non-US company or a private company, tell the user that
deepKPI doesn't have coverage and offer to do a qualitative analysis instead
(without the data-backed evidence cards and provenance links).

---

## Step 1: Read the analyst report

Read the uploaded PDF. Extract:

- **Company name and ticker**
- **Report metadata**: author/firm, date, rating action (upgrade/downgrade/initiation),
  price target if applicable. Store the firm name internally for source pills and claim
  banners, but **do not surface the firm name in the footer or synthesis**.
- **4-6 key arguments** the analyst makes. These are the claims you'll pressure-test.
  Look for: revenue/growth commentary, margin trends, segment performance, balance
  sheet / leverage, competitive positioning, specific catalysts or risks.

Write each argument as a 1-2 sentence summary. You'll use these as the section
headers in the final report. **In chat**, share this list once as the identified
main arguments; do not pre-write full evidence cards in the thread.

## Step 1.5: Market reaction context (price move since publication)

Get the stock **close price** on:

- **Report date** (use the report's publication date; if only a date is given, use that day's close)
- **Current date** (most recent close)

Compute percent move: \(\\Delta\\% = (P_\\text{now}/P_\\text{report} - 1)\\times 100\\).

### Reporting rules (keep concise)

- Add a small **\"Price since report\"** box near the top of the HTML with the two closes and the \(\\Delta\\%\\).
- Keep the commentary **blunt and non-narrative**: factual finance language only.
- If price data cannot be retrieved reliably in the current environment, state that in the HTML box and continue with the SEC pressure test.

## Step 2: Resolve the company in deepKPI

Use the **`retrieve-kpi-data`** workflow:

1. Call `query_company_id` with the company's official registrant name (not brand)
2. Call `list_kpis` (free) to see every available metric
3. Scan the KPI list to plan your searches — map each analyst argument to the
   most granular KPIs available

## Step 6: Generate the HTML report

Read `references/html-template.md` in this folder for the complete HTML/CSS/JS template.

The report structure includes:

- Header link label: **\"Analysis Pressure Test (GitHub)\"**
- Title: \"[Company] ([Ticker]): Pressure-Testing the [Firm] [Action]\"

## Step 7: Double-check the draft HTML (mandatory)

After the draft HTML file is written (saved path known), you **must** run the
**pressure-test double-check** before `present_files` / showing it to the user.

1. **Read** `pressure-test-double-check.md` in this folder (`analyst-report-pressure-test/`).
2. **Execute the procedure** in that document against the draft HTML:
   - If your host can invoke a **separate reviewer agent**, give it that doc plus
     the HTML path (and the analyst PDF path when available) and collect its output.
   - Otherwise, **perform the same pass yourself** in a distinct step: read the HTML
     end-to-end, build the claim graph, run rules **R1–R12**, and emit the **exact
     output format** specified there (structured review — **do not rewrite** the
     HTML inside the double-check output).
3. Pass the **source PDF path** into the double-check whenever you still have it;
   otherwise R1 and R8 must appear under **`Not checked`** in the review.

**You** (the authoring agent) **own revisions**: use the review's severity-ranked
findings to patch the HTML. Typical loop:

- Fix all **Critical** before delivery. **Fail** overall → treat as blocking until
  addressed or the user explicitly waives QA (only if they say so).
- **Needs Revision** → fix Critical, then re-run Step 7 on the updated file.
- **Pass** with only **Suggested** / **Optional** → you may still polish, then deliver.

Re-running Step 7 after substantive edits is **recommended** so regressions do not
ship.

---

## Reference files

| File | When to read |
|------|-------------|
| `references/html-template.md` | Always — contains the full HTML/CSS/JS template |
| `references/chart-patterns.md` | When building charts — palette, dash patterns, examples |
| `pressure-test-double-check.md` | **Always after draft HTML exists** — mandatory internal QA rubric and output format |



path: analyst-report-pressure-test/references/chart-patterns.md
content: # Chart Patterns Reference

Every chart in an Analysis Pressure Test report uses Chart.js 4.x on a dark background
with the blue-family palette. This file shows the patterns for common chart types
you'll encounter when visualizing SEC filing data.

## Palette

```js
const B1 = '#4FEAFF';  // cyan — primary series
const B2 = '#90caf9';  // light blue — secondary
const B3 = '#5b8def';  // mid blue — tertiary
const B4 = '#a78bfa';  // periwinkle — quaternary
const grid = { color: 'rgba(255,255,255,0.05)' };
```

## Series differentiation (when you can't use color alone)

When multiple series appear on the same chart, differentiate with ALL THREE:
shade, dash pattern, and point shape.

| Series | Color | borderDash | pointStyle |
|--------|-------|-----------|------------|
| 1st    | B1    | `[]` (solid) | `'circle'` |
| 2nd    | B2    | `[6,3]` | `'rect'` |
| 3rd    | B3    | `[2,3]` | `'triangle'` |
| 4th    | B4    | `[8,4,2,4]` | `'rectRounded'` |

## Common chart types

### Single-series bar (positive/negative shading)

Good for: annual volume growth, single KPI trend with sign changes.

```js
new Chart(document.getElementById('cN'), {
  type: 'bar',
  data: {
    labels: ['FY20','FY21','FY22','FY23','FY24','FY25'],
    datasets: [{
      data: [10, 6, -5, -10, -5, 7],
      backgroundColor: [10,6,-5,-10,-5,7].map(v => v >= 0 ? B1+'99' : B1+'33'),
      borderColor: [10,6,-5,-10,-5,7].map(v => v >= 0 ? B1 : B1+'88'),
      borderWidth: 1, borderRadius: 4, barPercentage: 0.6
    }]
  },
  options: {
    responsive: true,
    plugins: {
      legend: { display: false },
      tooltip: { callbacks: { label: c => c.parsed.y + '%' }}
    },
    scales: {
      y: { ticks: { callback: v => v + '%' }, grid },
      x: { grid: { display: false }}
    }
  }
});
```

### Multi-series line (segments over time)

Good for: comparing segment volume, margin trends across divisions.

```js
new Chart(document.getElementById('cN'), {
  type: 'line',
  data: {
    labels: ['FQ1 24','FQ2 24','FQ3 24','FQ1 25','FQ2 25'],
    datasets: [
      {
        label: 'Segment A',
        data: [38, 22, -4, -16, 2],
        borderColor: B1, backgroundColor: B1+'18',
        tension: 0.35, pointRadius: 5, borderWidth: 2.5,
        borderDash: [], pointStyle: 'circle'
      },
      {
        label: 'Segment B',
        data: [43, 4, -3, -18, -3],
        borderColor: B2, backgroundColor: B2+'18',
        tension: 0.35, pointRadius: 5, borderWidth: 2.5,
        borderDash: [6,3], pointStyle: 'rect'
      }
    ]
  },
  options: {
    responsive: true,
    plugins: { legend: { labels: { color: '#8b949e' } } },
    scales: {
      y: { grid, ticks: { color: '#8b949e' } },
      x: { grid: { display: false }, ticks: { color: '#8b949e' } }
    }
  }
});
```



path: analyst-report-pressure-test/references/html-template.md
content: # HTML Template Reference

This is the canonical HTML structure for every Analysis Pressure Test report.
Copy this skeleton and fill in the dynamic content. Do not deviate from the
CSS custom properties, class names, or layout structure — they are the Revelata
brand identity for this product.

**Logo asset:** The Revelata wordmark is **inlined as SVG** directly in the
header. No external asset is referenced and no file needs to be copied next
to the HTML. The logo links to `https://www.revelata.com/for-ai-builders`.

## Full HTML skeleton

```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>[TICKER] Analysis Pressure Test | Revelata</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js"></script>
<style>
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Figtree:wght@400;500;600;700&display=swap');
  :root {
    --bg: #0e1117; --surface: #161b22; --surface2: #1c2129;
    --border: #2a313a; --border-light: #353d47;
    --text: #e6edf3; --text-muted: #8b949e; --text-dim: #6e7681;
    --cyan: #4FEAFF; --cyan-dim: rgba(79,234,255,0.15); --cyan-glow: rgba(79,234,255,0.08);
    --blue: #90caf9; --blue-dim: rgba(144,202,249,0.12);
    --amber: #f59e0b; --amber-dim: rgba(245,158,11,0.12); --amber-text: #fbbf24;
    --red: #f87171; --red-dim: rgba(248,113,113,0.10);
    --green: #4ade80; --green-dim: rgba(74,222,128,0.10);
  }
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: 'Inter', system-ui, sans-serif;
    background: var(--bg); color: var(--text);
    line-height: 1.7; padding: 2.5rem;
    max-width: 900px; margin: 0 auto;
    font-size: 14.5px; -webkit-font-smoothing: antialiased;
  }

  /* Header */
  .header { margin-bottom: 2.5rem; }
  .header-brand { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.8rem; flex-wrap: wrap; }
  .header-brand .header-logo {
    display: block; height: 28px; width: auto; flex-shrink: 0;
  }
  .header-brand span {
    font-family: 'Figtree', 'Inter', system-ui, sans-serif;
    font-size: 1.1rem; font-weight: 600;
    color: var(--cyan);
  }
  .header-brand span a { color: var(--cyan); font-family: inherit; }
  .header-brand .header-divider {
    color: var(--border-light);
    font-weight: 300;
    font-size: 1.5rem;
    line-height: 1;
    margin: 0 0.1rem;
  }
  .header a { color: inherit; text-decoration: none; }
  .header a:hover { text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 3px; }
  h1 {
    font-size: 1.6rem; font-weight: 700;
    letter-spacing: -0.03em; color: #fff; margin-bottom: 0.3rem;
  }
  .subtitle { color: var(--text-muted); font-size: 0.85rem; margin-bottom: 1.5rem; }
  .subtitle strong { color: var(--red); font-weight: 600; }

  /* Legend */
  .legend {
    display: flex; gap: 2rem; padding: 0.9rem 1.2rem;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 8px; font-size: 0.8rem; color: var(--text-muted);
  }
  .legend-item { display: flex; align-items: center; gap: 0.5rem; }
  .legend-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }

  /* Price since report */
  .pricebox {
    margin-top: 1rem;
    background: var(--surface); border: 1px solid var(--border);
    border-left: 3px solid var(--cyan); border-radius: 8px;
    padding: 0.9rem 1.2rem;
  }
  .pricebox-title {
    font-size: 0.7rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.07em; color: var(--cyan);
    margin-bottom: 0.35rem;
  }
  .pricebox-body { font-size: 0.85rem; color: var(--text-muted); }
  .pricebox-body strong { color: #fff; font-weight: 650; }
  .pricebox-note { margin-top: 0.35rem; font-size: 0.75rem; color: var(--text-dim); }

  /* Section headings */
  h2 {
    font-size: 1.1rem; font-weight: 700; color: #fff;
    margin: 3rem 0 0.4rem; padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--border);
  }
  h2 .num { color: var(--cyan); margin-right: 0.4rem; }

  /* Analyst claim banner */
  .claim {
    background: var(--surface); border: 1px solid var(--border);
    border-left: 3px solid var(--amber); border-radius: 6px;
    padding: 0.9rem 1.1rem; margin: 1rem 0 1.2rem;
    font-size: 0.88rem; color: var(--text-muted);
  }
  .claim strong { color: var(--amber-text); font-weight: 600; }
  .claim .src {
    font-size: 0.7rem; font-weight: 600; color: var(--amber);
    text-transform: uppercase; letter-spacing: 0.06em; margin-right: 0.3rem;
  }

  /* Evidence cards */
  .evidence { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin: 1rem 0 1.5rem; }
  .ev-card {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 8px; padding: 1.1rem 1.2rem;
    font-size: 0.85rem; line-height: 1.65; color: var(--text-muted);
  }
  .ev-card p { margin-bottom: 0.6rem; }
  .ev-card p:last-child { margin-bottom: 0; }
  .ev-support { border-top: 3px solid var(--green); }
  .ev-counter { border-top: 3px solid var(--red); }
  .ev-label {
    font-size: 0.7rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.07em; margin-bottom: 0.7rem;
    display: flex; align-items: center; gap: 0.4rem;
  }
  .ev-support .ev-label { color: var(--green); }
  .ev-counter .ev-label { color: var(--red); }
  .ev-label svg { width: 13px; height: 13px; }

  /* Inline data highlights */
  .d { font-weight: 600; }
  .d-r { color: var(--amber-text); }
  .d-s { color: var(--cyan); }
  .d-s a, .ev-card a, .synthesis a:not(.footer a) {
    color: var(--cyan); text-decoration: underline;
    text-decoration-style: dotted; text-underline-offset: 2px;
  }
  .d-s a:hover, .ev-card a:hover, .synthesis a:hover {
    text-decoration-style: solid;
  }

  /* Source pills */
  .src-pill {
    display: inline-block; font-size: 0.6rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.05em;
    padding: 1px 5px; border-radius: 3px;
    vertical-align: middle; margin-right: 2px;
  }
  .src-r { background: var(--amber-dim); color: var(--amber); }
  .src-s { background: var(--cyan-dim); color: var(--cyan); }

  /* Charts */
  .chart-card {
    background: var(--surface); border: 1px solid var(--border);
    border-left: 3px solid var(--cyan); border-radius: 10px;
    padding: 1.3rem 1.4rem; margin: 1.2rem 0;
  }
  .chart-header {
    display: flex; justify-content: space-between;
    align-items: baseline; margin-bottom: 0.8rem;
  }
  .chart-title { font-size: 0.8rem; font-weight: 600; color: var(--text); letter-spacing: 0.01em; }
  .chart-src { font-size: 0.65rem; color: var(--text-dim); }
  canvas { max-height: 280px; }

  /* Synthesis */
  .synthesis {
    background: var(--cyan-glow);
    border: 1px solid rgba(79,234,255,0.25);
    border-radius: 10px; padding: 1.6rem 1.8rem; margin: 3rem 0 1rem;
  }
  .synthesis h2 { border: none; margin-top: 0; color: var(--cyan); }
  .synthesis p { margin-bottom: 1rem; color: var(--text-muted); font-size: 0.9rem; }
  .synthesis p:last-child { margin-bottom: 0; }

  /* Footer */
  .footer {
    margin-top: 2.5rem; padding-top: 1.4rem;
    border-top: 1px solid var(--border);
    font-size: 0.75rem; color: var(--text-dim); text-align: center;
  }
  .footer a { color: var(--cyan); text-decoration: none; }
  .footer a:hover { text-decoration: underline; text-decoration-style: dotted; }

  /* Disclosures */
  .disclosures {
    margin-top: 1.5rem; padding-top: 1.2rem;
    border-top: 1px solid var(--border);
    font-size: 0.68rem; color: var(--text-dim);
    line-height: 1.6;
  }
  .disclosures p { margin-top: 0.7rem; }
  .disclosures p:first-child { margin-top: 0; }
  .disclosures strong { color: var(--text-muted); font-weight: 700; }

  /* Closing CTA — plain on page background, between footer and disclosures */
  .closing-cta {
    margin-top: 2rem;
    font-size: 0.82rem; color: var(--text-muted);
    line-height: 1.65;
  }
  .closing-cta .cta-setup-label {
    font-family: 'Figtree', 'Inter', system-ui, sans-serif;
    font-size: 1.15rem; font-weight: 700;
    margin-bottom: 1rem;
  }
  .closing-cta .cta-setup-label a {
    color: var(--cyan);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: border-color 0.15s ease;
  }
  .closing-cta .cta-setup-label a:hover {
    border-bottom-color: var(--cyan);
    text-decoration: none;
  }
  .closing-cta .cta-paths {
    display: grid; grid-template-columns: 1fr 1fr; gap: 1.6rem;
    margin-top: 0.3rem;
  }
  .closing-cta .cta-path-label {
    font-size: 0.7rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.07em;
    color: var(--text); margin-bottom: 0.5rem;
    padding-bottom: 0.4rem; border-bottom: 1px solid var(--border);
  }
  .closing-cta strong { color: var(--text-muted); font-weight: 700; }
  .closing-cta a:not(.cta-setup-label *) {
    color: var(--cyan); text-decoration: underline;
    text-decoration-style: dotted; text-underline-offset: 2px;
  }
  .closing-cta a:not(.cta-setup-label *):hover { text-decoration-style: solid; }
  .closing-cta ol { padding-left: 1.3rem; margin-top: 0.3rem; }
  .closing-cta ol li { margin: 0.35rem 0; }
  .closing-cta code {
    font-family: ui-monospace, 'SF Mono', Menlo, monospace;
    font-size: 0.75rem; color: var(--text);
    background: var(--surface); padding: 1px 6px; border-radius: 3px;
    border: 1px solid var(--border);
  }

  /* Responsive */
  @media (max-width: 700px) {
    body { padding: 1.2rem; }
    .evidence { grid-template-columns: 1fr; }
    .legend { flex-direction: column; gap: 0.5rem; }
    .closing-cta .cta-paths { grid-template-columns: 1fr; gap: 1.2rem; }
  }
</style>
</head>
<body>

<!-- ===== HEADER ===== -->
<div class="header">
  <div class="header-brand">
    <a href="https://www.revelata.com/for-ai-builders" target="_blank" rel="noopener noreferrer" aria-label="Revelata">
      <svg class="header-logo" width="159" height="34" viewBox="0 0 159 34" fill="none" xmlns="http://www.w3.org/2000/svg" aria-label="Revelata Inc">
        <path d="M42.4412 26.6676V7.28626H48.7539C50.0091 7.28626 51.1166 7.53545 52.0765 8.03382C53.0548 8.5322 53.8116 9.22439 54.3468 10.1104C54.9006 10.9964 55.1775 12.0116 55.1775 13.156C55.1775 14.3005 54.8821 15.3157 54.2915 16.2017C53.7008 17.0877 52.8979 17.7891 51.8826 18.3059C50.8674 18.8043 49.723 19.0535 48.4494 19.0535H44.7946V26.6676H42.4412ZM53.3778 26.6676L48.7263 18.7213L50.5813 17.503L55.9527 26.6676H53.3778ZM44.7946 16.8939H49.0862C49.7876 16.8939 50.4152 16.737 50.969 16.4232C51.5227 16.0909 51.9657 15.6479 52.298 15.0942C52.6487 14.522 52.824 13.8759 52.824 13.156C52.824 12.0485 52.4364 11.1533 51.6611 10.4703C50.9043 9.76891 49.9168 9.4182 48.6986 9.4182H44.7946V16.8939ZM65.1997 26.9999C63.8523 26.9999 62.6617 26.6953 61.628 26.0862C60.5944 25.4586 59.7822 24.6003 59.1915 23.5112C58.6193 22.4222 58.3332 21.167 58.3332 19.7457C58.3332 18.3244 58.6193 17.0692 59.1915 15.9802C59.7822 14.8911 60.5851 14.042 61.6004 13.4329C62.634 12.8053 63.8154 12.4915 65.1444 12.4915C66.4365 12.4915 67.5532 12.8146 68.4946 13.4606C69.436 14.0882 70.1651 14.9742 70.6819 16.1186C71.1987 17.263 71.4572 18.6105 71.4572 20.161H60.0222L60.5759 19.6903C60.5759 20.7978 60.7697 21.7484 61.1574 22.5421C61.5634 23.3359 62.1264 23.945 62.8463 24.3695C63.5662 24.7756 64.3876 24.9787 65.3105 24.9787C66.2888 24.9787 67.1102 24.7479 67.7747 24.2865C68.4577 23.825 68.9837 23.2159 69.3529 22.4591L71.2633 23.4281C70.9126 24.148 70.4419 24.7756 69.8513 25.3109C69.2791 25.8462 68.5961 26.2615 67.8024 26.5569C67.0271 26.8522 66.1596 26.9999 65.1997 26.9999ZM60.7144 18.7489L60.1329 18.3059H69.6851L69.1037 18.7766C69.1037 17.8906 68.9283 17.1246 68.5776 16.4786C68.2269 15.8325 67.7562 15.3341 67.1656 14.9834C66.5749 14.6327 65.8919 14.4574 65.1167 14.4574C64.3599 14.4574 63.64 14.6327 62.957 14.9834C62.2925 15.3341 61.748 15.8325 61.3235 16.4786C60.9174 17.1061 60.7144 17.8629 60.7144 18.7489ZM78.1355 26.6676L83.7838 12.8238H86.1095L80.3228 26.6676H78.1355ZM77.9971 26.6676L72.2103 12.8238H74.5084L80.1567 26.6676H77.9971ZM94.023 26.9999C92.6755 26.9999 91.485 26.6953 90.4513 26.0862C89.4176 25.4586 88.6055 24.6003 88.0148 23.5112C87.4426 22.4222 87.1565 21.167 87.1565 19.7457C87.1565 18.3244 87.4426 17.0692 88.0148 15.9802C88.6055 14.8911 89.4084 14.042 90.4236 13.4329C91.4573 12.8053 92.6386 12.4915 93.9676 12.4915C95.2597 12.4915 96.3765 12.8146 97.3178 13.4606C98.2592 14.0882 98.9883 14.9742 99.5052 16.1186C100.022 17.263 100.28 18.6105 100.28 20.161H88.8454L89.3992 19.6903C89.3992 20.7978 89.593 21.7484 89.9806 22.5421C90.3867 23.3359 90.9497 23.945 91.6696 24.3695C92.3894 24.7756 93.2108 24.9787 94.1338 24.9787C95.1121 24.9787 95.9335 24.7479 96.598 24.2865C97.2809 23.825 97.807 23.2159 98.1762 22.4591L100.087 23.4281C99.7359 24.148 99.2652 24.7756 98.6745 25.3109C98.1023 25.8462 97.4194 26.2615 96.6256 26.5569C95.8504 26.8522 94.9828 26.9999 94.023 26.9999ZM89.5376 18.7489L88.9562 18.3059H98.5084L97.927 18.7766C97.927 17.8906 97.7516 17.1246 97.4009 16.4786C97.0502 15.8325 96.5795 15.3341 95.9888 14.9834C95.3982 14.6327 94.7152 14.4574 93.9399 14.4574C93.1832 14.4574 92.4633 14.6327 91.7803 14.9834C91.1158 15.3341 90.5713 15.8325 90.1467 16.4786C89.7407 17.1061 89.5376 17.8629 89.5376 18.7489ZM103.074 26.6676V7.28626H105.289V26.6676H103.074ZM117.686 26.6676L117.575 24.3972V19.3581C117.575 18.269 117.455 17.3738 117.215 16.6724C116.975 15.9525 116.597 15.408 116.08 15.0388C115.563 14.6696 114.889 14.485 114.058 14.485C113.302 14.485 112.646 14.6419 112.093 14.9557C111.557 15.2511 111.114 15.731 110.764 16.3955L108.77 15.6202C109.121 14.9742 109.545 14.4204 110.044 13.959C110.542 13.4791 111.124 13.1191 111.788 12.8792C112.453 12.6207 113.209 12.4915 114.058 12.4915C115.351 12.4915 116.412 12.75 117.243 13.2668C118.092 13.7652 118.728 14.5127 119.153 15.5095C119.578 16.4878 119.781 17.706 119.762 19.1643L119.734 26.6676H117.686ZM113.532 26.9999C111.908 26.9999 110.634 26.6307 109.712 25.8923C108.807 25.1356 108.355 24.0927 108.355 22.7636C108.355 21.3608 108.816 20.2902 109.739 19.5519C110.681 18.7951 111.991 18.4167 113.671 18.4167H117.63V20.2718H114.169C112.877 20.2718 111.954 20.484 111.4 20.9086C110.865 21.3331 110.598 21.9422 110.598 22.736C110.598 23.4558 110.865 24.028 111.4 24.4526C111.936 24.8587 112.683 25.0617 113.643 25.0617C114.437 25.0617 115.129 24.8956 115.72 24.5633C116.31 24.2126 116.763 23.7235 117.076 23.0959C117.409 22.4499 117.575 21.6931 117.575 20.8255H118.516C118.516 22.7083 118.092 24.2126 117.243 25.3386C116.393 26.4461 115.157 26.9999 113.532 26.9999ZM128.477 26.9999C127.13 26.9999 126.087 26.6491 125.349 25.9477C124.61 25.2463 124.241 24.2588 124.241 22.9851V8.50451H126.456V22.7636C126.456 23.4651 126.641 24.0096 127.01 24.3972C127.397 24.7664 127.933 24.951 128.616 24.951C128.837 24.951 129.049 24.9233 129.252 24.8679C129.474 24.7941 129.76 24.6279 130.111 24.3695L130.969 26.1692C130.489 26.483 130.055 26.6953 129.668 26.806C129.28 26.9352 128.883 26.9999 128.477 26.9999ZM121.832 14.7896V12.8238H130.609V14.7896H121.832ZM142.183 26.6676L142.072 24.3972V19.3581C142.072 18.269 141.952 17.3738 141.712 16.6724C141.472 15.9525 141.094 15.408 140.577 15.0388C140.06 14.6696 139.386 14.485 138.556 14.485C137.799 14.485 137.143 14.6419 136.59 14.9557C136.054 15.2511 135.611 15.731 135.261 16.3955L133.267 15.6202C133.618 14.9742 134.042 14.4204 134.541 13.959C135.039 13.4791 135.621 13.1191 136.285 12.8792C136.95 12.6207 137.706 12.4915 138.556 12.4915C139.848 12.4915 140.909 12.75 141.74 13.2668C142.589 13.7652 143.226 14.5127 143.65 15.5095C144.075 16.4878 144.278 17.706 144.259 19.1643L144.232 26.6676H142.183ZM138.029 26.9999C136.405 26.9999 135.132 26.6307 134.209 25.8923C133.304 25.1356 132.852 24.0927 132.852 22.7636C132.852 21.3608 133.313 20.2902 134.236 19.5519C135.178 18.7951 136.488 18.4167 138.168 18.4167H142.127V20.2718H138.666C137.374 20.2718 136.451 20.484 135.898 20.9086C135.362 21.3331 135.095 21.9422 135.095 22.736C135.095 23.4558 135.362 24.028 135.898 24.4526C136.433 24.8587 137.18 25.0617 138.14 25.0617C138.934 25.0617 139.626 24.8956 140.217 24.5633C140.807 24.2126 141.26 23.7235 141.573 23.0959C141.906 22.4499 142.072 21.6931 142.072 20.8255H143.013C143.013 22.7083 142.589 24.2126 141.74 25.3386C140.891 26.4461 139.654 26.9999 138.029 26.9999Z" fill="#ffffff"/>
        <path d="M146.357 28.6888V26.6676H157.432V28.6888H146.357Z" fill="#4FEAFF"/>
        <path d="M5.08739 7.94839L16.9844 2.21909L28.8814 7.94839L31.8197 20.822L23.5868 31.1459H10.3821L2.14907 20.822L5.08739 7.94839Z" stroke="#4FEAFF" stroke-width="1.78606"/>
        <path d="M7.16529 15.9562L12.0207 8.8345L20.616 8.19038L26.4787 14.5088L25.194 23.0319L17.7294 27.3416L9.70589 24.1926L7.16529 15.9562Z" stroke="#4FEAFF" stroke-width="1.78606"/>
        <path d="M13.3317 14.5225L16.9857 12.7628L20.6398 14.5225L21.5423 18.4765L19.0136 21.6474H14.9579L12.4292 18.4765L13.3317 14.5225Z" stroke="#4FEAFF" stroke-width="1.78606"/>
        <path d="M31.9318 30.2429C31.6471 30.2429 31.3754 30.1885 31.1166 30.0798C30.863 29.9711 30.6405 29.821 30.449 29.6295C30.2575 29.438 30.1074 29.2155 29.9987 28.9619C29.89 28.7031 29.8356 28.4314 29.8356 28.1467C29.8356 27.8517 29.89 27.5774 29.9987 27.3238C30.1074 27.0702 30.2575 26.8476 30.449 26.6561C30.6405 26.4646 30.863 26.3145 31.1166 26.2058C31.3754 26.0971 31.6471 26.0428 31.9318 26.0428C32.2268 26.0428 32.5011 26.0971 32.7547 26.2058C33.0084 26.3145 33.2309 26.4646 33.4224 26.6561C33.6139 26.8476 33.764 27.0702 33.8727 27.3238C33.9814 27.5774 34.0357 27.8517 34.0357 28.1467C34.0357 28.4314 33.9814 28.7031 33.8727 28.9619C33.764 29.2155 33.6139 29.438 33.4224 29.6295C33.2309 29.821 33.0084 29.9711 32.7547 30.0798C32.5011 30.1885 32.2268 30.2429 31.9318 30.2429ZM31.9318 29.8081C32.2579 29.8081 32.5451 29.7382 32.7936 29.5985C33.042 29.4587 33.2361 29.2647 33.3758 29.0162C33.5156 28.7626 33.5854 28.4728 33.5854 28.1467C33.5854 27.8155 33.5156 27.5256 33.3758 27.2772C33.2361 27.0287 33.042 26.8347 32.7936 26.6949C32.5451 26.55 32.2579 26.4775 31.9318 26.4775C31.6109 26.4775 31.3262 26.55 31.0778 26.6949C30.8294 26.8347 30.6353 27.0287 30.4955 27.2772C30.3558 27.5256 30.2859 27.8155 30.2859 28.1467C30.2859 28.4728 30.3558 28.7626 30.4955 29.0162C30.6353 29.2647 30.8294 29.4587 31.0778 29.5985C31.3262 29.7382 31.6109 29.8081 31.9318 29.8081ZM31.1477 29.2491V26.9822H31.9629C32.1958 26.9822 32.3873 27.0494 32.5374 27.184C32.6875 27.3134 32.7625 27.4868 32.7625 27.7042C32.7625 27.8491 32.7211 27.9785 32.6383 28.0924C32.5607 28.2062 32.4546 28.2916 32.32 28.3486L32.8557 29.2491H32.3976L31.9318 28.4262H31.5514V29.2491H31.1477ZM31.5514 28.0535H31.9784C32.0819 28.0535 32.1673 28.0225 32.2346 27.9604C32.307 27.8931 32.3433 27.8077 32.3433 27.7042C32.3433 27.5955 32.307 27.5101 32.2346 27.448C32.1621 27.3807 32.0664 27.3471 31.9473 27.3471H31.5514V28.0535Z" fill="#4FEAFF"/>
      </svg>
    </a>
    <span class="header-divider">|</span>
    <span><a href="https://github.com/revelata/deepkpi-agents" target="_blank" rel="noopener noreferrer">Analysis Pressure Test (GitHub)</a></span>
  </div>
  <h1>[Company] ([TICKER]): Pressure-Testing the [Firm] [Action]</h1>
  <p class="subtitle">
    [Firm] [Division] &mdash; "[Report Title]" &mdash; [Date] &mdash;
    Rating: [Old] &rarr; <strong>[New]</strong>
  </p>

  <div class="legend">
    <div class="legend-item">
      <div class="legend-dot" style="background:var(--amber)"></div>
      Analyst report data
    </div>
    <div class="legend-item">
      <div class="legend-dot" style="background:var(--cyan)"></div>
      Supplemental data from SEC filings (deepKPI)
    </div>
  </div>

  <!-- Price reaction context (fill these placeholders) -->
  <div class="pricebox">
    <div class="pricebox-title">Price since report</div>
    <div class="pricebox-body">
      Report date close: <strong>$[P_REPORT]</strong> &nbsp;·&nbsp;
      Most recent close: <strong>$[P_NOW]</strong> &nbsp;·&nbsp;
      Move: <strong>[DELTA_PCT]%</strong>
    </div>
    <div class="pricebox-note">
      If the report is &gt;3 weeks old, add 2–4 sentences on what moved and which SEC KPIs
      would have hinted at it. If &gt;3 months old, contrast data available then vs new filings since.
    </div>
  </div>
</div>

<!-- ===== ARGUMENT N ===== -->
<!-- Repeat this block for each argument (4-6 total) -->

<h2><span class="num">01</span> [Argument Title]</h2>

<div class="claim">
  <span class="src">[FIRM] says:</span>
  [1-2 sentence summary of the analyst's claim. Bold the key numbers.]
</div>

<!-- Optional: 1-2 chart cards if visual comparison helps -->
<div class="chart-card">
  <div class="chart-header">
    <span class="chart-title">[Chart Title]</span>
    <span class="chart-src">
      <span class="src-pill src-s">SEC</span> [Filing type]
    </span>
  </div>
  <canvas id="c[N]"></canvas>
</div>

<div class="evidence">
  <div class="ev-card ev-support">
    <div class="ev-label">
      <svg viewBox="0 0 16 16" fill="currentColor">
        <path d="M8 1a7 7 0 100 14A7 7 0 008 1zm1 10H7V7h2v4zm0-5H7V4h2v2z"/>
      </svg>
      Supports the thesis
    </div>
    <p>
      <span class="src-pill src-s">SEC</span>
      [Analysis with hyperlinked numbers:
       <span class="d d-s"><a href="provenance-url" target="_blank">$XXM</a></span>]
    </p>
  </div>
  <div class="ev-card ev-counter">
    <div class="ev-label">
      <svg viewBox="0 0 16 16" fill="currentColor">
        <path d="M8 1a7 7 0 100 14A7 7 0 008 1zm1 10H7V7h2v4zm0-5H7V4h2v2z"/>
      </svg>
      Complicates the thesis
    </div>
    <p>
      <span class="src-pill src-s">SEC</span>
      [Counter-analysis with hyperlinked numbers]
    </p>
    <p>
      <span class="src-pill src-r">[FIRM]</span>
      [Relevant point from the report itself that complicates the thesis]
    </p>
  </div>
</div>

<!-- ===== END OF ARGUMENT BLOCKS ===== -->

<!-- ===== SYNTHESIS ===== -->
<div class="synthesis">
  <h2>The Deeper Picture</h2>
  <p>[Paragraph 1: what the analyst gets right, with hyperlinked numbers]</p>
  <p>[Paragraph 2: what the analyst misses, the key risk/decision point]</p>
</div>

<!-- ===== FOOTER ===== -->
<div class="footer">
  Supplemental data sourced from SEC filings via
  <a href="https://www.revelata.com" target="_blank">Revelata deepKPI</a>.
</div>

<!-- ===== CLOSING CTA ===== -->
<!-- Plain on page background (no box). Keep this CTA minimal: link out to GitHub
     for installation and setup (do not embed shell commands here). -->
<div class="closing-cta">
  <p class="cta-setup-label">
    <a href="https://github.com/revelata/deepkpi-agents" target="_blank" rel="noopener noreferrer">Run this on any report with your agent:</a>
  </p>
  <p>
    Install and setup instructions (Claude connector + OpenClaw) live on GitHub:
    <a href="https://github.com/revelata/deepkpi-agents" target="_blank" rel="noopener noreferrer">deepkpi-agents</a>.
  </p>
</div>

<!-- ===== DISCLOSURES ===== -->
<div class="disclosures">
  <p><strong>Compensation Disclosure:</strong> No part of the compensation of any Revelata personnel was, is, or will be directly or indirectly related to the specific views, conclusions, or recommendations expressed in this report, or to the coverage of any particular security or issuer herein.</p>

  <p><strong>Third-Party Content Disclosure:</strong> This report references and comments on research produced by a third-party analyst and their affiliated institution. Any such references are made for purposes of analysis and commentary only. The referenced analyst and their institution have not reviewed, approved, sponsored, or endorsed this report, Revelata, or any of Revelata's products, services, views, or conclusions, and no such endorsement or affiliation should be inferred. All commentary, opinions, and conclusions added by Revelata are solely those of Revelata and do not represent the views of the referenced analyst or their institution.</p>

  <p><strong>General Disclosure:</strong> The information contained in this equity research report is provided for informational purposes only and is not intended to constitute financial advice or a recommendation to buy, sell, or hold any securities. The opinions expressed herein are as of the date of publication and are subject to change without notice. This report does not take into account the investment objectives, financial situation, or specific needs of any individual investor.</p>

  <p>We are not a licensed financial advisor, broker, or dealer, and this report is not intended to provide investment, legal, accounting, or tax advice. Any reliance on the information contained in this report is at the sole discretion and risk of the user.</p>
</div>

<!-- ===== CHARTS ===== -->
<script>
// Chart.js global defaults for dark theme
Chart.defaults.color = '#8b949e';
Chart.defaults.borderColor = '#2a313a';
Chart.defaults.font.family = "'Inter', system-ui, sans-serif";
Chart.defaults.font.size = 11;

// Blue/cyan palette — ALL SEC data charts use only these colors
const B1 = '#4FEAFF';  // cyan — primary
const B2 = '#90caf9';  // light blue — secondary
const B3 = '#5b8def';  // mid blue — tertiary
const B4 = '#a78bfa';  // periwinkle — quaternary
const grid = { color: 'rgba(255,255,255,0.05)' };

// [Insert chart constructors here — see chart-patterns.md for examples]
</script>
</body>
</html>
```

## Key rules

1. **Never change the CSS custom properties** — they are the brand identity
2. **Logo is inlined as SVG in the header** — no external file reference. Links to `https://www.revelata.com/for-ai-builders`.
3. **Header divider is a vertical pipe** (`|`) styled in `--border-light` at 1.5rem — sits between the wordmark and the "Analysis Pressure Test (GitHub)" label.
4. **Closing CTA is minimal** — do not embed install commands in the HTML. Link to the GitHub repo for setup.



path: analyst-report-pressure-test/evals/evals.json
content: {
  "skill_name": "analyst-report-pressure-test",
  "evals": [
    {
      "id": 1,
      "prompt": "Pressure test this. [attaches sell-side downgrade report PDF for consumer staples issuer]",
      "expected_output": "An interactive HTML report with 5 argument sections, Chart.js charts, amber/cyan source attribution, provenance hyperlinks to deepKPI URLs, and a 2-paragraph synthesis. Should identify the issuer CIK, use fiscal quarters ending Jun 30, and pull segment-level data before consolidated.",
      "files": ["/sessions/[REDACTED]/mnt/uploads/[REDACTED]-sell-side-downgrade-report.pdf"],
      "assertions": []
    },
    {
      "id": 2,
      "prompt": "I uploaded a sell-side note on a major restaurant chain. Can you critically analyze the key arguments and pull actual SEC data to support or challenge them?",
      "expected_output": "Should recognize this as a pressure-test request even without the exact phrase. Should resolve the chain's CIK, pull restaurant-level KPIs (store count, comparable sales, AUV), segment data, and produce the standard HTML report with Revelata branding.",
      "files": [],
      "assertions": []
    },
    {
      "id": 3,
      "prompt": "Pressure test this report on a social/tech platform company. [attaches analyst report PDF]",
      "expected_output": "Should resolve the company's CIK, recognize the tech/social media context, pull ARPU, DAU, revenue by geography, and ad-related KPIs. HTML report with appropriate charts for user growth and monetization trends.",
      "files": [],
      "assertions": []
    }
  ]
}



path: retrieve-kpi-data/retrieve-kpi-data.md
content: ---
name: retrieve-kpi-data
description: >
  Retrieves financial and operational KPIs for a US public company from Revelata's
  deepKPI database. Use for historical metrics from SEC filings — revenue by segment,
  unit-level KPIs (paying users, store counts, same-store sales, ASP, ARPU,
  deliveries), income statement, balance sheet, or cash flow data. Triggers include
  "pull data for", "get historicals for", "find the KPI", "what does deepKPI have
  on", or modeling tasks that need structured time series. For verbatim filing text,
  MD&A quotes, full filing markdown, or "what did they say", use retrieve-sec-filing.
  For what a company does, segment/geography breakdowns, or thematic “who does X?”
  lists, use company-summary-segments instead.
  Always use before analyzing or projecting on KPIs. After in-chat KPI tables, end
  with a bold Excel offer unless the user asked for a file or declined. For .xlsx,
  follow format-deepkpi-for-excel.
---

# retrieve-kpi-data

**The sole data source for all historical financial and operational metrics is
deepKPI.** Do not use LLM's training knowledge, analyst reports, or any other
source for specific financial figures. Every number in the output must trace back
to a deepKPI call.

**SEC filing language (quotes, MD&A, full filing markdown):** use
**`retrieve-sec-filing/retrieve-sec-filing.md`** — not this doc.

**Business description, segment/geo structure, thematic company discovery:** use
**`company-summary-segments/company-summary-segments.md`** (`get_company_summary`,
`get_company_segments`, `company_summary_search`) — not this doc.

## Data source (deepKPI)

| Context | How |
|---------|-----|
| **Claude (preferred)** | MCP tools — `query_company_id` · `list_kpis` · `search_kpis` |
| **OpenClaw** | Read `deepkpi-api/deepkpi-api.md` and call the REST endpoints using `$DEEPKPI_API_KEY` |
| **Env fallback** (`DEEPKPI_API_KEY` set) | `POST https://deepkpi-api.revelata.com/v1.0/...` — see `deepkpi-api.md`. Same API also exposes filing markdown (**`retrieve-sec-filing`**) and summary/segment tools (**`company-summary-segments`**). Headers: `Content-Type: application/json`, `X-[REDACTED_SECRET]` |

If none of the above applies, say so and ask the user how to proceed.

## Hard stop if deepKPI access fails

If the MCP connector or REST API calls fail (auth/network/credits/service errors) and you cannot access deepKPI, STOP and ask the user whether they want to proceed **without deepKPI**.

- If the user says **no**: stop.
- If the user says **yes**: continue, but DO NOT use any deepKPI skill branding, formatting conventions, or “Powered by Revelata” framing for data sourced elsewhere (web, third-party APIs, general knowledge). Clearly label the alternate sources.

## Opening line

Before doing anything else, say:

**"Let me pull the KPI data using deepKPI."**

## Granularity principle — always go deep first

deepKPI's value is in the detail. Users asking broad questions ("how is the
company doing?", "analyze their revenue") are used to top-line summaries from
Bloomberg or news articles. Surprise them by going granular first.

**Default search order:**
1. **Unit-level KPIs first** — store counts, same-store/comparable sales, ASP,
   ARPU, deliveries, paying users, occupancy, RevPAR, etc.
2. **Segment or geography breakdowns** — revenue by business unit, brand,
   region, or channel before consolidated totals
3. **Margin and cost structure detail** — food costs as % of revenue, labor,
   four-wall EBITDA, restaurant-level margins before blended operating margin
4. **Consolidated / top-line metrics last** — only after the above; use as
   context or cross-check, not as the primary answer

If granular data exists for a metric, never lead with the consolidated version.
Only fall back to top-line when the detailed series is genuinely absent from
deepKPI. Note when you've done this.

This applies to both data pulls and analysis. When writing analysis, build
the narrative from the unit economics up — don't start with "revenue grew X%"
when you have store count, traffic, and ticket data to explain why.

## Recency principle — never settle for avoidably stale data

If deepKPI has quarterly coverage (10‑Q-derived periods) that is more recent than the
last annual 10‑K figure for the same KPI, **use the quarterly data** when the user’s
question is about “current”, “latest”, “recent”, or near-term dynamics.

- Do **not** write (or imply) “our data is a little old” if a more recent 10‑Q period
  exists for the KPI in question.
- Use annual (10‑K) series for **long-cycle** context, not as an excuse to stop early
  on recency.
- If quarterly data is genuinely unavailable for a KPI, say so plainly and use the
  freshest available period; do not shrug or hand-wave.

## Retrieval workflow

### 1. Resolve company ID

Call `query_company_id` with the official registrant name (not a brand or
subsidiary). Map common brands first:
- "Chipotle" → "Chipotle Mexican Grill" · "Snapchat" → "Snap Inc."
- "Olive Garden" → "Darden Restaurants" · "CarMax Auto Finance" → "CarMax Inc."

The returned `company_id` is the SEC CIK. Required for all subsequent calls.

### 2. Discover available KPIs — always do this first, it's free

Call `list_kpis` before any `search_kpis` call. It returns every KPI name
organized by category: Company KPIs, Segment Financials, Income Statement,
Balance Sheet, Cash Flow, Capital Structure.

When you would like to retrieve a specific KPI, use the exact name strings from 
this list as `search_kpis` queries with number of results equal to 1 — this
avoids wasted credits and ambiguous matches. 

Never skip this step.

### 3. Search for specific KPIs

Call `search_kpis`. Each result costs 1 credit — start with `num_of_res: 3`,
increase only if needed. 

Effective query patterns:
- Be specific: `"average revenue per paying user"` not `"ARPU"`
- Include segment context: `"Chipotle domestic restaurant comparable sales increase"`
- Include cost language: `"food beverage and packaging costs as percentage"`
- Geographic splits: `"Net Sales by Geography Americas Europe Greater China"`

A typical request needs 2–4 separate searches.

### 4. Handle gaps

**Whenever quarterly granularity is requested, always attempt to derive Q4 for
flow metrics before presenting incomplete data.** Do not surface a partial series
(Q1–Q3 only) without first checking whether FY is available and computing
`Q4 = FY − (Q1+Q2+Q3)`. Only leave Q4 blank if the annual figure is also absent.

| Gap | Handling |
|---|---|
| Q4 missing, have Q1–Q3 + FY | Derive: Q4 = FY − (Q1+Q2+Q3). Read `derive-implied-metric/derive-implied-metric.md`. |
| Annual missing, have quarters | Sum four quarters (flow items only). |
| Segment missing, have total + others | Derive: missing = total − sum(known). |
| Balance sheet Q4 missing | Use FY year-end value — stocks are snapshots, not flows. |
| Metric absent entirely | Note the gap; for narrative context from filings, follow **`retrieve-sec-filing/retrieve-sec-filing.md`** (`list_sec_filing_markdowns` + `get_sec_filing_markdown`). |

Flag clearly when a value is derived or manually sourced from filings.


## Provenance — non-negotiable rules

deepKPI returns a provenance URL for every data point linking to the exact SEC
filing passage it was extracted from. These URLs are the audit trail.

- **Every number in the output must have a clickable hyperlink** to its deepKPI
  provenance URL. No exceptions.
- Copy URLs **exactly as returned** from the API. Never reconstruct, shorten, or
  guess a URL. If uncertain, omit and cite filing type + period instead. 
- Format: embed the link directly in the cell value — `[$248.0M](exact-url)` or
  `[2,410 stores](exact-url)`. The value and its source are one clickable unit.
- Group multiple values from the same filing by linking each to the same URL.
- Never present a number without at least its provenance URL. 
- If a value is derived, provide the provenance of its operands.

## After the pulls are complete

Once all deepKPI calls have returned, follow the branch that matches what the user
asked for. If they asked for more than one (e.g. analysis **and** a CSV), satisfy
every constraint that applies.

**Hard requirement — in-chat data pull:** If your reply includes **data-pull
tables** (KPI numbers for the user) and the user **did not** ask for Excel/CSV in
that same message, you **must not** end your response until you have asked the
**bold** Excel question in **Mandatory: Excel offer after in-chat data pull**
below. Treat this as part of the deliverable, not optional follow-up.

### Analysis

When the user wants **analysis**, **interpretation**, **trends**, **commentary**,
or **what it means** — structure the response from the ground up: unit economics
and segment detail first, consolidated metrics as context. A response that leads
with "revenue grew 12%" when you have same-store sales, ticket size, and traffic
data is a missed opportunity — pull the thread from the most granular level
available and build toward the headline number, not the reverse.

**Still enforce Provenance:** every **numeric figure** must include its deepKPI
provenance using `[value](exact-url)` (and for derived numbers, link operands or
state sources as already required). No bare numbers.

### Data pull (in-chat: read top to bottom)

When the user wants **data**, **historicals**, **pull KPIs**, or a **modeling
feed** but has **not** (yet) asked for CSV or an Excel file:

- **Tall layout in chat** — optimize for **reading in the thread**. Use tables where
  **each row is one period** (time reads **down**). **Do not** lay out **dates as
  many columns** in chat — that wide date-axis layout is for **.xlsx** only (see
  **`format-deepkpi-for-excel`**).
- **Same periods → one table, metrics as columns:** When multiple metrics **share the
  same period set** (same granularity — e.g. all quarterly with identical quarter
  labels, or all annual with identical FY labels), **combine them into a single
  table**: first column **Period**, then **one column per metric** (clear header per
  column, each cell `[value](url)`). Do **not** split into separate one-column tables
  when the periods line up. Use **separate tables** only when period axes **differ**
  (annual vs quarterly, misaligned dates, or incompatible units need their own block).
- **Order:** Show **all annual figures first**, in **chronological order** (oldest
  at the **top**), then a **clear break** (e.g. horizontal rule, blank line, or a
  **Quarterly** subheading), then **all quarterlies** (oldest first). Do not
  interleave annual and quarterly rows without a visual separation.
- **Consolidate or split by KPI identity:** If deepKPI returns multiple series that
  are the **same KPI** (same metric, **same unit**, **same aggregation period**),
  **merge into one vertical series** (one row per date, value in the value column).
  If they **differ** (e.g. quarterly vs annual, or different units), use **separate
  blocks** or **separate labeled tables** — **one block per distinct deepKPI time
  series** when they are not the same KPI.
- **Derived / imputed metrics:** When you **fill a missing point** in an existing
  series (e.g. Q4 from FY − Q1−Q2−Q3), put the value **in that series’ row** in the
  correct period column—**not** a separate “Q4 (derived)” line item. **Bold** or
  annotate in-cell / **Notes** where helpful. **Distinct** derived KPIs (different
  line item, e.g. YoY %) may still use their **own** row or column.
- **Provenance:** `[value](exact-url)` per **Provenance — non-negotiable rules**.
- **Prose:** optional short intro; do not bury the data in long narrative unless the
  user asked for analysis.

For layout examples, see **In-chat table template (data pull)** below.

### Mandatory: Excel offer after in-chat data pull

**You must do this** whenever you showed KPI **data-pull** tables and the user did
**not** already request a file (CSV / spreadsheet / Excel / `.xlsx`) in the same turn.

1. Deliver the in-chat tables first.
2. Then, in the **same assistant response**, add a **final** paragraph whose **main
   question is entirely wrapped in Markdown bold** (`**...**`), asking whether the
   user wants an **Excel workbook (.xlsx)** built for modeling (**periods as
   columns:** annual block, blank separator, quarterly block — skill
   **`format-deepkpi-for-excel`**). Example (paraphrase allowed; **bold** is not optional):

   **Would you like me to build an Excel workbook (.xlsx) laid out for modeling — periods across columns (annuals, then a blank column, then quarterlies) per our export spec (`format-deepkpi-for-excel`)?**

3. Do **not** skip this step because the answer feels complete without it. Do **not**
   bury it mid-message; put it **after** the tables so it is visible.
4. If they **decline**, stop; if they **accept**, build the file per
   **`format-deepkpi-for-excel`**.
5. **Skip** this block only if: they already asked for a file export in that turn,
   or you did **analysis-only** with **no** data tables, or they explicitly said they
   do not want Excel.

### CSV or spreadsheet output

When the user asks for **CSV**, **spreadsheet**, **Excel**, **.xlsx**, agrees to
the **post-pull .xlsx offer**, or downloadable tabular output for a model — read
`format-deepkpi-for-excel/format-deepkpi-for-excel.md` and follow it in full
(plus the **xlsx** skill for implementation).

---

## In-chat table template (data pull)

Structure (read **down** the page; **time is rows**, not columns):

- **Annual block first** — one table: **Period |** then one column per metric if
  several annual series share FY labels; otherwise `Period | Value`. Oldest period
  at the **top**.
- **Break** — then **Quarterly** table(s): if quarterlies **align** on the same
  periods, use **one table** with **Period | Metric A | Metric B | …**. Otherwise
  split by mismatched axes.
- **Merge vs split (KPI identity)** — unchanged: merge values that are the same KPI;
  separate rows when metric/unit/aggregation differs.
- **Derivations / imputation** — gap-fills (imputed Q4, etc.) live **inside** the
  same row as the parent series for that period; **do not** add an extra line item
  for the imputed point. Other derived KPIs get their own row/column when they are
  genuinely separate metrics. **Note** imputation in Notes or inline where needed.

**.xlsx is different:** file export uses **periods as columns** (annual block |
blank | quarterlies) — see **`format-deepkpi-for-excel`**.

```
## [Metric group] ([Ticker])
Units: $M unless noted (store count = stores)

### Annual
| Period | Revenue (annual) | … |
|--------|------------------|---|
| FY2022 | [$1,196.8](url)  | … |
| FY2023 | [$1,383.6](url)  | … |

### Quarterly — aligned metrics (one table)
| Period  | Revenue            | Store count |
|---------|--------------------|-------------|
| FY22-Q1 | [$248.0](url)      | [2,410](url) |
| FY22-Q2 | [$300.9](url)      | [2,445](url) |
| FY22-Q3 | [$292.2](url)      | [2,489](url) |
| FY22-Q4 | **[$355.7](url)** (imputed in this row: FY−Q1−Q2−Q3; link operands) | [2,521](url) |
| FY23-Q1 | [$267.1](url)      | [2,563](url) |
```

## Excel workbook (`.xlsx`)

For any **CSV / spreadsheet / Excel** deliverable from deepKPI, read
`format-deepkpi-for-excel/format-deepkpi-for-excel.md` and apply it end-to-end
(layout, styling, hyperlinks, dates, freeze panes, column grouping, checklist,
CSV notes). Use the **xlsx** skill to implement it. Do not duplicate those rules here.

## Common failure modes

- **Dates as many columns in chat** on a plain data pull: keep **periods as rows**;
  you may use **one column per metric** when periods align. Reserve **dates as
  columns** (wide date axis) for **.xlsx** only.
- **Splitting aligned metrics** into duplicate single-metric tables: if periods
  match, **combine into one table** with a column per metric.
- **Skipping list_kpis**: it's free and consistently guides better, cheaper searches.
- **Querying too broadly**: "revenue" returns weak matches; use segment-specific terms.
- **Leading with top-line when granular data exists**: always check for unit-level and segment KPIs first; only use consolidated totals when detail is unavailable. Showing same-store sales + traffic + ticket is more valuable than consolidated revenue alone.
- **Apologizing for stale 10‑K data when a newer 10‑Q exists**: if the KPI has a more
  recent quarterly period available, use it. Reserve annual-only caveats for cases
  where quarterlies truly aren’t present in deepKPI.
- **Mixing period types silently**: always label each value as annual or quarterly.
- **Balance sheet items as flows**: receivables at Dec 31 IS Q4 — don't subtract.
- **Hallucinating a URL**: if you don't have the exact URL, say so; never construct one.
- **Plain-text URLs in tables**: always format as `[label](url)` — clickability is required.
- **Extra Source rows in .xlsx**: filing identity belongs in the **cell hyperlink**
  only; do not add redundant source listing rows.
- **Omitting the post-pull Excel question** after showing KPI tables: the **bold**
  offer is **mandatory** unless the user already asked for a file or refused Excel.
- **Verbatim filing text / “what did they say”**: wrong skill — use
  **`retrieve-sec-filing`** instead of improvising from KPI pulls.
- **“What do they do?” / segment breakdowns / “who operates in X?”**: wrong skill —
  use **`company-summary-segments`** instead of `search_kpis` alone. (Target-based
  “most similar” benchmarking: future skill — not `company_summary_search` as a substitute.)

path: format-deepkpi-for-excel/format-deepkpi-for-excel.md
content: ---
name: format-deepkpi-for-excel
description: >
  Canonical Excel (.xlsx) layout and styling for deepKPI financial exports: 
  wide layout, annual then quarterly columns, Calibri, pale-green fill on deepKPI input cells, dark-blue hyperlinked numbers,
  numeric date headers, time series values as Excel numbers (not text), freeze panes,
  column grouping, no redundant Source rows;
  same metric at quarterly and annual frequency (same definition/unit) on one row
  across period columns, not two rows; derived cells must be live formulas, never
  hardcoded computed values.
  Use whenever building a spreadsheet from deepKPI data — after any tool such as
  retrieve-kpi-data, analyze-seasonality, derive-implied-metric that sources data
  from deepKPI. Pair with the xlsx skill for implementation. 
---
# format-deepkpi-for-excel

**In-chat** KPI tables stay **tall** (periods as rows). **Excel** workbooks are
**wide** (periods across columns) for modeling. This skill is the **single source of
truth** for deepKPI `.xlsx` structure and visuals.

Always invoke the **xlsx skill** for spreadsheet output — it governs formula
discipline, tooling, and general conventions. The sections below add **financial /
deepKPI-specific** requirements on top.

## DeepKPI Excel export spec

Use whenever the user wants a **file** (or accepted a post-pull `.xlsx` or `.csv` 
offer).

### Sheet defaults (apply to the whole workbook)

- **Font:** **Calibri** for the sheet. **Hyperlinked value cells** (provenance links)
  use **dark blue** font (`#0563C1` / `FF0563C1`) and the **number format** in
  **Hyperlinks** below so they read like real links — see that section. Other body
  (non-linked) styling follows **Color conventions**.
- **Gridlines:** **Off** — the worksheet should present with **no visible cell
  grid** (Excel: gridlines hidden for the sheet).
- **Empty data cells** (no value for that period): show a **dash** (`-` or
  accounting-style em dash), not a blank cell — consistent for the data region
  (period columns from Col E onward, and any comparable body area).

### Time series values — store as numbers (not text)

- Any **numeric** value written from deepKPI **time series** (reported actuals,
  imputed amounts, ratios, rates, and other quantitative points) must be stored as
  **Excel number values** (numeric cell type), **not** as text — so sorting, charts,
  `SUM`, and arithmetic work without coercion.
- **Do not** write series values as strings that only *look* like numbers (e.g.
  quote-prefixed cells, padded text, or literals like `"1,234.5"` as the stored
  value). Use a **real numeric** `cell.value` (or equivalent) and apply **number
  format** (currency, percent, thousands, decimals) for display.
- **Percent / basis points:** store the **numeric** magnitude the sheet should use
  (per your convention, e.g. decimal fraction for percent format), still as a
  number — not a text label such as `"15%"` unless the underlying source is
  genuinely non-numeric.
- **Hyperlinked value cells:** the **cell value** remains numeric when the metric is
  numeric; the provenance hyperlink is layered on the cell — do not replace the
  number with a text-only representation. Display them with **dark blue** font and
  the **hyperlink number format** in **Hyperlinks** (percent-style for rates; for
  counts/currency use the sheet accounting format **with the same dark blue**).

### Title cell **C1** (not A1)

Columns **A** and **B** are **hidden** (audit trail). A title in **A1** would not
**show** — put the workbook title in **C1** (first visible column). Leave **A1:B1**
empty.

- **C1** is a short **title / description** of the workbook: **bold**, **font
  size 12**, **Calibri**, **normal sentence case** (not ALL CAPS). Include the
  **full official company name** as registered (e.g. from `query_company_id` /
  SEC registrant), plus what the sheet contains (e.g. historical KPIs / deepKPI
  extract). Example shape: `Chipotle Mexican Grill, Inc. — quarterly and annual
  KPI historicals (deepKPI)`. For long titles, merge **C1** rightward across the
  label area (e.g. **C1:D1**) or as needed; do not place the title in hidden
  columns.
- **Row 2 must be empty** — leave the **entire row blank** (no titles, no merged
  filler). This separates the **C1** title from the data block.
- **Row 3** is the first row used for **period headers** (dates in Col E onward) and
  any ALL CAPS section labels that sit on the same row as those headers if your
  layout uses that pattern; **row 4** is the **first** KPI **data** row unless your
  template needs an extra header row (if so, keep **one** blank row still **only**
  between the title row and where dates begin).

### Period column headers (store dates as numbers)

- Do **not** type period labels as plain text in header cells. **Store real Excel
  date serials** in the **date header row** (**row 3** in the default layout: **C1**
  title → blank row 2 → **headers row 3**), in Col E onward, then apply **number format**:
  - **Quarterly columns:** `mmm-yy` (displays **Mar-22**, **Dec-23**, etc.).
  - **Annual columns:** use a consistent year-end (or fiscal year-end) **date
    value** in the cell and format as **`yyyy`** (or equivalent) so it reads clearly;
    do not use text like `FY2022` unless it is still a formatted date number.
- That same header row remains **bold** and **underlined** (font), per layout rules.

### Freeze panes

- Set **freeze panes** so when the user scrolls:
  - The **period header row** (date labels in Col E onward) **stays visible** below
    the title and blank spacer; and
  - **Columns A through D** **stay visible** horizontally.
- **Default row layout:** Row **1** = **C1** title (leave **A1:B1** empty) · Row **2** =
  empty · Row **3** = period headers · Row **4** = first data row → set freeze to
  **`E4`** (top-left of the scrollable grid: first data cell under the date headers,
  right of Col D).
- If you add rows above the date header for extra titles only, still keep **exactly
  one fully blank row** between the last title row and the date header row, then
  freeze at the cell **under** the header row and **right of** column D.

### Layout — revenue build model convention

Format all output spreadsheets as a **revenue build model**:

- **One row per KPI or distinct time series** — use **one row with many
  date columns** when multiple deepKPI series are the **same KPI** (same metric
  definition and **same unit**). **Quarterly and annual variants of the same
  metric** (e.g. `Sales - Olive Garden - 3 Month` and `Sales - Olive Garden -
  Annual`) belong on the **same row**: put **annual** values under the **annual
  column block** and **quarterly** values under the **quarterly** block — **do
  not** put them on two separate rows. Only **split into separate rows** when the
  series truly differ (different definition, unit, segment, or a different metric
  — not merely a different aggregation period). Do not fragment one series into
  "Revenue - Q1" / "Revenue - Q2" rows. **Each value lands in the column that
  matches its reporting period;** Col A may list multiple deepKPI source strings
  if you merged quarterly + annual into one row (or keep one canonical display
  label in Col C).
- **Imputation / gap-fill (same series row):** When you **impute** a missing point
  in an existing stream (e.g. **Q4 = FY − Q1 − Q2 − Q3** because there is no Q4
  10-Q), put the value **only** in **that series’ row**, in the **missing period
  column(s)**—as a **live `=` formula** (black font, no green input styling). **Do
  not** add a separate line item such as “Q4 (derived)”, “Q4 Revenue”, or “Imputed
  Q4” beneath the quarterly row. **Especially in Excel**, the quarterly KPI stays
  **one row**; Q4 cells reference FY and Q1–Q3. **Annual figures for that same
  metric** (same definition and unit, only FY vs quarterly frequency) sit on **this
  same row** in the annual columns — not on a second row. Document imputation in
  **Notes** or an agreed footnote row, not as an extra KPI row.
- **Distinct derived KPIs** (YoY %, margins, segment remainder **as its own metric**,
  build subtotals): **operand** rows above where needed; the **derived KPI** gets
  its **own** row—because it is a **different** line item, not a hole in one stream.
  Those cells are still **live formulas** (see **Derived values — formulas only**).
- **Time periods flow left to right** within each block. Row labels in column A.
- **Three-column label system**:
  - Col A (hidden): deepKPI metric name string — serves as audit trail
  - Col B: Display label (what users see)
  - Col C: Units tag, italic (e.g., `(in thousands)`)
  - Col D onward: time-period data values
- **KPI names (Col C — display labels) — one pattern for the whole sheet:** Before
  filling rows, choose a **single** convention for how **metric + qualifier /
  segment** reads. **Prefer** separating the qualifier with an **em dash or hyphen**
  (`Revenue — Americas`, `Dues - Black Card`) — **avoid** parenthetical modifiers
  (`Metric (segment)`) when a dash-separated label reads naturally. Apply the
  pattern **everywhere** — do not mix styles for parallel constructs (e.g. not
  *Black Card Penetration* on one row and *Dues — Black Card* on another).
- **Abbreviations in Col C:** Prefer **full words**; use abbreviations **sparingly**
  and only when they are **standard in the industry** (e.g. **ARPU**, **ASP**,
  **EPS**). **Do not** use opaque or company-specific codes (e.g. **BOC**, internal
  segment codes) unless the user explicitly asked for that exact label. If a KPI 
  has a specific abbreviation already baked in that you don't recognize, e.g. CCHBC
  then use it as it appears.
- Col A may still hold the raw deepKPI string; Col C should read as a **consistent
  series of human-readable labels**.
- **Annual and quarterly column blocks:** **Annual columns first** (FY2017,
  FY2018 … or 4-digit year labels), left → right, oldest first. Then **one blank
  column**. Then **quarterly columns** (Mar-22, Jun-22, Sep-22, Dec-22 …), left →
  right, oldest first. Do **not** put quarterlies before annuals.
- **Column outline / grouping (expand–collapse):** Create **two** separate Excel
  **column groups** (outline) so the user can **collapse or expand** the **annual**
  block vs the **quarterly** block: (1) group **only** the contiguous **annual**
  period columns (including the date header row for those columns); (2) group
  **only** the contiguous **quarterly** period columns. Leave the **blank separator
  column ungrouped** (between the two groups). Columns **A–D** are **not** grouped.
  Match Excel **Data → Group** behavior (or your library’s equivalent), e.g.
  openpyxl: set `outlineLevel = 1` on each `column_dimensions` entry spanning the
  annual columns, then again for the quarterly span (**sibling** groups, not one
  nested group). Leave groups **expanded** by default so numbers are visible unless
  the xlsx skill says otherwise.
- **Date header row** (Col E onward): **numeric Excel dates** with display formats
  above (**Mar-22** style for quarterlies); **Bold** and **underlined** font.
  (Calibri.)
- **ALL CAPS section header rows** (e.g. `REVENUE BUILD`): **Bold** and **font
  underlined** (underline the text in Col C for that row; background unchanged
  unless the xlsx skill says otherwise).
- **Color conventions** (Revelata KPI inputs — overriding generic xlsx fill rules
  for this file type):
  - **deepKPI-sourced input values** (“hardcoded” from API): **fill / background**
    **`#E2EFDA`** (Excel ARGB `FFE2EFDA`). **Font color:** use **`#0563C1`**
    (`FF0563C1`) — **dark blue** — on cells that have an **Excel hyperlink** to
    provenance (so links look like links). Use **`#00B050`** (`FF00B050`) only for
    **non-hyperlinked** sourced numerics if any (rare); default is **dark blue** on
    all linked value cells.
  - **Derived / calculated formula cells**: **Black** font (default or explicit); no
    green tint unless the xlsx skill differs.
  - **Col A source-label text**: **Blue** `#0070C0` (`FF0070C0`) where still specified below.
  - **Red** `#FF0000` (`FFFF0000`): estimated or external values (use sparingly)
- **% change rows**: italic label + italic data, formatted as accounting-style %:
  `_(* #,##0.0%_);_(* \(#,##0.0%\);_(* "-"?_);_(@_)`
- **Number format** for all data values (accounting with dash for zero):
  `_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)`
- **Subtotals**: bold; last item before total gets a thin bottom border.
- **Grand totals**: bold, double top border.
- **Sub-items**: indent label in Col C with two leading spaces.

```
Col A (hidden)            | Col B | Col C                  | Col D          | FY2022       | FY2023       |   | Mar-22       | Jun-22       | Sep-22       | Dec-22       | … |
--------------------------|-------|------------------------|----------------|--------------|--------------|---|--------------|--------------|--------------|--------------|---|
                          |       | REVENUE BUILD          |                |              |              |   |              |              |              |              |   |  ← ALL CAPS bold + underlined
revenue; qtr+FY ($)       |  33   | Revenue                | (in thousands) | [1,196,826] inp| [1,383,600] inp|   | [248,017] inp| [300,941] inp| [292,246] inp| [355,622] drv| … | ← one row: FY block + quarterly block; Q4 imputed = FY−Q1−Q2−Q3 in Dec column, black—not a separate “Q4” row; not a second “annual only” row
                          |  34   |   % YoY                |                |   +15.6%     |   +12.5%     |   |     n/a      |   +21.1%     |   +15.2%     |              | … | ← italic; distinct KPI → own row OK
```

*(Legend: **row 2 blank** between **C1** title and headers; date header row —
**numeric** dates, bold + underlined; empty inputs — `-`; **C1** = bold 12pt title
with full company name; **A1:B1** empty.)*

### Derived values — formulas only

**Every derived cell** must be a live Excel **`=`
formula** referencing inputs. **Imputed quarters** (e.g. Q4 = FY − Q1 − Q2 − Q3) live
in the **same row** as that quarterly series, in the gap column—**not** on a
separate “Q4 derived” row. **Annual and quarterly pulls of the same metric** stay on
that **same row** (annual columns vs quarterly columns), not a second row for “Annual”
only. **Distinct** derived KPIs (YoY %, ratios, remainder
lines, projections) use **their own** rows because they are different series.

**Never** type, paste, or “hardcode” the computed number into a derived cell — even if
it matches what you calculated in chat or in your head. The workbook must
**recalculate** when inputs change; a static numeric literal in a derived cell is a
failure. Only **deepKPI-sourced inputs** (values taken straight from the API) may be
literal values in cells (still with hyperlinks per this skill).

### Hyperlinks — provenance only (no extra Source rows)

Every deepKPI value must carry an **actual Excel hyperlink** on the **value cell** —
that is the filing reference. **Do not** add separate **Source** rows, **Source**
columns, or other redundant blocks that only restate the filing name; the link is
sufficient.

- **Display:** Use the **metric value** (or short label) as the link text, not
  “10-K FY2024” unless that is the value shown.
- **Style (linked value cells):** **Font color** **dark blue** **`#0563C1`**
  (Excel ARGB `FF0563C1`). **Do not** rely on underline to signal links — Excel’s
  per-character underline on hyperlinked numbers is unreliable across clients and
  libraries.
- **Number format** on **hyperlinked** numeric cells (rates / percents / ratios stored
  as decimal fractions, e.g. `0.105` → 10.5%):

  `_(#,##0.0%_);_((#,##0.0%);_(-_);_(@_)`

  For **counts, currency, or other non-percent** linked values, keep the sheet’s
  standard accounting format from **Number format** above (`_(* #,##0_);_(* \(#,##0\);…`)
  but **still** apply **dark blue** (`FF0563C1`) on the font so the cell reads as a
  link.
- **Calibri** on link cells.

Use `cell.hyperlink` + numeric `cell.value`, or `=HYPERLINK("url", …)` with a numeric
cell — apply **font color** and **number format** on the cell as above (not default
hyperlink styling).

Never store a provenance URL as **plain text only** in the data grid.

**CSV:** Cannot store hyperlinks. Add a `provenance_url` column with raw URL
strings, and warn the user that links are not clickable — recommend .xlsx.

### Pre-delivery checklist (Excel output)

Before presenting the file link, verify every item. Do not deliver the file until all boxes pass.

- [ ] No spurious row fragmentation (no "metric - Q1" rows); merged same-KPI
      series = one row; **quarterly + annual for the same metric (same definition /
      unit)** = **one row** (annual block + quarterly block), not two rows; **imputed
      Q4 (etc.) in that row’s column**, not a separate “Q4 derived” line item;
      distinct KPIs = separate rows
- [ ] **Annual columns are the left block**, blank separator, **quarterly columns
      on the right** — not the reverse
- [ ] **Column groups** defined: **annual** block and **quarterly** block each
      collapsible via outline (separator + cols A–D **outside** groups)
- [ ] **Calibri** as the workbook body font
- [ ] **Gridlines hidden** (no visible cell grid on the sheet)
- [ ] **C1** (not A1): **bold**, **12pt**, sentence case, **full official company name** +
      data description; **A1:B1** empty (hidden columns)
- [ ] **Row 2** entirely **blank** between title and date headers
- [ ] **Date headers**: **Excel date serials** in cells, formatted **`mmm-yy`**
      (etc.), **not** typed text — **bold** + **underlined** (default: **row 3**)
- [ ] **Freeze panes** at **`E4`** by default (or equivalent: below header row,
      right of **D**)
- [ ] **No** extra **Source** rows/columns for filings — only **hyperlinks** on value
      cells
- [ ] **Hyperlinks** on value cells: **dark blue** font `FF0563C1`; number format
      `_(#,##0.0%_);_((#,##0.0%);_(-_);_(@_)` for percent-class metrics; accounting
      format + same blue for non-percent linked values; **do not** depend on underline
- [ ] **Empty** data cells show a **dash** (not blank) in the data region
- [ ] **deepKPI input** cells: fill **`#E2EFDA`**; **hyperlinked** inputs **dark blue**
      `FF0563C1` per **Hyperlinks**
- [ ] **Derived** cells: **black** font (no green input styling); formulas live
- [ ] Every derived value is a live `=` formula referencing input cells — no hardcoded numbers
- [ ] **Time series numerics** stored as **Excel numbers**, not text strings
- [ ] Number format `_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)` applied to data cells as applicable
- [ ] Every deepKPI-sourced cell has an actual Excel hyperlink (not a plain-text URL string)
- [ ] **ALL CAPS** section headers: **bold** and **underlined**
- [ ] **Col C** display labels: **one** naming pattern sheet-wide; **prefer** em dash
      or hyphen over **parentheses** for qualifiers; abbreviations only when
      **industry-standard** (e.g. ARPU), not opaque codes (e.g. BOC)
- [ ] Col A (deepKPI metric name) and Col B (index) are hidden

## Common failure modes (Excel)

- **Extra Source rows**: filing identity lives in the **cell hyperlink** only.
- **Green font on hyperlinked values** — use **dark blue** `FF0563C1` and the **percent
  format** (or accounting + blue for non-percent) so links look like links **without**
  relying on underline.
- **Text-only date headers** — use **numeric** Excel dates + `mmm-yy` / year format.
- **Text-stored time series values** — numeric KPI points must be **Excel numbers**,
  not strings; use number format for display, not text that mimics a number.
- **Quarterly columns before annual** — **annuals left**, blank, **quarterlies right**.
- **Hardcoded derived numbers** — if a cell is computed from other cells, it must
  be a **formula**, not a pasted constant (even if “correct”).
- **Parenthetical KPI labels** (`Name (modifier)`) or **opaque abbreviations** in
  Col C when **dash-separated** names or **spelled-out** words would be clearer.
- **Extra row for imputed Q4** — imputation belongs **in the quarterly series row**,
  not a second row for the same stream.
- **Two rows for quarterly vs annual of the same metric** — if definition and unit
  match and only aggregation differs (e.g. `… - 3 Month` vs `… - Annual`), use **one
  row** with FY values in the annual columns and quarterlies in the quarterly columns.


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)