fix(vocab): reject lexical hints paired with sentences

This commit is contained in:
Torsten Schulz (local)
2026-08-27 12:25:43 +02:00
parent c836c709c4
commit d9397f741f
4 changed files with 37 additions and 3 deletions

View File

@@ -0,0 +1,17 @@
'use strict';
module.exports = {
async up(queryInterface) {
// A legacy gap-fill hint was persisted as a vocabulary answer. The pair
// "jetzt/heute" → "Karon naa ko diri" is not a valid translation card.
await queryInterface.sequelize.query(`
DELETE FROM community.vocab_srs_item
WHERE lower(trim(learning)) = 'jetzt/heute'
AND lower(trim(reference)) = 'karon naa ko diri';
`);
},
async down() {
// Do not restore an invalid study card.
}
};

View File

@@ -201,8 +201,15 @@ export default class VocabService {
const rightLooksSentence = rightWords >= 3 || /[?!.].+\S/.test(rightText);
const leftLooksShortFragment = leftWords <= 1 && leftText.length <= 12;
const rightLooksShortFragment = rightWords <= 1 && rightText.length <= 12;
// A slash-separated hint such as "jetzt/heute" is a lexical alternative,
// never the translation of a full sentence such as "Karon naa ko diri".
const leftLooksLexicalHint = /\//.test(leftText) && leftWords <= 2 && leftText.length <= 24;
const rightLooksLexicalHint = /\//.test(rightText) && rightWords <= 2 && rightText.length <= 24;
return (leftLooksShortFragment && rightLooksSentence) || (rightLooksShortFragment && leftLooksSentence);
return (leftLooksShortFragment && rightLooksSentence)
|| (rightLooksShortFragment && leftLooksSentence)
|| (leftLooksLexicalHint && rightLooksSentence)
|| (rightLooksLexicalHint && leftLooksSentence);
}
_calculateSrsSchedule(item, { correct } = {}) {

View File

@@ -739,8 +739,13 @@ export default {
const rightLooksSentence = rightWords >= 3 || /[?!.].+\S/.test(rightText);
const leftLooksShortFragment = leftWords <= 1 && leftText.length <= 12;
const rightLooksShortFragment = rightWords <= 1 && rightText.length <= 12;
const leftLooksLexicalHint = /\//.test(leftText) && leftWords <= 2 && leftText.length <= 24;
const rightLooksLexicalHint = /\//.test(rightText) && rightWords <= 2 && rightText.length <= 24;
return (leftLooksShortFragment && rightLooksSentence) || (rightLooksShortFragment && leftLooksSentence);
return (leftLooksShortFragment && rightLooksSentence)
|| (rightLooksShortFragment && leftLooksSentence)
|| (leftLooksLexicalHint && rightLooksSentence)
|| (rightLooksLexicalHint && leftLooksSentence);
},
splitPhraseAlternatives(value) {
const text = String(value || '').trim();

View File

@@ -2320,8 +2320,13 @@ export default {
const rightLooksSentence = rightWords >= 3 || /[?!.].+\S/.test(rightText);
const leftLooksShortFragment = leftWords <= 1 && leftText.length <= 12;
const rightLooksShortFragment = rightWords <= 1 && rightText.length <= 12;
const leftLooksLexicalHint = /\//.test(leftText) && leftWords <= 2 && leftText.length <= 24;
const rightLooksLexicalHint = /\//.test(rightText) && rightWords <= 2 && rightText.length <= 24;
return (leftLooksShortFragment && rightLooksSentence) || (rightLooksShortFragment && leftLooksSentence);
return (leftLooksShortFragment && rightLooksSentence)
|| (rightLooksShortFragment && leftLooksSentence)
|| (leftLooksLexicalHint && rightLooksSentence)
|| (rightLooksLexicalHint && leftLooksSentence);
},
isTrainableLessonVocabPair(learning, reference) {
const l = String(learning || '').trim();