Commit Graph
105 Commits
Author SHA1 Message Date
Ayobami Adegoke 70e0eb43ce fix(cli): reject negative and fractional count/pagination flags in Danish portal CLIs (#191)
Bare z.coerce.number() accepted negative and fractional values for count/pagination flags, and slice(0, limit) with a negative limit silently dropped trailing results instead of erroring. Tightens the schemas to .int().min(1) across all four Danish portal CLIs (including jobnet occupations --per-page) with network-free validation tests.

By @ayobamiseun.
2026-07-19 19:38:48 +02:00
落尘 3a184bc115 fix(jobbank): parse JobPosting entries nested in JSON-LD @graph (#190)
Extracts the JSON-LD JobPosting lookup into a recursive parseJobPostingJsonLd helper that handles top-level objects, arrays, and @graph wrappers (including nested combinations), keeps skipping malformed scripts, and covers all four cases with network-free Bun tests.

By @luochen211. Closes #189.
2026-07-19 19:38:32 +02:00
Yuan Chen 61d17d1bda feat(commands): add /gmail-sync - confirm-before-write status sync from Gmail (#170)
Scans Gmail (via the claude.ai Gmail connector) for status signals on open tracked applications - interview invites, assessments, offers, rejections - and proposes them as a sourced batch the user must approve before anything is written to job_search_tracker.csv or outcome.md. Never proposes hired/offer_declined (user's real-world decision), routes conflicting signals to manual /outcome, appends-only to Notes, idempotent by message ID, read-only against the mailbox, and degrades to one message + clean exit without the connector (the /notion-sync precedent). State is gitignored personal data.

By @chenyuan99, who raised the connector-dependency tension himself and restructured classification and writing into separate approval-gated steps.
2026-07-19 19:38:15 +02:00
Jovin Nicholas f51a766e72 feat(apply): factual grounding audit against the union fact base (#185)
Reviewer-side Factual Grounding Audit: every date, employer, job title, and quantitative metric in both drafts is checked against the union of 01-candidate-profile.md + cv/main_example.tex + CLAUDE.md's Candidate Profile section (grounded if ANY source supports it; inter-source mismatches surfaced as profile-consistency warnings; draft drift returned as Part A edits with reason "grounding"). Drafter-side rule makes those three sources the sole source of truth for facts - existing tailored CVs are structure/phrasing reference only. Fixes the structural drift loop where tailored output fed back as source material; companion to the maintainer-side #178 setup fix.

Reported, diagnosed, and implemented by @jovin-nicholas (#177); the failure mode was validated empirically by the output benchmark (blind judges found the exact escalation class in pre-audit outputs).

Closes #177
2026-07-19 19:22:46 +02:00
Lautaro Emanuel Jimenez 8ac6965170 docs(documents): add postings/ drop folder for bot-blocked job postings (#187)
Manual fallback for postings that block automated fetches: paste the text into documents/postings/<Job Title>.txt. Gitignored so posting text stays local; README documents the convention as a scratch inbox, with applications/<company>_<role>/job_posting.md remaining the archive.
2026-07-19 07:19:26 +02:00
Mads LorentzenandClaude Fable 5 122db059cb feat(apply): requirement-coverage rules and CV targeting improvements from output benchmark (#184)
Seven improvements sourced from blind regression probes comparing current
outputs against real April-2026 baselines (each an area where the older
outputs scored better):
- every stated requirement addressed - matched or honestly gapped, never
  silently omitted (the benchmark run omitted a stated Kubernetes
  requirement entirely; omission reads as hiding under questioning)
- nice-to-haves engaged by name with honest adjacency framing; posting's
  literal term preferred, including in CV section headings
- stated logistics/prerequisites addressed in the letter (clearances,
  availability, job ID, multi-country language mapping)
- domain-transfer argument leads the CV profile statement for
  domain-changers
- evidence links (href) on every verifiable named artifact
framework_version: 05 -> 1.2.0.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 22:22:05 +02:00
Mads LorentzenandClaude Fable 5 12717d2c12 fix(templates): correct 06 structure-block antipattern and 05 needspace scope (#183)
Both found by empirically re-running the /apply pipeline end-to-end:
06's Document Structure block still demonstrated itemize wrapped inside
lettercontent - the exact antipattern its own pitfall section forbids -
and following 05's needspace guidance at section level pushed an entire
Education block to a new page, costing a page instead of saving one.
framework_version: 05 -> 1.1.1, 06 -> 1.0.1.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 22:19:02 +02:00
Mads LorentzenandClaude Fable 5 de91a97fe8 feat(apply): make CV language a profile setting, defaulting to English (#179)
The CV was hardcoded 'Always in English' - fine for the Danish/English
demonstration profile, a real disadvantage for fork users in markets
where applications are expected in the local language (cover letters
already match the posting's language). /setup now asks once and records
'CV language:' in CLAUDE.md's Identity section; /apply reads it with
English as the default, so existing users see zero behavior change.
The ATS keyword rule is reworded language-neutrally.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 08:39:51 +02:00
Mads LorentzenandClaude Fable 5 3847088986 fix(setup): ground Path A profile-statement extraction against the profile (#178)
Completes the loop behind #177: /apply drift could be archived by
/outcome, then laundered into 05-cv-templates.md as a reusable template
by /setup Path A - promoting a one-off drifted claim into source
material for every future application. Path A now verifies extracted
statements' factual claims against 01-candidate-profile.md (keeping
framing only), and 05-cv-templates.md marks [Used for:] statements as
phrasing references, never fact sources. framework_version 1.1.0.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 08:39:17 +02:00
Mads Lorentzen d2e14418ca docs(setup): document upstream-pull workflow and failure-isolate install loops (#176)
Adds SETUP.md section 8 (pulling upstream updates into a personalized fork: commit-first, check_upstream_updates.py preview, conflicts-as-signal) closing #174, reported by @sharique. Also brings SETUP.md's duplicate install loops up to #157's failure-isolated pattern.
2026-07-17 22:05:43 +02:00
Ayobami Adegoke da2c3bbec9 test(cli): cover Jobindex and Jobnet error contracts (#172)
Extend the offline CLI contract tests to the two remaining Danish
portal CLIs. Both implement the documented error contract (JSON
errors on stderr, exit 1) but had no test locking it in:

- jobindex-search: search without --query, detail without an ID,
  and bunli numeric-option validation (--page not-a-number)
- jobnet-search: detail without an ID, occupations without
  --search-string, suggestions without --query, and numeric-option
  validation

All asserted paths exit before any network request, matching the
no-live-portal-requests CI policy. Assertions were written against
observed CLI output, not assumed shapes.
2026-07-17 21:56:13 +02:00
Mads Lorentzen fb91be7a0b security: treat job postings as untrusted input across /apply and /rank (#175)
Prompt-injection hardening from the dataflow analysis in #173 by @Defaultuser361: data-not-instructions rules in /apply and /rank, reviewer research constrained to the user-confirmed company identity, writing-style verify rule tightened to independently located sources (framework_version 1.1.0), SECURITY.md private reporting channel, README note. Closes #173.
2026-07-17 21:48:59 +02:00
Jaewon Chung ac6a734e16 fix(apply): name CVs main_<company>_<role> to avoid overwrites (#171)
CVs from /apply were named cv/main_<company>.tex, so a second role at the same company overwrote the first (cover letters already carried the role). Aligns CV naming to main_<company>_<role>.tex across apply, add-template, the CV template guide, CLAUDE.md, and SETUP.md; /outcome and /interview fallbacks glob main_<company>*.tex to match both legacy and new names. framework_version bumped on both touched framework files.
2026-07-17 21:26:04 +02:00
Adri f1ed475d59 feat(notion-sync): one-way read-only pipeline view in Notion via MCP (#169)
Adds /notion-sync per the conditions agreed in discussion #166: tool-agnostic sync contract with Notion as the in-tree reference binding, silently optional (covers unconfigured, headless, and unauthenticated states), read-only toward the repo with the gitignored sync-state file as its only local write, write-once page bodies, documents sync as filenames only. Complements /html-report: deep local dashboard vs glanceable anywhere-view.
2026-07-17 21:26:02 +02:00
Mads LorentzenandClaude Fable 5 dd6d7efea6 docs: warn fork authors about GitHub's default PR base (#167)
Three personalized-fork PRs (#155, #162, #165) were filed against
upstream by accident in one week - GitHub points new fork PRs at the
upstream repo by default, and nothing warned about it at the moment of
filing. Adds a PR template with the heads-up in the compose box (plus
the review norms the process asks for anyway) and one sentence in
CONTRIBUTING's fork section naming the mechanism.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 22:26:45 +02:00
Yuan Chen 848eddbecc feat(html-report): add /html-report command for application tracker dashboard (#131)
Self-contained HTML dashboard generated from job_search_tracker.csv and the application archives: stat cards, status/sector/channel/funnel charts as hand-generated inline SVG (no CDN, fully offline), HTML-escaped interpolation throughout, and a filterable applications table. Includes Python guards for the command file and the reports/ gitignore rule.
2026-07-16 21:48:59 +02:00
Mads LorentzenandClaude Fable 5 be427a7607 docs: codify the runtime policy - Claude Code first, runtime forks welcome (#163)
Writes down the architecture decision from the #78 discussion (2026-07-15):
Claude Code is the reference runtime; other agent runtimes are supported at
the edges via the portable portal skills in .agents/skills/, the root
AGENTS.md signpost, and thin-pointer community forks. Per-runtime command
trees stay in forks for the same reason market portals do.

README gets one line in Prerequisites; CONTRIBUTING gets the policy section
beside the market-skills rule it mirrors, including the explicit revisit
conditions.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 22:34:10 +02:00
Jovin Nicholas 1db48568b3 feat(agents-config): add root AGENTS.md thin-pointer specification (#159)
Root AGENTS.md pointer file per the architecture decision in discussion #78: documents both config roots (.agents/skills/ portable portal skills, .claude/ orchestration) and the profile entry points, carries a framework_version marker registered in both version tools.

Design case made by @erikpr1994 in the #78 architecture thread; implementation by @jovin-nicholas.
2026-07-15 22:33:42 +02:00
Erik Pastor Rios 37595187d6 feat(job-scraper): per-portal enabled toggle honored by /scrape (#160)
Implements the mechanism approved in discussion #93: enabled: true|false frontmatter on portal skills (missing key = enabled), honored during /scrape portal discovery, with skipped portals reported visibly in the run summary.
2026-07-15 20:20:37 +02:00
Alaa-TaiebandTunic Assistant 55ba1c1652 fix(salary): validate category shape and add --validate preflight (#156)
validate_data() accepted category values that are not {count?, index?}
objects. They slipped through to format_entry(), which then raised
AttributeError on a normal table lookup (or serialized a malformed shape
under --json). It also accepted duplicate company names silently.

- collect_validation_issues() now also flags a non-object category value
  (and non-numeric count / non number-or-string index) as a hard error,
  and duplicate company names as a warning.
- validate_data() keeps its eager-fail behavior (same messages), so
  existing tests and load_data() are unchanged.
- --validate runs the checks standalone and prints an actionable report
  (exit 1 on errors, 0 on warnings-only/clean), letting users pre-flight
  their BYO salary_data.json.

Reproduced on master: validate_data({'companies':[{'company':'Acme',
'categories':{'eng':'not_a_dict'}}]}) returns without error, but
format_entry then raises AttributeError.

Co-authored-by: Tunic Assistant <assistant@tunic.local>
2026-07-15 07:53:01 +02:00
Carlos Mestre CebriánandClaude Fable 5 47118dcbf2 docs(readme): make install loops failure-isolated per iteration (#157)
A failed iteration in the Quick start install loops (e.g. bun missing
from PATH) skipped the cd back to the repo root, so every remaining
tool's cd failed in cascade and the shell ended up stranded inside
.agents/skills/<tool>/cli with nothing else installed. Run each bash
iteration in a subshell and use Push-Location/Pop-Location in
PowerShell so a failure stays contained to its own tool and the loop
always returns to the repo root.


Claude-Session: https://claude.ai/code/session_015EQ2xeixvVdnvbihce3aSt

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 07:52:07 +02:00
Rasika d1e707ef1f feat(job-scraper): referral-contact LinkedIn search links for high/medium-fit jobs (#149)
* added contact skill

* refactor(job-scraper): fold referral-contacts into Step 4.5, drop contacts cache
2026-07-15 07:52:04 +02:00
Alaa-Taieb 1417e3cbdf fix(salary): skip non-numeric and identifier columns in Excel conversion (#152)
parse_sheet treated every column that was not company/city as a salary category, with no check that the column actually held numeric salary data. This turned free-text columns (e.g. Notes) into bogus string categories and numeric identifier columns (e.g. Id) into mistaken salary indexes.

- Drop identifier headers (ID_PATTERNS = {id, personnummer}) at classification time.

- Skip non-numeric standalone values and fully-null count/index pairs at row-processing time.

- Adds regression tests (skips_free_text_column, skips_numeric_identifier_column, keeps_numeric_salary_column) that fail on master and pass after the fix.
2026-07-14 20:11:11 +02:00
Alaa-Taieb 4128ca0318 fix(salary): detect company column from header token, not exact match (#151)
convert_salary_excel.py detected the company column via exact membership
in COMPANY_PATTERNS, so common real-world headers like "Company Name" or
"Employer Name" were never matched. parse_sheet then returned [] for that
sheet, silently dropping it from salary_data.json (or exiting with no
output for a single-sheet file).

Route company-column detection through the existing header_matches()
token matcher (already used for count/index detection). This only adds
detections; inputs that already worked (bare "Company"/"Firma"/...) are
unaffected.

Adds a regression test in tests/test_convert_salary_excel.py that fails
on master (returns []) and passes after the fix.
2026-07-14 14:35:45 +02:00
Yash Rajeshbhai DarjiandCursor 0a8fc194e5 docs: sync onboarding with linkedin-search + freehire-search reality (#150)
/setup still told non-DK users that built-in CLIs are Denmark-specific.
Align setup, /add-portal, and search-queries.md with shipped country-agnostic
CLIs and /scrape auto-discovery (post #85 / #95 / #102).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-14 14:30:49 +02:00
Erik Pastor Rios b20467df4a feat(versioning): framework_version markers, CI version guard, and fork update checker (#144)
* Add framework_version markers to assistant skills and implement CI version guard and update checker

* Address review feedback: update ci.yml based on latest upstream, gate CI version guard to upstream repo, and remove non-ASCII characters from check_upstream_updates.py
2026-07-14 14:29:24 +02:00
Ayobami Adegoke 03798ec974 test(cli): cover Jobbank and Jobdanmark contracts (#148)
Jobbank and Jobdanmark each had only one narrow test, leaving required-argument errors, RSS normalization, JSON-LD variants, and malformed-page handling unprotected.

Add network-free fixture and subprocess tests for repeated RSS filters, description and ID parsing, stderr JSON errors, Bunli numeric validation, JSON-LD objects and arrays, optional fields, not-found pages, and parse failures.

The suites now cover eight Jobbank cases and six Jobdanmark cases without making live portal requests.
2026-07-13 20:45:38 +02:00
Yiğit Ö. Ünver fca1c4234e docs(setup): add needspace to the minimal TeX install list (#147) 2026-07-13 20:45:36 +02:00
Ayobami Adegoke a03529f894 fix(lint): report malformed settings shapes without crashing (#146)
Valid JSON such as [] or {"permissions": []} caused lint_skills.py to raise AttributeError because it assumed both values were objects.

Validate the top-level settings value and permissions object before reading nested keys. Malformed settings now produce clear lint errors and exit 1 without a traceback.

Add subprocess regression tests covering invalid JSON, malformed root values, invalid permissions values, and non-list permissions.allow values.
2026-07-13 20:45:22 +02:00
Ayobami Adegoke 160b479868 ci: verify PDF page counts and text layers via poppler (#145) 2026-07-13 16:36:46 +02:00
Ayobami Adegoke e341d19abd fix(salary): validate salary data shape before lookup (#141) 2026-07-13 15:55:55 +02:00
Ayobami Adegoke 99cf1000d6 ci: run CLI fixture/mock test suites (#134) 2026-07-12 18:02:23 +02:00
Ayobami Adegoke ff78dae48a test(jobnet): extract pure helpers and add normalization tests (#133)
* docs: clean all add-template compile artifacts

* Add Jobnet CLI normalization tests
2026-07-12 18:02:17 +02:00
Mads LorentzenandClaude Fable 5 1526afcbfe docs: add the maintainer's story to the README (#138)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 16:34:58 +02:00
Mads LorentzenandClaude Fable 5 855b6725f3 brand: tagline line + the hired-moment coffee ask (#136)
* feat(brand): tagline under the H1 and the hired-moment coffee line

Two items from the branding strategy: the positioning line lands in the
README itself (the repo description already carries it), and /outcome's
hired path gets its single, value-framed donation ask - once per hire,
never nagging, never effort-framed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(brand): pay-it-forward framing for the hired-moment line

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 11:17:48 +02:00
Mads LorentzenandClaude Fable 5 013b90132b chore: slim brand assets to just the mascot GIF (#135)
The regeneration pipeline, AI source sheets, retired sprites, avatar,
social card, and internal design/plan docs are maintainer tooling, not
template content - archived in the maintainer's private workspace. Fork
users get the 30 KB animation and nothing they didn't ask for. The
.gitignore PNG allowlist is dropped along with the PNGs it served.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 10:30:55 +02:00
Mads LorentzenandClaude Fable 5 09f0417d78 brand: meet Pip, the courier bird (#132)
* docs: add mascot & brand design spec (Pip the courier bird)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: Pip wears a tie - update mascot spec to v5 flight loop

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: add Pip brand PR implementation plan

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(plan): v7 master GIF - drop frame scaling, add enclosed-hole transparency

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(plan): v8 master GIF - fix hole classification (chest stays opaque)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(plan): scrub stale v5 references

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(plan): v10 master GIF - line-fitted envelope border clipping

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(plan): label pipeline as v10

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(plan): v16 master GIF - targeted removal of gap blob

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(plan): v17 master GIF - drop envelope border clipping, keep blob removal

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(plan): v19 final master GIF - user-approved thin outline repair

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(brand): add Pip mascot assets and regeneration pipeline

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(brand): Pip takes over the README header

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(spec): scrub stale scaling line

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(brand): avatar, social card, and mascot sources (PNG allowlist)

The global *.png personal-data rule silently excluded the mascot's source
sheets and generated PNGs; allowlist the upstream-controlled assets/mascot/
paths without weakening the fork-protecting rule.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 10:21:36 +02:00
Ayobami Adegoke 8bee3ddb97 docs(add-template): clean all test compile artifacts (#130) 2026-07-11 22:06:04 +02:00
Ayobami Adegoke 379abad503 docs(add-template): clarify --use activation metadata (#129) 2026-07-11 22:05:05 +02:00
Ayobami Adegoke 569b1df371 fix(security): harden guard JSON shape handling (#128) 2026-07-11 22:04:54 +02:00
Mads LorentzenandClaude Fable 5 543d1a733e docs: add no-crypto/no-token disclaimer (#127)
The repo's owner has received multiple pump.fun token-sponsorship
solicitations this week. This pre-empts any 'the developer
acknowledged the token' narrative and protects users from
unauthorized schemes trading on the project's name.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:12:42 +02:00
Mads LorentzenandClaude Fable 5 22d8b48dcf docs: add Trendshift #1-repository-of-the-day badge (#126)
Commemorates #1 on GitHub Trending (all languages), July 7 2026.
Official Trendshift embed, linked to the tracked stats page.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 17:24:43 +02:00
♦ jabarii♦ c134eef553 refactor(salary): optimize search match scoring and normalize Excel category keys (#101)
This commit improves the performance and consistency of the salary tools:

- Redundant query normalization and word extraction are eliminated in salary_lookup.py by pre-calculating representations once before the search loop.
- A match_score_optimized helper is introduced to perform the comparison using the pre-calculated query data, preserving full backward compatibility for match_score.
- Normalization in tools/convert_salary_excel.py is unified: paired column headers now consistently substitute spaces and dashes with underscores (e.g. 'software_engineering') to match the single-column formatting.
- Unit test coverage is significantly expanded in tests/test_salary_lookup.py and tests/test_convert_salary_excel.py to cover normalization, anglicization, search filtering, and matching behaviors.
2026-07-10 15:24:20 +02:00
Erik Pastor RiosandClaude Opus 4.8 7e8df35819 docs(job-scraper): make search queries market-neutral (#95)
Rebased onto current master. The SKILL.md description and "How It Works"
copy were already generalized by #102, so this drops those now-redundant
edits and keeps only the unique remaining value: replacing the hardcoded
Danish job boards (jobindex.dk, karriere.dk, jobfinder.dk, akademikernes.dk)
and Danish location terms in search-queries.md with configurable
placeholders and an /add-portal pointer, so the query templates apply to
any market.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 08:06:54 +02:00
Erik Pastor RiosandClaude Opus 4.8 a278ad7a50 refactor(salary): make compound-word matching locale-agnostic (#94)
* refactor(salary): make compound-word matching locale-agnostic

The Excel column detector hardcoded a DANISH_COMPOUND_PATTERNS set inside
header_matches(), so the compound-word matching that helps Danish headers
(e.g. "lønindeks") was baked into the algorithm by name and unavailable to
any other locale without editing the source.

Rename it to COMPOUND_PATTERNS and pass it as a parameter (default
unchanged, so the Danish demonstration data behaves identically). A
different-locale spreadsheet can now supply its own compound tokens via
header_matches(..., compound_patterns=...). Add a test covering both the
preserved default and the parameterized path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(salary): drop unused compound_patterns parameter

Per review: keep the DANISH_COMPOUND_PATTERNS -> COMPOUND_PATTERNS
rename (universal template naming, defaults still Danish), but remove
the compound_patterns= parameter. No caller passes a custom set, and a
fork adapting another locale edits the module-level constant either way,
so parameterizing it is speculative generality per CONTRIBUTING.md.

header_matches() now reads COMPOUND_PATTERNS directly. Test updated to
verify compound-vs-whole-token matching against the constant.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 08:06:05 +02:00
Ayobami Adegoke cd7c22325b ci: run the Python test suite — CONTRIBUTING.md asks for tests CI never executes (#100)
* ci: run the Python test suite - CONTRIBUTING.md asks for tests CI never executes

CONTRIBUTING.md tells contributors to put Python tool tests in tests/
and run the relevant suites, and tests/ now holds real ones
(test_salary_lookup.py, test_convert_salary_excel.py from #75) - but no
CI job executes them. A suite that never runs in CI can't gate a PR and
silently rots. New python-tests job: unittest discover over tests/,
stdlib only, no new dependencies. Future test files run without any
workflow change.

Also lands tests/test_security_guards.py, which missed #84's merge
window (pushed to the branch as #84 was being merged; the merge took
2a6cb8c, the tests were 260c37a). 13 unittest cases in the existing
tests/ style: each copies the guard script into a synthetic repo tree
and runs it as a subprocess - the same way CI invokes it - asserting
real exit codes and messages. Every forbidden state fails (Bash(*) and
Bash(curl:*) additions, each personal-data gitignore rule removed one
at a time, each forbidden lifecycle script, trustedDependencies,
invalid settings JSON, zero manifests); every non-event passes (dropped
shipped permission, extra ignore rules, benign scripts, hostile
manifest inside node_modules); and the real repo passes its own guards.

22 tests total, all passing locally via the exact command the job runs.

* test: use benign lifecycle-script values in fixtures - AV heuristics flag attack-shaped strings

Review found the curl-pipe-to-sh fixture value matches a real Defender
signature (Trojan:Script/Stealer.HAX!MTB): Windows quarantines the temp
package.json mid-test, making the suite flaky for any Windows
contributor who runs it - while proving nothing extra, since the guard
flags the script KEY and never inspects the value.

Fixture values are now 'echo test' (also in the node_modules-ignored
test, same class of string), with a comment on the key-only test
explaining why the value must stay benign so a future 'make the fixture
realistic' cleanup doesn't reintroduce the quarantine flake. Coverage
is unchanged: same keys, same assertions, 13 tests passing.
2026-07-10 08:06:00 +02:00
Kienne d0846aad1d Add Jobdanmark detail HTML fallback (#115) 2026-07-10 08:05:40 +02:00
Kienne 1bc119dffd Report Jobbank Cloudflare blocking clearly (#114) 2026-07-10 08:05:24 +02:00
Sai Sridhar Tarra 44fa00c8c6 test: add coverage for match_score and search_company (#106) (#109) 2026-07-10 08:05:02 +02:00
Sai Sridhar Tarra 30e8b44759 docs: mention /interview as next step after /apply (#108) (#110) 2026-07-10 08:04:23 +02:00