fix(ci): address PR review and quality gate

This commit is contained in:
2026-07-22 23:57:47 -07:00
parent e0dbe5c8cd
commit d140ae6e56
8 changed files with 43 additions and 22 deletions
@@ -5,6 +5,7 @@ import os from 'node:os';
import path from 'node:path';
import type { AnkiConnectConfig } from '../types/anki';
import { setLogLevel } from '../logger';
import { KnownWordCacheManager, getKnownWordCacheLifecycleConfig } from './known-word-cache';
interface HarnessNoteInfo {
@@ -255,8 +256,14 @@ test('getKnownWordTier returns null and skips tier queries when maturity is disa
test('refresh preserves known-word cache when maturity lookup fails', async () => {
const { manager, statePath, clientState, cleanup } = createMaturityHarness(maturityConfig());
const originalInfo = console.info;
const infoLogs: string[] = [];
setLogLevel('info');
try {
console.info = (...args: unknown[]) => {
infoLogs.push(args.map((value) => String(value)).join(' '));
};
clientState.findNotesByQuery.set('deck:"Mining"', [1]);
clientState.failedQueries.add('deck:"Mining" prop:ivl>=21');
clientState.notesInfoResult = [{ noteId: 1, fields: { Word: { value: '猫' } } }];
@@ -271,7 +278,10 @@ test('refresh preserves known-word cache when maturity lookup fails', async () =
};
assert.equal(persisted.version, 4);
assert.deepEqual(persisted.tiers, {});
assert.match(infoLogs.join('\n'), /maturityTiers=fetch-failed/);
} finally {
console.info = originalInfo;
setLogLevel(undefined);
cleanup();
}
});
+9 -2
View File
@@ -389,8 +389,10 @@ export class KnownWordCacheManager {
this.isRefreshingKnownWords = true;
try {
const noteFieldsById = await this.fetchKnownWordNoteFieldsById();
const maturityTrackingEnabled = this.isMaturityTrackingEnabled();
let maturityFetchFailed = false;
let tierSets = null;
if (this.isMaturityTrackingEnabled()) {
if (maturityTrackingEnabled) {
try {
tierSets = await fetchKnownWordMaturityTierSets(
(query, options) => this.deps.client.findNotes(query, options),
@@ -398,6 +400,7 @@ export class KnownWordCacheManager {
getMatureIntervalThresholdDays(this.deps.getConfig()),
);
} catch (error) {
maturityFetchFailed = true;
log.warn('Failed to fetch known-word maturity tiers:', (error as Error).message);
}
}
@@ -441,7 +444,11 @@ export class KnownWordCacheManager {
'Known-word cache refreshed',
`noteCount=${currentNoteIds.length}`,
`wordCount=${this.wordReadingNoteIds.size}`,
tierSets ? `maturityTiers=${this.noteTierById.size}` : 'maturityTiers=off',
tierSets
? `maturityTiers=${this.noteTierById.size}`
: maturityFetchFailed
? 'maturityTiers=fetch-failed'
: 'maturityTiers=off',
);
} catch (error) {
log.warn('Failed to refresh known-word cache:', (error as Error).message);
@@ -35,20 +35,11 @@ test('maturity is enabled only when both highlight and maturity flags are on', (
test('mature threshold falls back to default for invalid values', () => {
assert.equal(DEFAULT_MATURE_INTERVAL_THRESHOLD_DAYS, 21);
assert.equal(
getMatureIntervalThresholdDays(makeConfig({ matureThresholdDays: 30 })),
30,
);
assert.equal(
getMatureIntervalThresholdDays(makeConfig({ matureThresholdDays: 14.9 })),
14,
);
assert.equal(getMatureIntervalThresholdDays(makeConfig({ matureThresholdDays: 30 })), 30);
assert.equal(getMatureIntervalThresholdDays(makeConfig({ matureThresholdDays: 14.9 })), 14);
assert.equal(getMatureIntervalThresholdDays(makeConfig({ matureThresholdDays: 0 })), 21);
assert.equal(getMatureIntervalThresholdDays(makeConfig({ matureThresholdDays: -5 })), 21);
assert.equal(
getMatureIntervalThresholdDays(makeConfig({ matureThresholdDays: Number.NaN })),
21,
);
assert.equal(getMatureIntervalThresholdDays(makeConfig({ matureThresholdDays: Number.NaN })), 21);
assert.equal(getMatureIntervalThresholdDays(makeConfig({})), 21);
assert.equal(getMatureIntervalThresholdDays(makeConfig(undefined)), 21);
});
@@ -80,9 +80,7 @@ test('annotateTokens resolves maturity through the kana reading fallback', () =>
reading: string | undefined;
allowReadingOnlyMatch: boolean | undefined;
}> = [];
const tokens = [
makeToken({ surface: '大体', headword: '大体', reading: 'だいたい', endPos: 2 }),
];
const tokens = [makeToken({ surface: '大体', headword: '大体', reading: 'だいたい', endPos: 2 })];
const result = annotateTokens(
tokens,
@@ -646,7 +646,9 @@ function computeTokenKnownMaturity(
if (!fallbackReading || fallbackReading === matchText.trim()) {
return undefined;
}
return getKnownWordTier(fallbackReading, undefined, { allowReadingOnlyMatch: false }) ?? undefined;
return (
getKnownWordTier(fallbackReading, undefined, { allowReadingOnlyMatch: false }) ?? undefined
);
}
function filterTokenFrequencyRank(
@@ -250,8 +250,5 @@ test('computeWordClass gives n+1 and name matches precedence over maturity', ()
surface: 'アクア',
}) as MergedToken & { isNameMatch?: boolean };
nameMatch.isNameMatch = true;
assert.equal(
computeWordClass(nameMatch, { nameMatchEnabled: true }),
'word word-name-match',
);
assert.equal(computeWordClass(nameMatch, { nameMatchEnabled: true }), 'word word-name-match');
});