Commit Graph
8 Commits
Author SHA1 Message Date
dennisthiessenandClaude Opus 5 afdef7eb94 refactor: shared agent workflows (F01) and one application registry (F02)
Checkpoint for the 2026-09-11 project review remediation. Work by a previous
agent that ran out of context; committed unchanged as a rollback point before
the remaining findings land on top of it.

F01 — the two agent directories had drifted into different processes
- Six shared workflows under `resume_builder/reference/workflows/`; both
  `.agents/skills/` and `.claude/skills/` are now thin entrypoints that route
  to the same file instead of carrying full copies.
- The `.claude` copies were the stale side: fixed bullet line variants and
  character budgets that the newer process had already dropped. Removing them
  is the point of the change, not collateral.
- Parity/link regression test added; corrected the top-level file map, which
  pointed at a directory that does not exist.

F02 — application status was stored in four places and disagreed
- New registry `job_scout/state/applications.json` (26 records) with
  `application_records.py` (schema, validation, transactional write) and
  `application_tracker.py` (add/update, no quota).
- AGENTS.md and CLAUDE.md no longer keep their own status tables; both point
  at `current_applications.md`, generated from the registry.
- Interview-reached is now independent of outcome, so a withdrawal after an
  interview can record both facts. The old tables are preserved verbatim in
  `job_scout/state/history/application_status_before_2026-09-11.json`.

Verification: `python -m unittest discover -s tests -v` — 18/18 pass.
Spot-checked that the detailed SBB and Kdo Cy notes survived the migration
into the registry rather than being flattened.

Known unresolved, deliberately not invented (see FIX_PROGRESS.md):
Aker BP's application date and its Adjacent-despite-79 classification.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qej5SBvhcbGXHwLqNWiskM
2026-09-11 19:23:13 +02:00
dennisthiessenandClaude Opus 5 0d999ab21b feat(scout): automate Kdo Cy via Prospective API; close SBB and Kdo Cy
Scout
- New `prospective` adapter for ohws.prospective.ch, wired up as `kdocy`
  (jobs.admin.ch, filtered to Kommando Cyber). jobs.admin.ch is an S3-hosted
  SPA that returns AccessDenied to any direct fetch, headless included, so the
  site cannot be scraped -- but the SPA reads a public, unauthenticated API.
  All 463 federal roles in ~2.4s, against RUAG's 35s Playwright scrape.
- This board is richer than any other source: Lohnklasse, application deadline,
  a named contact per posting, and the full Aufgaben/Anforderungen body, so
  scoring runs against the JD text rather than the title.
- Thread `deadline` through normalization, the markdown report and the JSON
  dump. A board with hard deadlines needs them on the row.
- Match `verwaltungseinheit_*` by prefix: the sub-unit key is department
  specific (VBS 1083398, EFD 1083364) and hardcoding one breaks reuse.
- MANUAL_CHECK entry for the Bundeswehr Reserve portal. The data is reachable
  (SAP E-Recruiting OData, SearchCategory 0022) but the portal actively blocks
  automation, and getting through needs UA spoofing plus masking
  navigator.webdriver. Not wired up by choice -- the operator-sanctioned
  Suchauftrag/job alert is the better channel. Reasoning is in the comment.

Applications
- SBB Data Engineer 103755: interviewed 2026-09-09, WITHDRAWN by the candidate
  2026-09-11. Net downgrade on four axes (41h vs 40h, 25+Brueckentage vs 28+5,
  3 vs 2 office days, and Anforderungsniveau K tops out ~145k against ~135k
  inside a band running to ~160k -- he would enter K at its ceiling merely to
  break even). The cohort's only interview, and it ended as his no, not theirs.
- Kdo Cy DevOps Engineer III: REJECTED 2026-09-10, 14 days, no interview.
  Form letter with no diagnostic content. Identical on every recorded
  dimension to SBB (core / 79 / gate pass / DQ 92 / weak channel) and the two
  went opposite ways -- recorded as worth watching, not as evidence for the
  channel thesis.
