ATS Labs — build spec for the 8 newly-detected ATSes (WW-ATS)¶
Detection for these 8 landed in AtsDetector (commit 4307589). Next: a per-ATS
ScraperLab so an agent can build + iterate each apply-automation engine against a
fake site before promoting it to a production src/…/{Ats}ApplyEngine.cs.
Lab template (copy from tools/WorkWingman.ScraperLab.Lever/)¶
Each tools/WorkWingman.ScraperLab.<Ats>/ mirrors Lever's file set:
- WorkWingman.ScraperLab.<Ats>.csproj — Exe, net10.0, IsPackable=false, Playwright ref,
ProjectReferences to WorkWingman.Core + WorkWingman.Infrastructure.
- <Ats>Selectors.cs — ordered fallback selector chains (id → name → aria → placeholder).
- <Ats>AutomationEngine.cs — fill engine. SINGLE-PAGE unless noted. Submit is LOCATED, NEVER
clicked (hard invariant). Custom question the profile can't answer → JudgementCall, never guess.
- Fake<Ats>Site.cs — offline fixture HTML mirroring the real form (seed from recon below).
- <Ats>Variation.cs, LabProfile.cs, LabVault.cs, LabMetrics.cs, LoopRunner.cs, Program.cs
— harness boilerplate, copy from Lever and rename namespace.
- Add both the lab and a .Tests project to WorkWingman.slnx.
Per-ATS recon (markers live-verified ✅ / web-confirmed ⦿)¶
| ATS | Kind | Host / fingerprint | Live board to harvest form | Page shape |
|---|---|---|---|---|
| SmartRecruiters | SmartRecruiters |
smartrecruiters.com ✅ |
jobs.smartrecruiters.com/{co}/{id} ; API api.smartrecruiters.com/v1/companies/{co}/postings | hosted form, single page |
| Ashby | Ashby |
ashbyhq.com ✅ |
jobs.ashbyhq.com/{co}/{uuid}/application ; GraphQL /api/non-user-graphql | SPA, single page |
| Workable | Workable |
workable.com ✅ |
apply.workable.com/{co}/j/{TOKEN}/apply/ ; API /api/v3/accounts | single page |
| Jobvite | Jobvite |
jobvite.com ✅ |
jobs.jobvite.com/{co}/job/{id} | server-rendered, jv-* classes |
| Eightfold | Eightfold |
eightfold.ai ⦿ |
{co}.eightfold.ai/careers/job/{id} (nvidia/eaton/lamresearch) ; API /api/apply/v2 | SPA (PCSApp) |
| RippleHire | RippleHire |
ripplehire.com ⦿ |
{co}.ripplehire.com/{co}/careers ; portal {co}-cp.ripplehire.com/candidate-portal | portal, sign-in gated |
| Salesforce Sites | SalesforceCareers |
salesforce-sites.com ⦿ |
slalom.my.salesforce-sites.com/careers , /buildcareers | Experience Cloud (aura/lightning) |
| Phenom | Phenom |
fingerprint: data-ph-at-*, phApp.ddo, phenompeople.com ⦿ |
careers.geaerospace.com/global/en/... , careers.phenom.com | employer-domain SPA |
Harvest procedure (per ATS): open the live board in the Browser pane → read_network_requests
(API host/path) → read_page / get_page_text (field labels, data-* anchors, submit control) →
record the apply-form field set + selector anchors → encode into Fake<Ats>Site.cs + <Ats>Selectors.cs.
NO PII entry, NO submit (walk-forms-only), same posture as the ATS-walkthrough weekend.
Build order (cleanest first — single-page hosted forms)¶
- Ashby, 2. SmartRecruiters, 3. Workable, 4. Jobvite (hosted single-page — closest to Lever template)
- Eightfold, 6. Phenom (SPA — need hydration waits like the Workday/Icims engines)
- SalesforceCareers, 8. RippleHire (auth/sign-in gated → attended-only engine,
SupportsBackgroundDrive=false, mirror the Avature/Amazon attended-only posture)
Promotion¶
When a lab's engine reliably fills its fake site (selector hit-rate tracked by LabMetrics), promote to
src/WorkWingman.Infrastructure/Automation/{Ats}ApplyEngine.cs + {Ats}Selectors.cs, register in
Program.cs + ApplyEngineRouter, add {Ats}ApplyEngineTests.cs. Then the router drives real applies
for that Kind instead of the generic manual checklist.
Safety invariants (every lab + engine)¶
Never click Submit (locate only). Never type stored passwords. Never create accounts. Attended-only ATSes (sign-in/account-gated: RippleHire, SalesforceCareers) publish the run as Paused, not Running.