santifer/career-ops · warning
⚠️ Skipping : cannot tell score from status in columns 5–6…
Error message
⚠️ Skipping ${filename}: cannot tell score from status in columns 5–6 ("${parts[4]}" | "${parts[5]}") — refusing to merge a possible column swap What it means
In the headerless positional forms, columns 5 and 6 hold score and status — but the two orders in circulation disagree (batch TSVs write status/score, applications.md writes score/status), so resolveScoreStatus identifies each cell by content: a score matches the X.X/5 (or sentinel) pattern, a status never does. When neither cell is recognizably a score (e.g. both look like statuses, or neither does), the pair is undecidable and the row is refused rather than merged with swapped columns.
Solutions
- Switch this row to the headed TSV form (labels row + one data row) — the header disambiguates score/status by name, so a '—'/'—' discarded row merges correctly.
- If staying headerless, write a recognizable score ('4.2/5') or score sentinel 'N/A' in one of columns 5-6 so the pair becomes decidable.
- Verify both cells actually belong in columns 5-6 — an earlier missing cell shifts everything left and can produce this warning.
- Check the status values against templates/states.yml; a typo'd status that matches no pattern contributes to the ambiguity.
Example fix
// before (headerless: '—' in both cells — undecidable) 42 2026-09-16 Acme Backend — — ❌ [042](reports/042.md) // after (headed form resolves by name) score status — Discarded
Defensive patterns
Strategy: validation
Validate before calling
const scoreLike = (v) => /^\d\.\d\/5$/.test(String(v ?? '').replace(/\*\*/g, '').trim()) || ['N/A','—','-'].includes(String(v ?? '').trim());
const isStatusLike = (v) => /^[A-Za-z][A-Za-z ]*$/.test(String(v ?? '').trim());
if (scoreLike(a) === scoreLike(b)) {
throw new Error(`${file}: cannot tell score from status in columns 5-6 — use the headed form`);
} Prevention
- Use the headed TSV form for any row that cannot carry a recognizable score (e.g. Discarded with '—' in both cells) — the header resolves score/status by name with no undecidable case.
- In headerless rows, always write a pattern-recognizable score ('X.X/5' or 'N/A') so the content sniffing succeeds.
- Validate status strings against templates/states.yml before emitting.
- Count cells first — a shifted row can push a status into columns 5-6 and trigger this warning.
When it happens
Trigger: parseTsvContent (merge-tracker.mjs:953-956 for pipe rows): resolveScoreStatus(parts[4], parts[5]) returns null — neither cell matches the score pattern nor a sentinel. Classic case: a discarded, never-scored row carrying '—' in both cells, or two status-looking strings ('Applied' | 'Evaluated').
Common situations: A discarded row used the '—' sentinel for both score and status (the known undecidable case — use the headed form, which has no such case); the writer emitted two status values; a non-standard score format ('four point two', '85%') that matches neither pattern; columns 5-6 were shifted by an earlier dropped cell.
Related errors
- ⚠️ Skipping : the column labelled "score" reads " ", which…
- ⚠️ Skipping : a URL sits under " " while the "url" cell is…
- ⚠️ Skipping : data row has field(s), missing the required…
- ⚠️ Skipping : data rows — one addition per file
- ⚠️ Skipping : header row with no data row
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/1d0adca61a467541.
Report an issue: GitHub.
Appendix: source
Thrown at merge-tracker.mjs:955
let parts;
let addition;
// Detect pipe-delimited (markdown table row)
if (content.startsWith('|')) {
parts = content.split('|').map(s => s.trim());
if (parts[0] === '') parts.shift();
if (parts[parts.length - 1] === '') parts.pop();
if (parts.length < 8) {
console.warn(`⚠️ Skipping malformed pipe-delimited ${filename}: ${parts.length} fields`);
return null;
}
// Format: num | date | company | role | score | status | pdf | report | notes [| location]
// Identify score vs status by content, not position, so a swapped row can't
// merge silently (#1427).
const resolved = resolveScoreStatus(parts[4], parts[5]);
if (!resolved) {
console.warn(`⚠️ Skipping ${filename}: cannot tell score from status in columns 5–6 ("${parts[4]}" | "${parts[5]}") — refusing to merge a possible column swap`);
return null;
}
addition = {
num: parseTrackerNum(parts[0]),
date: parts[1],
company: parts[2],
role: parts[3],
// Write-canonical: the tracker stores scores unbolded (verify-pipeline
// rejects bold scores), so strip any markdown bold from the incoming cell.
score: resolved.score.replace(/\*\*/g, '').trim(),
status: validateStatus(resolved.status),
pdf: parts[6],
report: parts[7],
notes: parts[8] || '',
};
const extras = parseTsvExtras(parts, filename);
if (!extras) return null;
Object.assign(addition, extras);View on GitHub (pinned to aac998c7ed)