mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-11-02 13:12:50 +00:00
09a8c31b24651c0c8274cc86fec7d703c21931b3
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e355eafe27 |
fix(verify-layout): find an orphaned entry header by where the text starts (#508)
find_orphans() compared each line's left edge with the document margin: an un-indented last line followed by an indented first line was an entry header orphaned from its bullets. A list marker moves a line's left edge without moving its text, so the rule misread two templates: * one that merges each bullet's marker into its first line (#481): a bullet wrapping across the break was reported as an orphaned header, and a real orphaned header followed by such bullets was not reported; * the stock CV, when its outer marker extracts as a line of its own: a [Job Title] header left at the foot of a page, bullets overleaf, was not reported (its text at x70.4 counts as indented), and a one-line list item whose outer marker is set 1.3pt below it - so the marker sorts last on the page - was reported as a split bullet although the whole item is on that page. Following discussion #481, the rule now reads text x: * parse_pdf records where a line's text starts after leading LIST_MARKERS words (Line.text_left, defaulted). The set is the agreed Unicode bullets without the dashes (`• ‣ ▪ ● ·`): a bullet's second line may open with an em dash, and the stock Honors item's second line opens with an en dash. Other glyphs are text, so a line that merges the stock outer marker (`○` on some setups, an emoji on others) keeps the marker's x, as the left-edge rule read it; * find_orphans compares the text x of a page's last printed line with that of the next page's first printed line, and reports an orphaned header when the latter is more than INDENT_PT further in. Bbox lines whose tops are within SAME_PRINTED_LINE_PT (3pt) are one printed line: pdftotext's rounded-yMin buckets split a line where a bold word sits 0.2pt off, or where a marker sits 1.3pt below its text. A line whose text starts more than SET_IN_LIMIT_PT (60pt) past the margin is set right or centred (a running header) and is skipped as the opener; * a page ending on a marker with no text beside it keeps the lone-marker report, with its condition and message unchanged. Stock cv/main_example.tex, \vspace* of 0-600pt in 8pt steps before four entries, 304 lualatex builds (and the same 304 with xelatex): this adds 15 reports, each a [Job Title] header at the foot of a page with its bullets overleaf; the other 289 builds give byte-identical output. The reported. A two-line outer item whose marker sorts last and that wraps across the break is no longer reported as a split bullet: it is read like the #481 wrapped bullet, which is expected clean. Tests: TestOrphansReadTextX (13; 7 fixes and the wrapped two-line item fail on master's logic, 5 pin behaviour master already had) and TestTextStart (4). On Python 3.10-3.14 `python -W error::SyntaxWarning -m unittest discover -s tests -t .` passes 520 tests (master 503); lint_skills.py, check_framework_version.py and security_guards.py OK. |
||
|
|
97e2575795 |
fix(tests): escape the regex in test_verify_pdf's docstring and compile-check tests/*.py (#503)
FindNonAsciiDateRangesTests' docstring (from #498) quotes the regex `\s*`
in a non-raw string. `\s` is an invalid escape sequence, so Python 3.12+
prints a SyntaxWarning for it (CPython gh-98401) when
tests/test_verify_pdf.py is compiled. It is in this repo's own CI log
for
|
||
|
|
a62af6a068 |
fix(verify-layout): escape the docstring's LaTeX macro so the tool stops emitting SyntaxWarning (#480)
`tools/verify_layout.py`'s module docstring explains which documents trigger
the Poppler `-bbox` crash, and names the macro whose absence causes it:
`\hypersetup{pdftitle=...}`. In a non-raw docstring `\h` is an invalid escape
sequence, so compiling the module prints
SyntaxWarning: "\h" is an invalid escape sequence.
Such sequences will not work in the future. Did you mean "\\h"?
on Python 3.12+ (CPython gh-98401 promoted the long-standing
DeprecationWarning to a SyntaxWarning). The 3.15 language reference still
documents the sequence as a SyntaxWarning, with a SyntaxError only "in a
future Python version".
This is on the real path, not a constructed one: /apply Step 5b runs
`python3 tools/verify_layout.py <pdf>` once per document, so the first
invocation after any source change prints the warning into the middle of the
layout report a user is reading to judge their CV. It is also visible in this
repo's own CI log, where `python -m unittest discover -s tests -t . -v` prints
it above the test results.
Reproduce on master:
python3 -W error::SyntaxWarning -c "compile(open('tools/verify_layout.py',
encoding='utf-8').read(), 'tools/verify_layout.py', 'exec')"
raises on master; after this change it is silent.
Escaping (rather than making the docstring raw) keeps the surrounding prose
unchanged, and the single-backtick markup matches the other inline literals in
the same docstring. The rendered text still reads `\hypersetup{...}`.
The new `ToolsCompileWithoutWarnings` case is a pure `compile()` of the source
text of every `tools/*.py` inside `warnings.catch_warnings(record=True)` and
asserts no `SyntaxWarning` or `DeprecationWarning` (3.10 and 3.11 report the
same escape as a DeprecationWarning) - no cache file, no temp file, so it runs
the same on Windows (py_compile's atomic rename over an open
NamedTemporaryFile is what the first version tripped on). It fails on master
and passes here on every Python in the CI matrix, and it guards the next
docstring that quotes a macro.
Verification on Python 3.10, 3.11, 3.12, 3.13 and 3.14: `python3 -m unittest discover -s
tests -t .` (488 tests OK; master is 487), `python3 -W error::SyntaxWarning`
compile of every `tools/*.py`, `tests/test_changelog_structure.py`.
|
||
|
|
1b65f7198a |
fix(verify-layout): name both causes of a broken bounding-box extractor (#451) (#465)
verify_layout.py's skipped: message blamed only the xpdf-based pdftotext that
Git for Windows puts ahead of Poppler in PATH. A real Poppler can abort too:
26.0x before 26.05 crashes -bbox/-bbox-layout/-htmlmeta on a PDF whose Info
dictionary carries an empty string in any field, and hyperref writes exactly
that for every field it does not set. A lualatex/pdflatex document built with
hyperref and no \hypersetup{pdftitle=...} - an ordinary /add-template CV
template, not a malformed one - hits this with a working Poppler installed,
and the old message sent the reader to check their PATH when nothing was
wrong with it.
Named both causes in the raised message, the code comment above it, and the
module docstring. Behavior is unchanged: either cause still degrades to
skipped: exit 2, not exit 1, since a broken extractor is still not a broken
document.
Added test_poppler_abort_on_empty_info_string_names_that_cause_too, mocking
subprocess.run to raise CalledProcessError the way a real Poppler 26.0x abort
does (exit 1, a libc++abi out_of_range trace on stderr) rather than the
xpdf case's exit 99 - the two failures are the same exception type with
different exit codes and stderr text, so the message has to actually
distinguish them, not just catch the one class. Negative control: this test
fails against the pre-fix message with "'Poppler aborted' not found in
'...a pdftotext without -bbox is usually the xpdf build...'".
Thanks to @main-sounds-audio for the report and the isolated repro (which
field, which Poppler modes, five runs of five) that pinned this to Poppler's
own upstream regression (issue #1699, fixed in 26.05.0) rather than an
extraction-library swap.
Fixes #451
|
||
|
|
cbd8a991ab |
feat(layout): measure compiled PDF layout instead of eyeballing it (#378)
* feat(layout): measure compiled PDF layout instead of eyeballing it /apply Step 5b asks for layout properties and executes none of them: they are checked by reading the rendered page, which is exactly how they get missed. The failure that motivates this is silent under every existing check. A moderncv \cventry renders as a tabular, so an entry is one unbreakable block; when it does not fit in the space left, the whole entry moves to the next page and leaves a hole behind. The document still compiles, still reports the expected page count, and still passes tools/verify_pdf.py. Observed in the wild at 273pt, roughly 19 blank lines, mid-page, on a CV whose visual read looked fine. tools/verify_layout.py reports per page where the text starts and stops, bottom whitespace as a share of page height, and the largest gap between lines, then exits 1 on a hole over 100pt, a non-final page ending more than 25% early, body text colliding with the page-number footer, a final page more than 35% empty, or an entry header or section heading stranded at a page break. Page count is deliberately not checked here - verify_pdf.py --pages already does that, and two implementations of one rule drift. Geometry comes from Poppler pdftotext -bbox, already a dependency; a missing Poppler exits 2 with "skipped:" rather than failing the run. Tests build synthetic Page/Line geometry, so the suite needs neither Poppler nor a LaTeX toolchain and runs on the existing 3.10-3.14 matrix. * fix(layout): survive Windows encoding and a pdftotext without -bbox Review found two failures on the repo's primary platform: subprocess.run(..., text=True) decoded pdftotext's UTF-8 output with the Windows ANSI codepage and crashed on the stock cv/main_example.pdf. It now passes encoding="utf-8" with errors="replace" at the call site, matching the fix verify_pdf.py already carries from #369. Git for Windows ships an xpdf-based pdftotext that shadows Poppler in a default PATH and has no -bbox flag; it exited 99, the CalledProcessError escaped, and the run ended in exit 1 - indistinguishable from a real layout problem, which would send /apply chasing a phantom hole. That now routes to the existing "skipped:" exit 2 path with a message naming the likely cause, covered by three tests on the extractor-failure path. Also from review: - .claude/settings.json and security_guards.py gain the verify_layout.py permission entries. apply.md Step 5b runs the tool on every /apply, so without them every run prompts. - The docstring and CHANGELOG no longer call Poppler a dependency verify_pdf.py relies on. Since #369 verify_pdf prefers pypdf and Poppler is the fallback; word bboxes have no pypdf equivalent, so this is the one step that still wants it, and that is now what the text says. - Docstring and apply.md state that the thresholds are calibrated for the stock moderncv and cover.cls geometry, and that the shipped example CV fails the thin-final-page rule by design. - largest_gap documents that it measures top-to-top, so a tall line inflates the gap by its own height - over-detection, the safe direction. - The test module imports via tools.verify_layout like test_verify_pdf.py instead of sys.path.insert. * fix(verify_layout): quote only the first stderr line in the skip message (#378) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013fqqLgQSnwgWkv98twQhHi --------- Co-authored-by: Mads Lorentzen <madslorentzen_17@hotmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |