diff --git a/backend/app/api/endpoints/sessions.py b/backend/app/api/endpoints/sessions.py
index 86286b6c..922563b3 100644
--- a/backend/app/api/endpoints/sessions.py
+++ b/backend/app/api/endpoints/sessions.py
@@ -273,6 +273,16 @@ def _generate_markdown_export(session: Session, options: SessionExport) -> str:
lines.append("---")
lines.append("")
+ # Scratchpad / Evidence section
+ scratchpad = getattr(session, 'scratchpad', '') or ''
+ if scratchpad.strip():
+ lines.append("## Evidence / Reference")
+ lines.append("")
+ lines.append(scratchpad)
+ lines.append("")
+ lines.append("---")
+ lines.append("")
+
lines.append("## Troubleshooting Steps")
lines.append("")
@@ -311,6 +321,14 @@ def _generate_text_export(session: Session, options: SessionExport) -> str:
lines.append(f"Completed: {session.completed_at.strftime('%Y-%m-%d %H:%M')}")
lines.append("")
+ # Scratchpad / Evidence section
+ scratchpad = getattr(session, 'scratchpad', '') or ''
+ if scratchpad.strip():
+ lines.append("EVIDENCE / REFERENCE")
+ lines.append("-" * 20)
+ lines.append(scratchpad)
+ lines.append("")
+
lines.append("TROUBLESHOOTING STEPS")
lines.append("-" * 20)
@@ -360,6 +378,12 @@ def _generate_html_export(session: Session, options: SessionExport) -> str:
html.append(f'
Completed: {session.completed_at.strftime("%Y-%m-%d %H:%M")}
')
html.append('')
+ # Scratchpad / Evidence section
+ scratchpad = getattr(session, 'scratchpad', '') or ''
+ if scratchpad.strip():
+ html.append('Evidence / Reference
')
+ html.append(f'{scratchpad}
')
+
html.append('Troubleshooting Steps
')
for i, decision in enumerate(session.decisions, 1):
diff --git a/backend/tests/test_sessions.py b/backend/tests/test_sessions.py
index d7994de4..3ad858bc 100644
--- a/backend/tests/test_sessions.py
+++ b/backend/tests/test_sessions.py
@@ -461,3 +461,145 @@ class TestSessions:
assert response.status_code == 200
assert response.json()["scratchpad"] == "post-resolution notes"
+
+ @pytest.mark.asyncio
+ async def test_export_includes_scratchpad_markdown(
+ self, client: AsyncClient, auth_headers: dict, test_tree: dict
+ ):
+ """Test that markdown export includes scratchpad content."""
+ # Create session with scratchpad
+ create_response = await client.post(
+ "/api/v1/sessions",
+ json={"tree_id": test_tree["id"], "ticket_number": "SP-001"},
+ headers=auth_headers
+ )
+ session_id = create_response.json()["id"]
+
+ # Add scratchpad content
+ await client.patch(
+ f"/api/v1/sessions/{session_id}/scratchpad",
+ json={"scratchpad": "- Server IP: 192.168.1.50\n- Error: 0x80070005"},
+ headers=auth_headers
+ )
+
+ # Export as markdown
+ response = await client.post(
+ f"/api/v1/sessions/{session_id}/export",
+ json={"format": "markdown", "include_tree_info": True},
+ headers=auth_headers
+ )
+
+ assert response.status_code == 200
+ content = response.text
+ assert "## Evidence / Reference" in content
+ assert "192.168.1.50" in content
+ assert "0x80070005" in content
+
+ @pytest.mark.asyncio
+ async def test_export_includes_scratchpad_text(
+ self, client: AsyncClient, auth_headers: dict, test_tree: dict
+ ):
+ """Test that text export includes scratchpad content."""
+ create_response = await client.post(
+ "/api/v1/sessions",
+ json={"tree_id": test_tree["id"]},
+ headers=auth_headers
+ )
+ session_id = create_response.json()["id"]
+
+ await client.patch(
+ f"/api/v1/sessions/{session_id}/scratchpad",
+ json={"scratchpad": "Error code: 12345"},
+ headers=auth_headers
+ )
+
+ response = await client.post(
+ f"/api/v1/sessions/{session_id}/export",
+ json={"format": "text"},
+ headers=auth_headers
+ )
+
+ assert response.status_code == 200
+ content = response.text
+ assert "EVIDENCE / REFERENCE" in content
+ assert "Error code: 12345" in content
+
+ @pytest.mark.asyncio
+ async def test_export_includes_scratchpad_html(
+ self, client: AsyncClient, auth_headers: dict, test_tree: dict
+ ):
+ """Test that HTML export includes scratchpad content."""
+ create_response = await client.post(
+ "/api/v1/sessions",
+ json={"tree_id": test_tree["id"]},
+ headers=auth_headers
+ )
+ session_id = create_response.json()["id"]
+
+ await client.patch(
+ f"/api/v1/sessions/{session_id}/scratchpad",
+ json={"scratchpad": "DNS server: 10.0.0.5"},
+ headers=auth_headers
+ )
+
+ response = await client.post(
+ f"/api/v1/sessions/{session_id}/export",
+ json={"format": "html"},
+ headers=auth_headers
+ )
+
+ assert response.status_code == 200
+ content = response.text
+ assert "Evidence / Reference" in content
+ assert "DNS server: 10.0.0.5" in content
+
+ @pytest.mark.asyncio
+ async def test_export_excludes_empty_scratchpad(
+ self, client: AsyncClient, auth_headers: dict, test_tree: dict
+ ):
+ """Test that export omits scratchpad section when empty."""
+ create_response = await client.post(
+ "/api/v1/sessions",
+ json={"tree_id": test_tree["id"]},
+ headers=auth_headers
+ )
+ session_id = create_response.json()["id"]
+
+ # Export without setting scratchpad
+ response = await client.post(
+ f"/api/v1/sessions/{session_id}/export",
+ json={"format": "markdown"},
+ headers=auth_headers
+ )
+
+ assert response.status_code == 200
+ content = response.text
+ assert "Evidence / Reference" not in content
+
+ @pytest.mark.asyncio
+ async def test_export_excludes_whitespace_only_scratchpad(
+ self, client: AsyncClient, auth_headers: dict, test_tree: dict
+ ):
+ """Test that export omits scratchpad section when only whitespace."""
+ create_response = await client.post(
+ "/api/v1/sessions",
+ json={"tree_id": test_tree["id"]},
+ headers=auth_headers
+ )
+ session_id = create_response.json()["id"]
+
+ await client.patch(
+ f"/api/v1/sessions/{session_id}/scratchpad",
+ json={"scratchpad": " \n \n "},
+ headers=auth_headers
+ )
+
+ response = await client.post(
+ f"/api/v1/sessions/{session_id}/export",
+ json={"format": "markdown"},
+ headers=auth_headers
+ )
+
+ assert response.status_code == 200
+ content = response.text
+ assert "Evidence / Reference" not in content