job-research/docs/superpowers/specs/2026-05-26-candidate-profile-ingestion-design.md

6.3 KiB

Candidate Profile Ingestion Design

This spec covers the simplified first executable slice of the job discovery system: take a PDF CV and a light-template markdown profile, then produce one usable candidate-profile.yaml that the user can inspect and edit directly. It stops before scraping, ranking, separate Search Preferences, or OpenCode-driven session overrides.

Scope

This slice must let the user:

  • provide a PDF CV,
  • provide a light structured markdown profile,
  • run one main CLI command,
  • produce one canonical normalized YAML profile,
  • see warnings when CV facts and markdown intent disagree or when extraction is uncertain,
  • edit the resulting YAML directly if they want to refine or correct it.

Out of scope:

  • job scraping,
  • ranking,
  • separate saved Search Preferences,
  • multi-step override workflows,
  • hard-stop review gates,
  • browser or web UI flows.

Architecture

The design is a single-step profile normalizer.

Inputs:

  • PDF CV for raw career history,
  • light-template markdown profile for curated interpretation, job intent, and constraints.

Output:

  • one canonical candidate-profile.yaml.

The trust rule is simpler than the earlier layered design: the system always writes the output file, but it never hides uncertainty. When the CV and markdown profile disagree on facts, or when extraction confidence is weak, the output YAML includes explicit warnings. The user can then edit the canonical YAML directly.

Components

CV Extractor

Responsibility:

  • read the PDF CV,
  • extract text deterministically,
  • derive structured career-history candidates.

Expected fields include:

  • identity basics,
  • experience entries,
  • education entries,
  • skill mentions,
  • language mentions.

Behavior:

  • prefer explicit extraction over inference,
  • leave uncertainty visible instead of guessing,
  • use LLM assistance only when deterministic extraction is too weak to structure useful output.

Markdown Profile Parser

Responsibility:

  • read a light required markdown template,
  • parse known sections into structured authored intent.

Required sections:

  • Summary
  • Target Roles
  • Strengths
  • Skills To Emphasize
  • Constraints
  • Notes

This file carries both durable interpretation and current job intent for the first slice.

Profile Merger

Responsibility:

  • combine CV-derived facts and markdown-derived intent,
  • normalize them into one canonical profile document,
  • record warnings for factual conflicts or ambiguity.

Authority rules:

  • CV is the default source for raw career history,
  • markdown profile is the source for interpretation, emphasis, and job intent,
  • factual disagreement becomes a warning, not a blocked workflow,
  • the final YAML is user-editable and becomes the local source of truth after generation.

Data Flow

  1. The user provides a PDF CV.
  2. The user provides a light-template markdown profile.
  3. The system extracts CV-derived structured candidates.
  4. The system parses markdown-derived authored intent.
  5. The system merges both into one normalized profile document.
  6. The system writes candidate-profile.yaml.
  7. The system includes warnings inside the YAML when facts conflict or extraction is uncertain.
  8. The user edits candidate-profile.yaml directly if they want to refine the final result.

File Layout

data/
  candidate-profile.yaml

Optional debug artifacts may be added later, but the first slice should optimize for a single obvious output file.

Output Shape

The canonical YAML should include:

  • identity and summary,
  • target roles and job intent,
  • skills and technologies,
  • experience entries,
  • education entries,
  • constraints,
  • notes,
  • warnings.

The warnings section should be human-readable and should point out:

  • factual conflicts,
  • missing important fields,
  • low-confidence extraction areas.

Validation and Error Handling

Hard Failures

These should fail immediately and avoid producing misleading output:

  • unreadable or missing PDF input,
  • malformed markdown template missing required headings,
  • invalid command arguments.

Non-Blocking Warnings

These should still produce candidate-profile.yaml:

  • factual conflicts between CV and markdown profile,
  • incomplete optional fields,
  • low-confidence extraction,
  • unclear dates or inferred experience totals.

The system must prefer explicit warnings over silent incorrect certainty.

Command Surface

The first slice should expose one main command:

  • build-profile --cv <cv.pdf> --profile <profile.md> --out data/candidate-profile.yaml

Optional helper commands may be added later, but they are not required for this slice.

Expected behavior:

  • read both inputs,
  • produce one canonical YAML file,
  • print a success message,
  • print whether warnings were included.

LLM Usage Boundaries

This slice is deterministic-first.

Allowed LLM use:

  • fallback structuring help when deterministic extraction alone cannot produce a usable normalized profile.

Disallowed LLM use:

  • replacing deterministic extraction as the default path,
  • silently deciding factual conflicts,
  • acting as the only source of truth for the final persisted profile.

Testing Strategy

The first slice should be tested around usefulness and transparency.

Core test cases:

  • valid CV plus valid markdown produces candidate-profile.yaml,
  • missing required markdown sections fails clearly,
  • factual conflict still writes output and records warnings,
  • final YAML contains both extracted facts and markdown intent,
  • output serialization is stable and readable,
  • command-line usage is repeatable.

Acceptance Criteria

This slice is done when:

  • a real PDF CV and light-template markdown profile can produce one local candidate-profile.yaml,
  • the YAML is readable and useful enough for the user to trust and edit directly,
  • factual conflicts and uncertainty appear as warnings rather than hidden behavior,
  • the workflow is one obvious command rather than a multi-step state machine,
  • the result is good enough to become the input to later scraping and ranking work.

Non-Goals for This Slice

This design intentionally does not solve:

  • job board integration,
  • listing normalization,
  • score computation,
  • Stretch Opportunity classification,
  • dismissed listing behavior,
  • separate persisted Search Preferences,
  • session-level conversational overrides.

Those belong to later slices after the system can reliably understand the candidate.