From 32547dfe000bdc70eec40a1fbc608fa4476deee1 Mon Sep 17 00:00:00 2001 From: welsberr Date: Fri, 8 May 2026 14:27:10 -0400 Subject: [PATCH] Use Notebook signals in learner workbench --- src/didactopus/learner_workbench.py | 23 +++++++++++++++++++++++ tests/test_learner_workbench.py | 13 +++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/didactopus/learner_workbench.py b/src/didactopus/learner_workbench.py index 8468617..b9cb826 100755 --- a/src/didactopus/learner_workbench.py +++ b/src/didactopus/learner_workbench.py @@ -34,12 +34,18 @@ def _load_groundrecall_summary(pack_dir: Path) -> dict: } ) top_rationales = [str(item.get("rationale", "")).strip() for item in review_candidates if str(item.get("rationale", "")).strip()][:3] + source_role_summary = payload.get("source_role_summary", {}) or {} + key_distinctions = payload.get("key_distinctions", []) or [] + secondary_products = payload.get("review_context", {}).get("secondary_products", {}) if isinstance(payload.get("review_context"), dict) else {} return { "concept_id": concept.get("concept_id", ""), "concept_title": concept.get("title", ""), "review_candidate_count": len(review_candidates), "graph_codes": graph_codes, "top_rationales": top_rationales, + "source_role_summary": source_role_summary, + "key_distinctions": key_distinctions[:5], + "secondary_products": secondary_products, } @@ -95,6 +101,23 @@ def _groundrecall_block(summary: dict) -> str: graph_codes = summary.get("graph_codes", []) or [] if graph_codes: lines.append(f"- Structural signals: {', '.join(graph_codes)}") + source_role_summary = summary.get("source_role_summary", {}) or {} + if source_role_summary: + lines.append( + "- Source roles: " + + ", ".join(f"{role}={count}" for role, count in sorted(source_role_summary.items())) + ) + for item in summary.get("key_distinctions", []) or []: + text = str(item.get("text", "")).strip() + distinction_type = str(item.get("distinction_type", "")).strip() + if text: + lines.append(f"- Distinction ({distinction_type or 'contrast'}): {text}") + secondary_products = summary.get("secondary_products", {}) or {} + if secondary_products: + lines.append( + "- Secondary review products: " + + ", ".join(f"{key}={value}" for key, value in sorted(secondary_products.items()) if value) + ) for rationale in summary.get("top_rationales", []) or []: lines.append(f"- Review cue: {rationale}") return "\n".join(lines) diff --git a/tests/test_learner_workbench.py b/tests/test_learner_workbench.py index c11e212..eeab3c4 100755 --- a/tests/test_learner_workbench.py +++ b/tests/test_learner_workbench.py @@ -62,6 +62,15 @@ def test_build_pack_workbench_session_includes_groundrecall_context(monkeypatch, { "bundle_kind": "groundrecall_query_bundle", "concept": {"concept_id": "concept::question-framing", "title": "Question Framing"}, + "source_role_summary": {"overview": 1, "argumentation": 1}, + "key_distinctions": [ + { + "claim_id": "clm_001", + "distinction_type": "non_implication", + "cue": "does not imply", + "text": "A guiding question does not imply a settled interpretation.", + } + ], "review_candidates": [ { "candidate_id": "concept::question-framing", @@ -88,4 +97,8 @@ def test_build_pack_workbench_session_includes_groundrecall_context(monkeypatch, assert payload["groundrecall"]["review_candidate_count"] == 1 assert payload["groundrecall"]["graph_codes"] == ["bridge_concept"] + assert payload["groundrecall"]["source_role_summary"]["overview"] == 1 + assert payload["groundrecall"]["key_distinctions"][0]["distinction_type"] == "non_implication" assert "GroundRecall context:" in payload["mentor"]["text"] + assert "Source roles:" in payload["mentor"]["text"] + assert "Distinction" in payload["mentor"]["text"]