mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-09-17 00:26:26 +00:00
fix(apply): run the page-count check Step 5b claimed Step 5d already ran (#476)
Step 5b's prose said "Page count is not checked here - that is verify_pdf.py --pages's job, and Step 5d already runs it", and verify_layout.py's docstring declines to measure page count for the same reason. Step 5d's only verify_pdf.py call is --dump-text, and no step in the workflow passed --pages at all (only the upstream-only CI assertion on the stock examples does), so the hard 2-page CV and 1-page cover letter limits were enforced by nothing but the visual PDF read - the "measure first, then look" failure 5b was written to stop. 5b now runs verify_pdf.py --pages 2 on the CV and --pages 1 on the cover letter ahead of verify_layout.py, names the ACTIVE-TEMPLATE page limit as the substitute for a custom template, and the deferral sentence points at those lines instead of at 5d. tests/test_apply_page_count.py pins the invocations, their counts, their order relative to the layout measurement, and that no prose defers the check to a step that does not run it; all four cases fail on master.
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
"""Guard for /apply Step 5b's page-count check.
|
||||
|
||||
The 2-page CV and 1-page cover letter limits are the hard rules of
|
||||
05-cv-templates.md and 06-cover-letter-templates.md, and two places defer
|
||||
their enforcement to `tools/verify_pdf.py --pages`: `verify_layout.py`'s
|
||||
docstring ("page count is verify_pdf.py's job, and CI runs it") and Step 5b's
|
||||
own prose, which used to say "Step 5d already runs it". Step 5d's only
|
||||
invocation is `--dump-text`, and no other step passed `--pages` at all, so
|
||||
the one rule with a mechanical check had zero runnable implementations in
|
||||
the workflow. These tests pin that the invocations exist where the prose says
|
||||
they do, with the counts the guides require, and that no step defers the
|
||||
check to another step that does not run it.
|
||||
"""
|
||||
import re
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
APPLY = REPO / ".claude" / "commands" / "apply.md"
|
||||
VERIFY_LAYOUT = REPO / "tools" / "verify_layout.py"
|
||||
|
||||
|
||||
def section(path, heading):
|
||||
"""The body of one markdown section, up to the next heading of any depth."""
|
||||
text = path.read_text(encoding="utf-8")
|
||||
start = text.index(heading) + len(heading)
|
||||
rest = text[start:]
|
||||
end = re.search(r"^#{1,4} ", rest, re.MULTILINE)
|
||||
return rest[: end.start()] if end else rest
|
||||
|
||||
|
||||
def page_count_invocations(text):
|
||||
"""(document path, page count) for every runnable verify_pdf --pages line."""
|
||||
return re.findall(
|
||||
r"^python tools/verify_pdf\.py (\S+) --pages (\d+)\s*$", text, re.MULTILINE
|
||||
)
|
||||
|
||||
|
||||
class ApplyRunsThePageCountCheck(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.step_5b = section(APPLY, "### 5b. Inspect layout")
|
||||
|
||||
def test_step_5b_checks_both_documents_with_the_guides_page_limits(self):
|
||||
invocations = dict(page_count_invocations(self.step_5b))
|
||||
self.assertEqual(
|
||||
invocations.get("cv/main_<company>_<role>.pdf"),
|
||||
"2",
|
||||
"Step 5b must run verify_pdf.py --pages 2 on the CV - the hard "
|
||||
"2-page limit has no other mechanical check",
|
||||
)
|
||||
self.assertEqual(
|
||||
invocations.get("cover_letters/cover_<company>_<role>.pdf"),
|
||||
"1",
|
||||
"Step 5b must run verify_pdf.py --pages 1 on the cover letter",
|
||||
)
|
||||
|
||||
def test_page_count_runs_before_the_layout_measurement(self):
|
||||
# verify_layout.py's own docstring declines to check page count because
|
||||
# verify_pdf.py --pages does; the deferral only holds if that runs first.
|
||||
first_pages = self.step_5b.index("--pages")
|
||||
first_layout = self.step_5b.index("verify_layout.py")
|
||||
self.assertLess(first_pages, first_layout)
|
||||
|
||||
def test_no_step_defers_the_check_to_a_step_that_does_not_run_it(self):
|
||||
text = APPLY.read_text(encoding="utf-8")
|
||||
self.assertNotIn(
|
||||
"Step 5d already runs it",
|
||||
text,
|
||||
"Step 5d's only verify_pdf call is --dump-text; the page-count "
|
||||
"invocation lives in 5b and the prose must point there",
|
||||
)
|
||||
|
||||
def test_layout_tools_deferral_is_backed_by_a_runnable_invocation(self):
|
||||
docstring = VERIFY_LAYOUT.read_text(encoding="utf-8")
|
||||
self.assertIn("verify_pdf.py --pages", docstring)
|
||||
self.assertGreaterEqual(
|
||||
len(page_count_invocations(APPLY.read_text(encoding="utf-8"))),
|
||||
2,
|
||||
"verify_layout.py defers page count to verify_pdf.py --pages, so "
|
||||
"/apply must actually invoke it",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user