- Citadel row cleaned up: it claimed the cohort and decision-log entries were
  deliberately unwritten while its own status line read SUBMITTED. Both exist.
  The next-step cell still said "ask BEFORE building the package" two weeks
  after submission.

Decision log
- 69 RUAG rows -> 3 undecided. 63 title/family rule-outs, each noting that it
  is not a JD read, plus three that are: Test Manager C5I, System Engineer C5I,
  ICT Solution Architect. Guarded against the shared F/A-18 slug so one write
  could not silently swallow the other.

Note: the K->L/Kader rule is SBB-specific and was deliberately narrowed --
Anforderungsniveau is SBB's own system and does not map onto jobs.admin.ch
(Lohnklassen), RUAG or PostFinance. Thun-area employers sit outside the Bern
salary logic entirely.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qej5SBvhcbGXHwLqNWiskM
2026-09-11 17:30:46 +02:00
dennisthiessenandClaude Opus 5 a0ec2fedb5 feat: NVIDIA Sr DevOps application, drop cohort caps, fix Workday/decision-log bugs
Scout run 2026-09-04 (36 companies, 778 eligible) plus the NVIDIA package it
surfaced, and the tooling and policy fixes found along the way.

Application
- NVIDIA Senior DevOps Engineer, Zurich (JR2024256): submitted 2026-09-05.
  Evidence Fit 64/100 Stretch, hard gate FAIL x2, channel Weak. Sent on an
  explicit user override with the working model unresolved, so hybrid-vs-onsite
  is a live screening topic. 2pp resume + 1pp cover letter, both validators
  PASS, 0 boxes, 0 Tier 1 findings open.

Policy
- Drop the 7 Core / 2 Adjacent / 1 Stretch cohort caps. They had no derivation
  and were overridden whenever they bound, and the cohort was confounded: it
  tested fit class while holding channel constant at Weak across all six
  applications. Keep the recording, drop the rationing.
- Channel replaces the slot budget as the rationed variable: no application
  goes out cold when a named contact is published and reachable.
- Propagated through shared_ops, session_file_template, cohort_tracker
  (counts, never counts-against-a-target) and application_cohort.json.

Tool fixes
- fetch_workday emitted 404 URLs for every Workday company (NVIDIA, Novartis,
  Equinor): externalPath is site-relative and needs the locale + site prefix.
  6/6 short-form 404, 3/3 long-form 200. 773 dead links repaired across 42
  archived reports.
- find_decision_url silently de-linked decisions on two boards, which is why
  ruled-out roles kept resurfacing as undecided. RUAG rotates its UUID on
  repost; BIS migrated its vacancy URL scheme, orphaning 5 decisions including
  a live application. Fixed as a two-tier match, not a slug key -- slugs
  collide (two live RUAG reqs shared one).

Knowledge base
- claims.json: add Bash / shell scripting, the third canonical gap of this
  shape after Ansible and Linux administration.
- bundle_data_platform: BS-4 was framed as a delivered observability stack over
  what claims.json calls a proof of concept -- the defect the 2026-08-21 sweep
  was told to look for.
- CLAUDE.md and AGENTS.md: correct the RUAG Data Lakehouse shortlist claim,
  which the JD does not support and which both files still asserted.
- resume_template: comment-guard the missing babel/ngerman language block.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFb8tTCig5r1KzkQiNXcYt
2026-09-05 13:24:44 +02:00
dennisthiessenandClaude Opus 5 9a188cafef feat(sbb): interview invitation 2026-09-09, write interview brief
SBB Data Engineer (Job ID 103755): invited 2026-08-28 for Wednesday
9 September 2026, 08:30, 45 min on Teams.

Per the posting's own process this is stage 2 of 4 - "Virtuelles
Kennenlernen mit HR und Fuehrungskraft" - so HR together with Andri
Wienandts, not a pure HR screen. 45 minutes shared between two people,
which is the practical constraint the brief is built around.

