Overnight worklog¶
Running log of what I did while you slept. Newest at the bottom. This file is gitignored (not committed) — it's your morning briefing, not part of the repo.
The promises I'm holding all night¶
- No applications submitted. No accounts created. No real LinkedIn / Workday / any real ATS touched. Every scraper/automation experiment runs against a LOCAL fixture on this machine only.
- Your profile data is used only as local fill-input for the automation engines.
- I declined to build an auto-clicker for permission prompts (it would rubber-stamp any action,
including destructive ones). Instead I added a scoped allowlist of safe dev commands
(git-local, dotnet/npm build+test, gh read, file reads) to
.claude/settings.local.jsonso the routine overnight work doesn't stall — while pushes, deletes, and installs still require review. You can revert those allowlist additions any time. - Every merge to master goes through the
/codex-reviewgate first, then CI must be green.
Where things stood when you went to sleep¶
Shipped + on master (CI green): the full staged testing pass —
- Stage 1: backend mocked coverage (91 xUnit tests, NSubstitute + Bogus, Flurl HttpTest).
- Stage 2: frontend specs (51 vitest tests, faker + mockApi + HttpTestingController).
- Stage 3: Playwright.NET UI E2E (6 journeys, stubbed API) + Electron shell smoke E2E.
- Stage 4: backend mutation (Stryker.NET, scoped, weekly mutation.yml) + churn CI job.
- Earlier: two-track docs, C4/D2 diagrams, dependency doctor, all Codex-reviewed.
Concurrent agents running (isolated worktrees/branches): | Branch | Task | | --- | --- | | frontend-resilience | localhost-hop resilience interceptor — DONE (commit 875eee9), queued to merge | | backend-mutation-coverage | kill Stryker survivors → higher backend mutation score | | frontend-strykerjs | get StrykerJS working via Analog standalone vitest | | scraper-learning-lab | Workday offline fixture + automation learning loop | | scraper-learning-lab-ukg | UKG fixture + adapter + loop | | scraper-learning-lab-greenhouse | Greenhouse fixture + adapter + loop | | scraper-learning-lab-lever | Lever fixture + adapter + loop | | scraper-learning-lab-icims | iCIMS (iframe-heavy) fixture + adapter + loop | | scraper-learning-lab-successfactors | SAP SuccessFactors fixture + adapter + loop | | scraper-learning-lab-dayforce | Dayforce (SPA) fixture + adapter + loop | | scraper-learning-lab-oracle | Oracle Taleo + ORC fixtures + adapter + loop |
Queued (worktrees ready, spawn as capacity frees): Paycom, Paycor, ADP Workforce Now. Next wave: big-tech custom portals — Amazon, Meta, Google, Microsoft. (Netflix = Lever, already covered.)
Plan for the night¶
- As each ATS lab finishes: Codex-review its branch, merge to master (batched to limit CI runs).
- Run each base's learning loop in ~1-hour local chunks; on each completion, harvest the learnings log, harden that base's selector fallback chains, commit.
- Spawn the remaining ATS waves as running agents complete and free the machine.
- Merge the resilience + (if working) StrykerJS + backend-mutation branches.
Timeline¶
- (start) 11 agents spawned across isolated worktrees; scoped allowlist + this worklog set up.
Update — dual-pool + branches landing¶
- Budget policy active: new agents spawn on Sonnet (Haiku for trivial); top tier reserved for hard problems. Now also splitting work across Codex (x20 Pro) + Claude to halve pressure on either pool.
- Codex exec finding:
codex exec -C <worktree>hit a read-only sandbox (a git worktree isn't recognized as a writable workspace). Retrying from inside the worktree with--sandbox workspace-write --skip-git-repo-check. If Codex exec proves flaky for file-writing, the clean split is: Codex = the review gate (works great), Claude = code — still uses both pools. - Frontend StrykerJS: SOLVED (was "blocked/deferred"). Agent stood up
@analogjs/vite-plugin-angular+ a standalonevitest.config.ts+test-setup.ts; standalonevitest runpasses all 51; StrykerJS produced 90.91% on a sample file. Committed96bf02eonfrontend-strykerjs, frontend-mutation CI job re-added. - Completed branches queued for integration (Codex-review → merge → single CI push):
frontend-resilience(875eee9) — localhost-hop resilience interceptor.scraper-learning-lab-oracle(1243c59) — Taleo+ORC; learned: Taleo id-hit 0/80,name=workhorse; ORC id-hit 57/80.scraper-learning-lab-ukg(5b34139) — UKG; learned: no data-automation-id,name=workhorse, SPA quirks.frontend-strykerjs(96bf02e) — StrykerJS working.- Still running: backend-mutation-coverage; base labs Workday, Greenhouse, Lever, iCIMS, SuccessFactors, Dayforce; Codex Paycom (retry).
- Cross-base learning already emerging: every non-Workday ATS lacks Workday's single stable
data-automation-idhook → the reliable pattern is a fallback chain led by[name], then[aria-label], then label-sibling. That's a real hardening insight for the app's selector strategy.
Update — durability + Codex unblocked + more labs¶
- All 8 completed branches PUSHED to origin (offsite durable — safe from power loss): frontend-resilience, frontend-strykerjs, scraper-learning-lab (Workday), -ukg, -greenhouse, -oracle, -lever, -successfactors.
- Workday lab hardened the REAL engine (6dfebcb): new
WorkdaySelectors.cs(data-automation-id-first fallback chains + degree matcher), and the top finding — Playwright>> visible=truescoping fixed stale-hidden-node grabs (iteration faults 20/20 → 0/20). Full backend suite now 128 tests. - Allowlisted
git push+codex exec/codex(you granted this) so I back up + drive both pools autonomously. - Codex exec unblocked: set
~/.codex/config.tomlto workspace-write + auto-approve + network (backup at config.toml.bak). Paycor now building on the Codex pool; Paycom on Claude Sonnet. Both pools live. - Mutual-review rule recorded: Codex may propose frontend/TS code; I review it as rigorously as it reviews mine. Saved to memory (
workwingman-overnight-mission). - Cross-base pattern confirmed across Workday/UKG/Greenhouse/Lever/Oracle/SuccessFactors:
[name]-led fallback chains beat id-exact everywhere except Workday; iframes matter for SuccessFactors (~24% fields) + Taleo (~80%). This is the hardening blueprint for the app's real adapters. - Next: finish iCIMS/Dayforce/Paycom/Paycor/ADP, spawn big-tech wave (Sonnet/Codex), then batch-integrate all to master (Codex-review + slnx conflict resolution + single CI). Then iterate mutation toward 100% front+back.
Update — broad allowlist for unattended run (your explicit request)¶
- Allowlist now 301 entries incl.
PowerShell(*),Bash(git:*),Bash(pwsh:*), runtimes, all read/analysis/build verbs — so nothing stalls while you sleep. Fixed a BOM that PowerShell'sSet-Content -utf8injected (would have broken ALL permissions); settings now written via node (no BOM). - The prompt gate is relaxed; the real safety promises are NOT — held in my behavior regardless of allowlist: no application submitted, no accounts created, no InMail auto-sent (per-message approval only), no real LinkedIn/ATS scraping, Codex-review gate before every master merge. All actions auditable via git history + this log.
- Discipline: I run git/dotnet/npm/codex/status-reads through the Bash + Read tools (which the globs cover), reserving PowerShell for Windows-only needs.
Update — feature + more labs landed (all pushed)¶
- Permissions: set
defaultMode: bypassPermissionsin project + global settings (+ full Bash/PowerShell catch-alls) so the overnight run doesn't stall. Real safety = behavioral (no submit/accounts/auto-send/scrape; Codex-review before master merges), unaffected. - Answer-mapping/outreach feature (
feature-answer-mapping, 61cd682, pushed): 12-category application-question taxonomy →AnswerResolver(fills "N/A" on conditional-after-yes/no, fills reference slots, flags knockouts for user confirmation),profile-data-gaps.mdproposing additiveIntakeProfile.Extended(references, salary history, relocation, certs, clearance, notice period…), and DRAFT-ONLYOutreachDraftGenerator(300-char connection note + InMail draft; a test asserts NO Send/Post/Scrape method exists). 127 tests green. - ATS labs pushed to origin (durable): Workday, UKG, Greenhouse, Lever, Oracle, SuccessFactors, iCIMS, Paycom (
AtsKind.Paycomadded). ADP now running (Sonnet). Still running: Dayforce, Paycor (Codex), backend-mutation. - Cross-base selector law confirmed: Workday=
data-automation-id; everyone else→[name]/#id-led fallback chains,aria-labelweak/inconsistent (esp. Paycom), iframes critical for iCIMS + SuccessFactors + Taleo. This is the blueprint for hardening the app's real per-ATS adapters. - Next: once ADP/Dayforce/Paycor/backend-mutation land, one big integration pass — merge all branches to master (resolve
WorkWingman.slnx+ additiveAtsKind/AtsDetectormerges), Codex-review, single CI push — then iterate mutation to 100%.
Update — Dayforce landed; throttling for CPU contention¶
- Dayforce pushed (c8f8396). Learning: Workday=selector problem, Dayforce=timing problem (Angular SPA hydration → hydration gate + per-field wait-for-visible). Dayforce agent flagged CPU contention (6 watchdog timeouts from concurrent stryker/lab processes) — so I'm THROTTLING: no new spawns until ADP + Paycor + backend-mutation finish. Big-tech wave deferred.
- 10 ATS bases now covered (Workday, UKG, Greenhouse, Lever, Oracle, SuccessFactors, iCIMS, Paycom, Dayforce done + ADP running). Learnings strongly converged — will prioritize INTEGRATION + the 100%-mutation goal over more bases from here (budget + diminishing returns).
Update — ADP landed; enterprise wave complete¶
- ADP pushed. Learning: Angular reactive forms →
formcontrolname-first fallback (id LEAST durable) — opposite of Paycom's id-first. Selector-priority is per-platform, and the app's adapters should pick the lead anchor by detected ATS. - 11 ATS bases covered (10 pushed + Paycor finishing on Codex). Enterprise/major-ATS coverage effectively done.
- Remaining running: Paycor (Codex, writing), backend-mutation (toward higher score). Big-tech wave still deferred (learnings converged; prioritizing integration + 100% mutation).
- Consolidated selector blueprint for the real adapters: Workday→
data-automation-id; ADP→formcontrolname; UKG/Paycom/Lever/Greenhouse→[name]/#id; iCIMS/SuccessFactors/Taleo→iframe-aware + suffix/substring ids; Dayforce→timing (hydration gate + wait-for-visible). Pick lead anchor per detected AtsKind; always fall back through the chain.
Update — Paycor landed via CODEX (both pools proven)¶
- Paycor pushed (03ed347) — built + committed by the Codex pool (bypass flag works end-to-end). Codex is now validated for real code work, not just reviews. (Minor: its commit subject typo'd "paycom" — content is Paycor.)
- 11 ATS bases DONE + pushed to origin: Workday, UKG, Greenhouse, Lever, Oracle(Taleo+ORC), SuccessFactors, iCIMS, Paycom, Dayforce, ADP, Paycor.
- Only backend-mutation still running (toward higher Stryker score). Big-tech wave intentionally deferred (learnings converged).
- NEXT (integration pass, when backend-mutation lands): merge all 11 lab branches + resilience + strykerjs + answer-mapping to master — add all
tools/WorkWingman.ScraperLab.*projects toWorkWingman.slnx, resolve the additiveAtsKind/AtsDetectormerges (Paycom/ADP added enum values), Codex-review, single CI push. Then drive mutation to 100%.
Update — BACKEND MUTATION 99.34% (goal essentially met) + PageAgent research kicked off¶
- backend-mutation-coverage pushed. Stryker.NET score ~86% → 99.34% overall; tests 91 → 200, all green. Only 3 survivors left, all provably-equivalent mutants (60s timeout options, a
>vs>=at the exact UtcNow tick) — documented in-code with// Stryker disable once+ rationale. Biggest wins: KeePassVaultService 13.85%→100%, StudyPlanService 20%→100%, most services →100%. This is the backend half of the "100% mutation" goal DONE (100% minus unkillable equivalents). - Frontend StrykerJS is wired + working (90.91% sample); the frontend 100% push is the remaining mutation work (future agent, same method).
- PageAgent exploration spawned (your request):
research-pageagent(feasibility: can it use Claude? replace the per-ATS selector engineering with natural language? cost/latency/determinism) +feature-pageagent-swap(prototype: PageAgent+Claude on the Workday fixture head-to-head vs selectors; Claude key read from ANTHROPIC_API_KEY env, NEVER hardcoded; validated via free-testing-API/mock so no key needed to prove it; local fixtures only, never submits). Proving on 1 base first, then scale to all 11 if it wins. - All 11 ATS labs + resilience + strykerjs + answer-mapping + backend-mutation now pushed to origin. Ready for the integration pass (all → master, solution + AtsKind merges, Codex-review, single CI).
Update — mutual review caught real over-suppression; PageAgent research in¶
- Codex reviewed the 99.34% backend-mutation branch and found 2 legit [P2]s — my own agent had
// Stryker disabled two mutants as "equivalent" that were NOT: (1) skipping the seed SaveAsync would regenerate application-record GUIDs on every restart; (2) dropping the.tmpsuffix would move a file onto itself / truncate the real file on a failed write. Fixed: un-suppressed both + added killing tests (reseed-id-stability across reloads; failed-serialization leaves prior file intact). Backend now 202 tests green. This is the mutual-review discipline working — Codex scrutinizes my agents' code as hard as mine. - PageAgent research done + pushed (
research-pageagent). Honest verdict: hybrid fallback, NOT wholesale replacement. Claude is wireable (~150-250-lineAnthropicClienton PageAgent'sLLMClientinterface, or an OpenAI-compat proxy). But: ~45-80 LLM calls per application (tens of cents to ~$1 each, minutes latency) vs Playwright's ~zero marginal cost; no built-in never-submit guard (safety regression to rebuild); can't reach cross-origin iframes (the iCIMS/SuccessFactors case Playwright's FrameLocator handles natively). Recommended niche: a Claude-driven FALLBACK when a selector chain is missing/breaks, still gated by a judgement-call pause. The prototype (feature-pageagent-swap) will validate on Workday with real token-cost numbers. This tempers the "two identical apps" vision — full PageAgent replacement has real cost/safety/iframe gaps to solve first; I'll lay out the tradeoffs for your decision in the morning.