Rifqi Hafizuddin Claude Fable 5 commited on
Commit
eef6de8
·
1 Parent(s): 4253733

[KM-644] report: drop Notes/Unresolved/Method sections from rendered markdown (compact report)

Browse files

Team decision 2026-07-09: the rendered report drops "Notes & Limitations",
"Attempted, Unresolved", and "How This Was Analyzed" (render blocks commented
out, restorable). JSON body unchanged: caveats/open_questions/unresolved/
method_steps still populate AnalysisReport, so the /records curation flow and
exclude_record_ids semantics are unaffected. "Excluded Analyses" stays.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

API_CONTRACT_BE_PYTHON.md CHANGED
@@ -412,7 +412,7 @@ Response `200`:
412
  ]
413
  ```
414
 
415
- `substantive: false` means no `analyze_*` step succeeded — that run would land under "Attempted, Unresolved" rather than the findings body. If no runs exist, returns `[]`.
416
 
417
  ### `GET /api/v1/tools/report/{analysis_id}/readiness` (added 2026-07-09)
418
 
 
412
  ]
413
  ```
414
 
415
+ `substantive: false` means no `analyze_*` step succeeded — that run is listed in the report's `unresolved` JSON field rather than the findings body. (Since 2026-07-09 the rendered markdown is compact and no longer includes "Attempted, Unresolved" / "Notes & Limitations" / "How This Was Analyzed" sections; the JSON fields `unresolved` / `caveats` / `open_questions` / `method_steps` are unchanged.) If no runs exist, returns `[]`.
416
 
417
  ### `GET /api/v1/tools/report/{analysis_id}/readiness` (added 2026-07-09)
418
 
REPO_STATUS.md CHANGED
@@ -2,7 +2,7 @@
2
 
3
  **Audience:** teammates onboarding onto the Python repo (`Agentic-Service-Data-Eyond-Catalog`).
4
  **Scope:** what the code does **right now** (branch `pr/4`, ticket KM-652). Describes current state only — no roadmap or to-dos.
