Skip to content

Commit 5d3a3e4

Browse files
josers18claude
andcommitted
docs: refresh after demo-day hardening pass (Tableau 40s, SectionRail, client cache)
Brings written artifacts in line with code shipped today (2026-05-07). No prose rewrites — surgical updates only: - docs/OPERATIONS.md + docs/LLM_PROMPT_GUIDE.md: Today-path Tableau analyze timeout cited as 25s → updated to 40s with the SSE-keeps-bytes-flowing rationale (Heroku H12 idle timer doesn't apply since every Today route streams from first byte; the cap is purely a wedged-call backstop). - docs/README.md: new 2026-05-07 milestone entry covering pinned DC SQL in Pulse + Drafts, pinned Tableau utterance, Tableau timeout bump, Analyze fresh-start, ClientDetailSheet session cache, SectionRail, Ask Bar brightening. - docs/ARTIFACTS.md: ClientDetailSheet row notes the session-cache pattern. - components/README.md: adds SectionRail to persistent chrome; updates ClientDetailSheet row with the cache + data-horizon-overlay note; notes UserMenu clears the cache on sign-out; notes AskBar brightness bump. - lib/client/README.md: new "Session-scoped caches" section covering clientDetailCache.ts. - README.md: one-liner mention of SectionRail + session cache in the Today bullet. CLAUDE.md is gitignored — not touched. Tier validation docs (ASK_MY_DATA_T1, ANALYZE_T2) and historical references (SEED_DATA_SPEC, CURSOR_MCP_SETUP) are unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 41bda81 commit 5d3a3e4

7 files changed

Lines changed: 15 additions & 7 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
## What it does
3838

39-
- **Home (Today)** (`/`) — **Morning brief** (life-event hierarchy + "Recent life events"), **priority queue**, **today's arc**, **portfolio pulse**, **pulse strip**, **pre-drafted actions**, **live signals**, **section insight** banners, **Ask** bar (typed + voice + drafted actions), **Prep me** (per-client briefing via `/api/prep`).
39+
- **Home (Today)** (`/`) — **Morning brief** (life-event hierarchy + "Recent life events"), **priority queue**, **today's arc**, **portfolio pulse**, **pulse strip**, **pre-drafted actions**, **live signals**, **section insight** banners, **Ask** bar (typed + voice + drafted actions), **Prep me** (per-client briefing via `/api/prep`), **left-edge section rail** (scroll-spy with click-to-jump at xl+), **session-cached Client 360° sheet** (first open ~10s for full depth, every reopen instant during the session).
4040
- **Ask My Data** (`/ask-data`) — multi-turn exploratory SQL agent over Data Cloud. Markdown-rendered responses, persisted thread history, reasoning trail, follow-up pill suggestions.
4141
- **Analyze** (`/analyze/[modelId]`) — governed analytics workbench over Tableau Next SDMs. 18 chart types with grounded MiniMax chart selection, per-model starter questions, multi-turn in-memory conversation, clickable metric chips, Business Preferences panel.
4242
- The LLM orchestrates three **Salesforce-hosted MCP** servers (CRM SObject, Data 360 SQL, Tableau Next) plus optional **Heroku toolkit** MCP. The UI streams tokens and a collapsible **reasoning trail** of tool calls (success + handled errors).

components/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,11 @@ The five protected surfaces from the contest spec, plus shared chrome.
4141

4242
| Component | Role |
4343
|-----------|------|
44-
| `AskBar.tsx` | Fixed-bottom Ask Horizon input — typed + voice + drafted-action picker. Posts to `/api/ask` (SSE). |
44+
| `AskBar.tsx` | Fixed-bottom Ask Horizon input — typed + voice + drafted-action picker. Posts to `/api/ask` (SSE). Background mixed +6% white via `color-mix(in oklab, …)` so the bar reads as elevated against the dark page. |
45+
| `SectionRail.tsx` | Left-edge scroll-spy at xl+. Connected dots + inline labels for the 5 main-column sections (Brief, Arc, Priority, Pulse, Drafts — Live Signals lives in the right-rail and is intentionally not on the rail). Active dot is full-bright with a halo, passed dots are mid-faint, upcoming dots are deeply faint. Click any dot to smooth-scroll. Watches the DOM for `[data-horizon-overlay]` via `MutationObserver` and fades out while a sheet is open. |
4546
| `PulseStrip.tsx` | Compact KPI strip in the sticky header (signed-in only). |
4647
| `HeaderClock.tsx` | Live wall-clock + day-of-week in header. |
47-
| `UserMenu.tsx` | Banker name / email dropdown; sign-out. |
48+
| `UserMenu.tsx` | Banker name / email dropdown; sign-out (also clears the Client Detail session cache). |
4849
| `ThemeSwitcher.tsx` | 42-theme palette switcher (`data-theme="…"`). |
4950
| `SectionInsight.tsx` | The narrow info banner that sits above each section (`InsightsBatchProvider` batches the agent calls). |
5051
| `ReasoningTrail.tsx` | Collapsible MCP-tool-call trace; rendered inside every agent section. |
@@ -54,7 +55,7 @@ The five protected surfaces from the contest spec, plus shared chrome.
5455

5556
| Component | Role |
5657
|-----------|------|
57-
| `ClientDetailSheet.tsx` | Right-side slide-in 360° client view (Esc closes). Streams from `/api/client/[id]`. |
58+
| `ClientDetailSheet.tsx` | Right-side slide-in 360° client view (Esc closes). Streams from `/api/client/[id]` on first open; on reopen during the same session, hydrates synchronously from `lib/client/clientDetailCache.ts` (`sessionStorage`). Renders `data-horizon-overlay="client-detail"` on the backdrop so chrome like `SectionRail` can observe and fade out while it's open. |
5859
| `DraftActionCard.tsx` | One draft row with three-state status (idle / pending / executed). |
5960
| `PulseTile.tsx` | One KPI tile inside Portfolio Pulse, with delta + explanation popover. |
6061
| `ArcNode.tsx`, `ArcTimeline.tsx` | Timeline rendering for Today's Arc. |

docs/ARTIFACTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ See [**LLM_PROMPT_GUIDE.md**](./LLM_PROMPT_GUIDE.md) for editing rules and a fai
2727
| Pre-drafted actions | `components/horizon/PreDraftedActions.tsx` | `GET /api/drafts` (SSE); execute `POST /api/actions` |
2828
| Live signals | `components/horizon/SignalFeed.tsx` | `GET /api/signals` (JSON; client polls ~45s) |
2929
| Ask bar | `components/horizon/AskBar.tsx` | `POST /api/ask` (SSE); **Prep me** uses `POST /api/prep` (SSE) from embedded prep flow |
30-
| Client 360 sheet | `components/horizon/ClientDetailSheet.tsx` | `GET /api/client/[id]` (SSE) |
30+
| Client 360 sheet | `components/horizon/ClientDetailSheet.tsx` | `GET /api/client/[id]` (SSE) — first open streams the 6-tool fan-out (4 SOQL + DC SQL + Tableau analyze, ~10s); subsequent opens the same session render synchronously from `sessionStorage` via `lib/client/clientDetailCache.ts`. Cleared on sign-out. |
3131
| Section insights | `components/horizon/SectionInsight.tsx` + `InsightsBatchProvider` | `POST /api/insights` (SSE) |
3232
| **Ask My Data** (`/ask-data`) | `components/ask-data/Conversation.tsx` | `POST /api/ask-data` (SSE); threads via `GET/POST/DELETE /api/ask-threads`; follow-ups via `POST /api/analyze-followups` |
3333
| **Analyze** (`/analyze/[modelId]`) | `components/analyze/AnalyzeWorkbench.tsx` | `POST /api/analyze-ask` (SSE); model list via `GET /api/analyze-models`; follow-ups via `POST /api/analyze-followups` |

docs/LLM_PROMPT_GUIDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ These patterns **actually appeared** in demo runs; `system.ts` §MCP HYGIENE enc
4949
|---------|--------|------------|
5050
| `Semantic model apiName "X" does not exist in this org` (preflight) | Model invented an apiName (e.g. `Sales_Analytics`, `Service_Pipeline`). | New on 2026-05-06: `preflightTableauAnalyze` rejects unknown apiNames before the network call when the SDM cache is preloaded, with the real list of valid apiNames in the rejection's `instruction` field. Catches the most common SDM hallucination at zero round-trip cost. |
5151
| `INVALID_INPUT — don't have access to the semantic model` (post-preflight) | Either (a) the SDM cache is empty so the preflight didn't run, or (b) the cache was refreshed by an admin token but the banker has narrower visibility. | Confirm cache state via `GET /api/admin/refresh-dc-cache` → look at `tableau.cached` and `tableau.apiNames`. If `cached: false`, refresh via `?run=1&tool=tableau&force=1`. Real permission gaps trip the breaker on first occurrence (see `INVALID_INPUT` / "don't have access" in `TRIP_ERROR_PATTERNS`). |
52-
| `analyze_data exceeded 25000ms` (Today path) | Utterance is too long or multi-clause; Tableau's LLM Q&A takes >25s on heavy banker books. | Today's cap was bumped 20s → 25s on 2026-05-06. Analyze surface uses a separate 45s cap (`firstPartyTableauNext.ts`) since it's a single-tool turn. Keep utterances under 15 words and single-facet to stay well under either ceiling. |
52+
| `analyze_data exceeded 40000ms` (Today path) | Utterance is too long or multi-clause; Tableau's LLM Q&A takes >25s on heavy banker books. | Today's cap progressed 20s → 25s (2026-05-06) → **40s (2026-05-07)**. Today routes stream via SSE from first byte so Heroku's 30s H12 idle timer doesn't apply — the 40s cap is purely a wedged-call backstop. Pulse pins a known-fast utterance (`"Total Current_Balance across Deposits"` on the `Financial_Accounts` SDM) so it stays well under any ceiling. Analyze surface uses a separate 45s cap (`firstPartyTableauNext.ts`). |
5353
| `Unknown tool "tableau_next__list_semantic_models"` | Model called a tool the cache-aware filter strips. | Expected rejection — means a prompt still directs the model to a filtered tool. Rewrite that prompt to point at the injected catalog. |
5454

5555
### Analyze (Kimi + Tableau Next)

docs/OPERATIONS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ When the UI shows yellow “schema mismatch / handled” or red failures:
174174
| `INVALID_INPUT — don't have access to the semantic model` (rare, post-preflight) | Real org permission gap. Post-preflight, this means the cache and the banker's token disagree on visibility. Most often the cache was refreshed by an admin and the banker doesn't have the SDM. Trips the breaker on first occurrence (no retry storm). |
175175
| `Unknown tool` rejection on a filtered tool (e.g. `list_semantic_models`, `get_dc_metadata`) | Model tried to call a tool that the cache-aware filter has stripped. Expected behavior when a prompt still references the filtered tool — search `lib/prompts/` for the directive and rewrite to point at the catalog in the system prompt. |
176176
| `MALFORMED_QUERY` / `unexpected token` on `salesforce_crm.soqlQuery` | Bad SOQL date literal (e.g. `NEXT_7_DAYS` instead of `NEXT_N_DAYS:7`, or quoted `ActivityDate`). See [LLM_PROMPT_GUIDE.md](./LLM_PROMPT_GUIDE.md). |
177-
| `504 Gateway Timeout — tableau_next.analyze_data exceeded 25000ms` | Today path's Tableau Q&A timeout (was 20s, bumped to 25s on 2026-05-06). Legitimate upstream slowness on heavy banker books. Analyze surface uses a separate 45s cap (`firstPartyTableauNext.ts`) since it runs analyze_data as a single-tool turn. |
177+
| `504 Gateway Timeout — tableau_next.analyze_data exceeded 40000ms` | Today path's Tableau Q&A timeout (20s25s on 2026-05-06**40s on 2026-05-07**). Every Today route streams via SSE from first byte so Heroku's 30s H12 idle timer doesn't apply (bytes flow continuously while analyze is in flight). The 40s cap is purely so a wedged Tableau call eventually fails the breaker. Analyze surface uses a separate 45s cap (`firstPartyTableauNext.ts`) since it runs analyze_data as a single-tool turn. |
178178
| `504 Gateway Timeout — <other server>.<tool> exceeded Nms` | Per-tool client-side timeout fired. Legitimate upstream slowness — check if a specific DC DMO is consistently slow and consider narrowing the utterance or dropping the call. |
179179
| `blocked by schema-mismatch breaker` | Expected after a bad Data Cloud or SOQL shape — prevents tool-slot burn; narrative should degrade gracefully. |
180180
| `Duplicate <tool> suppressed.` | Dispatcher-level duplicate suppression. Per-iteration (multiple calls to same tool in one LLM response) or turn-wide (budget-limited tools like `analyze_data` that already ran successfully). Expected when the model hedges; the narrative should still complete on a subsequent iteration. |

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ For per-folder explanations, see the README in each:
5757

5858
## Recent milestones
5959

60+
- **2026-05-07 — Demo-day hardening + UX polish.** Pulse + Drafts now emit verbatim DC SQL against `Financial_Transactions_Snow_XL__dll` with column names quoted from the cached catalog (`amount__c`, `transactiondate__c`, etc.) and a pinned `TIMESTAMP '2024-06-01 00:00:00 UTC'` cutoff (the demo org's transaction stream ends 2026-06-30; relative `CURRENT_DATE` filters returned zero rows). Pulse's Tableau analyze pinned to `Financial_Accounts` SDM with utterance `"Total Current_Balance across Deposits"`. Today-path Tableau timeout 25s → 40s — every Today route streams SSE from first byte so the H12 idle timer doesn't apply, the cap is just a wedged-call backstop. Analyze surface stops replaying the persisted last analysis on every visit (DB write path retained for audit, just no read-back). New `SectionRail` left-edge scroll-spy with connected dots + inline labels for the 5 main column sections, hides itself when a `ClientDetailSheet` is open via `data-horizon-overlay`. ClientDetailSheet now keeps the full 6-tool depth (4 SOQL + 1 DC SQL + 1 Tableau analyze) but caches the final narrative + reasoning trail in `sessionStorage` keyed by clientId — first open ~10s, every reopen during the session is instant. Cleared on sign-out. Section labels bumped to 13px semibold + bright text; Ask Bar input + result panel mixed +6% white via `color-mix(in oklab, …)` so they pop off dark themes. See `lib/client/clientDetailCache.ts` and `components/horizon/SectionRail.tsx`.
6061
- **2026-05-06 (PM) — Scheduler self-heals + SDM apiName preflight + UI chrome.** Headline: scheduler refresh jobs were failing silently because (a) `tsx` was in `devDependencies` so the post-build slug couldn't run them and (b) they required a banker `SF_ACCESS_TOKEN` env var the scheduler can't have. Fixes: `tsx``dependencies`, new `scheduler_credentials` singleton table holding the last-good banker `refresh_token`, `scripts/lib/resolveSfToken.ts` resolves a fresh access token at job start (env → config var → DB row). Also: Today-side preflight rejects unknown SDM apiNames (catches Claude inventing names like `Sales_Analytics`), `INVALID_INPUT` / "don't have access" added to breaker patterns, system prompt v1.6.0 forbids owner-user pivots on DC DMOs, Today-path Tableau timeout 20s → 25s, unified `bg-surface` panels across all home-page sections, bold centered section titles on `/`, `/ask`, `/analyze`. See [OPERATIONS.md](./OPERATIONS.md#scheduled-jobs).
6162
- **2026-05-06 (AM) — Agent loop hardening + `defaultExc` unwrap.** Every successful `post_dc_query_sql` was being wrapped in a string-inside-string envelope that the agent couldn't read; the unwrap lives at both MCP wrapper boundaries now. Also: turn-wide `analyze_data` budget on Analyze, synthetic-guard circuit-breaker shield, `<think>`-tag streaming stripper in Ask My Data, visualization-follow-up tool-choice forcing, unified dark/light chart palette, Ask My Data Markdown rendering + preloaded DC catalog + pinned-DMO inclusion list, dev-friendly admin refresh route. See [LLM_PROMPT_GUIDE.md](./LLM_PROMPT_GUIDE.md) failure-mode catalog.
6263
- **2026-05-01 — Metadata cache layer.** The agent preloads Data Cloud DMO metadata and Tableau semantic models from a Redis cache refreshed by Heroku Scheduler. Discovery tools (`get_dc_metadata`, `list_semantic_models`) are hidden from the model when the cache is warm — the catalog in the system prompt replaces them. See [ARCHITECTURE.md#metadata-cache-layer](./ARCHITECTURE.md#metadata-cache-layer) and [OPERATIONS.md#scheduled-jobs](./OPERATIONS.md#scheduled-jobs).

lib/client/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ All three implement the same skeleton: `fetch` with `Accept: text/event-stream`,
7272
| `agentStartStagger.ts` | Per-section delays so Today doesn't fire 5 SSE streams in the same tick (avoids stacking 401 cascades pre-auth). |
7373
| `sfLabelsCache.ts` | In-memory cache of SF-ID → label resolutions across the page. Backed by `/api/sf/labels`. |
7474

75+
### Session-scoped caches
76+
77+
| File | Purpose |
78+
|------|---------|
79+
| `clientDetailCache.ts` | `sessionStorage`-backed cache for `/api/client/[id]` 360° sheets. Snapshots the final narrative (the 360° JSON), the reasoning-trail steps, and the inference badge keyed by `clientId` on stream completion. `ClientDetailSheet.tsx` checks the cache on mount; on hit it skips the network call and hydrates synchronously. Cleared on sign-out (`UserMenu.tsx``clearClientDetailCache()`). Trade-off: first open pays the full 6-tool fan-out (~10s) for depth, every reopen during the same browser session is instant. |
80+
7581
## Conventions
7682

7783
- Every file is **client-only**. Importing them from a Server Component will fail at build time.

0 commit comments

Comments
 (0)