fix: address PR #57 CodeRabbit feedback

- Acquire AniList post-watch in-flight lock before async gating to prevent duplicate writes
- Isolate manual watched mark result from AniList post-watch callback failures
- Report known-word cache clears as mutations during immediate append when state existed
- Add regression tests for each fix
This commit is contained in:
2026-05-03 22:15:18 -07:00
parent f2fb9fa1b9
commit 77f5a48f5d
8 changed files with 225 additions and 22 deletions
+22 -19
View File
@@ -144,33 +144,36 @@ export function createMaybeRunAnilistPostWatchUpdateHandler(deps: {
deps.resetTrackedMedia(mediaKey);
}
let watchedSeconds = 0;
if (!force) {
const watchedSeconds = deps.getWatchedSeconds();
watchedSeconds = deps.getWatchedSeconds();
if (!Number.isFinite(watchedSeconds) || watchedSeconds < deps.minWatchSeconds) {
return;
}
const duration = await deps.maybeProbeAnilistDuration(mediaKey);
if (!duration || duration <= 0) {
return;
}
if (watchedSeconds / duration < deps.minWatchRatio) {
return;
}
}
const guess = await deps.ensureAnilistMediaGuess(mediaKey);
if (!guess?.title || !guess.episode || guess.episode <= 0) {
return;
}
const attemptKey = buildAnilistAttemptKey(mediaKey, guess.episode);
if (deps.hasAttemptedUpdateKey(attemptKey)) {
return;
}
deps.setInFlight(true);
try {
if (!force) {
const duration = await deps.maybeProbeAnilistDuration(mediaKey);
if (!duration || duration <= 0) {
return;
}
if (watchedSeconds / duration < deps.minWatchRatio) {
return;
}
}
const guess = await deps.ensureAnilistMediaGuess(mediaKey);
if (!guess?.title || !guess.episode || guess.episode <= 0) {
return;
}
const attemptKey = buildAnilistAttemptKey(mediaKey, guess.episode);
if (deps.hasAttemptedUpdateKey(attemptKey)) {
return;
}
await deps.processNextAnilistRetryUpdate();
if (deps.hasAttemptedUpdateKey(attemptKey)) {
return;