"""Guards for the company-research cache spec. /apply Step 3's reviewer agent and /interview Step 2 each independently execute the Company Research Checklist (04-job-evaluation.md) for the same company when both commands run against the same application - confirmed by reading both files, not assumed. The cache lets either consumer reuse a recent result instead of repeating the search/fetch work. These are markdown specs (the spec IS the implementation), so these tests pin the invariants that would break silently: that the cache is actually read before researching, and - the part most likely to be dropped in a future edit, since it is easy to add the read half and forget the write half - that fresh research gets written back for the next consumer to find. """ import unittest from pathlib import Path REPO = Path(__file__).resolve().parent.parent EVALUATION = REPO / ".claude" / "skills" / "job-application-assistant" / "04-job-evaluation.md" APPLY = REPO / ".claude" / "commands" / "apply.md" INTERVIEW = REPO / ".claude" / "commands" / "interview.md" def _sections(text: str, marker: str) -> dict[str, str]: """Split a markdown spec into {heading: body} on a given '\\n ' prefix.""" parts = text.split(f"\n{marker} ") result = {} for part in parts[1:]: heading, _, body = part.partition("\n") result[heading.strip()] = body return result def _apply_research_step() -> str: """apply.md's '### 1. Research the Company' subsection, isolated from the other numbered subsections under Step 3.""" text = APPLY.read_text(encoding="utf-8") sections = _sections(text, "###") for heading, body in sections.items(): if heading.startswith("1. Research the Company"): return body return "" def _interview_research_step() -> str: text = INTERVIEW.read_text(encoding="utf-8") sections = _sections(text, "##") for heading, body in sections.items(): if heading.startswith("Step 2: Research the Company"): return body return "" class TestCacheDefinition(unittest.TestCase): def setUp(self): self.text = EVALUATION.read_text(encoding="utf-8") self.sections = _sections(self.text, "##") def test_evaluation_file_defines_the_cache_section(self): self.assertIn( "Company Research Cache", self.sections, "04-job-evaluation.md must define a 'Company Research Cache' section", ) def test_cache_definition_specifies_location_and_ttl(self): body = self.sections.get("Company Research Cache", "") self.assertIn("company_research/", body, "cache section must name the storage directory") self.assertIn("30", body, "cache section must state the TTL (30 days)") self.assertIn("fetched_date", body, "cache section must name the freshness field") def test_cache_definition_preserves_the_verification_rule(self): """The cache must not weaken the existing 'verify before quoting' rule - it should explicitly say a cache hit is a lead, not a substitute for it.""" body = self.sections.get("Company Research Cache", "") self.assertIn( "lead", body, "cache section must say a cache hit is a lead, matching the existing " "reviewer-agent-research trust model, not a verified source on its own", ) self.assertRegex( body, r"[Vv]erif", "cache section must restate that final-claim verification still applies", ) class TestApplyWiring(unittest.TestCase): def test_reviewer_prompt_checks_cache_before_researching(self): body = _apply_research_step() self.assertNotEqual(body, "", "could not locate apply.md's Research the Company step") self.assertIn("company_research/", body, "reviewer prompt must reference the cache path") self.assertRegex( body, r"[Cc]heck the cache", "reviewer prompt must instruct checking the cache before researching", ) def test_reviewer_prompt_writes_back_after_fresh_research(self): body = _apply_research_step() self.assertRegex( body, r"write.*company_research/|company_research/.*write", "reviewer prompt must instruct writing fresh research back to the cache " "- the write half is the one most likely to be dropped silently", ) class TestInterviewWiring(unittest.TestCase): def test_step_2_checks_cache_before_researching(self): body = _interview_research_step() self.assertNotEqual(body, "", "could not locate interview.md's Step 2") self.assertIn("company_research/", body, "Step 2 must reference the cache path") self.assertRegex( body, r"[Cc]heck the cache", "Step 2 must instruct checking the cache before researching", ) def test_step_2_writes_back_after_fresh_research(self): body = _interview_research_step() self.assertRegex( body, r"write.*cache|cache file with", "Step 2 must instruct writing fresh research back to the cache", ) def test_step_2_still_requires_verification_before_using_a_claim(self): """Pre-existing rule (unrelated to this cache) that must survive: the cache must not be presented as a substitute for it.""" body = _interview_research_step() self.assertIn( "Verify before using", body, "Step 2 must keep its existing verification requirement", ) if __name__ == "__main__": unittest.main()