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 filesTeam 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 +1 -1
- REPO_STATUS.md +1 -1
- src/agents/report/generator.py +41 -31
- src/models/api/report.py +3 -2
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
|
| 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 |
-
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
|
| 471 |
-
|
| 472 |
-
|
| 473 |
-
|
| 474 |
-
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
|
| 481 |
-
|
| 482 |
-
|
| 483 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 495 |
-
|
| 496 |
-
|
| 497 |
-
|
| 498 |
-
|
| 499 |
-
|
| 500 |
-
|
| 501 |
-
|
| 502 |
-
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
|
|
|
|
|
|
|
|
|
|
| 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
|
| 562 |
-
#
|
|
|
|
| 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
|
| 28 |
-
|
|
|
|
| 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.")
|