santifer/career-ops · info
# : — no automatic update
Error message
#${conflict.num}: ${summary} — no automatic update What it means
The per-conflict detail line emitted by reply-watch's main: for tracker row #N it joins each contending status with its reply count (e.g. "Responded (1 reply) vs Interview (2 replies)") and states that no automatic update was made. It exists so the user can arbitrate which status is correct.
Solutions
- Read the two (or more) contending statuses and pick the one matching the most recent/authoritative reply, then `node set-status.mjs <#> <State>`.
- Inspect the underlying replies in data/reply-candidates.json to spot the misclassified one and correct its classification.
- No data is lost — the tracker is untouched — so resolving is purely a manual status decision.
Example fix
// before // #18: Responded (1 reply) vs Interview (1 reply) // after node set-status.mjs 18 Interview --note "invite received after initial reply"
Defensive patterns
Strategy: validation
Validate before calling
if (conflict.choices.length > 1) {
console.warn(`#${conflict.num}: ${conflict.choices.map(c => c.newStatus).join(' vs ')} — decide which reply is authoritative`);
} Try / catch
const summary = conflict.choices
.map(c => `${c.newStatus} (${c.count} ${c.count === 1 ? 'reply' : 'replies'})`)
.join(' vs ');
console.warn(` #${conflict.num}: ${summary} — no automatic update`); Prevention
- Inspect the underlying replies, not just the counts, before choosing a status.
- Prefer the most recent/authoritative reply (human recruiter over automated ATS).
- Record the decision via set-status.mjs --note for auditability.
When it happens
Trigger: Same trigger as the conflict header: groupStatusRecommendations returns conflicts for a # because classified replies for that row disagree on the target status.
Common situations: Mixed automated + human replies for one application; stale row already advanced past the recommended status; classifier disagreement on ambiguous phrasing ("unfortunately... but keep in touch" vs interview scheduling).
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
- Conflicting status recommendations require manual review:
- Skipped # : row no longer exists in the tracker
- Skipped # : status changed from to during review
- ⚠️ Could not save report
- Cross-channel duplicate
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/de0ef41c11ce5cd4.
Report an issue: GitHub.
Appendix: source
Thrown at reply-watch.mjs:299
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('');
const answer = await askQuestion(`Apply recommended status updates to ${APPS_FILE}? (y/N): `);
if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
const statusLogFile = path.join(path.dirname(APPS_FILE), 'status-log.tsv');
const todayStr = localToday();
View on GitHub (pinned to aac998c7ed)