- Add read_discovery_answers() to parse discovery-log.md rows into dicts with low_confidence and needs_followup boolean flags. - Add append_followup_answer() to append follow-up rows linked to original Q-A IDs. - Add 'ask-more' CLI command that detects Low-confidence and Follow-up-needed answers, prompts for additional details, and records them in the log. - Add 6 tests: read_discovery_answers round-trip, empty-log handling, low-confidence detection, follow-up flag detection, and append_followup.
211 lines
6.4 KiB
Python
211 lines
6.4 KiB
Python
from pathlib import Path
|
|
|
|
import rdb_discovery.discovery as discovery_mod
|
|
|
|
|
|
def test_core_questions_returns_10_items() -> None:
|
|
questions = discovery_mod.core_questions()
|
|
assert len(questions) == 10
|
|
|
|
|
|
def test_append_creates_file_when_missing(tmp_path: Path) -> None:
|
|
log_path = tmp_path / "context" / "discovery-log.md"
|
|
assert not log_path.exists()
|
|
|
|
discovery_mod.append_discovery_answer(
|
|
tmp_path,
|
|
question_id="Q-001",
|
|
question="What problem are we solving?",
|
|
answer="A great app",
|
|
confidence="High",
|
|
follow_up_needed="No",
|
|
)
|
|
|
|
assert log_path.exists()
|
|
|
|
|
|
def test_append_records_all_fields(tmp_path: Path) -> None:
|
|
discovery_mod.append_discovery_answer(
|
|
tmp_path,
|
|
question_id="Q-001",
|
|
question="What problem are we solving?",
|
|
answer="A great app",
|
|
confidence="High",
|
|
follow_up_needed="No",
|
|
)
|
|
|
|
content = (tmp_path / "context" / "discovery-log.md").read_text(encoding="utf-8")
|
|
assert "| Q-001 |" in content
|
|
assert "What problem are we solving?" in content
|
|
assert "A great app" in content
|
|
assert "High" in content
|
|
assert "No" in content
|
|
|
|
|
|
def test_append_escapes_pipe_in_answer(tmp_path: Path) -> None:
|
|
discovery_mod.append_discovery_answer(
|
|
tmp_path,
|
|
question_id="Q-001",
|
|
question="What | is this?",
|
|
answer="A | B",
|
|
confidence="High",
|
|
follow_up_needed="No",
|
|
)
|
|
|
|
content = (tmp_path / "context" / "discovery-log.md").read_text(encoding="utf-8")
|
|
# Piped answers should be escaped so the table row doesn't break
|
|
assert "\\|" in content
|
|
|
|
|
|
def test_append_escapes_newline_in_answer(tmp_path: Path) -> None:
|
|
discovery_mod.append_discovery_answer(
|
|
tmp_path,
|
|
question_id="Q-001",
|
|
question="Multi\nline?",
|
|
answer="A\nB\nC",
|
|
confidence="High",
|
|
follow_up_needed="No",
|
|
)
|
|
|
|
content = (tmp_path / "context" / "discovery-log.md").read_text(encoding="utf-8")
|
|
# Data rows should each be a single line — no embedded newlines
|
|
data_lines = [l for l in content.splitlines() if l.startswith("| Q-")]
|
|
assert len(data_lines) == 1
|
|
assert "\n" not in data_lines[0]
|
|
|
|
|
|
def test_append_preserves_existing_history(tmp_path: Path) -> None:
|
|
log_path = tmp_path / "context" / "discovery-log.md"
|
|
|
|
discovery_mod.append_discovery_answer(
|
|
tmp_path,
|
|
question_id="Q-001",
|
|
question="First?",
|
|
answer="Ans 1",
|
|
confidence="High",
|
|
follow_up_needed="No",
|
|
)
|
|
|
|
assert log_path.read_text(encoding="utf-8").count("Ans 1") == 1
|
|
|
|
discovery_mod.append_discovery_answer(
|
|
tmp_path,
|
|
question_id="Q-002",
|
|
question="Second?",
|
|
answer="Ans 2",
|
|
confidence="Low",
|
|
follow_up_needed="Yes",
|
|
)
|
|
|
|
content = log_path.read_text(encoding="utf-8")
|
|
assert "Ans 1" in content
|
|
assert "Ans 2" in content
|
|
# Two data rows, not one
|
|
data_rows = [l for l in content.splitlines() if l.startswith("| Q-")]
|
|
assert len(data_rows) == 2
|
|
|
|
|
|
def test_read_discovery_answers_returns_dicts(tmp_path: Path) -> None:
|
|
discovery_mod.append_discovery_answer(
|
|
tmp_path,
|
|
question_id="Q-001",
|
|
question="What is this?",
|
|
answer="A thing",
|
|
confidence="High",
|
|
follow_up_needed="No",
|
|
)
|
|
|
|
answers = discovery_mod.read_discovery_answers(tmp_path)
|
|
assert len(answers) == 1
|
|
assert answers[0]["id"] == "Q-001"
|
|
assert answers[0]["question"] == "What is this?"
|
|
assert answers[0]["answer"] == "A thing"
|
|
assert answers[0]["confidence"] == "High"
|
|
assert answers[0]["follow_up_needed"] == "No"
|
|
assert answers[0]["needs_followup"] is False
|
|
assert answers[0]["low_confidence"] is False
|
|
|
|
|
|
def test_read_discovery_answers_returns_empty_when_no_log(tmp_path: Path) -> None:
|
|
log_path = tmp_path / "context" / "discovery-log.md"
|
|
assert not log_path.exists()
|
|
|
|
answers = discovery_mod.read_discovery_answers(tmp_path)
|
|
assert answers == []
|
|
|
|
|
|
def test_read_discovery_answers_detects_low_confidence(tmp_path: Path) -> None:
|
|
discovery_mod.append_discovery_answer(
|
|
tmp_path,
|
|
question_id="Q-002",
|
|
question="How much?",
|
|
answer="About half",
|
|
confidence="Low",
|
|
follow_up_needed="No",
|
|
)
|
|
|
|
answers = discovery_mod.read_discovery_answers(tmp_path)
|
|
low_conf_rows = [a for a in answers if a["low_confidence"]]
|
|
assert len(low_conf_rows) == 1
|
|
assert low_conf_rows[0]["id"] == "Q-002"
|
|
|
|
|
|
def test_read_discovery_answers_detects_followup_flag(tmp_path: Path) -> None:
|
|
discovery_mod.append_discovery_answer(
|
|
tmp_path,
|
|
question_id="Q-003",
|
|
question="What next?",
|
|
answer="TBD",
|
|
confidence="High",
|
|
follow_up_needed="Yes",
|
|
)
|
|
|
|
answers = discovery_mod.read_discovery_answers(tmp_path)
|
|
fu_rows = [a for a in answers if a["needs_followup"]]
|
|
assert len(fu_rows) == 1
|
|
assert fu_rows[0]["id"] == "Q-003"
|
|
|
|
|
|
def test_append_followup_appends_row(tmp_path: Path) -> None:
|
|
# First create the log with an existing entry
|
|
discovery_mod.append_discovery_answer(
|
|
tmp_path,
|
|
question_id="Q-010",
|
|
question="Original?",
|
|
answer="Original answer",
|
|
confidence="High",
|
|
follow_up_needed="No",
|
|
)
|
|
|
|
original_count = len(discovery_mod.read_discovery_answers(tmp_path))
|
|
|
|
discovery_mod.append_followup_answer(
|
|
tmp_path,
|
|
question_id="Q-010",
|
|
follow_up_question="Can you elaborate?",
|
|
answer="Yes, it's bigger than expected.",
|
|
confidence="Medium",
|
|
)
|
|
|
|
answers = discovery_mod.read_discovery_answers(tmp_path)
|
|
assert len(answers) == original_count + 1
|
|
# The new row should have the original Q-010 id and follow-up data
|
|
new_row = [a for a in answers if a["question"] == "Can you elaborate?"][0]
|
|
assert new_row["follow_up_needed"] == "Yes"
|
|
assert new_row["confidence"] == "Medium"
|
|
|
|
|
|
def test_header_is_written_on_create(tmp_path: Path) -> None:
|
|
discovery_mod.append_discovery_answer(
|
|
tmp_path,
|
|
question_id="Q-001",
|
|
question="Test?",
|
|
answer="T",
|
|
confidence="High",
|
|
follow_up_needed="No",
|
|
)
|
|
|
|
content = (tmp_path / "context" / "discovery-log.md").read_text(encoding="utf-8")
|
|
assert "# Discovery Log" in content
|
|
assert "| ID | Question | Answer | Confidence | Follow-up needed | Linked decision | Linked task | Date |" in content
|