Application question taxonomy (technical)¶
Every question shape ATS forms (Workday, Greenhouse, Lever, iCIMS, UKG, and the rest) ask,
grouped by category. Each entry maps to the QuestionType enum in
ApplicationQuestion.cs, the
IntakeProfile field that answers it, and — where relevant — the edge case that makes it
tricky to automate. Resolution logic lives in
AnswerResolver.cs.
Plain-language version: ../plain/application-question-taxonomy.md
Source of truth: the code. If this page and AnswerResolver.cs disagree, the code wins — fix
the page (see the two-track docs rule in contributing.md).
How to read the tables¶
- Profile field — the
IntakeProfile(orIntakeProfile.Extended, see profile-data-gaps.md) memberAnswerResolverreads. - Needed from user — the information any user must supply, once, for this question to ever resolve — independent of which specific ATS asks it.
- Edge case — a behavior that breaks naive automation; see Edge cases below for the shared handling.
1. Identity / contact¶
| Question | QuestionType |
Profile field | Needed from user |
|---|---|---|---|
| Legal first/last name | LegalFirstName / LegalLastName |
Contact.LegalFirstName/LastName |
Name exactly as it appears on a government ID (some ATSes validate this against later background-check steps). |
| Preferred / goes-by name | PreferredName |
Contact.PreferredName (falls back to legal first name) |
Optional nickname. |
Email |
Contact.Email |
One address the user actually checks — this becomes the ATS account login. | |
| Phone | Phone |
Contact.Phone |
Best contact number, with country code if outside the US. |
| Mailing address | Address |
Contact.Address |
Full street address — some forms split this into street/city/state/zip fields; WorkWingman stores it as one string and lets the automation engine split on fill. |
2. Work authorization + sponsorship¶
| Question | QuestionType |
Profile field | Needed from user |
|---|---|---|---|
| "Are you authorized to work in [country] without sponsorship?" | AuthorizedToWorkInCountry |
Eligibility.AuthorizedToWorkUs |
A true yes/no — this is a knockout question (see below). |
| "Will you now or in the future require sponsorship?" | RequiresSponsorshipNowOrFuture |
Eligibility.RequiresSponsorship |
A true yes/no — also a knockout question. Note the two questions are logically linked (rarely both "No, don't need it" + "Yes, will need it") but AnswerResolver treats them independently since ATSes phrase them independently. |
| Visa status / type held | VisaStatus |
Derived from Eligibility.RequiresSponsorship |
Specific visa type (H-1B, TN, OPT, etc.) if sponsorship is relevant — not fully structured yet, see gaps doc. |
3. Eligibility (age, clearance, non-compete)¶
| Question | QuestionType |
Profile field | Needed from user |
|---|---|---|---|
| "Are you at least 18 years old?" | IsAtLeast18 |
Extended.IsAtLeast18 |
A yes/no, collected once at onboarding rather than re-asked every application — knockout. |
| "Do you currently hold a security clearance?" | SecurityClearanceHeld |
Derived from Extended.SecurityClearanceLevel / Eligibility.SecurityClearance |
Whether any clearance is held — knockout for cleared roles. |
| Clearance level | SecurityClearanceLevel |
Extended.SecurityClearanceLevel |
Specific level (Public Trust, Secret, Top Secret, TS/SCI, polygraph type) and, ideally, expiration date (Extended.SecurityClearanceExpiresOn) since lapsed clearances often still count differently than active ones. |
| "Are you bound by a non-compete or non-solicit agreement?" | BoundByNonCompete |
Extended.BoundByNonCompete + NonCompeteDetails |
Yes/no plus, if yes, which employer and expiration — knockout for close competitors. |
| "Have you previously been employed by [Company]?" | PreviouslyEmployedByCompany |
Extended.PreviouslyEmployedByCompany |
Yes/no — affects rehire-eligibility routing, not usually a hard knockout. |
4. EEO / demographics (always optional)¶
| Question | QuestionType |
Profile field | Needed from user |
|---|---|---|---|
| Gender identity | Gender |
Demographics.Gender |
Optional self-identification. |
| Race / ethnicity | RaceEthnicity |
Demographics.RaceEthnicity |
Optional self-identification. |
| Veteran status | VeteranStatus |
Demographics.VeteranStatus |
Optional — US federal contractors are required to ask (VEVRAA) but the candidate is never required to answer. |
| Disability status | DisabilityStatus |
Demographics.DisabilityStatus |
Optional — same OFCCP self-ID framing as veteran status. |
These are never treated as gaps. AnswerResolver.VoluntaryDemographic reports
IsGap = false even when the field is unset, because "prefer not to answer" is the complete,
correct answer for an EEO question WorkWingman never fabricates a response to. The value is
applied exactly as the user set it, or left at the form's neutral default.
5. Education¶
| Question | QuestionType |
Profile field | Needed from user |
|---|---|---|---|
| School / university | School |
Education[latest].School |
At minimum, the highest/most recent credential. |
| Degree | Degree |
Education[latest].Degree |
Degree type (BS, MS, MBA, etc.) — some ATSes want this as free text, others as a constrained dropdown WorkWingman must fuzzy-match. |
| Field of study | FieldOfStudy |
Education[latest].FieldOfStudy |
Major/concentration. |
| Graduation year | GraduationYear |
Education[latest].GraduationYear |
Year, or expected year if in progress. |
AnswerResolver picks the entry with the highest GraduationYear when multiple degrees exist;
a future iteration could ask per-question which degree a form wants (e.g. "highest" vs. "most
relevant to role").
6. Work experience¶
| Question | QuestionType |
Profile field | Needed from user |
|---|---|---|---|
| Employer name | EmployerName |
WorkHistory[latest].Company |
Every employer for at least the ATS-required lookback window (commonly 7-10 years). |
| Job title | JobTitle |
WorkHistory[latest].Title |
Title as held, not an aspirational title. |
| Start / end date | EmploymentStartDate / EmploymentEndDate |
WorkHistory[latest].StartDate/EndDate |
Month + year is usually enough. |
| Reason for leaving | ReasonForLeaving |
(gap — see profile-data-gaps.md) | Short, consistent phrasing per employer so it doesn't contradict itself across applications. |
AnswerResolver currently takes WorkHistory.FirstOrDefault() as "latest," matching how
IntakeProfile.WorkHistory is populated (most-recent-first) elsewhere in the app.
7. Skills / certifications¶
| Question | QuestionType |
Profile field | Needed from user |
|---|---|---|---|
| Skills list | Skills |
TopSkills |
A curated top-skills list (joined with commas for free-text boxes; automation can also target multi-select skill pickers keyword-by-keyword). |
| Certification name | CertificationName |
Extended.Certifications[latest].Name |
Certification title (AWS Certified Solutions Architect, PMP, etc.). |
| License / credential number | LicenseNumber |
Extended.Certifications[latest].CredentialId |
The credential ID some ATSes verify against the issuer. |
8. Screening / knockout questions¶
| Question | QuestionType |
Profile field | Needed from user |
|---|---|---|---|
| "How many years of experience do you have with X?" | YearsOfExperienceInSkill |
(gap) | Per-skill years — not a single number, needs either a structured skills-with-years list or a per-question judgement call (mirrors WorkdayAutomationEngine's JudgementCall flow). |
| Custom yes/no screening question | ScreeningYesNo |
(gap, flagged IsKnockout) |
No generic mapping exists — every job invents its own ("Can you lift 50 lbs?", "Do you have a car?"). Always surfaced as a judgement call. |
| Custom free-text screening question | ScreeningFreeText |
(gap) | Same — routed to Claude drafting or a judgement call, never guessed. |
9. Salary, start date, relocation, work model¶
| Question | QuestionType |
Profile field | Needed from user |
|---|---|---|---|
| Salary expectation | SalaryExpectation |
Eligibility.SalaryExpectation |
A number or range the user is comfortable citing — see gaps doc for the "many states forbid asking salary history" nuance. |
| Salary history | SalaryHistory |
Extended.SalaryHistory |
Prior compensation, only where legal to ask. |
| Earliest start date | EarliestStartDate |
Eligibility.EarliestStartDate |
A date or "immediately" / "2 weeks notice." |
| Notice period | NoticePeriod |
Extended.NoticePeriod |
How much notice the current employer is owed. |
| Willing to relocate | WillingToRelocate |
Extended.WillingToRelocate (falls back to Eligibility.RelocationPreference free text) |
A clean yes/no/case-by-case, distinct from the free-text relocation preference already on the profile. |
| Work model preference | WorkModelPreference |
Eligibility.WorkModelPreference |
Remote/hybrid/on-site preference. |
| Employment type preference | EmploymentTypePreference |
Extended.EmploymentTypePreference |
W-2 vs. contract/1099 willingness. |
10. Custom per-job questions¶
| Question | QuestionType |
Profile field | Needed from user |
|---|---|---|---|
| "How did you hear about us?" | HowDidYouHearAboutUs |
Extended.HowDidYouHearAboutUs |
A default source (e.g. "LinkedIn") reused unless the specific job warrants something else (e.g. a referral). |
| "Why do you want to work here?" | WhyThisCompany |
(gap — drafted, not a static field) | Per-company motivation is generated by the document/outreach drafters from the story profile, not read off a static field. |
| Any other custom free text | CustomFreeText |
(gap) | Routed to a judgement call or Claude drafting. |
11. References¶
| Question | QuestionType |
Profile field | Needed from user |
|---|---|---|---|
| Reference name/relationship/company/phone/email, slot N | ReferenceName/ReferenceRelationship/ReferenceCompany/ReferencePhone/ReferenceEmail |
Extended.References[N-1] via ApplicationQuestion.RepeatIndex + ReferenceField |
2-3 pre-cleared references (name, how they know the user, employer, phone, email). |
See Edge cases → reference slots below.
12. Consents / acknowledgements¶
| Question | QuestionType |
Profile field | Needed from user |
|---|---|---|---|
| Background-check consent | BackgroundCheckConsent |
(never auto-filled) | Explicit, in-the-moment affirmation. |
| Drug-test consent | DrugTestConsent |
(never auto-filled) | Same. |
| At-will employment acknowledgement | AtWillAcknowledgement |
(never auto-filled) | Same. |
| E-Verify acknowledgement | EVerifyAcknowledgement |
(never auto-filled) | Same. |
| EEO notice acknowledgement | EqualOpportunityAcknowledgement |
(never auto-filled) | Same. |
| "I certify the above is true and complete" | InformationAccuracyCertification |
(never auto-filled) | Same. |
AnswerResolver deliberately returns a gap + RequiresUserConfirmation = true for every
consent/acknowledgement question rather than auto-affirming a legal statement on the user's
behalf — this mirrors AutomationSettings.AlwaysRequireReviewBeforeSubmit, which is locked on.
Edge cases¶
Yes/No → conditional "N/A" text box¶
Many forms show a hidden text box that reveals after a yes/no question — e.g. "Have you ever
been convicted of a felony?" → "If yes, please explain." When the underlying yes/no answer
makes the follow-up not applicable, the box still has to be filled with the literal string
"N/A"; leaving it blank commonly fails client-side validation because the field is marked
required regardless of the branch taken.
Modeled by ApplicationQuestion.Control = ControlKind.ConditionalTextAfterYesNo (or the
IsConditionalOnYesNo flag), ConditionalTriggerValue (which yes/no answer makes the box
relevant), and PrecedingYesNoAnswer (what the user/automation actually answered).
AnswerResolver.ResolveConditionalText:
- fills the literal string
"N/A"(viaAnswerResolver.NotApplicable) whenPrecedingYesNoAnswer != ConditionalTriggerValue; - looks for real explanatory text (
Extended.ConvictionDetailstoday; extend per use case) when the box is applicable; - never guesses when
PrecedingYesNoAnswerisnull— it returns a gap instead of risking either a wrongly-blank required field or a wrongly-dismissive "N/A" over real content that should have been disclosed.
Reference slots¶
Reference questions repeat in slots (Reference 1, Reference 2, …), each with several sub-fields.
ApplicationQuestion.RepeatIndex (1-based) + ReferenceField locate the right entry in
IntakeProfile.Extended.References. AnswerResolver.ResolveReferenceField:
- fills whichever sub-field (name/relationship/company/phone/email) the slot asks for when a reference exists at that index;
- handles gracefully — not an exception — when the user has no references on file yet, or
when the form asks for more reference slots than the user has supplied. Both return a gap
(
IsGap = true, empty value, explanatoryReasoning) rather than fabricating a person.
Conditional reveals¶
Beyond the yes/no → N/A case, answering one question can unlock an entirely new required field
(e.g. selecting "Other" in a dropdown reveals a "please specify" box, or answering "Yes" to
"Do you have a clearance?" reveals the clearance-level dropdown). These are represented the same
way as the N/A case — a follow-up ApplicationQuestion whose relevance depends on a preceding
answer — but the content required differs (real text, not "N/A") depending on which branch was
taken. The taxonomy handles the specific "yes/no → N/A" case generically in AnswerResolver
because it's ubiquitous across ATSes; job-specific reveals (a custom dropdown revealing a custom
box) fall through to ScreeningFreeText/CustomFreeText and a judgement call, matching how
WorkdayAutomationEngine.TryFillFieldAsync already pauses on low-confidence fields.
Knockout questions¶
A knockout question is one where a "wrong" answer causes the ATS to auto-reject the
application before any human reviews it — most commonly work authorization, sponsorship
requirements, minimum age, and clearance/background prerequisites. ApplicationQuestion
.IsKnockout (also implicitly true for AuthorizedToWorkInCountry, RequiresSponsorshipNowOrFuture,
IsAtLeast18, SecurityClearanceHeld, BoundByNonCompete, DisclosableConviction, and every
consent/acknowledgement type) forces ResolvedAnswer.RequiresUserConfirmation = true regardless
of confidence — AnswerResolver will confidently fill "Yes"/"No" from the profile, but the
caller (automation engine, or the manual-apply UI) must always surface it for an explicit nod
before the application submits. This is the same pattern WorkdayAutomationEngine uses for
low-confidence fields (JudgementCall), applied unconditionally to anything that can silently
end the application.
Related docs¶
- Plain-language version: ../plain/application-question-taxonomy.md
- Profile gaps + proposed
IntakeProfileadditions: profile-data-gaps.md - Outreach drafting (separate concern, same draft-only philosophy): outreach-drafting.md
- architecture.md · api-reference.md
- Doc index: ../README.md