fix: follow-up review corrections, BIS rejection, and a gitignore miss
Second-pass review of this session's work by another agent. It corrected several
real mistakes of mine and finished F06 gaps I had left open. Reviewed, verified
and committed as-is.
THE MISS THAT MATTERS
`job_scout/state/applications.json` — the authoritative application registry
introduced by F02 — was never actually tracked. `job_scout/state/*` in
.gitignore silently excluded it, so my checkpoint commit afdef7e claimed to add
it and did not. Only `application_cohort.json`, the GENERATED projection, was
version-controlled; the source of truth and the migration history backup were
not. .gitignore now carries explicit negations for both.
MY ERRORS, CORRECTED
- "kastellaun" was in CH_LOCATION_KEYWORDS. Kastellaun is in Rhineland-Palatinate.
I took it from a Bundeswehr reserve listing and filed it under Switzerland -
precisely the class of bug F12 existed to fix.
- The F12 fix only widened the keyword list; SmartRecruiters still discarded the
structured country, which was the concrete case the review named
(city=Baar, country=CH). The adapter now preserves it, and a COUNTRY_NAMES
mapping gives country precedence over a bare town name.
- F15 was applied to Taleo and Prospective only. Greenhouse still wrote
`updated_at` into `posted`; it now uses `published_at` and carries provenance.
- My negation guard `\b(no|not|...)\b[^.;]{0,60}$` was too loose - an unrelated
"not" within 60 characters could mask a real claim. Tightened to require the
negation to govern the term.
- F18's retirement of the macro-count rule missed "Four to six compact skills
lines" in the workflow; removed now.
F06 GAPS I LEFT OPEN, NOW CLOSED
Date-format validation on education/employment periods (the 2035-99 case named
in the review), evidence-structure validation, referential integrity on evidence
source files, and the missing-identity KeyError.
F10 TAKEN FURTHER, AND RIGHTLY
I demoted the US-GPA fields to *_orientation_only. They are now removed
entirely, with grade_output_rule saying what to do instead: use the German grade
and scale, and if a recipient requires a US GPA, use THEIR method and record it.
Keeping a number derived by a non-recognised method invites its use.
Also: the Capgemini omit-preference now sits in experience_capgemini.md itself,
alongside the instruction not to fill or explain the intentional gap.
BIS BASEL - REJECTED 2026-09-11
jr100429, applied 2026-07-10, no interview, no reason given. Recorded in the
registry with a dated event and in the decision log; the "prep interview brief
when screening lands" next action is cleared. This also settles the 2026-09-04
observation that the req had vanished from the BIS board - it was a real
rejection, not just a closed posting.
VERIFICATION I RAN MYSELF BEFORE COMMITTING
49/49 tests. Validator PASS with 0 advisory warnings. Package manifest and
registry views current. All 12 F12 location cases still correct, including
Kastellaun now rejecting. The F05 counter-proof still catches all 9 violations.
SBB, NVIDIA, RUAG and Kdo Cy resumes still scan clean. Diffs are net-additive
across every reference file - the deletions are replacements, not losses.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qej5SBvhcbGXHwLqNWiskM
This commit is contained in:
1 parent
925a2d74a3
commit
34299bce54
25 files changed
+1427
-322
No files matched your search
@@ -8,38 +8,38 @@ The review reported ~50-55% for four packages. This reproduces that measurement
|
||||
compiled PDF so a change can be checked rather than asserted. The percentage is a diagnostic,
|
||||
never a target: no pixel goal, no forced page-two filling.
|
||||
"""
|
||||
import io
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
|
||||
PDFTOTEXT = Path(r"C:\Users\Dennis\AppData\Local\Programs\MiKTeX\miktex\bin\x64\pdftotext.exe")
|
||||
HEADINGS = ("professional experience", "berufserfahrung", "experience")
|
||||
|
||||
|
||||
def measure(pdf: Path) -> dict:
|
||||
executable = shutil.which("pdftotext")
|
||||
if not executable:
|
||||
raise RuntimeError("pdftotext is required on PATH (Poppler or MiKTeX)")
|
||||
with tempfile.TemporaryDirectory() as work:
|
||||
out = Path(work) / "bbox.xml"
|
||||
subprocess.run([str(PDFTOTEXT), "-bbox", "-f", "1", "-l", "1", str(pdf), str(out)],
|
||||
subprocess.run([executable, "-bbox", "-f", "1", "-l", "1", str(pdf), str(out)],
|
||||
capture_output=True, check=True)
|
||||
xml = out.read_text(encoding="utf-8", errors="replace")
|
||||
page = re.search(r'<page width="([\d.]+)" height="([\d.]+)"', xml)
|
||||
if page is None:
|
||||
raise ValueError("No page geometry found in pdftotext output")
|
||||
height = float(page.group(2))
|
||||
words = [(float(m.group(2)), m.group(5).lower())
|
||||
for m in re.finditer(
|
||||
r'<word xMin="([\d.]+)" yMin="([\d.]+)" xMax="([\d.]+)" yMax="([\d.]+)">([^<]*)</word>',
|
||||
xml)]
|
||||
first_y = None
|
||||
for index, (y, text) in enumerate(words):
|
||||
if text in ("professional", "berufserfahrung", "experience"):
|
||||
following = " ".join(w for _, w in words[index:index + 2])
|
||||
if any(h.startswith(following.split()[0]) for h in HEADINGS):
|
||||
first_y = y
|
||||
break
|
||||
lines = len({round(y, 1) for y, _ in words})
|
||||
rows = {}
|
||||
for y, text in words:
|
||||
rows.setdefault(round(y, 1), []).append(text)
|
||||
first_y = next((y for y, row in sorted(rows.items()) if " ".join(row).strip() in HEADINGS), None)
|
||||
lines = len(rows)
|
||||
return {
|
||||
"height": height,
|
||||
"experience_y": first_y,
|
||||
|
||||
Reference in new issue
Block a user