gogcli-mcp-gmail 2.22.0 → 2.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,67 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { authoredBodyLines, measureBodyAgreement } from '../../src/tools/gmail-extra.js';
3
+
4
+ /**
5
+ * HAZARD A — the lineage judgement must not fire on two unrelated drafts.
6
+ *
7
+ * `boilerplateLineFlags` stripped the RFC 3676 `-- ` block, the client's own
8
+ * `Sent from my iPhone`, and the NAME under a sign-off — but the run stopped at
9
+ * the first line that was not name-shaped, so a USER-CONFIGURED signature
10
+ * survived as authored prose:
11
+ *
12
+ * Thanks, -> stripped
13
+ * Chris Hall -> stripped
14
+ * (704) 555-0142 -> run stopped; survived
15
+ * chris.c.hall@gmail.com -> survived
16
+ * https://example.com/chris -> survived
17
+ *
18
+ * Those lines are identical on every message the account composes. Measured
19
+ * before the fix: two unrelated drafts shared 3 authored lines / 61 chars and
20
+ * scored similarity 0.60 against a 0.60 threshold — meetsThreshold TRUE on a
21
+ * plumber note and a soccer note. In a mailbox whose drafts go to a parenting
22
+ * coordinator, a wrong pairing is the expensive direction.
23
+ */
24
+ const SIGNATURE = ['Thanks,', 'Chris Hall', '(704) 555-0142', 'chris.c.hall@gmail.com', 'https://example.com/chris'];
25
+ const withSig = (body: string[]) => ['Hi Sam,', '', ...body, '', ...SIGNATURE].join('\n');
26
+
27
+ describe('a shared signature is never lineage evidence', () => {
28
+ it('does not pair two unrelated drafts that share one signature', () => {
29
+ const m = measureBodyAgreement(withSig(['The plumber comes Tuesday at 9am.']), withSig(['Soccer registration closes Friday.']));
30
+ expect(m.sharedAuthoredLines).toBe(0);
31
+ expect(m.meetsThreshold).toBe(false);
32
+ });
33
+
34
+ it('strips the whole signature block, not just the name', () => {
35
+ expect(authoredBodyLines(withSig(['The plumber comes Tuesday at 9am.']))).toEqual(['The plumber comes Tuesday at 9am.']);
36
+ });
37
+ });
38
+
39
+ describe('and it still stops at authored content', () => {
40
+ it('keeps a postscript under the signature', () => {
41
+ expect(authoredBodyLines([...SIGNATURE, '', 'P.S. The invoice is attached.'].join('\n')))
42
+ .toEqual(['P.S. The invoice is attached.']);
43
+ });
44
+
45
+ it('keeps prose under the sign-off', () => {
46
+ expect(authoredBodyLines(['Thanks,', 'Chris', '', 'Actually the plumber moved to Wednesday.'].join('\n')))
47
+ .toEqual(['Actually the plumber moved to Wednesday.']);
48
+ });
49
+
50
+ it('keeps contact-shaped lines that are NOT under a sign-off', () => {
51
+ // The rule is positional. A bare phone number in the body is content.
52
+ expect(authoredBodyLines(['(704) 555-0142', 'chris@example.com'].join('\n')))
53
+ .toEqual(['(704) 555-0142', 'chris@example.com']);
54
+ });
55
+
56
+ it('keeps a phone number inside a sentence', () => {
57
+ expect(authoredBodyLines(['Call me at (704) 555-0142 about the roof.', '', 'Thanks,', 'Chris'].join('\n')))
58
+ .toEqual(['Call me at (704) 555-0142 about the roof.']);
59
+ });
60
+
61
+ it('still pairs two drafts that genuinely share authored prose', () => {
62
+ const shared = ['The plumber comes Tuesday at 9am.', 'He will need access to the crawlspace.', 'I left a key under the mat for him.'];
63
+ const m = measureBodyAgreement(withSig(shared), withSig([...shared, 'One more thing: the gate code is 4417.']));
64
+ expect(m.sharedAuthoredLines).toBeGreaterThanOrEqual(3);
65
+ expect(m.meetsThreshold).toBe(true);
66
+ });
67
+ });