refactor: clarify investigation map as ux placeholder
This commit is contained in:
@@ -82,12 +82,12 @@ export default function InvestigationMap({ turnCount = 0 }) {
|
|||||||
if (!hasActiveTopics && groups.established.length === 0) return null;
|
if (!hasActiveTopics && groups.established.length === 0) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg border border-gray-200 bg-white p-5" role="region" aria-label="Investigation map">
|
<div className="rounded-lg border border-gray-200 bg-white p-5" role="region" aria-label="Investigation map preview">
|
||||||
<h2 className="mb-1 text-sm font-semibold uppercase tracking-wide text-gray-500">
|
<h2 className="mb-1 text-sm font-semibold uppercase tracking-wide text-gray-500">
|
||||||
Investigation Map
|
Investigation Map Preview
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mb-3 text-xs text-gray-400">
|
<p className="mb-3 text-xs text-gray-400">
|
||||||
We are building an understanding of your situation one question at a time.
|
This preview shows where a future reasoning map may appear. Its final shape will emerge from the reasoning engine.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="space-y-px border-t border-gray-100 pt-3" role="list" aria-label="Investigation topics">
|
<div className="space-y-px border-t border-gray-100 pt-3" role="list" aria-label="Investigation topics">
|
||||||
|
|||||||
@@ -99,10 +99,32 @@ temporary workaround and the desired eventual contract.
|
|||||||
|
|
||||||
## Investigation Map (Workspace UX)
|
## Investigation Map (Workspace UX)
|
||||||
|
|
||||||
|
### Open design decision — final map shape intentionally unresolved
|
||||||
|
|
||||||
|
The current Investigation Map implementation exists **only** to validate:
|
||||||
|
- placement within the workspace;
|
||||||
|
- information density at preview scale;
|
||||||
|
- status presentation (established / current / unknown);
|
||||||
|
- responsive layout across viewports;
|
||||||
|
- interaction with surrounding components across turns.
|
||||||
|
|
||||||
|
It is NOT a committed design. The eventual map should be derived from the reasoning engine, not from hard-coded UI categories.
|
||||||
|
|
||||||
|
The following are unresolved design questions — do NOT treat them as agreed contract fields:
|
||||||
|
|
||||||
|
- Will the engine provide a flat topic list, hierarchy, branches, or grouped clusters?
|
||||||
|
- Who determines ordering — engine or user interaction?
|
||||||
|
- Will there be evidence counts, completion percentages, or path metadata?
|
||||||
|
- How does the map handle dynamic addition/removal of topics during investigation?
|
||||||
|
|
||||||
|
### Current entry (temporary)
|
||||||
|
|
||||||
| Feature | UI need | Temporary mock | Desired reasoning output | Likely stage | Notes |
|
| Feature | UI need | Temporary mock | Desired reasoning output | Likely stage | Notes |
|
||||||
| ---------------------- | ---------------------------------- | --------------------------------------------------- | -------------------------------------------------------------- | ---------------------- | -------------------------------------------------------- |
|
| ---------------------- | ---------------------------------- | --------------------------------------------------- | -------------------------------------------------------------- | ---------------------- | -------------------------------------------------------- |
|
||||||
| InvestigationMap | Visible investigation progress | Mock topic set with manual turn-based status progression | Engine emits `investigationTopics: [{ title, status, ordering?, evidenceCount? }]` | Each turn — start and update response | UI displays topics in engine-determined order; statuses: "established" / "current" / "unknown" |
|
| InvestigationMap | Visible investigation progress | **mock-only placeholder**: minimal set of neutral topic names (≤5) with manual turn-based status progression | Engine emits `investigationTopics: [{ title, status, ordering?, evidenceCount? }]` | Each turn — start and update response | UI displays topics in engine-determined order; statuses: "established" / "current" / "unknown" |
|
||||||
| InvestigationMap | Topic status evolution across turns | Hardcoded PROGRESSION array indexed by `investigationHistory.length` | Engine determines which topics are established, active, or unknown at each turn | Question selection phase | Topics should not expose graph internals; plain-language labels only |
|
| InvestigationMap | Topic status evolution across turns | **mock-only placeholder**: Hardcoded PROGRESSION array indexed by `investigationHistory.length` | Engine determines which topics are established, active, or unknown at each turn | Question selection phase | Topics should not expose graph internals; plain-language labels only |
|
||||||
|
|
||||||
|
The current adapter (`lib/map/investigation-map-adapter.js`) uses generic placeholder names (e.g. "Starting point", "Current focus") explicitly because they do NOT represent a domain-specific design decision.
|
||||||
|
|
||||||
## Open Questions / Future Work
|
## Open Questions / Future Work
|
||||||
|
|
||||||
|
|||||||
@@ -1,50 +1,46 @@
|
|||||||
/**
|
/**
|
||||||
* Investigation Map Mock Adapter
|
* ┌─────────────────────────────────────────────────────────────────────┐
|
||||||
*
|
* │ INVESTIGATION MAP — UX PLACEHOLDER ADAPTER │
|
||||||
* Provides the Investigation Map with a set of investigation topics and their
|
* │ │
|
||||||
* current status (established / current / unknown).
|
* │ This adapter drives a minimal mock to validate UX placement, │
|
||||||
*
|
* │ spacing, status appearance, responsive behaviour, and state │
|
||||||
* TODO: Replace this mock adapter when the reasoning engine emits real
|
* │ change across turns. │
|
||||||
* investigation data. The eventual contract should provide:
|
* │ │
|
||||||
* - `investigationTopics`: [{ title, status, evidenceCount? }]
|
* │ The topic names below are mock-only placeholders. They are NOT │
|
||||||
* - `topicStatus` values: "established" | "current" | "unknown"
|
* │ part of the reasoning contract and do NOT imply the final map │
|
||||||
* - `topicOrdering`: the reasoning-engine-determined sequence
|
* │ structure — which may be hierarchical, grouped, branching, or │
|
||||||
* - `evidenceCount`: optional count of supporting evidence per topic
|
* │ something else entirely. │
|
||||||
*
|
* │ │
|
||||||
* Until then, this adapter drives a realistic mock progression across turns.
|
* │ The UI will eventually consume real reasoning output once that │
|
||||||
|
* │ design stabilises. │
|
||||||
|
* └─────────────────────────────────────────────────────────────────────┘
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @type {Array<{ title: string }>} */
|
/** @type {Array<{ title: string }>} — mock-only placeholder names */
|
||||||
const TOPICS = [
|
const TOPICS = [
|
||||||
{ title: "Central situation" },
|
{ title: "Starting point" },
|
||||||
{ title: "Complaint trend direction" },
|
{ title: "What is known" },
|
||||||
{ title: "Measurement basis" },
|
{ title: "Current focus" },
|
||||||
{ title: "Production volume context" },
|
{ title: "Questions still open" },
|
||||||
{ title: "QA process changes" },
|
{ title: "Possible explanations" },
|
||||||
{ title: "Product change log" },
|
|
||||||
{ title: "Support response patterns" },
|
|
||||||
{ title: "Prior similar cases" },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status progression per turn index.
|
* Status progression per turn index.
|
||||||
* The reasoning engine will eventually determine these values.
|
* The reasoning engine will eventually determine these values.
|
||||||
|
*
|
||||||
|
* With N placeholder topics we have N-1 progressive states (indices 0 to N-2).
|
||||||
|
* Beyond that the map stabilises: all topics established except the last one current.
|
||||||
*/
|
*/
|
||||||
const PROGRESSION = [
|
const PROGRESSION = [
|
||||||
// Turn 0 — initial analysis just started
|
// Turn 0 — initial analysis just started
|
||||||
["established", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown"],
|
["established", "current", "unknown", "unknown", "unknown"],
|
||||||
// Turn 1 — first question answered
|
// Turn 1 — first question answered
|
||||||
["established", "established", "current", "unknown", "unknown", "unknown", "unknown", "unknown"],
|
["established", "established", "current", "unknown", "unknown"],
|
||||||
// Turn 2 — second question answered
|
// Turn 2 — second question answered
|
||||||
["established", "established", "established", "current", "unknown", "unknown", "unknown", "unknown"],
|
["established", "established", "established", "current", "unknown"],
|
||||||
// Turn 3 — third question answered
|
// Turn 3+ — third answer and beyond (all topics resolved, last in progress)
|
||||||
["established", "established", "established", "established", "current", "unknown", "unknown", "unknown"],
|
["established", "established", "established", "established", "current"],
|
||||||
// Turn 4 — fourth question answered
|
|
||||||
["established", "established", "established", "established", "established", "current", "unknown", "unknown"],
|
|
||||||
// Turn 5 — fifth question answered
|
|
||||||
["established", "established", "established", "established", "established", "established", "current", "unknown"],
|
|
||||||
// Turn 6+ — final turn
|
|
||||||
["established", "established", "established", "established", "established", "established", "established", "current"],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,7 +49,8 @@ const PROGRESSION = [
|
|||||||
* @returns {{ title: string, status: 'established' | 'current' | 'unknown' }[]}
|
* @returns {{ title: string, status: 'established' | 'current' | 'unknown' }[]}
|
||||||
*/
|
*/
|
||||||
export function getInvestigationMapTopics(turnIndex) {
|
export function getInvestigationMapTopics(turnIndex) {
|
||||||
const idx = Math.min(turnIndex, PROGRESSION.length - 1);
|
// Clamp to last progression entry so the map stabilises when all topics are covered
|
||||||
|
const idx = Math.min(Math.max(turnIndex, 0), PROGRESSION.length - 1);
|
||||||
return TOPICS.map((topic, i) => ({
|
return TOPICS.map((topic, i) => ({
|
||||||
title: topic.title,
|
title: topic.title,
|
||||||
status: PROGRESSION[idx][i],
|
status: PROGRESSION[idx][i],
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ test("update submission replaces response panel with loading card, preserves con
|
|||||||
|
|
||||||
/* ═══════ Test: investigation map appears and evolves across turns ═ */
|
/* ═══════ Test: investigation map appears and evolves across turns ═ */
|
||||||
|
|
||||||
test("investigation map: appears after start, topics evolve across mocked turns", async ({ page }) => {
|
test("investigation map preview: appears after start, topics evolve across mocked turns", async ({ page }) => {
|
||||||
await page.goto("/");
|
await page.goto("/");
|
||||||
|
|
||||||
await page.evaluate(() => {
|
await page.evaluate(() => {
|
||||||
@@ -387,24 +387,22 @@ test("investigation map: appears after start, topics evolve across mocked turns"
|
|||||||
await waitForLoading(page);
|
await waitForLoading(page);
|
||||||
await waitForWorkspaceReady(page);
|
await waitForWorkspaceReady(page);
|
||||||
|
|
||||||
// Verify the investigation map card is present after start
|
// Verify the investigation map preview card is present after start
|
||||||
const mapCard = page.locator('[aria-label="Investigation map"]');
|
const mapCard = page.locator('[aria-label="Investigation map preview"]');
|
||||||
await expect(mapCard).toBeVisible();
|
await expect(mapCard).toBeVisible();
|
||||||
|
|
||||||
// Map heading visible
|
// Preview heading visible
|
||||||
await expect(mapCard.getByRole("heading", { name: "Investigation Map" })).toBeVisible();
|
await expect(mapCard.getByRole("heading", { name: "Investigation Map Preview" })).toBeVisible();
|
||||||
|
|
||||||
// Helper text visible
|
// Placeholder note visible (secondary text)
|
||||||
await expect(mapCard.getByText(/building an understanding/i)).toBeVisible();
|
await expect(mapCard.getByText(/This preview shows where a future reasoning map/i)).toBeVisible();
|
||||||
|
|
||||||
// At turn 0 (initial analysis): one topic established, one current, rest unknown
|
// Helper for counting topics by status across turns
|
||||||
const establishedTopics = page.locator('[data-testid="map-topic-established"]');
|
const byStatus = (status) => page.locator(`[data-testid="map-topic-${status}"]`);
|
||||||
const currentTopics = page.locator('[data-testid="map-topic-current"]');
|
|
||||||
const unknownTopics = page.locator('[data-testid="map-topic-unknown"]');
|
|
||||||
|
|
||||||
await expect(establishedTopics).toHaveCount(1);
|
// At turn 0: one established + one current (≤5 neutral placeholder topics total)
|
||||||
await expect(currentTopics).toHaveCount(1);
|
await expect(byStatus("established")).toHaveCount(1);
|
||||||
await expect(unknownTopics).toHaveCount(6);
|
await expect(byStatus("current")).toHaveCount(1);
|
||||||
|
|
||||||
// Submit first answer → turn 1: one more established, next topic becomes current
|
// Submit first answer → turn 1: one more established, next topic becomes current
|
||||||
const answerTextarea = page.locator('textarea[placeholder*=Answer]');
|
const answerTextarea = page.locator('textarea[placeholder*=Answer]');
|
||||||
@@ -418,10 +416,9 @@ test("investigation map: appears after start, topics evolve across mocked turns"
|
|||||||
// Current investigation remains visible (context preserved)
|
// Current investigation remains visible (context preserved)
|
||||||
await expect(page.getByRole("heading", { name: "Current investigation" })).toBeVisible({ timeout: 5_000 });
|
await expect(page.getByRole("heading", { name: "Current investigation" })).toBeVisible({ timeout: 5_000 });
|
||||||
|
|
||||||
// Map should update: 2 established, 1 current, 5 unknown
|
// Map updated: established count increased, current still present (state shift across turns)
|
||||||
await expect(establishedTopics).toHaveCount(2);
|
await expect(byStatus("established")).toHaveCount(2);
|
||||||
await expect(currentTopics).toHaveCount(1);
|
await expect(byStatus("current")).toHaveCount(1);
|
||||||
await expect(unknownTopics).toHaveCount(5);
|
|
||||||
|
|
||||||
// Submit second answer → turn 2
|
// Submit second answer → turn 2
|
||||||
const answerTextarea2 = page.locator('textarea[placeholder*=Answer]');
|
const answerTextarea2 = page.locator('textarea[placeholder*=Answer]');
|
||||||
@@ -432,10 +429,9 @@ test("investigation map: appears after start, topics evolve across mocked turns"
|
|||||||
await waitForLoading(page);
|
await waitForLoading(page);
|
||||||
await waitForWorkspaceReady(page);
|
await waitForWorkspaceReady(page);
|
||||||
|
|
||||||
// After second update: 3 established, current shifts again
|
// After second update: established count increased again (current shifted)
|
||||||
await expect(establishedTopics).toHaveCount(3);
|
await expect(byStatus("established")).toHaveCount(3);
|
||||||
await expect(currentTopics).toHaveCount(1);
|
await expect(byStatus("current")).toHaveCount(1);
|
||||||
await expect(unknownTopics).toHaveCount(4);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Reference in New Issue
Block a user