Feature/product platform foundation v0.62 #1
@@ -90,3 +90,8 @@ The workspace should always answer:
|
|||||||
The interface should minimise cognitive load by presenting the current state first and allowing progressively deeper exploration only when requested.
|
The interface should minimise cognitive load by presenting the current state first and allowing progressively deeper exploration only when requested.
|
||||||
|
|
||||||
The engine may contain hundreds of reasoning nodes; the user should only see the information required to take the next meaningful action.
|
The engine may contain hundreds of reasoning nodes; the user should only see the information required to take the next meaningful action.
|
||||||
|
|
||||||
|
## Why workspace layout matters (v0.7)
|
||||||
|
|
||||||
|
This phase optimises for simultaneous visibility instead of sequential scrolling.
|
||||||
|
Related panels — Understanding alongside Investigation Map, Situation alongside History — can appear side-by-side on wide screens while mobile continues to stack everything vertically. The reasoning engine is completely unaware of these changes; only the presentation layer is affected.
|
||||||
|
|||||||
@@ -136,6 +136,66 @@ Avoid:
|
|||||||
|
|
||||||
The next question should be the strongest visual element.
|
The next question should be the strongest visual element.
|
||||||
|
|
||||||
|
## Workspace Layout Philosophy
|
||||||
|
|
||||||
|
The Confidence Engine is a workspace, not a document.
|
||||||
|
|
||||||
|
Documents optimise for reading from top to bottom.
|
||||||
|
|
||||||
|
Workspaces optimise for allowing related information to be visible simultaneously.
|
||||||
|
|
||||||
|
As investigations become larger, users should not be forced into unnecessary
|
||||||
|
vertical scrolling simply because horizontal space is available.
|
||||||
|
|
||||||
|
Layout decisions should always ask:
|
||||||
|
|
||||||
|
> "How much useful investigation context can be seen at one time?"
|
||||||
|
|
||||||
|
rather than:
|
||||||
|
|
||||||
|
> "How narrow can the content column be?"
|
||||||
|
|
||||||
|
### Principles
|
||||||
|
|
||||||
|
- **Active investigation remains the primary focus.** The current question and response form are always fully visible first.
|
||||||
|
- **Frequently referenced information should remain visible.** Understanding and Investigation Map should be scannable without scrolling away from the active question.
|
||||||
|
- **Reference material may share horizontal space on larger displays.** Situation and History can sit side-by-side when there is room.
|
||||||
|
- **Layout should adapt to available space without changing the investigation flow.** The same information is always present; only its arrangement changes.
|
||||||
|
- **Mobile and tablet continue to use a stacked single-column layout.** No progressive disclosure at small sizes — every section remains accessible by scrolling, just as it always has been.
|
||||||
|
- **Desktop progressively exposes more simultaneous context.** Instead of simply adding whitespace, wider screens reveal horizontal relationships between related panels.
|
||||||
|
|
||||||
|
### Desktop layout model (wide screens)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───────────────────── full-width ─────────────────────┐
|
||||||
|
│ Investigation Summary │
|
||||||
|
├───────────────────────────────────────────────────────┤
|
||||||
|
│ Active Workspace │ Working Memory │
|
||||||
|
│ (full width) │ Understanding Map │
|
||||||
|
│ Current Investigation │ │
|
||||||
|
│ Response └─────────────────────────────────┘
|
||||||
|
├───────────────────────────────────────────────────────┤
|
||||||
|
│ Reference: Situation │ History │
|
||||||
|
├───────────────────────────────────────────────────────┤
|
||||||
|
│ Developer Details (always below) │
|
||||||
|
└───────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Visual goal
|
||||||
|
|
||||||
|
The page should feel less like a long report and more like an investigator's
|
||||||
|
workspace. The eye should be able to compare Understanding alongside Investigation Map without scrolling, and Situation alongside History in the same way.
|
||||||
|
|
||||||
|
### What this phase does NOT include
|
||||||
|
|
||||||
|
- No card redesigns.
|
||||||
|
- No new navigation.
|
||||||
|
- No account management or top bar.
|
||||||
|
- No tabs, collapsing layouts, resizable panes, floating panels, or masonry.
|
||||||
|
- No typography or colour changes.
|
||||||
|
|
||||||
|
This is a layout-only phase. The reasoning engine should remain completely unaware of presentation decisions.
|
||||||
|
|
||||||
## TL;DR Workspace Rules
|
## TL;DR Workspace Rules
|
||||||
|
|
||||||
The newest state is the most important state.
|
The newest state is the most important state.
|
||||||
|
|||||||
@@ -656,10 +656,10 @@ export default function ReasoningWorkspace({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{/* ── Investigation summary card ─────────────── */}
|
{/* ── Investigation summary card — always full-width ─────────── */}
|
||||||
<InvestigationSummaryPanel graph={graph} selectedQuestion={selectedQ} result={result} updateStatus={updateStatus} />
|
<InvestigationSummaryPanel graph={graph} selectedQuestion={selectedQ} result={result} updateStatus={updateStatus} />
|
||||||
|
|
||||||
{/* ── Active investigation context (always visible while question exists) ─ */}
|
{/* Active workspace — primary focus, full-width column ─────── */}
|
||||||
{hasSelectedQuestion && (
|
{hasSelectedQuestion && (
|
||||||
<>
|
<>
|
||||||
<CurrentInvestigationCard selectedQuestion={selectedQ} graph={graph} />
|
<CurrentInvestigationCard selectedQuestion={selectedQ} graph={graph} />
|
||||||
@@ -669,71 +669,82 @@ export default function ReasoningWorkspace({
|
|||||||
{/* Post-update acknowledgement — only after success, never during loading */}
|
{/* Post-update acknowledgement — only after success, never during loading */}
|
||||||
{updateStatus === "success" && !isUpdating && <UpdateAcknowledgement updateResult={result} />}
|
{updateStatus === "success" && !isUpdating && <UpdateAcknowledgement updateResult={result} />}
|
||||||
|
|
||||||
{/* ── Local update loading (always visible when updating) ─ */}
|
{/* ── Active workspace (left) + Working memory (right) ─────── */}
|
||||||
{isUpdating && (
|
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||||
<LoadingOverlay
|
{/* Left column — active workspace */}
|
||||||
isLoading={true}
|
<div className="space-y-6">
|
||||||
elapsed={updateElapsed}
|
{/* ── Local update loading (always visible when updating) ─ */}
|
||||||
currentMessage={updateMsg}
|
{isUpdating && (
|
||||||
variant="update"
|
<LoadingOverlay
|
||||||
/>
|
isLoading={true}
|
||||||
)}
|
elapsed={updateElapsed}
|
||||||
|
currentMessage={updateMsg}
|
||||||
{/* ── Response form — hidden during update loading ─ */}
|
variant="update"
|
||||||
{!isUpdating && canAnswer && (
|
|
||||||
<form onSubmit={handleUpdateCaptureAndSubmit} className="space-y-4 rounded-lg border border-gray-200 bg-white p-5">
|
|
||||||
<div>
|
|
||||||
<label htmlFor="rw-answer" className="mb-2 block text-sm font-medium text-gray-700">
|
|
||||||
Response
|
|
||||||
</label>
|
|
||||||
<textarea
|
|
||||||
id="rw-answer"
|
|
||||||
value={answer}
|
|
||||||
onChange={(e) => setAnswer(e.target.value)}
|
|
||||||
rows={4}
|
|
||||||
disabled={updateStatus === "loading"}
|
|
||||||
className="w-full rounded-lg border border-gray-300 px-4 py-3 text-sm focus:border-gray-500 focus:outline-none focus:ring-2 focus:ring-gray-400 disabled:cursor-not-allowed disabled:opacity-60"
|
|
||||||
placeholder="Enter the answer to the selected question..."
|
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* ── Response form — hidden during update loading ─ */}
|
||||||
|
{!isUpdating && canAnswer && (
|
||||||
|
<form onSubmit={handleUpdateCaptureAndSubmit} className="space-y-4 rounded-lg border border-gray-200 bg-white p-5">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="rw-answer" className="mb-2 block text-sm font-medium text-gray-700">
|
||||||
|
Response
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
id="rw-answer"
|
||||||
|
value={answer}
|
||||||
|
onChange={(e) => setAnswer(e.target.value)}
|
||||||
|
rows={4}
|
||||||
|
disabled={updateStatus === "loading"}
|
||||||
|
className="w-full rounded-lg border border-gray-300 px-4 py-3 text-sm focus:border-gray-500 focus:outline-none focus:ring-2 focus:ring-gray-400 disabled:cursor-not-allowed disabled:opacity-60"
|
||||||
|
placeholder="Enter the answer to the selected question..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<p className="text-xs text-gray-400">
|
||||||
|
One update turn only in this prototype.
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={!answer.trim()}
|
||||||
|
className="rounded-lg bg-blue-700 px-5 py-2.5 text-sm font-medium text-white transition hover:bg-blue-600 disabled:cursor-not-allowed disabled:opacity-40"
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* ── Terminal state: outcome card — hidden during update loading ─ */}
|
||||||
|
{!isUpdating && status === "success" && !hasSelectedQuestion && graph && genuineCompletion && (
|
||||||
|
<CompletionCard summary={resolveCurrentSummary(propUnderstanding || graph?.currentSummary || result?.updatedSituationGraph?.currentSummary)} />
|
||||||
|
)}
|
||||||
|
{!isUpdating && status === "success" && !hasSelectedQuestion && graph && !genuineCompletion && (
|
||||||
|
<EvidenceLimitCard summary={resolveCurrentSummary(propUnderstanding || graph?.currentSummary || result?.updatedSituationGraph?.currentSummary)} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Right column — working memory: Understanding + Map */}
|
||||||
|
{hasSelectedQuestion && (
|
||||||
|
<div className="space-y-6">
|
||||||
|
{hasCurrentSummaryCondition && (
|
||||||
|
<CurrentUnderstandingCard currentSummary={graph?.currentSummary || result?.updatedSituationGraph?.currentSummary} plainLanguage={propUnderstanding || null} />
|
||||||
|
)}
|
||||||
|
<InvestigationMap turnCount={investigationHistory.length} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between">
|
)}
|
||||||
<p className="text-xs text-gray-400">
|
</div>
|
||||||
One update turn only in this prototype.
|
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
disabled={!answer.trim()}
|
|
||||||
className="rounded-lg bg-blue-700 px-5 py-2.5 text-sm font-medium text-white transition hover:bg-blue-600 disabled:cursor-not-allowed disabled:opacity-40"
|
|
||||||
>
|
|
||||||
Update
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* ── Terminal state: outcome card — hidden during update loading ─ */}
|
{/* ── Reference row — Situation + History side-by-side on desktop ─ */}
|
||||||
{!isUpdating && status === "success" && !hasSelectedQuestion && graph && genuineCompletion && (
|
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||||
<CompletionCard summary={resolveCurrentSummary(propUnderstanding || graph?.currentSummary || result?.updatedSituationGraph?.currentSummary)} />
|
<OriginalSituation scenario={scenario} centralStatement={graph?.centralStatement} />
|
||||||
)}
|
{investigationHistory.length > 0 && (
|
||||||
{!isUpdating && status === "success" && !hasSelectedQuestion && graph && !genuineCompletion && (
|
<InvestigationHistory turns={investigationHistory} />
|
||||||
<EvidenceLimitCard summary={resolveCurrentSummary(propUnderstanding || graph?.currentSummary || result?.updatedSituationGraph?.currentSummary)} />
|
)}
|
||||||
)}
|
</div>
|
||||||
|
|
||||||
{/* ── Current understanding (active investigation only) ─ */}
|
{/* ── Developer details (collapsed by default, always below) ── */}
|
||||||
{hasCurrentSummaryCondition && hasSelectedQuestion && (
|
|
||||||
<CurrentUnderstandingCard currentSummary={graph?.currentSummary || result?.updatedSituationGraph?.currentSummary} plainLanguage={propUnderstanding || null} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* ── Investigation Map (visible during active investigation) ─ */}
|
|
||||||
{hasSelectedQuestion && (
|
|
||||||
<InvestigationMap turnCount={investigationHistory.length} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<OriginalSituation scenario={scenario} centralStatement={graph?.centralStatement} />
|
|
||||||
|
|
||||||
{investigationHistory.length > 0 && <InvestigationHistory turns={investigationHistory} />}
|
|
||||||
|
|
||||||
{/* ── Developer details (collapsed by default) ── */}
|
|
||||||
{(status === "success" || status === "error") && graph && (
|
{(status === "success" || status === "error") && graph && (
|
||||||
<DeveloperDetails
|
<DeveloperDetails
|
||||||
graph={graph}
|
graph={graph}
|
||||||
|
|||||||
@@ -141,3 +141,5 @@ The current adapter (`lib/map/investigation-map-adapter.js`) uses generic placeh
|
|||||||
6. **Recovery action granularity**: The recovery cards currently offer a single "restart investigation" action. Future engine contracts could support partial recovery (e.g., retry with different parameters, switch models) rather than full restart.
|
6. **Recovery action granularity**: The recovery cards currently offer a single "restart investigation" action. Future engine contracts could support partial recovery (e.g., retry with different parameters, switch models) rather than full restart.
|
||||||
|
|
||||||
7. **Investigation duration tracking**: The summary panel computes elapsed time from `Date.now() - updatedAt`. If the engine emits proper timestamps, the UI can show accurate elapsed duration and investigate stalls (>5 min between turns).
|
7. **Investigation duration tracking**: The summary panel computes elapsed time from `Date.now() - updatedAt`. If the engine emits proper timestamps, the UI can show accurate elapsed duration and investigate stalls (>5 min between turns).
|
||||||
|
|
||||||
|
8. **Layout independence (v0.7 workspace layout phase)**: Reasoning outputs must remain entirely independent of presentation layout. The UI's responsive workspace layout — which progressively reveals simultaneous context on wide screens — is a pure presentation concern. No reasoning contract field should be added, removed, or modified to accommodate layout changes. Future reasoning outputs should carry data semantically; how that data arranges itself visually is the responsibility of the presentation layer alone.
|
||||||
|
|||||||
Reference in New Issue
Block a user