santifer/career-ops · warning

Application Answers section has ${skipped.length} unreadable

Error message

Application Answers section has ${skipped.length} unreadable ${skipped.length === 1 ? 'entry' : 'entries'}: ${skipped.join(' | ')}

What it means

Emitted by Check 13 of verify-pipeline.mjs for active-interviews.md rows classified resolution 'unmatched': checkTrackerSync could not pair the row with any applications.md row. Matching relies on a '#N in tracker' Notes reference or fuzzy Company+Role; m.note states why both failed for this row, so the sync check cannot reason about its status at all.

Source

Thrown at application-answers.mjs:311

    afterHeading,
    nextHeading ? afterHeading + nextHeading.index : report.length,
  );

  const dateHit = /^\*\*Date:\*\*\s*(.*)$/m.exec(body);
  const stateHit = /^\*\*State:\*\*\s*(.*)$/m.exec(body);
  const groups = sliceGroups(body);

  const snapshot = {
    date: dateHit ? dateHit[1].trim() : '',
    state: stateHit ? stateHit[1].trim().toLowerCase() : '',
    freeText: parseQaEntries(groups.freeText, 'question', 'answer', onSkip),
    selections: parseCompactEntries(groups.selections, 'question', 'selection', onSkip),
    fieldValues: parseCompactEntries(groups.fieldValues, 'question', 'answer', onSkip),
    files: parseFileEntries(groups.files, onSkip),
  };

  if (strict && skipped.length) {
    throw new Error(
      `Application Answers section has ${skipped.length} unreadable ` +
      `${skipped.length === 1 ? 'entry' : 'entries'}: ${skipped.join(' | ')}`,
    );
  }
  return snapshot;
}

export function upsertApplicationAnswersSection(reportText, snapshot = {}) {
  const report = String(reportText ?? '').replace(/\r\n/g, '\n');
  const section = formatApplicationAnswersSection(snapshot).trimEnd();
  const heading = /^## Application Answers\s*$/m.exec(report);

  if (!heading) {
    return `${report.trimEnd()}\n\n${section}\n`;
  }

  const start = heading.index;
  const afterHeading = start + heading[0].length;

View on GitHub (pinned to 60398d6549)

Solutions

  1. Add '#17 in tracker' (the tracker row's number) to the active-interviews row's Notes so matching becomes exact
  2. Or align the Company/Role spelling in active-interviews.md with the applications.md row
  3. If no tracker row exists at all, add one via a batch/tracker-additions TSV and `node merge-tracker.mjs`, then reference it
  4. Re-run `node verify-pipeline.mjs`

Example fix

// before (data/active-interviews.md row):
| Acme GmbH | Backend Engineer | R2 scheduled | ... |

// after:
| Acme GmbH | Backend Engineer | R2 scheduled | #17 in tracker | ... |
Defensive patterns

Strategy: validation

Validate before calling

// Run when writing an active-interviews row: guarantee it can be matched back
// to a tracker row by the exact '#N in tracker' reference.
export function trackerRef(num) { return `#${num} in tracker`; }
export function rowIsMatchable(notes, trackerNums) {
  const m = String(notes ?? '').match(/#(\d+) in tracker/);
  return !!m && trackerNums.has(Number(m[1]));
}

Type guard

const hasTrackerReference = (notes) => /#\d+ in tracker/.test(String(notes ?? ''));

Prevention

When it happens

Trigger: An active-interviews row typed by hand with no '#N in tracker' reference and company/role spelled differently from the tracker (legal name vs brand name, abbreviations, localized spellings); a row for a company that was never added to applications.md.

Common situations: Interview prep written up before the tracker row was merged; copy-paste from an invite email whose company naming differs from the tracker; agencies renaming the employer between application and interview stages.

Related errors


AI-assisted analysis of santifer/career-ops@60398d6549 (2026-08-20). Data as JSON: /api/errors/040c530e9182432e. Report an issue: GitHub.