← Adobe CJACONTENT HISTORY

Update to Adobe CJA

Snapshot Sep 30, 2026 · 22:53 UTC · version 2.0.0

Collection source: not recorded for this historical snapshot.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "name": "cja-executive-briefing",
  "description": "Generates a polished, leadership-ready performance briefing with KPI tiles, executive narrative bullets, and a driver analysis — all as a print-ready HTML document. Always use this skill when someone asks for an executive summary, performance briefing, leadership readout, stakeholder update, or business review — even if they don't say \"executive\" explicitly. Trigger phrases include: \"write a summary of last week's performance,\" \"create a briefing for our leadership team,\" \"produce a monthly business review,\" \"what should I tell executives about our metrics,\" \"generate a performance narrative,\" \"QBR summary,\" \"weekly business review,\" \"board update,\" \"stakeholder briefing,\" \"how did we do last week,\" or \"give me a performance snapshot.\" When in doubt, use this skill — it is always better to produce a polished briefing than a raw data dump.\n",
  "included_files": [
    {
      "relative_path": "evals/evals.json",
      "size_in_bytes": 3945
    }
  ],
  "skill_md_contents": "---\nname: cja-executive-briefing\ndescription: >\n  Generates a polished, leadership-ready performance briefing with KPI tiles,\n  executive narrative bullets, and a driver analysis — all as a print-ready HTML\n  document. Always use this skill when someone asks for an executive summary,\n  performance briefing, leadership readout, stakeholder update, or business review\n  — even if they don't say \"executive\" explicitly. Trigger phrases include:\n  \"write a summary of last week's performance,\" \"create a briefing for our\n  leadership team,\" \"produce a monthly business review,\" \"what should I tell\n  executives about our metrics,\" \"generate a performance narrative,\" \"QBR summary,\"\n  \"weekly business review,\" \"board update,\" \"stakeholder briefing,\" \"how did we\n  do last week,\" or \"give me a performance snapshot.\" When in doubt, use this skill\n  — it is always better to produce a polished briefing than a raw data dump.\nlicense: Apache-2.0\nmetadata:\n  author: Adobe\n  version: \"1.0\"\n---\n\n# Executive Briefing (Customer Journey Analytics)\n\nProduce a polished, leadership-ready performance document. Executives do not\nread data tables — they read narratives that answer \"are we growing?\", \"what\nchanged?\", and \"what do we do about it?\"\n\nThis skill converts CJA data into a briefing that a VP or C-suite leader can\nread in under 3 minutes, with supporting data available for those who want to\ndig deeper.\n\nTone: business impact, not technical metrics. Write \"Revenue grew 12% driven by\na strong Paid Search week\" not \"metrics/revenue increased by 0.12 per metrics/sessions.\"\n\n---\n\n## CJA MCP Tools Used\n\n- `describeCja(DATAVIEW_CONTEXT_GUIDE)` — understand the business context of the data view\n- `listComponentUsage` — identify the north-star and supporting KPIs\n- `findMetrics` — resolve user-specified or discovered metric IDs\n- `findCalculatedMetrics` — include custom business KPIs\n- `runReport` — pull KPI values for current and comparison period\n- `searchDimensionItems` — identify top driver dimension values\n\n---\n\n## Phase 0 — Setup\n\n1. Call `findDataViews` to list available data views.\n2. If the user hasn't specified a data view, present the list and ask which to use.\n3. Call `setDefaultSessionDataViewId` with the chosen ID.\n4. Confirm the reporting period (default: last 7 days) and the audience for the briefing (executive, board, team lead).\n\n---\n\n## Phase 1 — Establish Context\n\n### 1.1 Load data view context\n\nCall `describeCja(\"DATAVIEW_CONTEXT_GUIDE\")` to understand:\n- What business the data view represents (e-commerce, media, SaaS, etc.)\n- The primary conversion event and revenue metric\n- **Calendar conventions and timezone.** Record these values — they are\n  inputs to every date computation in 1.2:\n  - `WEEK_START_DOW` — day of week each week starts on (Sunday, Monday, …).\n    Default: **Monday** (ISO 8601) if the context guide doesn't specify.\n  - `FISCAL_YEAR_START_MONTH` — month the fiscal year begins. Default:\n    **January** (calendar year) if the context guide doesn't specify.\n  - `TIMEZONE` — for example, `America/Los_Angeles`.\n  - `CALENDAR_SOURCE` — one of `\"context guide\"` (values came from `describeCja`),\n    `\"default fallback\"` (the context guide didn't expose them and you used the\n    defaults above), or `\"user override\"` (the user explicitly specified them).\n\nThis context determines what counts as the \"north-star metric\" and what\nlanguage to use in the narrative (e.g., \"subscribers\" vs \"customers\" vs \"users\").\n\n### 1.2 Determine reporting period\n\nInfer the period type from the user's request. Do not stop to ask — proceed immediately.\n\n#### The principle\n\nTwo runs of this skill on the same data view, period type, and prompt MUST\nproduce identical `current` and `comparison` date ranges. Determinism comes\nfrom (a) reading calendar conventions from 1.1 instead of improvising, and\n(b) applying the alignment rule for the period type without taste calls.\n\n#### Period type → alignment rule\n\nPick exactly one period type from the user's request:\n\n| User request | `PERIOD_TYPE` | Current period | Comparison period |\n|---|---|---|---|\n| \"last week\" / unspecified | `weekly` | Most recent full week ending before today, aligned to `WEEK_START_DOW` (exactly 7 days) | The week immediately before, same alignment |\n| \"this month\" / \"MTD\" | `month-to-date` | 1st of current month → today | 1st of prior month → same day-of-month as today |\n| \"last month\" | `monthly` | Prior full calendar month (1st → last day) | The month before that |\n| \"this quarter\" / \"QTD\" | `quarter-to-date` | Start of current fiscal quarter → today; fiscal quarters derived from `FISCAL_YEAR_START_MONTH` | Same days into the prior fiscal quarter |\n| \"last quarter\" / \"Q[N]\" | `quarterly` | Prior full fiscal quarter | The fiscal quarter before that |\n| Custom date range | `custom` | Use as specified | Equal-length window ending the day before `current.startDate` |\n\n#### Universal invariants (must hold for every period type)\n\nBefore calling `runReport`, verify all six:\n\n1. `current.startDate < current.endDate`\n2. `comparison.startDate < comparison.endDate`\n3. `comparison.endDate < current.startDate` (no overlap)\n4. The day after `comparison.endDate` equals `current.startDate` (contiguous)\n5. `current` and `comparison` have the **same length in days**\n6. The alignment rule for `PERIOD_TYPE` is satisfied:\n   - `weekly`: both `startDate`s fall on `WEEK_START_DOW`\n   - `monthly`: both `startDate`s fall on the 1st of a month\n   - `month-to-date`: both `startDate`s fall on the 1st; both `endDate`s have the same day-of-month\n   - `quarterly`: both `startDate`s fall on the first day of a fiscal quarter\n   - `quarter-to-date`: both `startDate`s fall on a fiscal quarter start; both `endDate`s are the same number of days into the quarter\n   - `custom`: lengths match; contiguity holds\n\nIf ANY invariant fails, recompute the dates. **Never** paper over a mismatch by editing the footer.\n\n#### Worked examples — today is Tuesday, May 26, 2026\n\nThese examples assume the data view's context guide returns `WEEK_START_DOW = Sunday` and `FISCAL_YEAR_START_MONTH = January`. Numbers change for other calendars — that's exactly the point.\n\n| User request | `PERIOD_TYPE` | Current | Comparison |\n|---|---|---|---|\n| \"last week\" | `weekly` | May 17 (Sun) – May 23 (Sat) | May 10 (Sun) – May 16 (Sat) |\n| \"this month\" / \"MTD\" | `month-to-date` | May 1 – May 26 | Apr 1 – Apr 26 |\n| \"last month\" | `monthly` | Apr 1 – Apr 30 | Mar 1 – Mar 31 |\n| \"this quarter\" / \"QTD\" | `quarter-to-date` | Apr 1 – May 26 | Jan 1 – Feb 24 |\n| \"last quarter\" | `quarterly` | Jan 1 – Mar 31 | Oct 1 – Dec 31 (2025) |\n| Custom: \"May 15–22\" | `custom` | May 15 – May 22 (8 days) | May 7 – May 14 (8 days) |\n\nIf `WEEK_START_DOW = Monday` instead, the weekly row becomes `May 18 (Mon) – May 24 (Sun)` vs `May 11 (Mon) – May 17 (Sun)`. The other rows are unchanged.\n\n#### A common AI failure mode\n\nThe AI may \"know\" from training data that weeks are Mon–Sun (ISO 8601) or that\nquarters are Q1=Jan–Mar (calendar). Silently overriding the context guide with\nthose defaults is exactly the determinism bug this section exists to prevent.\nThe footer's methodology line MUST accurately describe the dates you computed\n— if footer says \"weeks start Sunday\" but `current.startDate` is a Monday,\nthat's a bug to fix in the dates, not in the footer.\n\n### 1.3 Audience assumption\n\nDefault to **internal leadership** (VPs, directors, senior managers). This means:\n- Include specific dimension values (e.g., channel names) in the narrative\n- Surface both positive and negative findings with equal directness\n- The reader understands your business — no need to define basic terms\n\nIf the user says \"external,\" \"board,\" or \"investors,\" shift to higher-level\nbusiness outcomes, remove any internal channel naming that could be sensitive,\nand lead with the most positive finding.\n\n---\n\n## Phase 2 — Discover North-Star Metrics\n\nPull the most-used metrics to identify what the org actually tracks as success.\nRun both calls in parallel — this is fast and sets the foundation for every KPI\ndecision downstream:\n\n```\nlistComponentUsage(componentType: \"metric\")\nlistComponentUsage(componentType: \"calculatedMetric\")\n```\n\n### Deterministic selection — do not improvise\n\nThe KPI set MUST be reproducible across runs for the same data view. Two runs of\nthis skill on the same period must produce the same metric values, which requires\nselecting the **same metric IDs** every time. Follow this algorithm exactly:\n\n1. Combine both `listComponentUsage` results into a single ranked list.\n2. Sort by `usageCount` descending. Break ties by metric ID alphabetically\n   (stable secondary sort).\n3. Resolve metric IDs to human-readable display names with `describeMetric` or\n   `describeCalculatedMetric`.\n4. Take the top **6 metric IDs** from this sorted list. That is the KPI set.\n\nDo NOT cherry-pick by metric \"type\" (volume vs conversion vs revenue) and do NOT\nswap in an alternative metric because its name reads better in a narrative.\nDifferent runs picking `metrics/orders` vs `metrics/orders_1_1` produce wildly\ndifferent numbers and break trust in the briefing.\n\n### When the user specifies metrics explicitly\n\nIf the user names metrics in their request (\"give me a briefing on revenue,\norders, and conversion rate\"), resolve each name to **one** specific metric ID\nvia `findMetrics`. If multiple metrics match a name (e.g., \"Orders\" matches both\n`metrics/orders` and a calculated metric called \"Orders\"), pick the one with\nthe highest `usageCount` and document the choice.\n\n### Always disclose the metric IDs used\n\nInclude a small \"Metrics included\" line in the briefing artifact's footer\nlisting the resolved metric IDs (e.g., `metrics/orders_1_1`, `metrics/visits`,\n`metrics/page_views`). This makes the report auditable and lets the user\nconfirm a re-run is using the same metrics.\n\nCap at 6 KPIs. More is noise.\n\n---\n\n## Phase 3 — Pull KPI Data\n\nRun both reports in parallel — current period and comparison period — with all\nselected metrics. Use a date dimension (e.g., `variables/daterangeday`) so the\nreport returns summary totals across the full period. The `summaryData.totals`\narray in the response contains the aggregate values you need.\n\n```\nrunReport(\n  startDate: \"<current period start>T00:00:00\",\n  endDate: \"<current period end>T00:00:00\",\n  dimensionIds: \"variables/daterangeday\",\n  metricIds: \"metrics/visits,metrics/orders_1_1,metrics/revenue_1,...\",\n  page: 0,\n  limit: 1\n)\nrunReport(\n  startDate: \"<prior period start>T00:00:00\",\n  endDate: \"<prior period end>T00:00:00\",\n  dimensionIds: \"variables/daterangeday\",\n  metricIds: \"metrics/visits,metrics/orders_1_1,metrics/revenue_1,...\",\n  page: 0,\n  limit: 1\n)\n```\n\nRead `summaryData.filteredTotals` from each response — the values correspond to\nthe metrics in the order they were specified in `metricIds`.\n\nCompute for each KPI:\n- `current` value\n- `prior` value\n- `delta` = current − prior\n- `pctChange` = delta / prior × 100\n- `direction`: up / down / flat (using ±3% threshold)\n- `polarity`: positive if higher is better, negative if lower is better\n- `signal`: green (favorable), red (unfavorable), yellow (mixed/flat)\n\n---\n\n## Phase 4 — Find What Drove the Movement\n\nFor the 2 KPIs with the largest absolute % change, find the top driver:\n\nRun current and prior period breakdown reports in parallel:\n\n```\nrunReport(\n  startDate: \"<current period start>\",\n  endDate: \"<current period end>\",\n  dimensionIds: \"variables/marketing_channel\",\n  metricIds: \"<top-moved metric id>\",\n  limit: 5\n)\nrunReport(\n  startDate: \"<prior period start>\",\n  endDate: \"<prior period end>\",\n  dimensionIds: \"variables/marketing_channel\",\n  metricIds: \"<top-moved metric id>\",\n  limit: 5\n)\n```\n\nCompare channel-level values between periods to find which dimension value's delta\nmost closely mirrors the overall metric change. This becomes the \"driven by\" phrase\nin the narrative.\n\nOnly run dimension breakdowns for the 2 most-moved metrics (by absolute % change).\nThis constraint exists because: (a) more breakdowns add latency without adding\nexecutive value, and (b) the two largest movers are what leadership will ask about\nfirst. The remaining KPIs get context from the narrative without needing attribution.\n\nIf `variables/marketing_channel` returns no useful breakdown (e.g., only one\nchannel has data), try `variables/page_type` or `variables/product_category`\nas alternative driver dimensions.\n\n---\n\n## Phase 5 — Write the Executive Narrative\n\nCompose 3–5 bullet points as the narrative. Each bullet follows this structure:\n\n**[Signal emoji] [Metric]: [Value] ([+/-pctChange%] vs [prior period]) — [Plain-English context]**\n\nGuidelines:\n- Open with the most important finding (highest-impact metric, positive or negative)\n- Use business language: \"revenue,\" \"customers,\" \"conversions\" — not \"metrics/revenue\"\n- Name the driver when known: \"driven by Paid Search,\" \"led by Product Page improvements\"\n- Include one forward-looking note if relevant: \"This trend should be monitored...\"\n- For negative trends: be direct but not alarming. Suggest investigation, not panic.\n\nExamples of well-written bullets:\n- \"Revenue reached $1.24M last week, up 8.2% vs prior week — Paid Search drove the majority of the gain (+$82K).\"\n- \"Conversion Rate declined to 2.1% (−0.4pp), primarily on mobile. Desktop conversion remained stable at 3.4%.\"\n- \"Sessions were flat at 540K (+1.1%) — organic and direct traffic offset a reduction in email campaign sends.\"\n- \"Bounce Rate ticked up to 43% (+2pp). No single driver identified; worth monitoring through end of month.\"\n\n---\n\n## Phase 6 — Generate the HTML Briefing Document\n\nGenerate the briefing inline. Write to `/tmp/cja_executive_briefing_<YYYY-MM-DD_HHMMSS>.html`.\nThis document should look polished enough to share with leadership — not a\ndeveloper tool output.\n\n\n### Rendering rules — apply consistently across runs\n\nTwo runs of this skill on the same data view + period must render identically\n(modulo the generation timestamp). The rules below pin the formatting choices\nthat the AI would otherwise drift on.\n\n#### Number formatting\n\n- **KPI values** (the big number in each tile) — use full digits with\n  thousands separators (`8,160`, `77,584`, `1,250,000`). Do **NOT** use SI\n  suffixes like `K` or `M`, even for large values. Executives want exact\n  numbers, not abbreviations.\n- **Percent change** (in pills and narrative bullets) — always one decimal\n  place, rounded **half-away-from-zero**. For example, `−23.55%` displays as\n  `−23.6%`, never `−23.5%`. Compute on full-precision values; round only at\n  display time.\n- **Percentage-point change** (for already-percentage metrics like Conversion\n  Rate or Bounce Rate) — same rounding, suffix `pp`. Example: `+0.40 pp`.\n- **Currency** — `$` prefix with thousands separators and no decimals for\n  values ≥ $100 (`$1,240,000`); cents only when value < $100 (`$45.20`).\n\n#### Null / missing data handling\n\nA KPI tile must reflect what the data view actually returned. The AI must\n**not** silently substitute a different metric or hide a tile to make the\nbriefing look cleaner.\n\n- **Both periods return 0 or NULL** for a metric in the resolved set: render\n  the tile with `kpi-value` = `Data unavailable`, pill class `flat`, pill text\n  `⚠ N/A`, and `prior` text = `Both periods returned no data — validate\n  instrumentation`. The tile stays in the grid; do not omit it.\n- **One period returns valid data, the other 0 / NULL**: render the tile with\n  the valid value as `kpi-value`, pill class `flat`, pill text `⚠ N/A`, and\n  `prior` text = `Prior {period_noun}: no data`.\n- **Never** substitute a derived metric (e.g., adding \"Conversion Rate\"\n  because Revenue came back $0). The visible KPI set MUST match the resolved\n  metric IDs disclosed in the footer.\n- If a Revenue / monetary metric is unavailable, surface a `.callout.note`\n  above the KPI grid explaining the gap. Do not invent a value.\n\n\n### Template variables\n\nPopulate every `{PLACEHOLDER}` in the HTML template below using these rules.\nThe briefing belongs to the customer — never substitute Adobe, CJA, or any\nvendor language into customer-visible fields.\n\n- **`{ORG_NAME}`** — The customer's business or brand name, derived from the\n  data view context loaded in Phase 1.1. Strip technical/environment suffixes\n  like ` — Prod`, ` - Demo`, ` Stage`, ` Test`, ` MCP`. If the data view name\n  has no clean brand label, fall back to the data view display name with\n  suffixes removed. Do **not** invent a name and do **not** substitute a\n  vendor name.\n- **`{PERIOD_TYPE}`** — One of `Weekly`, `Monthly`, `Quarterly`, or\n  `Performance` (default), chosen from the period inferred in Phase 1.2.\n- **`{LEDE_SENTENCE}`** — Use exactly this pattern, with no vendor names:\n  `Leadership readout for the {period type lowercase} of {PERIOD_LABEL} compared to {COMPARISON_LABEL}.`\n  Example: `Leadership readout for the week of May 12–18, 2026 compared to May 5–11, 2026.`\n- **`{DATA_VIEW}`** — Data view display name as returned by `findDataViews`.\n  Suffixes are acceptable here — this row is the technical identifier line,\n  not the title.\n- **`{PERIOD_LABEL}`** / **`{COMPARISON_LABEL}`** — Human-readable date ranges,\n  e.g., `May 12–18, 2026`.\n- **`{GENERATED_DATE}`** — Today's date in the same human format,\n  e.g., `May 23, 2026`.\n- **`{METRIC_LABEL}` / `{FORMATTED_VALUE}` / `{PCT_CHANGE}` / `{PRIOR_VALUE}`** —\n  Per-KPI values from Phase 3. Use the metric's customer-facing display name,\n  not its internal ID.\n\n### HTML Template\n\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<title>Performance Briefing &mdash; {ORG_NAME} &mdash; {PERIOD}</title>\n<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n<link href=\"https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700;900&family=Inter:wght@400;500;600;700&display=swap\" rel=\"stylesheet\">\n<style>\n  * { box-sizing: border-box; margin: 0; padding: 0; }\n  :root {\n    --bg: #f5f4f1;\n    --surface: #ffffff;\n    --ink: #1a1a1a;\n    --ink-muted: #6b6b6b;\n    --border: #e5e2dc;\n    --header-bg: #0e0e10;\n    --header-warm: #3a1010;\n    --accent-red: #c8312f;\n    --accent-red-bright: #ff6b68;\n    --accent-red-soft: #fdecea;\n    --accent-green: #1f7a4d;\n    --accent-yellow: #d4a017;\n  }\n  body { font-family: \"Inter\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n         background: var(--bg); color: var(--ink); line-height: 1.5;\n         -webkit-font-smoothing: antialiased; }\n\n  /* === Header === */\n  header { background: linear-gradient(120deg, var(--header-bg) 0%, #1a0d0d 55%, var(--header-warm) 100%);\n           color: #fff; padding: 56px 56px 44px; position: relative; overflow: hidden; }\n  header::after { content: \"\"; position: absolute; right: -140px; top: -140px;\n                  width: 460px; height: 460px;\n                  background: radial-gradient(circle, rgba(200,49,47,.35) 0%, transparent 70%);\n                  pointer-events: none; }\n  .header-inner { max-width: 1080px; margin: 0 auto; position: relative; z-index: 1; }\n  .eyebrow { display: inline-flex; align-items: center; gap: 8px;\n             padding: 6px 14px; border: 1px solid rgba(255,107,104,.55);\n             border-radius: 999px; color: var(--accent-red-bright);\n             font-size: 11px; font-weight: 600; letter-spacing: 1.2px;\n             text-transform: uppercase; margin-bottom: 24px;\n             background: rgba(200,49,47,.10); }\n  .eyebrow::before { content: \"\"; width: 6px; height: 6px;\n                     background: var(--accent-red-bright); border-radius: 50%; }\n  header h1 { font-family: \"Playfair Display\", Georgia, serif;\n              font-size: 56px; font-weight: 700; letter-spacing: -1.5px;\n              line-height: 1.05; margin-bottom: 14px; }\n  header .lede { font-size: 16px; max-width: 560px;\n                 color: rgba(255,255,255,.80); margin-bottom: 24px;\n                 line-height: 1.55; }\n  header .meta { display: flex; flex-wrap: wrap; gap: 22px;\n                 font-size: 13px; color: rgba(255,255,255,.60); }\n  header .meta span { display: inline-flex; align-items: center; gap: 6px; }\n  header .meta .icon { opacity: .8; }\n\n  /* === Tabs === */\n  nav { background: var(--surface); border-bottom: 1px solid var(--border);\n        padding: 0 56px; display: flex; gap: 28px;\n        position: sticky; top: 0; z-index: 50; }\n  nav a { display: block; padding: 16px 0; font-size: 14px;\n          color: var(--ink); text-decoration: none;\n          border-bottom: 2px solid transparent;\n          transition: border-color .15s ease; }\n  nav a:hover { border-bottom-color: var(--accent-red); }\n\n  /* === Container === */\n  .container { max-width: 1080px; margin: 0 auto; padding: 36px 56px 60px; }\n\n  /* === Callout === */\n  .callout { background: var(--accent-red-soft);\n             border-left: 4px solid var(--accent-red);\n             border-radius: 6px;\n             padding: 18px 22px; margin-bottom: 32px;\n             display: flex; gap: 14px; align-items: flex-start; }\n  .callout .warn-icon { font-size: 22px; line-height: 1; flex-shrink: 0;\n                        color: var(--accent-yellow); }\n  .callout-title { font-weight: 700; color: var(--accent-red);\n                   margin-bottom: 4px; font-size: 15px; }\n  .callout-body { font-size: 14px; color: #4a2222; line-height: 1.55; }\n  .callout.note { background: #fdf6e7; border-left-color: var(--accent-yellow); }\n  .callout.note .callout-title { color: #8a5a08; }\n  .callout.note .callout-body { color: #5a4108; }\n\n  /* === Section label === */\n  .section-label { font-size: 11px; font-weight: 700;\n                   text-transform: uppercase; letter-spacing: 1.4px;\n                   color: var(--ink-muted); margin-bottom: 14px;\n                   padding-bottom: 10px; border-bottom: 1px solid var(--border); }\n\n  /* === KPI grid === */\n  .kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n             gap: 14px; margin-bottom: 36px; }\n  .kpi-tile { background: var(--surface); border-radius: 8px;\n              padding: 22px 22px 20px;\n              border-top: 3px solid #b9b6ae;\n              box-shadow: 0 1px 3px rgba(0,0,0,.05); }\n  .kpi-tile.down { border-top-color: var(--accent-red); }\n  .kpi-tile.up   { border-top-color: var(--accent-green); }\n  .kpi-tile.flat { border-top-color: #b9b6ae; }\n  .kpi-head { display: flex; justify-content: space-between;\n              align-items: center; margin-bottom: 10px; }\n  .kpi-label { font-size: 11px; font-weight: 700;\n               text-transform: uppercase;\n               color: var(--ink-muted); letter-spacing: 1px; }\n  .kpi-value { font-family: \"Playfair Display\", Georgia, serif;\n               font-weight: 700; font-size: 38px;\n               line-height: 1; color: var(--ink);\n               margin-bottom: 12px; }\n  .pill { display: inline-flex; align-items: center; gap: 4px;\n          padding: 3px 9px; border-radius: 4px;\n          font-size: 12px; font-weight: 600; line-height: 1.4; }\n  .pill.down { background: var(--accent-red-soft); color: var(--accent-red); }\n  .pill.up   { background: #ebf5ef; color: var(--accent-green); }\n  .pill.flat { background: #f1efea; color: var(--ink-muted); }\n  .prior { display: block; margin-top: 10px;\n           font-size: 12px; color: var(--ink-muted); }\n\n  /* === Narrative === */\n  .narrative-card { background: var(--surface); border-radius: 8px;\n                    padding: 32px 36px;\n                    box-shadow: 0 1px 3px rgba(0,0,0,.04);\n                    margin-bottom: 24px; }\n  .narrative-card h2 { font-family: \"Playfair Display\", Georgia, serif;\n                       font-size: 24px; font-weight: 700;\n                       margin-bottom: 18px;\n                       padding-bottom: 12px;\n                       border-bottom: 1px solid var(--border); }\n  .bullet-list { list-style: none; }\n  .bullet-list li { padding: 14px 0; font-size: 15px; line-height: 1.65;\n                    border-bottom: 1px solid #f1eeea; }\n  .bullet-list li:last-child { border-bottom: none; }\n  .bullet-list .signal { margin-right: 6px; }\n  .bullet-list .metric-highlight { font-weight: 700; }\n  .bullet-list .driver { color: var(--accent-red); font-style: italic; }\n\n  /* === Sections (collapsible tables) === */\n  .section { background: var(--surface); border-radius: 8px;\n             box-shadow: 0 1px 3px rgba(0,0,0,.04);\n             margin-bottom: 22px; overflow: hidden; }\n  .section-header { padding: 18px 28px; border-bottom: 1px solid var(--border);\n                    display: flex; justify-content: space-between;\n                    align-items: center; cursor: pointer; }\n  .section-header h2 { font-family: \"Playfair Display\", Georgia, serif;\n                       font-size: 18px; font-weight: 700; }\n  table { width: 100%; border-collapse: collapse; font-size: 13px; }\n  thead th { background: #faf8f4; padding: 12px 22px;\n             text-align: left; font-weight: 600;\n             text-transform: uppercase; letter-spacing: .6px;\n             font-size: 11px; color: var(--ink-muted);\n             border-bottom: 1px solid var(--border); }\n  tbody td { padding: 12px 22px; border-bottom: 1px solid #f4f1eb; }\n  tbody tr:last-child td { border-bottom: none; }\n\n  .badge { display: inline-block; padding: 3px 9px; border-radius: 4px;\n           font-size: 11px; font-weight: 600; }\n  .badge.green  { background: #ebf5ef; color: var(--accent-green); }\n  .badge.red    { background: var(--accent-red-soft); color: var(--accent-red); }\n  .badge.yellow { background: #fef6e3; color: #b67a08; }\n  .badge.grey   { background: #f1efea; color: var(--ink-muted); }\n\n  footer { text-align: center; padding: 32px 24px;\n           font-size: 12px; color: var(--ink-muted); }\n\n  /* === Print === */\n  @media print {\n    nav { display: none; position: static; }\n    header { padding: 36px 32px 28px; }\n    header h1 { font-size: 42px; }\n    .section-header { cursor: default; }\n    .kpi-row { page-break-inside: avoid; }\n    .kpi-tile, .narrative-card, .section {\n      box-shadow: none; border: 1px solid var(--border);\n    }\n  }\n</style>\n</head>\n<body>\n\n<header>\n  <div class=\"header-inner\">\n    <div class=\"eyebrow\">{PERIOD_TYPE} Performance Briefing</div>\n    <h1>{ORG_NAME} Performance</h1>\n    <p class=\"lede\">{LEDE_SENTENCE}</p>\n    <div class=\"meta\">\n      <span><span class=\"icon\">&#128197;</span> {PERIOD_LABEL}</span>\n      <span><span class=\"icon\">&#128202;</span> {DATA_VIEW}</span>\n      <span><span class=\"icon\">&#128340;</span> Prepared {GENERATED_DATE}</span>\n    </div>\n  </div>\n</header>\n\n<nav>\n  <a href=\"#highlights\">Highlights</a>\n  <a href=\"#narrative\">Summary</a>\n  <a href=\"#data\">KPI Detail</a>\n  <a href=\"#drivers\">Drivers</a>\n</nav>\n\n<div class=\"container\">\n\n  <!--\n    Optional critical callout. Include ONLY when the data has a\n    notable finding worth raising above the fold (e.g., a metric\n    moved >25% week-over-week, or data is missing/anomalous).\n    Use the .note variant (yellow) for non-critical context;\n    omit entirely if there is nothing noteworthy.\n  -->\n  <!--\n  <div class=\"callout\">\n    <span class=\"warn-icon\">&#9888;</span>\n    <div>\n      <div class=\"callout-title\">Critical: {ONE_LINE_HEADLINE}</div>\n      <div class=\"callout-body\">{ONE_PARAGRAPH_CONTEXT}</div>\n    </div>\n  </div>\n  -->\n\n  <!-- Headline KPI Tiles -->\n  <div class=\"section-label\">Key Performance Indicators</div>\n  <div id=\"highlights\" class=\"kpi-row\">\n    <!-- Repeat for each KPI (4-6 tiles), class = up | down | flat:\n    <div class=\"kpi-tile down\">\n      <div class=\"kpi-head\">\n        <div class=\"kpi-label\">{METRIC_LABEL}</div>\n      </div>\n      <div class=\"kpi-value\">{FORMATTED_VALUE}</div>\n      <span class=\"pill down\">&#9660; {PCT_CHANGE}%</span>\n      <span class=\"prior\">Prior week: {PRIOR_VALUE}</span>\n    </div>\n    -->\n  </div>\n\n  <!-- Executive Narrative -->\n  <div id=\"narrative\" class=\"narrative-card\">\n    <h2>Executive Summary</h2>\n    <ul class=\"bullet-list\">\n      <!--\n      <li>\n        <span class=\"signal\">{EMOJI}</span>\n        <span class=\"metric-highlight\">{Metric}:</span> {value} ({delta} vs prior period) &mdash;\n        <span class=\"driver\">{plain-English driver or context}</span>\n      </li>\n      -->\n    </ul>\n  </div>\n\n  <!-- Supporting Data Table -->\n  <div id=\"data\" class=\"section\">\n    <div class=\"section-header\" onclick=\"toggle('data-body')\">\n      <h2>Full KPI Detail</h2>\n      <span id=\"data-body-icon\">&#9662;</span>\n    </div>\n    <div id=\"data-body\">\n      <table>\n        <thead><tr>\n          <th>Metric</th>\n          <th>{PERIOD_LABEL}</th>\n          <th>{COMPARISON_LABEL}</th>\n          <th>Change</th>\n          <th>% Change</th>\n          <th>Signal</th>\n        </tr></thead>\n        <tbody>\n          <!-- One row per KPI with delta and badge -->\n        </tbody>\n      </table>\n    </div>\n  </div>\n\n  <!-- Key Drivers -->\n  <div id=\"drivers\" class=\"section\">\n    <div class=\"section-header\" onclick=\"toggle('drv-body')\">\n      <h2>What Drove the Movement</h2>\n      <span id=\"drv-body-icon\">&#9662;</span>\n    </div>\n    <div id=\"drv-body\">\n      <table>\n        <thead><tr>\n          <th>Metric</th>\n          <th>Top Driver</th>\n          <th>Value This Period</th>\n          <th>Value Prior Period</th>\n          <th>Contribution</th>\n        </tr></thead>\n        <tbody>\n          <!-- One row per metric with top dimension driver -->\n        </tbody>\n      </table>\n    </div>\n  </div>\n\n</div>\n\n<footer>\n  Performance Briefing &mdash; {ORG_NAME} &mdash; Generated {GENERATED_DATE}<br>\n  <span style=\"opacity:.7\">\n    Methodology: {PERIOD_TYPE}\n    &middot; current {CURRENT_START_ISO}&ndash;{CURRENT_END_ISO}\n    &middot; comparison {COMPARISON_START_ISO}&ndash;{COMPARISON_END_ISO}\n    &middot; week starts {WEEK_START_DOW}\n    &middot; fiscal year starts {FISCAL_YEAR_START_MONTH}\n    &middot; tz {TIMEZONE}\n    &middot; calendar source: {CALENDAR_SOURCE}\n    &middot; metrics: {METRIC_IDS_CSV}\n  </span>\n</footer>\n\n<script>\nfunction toggle(id) {\n  var el = document.getElementById(id);\n  var ic = document.getElementById(id + '-icon');\n  if (el.style.display === 'none') { el.style.display=''; ic.textContent='\\u25be'; }\n  else { el.style.display='none'; ic.textContent='\\u25b8'; }\n}\n</script>\n</body></html>\n```\n\n---\n\n## Phase 7 — Deliver the Briefing\n\n1. Write the HTML to `/tmp/cja_executive_briefing_<YYYY-MM-DD_HHMMSS>.html`\n2. Open with `open /tmp/cja_executive_briefing_<YYYY-MM-DD_HHMMSS>.html`\n3. Output the narrative bullets directly in chat so the user can copy-paste\n   them into an email or slide deck immediately — the HTML is the \"appendix.\"\n\nIn-chat format:\n```\nPerformance Briefing — Last Week vs Prior Week\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n📈 Revenue: $1.24M (+8.2%) — Paid Search drove the majority of the gain.\n📉 Conversion Rate: 2.1% (−0.4pp) — Mobile checkout declined; desktop stable.\n➡  Sessions: 540K (+1.1%) — Essentially flat; organic offset email decline.\n📈 Orders: 11,340 (+6.7%) — Product page improvements appear to be contributing.\n⚠️  Bounce Rate: 43% (+2pp) — No clear driver identified; monitor next week.\n\nFull briefing document: /tmp/cja_executive_briefing_<YYYY-MM-DD_HHMMSS>.html\n```\n\n---\n\n## Tone and Style Rules\n\n1. **Write outcomes, not activities.** \"Revenue grew\" not \"metrics/revenue increased.\"\n2. **Name the driver concisely.** \"Paid Search drove the gain\" not \"Marketing\n   Channel = Paid Search had a higher value in period A vs period B.\"\n3. **One sentence per bullet.** Two at most. Executives skim.\n4. **Lead with the most important finding.** Do not build to a conclusion.\n5. **Be direct about bad news.** \"Conversion Rate declined\" not \"Conversion Rate\n   saw some movement in a downward direction.\"\n6. **Quantify everything.** Every bullet must have a number. Opinions without\n   data are not executive communication.\n7. **Avoid jargon.** No \"dimensions,\" \"metrics IDs,\" \"data view context,\" or\n   \"MCP tool calls\" in the output.\n\n## Important Guardrails\n\n- **Read-only reporting.** Never modify metrics, segments, or projects.\n- **Use business language, not technical IDs.** Replace dimension IDs (e.g., `variables/evar5`) with their display names. Never expose internal IDs in the narrative.\n- **Always state the date range prominently.** Executives need context — \"last week\" is ambiguous; write \"April 7–13, 2026.\"\n- **Don't invent data.** If a KPI is unavailable or the report returns no data, say so explicitly rather than omitting or estimating.\n- **Cap the briefing to the most impactful findings.** 3–5 KPI tiles + 2–3 driver bullets is ideal; more than 8 KPIs dilutes the message.\n- **Note significant context.** Mention known external factors (campaigns, holidays, product releases) that affect the metrics when relevant.\n- **Validate numbers before presenting.** Cross-check KPI values against a second `runReport` call if they look anomalous.\n- **Customer-branded output, never vendor-branded.** The briefing is the customer's document about their own business. Never use \"Adobe\", \"CJA\", \"Customer Journey Analytics\", or any vendor/product name in the customer-visible briefing (title, lede, narrative, tables, footer, or in-chat output). The red/black header palette is the only Adobe-branded element allowed in the artifact.\n\n---\n\n## Example Interaction\n\n> \"Write me an executive briefing for last week's performance.\"\n\n1. **Setup:** Confirm data view with `findDataViews`. User selects their primary data view. Call `setDefaultSessionDataViewId`.\n2. **Scope:** Confirm reporting period (last 7 days, April 7–13, 2026) and key KPIs (Revenue, Conversion Rate, Sessions, AOV).\n3. **Data pull:** Run `runReport` for each KPI: current week vs. prior week and vs. same week last year.\n4. **Narrative draft:** Compose 3–4 executive bullets in business language: \"Revenue of $2.4M was up 8% week-over-week, driven by a 15% increase in Paid Search conversions. Conversion Rate dipped 2 points to 3.1%, consistent with the product page redesign rollout on April 9.\"\n5. **HTML report:** Generate the print-ready HTML briefing with KPI tiles, narrative section, and driver table. Open the file. Present a 2-sentence summary to the user and offer to adjust tone or scope.\n"
}

SHA-256: 9a31fbaa3b01841cbfbe5b7e66beaba3403becc713033aa3a82dd5fab8f48e99