@postalsys/email-content 0.0.1
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.
- package/LICENSE +21 -0
- package/README.md +288 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/analyze.d.ts +91 -0
- package/dist/analyze.d.ts.map +1 -0
- package/dist/analyze.js +274 -0
- package/dist/analyze.js.map +1 -0
- package/dist/annotate/client.d.ts +64 -0
- package/dist/annotate/client.d.ts.map +1 -0
- package/dist/annotate/client.js +139 -0
- package/dist/annotate/client.js.map +1 -0
- package/dist/annotate/llm.d.ts +46 -0
- package/dist/annotate/llm.d.ts.map +1 -0
- package/dist/annotate/llm.js +107 -0
- package/dist/annotate/llm.js.map +1 -0
- package/dist/annotate/prompt.d.ts +38 -0
- package/dist/annotate/prompt.d.ts.map +1 -0
- package/dist/annotate/prompt.js +165 -0
- package/dist/annotate/prompt.js.map +1 -0
- package/dist/annotate/store.d.ts +43 -0
- package/dist/annotate/store.d.ts.map +1 -0
- package/dist/annotate/store.js +46 -0
- package/dist/annotate/store.js.map +1 -0
- package/dist/canonical/html.d.ts +33 -0
- package/dist/canonical/html.d.ts.map +1 -0
- package/dist/canonical/html.js +156 -0
- package/dist/canonical/html.js.map +1 -0
- package/dist/canonical/text.d.ts +75 -0
- package/dist/canonical/text.d.ts.map +1 -0
- package/dist/canonical/text.js +217 -0
- package/dist/canonical/text.js.map +1 -0
- package/dist/classify/confidence.d.ts +38 -0
- package/dist/classify/confidence.d.ts.map +1 -0
- package/dist/classify/confidence.js +59 -0
- package/dist/classify/confidence.js.map +1 -0
- package/dist/classify/reconcile.d.ts +52 -0
- package/dist/classify/reconcile.d.ts.map +1 -0
- package/dist/classify/reconcile.js +100 -0
- package/dist/classify/reconcile.js.map +1 -0
- package/dist/classify/rules.d.ts +51 -0
- package/dist/classify/rules.d.ts.map +1 -0
- package/dist/classify/rules.js +648 -0
- package/dist/classify/rules.js.map +1 -0
- package/dist/cli/annotate.d.ts +23 -0
- package/dist/cli/annotate.d.ts.map +1 -0
- package/dist/cli/annotate.js +328 -0
- package/dist/cli/annotate.js.map +1 -0
- package/dist/cli/args.d.ts +17 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +72 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/benchmark.d.ts +13 -0
- package/dist/cli/benchmark.d.ts.map +1 -0
- package/dist/cli/benchmark.js +172 -0
- package/dist/cli/benchmark.js.map +1 -0
- package/dist/cli/corpus.d.ts +9 -0
- package/dist/cli/corpus.d.ts.map +1 -0
- package/dist/cli/corpus.js +152 -0
- package/dist/cli/corpus.js.map +1 -0
- package/dist/cli/disagreements.d.ts +14 -0
- package/dist/cli/disagreements.d.ts.map +1 -0
- package/dist/cli/disagreements.js +133 -0
- package/dist/cli/disagreements.js.map +1 -0
- package/dist/cli/evaluate.d.ts +15 -0
- package/dist/cli/evaluate.d.ts.map +1 -0
- package/dist/cli/evaluate.js +215 -0
- package/dist/cli/evaluate.js.map +1 -0
- package/dist/cli/extract.d.ts +10 -0
- package/dist/cli/extract.d.ts.map +1 -0
- package/dist/cli/extract.js +139 -0
- package/dist/cli/extract.js.map +1 -0
- package/dist/cli/main.d.ts +9 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +147 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/corpus/analyze.d.ts +66 -0
- package/dist/corpus/analyze.d.ts.map +1 -0
- package/dist/corpus/analyze.js +214 -0
- package/dist/corpus/analyze.js.map +1 -0
- package/dist/corpus/migrations/index.d.ts +14 -0
- package/dist/corpus/migrations/index.d.ts.map +1 -0
- package/dist/corpus/migrations/index.js +158 -0
- package/dist/corpus/migrations/index.js.map +1 -0
- package/dist/corpus/sample.d.ts +66 -0
- package/dist/corpus/sample.d.ts.map +1 -0
- package/dist/corpus/sample.js +98 -0
- package/dist/corpus/sample.js.map +1 -0
- package/dist/corpus/scanner.d.ts +79 -0
- package/dist/corpus/scanner.d.ts.map +1 -0
- package/dist/corpus/scanner.js +256 -0
- package/dist/corpus/scanner.js.map +1 -0
- package/dist/corpus/stats.d.ts +76 -0
- package/dist/corpus/stats.d.ts.map +1 -0
- package/dist/corpus/stats.js +240 -0
- package/dist/corpus/stats.js.map +1 -0
- package/dist/corpus/store.d.ts +67 -0
- package/dist/corpus/store.d.ts.map +1 -0
- package/dist/corpus/store.js +196 -0
- package/dist/corpus/store.js.map +1 -0
- package/dist/corpus/thread-index.d.ts +31 -0
- package/dist/corpus/thread-index.d.ts.map +1 -0
- package/dist/corpus/thread-index.js +182 -0
- package/dist/corpus/thread-index.js.map +1 -0
- package/dist/corpus/worker.d.ts +21 -0
- package/dist/corpus/worker.d.ts.map +1 -0
- package/dist/corpus/worker.js +74 -0
- package/dist/corpus/worker.js.map +1 -0
- package/dist/detect/client.d.ts +28 -0
- package/dist/detect/client.d.ts.map +1 -0
- package/dist/detect/client.js +121 -0
- package/dist/detect/client.js.map +1 -0
- package/dist/detect/disclaimer.d.ts +12 -0
- package/dist/detect/disclaimer.d.ts.map +1 -0
- package/dist/detect/disclaimer.js +28 -0
- package/dist/detect/disclaimer.js.map +1 -0
- package/dist/detect/forward-header.d.ts +10 -0
- package/dist/detect/forward-header.d.ts.map +1 -0
- package/dist/detect/forward-header.js +35 -0
- package/dist/detect/forward-header.js.map +1 -0
- package/dist/detect/patterns/disclaimers.json +113 -0
- package/dist/detect/patterns/forward-headers.json +40 -0
- package/dist/detect/patterns/html-clients.json +157 -0
- package/dist/detect/patterns/quoted-headers.json +41 -0
- package/dist/detect/patterns/reply-headers.json +139 -0
- package/dist/detect/patterns/signatures.json +58 -0
- package/dist/detect/patterns.d.ts +43 -0
- package/dist/detect/patterns.d.ts.map +1 -0
- package/dist/detect/patterns.js +125 -0
- package/dist/detect/patterns.js.map +1 -0
- package/dist/detect/reply-header.d.ts +44 -0
- package/dist/detect/reply-header.d.ts.map +1 -0
- package/dist/detect/reply-header.js +134 -0
- package/dist/detect/reply-header.js.map +1 -0
- package/dist/detect/signature.d.ts +28 -0
- package/dist/detect/signature.d.ts.map +1 -0
- package/dist/detect/signature.js +77 -0
- package/dist/detect/signature.js.map +1 -0
- package/dist/detect/traffic.d.ts +26 -0
- package/dist/detect/traffic.d.ts.map +1 -0
- package/dist/detect/traffic.js +98 -0
- package/dist/detect/traffic.js.map +1 -0
- package/dist/eval/metrics.d.ts +87 -0
- package/dist/eval/metrics.d.ts.map +1 -0
- package/dist/eval/metrics.js +185 -0
- package/dist/eval/metrics.js.map +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +163 -0
- package/dist/index.js.map +1 -0
- package/dist/match/history.d.ts +62 -0
- package/dist/match/history.d.ts.map +1 -0
- package/dist/match/history.js +128 -0
- package/dist/match/history.js.map +1 -0
- package/dist/match/normalize.d.ts +33 -0
- package/dist/match/normalize.d.ts.map +1 -0
- package/dist/match/normalize.js +63 -0
- package/dist/match/normalize.js.map +1 -0
- package/dist/match/shingle.d.ts +44 -0
- package/dist/match/shingle.d.ts.map +1 -0
- package/dist/match/shingle.js +78 -0
- package/dist/match/shingle.js.map +1 -0
- package/dist/mime/charset.d.ts +33 -0
- package/dist/mime/charset.d.ts.map +1 -0
- package/dist/mime/charset.js +118 -0
- package/dist/mime/charset.js.map +1 -0
- package/dist/mime/headers.d.ts +32 -0
- package/dist/mime/headers.d.ts.map +1 -0
- package/dist/mime/headers.js +127 -0
- package/dist/mime/headers.js.map +1 -0
- package/dist/mime/model.d.ts +111 -0
- package/dist/mime/model.d.ts.map +1 -0
- package/dist/mime/model.js +17 -0
- package/dist/mime/model.js.map +1 -0
- package/dist/mime/parse.d.ts +27 -0
- package/dist/mime/parse.d.ts.map +1 -0
- package/dist/mime/parse.js +343 -0
- package/dist/mime/parse.js.map +1 -0
- package/dist/segment/features.d.ts +29 -0
- package/dist/segment/features.d.ts.map +1 -0
- package/dist/segment/features.js +102 -0
- package/dist/segment/features.js.map +1 -0
- package/dist/segment/html-blocks.d.ts +28 -0
- package/dist/segment/html-blocks.d.ts.map +1 -0
- package/dist/segment/html-blocks.js +596 -0
- package/dist/segment/html-blocks.js.map +1 -0
- package/dist/segment/text-blocks.d.ts +30 -0
- package/dist/segment/text-blocks.d.ts.map +1 -0
- package/dist/segment/text-blocks.js +204 -0
- package/dist/segment/text-blocks.js.map +1 -0
- package/dist/segment/types.d.ts +88 -0
- package/dist/segment/types.d.ts.map +1 -0
- package/dist/segment/types.js +11 -0
- package/dist/segment/types.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/dist/util/hash.d.ts +49 -0
- package/dist/util/hash.d.ts.map +1 -0
- package/dist/util/hash.js +0 -0
- package/dist/util/hash.js.map +1 -0
- package/dist/util/lang.d.ts +25 -0
- package/dist/util/lang.d.ts.map +1 -0
- package/dist/util/lang.js +135 -0
- package/dist/util/lang.js.map +1 -0
- package/dist/util/worker-pool.d.ts +51 -0
- package/dist/util/worker-pool.d.ts.map +1 -0
- package/dist/util/worker-pool.js +155 -0
- package/dist/util/worker-pool.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Corpus feature extraction.
|
|
4
|
+
*
|
|
5
|
+
* Turns a parsed message into the flat, privacy safe record stored in the corpus database. The hard
|
|
6
|
+
* rule here is that nothing derived from body text, subjects or addresses may leave this function
|
|
7
|
+
* in readable form. Subjects and addresses become salted hashes, sender domains are kept because
|
|
8
|
+
* they are needed for stratification, and body text is reduced to counts, ratios and a SimHash.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.analyzeMessage = analyzeMessage;
|
|
12
|
+
const html_1 = require("../canonical/html");
|
|
13
|
+
const text_1 = require("../canonical/text");
|
|
14
|
+
const client_1 = require("../detect/client");
|
|
15
|
+
const patterns_1 = require("../detect/patterns");
|
|
16
|
+
const traffic_1 = require("../detect/traffic");
|
|
17
|
+
const hash_1 = require("../util/hash");
|
|
18
|
+
const lang_1 = require("../util/lang");
|
|
19
|
+
const REPLY_SUBJECT = /^\s*(re|aw|sv|vs|vast|antw|res|odp|ответ)\s*(\[\d+\])?\s*:/i;
|
|
20
|
+
const FORWARD_SUBJECT = /^\s*(fwd?|tr|wg|vs|vl|doorst|пересылка)\s*:/i;
|
|
21
|
+
function pickParts(message) {
|
|
22
|
+
const plain = [];
|
|
23
|
+
const html = [];
|
|
24
|
+
let attachments = 0;
|
|
25
|
+
for (const part of message.parts) {
|
|
26
|
+
if (part.multipart) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const isText = part.contentType === 'text/plain' || part.contentType === 'text/html';
|
|
30
|
+
if (isText && part.disposition !== 'attachment') {
|
|
31
|
+
if (part.contentType === 'text/plain') {
|
|
32
|
+
plain.push(part);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
html.push(part);
|
|
36
|
+
}
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (part.rfc822) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
attachments++;
|
|
43
|
+
}
|
|
44
|
+
return { plain, html, attachments };
|
|
45
|
+
}
|
|
46
|
+
function distinct(values) {
|
|
47
|
+
const set = new Set();
|
|
48
|
+
for (const value of values) {
|
|
49
|
+
if (value) {
|
|
50
|
+
set.add(value.toLowerCase());
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return [...set].sort().join(',');
|
|
54
|
+
}
|
|
55
|
+
function extractDomain(address) {
|
|
56
|
+
if (!address) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const match = address.match(/@([A-Za-z0-9.-]+\.[A-Za-z]{2,})/);
|
|
60
|
+
return match?.[1] ? match[1].toLowerCase() : null;
|
|
61
|
+
}
|
|
62
|
+
function extractAddress(header) {
|
|
63
|
+
if (!header) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const angled = header.match(/<([^<>@\s]{1,64}@[^<>\s]{1,255})>/);
|
|
67
|
+
if (angled?.[1]) {
|
|
68
|
+
return angled[1].toLowerCase();
|
|
69
|
+
}
|
|
70
|
+
const bare = header.match(/([^<>\s,;"]{1,64}@[^<>\s,;"]{1,255})/);
|
|
71
|
+
return bare?.[1] ? bare[1].toLowerCase() : null;
|
|
72
|
+
}
|
|
73
|
+
/** Which line level markers fired anywhere in the text. Ids only, no matched content. */
|
|
74
|
+
function detectMarkers(lines) {
|
|
75
|
+
const patterns = (0, patterns_1.loadPatterns)();
|
|
76
|
+
const fired = new Set();
|
|
77
|
+
// Cap the scan. Reply markers cluster near the top and bottom of a body, and a digest with tens
|
|
78
|
+
// of thousands of lines would otherwise dominate the scan cost.
|
|
79
|
+
const limit = 3000;
|
|
80
|
+
const scan = lines.length > limit ? [...lines.slice(0, limit / 2), ...lines.slice(-limit / 2)] : lines;
|
|
81
|
+
for (const line of scan) {
|
|
82
|
+
if (line.length > 500) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
for (const pattern of patterns.replyHeaders) {
|
|
86
|
+
if (pattern.regex.test(line)) {
|
|
87
|
+
fired.add(`reply:${pattern.id}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
for (const pattern of patterns.forwardHeaders) {
|
|
91
|
+
if (pattern.regex.test(line)) {
|
|
92
|
+
fired.add(`forward:${pattern.id}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
for (const pattern of patterns.quotedHeaderFields) {
|
|
96
|
+
if (pattern.regex.test(line)) {
|
|
97
|
+
fired.add(`field:${pattern.id}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
for (const pattern of patterns.signatureDelimiters) {
|
|
101
|
+
if (pattern.regex.test(line)) {
|
|
102
|
+
fired.add(`sigdelim:${pattern.id}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
for (const pattern of patterns.signaturePhrases) {
|
|
106
|
+
if (pattern.regex.test(line)) {
|
|
107
|
+
fired.add(`sig:${pattern.id}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return [...fired].sort();
|
|
112
|
+
}
|
|
113
|
+
function detectDisclaimers(text) {
|
|
114
|
+
const patterns = (0, patterns_1.loadPatterns)();
|
|
115
|
+
// Disclaimers sit at the end. Scanning the tail keeps the cost bounded and avoids matching a
|
|
116
|
+
// discussion that happens to mention confidentiality in the middle of a thread.
|
|
117
|
+
const tail = text.length > 4000 ? text.slice(-4000) : text;
|
|
118
|
+
const fired = [];
|
|
119
|
+
for (const pattern of patterns.disclaimerPhrases) {
|
|
120
|
+
if (pattern.regex.test(tail)) {
|
|
121
|
+
fired.push(`disclaimer:${pattern.id}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return fired;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Build the corpus record for one parsed message.
|
|
128
|
+
*
|
|
129
|
+
* @param message parsed MIME structure
|
|
130
|
+
* @param salt per database salt for the privacy preserving hashes
|
|
131
|
+
*/
|
|
132
|
+
function analyzeMessage(message, salt) {
|
|
133
|
+
const { plain, html, attachments } = pickParts(message);
|
|
134
|
+
const headers = message.headers;
|
|
135
|
+
const plainText = plain
|
|
136
|
+
.map(part => part.decoded?.text || '')
|
|
137
|
+
.filter(Boolean)
|
|
138
|
+
.join('\n');
|
|
139
|
+
const htmlSource = html
|
|
140
|
+
.map(part => part.decoded?.text || '')
|
|
141
|
+
.filter(Boolean)
|
|
142
|
+
.join('\n');
|
|
143
|
+
const canonical = (0, text_1.canonicaliseText)(plainText);
|
|
144
|
+
const quoting = (0, text_1.profileQuoting)(canonical.lines);
|
|
145
|
+
const hints = htmlSource ? (0, html_1.detectHtmlHints)(htmlSource) : null;
|
|
146
|
+
// Language and markers come from whichever representation actually carries the content.
|
|
147
|
+
const htmlProjection = htmlSource && !plainText ? (0, html_1.stripTagsToText)(htmlSource) : '';
|
|
148
|
+
const analysisText = plainText || htmlProjection;
|
|
149
|
+
const markers = detectMarkers(canonical.lines.map(line => line.content));
|
|
150
|
+
if (htmlProjection) {
|
|
151
|
+
markers.push(...detectMarkers(htmlProjection.split('\n')));
|
|
152
|
+
}
|
|
153
|
+
markers.push(...detectDisclaimers(analysisText));
|
|
154
|
+
const bodyKind = plainText && htmlSource ? 'both' : plainText ? 'plain-only' : htmlSource ? 'html-only' : 'none';
|
|
155
|
+
const subject = headers.subject || '';
|
|
156
|
+
const subjectPrefix = !subject
|
|
157
|
+
? 'none'
|
|
158
|
+
: REPLY_SUBJECT.test(subject)
|
|
159
|
+
? 'reply'
|
|
160
|
+
: FORWARD_SUBJECT.test(subject)
|
|
161
|
+
? 'forward'
|
|
162
|
+
: 'plain';
|
|
163
|
+
const rootPart = message.partsById.get(message.rootId);
|
|
164
|
+
const boundary = rootPart?.contentTypeParams.boundary || null;
|
|
165
|
+
const fingerprint = (0, client_1.fingerprintClient)(headers, htmlSource || null, boundary);
|
|
166
|
+
const traffic = (0, traffic_1.classifyTraffic)(headers, message.rootHeaders);
|
|
167
|
+
const language = (0, lang_1.estimateLanguage)(analysisText);
|
|
168
|
+
const hasQuoteInPlain = quoting.quotedLines > 0 || markers.some(id => id.startsWith('reply:'));
|
|
169
|
+
const hasQuoteInHtml = Boolean(hints && (hints.hasBlockquote || hints.ids.some(id => id.includes('quote') || id.includes('Rply') || id.includes('separator'))));
|
|
170
|
+
const fromAddress = extractAddress(headers.from);
|
|
171
|
+
return {
|
|
172
|
+
messageId: headers.messageId,
|
|
173
|
+
inReplyTo: headers.inReplyTo,
|
|
174
|
+
referencesCount: headers.references.length,
|
|
175
|
+
referencesRoot: headers.references[0] ?? null,
|
|
176
|
+
dateMs: headers.dateMs,
|
|
177
|
+
fromDomain: extractDomain(headers.from),
|
|
178
|
+
fromHash: fromAddress ? (0, hash_1.saltedHash)(salt, fromAddress) : null,
|
|
179
|
+
subjectHash: subject ? (0, hash_1.saltedHash)(salt, subject.trim().toLowerCase().replace(REPLY_SUBJECT, '').replace(FORWARD_SUBJECT, '').trim()) : null,
|
|
180
|
+
subjectPrefix,
|
|
181
|
+
subjectLength: subject.length,
|
|
182
|
+
structure: message.structure,
|
|
183
|
+
bodyKind,
|
|
184
|
+
charsets: distinct([...plain, ...html].map(part => part.decoded?.charsetUsed ?? part.charset)),
|
|
185
|
+
encodings: distinct(message.parts.filter(part => !part.multipart).map(part => part.encoding)),
|
|
186
|
+
partCount: message.parts.length,
|
|
187
|
+
attachmentCount: attachments,
|
|
188
|
+
hasRfc822: message.parts.some(part => part.rfc822),
|
|
189
|
+
textChars: plainText.length,
|
|
190
|
+
htmlChars: htmlSource.length,
|
|
191
|
+
flowed: plain.some(part => part.flowed),
|
|
192
|
+
client: fingerprint.client,
|
|
193
|
+
clientSource: fingerprint.source,
|
|
194
|
+
traffic: traffic.traffic,
|
|
195
|
+
trafficSignals: traffic.signals.join(','),
|
|
196
|
+
isReply: Boolean(headers.inReplyTo) || subjectPrefix === 'reply',
|
|
197
|
+
isForward: subjectPrefix === 'forward' || markers.some(id => id.startsWith('forward:')),
|
|
198
|
+
quoteDepthMax: quoting.maxDepth,
|
|
199
|
+
quotedRatio: Number(quoting.quotedRatio.toFixed(4)),
|
|
200
|
+
replyStyle: plainText ? quoting.style : 'unknown',
|
|
201
|
+
markers: markers.sort().join(','),
|
|
202
|
+
htmlHints: hints ? hints.ids.join(',') : '',
|
|
203
|
+
blockquoteCount: hints?.blockquoteCount ?? 0,
|
|
204
|
+
tableCount: hints?.tableCount ?? 0,
|
|
205
|
+
hasImage: hints?.hasImage ?? false,
|
|
206
|
+
suspectMalformedHtml: hints?.suspectMalformed ?? false,
|
|
207
|
+
lang: language.lang,
|
|
208
|
+
langScore: Number(language.score.toFixed(3)),
|
|
209
|
+
bodySimhash: (0, hash_1.simhash64)(analysisText),
|
|
210
|
+
warnings: [...new Set(message.warnings.map(warning => warning.code))].sort().join(','),
|
|
211
|
+
quoteMarkingDisagrees: bodyKind === 'both' && hasQuoteInPlain !== hasQuoteInHtml
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=analyze.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/corpus/analyze.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forward only schema migrations.
|
|
3
|
+
*
|
|
4
|
+
* Applied in order, tracked with SQLite's user_version pragma. Migrations never rewrite history:
|
|
5
|
+
* to change a column, add a new migration. A corpus scan takes minutes and can be re-run, but
|
|
6
|
+
* annotations cannot be regenerated, so the annotation tables must only ever be extended.
|
|
7
|
+
*/
|
|
8
|
+
export interface Migration {
|
|
9
|
+
version: number;
|
|
10
|
+
name: string;
|
|
11
|
+
sql: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const MIGRATIONS: readonly Migration[];
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/corpus/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,SAAS;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,UAAU,EAAE,SAAS,SAAS,EAkJ1C,CAAC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Forward only schema migrations.
|
|
4
|
+
*
|
|
5
|
+
* Applied in order, tracked with SQLite's user_version pragma. Migrations never rewrite history:
|
|
6
|
+
* to change a column, add a new migration. A corpus scan takes minutes and can be re-run, but
|
|
7
|
+
* annotations cannot be regenerated, so the annotation tables must only ever be extended.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.MIGRATIONS = void 0;
|
|
11
|
+
exports.MIGRATIONS = [
|
|
12
|
+
{
|
|
13
|
+
version: 1,
|
|
14
|
+
name: 'corpus-core',
|
|
15
|
+
sql: `
|
|
16
|
+
CREATE TABLE meta (
|
|
17
|
+
key TEXT PRIMARY KEY,
|
|
18
|
+
value TEXT NOT NULL
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
-- One row per scan invocation, so that results can be attributed to a code version.
|
|
22
|
+
CREATE TABLE runs (
|
|
23
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
24
|
+
root TEXT NOT NULL,
|
|
25
|
+
started_at INTEGER NOT NULL,
|
|
26
|
+
finished_at INTEGER,
|
|
27
|
+
status TEXT NOT NULL DEFAULT 'running',
|
|
28
|
+
processing_version TEXT NOT NULL,
|
|
29
|
+
extractor_version TEXT NOT NULL,
|
|
30
|
+
options_json TEXT NOT NULL DEFAULT '{}',
|
|
31
|
+
files_seen INTEGER NOT NULL DEFAULT 0,
|
|
32
|
+
files_processed INTEGER NOT NULL DEFAULT 0,
|
|
33
|
+
files_failed INTEGER NOT NULL DEFAULT 0,
|
|
34
|
+
files_skipped INTEGER NOT NULL DEFAULT 0
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
-- One row per .eml file. Path is relative to the run root so a corpus can be moved.
|
|
38
|
+
CREATE TABLE files (
|
|
39
|
+
path TEXT PRIMARY KEY,
|
|
40
|
+
size INTEGER NOT NULL,
|
|
41
|
+
mtime INTEGER NOT NULL,
|
|
42
|
+
sha256 TEXT,
|
|
43
|
+
status TEXT NOT NULL,
|
|
44
|
+
error_code TEXT,
|
|
45
|
+
error_detail TEXT,
|
|
46
|
+
duration_ms INTEGER,
|
|
47
|
+
scanned_at INTEGER NOT NULL,
|
|
48
|
+
run_id INTEGER,
|
|
49
|
+
processing_version TEXT NOT NULL
|
|
50
|
+
);
|
|
51
|
+
CREATE INDEX files_sha256 ON files(sha256);
|
|
52
|
+
CREATE INDEX files_status ON files(status);
|
|
53
|
+
|
|
54
|
+
-- Derived, privacy safe metadata. No subjects, no addresses, no body text.
|
|
55
|
+
CREATE TABLE messages (
|
|
56
|
+
path TEXT PRIMARY KEY REFERENCES files(path) ON DELETE CASCADE,
|
|
57
|
+
message_id TEXT,
|
|
58
|
+
in_reply_to TEXT,
|
|
59
|
+
references_count INTEGER NOT NULL DEFAULT 0,
|
|
60
|
+
references_root TEXT,
|
|
61
|
+
date_ms INTEGER,
|
|
62
|
+
from_domain TEXT,
|
|
63
|
+
from_hash TEXT,
|
|
64
|
+
subject_hash TEXT,
|
|
65
|
+
subject_prefix TEXT,
|
|
66
|
+
subject_length INTEGER NOT NULL DEFAULT 0,
|
|
67
|
+
structure TEXT,
|
|
68
|
+
body_kind TEXT,
|
|
69
|
+
charsets TEXT,
|
|
70
|
+
encodings TEXT,
|
|
71
|
+
part_count INTEGER NOT NULL DEFAULT 0,
|
|
72
|
+
attachment_count INTEGER NOT NULL DEFAULT 0,
|
|
73
|
+
has_rfc822 INTEGER NOT NULL DEFAULT 0,
|
|
74
|
+
text_chars INTEGER NOT NULL DEFAULT 0,
|
|
75
|
+
html_chars INTEGER NOT NULL DEFAULT 0,
|
|
76
|
+
flowed INTEGER NOT NULL DEFAULT 0,
|
|
77
|
+
client TEXT,
|
|
78
|
+
client_source TEXT,
|
|
79
|
+
traffic TEXT,
|
|
80
|
+
traffic_signals TEXT,
|
|
81
|
+
is_reply INTEGER NOT NULL DEFAULT 0,
|
|
82
|
+
is_forward INTEGER NOT NULL DEFAULT 0,
|
|
83
|
+
quote_depth_max INTEGER NOT NULL DEFAULT 0,
|
|
84
|
+
quoted_ratio REAL NOT NULL DEFAULT 0,
|
|
85
|
+
reply_style TEXT,
|
|
86
|
+
markers TEXT,
|
|
87
|
+
html_hints TEXT,
|
|
88
|
+
blockquote_count INTEGER NOT NULL DEFAULT 0,
|
|
89
|
+
table_count INTEGER NOT NULL DEFAULT 0,
|
|
90
|
+
has_image INTEGER NOT NULL DEFAULT 0,
|
|
91
|
+
suspect_malformed_html INTEGER NOT NULL DEFAULT 0,
|
|
92
|
+
lang TEXT,
|
|
93
|
+
lang_score REAL NOT NULL DEFAULT 0,
|
|
94
|
+
body_simhash TEXT,
|
|
95
|
+
warnings TEXT,
|
|
96
|
+
quote_marking_disagrees INTEGER NOT NULL DEFAULT 0
|
|
97
|
+
);
|
|
98
|
+
CREATE INDEX messages_message_id ON messages(message_id);
|
|
99
|
+
CREATE INDEX messages_in_reply_to ON messages(in_reply_to);
|
|
100
|
+
CREATE INDEX messages_client ON messages(client);
|
|
101
|
+
CREATE INDEX messages_traffic ON messages(traffic);
|
|
102
|
+
CREATE INDEX messages_simhash ON messages(body_simhash);
|
|
103
|
+
CREATE INDEX messages_subject ON messages(subject_hash);
|
|
104
|
+
`
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
version: 2,
|
|
108
|
+
name: 'annotations',
|
|
109
|
+
sql: `
|
|
110
|
+
-- One row per annotation pass over a set of messages, so that labels can always be attributed to
|
|
111
|
+
-- a labeller, a model and a prompt version.
|
|
112
|
+
CREATE TABLE annotation_runs (
|
|
113
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
114
|
+
source TEXT NOT NULL, -- 'llm' | 'human' | 'weak' | 'distant'
|
|
115
|
+
model TEXT, -- model id for 'llm'
|
|
116
|
+
prompt_version TEXT,
|
|
117
|
+
extractor_version TEXT NOT NULL,
|
|
118
|
+
started_at INTEGER NOT NULL,
|
|
119
|
+
finished_at INTEGER,
|
|
120
|
+
messages INTEGER NOT NULL DEFAULT 0,
|
|
121
|
+
blocks INTEGER NOT NULL DEFAULT 0,
|
|
122
|
+
failures INTEGER NOT NULL DEFAULT 0,
|
|
123
|
+
prompt_tokens INTEGER NOT NULL DEFAULT 0,
|
|
124
|
+
completion_tokens INTEGER NOT NULL DEFAULT 0,
|
|
125
|
+
notes TEXT
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
-- Block level labels. Deliberately not unique on (path, block_index): the same block may be
|
|
129
|
+
-- labelled by several sources, and comparing them is the point.
|
|
130
|
+
CREATE TABLE annotations (
|
|
131
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
132
|
+
run_id INTEGER NOT NULL REFERENCES annotation_runs(id) ON DELETE CASCADE,
|
|
133
|
+
path TEXT NOT NULL,
|
|
134
|
+
representation TEXT NOT NULL,
|
|
135
|
+
block_index INTEGER NOT NULL,
|
|
136
|
+
mime_part TEXT,
|
|
137
|
+
block_start INTEGER,
|
|
138
|
+
block_end INTEGER,
|
|
139
|
+
char_count INTEGER NOT NULL DEFAULT 0,
|
|
140
|
+
source TEXT NOT NULL,
|
|
141
|
+
label TEXT NOT NULL,
|
|
142
|
+
confidence REAL NOT NULL DEFAULT 0,
|
|
143
|
+
-- What the deterministic baseline said about the same block, captured at annotation time so a
|
|
144
|
+
-- later rule change cannot silently rewrite history.
|
|
145
|
+
baseline_label TEXT,
|
|
146
|
+
baseline_conf REAL,
|
|
147
|
+
baseline_reasons TEXT,
|
|
148
|
+
agrees INTEGER NOT NULL DEFAULT 0,
|
|
149
|
+
notes TEXT
|
|
150
|
+
);
|
|
151
|
+
CREATE INDEX annotations_path ON annotations(path);
|
|
152
|
+
CREATE INDEX annotations_run ON annotations(run_id);
|
|
153
|
+
CREATE INDEX annotations_source ON annotations(source);
|
|
154
|
+
CREATE INDEX annotations_agree ON annotations(agrees);
|
|
155
|
+
`
|
|
156
|
+
}
|
|
157
|
+
];
|
|
158
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/corpus/migrations/index.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAQU,QAAA,UAAU,GAAyB;IAC5C;QACI,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,aAAa;QACnB,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyFZ;KACI;IACD;QACI,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,aAAa;QACnB,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CZ;KACI;CACJ,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stratified sampling over the corpus.
|
|
3
|
+
*
|
|
4
|
+
* Uniform random sampling of this corpus would produce a set that is almost entirely Gmail top
|
|
5
|
+
* posts in English, because that is what the corpus mostly is. The structures that actually break
|
|
6
|
+
* an extractor, interleaved replies, Outlook's unmarked history, malformed HTML, plain text only
|
|
7
|
+
* mail, are each a percent or two, and a random sample of a few hundred messages would contain a
|
|
8
|
+
* handful of each at best.
|
|
9
|
+
*
|
|
10
|
+
* So strata are defined by the structural properties that change how extraction behaves, each gets
|
|
11
|
+
* a quota, and a random control slice is included alongside so that unbiased numbers remain
|
|
12
|
+
* available. Selection within a stratum is deterministic: the same seed always picks the same
|
|
13
|
+
* messages, regardless of database order.
|
|
14
|
+
*/
|
|
15
|
+
import { type CorpusStore } from './store';
|
|
16
|
+
export interface Stratum {
|
|
17
|
+
id: string;
|
|
18
|
+
/** SQL predicate over the messages table, aliased m, joined to files as f. */
|
|
19
|
+
predicate: string;
|
|
20
|
+
/** Share of the total sample to allocate. Normalised across strata. */
|
|
21
|
+
weight: number;
|
|
22
|
+
description: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The strata that matter, with the reason each one exists.
|
|
26
|
+
*
|
|
27
|
+
* Weights are not proportional to prevalence. They are proportional to how much is learned per
|
|
28
|
+
* message, which for a rare structure is a great deal more.
|
|
29
|
+
*/
|
|
30
|
+
export declare const DEFAULT_STRATA: readonly Stratum[];
|
|
31
|
+
export interface SampleOptions {
|
|
32
|
+
/** Total messages wanted. */
|
|
33
|
+
count: number;
|
|
34
|
+
seed: string;
|
|
35
|
+
/** Restrict to a traffic class, or 'all'. */
|
|
36
|
+
traffic?: string;
|
|
37
|
+
/** Only messages that look like replies. */
|
|
38
|
+
repliesOnly?: boolean;
|
|
39
|
+
/** Exclude these paths, for example ones already annotated. */
|
|
40
|
+
exclude?: ReadonlySet<string>;
|
|
41
|
+
strata?: readonly Stratum[];
|
|
42
|
+
}
|
|
43
|
+
export interface SampleRow {
|
|
44
|
+
path: string;
|
|
45
|
+
stratum: string;
|
|
46
|
+
}
|
|
47
|
+
export interface SampleResult {
|
|
48
|
+
rows: SampleRow[];
|
|
49
|
+
/** How many were taken from each stratum, and how many were available. */
|
|
50
|
+
coverage: {
|
|
51
|
+
id: string;
|
|
52
|
+
requested: number;
|
|
53
|
+
taken: number;
|
|
54
|
+
available: number;
|
|
55
|
+
description: string;
|
|
56
|
+
}[];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Draw a stratified sample.
|
|
60
|
+
*
|
|
61
|
+
* Strata overlap by design: a message can be an Outlook interleaved reply in Estonian. It is
|
|
62
|
+
* assigned to the first stratum that claims it, so the rarer strata listed earlier fill first, and
|
|
63
|
+
* no message appears twice.
|
|
64
|
+
*/
|
|
65
|
+
export declare function stratifiedSample(store: CorpusStore, options: SampleOptions): SampleResult;
|
|
66
|
+
//# sourceMappingURL=sample.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample.d.ts","sourceRoot":"","sources":["../../src/corpus/sample.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,MAAM,WAAW,OAAO;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,OAAO,EAyB5C,CAAC;AAEF,MAAM,WAAW,aAAa;IAC1B,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACxG;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GAAG,YAAY,CA+CzF"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Stratified sampling over the corpus.
|
|
4
|
+
*
|
|
5
|
+
* Uniform random sampling of this corpus would produce a set that is almost entirely Gmail top
|
|
6
|
+
* posts in English, because that is what the corpus mostly is. The structures that actually break
|
|
7
|
+
* an extractor, interleaved replies, Outlook's unmarked history, malformed HTML, plain text only
|
|
8
|
+
* mail, are each a percent or two, and a random sample of a few hundred messages would contain a
|
|
9
|
+
* handful of each at best.
|
|
10
|
+
*
|
|
11
|
+
* So strata are defined by the structural properties that change how extraction behaves, each gets
|
|
12
|
+
* a quota, and a random control slice is included alongside so that unbiased numbers remain
|
|
13
|
+
* available. Selection within a stratum is deterministic: the same seed always picks the same
|
|
14
|
+
* messages, regardless of database order.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.DEFAULT_STRATA = void 0;
|
|
18
|
+
exports.stratifiedSample = stratifiedSample;
|
|
19
|
+
const hash_1 = require("../util/hash");
|
|
20
|
+
/**
|
|
21
|
+
* The strata that matter, with the reason each one exists.
|
|
22
|
+
*
|
|
23
|
+
* Weights are not proportional to prevalence. They are proportional to how much is learned per
|
|
24
|
+
* message, which for a rare structure is a great deal more.
|
|
25
|
+
*/
|
|
26
|
+
exports.DEFAULT_STRATA = [
|
|
27
|
+
{ id: 'interleaved', predicate: "m.reply_style = 'interleaved'", weight: 3, description: 'inline question and answer, the highest cost failure mode' },
|
|
28
|
+
{ id: 'bottom-post', predicate: "m.reply_style = 'bottom'", weight: 2, description: 'answer below the quote' },
|
|
29
|
+
{ id: 'top-and-trailing', predicate: "m.reply_style = 'top-and-trailing'", weight: 2, description: 'top post with something after the quote' },
|
|
30
|
+
{ id: 'plain-only', predicate: "m.body_kind = 'plain-only'", weight: 2, description: 'no HTML to fall back on' },
|
|
31
|
+
{ id: 'html-only', predicate: "m.body_kind = 'html-only'", weight: 2, description: 'no plain text to fall back on' },
|
|
32
|
+
{ id: 'representations-disagree', predicate: 'm.quote_marking_disagrees = 1', weight: 2, description: 'plain and HTML tell different stories' },
|
|
33
|
+
{
|
|
34
|
+
id: 'outlook',
|
|
35
|
+
predicate: "m.client IN ('outlook-desktop', 'outlook-web', 'outlook-mobile')",
|
|
36
|
+
weight: 3,
|
|
37
|
+
description: 'unmarked history, separators, nested x_ classes'
|
|
38
|
+
},
|
|
39
|
+
{ id: 'gmail', predicate: "m.client = 'gmail'", weight: 2, description: 'the most common client' },
|
|
40
|
+
{ id: 'apple-mail', predicate: "m.client IN ('apple-mail', 'apple-mail-mobile')", weight: 2, description: 'blockquote type=cite' },
|
|
41
|
+
{ id: 'thunderbird', predicate: "m.client = 'thunderbird'", weight: 2, description: 'moz-cite-prefix' },
|
|
42
|
+
{ id: 'unknown-client', predicate: "m.client = 'unknown'", weight: 2, description: 'no client fingerprint at all' },
|
|
43
|
+
{ id: 'deep-quote', predicate: 'm.quote_depth_max >= 3', weight: 2, description: 'deeply nested threads' },
|
|
44
|
+
{ id: 'forwarded', predicate: 'm.is_forward = 1', weight: 2, description: 'forwarded content must never be lost' },
|
|
45
|
+
{ id: 'tables', predicate: 'm.table_count > 2', weight: 1, description: 'table heavy layout' },
|
|
46
|
+
{ id: 'malformed-html', predicate: 'm.suspect_malformed_html = 1', weight: 1, description: 'markup that needs a forgiving parser' },
|
|
47
|
+
{ id: 'legacy-charset', predicate: "m.charsets NOT LIKE '%utf-8%' AND m.charsets != ''", weight: 1, description: 'legacy charset decoding' },
|
|
48
|
+
{ id: 'non-english', predicate: "m.lang NOT IN ('en', 'unknown')", weight: 2, description: 'multilingual attribution lines' },
|
|
49
|
+
{ id: 'has-warnings', predicate: "m.warnings != ''", weight: 1, description: 'messages the parser complained about' },
|
|
50
|
+
{ id: 'random-control', predicate: '1 = 1', weight: 4, description: 'unbiased slice for honest aggregate numbers' }
|
|
51
|
+
];
|
|
52
|
+
/**
|
|
53
|
+
* Draw a stratified sample.
|
|
54
|
+
*
|
|
55
|
+
* Strata overlap by design: a message can be an Outlook interleaved reply in Estonian. It is
|
|
56
|
+
* assigned to the first stratum that claims it, so the rarer strata listed earlier fill first, and
|
|
57
|
+
* no message appears twice.
|
|
58
|
+
*/
|
|
59
|
+
function stratifiedSample(store, options) {
|
|
60
|
+
const strata = options.strata ?? exports.DEFAULT_STRATA;
|
|
61
|
+
const exclude = options.exclude ?? new Set();
|
|
62
|
+
const totalWeight = strata.reduce((sum, stratum) => sum + stratum.weight, 0);
|
|
63
|
+
const base = ["f.status = 'ok'"];
|
|
64
|
+
if (options.traffic && options.traffic !== 'all') {
|
|
65
|
+
base.push(`m.traffic = '${options.traffic.replace(/'/g, '')}'`);
|
|
66
|
+
}
|
|
67
|
+
if (options.repliesOnly !== false) {
|
|
68
|
+
base.push('m.is_reply = 1');
|
|
69
|
+
}
|
|
70
|
+
const chosen = new Set();
|
|
71
|
+
const rows = [];
|
|
72
|
+
const coverage = [];
|
|
73
|
+
for (const stratum of strata) {
|
|
74
|
+
const quota = Math.max(1, Math.round((options.count * stratum.weight) / totalWeight));
|
|
75
|
+
const candidates = store
|
|
76
|
+
.query(`SELECT m.path AS path FROM messages m JOIN files f ON f.path = m.path WHERE ${[...base, stratum.predicate].join(' AND ')}`)
|
|
77
|
+
.map(row => row.path)
|
|
78
|
+
.filter(path => !exclude.has(path) && !chosen.has(path));
|
|
79
|
+
// Deterministic: hash each path with the seed and take the lowest values.
|
|
80
|
+
const ranked = candidates
|
|
81
|
+
.map(path => ({ path, score: (0, hash_1.deterministicUnit)(`${options.seed}:${stratum.id}`, path) }))
|
|
82
|
+
.sort((a, b) => a.score - b.score)
|
|
83
|
+
.slice(0, quota);
|
|
84
|
+
for (const item of ranked) {
|
|
85
|
+
chosen.add(item.path);
|
|
86
|
+
rows.push({ path: item.path, stratum: stratum.id });
|
|
87
|
+
}
|
|
88
|
+
coverage.push({
|
|
89
|
+
id: stratum.id,
|
|
90
|
+
requested: quota,
|
|
91
|
+
taken: ranked.length,
|
|
92
|
+
available: candidates.length,
|
|
93
|
+
description: stratum.description
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return { rows, coverage };
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=sample.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample.js","sourceRoot":"","sources":["../../src/corpus/sample.ts"],"names":[],"mappings":"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"}
|