Stage 0: Report Editing & Display Fixes
Goal
Make reports fully functional for end users who need to edit and present LLM outputs.
Bugs to Fix
Bug #9: Metadata Tab Disappearing
Root Cause:
client/src/features/multi-analysis/hooks/useTabAvailability.js:45-47
const hasMetadata = nonEmpty(results?.topic_patterns) ||
nonEmpty(results?.emotion_patterns) ||
nonEmpty(results?.entity_patterns);
The tab only appears when these 3 specific fields are populated. Reports using custom prompt templates (e.g., PEL GAC persona analyses) produce custom_fields like synthesized_personas instead, causing the tab to never appear.
Evidence from DB:
-- Last 5 multi_analyses all have:
has_topic_patterns: FALSE
has_entity_patterns: FALSE
has_emotion_patterns: FALSE
has_custom_fields: TRUE
Fix: Option A (Quick): Always show Metadata tab when any content exists
const hasMetadata = hasAnyContent(); // Reuse the existing helper
Option B (Better): Rename to “Details” tab and show:
- Input dataset summary (always)
- Pattern charts (when patterns exist)
- Custom fields (when they exist, with better rendering)
Files to Modify:
client/src/features/multi-analysis/hooks/useTabAvailability.jsclient/src/features/multi-analysis/components/tabs/MetadataTab.jsx
Bug #7: Raw JSON Display for Custom Fields
Root Cause:
client/src/features/multi-analysis/components/JsonBlock.jsx
The component categorizes object fields into:
primaryFields: quote, text, content, etc.metadataFields: emotion, speaker_id, etc.
Fields that don’t match (like capability_gaps, design_relevance, emotion_dynamics in synthesized_personas) fall through to “otherFields” and render as JSON.stringify(val).
Example Custom Field Structure:
{
"persona_name": "Urban Micro-venture Optimist",
"capability_gaps": "- Simple bookkeeping...\n- Marketing beyond...",
"design_relevance": "Represents the bulk of potential users...",
"emotion_dynamics": "Optimism spikes when sales flow...",
...10 more fields
}
None of these match the hardcoded patterns.
Fix Options:
Option A (Generic): Improve JsonBlock to render all string fields as prose, not JSON
// In otherFields rendering, check type first
{otherFields.map(({ key, val }) => (
<div key={key} className="text-sm">
<span className="font-medium">{key.replace(/_/g, ' ')}: </span>
{typeof val === 'string' ? (
<span className="whitespace-pre-wrap">{val}</span>
) : (
<span>{JSON.stringify(val)}</span>
)}
</div>
))}
Option B (Smart): Detect common patterns in custom_fields:
- If object has
persona_name, render as persona card - If array of objects with
name/description, render as list cards - Otherwise, render each field as a labeled section
Option C (Schema-driven): Use the prompt template’s response_format.json_schema to guide rendering
Recommendation: Start with Option A (quick win), then Option B for known patterns.
Files to Modify:
client/src/features/multi-analysis/components/JsonBlock.jsx- Possibly create
PersonaCard.jsx,GenericFieldRenderer.jsx
Bug #8: Custom Fields Not Editable
Root Cause:
client/src/features/multi-analysis/components/tabs/OverviewTab.jsx:140-146
{getCustomFields(results).map(([key, value]) => (
<JsonBlock
key={key}
title={formatKeyName(key)}
value={value}
/>
))}
JsonBlock is display-only. Standard fields have dedicated edit handlers:
state.editFields.executive_synthesisstate.editRecommendationsstate.editOrgHealth- etc.
Custom fields have no equivalent.
Fix Options:
Option A (Text editing): For each custom field, allow editing the JSON as text
{state.isEditing ? (
<Textarea
value={JSON.stringify(value, null, 2)}
onChange={(e) => updateCustomField(key, JSON.parse(e.target.value))}
/>
) : (
<JsonBlock value={value} />
)}
- Pro: Simple, works for all shapes
- Con: Users must edit JSON directly
Option B (Field-level editing): For string fields within objects, render as editable inputs
// For each persona object:
<input value={persona.persona_name} onChange={...} />
<textarea value={persona.capability_gaps} onChange={...} />
- Pro: Better UX
- Con: Only works for known structures
Option C (Monaco editor): Use Monaco with JSON validation
- Pro: Syntax highlighting, validation
- Con: Still requires JSON knowledge
Recommendation:
- Start with Option A (JSON textarea) as baseline
- Add Option B for
synthesized_personasspecifically (high-value use case)
Backend Changes:
The PUT /analyze/multi/{id} endpoint already accepts custom_fields updates:
# api/src/routers/analyses.py
class MultiAnalysisUpdate(BaseModel):
custom_fields: Optional[Dict[str, Any]] = None
No backend changes needed.
Files to Modify:
client/src/features/multi-analysis/components/JsonBlock.jsx(add edit mode)client/src/features/multi-analysis/hooks/useMultiAnalysisState.js(add edit state for custom fields)client/src/features/multi-analysis/components/tabs/OverviewTab.jsx(wire up editing)
Implementation Order
- Bug #9 first - Quick fix, high visibility (tab appears/disappears)
- Bug #7 second - Improves readability immediately
- Bug #8 third - Requires more state management work
Demo Criteria
User opens a completed multi-analysis report with custom fields (e.g., “Women Persona Analysis for PEL GAC”).
- All tabs appear (including Metadata/Details)
- Custom sections like “Synthesized Personas” render with readable formatting:
- Persona name as heading
- Each field as labeled paragraph, not JSON
- User clicks Edit on a custom section
- User modifies text (e.g., persona description)
- User saves - change persists
- Page refresh shows updated content
Testing Notes
Use these existing reports for testing:
f386393e-8e3f-4815-b2d2-7c63ccb8ce76- Women Persona Analysisd80062a9-3c6b-4a95-b754-db148f5045a2- Men Persona Analysis
Both have custom_fields with synthesized_personas (array of 5 persona objects) and persona_landscape_summary (string).