Profile data gaps (technical)¶
What IntakeProfile needs beyond its original onboarding shape to answer every question in the
taxonomy. All additions live on the new, optional
IntakeProfile.Extended (ExtendedProfile) object in
IntakeProfile.cs — nothing existing was
renamed, removed, or repurposed, so profiles saved before this change deserialize unchanged
(System.Text.Json defaults an absent nested object to its parameterless constructor).
Plain-language version: What WorkWingman Still Needs to Ask You. For the user-facing framing of why these questions get asked at all, see ../plain/application-question-taxonomy.md.
Why a nested Extended object instead of flattening onto IntakeProfile¶
- Backward compatibility is automatic. Adding new top-level properties to
IntakeProfilewould also be backward-compatible withSystem.Text.Json, but grouping the additions keeps the diff against the original onboarding shape self-contained and makes it obvious, on review, which fields are "core onboarding" (always asked) vs. "gap-fill" (asked opportunistically, filled in over time as forms demand them). LocalJsonStore(seeLocalJsonStore.cs) round-trips whatever shapeIntakeProfilehas viaSystem.Text.Json— no migration script is needed either way, but the grouping makes it easy to eventually version/migrateExtendedindependently if it grows large enough to warrant its own store document.
Gaps and the proposed fields¶
| Gap | New field(s) on ExtendedProfile |
Why the original profile didn't have it |
|---|---|---|
| References | References: List<ReferenceContact> (name, relationship, company, phone, email) |
Onboarding focused on the applicant's own history; references are a distinct, sensitive category (another person's contact info) worth its own explicit consent step. |
| Salary history | SalaryHistory: string |
Increasingly illegal to ask (many US states/cities ban salary-history questions) — kept separate from Eligibility.SalaryExpectation (which is your ask, always fair game) so the resolver can treat them differently and so the app can eventually warn "this job's state doesn't allow this question." |
| Willingness to relocate | WillingToRelocate: bool? |
Eligibility.RelocationPreference already exists but is free text (e.g. "Open to Austin or Denver") — good for cover letters, bad for a strict form yes/no. The new field is a clean tri-state (yes/no/not set) AnswerResolver can map directly, falling back to the free text when the structured value isn't set. |
| Certifications / licenses | Certifications: List<CertificationEntry> (name, issuing body, issued/expires dates, credential ID) |
Original profile only had TopSkills (flat strings) — certifications need structure (an expiring AWS cert is different from a skill keyword) and some forms verify the credential ID directly. |
| Security clearance level | SecurityClearanceLevel: string, SecurityClearanceExpiresOn: DateOnly? |
Eligibility.SecurityClearance already exists as a free-text summary; the structured level + expiration lets AnswerResolver answer "do you hold an active clearance" precisely (a lapsed Secret clearance often answers differently than an active one) rather than string-matching free text. |
| Availability / notice period | NoticePeriod: string |
Distinct from Eligibility.EarliestStartDate (a date) — notice period is a duration owed to the current employer ("2 weeks", "1 month"), which some forms ask for directly instead of/alongside a start date. |
| "How did you hear about us?" | HowDidYouHearAboutUs: string |
Nearly universal custom question with no prior home; defaults to one source (e.g. "LinkedIn") reusable across applications unless a specific job warrants a referral callout. |
| Rehire eligibility | PreviouslyEmployedByCompany: bool? |
Common on internal-transfer-aware ATSes (Workday especially) — "have you worked here before" routes to a different onboarding flow than a fresh applicant. |
| Non-compete / non-solicit | BoundByNonCompete: bool?, NonCompeteDetails: string |
Increasingly asked as companies get more cautious about hiring from direct competitors; a knockout-adjacent question the original profile had no home for. |
| Age attestation | IsAtLeast18: bool (defaults true) |
Asked on essentially every application; better to collect once at onboarding than re-derive it, and better to make it explicit than to assume. |
| Disclosable conviction | HasDisclosableConviction: bool?, ConvictionDetails: string |
The canonical "yes/no → N/A conditional text box" example (see taxonomy → edge cases); needs both the trigger answer and, if applicable, real explanatory text, worded consistently across applications. |
| Portfolio links | PortfolioLinks: List<string> |
GitHub/personal site/publications beyond the resume file itself — ConnectionsService already tracks a GitHub connection, but the profile had no field to place the actual link(s) on an application. |
| Desired title | DesiredTitle: string |
Some forms ask "what role are you interested in" as a free-standing question distinct from the job being applied to (e.g. general-application forms, talent-community signups). |
| Employment type preference | EmploymentTypePreference: string |
W-2 vs. 1099/contract willingness — some ATSes (especially staffing-agency-fronted ones) ask this directly. |
What this does not attempt to solve yet¶
- Per-skill years of experience (
YearsOfExperienceInSkillin the taxonomy) needs a structured "skill → years" map, not just the flatTopSkillslist. Deferred because the UX for capturing it (a full skills matrix at onboarding) is a bigger product decision than this pass scopes; today it resolves as a gap routed to a judgement call, same asWorkdayAutomationEngine's existing low-confidence-field flow. - Reason for leaving, per employer — needs per-
WorkHistoryEntrystructure (aReasonfield onWorkHistoryEntryitself) rather than a single profile-wide value, since the answer differs per job. Left out of this pass to avoid scope creep on the work-history shape; noted here so it's not lost. - Per-state salary-history legality —
SalaryHistoryis collected, but there's no logic yet that suppresses the question where asking is illegal. That's an ATS-detection-time decision (which state/city the job is in), not a profile-shape decision, and belongs closer toAtsDetector/WorkdayAutomationEngineonce that jurisdiction data source is chosen.
Related docs¶
- application-question-taxonomy.md — the full question catalog these fields answer
IntakeProfile.cs— the actual shapeAnswerResolver.cs— where each field gets read- Doc index: ../README.md