Spaces:
Running on Zero
Running on Zero
| """ | |
| NAH-13 — weak-topic targeting: next_card biases toward low-average-grade topics. | |
| No model needed (pure scheduling logic). Run: python3 test_weak_topic.py | |
| """ | |
| import learning_engine as le | |
| from schema import new_card | |
| def _deck(): | |
| return [ | |
| new_card("strong q1", "a", topic="Algebra", card_id="alg1"), | |
| new_card("strong q2", "a", topic="Algebra", card_id="alg2"), | |
| new_card("weak q1", "a", topic="Geometry", card_id="geo1"), | |
| new_card("weak q2", "a", topic="Geometry", card_id="geo2"), | |
| ] | |
| def test_no_history_keeps_order(): | |
| s = le.init_session(_deck()) | |
| # No answers yet -> serve the queue head untouched. | |
| assert le.next_card(s)["id"] == "alg1" | |
| assert s["queue"][0] == "alg1" | |
| print("ok no history -> normal queue order") | |
| def test_weak_topic_surfaces_first(): | |
| s = le.init_session(_deck()) | |
| # Simulate: aced Algebra, bombed Geometry. | |
| s["history"] = [ | |
| {"card_id": "alg1", "topic": "Algebra", "grade": 5, "user_answer": ""}, | |
| {"card_id": "geo1", "topic": "Geometry", "grade": 1, "user_answer": ""}, | |
| ] | |
| # Queue still leads with an Algebra card, but a weak Geometry card is in reach. | |
| s["queue"] = ["alg2", "geo2", "alg1"] | |
| card = le.next_card(s) | |
| assert card["topic"] == "Geometry", f"expected weak topic first, got {card}" | |
| assert s["queue"][0] == card["id"], "chosen card must be rotated to the front" | |
| print("ok weak topic (Geometry) surfaced ahead of strong topic") | |
| def test_lookahead_window_respected(): | |
| s = le.init_session(_deck()) | |
| s["history"] = [{"card_id": "geo1", "topic": "Geometry", "grade": 0, "user_answer": ""}] | |
| # Weak Geometry card sits beyond the lookahead window -> not pulled forward. | |
| s["queue"] = ["alg1", "alg2", "alg2", "alg1", "geo2"] | |
| le.WEAK_LOOKAHEAD # window is 4; geo2 is at index 4 | |
| card = le.next_card(s) | |
| assert card["topic"] == "Algebra", "weak card outside window should not jump" | |
| print("ok weak card beyond lookahead window left in place") | |
| def test_apply_result_contract_holds(): | |
| # next_card rotates the served card to front; apply_result pops the front. | |
| s = le.init_session(_deck()) | |
| s["history"] = [{"card_id": "geo1", "topic": "Geometry", "grade": 1, "user_answer": ""}] | |
| s["queue"] = ["alg1", "geo2"] | |
| card = le.next_card(s) | |
| assert card["id"] == "geo2" | |
| before = len(s["queue"]) | |
| le.apply_result(s, card, {"score": 4, "correct": True, | |
| "explanation": "", "missed_concept": ""}) | |
| assert "geo2" not in s["queue"][:1], "served card should be popped from front" | |
| assert len(s["queue"]) == before, "popped one, re-inserted one" | |
| print("ok apply_result still pops the served card from the front") | |
| if __name__ == "__main__": | |
| test_no_history_keeps_order() | |
| test_weak_topic_surfaces_first() | |
| test_lookahead_window_respected() | |
| test_apply_result_contract_holds() | |
| print("\nAll NAH-13 weak-topic tests passed.") | |