Skip to content

feat(ui): cross-cluster comparison + cross-cluster chat reasoning#3

Merged
ginaecho merged 1 commit into
feat/cross-explanationfrom
claude/dazzling-pasteur-0wbFu
May 30, 2026
Merged

feat(ui): cross-cluster comparison + cross-cluster chat reasoning#3
ginaecho merged 1 commit into
feat/cross-explanationfrom
claude/dazzling-pasteur-0wbFu

Conversation

@ginaecho

Copy link
Copy Markdown
Owner

Problem

When clustering finishes, users click a named-cluster card to chat with the LLM about it. But the chat (POST /api/cluster-chat) only loaded the single clicked cluster's stats into the system prompt, so the LLM had no data about any other cluster. Cross-cluster questions like "why are clusters 0 and 3 both high-spend, but 0 leans X while 3 leans Y?" couldn't be answered — the model literally couldn't see cluster 3's numbers.

Changes

1. Cross-cluster reasoning in the Named Clusters chat (ui/app.py)

  • The chat keeps the clicked cluster as the FOCUS, but now appends a compact roster of every cluster — name, size, and the features each is stronger/weaker in (with ratios + means) — under an "ALL CLUSTERS IN THIS RUN" section, with an instruction to cite the specific diverging features when contrasting.
  • Cross-cluster questions now get a grounded answer pointing at the actual features that split the clusters.
  • Updated chat help text + placeholder to advertise this.

2. Cross-cluster comparison in the Data & Evidence tab (ui/app.py + ui/static/app.js)

  • New POST /api/cluster-comparison endpoint runs an LLM contrasting analysis across all clusters: separating axes, look-alike-but-diverging pairs, overlap/merge candidates, and a takeaway.
  • Billed to the evidence ledger (separate from pipeline/naming cost), lazy (button-triggered, never auto-bills), and cached by cluster signature so re-opens/extra windows don't re-bill.
  • New "Cross-cluster comparison" card appears in the Evidence tab whenever there are ≥2 clusters, with an optional focus input.

Shared _clusters_overview_lines / _sorted_cluster_ids helpers back both paths.

Verification

  • python -m py_compile ui/app.py and node --check ui/static/app.js both pass.
  • Unit-tested the roster helper with synthetic personas to confirm it emits the per-cluster feature/ratio data the LLM needs.
  • Could not run the live Flask app end-to-end (no flask installed in the session, and personas.json is cleared on this branch), but the new code reads the identical persona/stats fields the existing card and chat code already rely on.

https://claude.ai/code/session_01QL4MpBtJ46QLcwBezp6Qk7


Generated by Claude Code

The per-cluster chat only loaded the clicked cluster's stats, so the LLM
could not answer cross-cluster questions ('why are clusters 0 and 3 both
high-X but 0 leans Y while 3 leans Z?'). Two changes fix this:

- /api/cluster-chat now appends a compact roster of EVERY cluster (name,
  size, stronger/weaker features + ratios) to the system prompt, with the
  clicked cluster kept as the focus. The model can now compare and contrast
  any clusters the user names in the Named Clusters tab.
- New /api/cluster-comparison endpoint runs an LLM contrasting analysis
  across all clusters (separating axes, look-alike-but-diverging pairs,
  merge candidates) on the evidence ledger, surfaced as an on-demand
  'Cross-cluster comparison' card in the Data & Evidence tab. Cached by
  cluster signature so re-opens don't re-bill.

Shared _clusters_overview_lines / _sorted_cluster_ids helpers back both.
Copilot AI review requested due to automatic review settings May 30, 2026 11:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds cross-cluster reasoning to the existing per-cluster chat and introduces a new on-demand cross-cluster comparison card in the Data & Evidence tab. The chat system prompt now embeds a roster of every cluster (so the LLM can contrast clusters), and a new /api/cluster-comparison endpoint produces a contrasting analysis billed to the evidence ledger with a signature-based cache.

Changes:

  • Augment cluster_chat system prompt with an "ALL CLUSTERS IN THIS RUN" roster via two new helpers (_sorted_cluster_ids, _clusters_overview_lines); update chat copy/placeholder.
  • Add POST /api/cluster-comparison with a TTL+lock-guarded cache, calling the persona agent bus under category='evidence'.
  • Add buildClusterComparisonCard / wireComparisonButton in the Evidence tab UI, shown when ≥2 personas exist.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
ui/app.py New helpers for cluster roster; expanded chat system prompt with cross-cluster roster; new /api/cluster-comparison endpoint with TTL cache.
ui/static/app.js New cross-cluster comparison card + wiring in Evidence tab; updated chat help text and placeholder.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 46a3a6f6d0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/app.py
Comment on lines +1053 to +1056
sig = "|".join(
f"{cid}:{personas[cid].get('persona', {}).get('name', '')}"
for cid in _sorted_cluster_ids(personas)
) + f"||focus={focus}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include cluster statistics in comparison cache key

When the same Flask process is used for another run that produces the same cluster IDs and persona names within the 10-minute TTL, this signature still hits even though the sizes/features passed to _clusters_overview_lines() may have changed. In that case the Data & Evidence tab returns an old cross-cluster analysis marked as cached, which can mislead experiment interpretation; include the roster/stat payload, output mtime, or run id in the key rather than only id/name/focus.

Useful? React with 👍 / 👎.

Comment thread ui/static/app.js
Comment on lines +2053 to +2058
const focus = (document.getElementById('ev-compare-focus')?.value || '').trim();
const out = document.getElementById('ev-compare-out');
btn.disabled = true;
btn.innerHTML = `<span class="spinner"></span>Comparing (evidence ledger)…`;
try {
const r = await api('POST', '/api/cluster-comparison', {focus});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve comparison state across evidence refreshes

The evidence tab is re-rendered by startGlobalRefreshWatchdog() every 20 seconds while visible, so if this LLM call takes longer than that the DOM nodes captured here are detached and the completed analysis is written into an invisible old out element; the replacement card also shows a fresh enabled button, allowing duplicate requests. Store the in-flight/result state outside the card or re-resolve the current elements after the await so long comparisons remain visible and cannot be rebilled accidentally.

Useful? React with 👍 / 👎.

@ginaecho ginaecho merged commit ebc2f74 into feat/cross-explanation May 30, 2026
1 check passed
@ginaecho ginaecho deleted the claude/dazzling-pasteur-0wbFu branch May 30, 2026 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants