santifer/career-ops · warning

⚠️ CV fact check warning

Error message

⚠️  CV fact check warning: ${basename(inputPath)}

What it means

generate-pdf.mjs runs a fact-check pass over the generated CV (metrics and facts against config/cv-facts.json, plus forbidden/advisory phrase lists). When the fact-check verdict is 'warn', it prints this warning naming the input file, followed by one line per advisory phrase found. It is a non-fatal console.warn: the PDF still renders.

Solutions

  1. Read the ' - advisory phrase:' lines printed immediately after and rewrite those phrases in cv.md or the generated CV
  2. Re-run the PDF generation and confirm the verdict changes to '✅ Fact check passed'
  3. If a flagged phrase is actually fine, add it to an allowlist in config/cv-facts.json
  4. If config/cv-facts.json is missing, create it so forbidden/advisory checks actually run (the warning above this one indicates they were skipped)

Example fix

// before
draft: "I was involved in migrating the pipeline"
// after
draft: "Migrated the ingestion pipeline, cutting batch time 40%"
Defensive patterns

Strategy: validation

Validate before calling

// run the fact-check standalone before rendering
const fc = await factCheckCV(cvText, config);
if (fc.verdict === 'warn') fc.warnings.forEach(w => console.log('advisory:', w));

Prevention

When it happens

Trigger: Running the CV/PDF mode when factCheckCV() returns verdict 'warn' — i.e. the CV text contains phrases on the advisory list (hedged or risky wording) but nothing on the forbidden list.

Common situations: CV drafts containing advisory phrasing like 'helped with', 'involved in', or unquantified claims the phrase lists flag; authors reviewing generated PDFs before sending them out.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16). Data as JSON: /api/errors/fb7c689a835a051b. Report an issue: GitHub.

Appendix: source

Thrown at generate-pdf.mjs:1363

  // normalized HTML, which is the document that actually prints.
  if (!skipFactCheck && cvMarkdown) {
    // Imported lazily, INSIDE the guard. A static import is resolved at module
    // load whether or not this branch runs, and the page-budget/batch suites copy
    // generate-pdf.mjs alone into a temp workspace — a static import of a sibling
    // that isn't copied made every one of those suites die with
    // ERR_MODULE_NOT_FOUND before reaching the behaviour under test. Those
    // fixtures also ship no cv.md, so this branch is never entered there. If the
    // module is genuinely missing in a real workspace this throws and the render
    // fails, which is the correct direction to fail for a fact gate.
    const { assertFacts } = await import('./verify-cv-facts.mjs');
    const factCheck = assertFacts(html, { label: basename(inputPath) });
    // Ahead of the verdict, because it qualifies it: with no config the phrase
    // lists are empty, so a "passed" below covers metrics and facts only.
    if (factCheck.configMissing) {
      console.warn('⚠️  No config/cv-facts.json — forbidden/advisory phrase checks did not run.');
    }
    if (factCheck.verdict === 'warn') {
      console.warn(`⚠️  CV fact check warning: ${basename(inputPath)}`);
      for (const phrase of factCheck.warnings) console.warn(`  - advisory phrase: ${phrase}`);
    } else {
      console.log('✅ Fact check passed');
    }
  }

  return renderHtmlToPdf(html, outputPath, {
    format,
    baseDir: dirname(inputPath),
    reportNum,
    inputPath,
    maxPages,
    strictPages,
    styleTokens: readStyleTokens(resolve(workspaceRoot, 'config', 'profile.yml')),
  });
}

/**

View on GitHub (pinned to aac998c7ed)