Skip to content

Self-assessment (technical)

An optional "know yourself" suite — personality, work style, communication style, learning style — stored locally and available to feed interview prep and self-marketing. Nothing here is required to use WorkWingman: every section is null/empty until the user chooses to take it.

Plain-language version: ../plain/self-assessment.md

The one rule that matters most: local vs. Google Forms

Everything in this feature is local-only by default. AssessmentService reads and writes exactly one LocalJsonStore key ("assessment") under %USERPROFILE%\Wingman\data\assessment.json. There is no network call anywhere in AssessmentService, BigFiveScorer, or the frontend save paths — see AssessmentServiceTests.Profile_NeverLeavesTheLocalStoreDirectory for the automated guard.

The one exception is GoogleFormsAssessmentExporter (GoogleFormsAssessmentExporter.cs), reachable only via POST /api/assessment/export/google-forms (AssessmentFormsController, deliberately a separate controller/route from the local read/write endpoints so it's obvious from routing alone which path leaves the machine). It mirrors the current profile into a new Google Form in the user's own Drive, via the same OAuth flow already used for the onboarding-interview form (GoogleFormsClient). This is:

  • Explicitly opt-in — never invoked from an automatic save; the frontend only calls it from the "Export (leaves your machine)" button, labeled as such in the UI.
  • The only place data leaves the machine. Google Forms/Sheets is a sync target the user chose, never a hosting or scoring backend — the local JSON file stays the source of truth regardless of whether the user ever exports.

Why this distinction matters: Google Forms responses are stored in Google's cloud, under the user's account, subject to Google's retention/access model — not "local" in any sense. A "self-assessment" feature that quietly defaulted to Google Forms would be handing personality data to a third party without the user asking for that. Making the export a clearly-labeled, separate, explicit action is the honest way to offer the convenience (a shareable/exportable copy in Drive) without violating the local-first premise the rest of the app makes everywhere else.

Big Five personality — IPIP, public domain, scored locally

We use the 50-item IPIP Big-Five Factor Markers (Goldberg, L. R. (1992). The development of markers for the Big-Five factor structure. Psychological Assessment, 4, 26-42), sourced from the International Personality Item Pool (https://ipip.ori.org/new_ipip-50-item-scale.htm). The IPIP project's own public-domain statement:

"because the IPIP is in the public domain, users have complete freedom to use the IPIP in any way that suits their purposes."

No license, fee, or attribution is legally required to use these items — the Goldberg citation above is included as good academic practice, not because it's mandated.

Why IPIP instead of the commercial NEO-PI-R or a homegrown item set: the IPIP-50 was purpose-built (Goldberg, 1992) to measure the same five constructs as the licensed NEO-PI-R, is extensively validated in the psychometrics literature, and — critically — is the only Big Five option that lets WorkWingman ship a real, published, validated instrument entirely locally, with zero licensing risk.

Items and keying

All 50 items live in IpipItem.cs (IpipBigFiveItemBank.Items), each tagged with its trait (BigFiveTrait) and whether it's reverse-keyed. Users rate each item 1 ("Very Inaccurate") to 5 ("Very Accurate"), per the standard IPIP administration instructions.

One naming note: IPIP's fourth factor is conventionally labeled "Emotional Stability" (higher = more stable). WorkWingman reports the more commonly recognized Neuroticism framing instead (higher = more prone to stress) — the item set is identical, but every item's ReverseKeyed flag for that factor is inverted relative to IPIP's own "Emotional Stability" keying, documented inline in IpipItem.cs.

Scoring — BigFiveScorer

BigFiveScorer.cs is pure and deterministic — no I/O, no randomness:

public static BigFiveResult Score(IReadOnlyDictionary<int, int> answers)
  • Validates every one of the 50 items is present and every rating is 1-5 (ArgumentException otherwise — a partial or corrupt submission never silently produces a misleading score).
  • Per trait: sums the 10 items, reverse-scoring (6 - rating) any item flagged ReverseKeyed. Raw score range is 10-50.
  • Percentile is a linear 0-100 position within the theoretical 10-50 range — not a population percentile. The IPIP project deliberately publishes no canned norm tables (https://ipip.ori.org/newNorms.htm) and recommends norming against your own sample instead. A transparent within-range position is the honest local-only alternative: WorkWingman never claims "you scored higher than X% of people," because it has no such population data and never will (no telemetry, no server).
  • Each trait gets a short plain-language interpretation from a Low/Mid/High band (raw ≤22 / 23-38 / ≥39), five distinct texts per trait (25 total).

Storage and the IAssessmentInsights seam

AssessmentService implements two interfaces:

  • IAssessmentService — get/save the whole profile, plus ScoreAndSaveBigFiveAsync which scores and persists in one call.
  • IAssessmentInsights — a read-only, plain-value-object seam (TraitSnapshot, StyleSnapshot) that the planned interview-coaching feature (feature-interview-coaching branch) consumes instead of depending on this feature's storage shape or IPIP internals directly. Every getter returns null when the user hasn't taken that section — callers must treat absence as "no signal available," never as a default/neutral trait value.

MBTI: why WorkWingman doesn't administer it

The actual Myers-Briggs Type Indicator is a proprietary, paid instrument owned by The Myers-Briggs Company — its items, scoring algorithm, and even the underlying construct definitions are commercial IP. WorkWingman does not reproduce, adapt, or approximate it.

Instead, SelfReportedMbti is a plain self-entry field (TypeCode, Source, EnteredAt) — the user takes a free instrument elsewhere and types in whatever result they got. AssessmentResourceMap (AssessmentResource.cs) curates three verified-live options (checked at write time, 2026-07):

Resource What it is Free?
16Personalities A NERIS-model 4-letter-type test, not licensed MBTI, but the most widely used free equivalent Yes (core result)
Open Extended Jungian Type Scales Built from public research data as an explicit open-source MBTI alternative Yes
Truity TypeFinder Myers-Briggs-style type test; paid upsell for the extended report only Yes (basic result)

WorkWingman never fetches, scrapes, or auto-fills from these sites — they're plain outbound links; the user takes the test on their own and copies the result back in.

Work / communication / learning style

These three are WorkWingman's own short preference questionnaires (frontend/src/app/features/self-assessment/style-items.ts), not reproductions of any licensed instrument:

  • Work style takes inspiration from DISC's four-dimension shape (Dominance / Influence / Steadiness / Conscientiousness), but DISC assessments themselves are commercial products with restricted item banks — so the 8 items here are self-authored, generic workplace-preference statements, scored by simple per-dimension averaging (scoreDimensions in style-items.ts).
  • Communication style (Direct / Diplomatic / Analytical / Expressive) is likewise a small, self-authored preference set, same scoring approach.
  • Learning style takes inspiration from the VARK idea (Visual / Auditory / Reading-Writing / Kinesthetic sensory-modality preference), but VARK itself is copyrighted — its questionnaire "may not be placed on other websites, apps... the questionnaire must not be published on the Internet, in any form" (https://vark-learn.com/copyright-information/). We verified this directly against the VARK copyright page rather than assuming; the 8 items here are WorkWingman's own, inspired by the general sensory-modality concept (which isn't ownable) without touching VARK's actual items or wording.

All three are scored client-side by scoreDimensions/primaryDimension (frontend/src/app/features/self-assessment/style-items.ts) — a 1-5 rating per item, averaged per dimension, scaled to 0-100 — then saved to the backend as a WorkStyleResult / CommunicationStyleResult / LearningStyleResult via the same local-only save path as everything else in this feature.

API surface

AssessmentController (src/WorkWingman.Api/Controllers/AssessmentController.cs):

Route Verb Purpose
/api/assessment GET Full AssessmentProfile
/api/assessment/ipip-items GET The 50 IPIP items (for rendering the questionnaire)
/api/assessment/big-five POST Scores + saves; body is { itemNumber: rating } for all 50 items
/api/assessment/mbti PUT Save SelfReportedMbti
/api/assessment/work-style PUT Save WorkStyleResult
/api/assessment/communication-style PUT Save CommunicationStyleResult
/api/assessment/learning-style PUT Save LearningStyleResult
/api/assessment/resources GET The curated external-test list
/api/assessment/export/google-forms POST Leaves the machine — separate controller (AssessmentFormsController)

Testing

  • BigFiveScorerTests — pure scorer: neutral/all-min/all-max extremes, percentile boundaries, reverse-keying correctness, band-boundary interpretations, missing/out-of-range guards, item bank shape (50 items, 10 per trait, numbers 1-50 unique).
  • AssessmentServiceTests — persistence round-trips per section, non-clobbering across sections, the IAssessmentInsights read seam, and the local-only-directory assertion.
  • AssessmentResourceMapTests — resource shape (non-empty fields, well-formed https URLs, unique names/URLs), guards that no curated link points back at WorkWingman itself.
  • GoogleFormsAssessmentExporterTests — the one non-local path, tested via Flurl's HttpTest (no real network), confirming it only fires when explicitly invoked.
  • Frontend: self-assessment.spec.ts (panel navigation, Big Five completion/scoring, MBTI blank-guard, all three style submits, the opt-in export flow) and style-items.spec.ts (dimension scoring/averaging, tie-breaking).
  • All manually verified end-to-end in a running instance: took the Big Five (all-3 answers scored 50/100 on every trait, matching Score_AllNeutralAnswers_EveryTraitScoresMidpoint), entered a self-reported MBTI type, confirmed the saved JSON on disk.