santifer/career-ops · warning
Skipped # : status changed from to during review
Error message
Skipped #${r.num}: status changed from ${r.oldStatus} to ${result.conflicts.get(r.num)} during review What it means
When applying the agreed status updates, reply-watch re-reads the tracker under a shared lock and detects rows whose status changed since the recommendations were computed. If row #N's current status no longer equals r.oldStatus, applying would overwrite a concurrent edit, so the update is skipped and this warning reports the observed intermediate change.
Solutions
- Re-run reply-watch: it will recompute recommendations against the current tracker state and either apply or surface a fresh conflict.
- If the concurrent change is the correct final state, do nothing — the skip prevented a clobbering overwrite.
- If the concurrent change was accidental, restore the intended status with `node set-status.mjs <#> <State>` and re-run.
- Avoid editing the tracker (manually or via other tools) while reply-watch is applying updates.
Example fix
// before // Skipped #42: status changed from Responded to Interview during review // after (recompute against current tracker) node reply-watch.mjs # fresh run applies against Interview-era state
Defensive patterns
Strategy: retry
Validate before calling
const current = getRowStatus(tracker, r.num);
if (current !== r.oldStatus) console.warn(`#${r.num} changed concurrently (${current}) — skipping`); Try / catch
} else if (result.conflicts.has(r.num)) {
console.warn(`Skipped #${r.num}: status changed from ${r.oldStatus} to ${result.conflicts.get(r.num)} during review`);
// re-run reply-watch to recompute against the new state
} Prevention
- Don't run set-status.mjs or edit the tracker while reply-watch is applying updates.
- Re-run reply-watch after any skip-during-review warning; it recomputes fresh recommendations.
- Keep the tracker as the single writer via set-status.mjs to minimize concurrent mutations.
When it happens
Trigger: Another process (set-status.mjs, tracker merge, a parallel session) modified the row between the recommendation phase and the apply phase; user hand-edited applications.md mid-run; a stale tracker file cached at read time.
Common situations: Running reply-watch while set-status.mjs runs from another terminal; reviewing an old reply-candidates.json against a tracker that has since advanced; two reply-watch runs overlapping.
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
- concurrent reservation test flaked
- # : — no automatic update
- Conflicting status recommendations require manual review:
- Skipped # : row no longer exists in the tracker
- Cannot verify tracker lock ownership at
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/08c4fe3e1853f06d.
Report an issue: GitHub.
Appendix: source
Thrown at reply-watch.mjs:338
const u = updatesByNum.get(num);
if (u) {
const line = `${num}\t${todayStr}\t${u.oldStatus}\t${u.newStatus}\treply-watch\t\n`;
try {
fs.appendFileSync(statusLogFile, line, 'utf-8');
} catch (err) {
console.warn(`Warning: failed to append to status-log.tsv for #${num}: ${err.message}`);
}
}
}
});
for (const r of updates) {
const count = r.count > 1 ? ` (${r.count} replies)` : '';
if (result.applied.has(r.num)) {
console.log(`Updated #${r.num} to ${r.newStatus}${count}`);
} else if (result.alreadyCurrent.has(r.num)) {
console.log(`No change for #${r.num}: already ${r.newStatus}${count}`);
} else if (result.conflicts.has(r.num)) {
console.warn(`Skipped #${r.num}: status changed from ${r.oldStatus} to ${result.conflicts.get(r.num)} during review`);
} else if (result.missing.has(r.num)) {
console.warn(`Skipped #${r.num}: row no longer exists in the tracker`);
}
}
console.log('\n✅ Tracker review complete');
// Sync tracker DB if tracker.mjs exists
try {
const { execSync } = await import('child_process');
execSync('node tracker.mjs sync', { stdio: 'ignore' });
console.log('Synced database index (applications.db).');
} catch (e) {
// ignore
}
} else {
console.log('Updates skipped.');
}
}View on GitHub (pinned to aac998c7ed)