Two facts worth recording:
- This is the FIRST conversion of the evidence-first cohort (6
  applications, 2 rejections), and it came from a COLD submit. The
  channel plan called for phoning Wienandts before applying; that never
  happened, so the published warm contact went unused.
- The resume never contained Snowflake, dbt or Power BI - the three
  literals an ATS keyword screen would have keyed on, and a risk the
  session had explicitly recorded as "accepted, not solvable". It did
  not filter him out, so a human read the dossier and the honest
  substitution framing survived first contact. One data point; not
  enough to revise strategy on, but it is evidence against assuming
  honest omissions are fatal at the screen.

Brief covers the four questions that must not go unasked (Anforderungs-
niveau K band, design/architecture scope vs current Staff + Component
Owner level, RAMSI's Java/Spring Boot/Angular share, Kidz Care rate),
the substitution answers for each named-but-non-canonical tool, the
swissTAMP/RIS/MUD context, and the thesis boundary - methods prototype,
no operational data, no accuracy figures, PSO surveyed only.

It also asks him to decide three things before the call rather than on
camera: what he does if K lands at 130-150k, if architecture is set
elsewhere, or if RAMSI turns out to be heavily Angular. Any one can be
a no, and the level question is the same shape as the declined BKW.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JMcHCsTKWvVzqyLChF5ckk
2026-08-28 16:41:55 +02:00
dennisthiessenandClaude Opus 5 a0f844c143 feat(ruag): submit AI Engineer C5I, and record the Kdo Cy package
RUAG C5I - AI Engineer C5I (Thun, app ID 18027): SUBMITTED 2026-08-27.
Evidence Fit 74/100, fit class Stretch, title-capability hard gate FAIL
(R1 build/operate the AI-LLM platform and R2 in-house LLM/retrieval are
Adjacent, not Direct) - all knowingly accepted under the user's explicit
Phase 0 override. Consumes the cohort's sole Stretch slot: cohort is now
6/10, Stretch 1/1.

Critique ran twice. Round 1 scored the documents 85/100 and raised three
Tier 1 items; Round 2, after the fixes, scores 93/100 with truth and
provenance 24/25 and zero Tier 1 findings. Evidence Fit did not move and
was not allowed to: PP-3 is a personal project and cannot convert an
Adjacent title-capability into a Direct one.

Documents (.tex is the deliverable; PDFs are gitignored):
- resume 2pp/13 bullets, letter 1pp/295 words, both validators PASS
- headline is now the canonical title "Staff Data, Analytics & AI
  Engineer", which puts the req's own word above the fold
- PP-3 added as a Projekte section - the only current Linux/hardening
  evidence, since BS-6 ended Dec 2022
- the letter names the AI-platform gap in one sentence, then connects
  SW-5 to C5I's stated DevSecOps model
- "governte" -> "governance-konforme"; JD term coverage 18/22 -> 22/22
  claimable, with all six gap terms still correctly absent

Two defects found and fixed that the first critique missed:
- the resume never loaded babel, so a German document was hyphenated
  with English patterns (Hal-bleiterfertigung, Tran-skription). Fixed
  with babel[ngerman] plus a Transkription exception; this also cleared
  an overfull box. Check this on every future German package -
  resume_template.tex likely has the same omission.
- IBM AI Engineering had no primary-source record. Certificate read
  directly (IBM via Coursera, 4 Jun 2020, verify 3ZBZFVAL6A34), recorded
  as entry #8; it also proves PyTorch, now evidence: certification.

Also included: the submitted Kdo Cy DevOps Engineer III package, the
Capgemini omit rule promoted into config.md, BW-1 canonicalized in
experience_bundeswehr.md, and a scout.py comment correcting the
telenorgroup slug from "near-empty" to a claimed board serving stale
phantom listings that DEMO_TITLES would not catch.

Compensation, PSP/project eligibility and role level were never resolved
before sending and are now live screening topics.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JMcHCsTKWvVzqyLChF5ckk
2026-08-27 23:20:17 +02:00
dennisthiessenandClaude Opus 5 93b0fc5b76 chore(akerbp): record rejection, cold channel and slot stays consumed
Rejected 2026-08-27, no interview, ~28 days after submission. Recorded
in all four places that track an outcome: cohort state, decision log,
the Active Sessions row and the session file's status block.

The cohort slot is not freed. A rejection consumes an attempt the same
way a submission does, so the Adjacent count stays 2/2 and the cohort
stays 4/10 - unlike the Google FDE III and AWS FDE no-gos, which were
declined before a package existed.

Recorded as rejected_no_interview on the evidence: nothing in the log
shows any contact after submission. Recruiter-vs-hiring-manager
disposition is a tracked cohort variable, so this is one edit away from
being corrected if a screen did happen.

The package was validator PASS with no Tier 1 truth findings and the
follow-up email to Per Olav Marthinsen was never actioned, making this a
pure cold submit. A cold-channel no-interview rejection does not
implicate document quality on its own. That is now 2 of 4 cohort
applications rejected without interview, both cold, which fits the
channel thesis already in the log - and application_strategy.md forbids
reacting to a single rejection, so no positioning or targeting changed.

The Norway lane is explicitly not closed. NATO JWC Stavanger is still
live and strong Norwegian employers remain in scope; both the row and
the decision note say so, because with Aker BP closed the earlier
Equinor note ("lane now reduced to the open Aker BP application") would
otherwise read as an implied closure.

Submission date left inconsistent on purpose: the contemporaneous
records say 2026-07-29, the retrospective ones 2026-07-30. Both now
carry a note pointing at the other rather than one being overwritten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JMcHCsTKWvVzqyLChF5ckk
2026-08-27 14:45:09 +02:00
dennisthiessenandClaude Opus 5 5cd5f49aa5 chore(citadel): record submission, and the form had no Zurich option
Submitted 2026-08-26. Cohort entry added (Adjacent 2/2, cohort now
4/10, channel weak x3) and decision logged.

The finding that matters is not the submission. The application form's
preferred-work-location selector offered no Zurich, despite the JD body
reading "in Miami, Zurich or New York", the posting header listing
Zurich, and the site's own Zurich location filter returning this exact
req when checked on 2026-08-25. The careers site footer reads Citadel
Enterprise Americas LLC, so the likeliest explanation is a US-entity
apply flow with European seats routed elsewhere, or a Zurich seat that
is closed while the multi-location posting stands.

This partly supersedes the working-model risk that blocked Phase 2. If
no Zurich seat is reachable through that form, whether Zurich runs
hybrid or five-day onsite is moot, and the application may be sitting
against a US requisition - a hard no under the standing no-relocation
constraint.

Carry-forward rule recorded in both CLAUDE.md and the session file:
check the application form's location selector before investing in a
package. Two independent signals - the posting's stated locations and
the employer's own location filter - both proved unreliable as evidence
that a seat is actually reachable. Phase 0 treated the filter result as
confirmation that the req was live in Zurich; that inference was weaker
than it looked.

Package itself is finished and reusable: both documents cleared the
validator with zero warnings and the Tier 1 fixes lifted JD term
coverage from 51% to 68%. Nothing about the documents is the weak point.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MHtzyTKBcg6BWhD5qFegtK
2026-08-26 09:49:08 +02:00
dennisthiessenandClaude Opus 5 af7189a93d chore(scout): version the application cohort tracker
application_cohort.json was caught by the blanket job_scout/state/*
ignore, so the cohort slot record (core/adjacent/stretch mix and every
application's fit class, evidence fit, hard gate and outcome) existed
only on one machine. decisions.json escaped the same rule only because
it had been tracked before the rule was added - an accident of history,
not a decision.

Both files are durable application history and belong in the repo. The
churny scan state (seen_jobs.json, last_scrape.json) stays ignored, as
does reports/ - all of it is regenerable by re-running the scout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MHtzyTKBcg6BWhD5qFegtK
2026-08-25 09:08:14 +02:00