test_brief.py
Language Python22.3 KB508 lines
#!/usr/bin/env python3"""Tests for brief.py. Offline: no network, no credentials, no model.python3 -m unittest discover -s analysis -vEvery case below states the failure it prevents rather than restating therule. The failures that matter here are silent ones: a briefing that rendersempty, or cut off, with nothing saying why.Following the same convention as the TypeScript suite, these assert properties(it raised, the message carries the stop_reason) rather than exact wording: atest that matches on message text can pin a wrong diagnosis in place."""from __future__ import annotationsimport ioimport jsonimport sysimport tempfileimport unittestfrom pathlib import Pathfrom unittest import mocksys.path.insert(0, str(Path(__file__).resolve().parent))import brief # noqa: E402def response(body: dict) -> mock.MagicMock:"""A stand-in for the urlopen context manager."""res = mock.MagicMock()res.read.return_value = json.dumps(body).encode()res.__enter__.return_value = resres.__exit__.return_value = Falsereturn resdef anthropic(**over) -> dict:base = {"content": [{"type": "text", "text": "A briefing."}],"stop_reason": "end_turn","usage": {"input_tokens": 100, "output_tokens": 20},}base.update(over)return basedef call(body: dict, max_tokens: int = 4000):with mock.patch("urllib.request.urlopen", return_value=response(body)):return brief.call_model("https://api.anthropic.com/v1", "claude-opus-5", "sys", "usr","key", 30, "anthropic", max_tokens,)PAYLOAD = {"schemaVersion": "1.0.0","people": [{"name": "Nora Lindqvist"}, {"name": "Sam Whitaker"}],}class NoTextBlockRaises(unittest.TestCase):"""Joining the text blocks of a response that has none returns "", which wouldbe written to briefings.json and rendered as a heading with nothing underit: a silent failure in the one project built to eliminate them."""def test_raises_rather_than_returning_empty(self):with self.assertRaises(brief.EmptyResponseError):call(anthropic(content=[]))def test_raises_when_only_non_text_blocks_came_back(self):with self.assertRaises(brief.EmptyResponseError):call(anthropic(content=[{"type": "thinking", "thinking": "..."}]))def test_raises_on_whitespace_only_text(self):with self.assertRaises(brief.EmptyResponseError):call(anthropic(content=[{"type": "text", "text": " \n "}]))def test_message_names_the_model_and_the_stop_reason(self):# The handoff asked for both by name: without them the error says a# briefing failed but not what the API reported about it.with self.assertRaises(brief.EmptyResponseError) as caught:call(anthropic(content=[], stop_reason="max_tokens"))msg = str(caught.exception)self.assertIn("claude-opus-5", msg)self.assertIn("max_tokens", msg)def test_message_names_the_block_types_that_did_come_back(self):with self.assertRaises(brief.EmptyResponseError) as caught:call(anthropic(content=[{"type": "thinking", "thinking": "..."}]))self.assertIn("thinking", str(caught.exception))def test_does_not_assert_an_unobserved_cause(self):# Report what was observed, not a guessed cause (rule 1). Whether# reasoning consumed the budget is inferred, not observed, so it may be# offered as a candidate but never stated as the cause.with self.assertRaises(brief.EmptyResponseError) as caught:call(anthropic(content=[], stop_reason="max_tokens"))msg = str(caught.exception).lower()self.assertIn("candidates", msg)for claim in ("most likely", "must be", "because the model"):self.assertNotIn(claim, msg)class TruncationIsReportedNotDiscarded(unittest.TestCase):"""A brief cut mid-word at the output limit must not be written to the pagewith no indication it is incomplete.Truncated-and-labelled beats absent. The text is kept andthe caller is told, rather than the brief being thrown away."""def test_keeps_the_text(self):text, _, _ = call(anthropic(content=[{"type": "text", "text": "Half a sen"}], stop_reason="max_tokens"))self.assertEqual(text, "Half a sen")def test_surfaces_the_stop_reason_so_the_caller_can_label_it(self):_, _, stop = call(anthropic(stop_reason="max_tokens"))self.assertEqual(stop, "max_tokens")self.assertIn(stop, brief.TRUNCATED_STOPS)def test_a_complete_brief_is_not_flagged(self):_, _, stop = call(anthropic(stop_reason="end_turn"))self.assertNotIn(stop, brief.TRUNCATED_STOPS)class UsageIsReadFromTheResponse(unittest.TestCase):def test_exact_token_counts_not_estimates(self):_, usage, _ = call(anthropic(usage={"input_tokens": 1984, "output_tokens": 430}))self.assertEqual(usage, {"input": 1984, "output": 430})class OpenAiBranchFailsTheSameWay(unittest.TestCase):"""The OpenAI-compatible path indexed ["choices"][0] directly, so a malformedresponse raised KeyError -- which says nothing about what went wrong. It getsthe same contract as the Anthropic path: raise, and say what came back."""def openai(self, body: dict):with mock.patch("urllib.request.urlopen", return_value=response(body)):return brief.call_model("http://127.0.0.1:1234/v1", "qwen3", "s", "u",None, 30, "openai", 4000)def test_no_choices_raises_something_informative(self):with self.assertRaises(brief.EmptyResponseError):self.openai({"error": "model not loaded"})def test_empty_message_raises(self):with self.assertRaises(brief.EmptyResponseError):self.openai({"choices": [{"message": {"content": ""}}]})def test_length_finish_reason_counts_as_truncated(self):_, _, stop = self.openai({"choices": [{"message": {"content": "Half a sen"}, "finish_reason": "length"}],"usage": {"prompt_tokens": 10, "completion_tokens": 5},})self.assertIn(stop, brief.TRUNCATED_STOPS)class AllIncludesTheCompanyBrief(unittest.TestCase):"""surfaces.ts gates the entire "Written briefing" card on the `company` key,with the leadership view nested inside it. An --all run without `company`would generate every brief while the board showed "Not generated for thissync", leadership included."""def test_all_generates_a_company_brief(self):keys = [j.key for j in brief.build_jobs(PAYLOAD, all_=True, person=None, view="standard")]self.assertIn("company", keys)def test_all_generates_exec_and_every_person(self):keys = [j.key for j in brief.build_jobs(PAYLOAD, all_=True, person=None, view="standard")]self.assertIn("exec", keys)for p in PAYLOAD["people"]:self.assertIn(p["name"], keys)def test_every_key_the_page_reads_is_covered(self):# The three shapes surfaces.ts looks up: `company` for the main card,# `exec` for the disclosure, and a person's roster name for "My day".keys = set(j.key for j in brief.build_jobs(PAYLOAD, all_=True, person=None, view="standard"))self.assertTrue({"company", "exec", "Nora Lindqvist"} <= keys)def test_no_duplicate_keys(self):keys = [j.key for j in brief.build_jobs(PAYLOAD, all_=True, person=None, view="standard")]self.assertEqual(len(keys), len(set(keys)))def test_a_single_person_run_writes_only_that_person(self):jobs = brief.build_jobs(PAYLOAD, all_=False, person="Sam Whitaker", view="standard")self.assertEqual([j.key for j in jobs], ["Sam Whitaker"])def test_exec_view_alone_keys_as_exec(self):jobs = brief.build_jobs(PAYLOAD, all_=False, person=None, view="exec")self.assertEqual([j.key for j in jobs], ["exec"])class BudgetsAreNotOneNumberForEverything(unittest.TestCase):"""A single max_tokens of 800 covered a ~2k-token exec prompt and a ~6.7k-tokencompany prompt alike, and both ran out. Each kind of brief carries its own."""def test_every_job_resolves_to_a_known_budget(self):for job in brief.build_jobs(PAYLOAD, all_=True, person=None, view="standard"):self.assertIn(job.budget, brief.MAX_TOKENS)def test_people_share_one_budget_rather_than_one_each(self):jobs = brief.build_jobs(PAYLOAD, all_=True, person=None, view="standard")people = [j for j in jobs if not j.key.startswith("company") and j.key != "exec"]self.assertTrue(people)for j in people:self.assertEqual(j.budget, "person")def test_the_all_hands_brief_is_priced_as_a_company_brief(self):# Same view over a slightly smaller payload. Priced as a person's brief it# would truncate: company measured 1715 output tokens against person 1029.jobs = brief.build_jobs(PAYLOAD, all_=True, person=None, view="standard")allhands = next(j for j in jobs if j.key == "company-allhands")self.assertEqual(allhands.budget, "company")def test_the_old_default_is_gone(self):# An 800-token ceiling truncates live briefings.for kind, budget in brief.MAX_TOKENS.items():self.assertGreater(budget, 800, kind)def test_every_budget_clears_what_was_measured_with_room_to_spare(self):# Live output_tokens from the run the budgets were set from.# A budget that merely equalled these would truncate on a busier day.measured = {"exec": 872, "company": 1715, "person": 1029}for kind, observed in measured.items():self.assertGreater(brief.MAX_TOKENS[kind], observed * 2, kind)def test_company_gets_the_largest_budget(self):# Exec, the most constrained prompt, might be expected to need the most.# Measured, company needs the most by a wide margin. This pins the# measurement, not the guess.self.assertEqual(max(brief.MAX_TOKENS, key=brief.MAX_TOKENS.get), "company")class NearCeilingWarnsBeforeItBreaks(unittest.TestCase):"""stop_reason only reports truncation once a brief has already gone outhalf-finished. This is the warning one run earlier."""def test_the_threshold_leaves_usable_headroom(self):self.assertTrue(0.5 < brief.NEAR_CEILING < 1.0)def test_the_measured_worst_case_does_not_trip_it(self):# company at 1715 against a 4000 budget is 43% -- comfortable. If a# budget change made today's real data warn, the budget is wrong.for kind, observed in {"exec": 872, "company": 1715, "person": 1029}.items():self.assertLess(observed, brief.MAX_TOKENS[kind] * brief.NEAR_CEILING, kind)MIN_PAYLOAD = {"schemaVersion": "1.0.0","generatedAt": "2026-08-25T18:38:31.943Z","day": "2026-08-25","timezone": "America/Chicago","mode": "live","sources": [{"name": "plinth", "ok": True, "error": None}],"rules": ["A rule that must reach the system prompt verbatim."],"execRules": ["Capacity, not performance."],"company": {"ourMove": 3},"exec": {"holding": 3},"dataHealth": {"unmeasurable": []},"people": [{"name": "Nora Lindqvist"}, {"name": "Sam Whitaker"}],}class RunEndToEnd(unittest.TestCase):"""Drives main() with a stubbed transport. Covers the parts that only show uponce the loop, the merge and the exit code are working together."""def setUp(self):self.dir = tempfile.TemporaryDirectory()self.addCleanup(self.dir.cleanup)self.payload = Path(self.dir.name) / "briefing-payload.json"self.payload.write_text(json.dumps(MIN_PAYLOAD), encoding="utf-8")self.out = Path(self.dir.name) / "briefings.json"def run_main(self, bodies: list[dict], argv: list[str]) -> int:full = ["brief.py", "--payload", str(self.payload), "--out", str(self.out),"--base-url", "https://api.anthropic.com/v1", "--api-key", "k","--model", "claude-opus-5", *argv]with mock.patch.object(sys, "argv", full), \mock.patch("urllib.request.urlopen",side_effect=[response(b) for b in bodies]), \mock.patch.object(sys, "stdout", io.StringIO()), \mock.patch.object(sys, "stderr", io.StringIO()):return brief.main()def written(self) -> dict:return json.loads(self.out.read_text(encoding="utf-8"))def test_all_writes_the_company_key_the_page_reads(self):code = self.run_main([anthropic()] * 5, ["--all"])self.assertEqual(code, 0)self.assertIn("company", self.written()["briefings"])def test_all_writes_exec_company_and_every_person(self):self.run_main([anthropic()] * 5, ["--all"])got = set(self.written()["briefings"])self.assertEqual(got, {"exec", "company", "company-allhands", "Nora Lindqvist", "Sam Whitaker"})def test_one_empty_response_does_not_lose_the_other_briefs(self):# Making call_model raise turned a single bad response into a run that# wrote nothing at all. The rest of the briefs and a named failure beats none.bodies = [anthropic(content=[]), anthropic(), anthropic(), anthropic(), anthropic()]code = self.run_main(bodies, ["--all"])self.assertEqual(code, 1, "a failed brief must still fail the run")got = self.written()["briefings"]self.assertNotIn("exec", got, "the failed brief must be absent, not blank")self.assertEqual(set(got), {"company", "company-allhands", "Nora Lindqvist", "Sam Whitaker"})def test_a_failed_brief_is_absent_rather_than_empty_string(self):# Absent renders as "not generated"; an empty string renders as a blank# briefing, which is the failure this whole change is about.self.run_main([anthropic(content=[])] + [anthropic()] * 4, ["--all"])for key, text in self.written()["briefings"].items():self.assertTrue(text.strip(), key)def test_truncated_briefs_are_listed_for_the_page(self):bodies = [anthropic(stop_reason="max_tokens")] + [anthropic()] * 4self.run_main(bodies, ["--all"])self.assertEqual(self.written()["truncated"], ["exec"])def test_a_clean_run_lists_nothing_as_truncated(self):self.run_main([anthropic()] * 5, ["--all"])self.assertEqual(self.written()["truncated"], [])def test_rerunning_one_person_clears_only_their_stale_flag(self):# Union-ing the old and new lists would label a brief truncated forever,# so a successful re-run has to drop the key it rewrote and no other.self.run_main([anthropic(stop_reason="max_tokens")] * 5, ["--all"])self.assertEqual(self.written()["truncated"],["Nora Lindqvist", "Sam Whitaker", "company", "company-allhands", "exec"])self.run_main([anthropic()], ["--person", "Nora Lindqvist"])self.assertEqual(self.written()["truncated"],["Sam Whitaker", "company", "company-allhands", "exec"])def test_a_single_person_run_does_not_wipe_the_morning(self):self.run_main([anthropic()] * 5, ["--all"])self.run_main([anthropic()], ["--person", "Nora Lindqvist"])self.assertEqual(set(self.written()["briefings"]),{"exec", "company", "company-allhands", "Nora Lindqvist", "Sam Whitaker"})def test_ties_the_briefing_to_the_sync_it_was_written_from(self):# main.ts and briefingAge() compare this against snap.syncedAt to decide# whether the prose and the numbers describe the same moment.self.run_main([anthropic()] * 5, ["--all"])self.assertEqual(self.written()["payloadGeneratedAt"], MIN_PAYLOAD["generatedAt"])class RulesReachTheSystemPrompt(unittest.TestCase):"""The payload ships its own `rules` array and brief.py's own docstring saysthey go in verbatim -- they are the traps that produce fluent, wrongsentences. A prompt built without them looks identical and is not."""def test_standard_view_carries_the_payload_rules(self):got = brief.system_prompt(MIN_PAYLOAD, "standard")self.assertIn(MIN_PAYLOAD["rules"][0], got)def test_exec_view_carries_both_rule_sets(self):got = brief.system_prompt(MIN_PAYLOAD, "exec")self.assertIn(MIN_PAYLOAD["execRules"][0], got)self.assertIn(MIN_PAYLOAD["rules"][0], got)def test_exec_rules_come_first(self):# Stated reason in the source: a model that runs out of attention should# lose the style guidance, not the limits.got = brief.system_prompt(MIN_PAYLOAD, "exec")self.assertLess(got.index(MIN_PAYLOAD["execRules"][0]),got.index(MIN_PAYLOAD["rules"][0]))if __name__ == "__main__":unittest.main()class RestrictedTodosNeverReachThePrompt(unittest.TestCase):"""Leadership Team to-dos are readable only by the leadership team. The company briefing namesto-dos by title, and prose cannot be redacted once a model has written it:there is no reliable way to strip a title from a paragraph that reasons aboutit, and asking the model not to mention it is a request, not a control.So the all-hands company brief is generated from a payload with those rowsremoved. These tests assert the removal, at the payload level, because that isthe only place the guarantee is enforceable."""def payload(self):# Shaped like the real payload, which is the whole point.## company.lateTodos is a count; the list lives under queues. A fixture# that put the list under company.lateTodos would pass against a shape# briefing-payload.ts never emits, while the filter removed nothing in# production. A fixture that does not match the contract tests the# fixture.return {**MIN_PAYLOAD,"company": {"ourMove": 3, "lateTodos": 2},"queues": {"lateTodos": [{"title": "SECRET leadership item", "restricted": True},{"title": "Open all-hands item", "restricted": False},]},"people": [{"name": "Nora Lindqvist", "todos": [{"title": "SECRET leadership item", "restricted": True},{"title": "Open all-hands item", "restricted": False},]},{"name": "Sam Whitaker", "todos": [{"title": "Another SECRET one", "restricted": True},]},],}def test_restricted_rows_are_gone(self):out = brief.without_restricted(self.payload())titles = [t["title"] for p in out["people"] for t in p["todos"]]self.assertEqual(titles, ["Open all-hands item"])def test_the_serialized_prompt_does_not_contain_the_titles(self):# The real guarantee: whatever ends up in the user turn must not carry# them. A filter that missed a nested copy would still pass the test above.out = brief.without_restricted(self.payload())prompt = brief.user_prompt(out, None, "standard")self.assertNotIn("SECRET leadership item", prompt)self.assertNotIn("Another SECRET one", prompt)self.assertIn("Open all-hands item", prompt)def test_the_queue_list_is_filtered_too(self):# queues.lateTodos is the company-level list of to-do TITLES. It was# never filtered, so every Leadership title reached the all-hands prompt# through it even once the rows were flagged.out = brief.without_restricted(self.payload())self.assertEqual([t["title"] for t in out["queues"]["lateTodos"]],["Open all-hands item"])def test_a_count_that_looks_like_a_list_is_left_alone(self):# company.lateTodos is an int. Filtering must not touch it, and must not# crash on it either -- reading it as a list is what pointed the filter at# nothing for a week.out = brief.without_restricted(self.payload())self.assertEqual(out["company"]["lateTodos"], 2)def test_every_list_of_titles_in_the_payload_is_covered(self):# The assertion that would have caught the original bug without knowing# where the list lived: after filtering, NO to-do dict anywhere in the# payload may still carry restricted=True.out = brief.without_restricted(self.payload())def walk(node):if isinstance(node, dict):if node.get("restricted") is True:yield nodefor v in node.values():yield from walk(v)elif isinstance(node, list):for v in node:yield from walk(v)self.assertEqual(list(walk(out)), [])def test_the_original_payload_is_untouched(self):# The full company brief is generated from the same object in the same# run. Mutating it in place would silently redact that one too.src = self.payload()brief.without_restricted(src)self.assertEqual(len(src["people"][0]["todos"]), 2)def test_it_reports_how_many_it_removed(self):out = brief.without_restricted(self.payload())self.assertEqual(out["_restrictedTodosRemoved"], 3)def test_a_todo_with_no_restricted_flag_is_kept(self):# `restricted` is computed in TypeScript. An older payload without the# field must not silently drop every row -- that would empty the brief and# look like a quiet week.p = {**MIN_PAYLOAD, "people": [{"name": "X", "todos": [{"title": "No flag"}]}]}out = brief.without_restricted(p)self.assertEqual([t["title"] for t in out["people"][0]["todos"]], ["No flag"])class TheAllHandsBriefIsItsOwnGeneration(unittest.TestCase):def test_all_produces_both_company_briefs(self):keys = [j.key for j in brief.build_jobs(PAYLOAD, all_=True, person=None, view="standard")]self.assertIn("company", keys)self.assertIn("company-allhands", keys)def test_they_are_distinct_keys(self):# surfaces.ts picks one by permission. If they collided, everyone would# read whichever was written last.keys = [j.key for j in brief.build_jobs(PAYLOAD, all_=True, person=None, view="standard")]self.assertEqual(len(keys), len(set(keys)))