diff --git a/src/services/command.ts b/src/services/command.ts index a74f940..188ed43 100644 --- a/src/services/command.ts +++ b/src/services/command.ts @@ -1070,7 +1070,7 @@ export class CommandService { // 2) Tokens de texto que empiezan por '@' como posibles asignados const atTokenCandidates = tokens.slice(2) .filter(t => t.startsWith('@')) - .map(t => t.replace(/^@+/, '').replace(/^\+/, '')); + .map(t => t.replace(/^@+/, '').replace(/^\+/, '').replace(/[.,;:!?)\]}¿¡"'’”]+$/, '')); const normalizedFromAtTokens = Array.from(new Set( atTokenCandidates.map((v) => { // Token especial: '@yo' (capturado como 'yo' tras limpiar '@') => autoasignación; no cuenta como fallo diff --git a/tests/unit/services/command.self-assign.test.ts b/tests/unit/services/command.self-assign.test.ts index e4958bc..9dd2b10 100644 --- a/tests/unit/services/command.self-assign.test.ts +++ b/tests/unit/services/command.self-assign.test.ts @@ -123,4 +123,37 @@ describe('CommandService - autoasignación con "yo" / "@yo"', () => { expect(assignees).toContain(sender); expect(String(t.description)).toBe('Mi tarea'); }); + + it('en grupo: "@yo," autoasigna y no incrementa métricas de fallo', async () => { + const sender = '600666777'; + await CommandService.handle({ + sender, + groupId: 'group2@g.us', + message: '/t n Revisar algo @yo,', + mentions: [], + }); + + const t = getLastTask(); + const assignees = getAssignees(Number(t.id)); + expect(assignees).toContain(sender); + expect(String(t.description)).toBe('Revisar algo'); + + const prom = Metrics.render?.('prom') || ''; + expect(prom).not.toContain('onboarding_assign_failures_total'); + }); + + it('en grupo: "(yo)" autoasigna y no queda en la descripción', async () => { + const sender = '600777888'; + await CommandService.handle({ + sender, + groupId: 'grp2@g.us', + message: '/t n Hacer (yo)', + mentions: [], + }); + + const t = getLastTask(); + const assignees = getAssignees(Number(t.id)); + expect(assignees).toContain(sender); + expect(String(t.description)).toBe('Hacer'); + }); });