Architecture
Input Normalization
How Teamcast resolves semantic drift across job inputs, resumes, and transcripts to produce fair, evidence-backed evaluations.
Teamcast's product promise is trustworthy, evidence-backed evaluation. That requires the system to reason on the same vocabulary across every surface — job descriptions, candidate resumes, recruiter edits, and interview transcripts.
Without normalization, the same capability appears in many forms and the system implicitly rewards wording overlap rather than actual skill. A candidate who writes ReactJS and a job that requires React describe the same thing — but an unnormalized system treats them as different.
The Core Problem
Teamcast must distinguish between four different types of evidence for any given skill:
| Evidence Type | What It Means | Where It Comes From |
|---|---|---|
| What the job asks for | Required capabilities from the hiring intent | Job description, skills array |
| What the candidate claims | Self-declared skills | Resume skills section, summary, qualifications |
| What the candidate has evidenced | Skills with textual proof of use | Project bullets, work experience, portfolio |
| What the candidate demonstrates live | Skills proven in the interview itself | Transcript turns, explanation depth, scenario responses |
Without this distinction, the planner asks generic questions and the assessor scores based on wording overlap instead of capability evidence. With it, the planner probes precisely and the assessor scores defensibly.
Canonical Skills and Roles
Teamcast maintains a shared vocabulary of canonical skills and role families that all inputs are mapped to before reaching the planner or assessor.
Canonical Skills
Each canonical skill has a single authoritative name and a list of known aliases. When any input contains a raw term, it is mapped to its canonical form before being used for planning or evaluation.
{
"canonicalName": "React",
"aliases": ["ReactJS", "react.js", "react js", "reactjs"],
"category": "frontend_framework"
}This means a job that requires React and a candidate who lists ReactJS are correctly treated as a match — no keyword luck required.
Canonical Roles
Job titles drift as much as skill names. Canonical roles map each position title to a role family and role category that drive competency selection. The role taxonomy is maintained by an AI enricher — when an unrecognized title is encountered, the system classifies it using the LLM and stores the result for all future interviews.
| Raw Title | Role Family | Role Category |
|---|---|---|
| SDR, BDR, Sales Development Rep | sdr_bdr | sales_gtm |
| AE, Account Executive, Closing Rep | account_executive | sales_gtm |
| Sales Engineer, Solutions Engineer | sales_engineer | sales_gtm |
| Frontend Dev, UI Engineer | frontend_engineering | engineering |
| ICU Nurse, Critical Care Nurse | critical_care_nursing * | healthcare * |
| Corporate Tax Attorney | corporate_tax_law * | legal * |
Entries marked * represent AI-enriched classifications. There are no hardcoded limits on which domains the system can interview for — any professional role is supported.
Capability Graph
Skills are connected in a capability graph that records which skills are commonly used alongside, prerequisite to, or build upon each other. During normalization, the system traverses this graph to find skills adjacent to those in the job requirements.
Adjacent skills are passed to the planner as context, enabling it to probe technically related areas even when they are not explicitly listed in the job description. The graph is seeded with known technology relationships and self-expands through AI enrichment as new skills are encountered.
Claimed vs Evidenced vs Demonstrated
Not every skill mention carries the same weight. Teamcast explicitly distinguishes three tiers of skill evidence, each stored as a separate artifact on the interview record.
| Tier | Meaning | Example Source |
|---|---|---|
| Claimed | The candidate says they know it | Skills section, self-declared qualifications, summary line |
| Evidenced | The candidate has textual proof of using it | Project bullets, work experience, portfolio text |
| Demonstrated | The candidate proves it live in the interview | Transcript turns, explanation depth, scenario responses |
These three tiers directly change how the planner behaves and how the assessor scores:
| Candidate Status for a Required Skill | Planner Behavior |
|---|---|
| Evidenced match | Ask deeper, higher-signal technical questions |
| Claimed-only match | Ask validation questions to test the claim |
| Missing but adjacent role | Probe transferability |
| Missing and non-adjacent | Deprioritize or flag as a gap |
Interview Record Artifacts
Every interview record persists a set of normalization artifacts from the moment it is created. These are immutable once written and available on any GET /interviews/:id response.
| Field | Type | Description |
|---|---|---|
| rawPayload | JSON | Exact original input as received — never modified |
| canonicalPayload | JSON | Normalized, structured form used by planner and assessor |
| diffReport | JSON | Field-level delta showing what changed during normalization |
| candidateClaimedSkills | string[] | Skills the candidate self-declares (resume skills / qualifications section) |
| candidateEvidencedSkills | string[] | Skills with project / work-experience evidence in the resume text |
| candidateDemonstratedSkills | string[] | Skills proven live in the interview (written by assessor after completion) |
{
"id": "interview-uuid",
"candidateClaimedSkills": ["React", "TypeScript", "Node.js"],
"candidateEvidencedSkills": ["React", "TypeScript"],
"canonicalPayload": {
"position": "Senior Frontend Engineer",
"skills": ["React", "TypeScript", "Node.js"],
"level": "SENIOR"
},
"diffReport": {
"skills[0]": { "before": "ReactJS", "after": "React" },
"skills[1]": { "before": "TS", "after": "TypeScript" }
},
"rawPayload": {
"position": "Sr Frontend Engineer",
"skills": ["ReactJS", "TS", "NodeJS"]
}
}diffReport is useful for recruiter transparency — it shows exactly what the system changed and why, without hiding the normalization behind a black box.How This Affects the Assessor
After the interview, the assessor scores based on canonical skills linked to transcript evidence spans — not raw wording. Each skill in the assessment report maps to specific turns in the transcript where the candidate addressed it.
{
"skill": "React",
"evidence": [
{ "turn": 4, "quote": "I built the component library using React hooks..." },
{ "turn": 11, "quote": "We migrated from class components in that project..." }
],
"score": 3,
"maxScore": 4
}This makes assessment results auditable. Recruiters can answer the question “why did this candidate score 3/4 on React?” by pointing to specific transcript evidence — not a generic summary.
Resume Parsing
Resumes submitted during interview creation are parsed to extract structured text before normalization is applied. This feeds both the claimed and evidenced skill extraction.
| Input Format | Supported |
|---|---|
| Yes | |
| DOCX / Word | Yes |
| Plain text (.txt) | Yes |
Use POST /api/v1/interviews/parse-resume to extract text from a resume file before creating an interview. See the Interviews API reference for the full endpoint details.