5
- **Snapshot date:** 2026-06-25. **Data-layer reconcile 2026-07-01:** §8/§12 updated — dedorch cutover done, `data_catalog` model reconciled. **Query-path fix 2026-07-02:** §8/§13 — dedorch catalogs ship no FKs → Python infers them (`fk_inference.py`); shared-Fernet-key gotcha documented. **Agent-quality fixes 2026-07-08 (pr/13):** from the scoped live-test review — the planner gains an explicit **infeasible** outcome (`TaskList.infeasible_reason` → deterministic EN/ID data-gap reply via `refusals.data_gap_message`; no more force-mapping absent measures like `pa` AS "revenue"), the IR validator rejects bare selects under `group_by` (self-corrects via the planner retry), `analyze_trend` handles integer year/month columns (was collapsing every row into one 1970-01 bucket), planner few-shots add top-N (Example G) + infeasible (Example H), numeric catalog `sample_values` are base64-decoded at read (`catalog/sample_decode.py` — stopgap for Go's byte-marshaling; primary fix is Go-side), traceability no longer emits null source rows for failed retrievals, and `check_data` hides `-1` row counts. **Report v2 + analyze_merge planner support 2026-07-09 (pr/13):** Sofia's `analyze_merge` tool (8abf635, KM-703) is now planner-supported (`_validate_data_source` guards `data_right`, two-retrieve→merge few-shot Example I, planner.md "Two measures per entity" rule); the report gains per-business-question answers (`bq_answers` — drafted by the SAME single LLM call, index-based record refs, deterministic fallback unchanged), "Attempted, Unresolved" + "Excluded Analyses" sections (failed runs are no longer silently dropped), evidence tables copied from `results_snapshot` (table-kind outputs, ≤3/record ≤10 rows ≤8 cols, `check_*` skipped), normalized caveat dedupe with caps (12/10), and single-language output via `detect_reply_language`; the report surface adds `GET /tools/report/{analysis_id}/records` (curation list), `GET …/readiness` (FE delta guard), and `exclude_record_ids` on POST — see API_CONTRACT_BE_PYTHON.md. **Cross-repo update 2026-06-29:** §2/§8/§11/§12 re-verified against
6
  the **Go source** (`Orchestrator-Agent-Service`), not its docs. The Go service has moved well past its
7
  own (uncommitted, stale) design docs: it now hosts the **dedorch SQL migrations** in-repo and a full
8
  **`/api/v1/analyses` + `/api/v1/skills`** REST surface. Go does **not** call Python yet — those skills
 
2
 
3
  **Audience:** teammates onboarding onto the Python repo (`Agentic-Service-Data-Eyond-Catalog`).
4
  **Scope:** what the code does **right now** (branch `pr/4`, ticket KM-652). Describes current state only — no roadmap or to-dos.
5
+ **Snapshot date:** 2026-06-25. **Data-layer reconcile 2026-07-01:** §8/§12 updated — dedorch cutover done, `data_catalog` model reconciled. **Query-path fix 2026-07-02:** §8/§13 — dedorch catalogs ship no FKs → Python infers them (`fk_inference.py`); shared-Fernet-key gotcha documented. **Agent-quality fixes 2026-07-08 (pr/13):** from the scoped live-test review — the planner gains an explicit **infeasible** outcome (`TaskList.infeasible_reason` → deterministic EN/ID data-gap reply via `refusals.data_gap_message`; no more force-mapping absent measures like `pa` AS "revenue"), the IR validator rejects bare selects under `group_by` (self-corrects via the planner retry), `analyze_trend` handles integer year/month columns (was collapsing every row into one 1970-01 bucket), planner few-shots add top-N (Example G) + infeasible (Example H), numeric catalog `sample_values` are base64-decoded at read (`catalog/sample_decode.py` — stopgap for Go's byte-marshaling; primary fix is Go-side), traceability no longer emits null source rows for failed retrievals, and `check_data` hides `-1` row counts. **Report v2 + analyze_merge planner support 2026-07-09 (pr/13):** Sofia's `analyze_merge` tool (8abf635, KM-703) is now planner-supported (`_validate_data_source` guards `data_right`, two-retrieve→merge few-shot Example I, planner.md "Two measures per entity" rule); the report gains per-business-question answers (`bq_answers` — drafted by the SAME single LLM call, index-based record refs, deterministic fallback unchanged), "Attempted, Unresolved" + "Excluded Analyses" sections (failed runs are no longer silently dropped), evidence tables copied from `results_snapshot` (table-kind outputs, ≤3/record ≤10 rows ≤8 cols, `check_*` skipped), normalized caveat dedupe with caps (12/10), and single-language output via `detect_reply_language`; the report surface adds `GET /tools/report/{analysis_id}/records` (curation list), `GET …/readiness` (FE delta guard), and `exclude_record_ids` on POST — see API_CONTRACT_BE_PYTHON.md. **Report compaction 2026-07-09 (pr/13):** the rendered markdown drops the "Notes & Limitations", "Attempted, Unresolved", and "How This Was Analyzed" sections (team decision — compact report; render blocks commented out in `report/generator.py`, not deleted). The JSON body keeps `caveats`/`open_questions`/`unresolved`/`method_steps` and the curation/records endpoints are unchanged. **Cross-repo update 2026-06-29:** §2/§8/§11/§12 re-verified against
6
  the **Go source** (`Orchestrator-Agent-Service`), not its docs. The Go service has moved well past its
7
  own (uncommitted, stale) design docs: it now hosts the **dedorch SQL migrations** in-repo and a full
8
  **`/api/v1/analyses` + `/api/v1/skills`** REST surface. Go does **not** call Python yet — those skills
src/agents/report/generator.py CHANGED
@@ -464,23 +464,29 @@ def _render_markdown(report: AnalysisReport) -> str:
464
  )
465
  parts.append("\n".join(lines))
466
 
467
- if report.caveats or report.open_questions:
468
- lines = ["## Notes & Limitations"]
469
- for n in report.caveats:
470
- lines.append(f"- {_mdx_escape(n.text)}")
471
- for n in report.open_questions:
472
- lines.append(f"- Open: {_mdx_escape(n.text)}")
473
- parts.append("\n".join(lines))
474
-
475
- if report.unresolved:
476
- lines = [
477
- "## Attempted, Unresolved",
478
- "*These analyses ran but produced no usable evidence;"
479
- " they are not reflected in the findings above.*",
480
- "",
481
- ]
482
- lines.extend(f"- {_mdx_escape(n.text)}" for n in report.unresolved)
483
- parts.append("\n".join(lines))
 
 
 
 
 
 
484
 
485
  if report.excluded:
486
  lines = [
@@ -491,18 +497,21 @@ def _render_markdown(report: AnalysisReport) -> str:
491
  lines.extend(f"- {_mdx_escape(n.text)}" for n in report.excluded)
492
  parts.append("\n".join(lines))
493
 
494
- if report.method_steps:
495
- lines = ["## How This Was Analyzed"]
496
- for stage_key, label in _STAGE_LABELS:
497
- steps = [s for s in report.method_steps if s.stage == stage_key]
498
- if not steps:
499
- continue
500
- rendered = "; ".join(
501
- f"{', '.join(_mdx_escape(t) for t in s.tools_used) or '—'} ({s.status})"
502
- for s in steps
503
- )
504
- lines.append(f"**{label}** — {rendered}")
505
- parts.append("\n".join(lines))
 
 
 
506
 
507
  return "\n\n---\n\n".join(parts)
508
 
@@ -558,8 +567,9 @@ class ReportGenerator:
558
  kept = [r for r in all_records if r.record_id not in excluded_ids]
559
  # The report body reflects only substantive runs — those with a successful
560
  # analysis step (the same set the report floor validates). Fully-failed runs
561
- # can't contradict the real findings, but they are no longer dropped
562
- # silently: they surface under "Attempted, Unresolved".
 
563
  records = [r for r in kept if has_successful_analysis(r)]
564
  unresolved_records = [r for r in kept if not has_successful_analysis(r)]
565
  if not records:
 
464
  )
465
  parts.append("\n".join(lines))
466
 
467
+ # ## Notes & Limitations — dropped from the rendered report 2026-07-09 (team
468
+ # decision: compact report). caveats/open_questions still populate the
469
+ # AnalysisReport JSON body; only the markdown section is gone.
470
+ # if report.caveats or report.open_questions:
471
+ # lines = ["## Notes & Limitations"]
472
+ # for n in report.caveats:
473
+ # lines.append(f"- {_mdx_escape(n.text)}")
474
+ # for n in report.open_questions:
475
+ # lines.append(f"- Open: {_mdx_escape(n.text)}")
476
+ # parts.append("\n".join(lines))
477
+
478
+ # ## Attempted, Unresolved dropped from the rendered report 2026-07-09 (team
479
+ # decision: compact report). Failed runs still populate `report.unresolved`
480
+ # (JSON body) and the /records curation list; only the markdown section is gone.
481
+ # if report.unresolved:
482
+ # lines = [
483
+ # "## Attempted, Unresolved",
484
+ # "*These analyses ran but produced no usable evidence;"
485
+ # " they are not reflected in the findings above.*",
486
+ # "",
487
+ # ]
488
+ # lines.extend(f"- {_mdx_escape(n.text)}" for n in report.unresolved)
489
+ # parts.append("\n".join(lines))
490
 
491
  if report.excluded:
492
  lines = [
 
497
  lines.extend(f"- {_mdx_escape(n.text)}" for n in report.excluded)
498
  parts.append("\n".join(lines))
499
 
500
+ # ## How This Was Analyzed — dropped from the rendered report 2026-07-09 (team
501
+ # decision: compact report). method_steps (and _STAGE_LABELS above) stay for the
502
+ # AnalysisReport JSON body; only the markdown section is gone.
503
+ # if report.method_steps:
504
+ # lines = ["## How This Was Analyzed"]
505
+ # for stage_key, label in _STAGE_LABELS:
506
+ # steps = [s for s in report.method_steps if s.stage == stage_key]
507
+ # if not steps:
508
+ # continue
509
+ # rendered = "; ".join(
510
+ # f"{', '.join(_mdx_escape(t) for t in s.tools_used) or ''} ({s.status})"
511
+ # for s in steps
512
+ # )
513
+ # lines.append(f"**{label}** — {rendered}")
514
+ # parts.append("\n".join(lines))
515
 
516
  return "\n\n---\n\n".join(parts)
517
 
 
567
  kept = [r for r in all_records if r.record_id not in excluded_ids]
568
  # The report body reflects only substantive runs — those with a successful
569
  # analysis step (the same set the report floor validates). Fully-failed runs
570
+ # can't contradict the real findings, but they are not dropped silently
571
+ # either: they surface in the JSON `unresolved` list and the /records
572
+ # curation endpoint (the rendered markdown section was dropped 2026-07-09).
573
  records = [r for r in kept if has_successful_analysis(r)]
574
  unresolved_records = [r for r in kept if not has_successful_analysis(r)]
575
  if not records:
src/models/api/report.py CHANGED
@@ -24,8 +24,9 @@ class AnalysisRecordEntry(BaseModel):
24
 
25
  The FE shows these before generating so the user can exclude runs
26
  (`exclude_record_ids` on POST /tools/report). `substantive` mirrors the
27
- report's own inclusion rule: non-substantive runs would land under
28
- "Attempted, Unresolved" rather than the findings body.
 
29
  """
30
 
31
  record_id: str = Field(..., description="Id to pass in exclude_record_ids.")
 
24
 
25
  The FE shows these before generating so the user can exclude runs
26
  (`exclude_record_ids` on POST /tools/report). `substantive` mirrors the
27
+ report's own inclusion rule: non-substantive runs land in the report's
28
+ `unresolved` list rather than the findings body (the "Attempted, Unresolved"
29
+ markdown section was dropped 2026-07-09; the JSON field remains).
30
  """
31
 
32
  record_id: str = Field(..., description="Id to pass in exclude_record_ids.")