Norway search (user request 2026-10-21/22: Trondheim, Bergen or similar, not Oslo) - New location policy norway_no_oslo: keeps a role if any Norwegian location is outside the Oslo area. Equinor and Telenor move to it. - New `nav` adapter for the NAV national register (arbeidsplassen.nav.no): keyword queries on a fixed request budget, paced; on HTTP 429 it stops and returns a PARTIAL run with a warning instead of failing. Full-ad text checks are cached in state/nav_detail_cache.json (ignored). Tested against fixtures only: the live API was rate-limiting during the build. - Dedicated boards where NAV was measured thin (2026-10-22: Nordic 0, DNV 2, Equinor 2 vs ~10, NATO 0): Nordic Semiconductor (teamtailor custom domain), DNV (new `algolia_jobs` adapter; app id/key/index read from the page each run), Arm Trondheim (new `radancy` adapter), Microsoft Norway (pcsx). Verified live: 7 / 6 / 7 / 6 roles outside Oslo. - NAV rows that duplicate a dedicated board's posting are dropped (employer alias + normalized title). Language / citizenship check - classify_language_requirement reads the requirement SENTENCE, not the posting language: "norsk og/eller engelsk" is English OK, "kommunisere godt ... på norsk og engelsk" is Norwegian required. Only an explicit Norwegian requirement or Norwegian-citizenship requirement filters a role; clearance is noted, never a gate. Runs on full ad text (NAV detail page, untruncated Teamtailor/PCSX descriptions). Telenor Lead Platform Engineer now reads NORWEGIAN REQUIRED (it read UNCLEAR on truncated text). - Norwegian title keywords added (they all scored 0 and were never checked). Employer reputation (user requirement 2026-10-22) - state/employer_reputation.json (now tracked): dated Glassdoor lookups with sources and the approved thresholds (good >= 3.8 on >= 50 reviews; ok 3.5-3.79 or thin-but-backed; avoid < 3.5; Vizrt excluded). Every report row shows the verdict; unlooked-up employers show UNCHECKED. Report - Sections per region: Switzerland, Norway, Europe-remote / Denmark (user preference); `--region=ch|no` runs one region only. Fixes - Microsoft links: apply.careers.microsoft.com<positionUrl>?jobId=<id> with a host alias so all 7 logged Microsoft decisions still resolve; the old jobs.careers.microsoft.com form redirected to a generic search page. PCSX calls retry on 429. CLAUDE.md corrections log: design/architecture gap (2026-10-21) and the Microsoft link fix; the EMEA-suffix location leak stays OPEN. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Evidence-first resume kit
This repository turns verified career evidence into role-specific LaTeX resumes and, when useful, cover letters. It is designed to prevent a common failure mode of AI-assisted applications: making a document sound closer to the job description by silently overstating skills, scope, titles, or outcomes.
The workflow separates three questions that should never be confused:
- Evidence Fit: does the candidate actually meet the role, including hard gates?
- Document Quality: does the resume communicate the supported evidence clearly?
- Channel Strength: is the application cold, referred, or supported by a warm contact?
A polished resume cannot repair a failed qualification gate. A strong fit can still be hidden by a weak document. The system records both.
Source hierarchy
source documents
-> structured extractions
-> canonical claims registry
-> experience records and role bundles
-> session plan
-> generated resume / optional cover letter
resume_builder/canonical/claims.json is the highest-authority career source. Generated files under output/ are never treated as evidence. historical_outputs.json records whether an older package is safe to consult, must be revalidated, or must not be reused.
Default application strategy
- Target Staff/Senior Data Engineering first.
- Use ML Platform/MLOps, data platform, analytics, and semiconductor profiles only where direct evidence covers the actual requirements.
- Treat direct LLM engineering, formal model evaluation, Terraform-heavy SRE, and similar missing required experience as gates rather than keyword opportunities.
- Record fit and outcomes without application quotas; a fit classification is a preparation signal.
- Add a warm-channel action for core applications.
The default document is a two-page International Tech resume for US-tech/FAANG-style roles in Europe. A Swiss/DACH policy overlay is available for employers that expect local conventions. Cover letters are conditional, not automatic.
Workflow
Add evidence
- Put employment records, project material, papers, or notes under
knowledge_base/. - Run
setup-extractto create a source-grounded extraction. - Review it, then run
setup-build-kbto update canonical claims, experience files, bundles, and support data.
Apply to a role
- Run
make-resumewith the real JD. - Review the requirement table and fit gate before approving content generation.
- Generate and validate the LaTeX resume.
- Run
make-clonly when the session records a justifiedYESdecision. - Run
critiquefor separate Evidence Fit, Document Quality, and Channel Strength findings. - Run
edit-resumefor approved repairs.
The skills live in .agents/skills/. Each application receives a session file under output/<Role>/ that preserves the JD, fit decision, claim IDs, content plan, validation results, and application status.
Validation
Validate the knowledge system:
python resume_builder/helpers/validate_resume_system.py
Validate a generated document:
python resume_builder/helpers/validate_resume_system.py --document output/Role/resume.tex
Track the uncapped application record (use summary --all for older applications too):
python resume_builder/helpers/cohort_tracker.py summary
job_scout/state/applications.json owns current status and event history. The old cohort JSON and
resume_builder/reference/current_applications.md are generated views. Update status without erasing interview history:
python resume_builder/helpers/cohort_tracker.py update --id <application-id> --date YYYY-MM-DD --event interview_held --note "Interview completed"
python resume_builder/helpers/cohort_tracker.py update --id <application-id> --date YYYY-MM-DD --outcome withdrawn_by_candidate --note "Reason"
python resume_builder/helpers/application_records.py --check
Use application_records.py --render to recover stale generated views. A classification that differs
from its numeric rubric needs --fit-override-reason; it is never silently relabelled.
Character counts are available only as readability diagnostics. There are no fixed character bands, equal-length bullet rules, or page-fill quotas.
Run the offline regression suite with python -m unittest discover -s tests -v.
The application registry and its import history are versioned; seen-state and generated PDFs are not.
package_manifest.py --check checks source/class content and any recorded PDFs that are present.
Missing local PDFs are permitted. After inspecting changes, run package_manifest.py to refresh
source hashes, or add --record-pdfs to explicitly record current PDF hashes. These snapshots
detect edits; they do not certify that an existing PDF was built from a particular source.
Scout writers are serialized with job_scout/state/scout.lock. After a crash, remove a stale
lock only after verifying no scout process is still running. Successful reports, including
--new-only and --only=..., mark their delivered results seen without changing other companies.
Output and prerequisites
The system writes .tex source only. Compile locally with a LaTeX distribution such as MiKTeX, TeX Live, or MacTeX. Generated resumes should also be checked through PDF rendering and text extraction before submission.
See DOCS.md for the architecture and policy reference.
License
MIT; see LICENSE.