santifer/career-ops · warning
Conflicting status recommendations require manual review:
Error message
Conflicting status recommendations require manual review:
What it means
reply-watch groups per-tracker-row status recommendations derived from classified replies. When replies for the same application number recommend different new statuses (a conflict), no automatic tracker update is performed; main prints this header and then one line per conflicting row so the user resolves manually.
Solutions
- Review the conflicting choices printed under this header and set the correct status yourself with `node set-status.mjs <#> <State> --note "..."`.
- Re-check the individual replies (paste-reply.mjs / classification) — one is likely misclassified; correct it and re-run.
- If both replies are genuinely distinct events, apply them in order manually (earliest first) so the tracker reflects the latest state.
- Re-run reply-watch afterwards; the conflict disappears once the row's current status matches one of the recommendations.
Example fix
// before // Conflicting status recommendations require manual review: // #42: Responded (1 reply) vs Rejected (1 replies) // after node set-status.mjs 42 Rejected --note "ATS rejection supersedes earlier recruiter email"
Defensive patterns
Strategy: validation
Validate before calling
const recs = groupStatusRecommendations(recommendations);
if (recs.conflicts.length > 0) {
console.warn('resolve conflicts manually with set-status.mjs before relying on automation');
} Try / catch
if (groupedRecommendations.conflicts.length > 0) {
for (const c of groupedRecommendations.conflicts) console.warn(`#${c.num}: needs manual review`);
return; // never auto-update conflicting rows
} Prevention
- Run reply-watch regularly so conflicts stay small and recent.
- Correct misclassified replies in reply-candidates.json before applying updates.
- Use set-status.mjs (not hand edits) so status-log history disambiguates conflicts.
When it happens
Trigger: Running reply-watch over reply-candidates.json where one tracker # received multiple replies classified to different canonical states — e.g. one email reads as Responded and another as Rejected for the same #.
Common situations: An interview invite and a form rejection arriving for the same req; a recruiter email and an automated ATS rejection in the same window; misclassification of an ambiguous reply pushing a minority vote.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- # : — no automatic update
- Skipped # : row no longer exists in the tracker
- Skipped # : status changed from to during review
- Sync drift (needs human review)
- ⚠️ Could not save report
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/5b224f8d8adedf69.
Report an issue: GitHub.
Appendix: source
Thrown at reply-watch.mjs:294
console.log('');
if (match.application_num !== null && classification.suggestedTrackerUpdate !== 'none' && classification.suggestedTrackerUpdate !== 'Needs Review') {
const app = apps.find(a => a.num === match.application_num);
if (app && app.status !== classification.suggestedTrackerUpdate) {
recommendations.push({
num: app.num,
company: app.company,
role: app.role,
oldStatus: app.status,
newStatus: classification.suggestedTrackerUpdate
});
}
}
});
const groupedRecommendations = groupStatusRecommendations(recommendations);
if (groupedRecommendations.conflicts.length > 0) {
console.warn('Conflicting status recommendations require manual review:');
for (const conflict of groupedRecommendations.conflicts) {
const summary = conflict.choices
.map(choice => `${choice.newStatus} (${choice.count} ${choice.count === 1 ? 'reply' : 'replies'})`)
.join(' vs ');
console.warn(` #${conflict.num}: ${summary} — no automatic update`);
}
console.log('');
}
if (groupedRecommendations.updates.length > 0) {
const updates = groupedRecommendations.updates;
console.log('Suggested status updates to apply:');
updates.forEach(r => {
const count = r.count > 1 ? ` (${r.count} replies)` : '';
console.log(` #${r.num} ${r.company} (${r.role}): ${r.oldStatus} → ${r.newStatus}${count}`);
});
console.log('');
View on GitHub (pinned to aac998c7ed)