sofhiaazzhr Claude Opus 4.8 commited on
Commit
6a3b169
Β·
1 Parent(s): 61ab293

[KM-680] feat(report): markdown section separators + inline emphasis in summary

Browse files

- Render a horizontal rule (---) between the header and each report section so it reads as a formal, sectioned document.
- Relax report_summary.md: the executive summary MAY use inline **bold**/*italic* for emphasis (kept no-headings/no-bullets so it doesn't duplicate the section structure or Key Findings).
- Tables / bold (method labels) / italic (meta + citations) were already emitted. Closes DEV_PLAN #23.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

DEV_PLAN.md CHANGED
@@ -132,7 +132,7 @@ Status legend: ⬜ not started Β· πŸ”„ in progress Β· βœ… done Β· β›” blocked Β·
132
  | 20 | **Help handoff:** update `handlers/help.py` + `help.md` β€” drop the `problem_validated` tier + `define_problem_statement` action (the skill it points at is gone as of #1) | Sofhia | βœ… | Done 2026-06-25. `help.py`: actions = `ask_analysis_question` (always) + `generate_report` (if ready); renders objective/business_questions (getattr-tolerant). `help.md` v1β†’v2: 3 tiers, no `/problem_statement`, `/generate report`β†’`/report`. Local test_help updated β†’ 11 pass |
133
  | 21 | Rename `analysis_records` β†’ **`agent_observability`** (model, `slow_path/store.py`, readers, `init_db`) | Rifqi | ⬜ new | Checkpoint: no "record" in the name (clashes w/ Go `analysis_message`). Confirm write scope: every agent call vs slow-path-only |
134
  | 22 | Finalize `agent_observability` schema β†’ hand to Harry for the dedorch migration/startup | Rifqi β†’ Harry | ⬜ new | Resolves #16 (table created post-cutover). Python still creates it locally until then |
135
- | 23 | Report markdown formatting: tables, **bold**, *italic*, horizontal separators | Sofhia | πŸ”„ new | Renderer already emits `##`/`**`/tables; verify italic + `---` separators + that the LLM summary keeps formatting. Minimum bar before charts |
136
  | 24 | Clarify report input contract: records table (+ `last_report` for edit mode?) | Rifqi/Sofhia ↔ Harry | ⬜ new | Edit-mode input left open at the checkpoint |
137
  | 25 | Confirm Python history source = Go `analysis_message` | Rifqi ↔ Harry | ⬜ new | New chat-room table (Q + A); replaces `chat_messages` for analyses |
138
  | 26 | **Charts (DEFERRED):** store Plotly JSON in a future `chart` table (not matplotlib PNG) | β€” | ⏸️ | After the markdown path is done end-to-end |
 
132
  | 20 | **Help handoff:** update `handlers/help.py` + `help.md` β€” drop the `problem_validated` tier + `define_problem_statement` action (the skill it points at is gone as of #1) | Sofhia | βœ… | Done 2026-06-25. `help.py`: actions = `ask_analysis_question` (always) + `generate_report` (if ready); renders objective/business_questions (getattr-tolerant). `help.md` v1β†’v2: 3 tiers, no `/problem_statement`, `/generate report`β†’`/report`. Local test_help updated β†’ 11 pass |
133
  | 21 | Rename `analysis_records` β†’ **`agent_observability`** (model, `slow_path/store.py`, readers, `init_db`) | Rifqi | ⬜ new | Checkpoint: no "record" in the name (clashes w/ Go `analysis_message`). Confirm write scope: every agent call vs slow-path-only |
134
  | 22 | Finalize `agent_observability` schema β†’ hand to Harry for the dedorch migration/startup | Rifqi β†’ Harry | ⬜ new | Resolves #16 (table created post-cutover). Python still creates it locally until then |
135
+ | 23 | Report markdown formatting: tables, **bold**, *italic*, horizontal separators | Sofhia | βœ… | Done 2026-06-25. Added `---` separators between header + each section in `_render_markdown`. Tables (EDA) / bold (method labels) / italic (meta + citations) already emitted. Relaxed `report_summary.md` to allow inline `**bold**`/`*italic*` for emphasis (kept no-headings/no-bullets so it doesn't duplicate the section structure / Key Findings). Compile + ruff clean |
136
  | 24 | Clarify report input contract: records table (+ `last_report` for edit mode?) | Rifqi/Sofhia ↔ Harry | ⬜ new | Edit-mode input left open at the checkpoint |
137
  | 25 | Confirm Python history source = Go `analysis_message` | Rifqi ↔ Harry | ⬜ new | New chat-room table (Q + A); replaces `chat_messages` for analyses |
138
  | 26 | **Charts (DEFERRED):** store Plotly JSON in a future `chart` table (not matplotlib PNG) | β€” | ⏸️ | After the markdown path is done end-to-end |
src/agents/report/generator.py CHANGED
@@ -185,13 +185,14 @@ def _build_human_content(
185
  def _render_markdown(report: AnalysisReport) -> str:
186
  # Version is deliberately NOT in the markdown β€” it is assigned by the store
187
  # after rendering and lives in the structured `version` field / API metadata.
188
- parts: list[str] = ["# Analysis Report"]
189
  meta = f"*Generated {report.generated_at:%Y-%m-%d}"
190
  author = report.user_name or report.user_id
191
  if author:
192
  meta += f" by {author}"
193
  meta += f" Β· {len(report.record_ids)} analyses Β· {len(report.data_sources)} source(s)*"
194
- parts.append(meta)
 
 
195
 
196
  ps = report.problem_statement
197
  if ps.objective:
@@ -248,7 +249,7 @@ def _render_markdown(report: AnalysisReport) -> str:
248
  lines.append(f"**{label}** β€” {rendered}")
249
  parts.append("\n".join(lines))
250
 
251
- return "\n\n".join(parts)
252
 
253
 
254
  # --------------------------------------------------------------------------- #
 
185
  def _render_markdown(report: AnalysisReport) -> str:
186
  # Version is deliberately NOT in the markdown β€” it is assigned by the store
187
  # after rendering and lives in the structured `version` field / API metadata.
 
188
  meta = f"*Generated {report.generated_at:%Y-%m-%d}"
189
  author = report.user_name or report.user_id
190
  if author:
191
  meta += f" by {author}"
192
  meta += f" Β· {len(report.record_ids)} analyses Β· {len(report.data_sources)} source(s)*"
193
+ # Title + meta form the header block; each subsequent section is divided by a
194
+ # horizontal rule (`---`) so the report reads as a formal, sectioned document.
195
+ parts: list[str] = ["# Analysis Report\n" + meta]
196
 
197
  ps = report.problem_statement
198
  if ps.objective:
 
249
  lines.append(f"**{label}** β€” {rendered}")
250
  parts.append("\n".join(lines))
251
 
252
+ return "\n\n---\n\n".join(parts)
253
 
254
 
255
  # --------------------------------------------------------------------------- #
src/config/prompts/report_summary.md CHANGED
@@ -7,4 +7,5 @@ Rules:
7
  - Do NOT introduce any number, fact, or claim that is not present in the findings. You are summarizing, not analyzing.
8
  - Do NOT simply restate every finding; connect them into a narrative and say what they mean for the objective.
9
  - If the findings are thin or inconclusive, say so plainly rather than overstating.
10
- - Plain business language, prose only β€” no headings, no bullet lists.
 
 
7
  - Do NOT introduce any number, fact, or claim that is not present in the findings. You are summarizing, not analyzing.
8
  - Do NOT simply restate every finding; connect them into a narrative and say what they mean for the objective.
9
  - If the findings are thin or inconclusive, say so plainly rather than overstating.
10
+ - Plain business language. Write **prose only β€” no headings, no bullet lists** (the report already supplies the section structure and a Key Findings list below this summary; do not duplicate them).
11
+ - You MAY use light inline markdown for emphasis within the prose β€” `**bold**` for the most decision-relevant figure or term, `*italic*` sparingly. Keep it subtle; do not bold whole sentences.