Microsoft Careers Scraper Automation Learnings¶
This lab is an offline, loopback-only fixture for the bespoke Microsoft careers apply flow. It does not call careers.microsoft.com, does not use a real account, and never submits. The local HttpListener binds to 127.0.0.1, renders deterministic seeded HTML, and exposes a submit route that is a no-op.
Selector strategy¶
Microsoft's careers flow is not a standard ATS vendor surface. There is no Workday-style data-automation-id contract and no iCIMS-style generated suffix pattern to lean on. The selector chain in MicrosoftSelectors therefore uses this order:
- Semantic
idvalues when present, such asfirstName,highestDegree, andsubmitApplication. - Semantic
namevalues, such asfirstName,degree, andrelocation. aria-labelvalues for degraded DOMs where ids are dropped.- Label-adjacent selectors such as
label:has-text('First name') + input.
The engine always asks Playwright for the first visible match through Locator(selector).Locator("visible=true").First. This matters because multi-step fixtures keep prior steps in the DOM but hidden. Repeated ids across hidden steps are a common failure mode in scraper labs; visible-first resolution prevents a hidden previous-step control from being filled or clicked.
Fallback chain¶
The fixture randomizes each field with IdStyle.Primary, IdStyle.Degraded, IdStyle.AriaOnly, or IdStyle.Missing. Primary hits exercise semantic ids. Degraded hits exercise names. Aria-only hits exercise accessibility metadata. Optional missing fields exercise not-found telemetry without halting the whole loop.
The review submit button is intentionally part of the selector set only so the automation can locate it. The lab then logs would submit (suppressed) and never clicks. The fixture button also has onclick="return false" and /submit is a no-op route.
Timing quirks¶
The fixture injects seeded page activation delays on some iterations. The runner waits for #step-*.active, then field-level resolution applies short per-selector timeouts. This catches brittle timing assumptions while keeping the 20-iteration learning loop fast enough for local development.
Hit-rate numbers¶
The lab writes JSONL plus a console summary after every five iterations and at the end. A successful 20-iteration run reports:
CompletedequalsIterations.SuppressedSubmitsequalsIterations.SubmitLocatedequalsIterations.- selector rows show primary hits versus fallback hits by field.
judgement-call:degreeandjudgement-call:custom-questionrecord expected ambiguous-field pauses.
Verified run on July 4, 2026 with --iterations 20 --seed 1337:
| Field | Attempts | Match rate | Primary hits | Fallback hits |
|---|---|---|---|---|
| Account continue | 32 | 62.5% | 8 | 12 |
| Account email | 42 | 47.6% | 3 | 17 |
| Account password | 33 | 60.6% | 11 | 9 |
| Address | 44 | 38.6% | 9 | 8 |
| Degree | 32 | 62.5% | 11 | 9 |
| Employer | 36 | 55.6% | 10 | 10 |
| First name | 41 | 48.8% | 6 | 14 |
| Last name | 35 | 57.1% | 9 | 11 |
| Next / Continue | 80 | 100.0% | 80 | 0 |
| Phone | 44 | 38.6% | 8 | 9 |
| Relocation preference | 32 | 62.5% | 12 | 8 |
| Resume upload | 26 | 76.9% | 14 | 6 |
| School | 37 | 54.1% | 8 | 12 |
| Submit button | 20 | 100.0% | 20 | 0 |
Overall: 20 iterations, 20 completed, 0 faulted, 18 judgement pauses, 20 submit controls located, and 20 suppressed submits. Expected failure-mode telemetry was judgement-call:degree 16 times and judgement-call:custom-question 13 times.
Why Microsoft is a prime PageAgent-advisor case¶
Microsoft's bespoke DOM is exactly where a PageAgent-style advisor is useful. The engine can fill deterministic fields through ordered selectors, but degree and custom screening questions still need semantic interpretation of arbitrary page text and option lists. The lab raises RunStatus.AwaitingJudgement with an ApplicationRun.PendingCall instead of guessing.
The IPageAdvisor seam being built on branch feature-pageagent-swap can plug into this judgement pause unchanged: the engine already exposes the field label, question, context, ranked options, and current run state. The advisor can inspect the visible DOM and recommend a ranked answer without changing the submit guard or selector resolver.