@polycode-projects/the-mechanical-code-talker 0.2.0 → 0.3.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,89 @@
1
+ #!/usr/bin/env node
2
+ // filter-dump.mjs — regenerate corpus/conceptnet/slice.jsonl from a ConceptNet
3
+ // ASSERTIONS DUMP instead of the API (the route actually used for the
4
+ // committed slice: api.conceptnet.io was hard-down, 502, on 2026-07-04).
5
+ // NOT part of the product path — a maintainer tool.
6
+ //
7
+ // curl -s https://s3.amazonaws.com/conceptnet/downloads/2019/edges/conceptnet-assertions-5.7.0.csv.gz \
8
+ // | gunzip -c \
9
+ // | node corpus/conceptnet/filter-dump.mjs > corpus/conceptnet/slice.jsonl
10
+ //
11
+ // Input: the tab-separated 5.7.0 dump on stdin —
12
+ // assertionURI \t rel \t start \t end \t {json: weight, surfaceText, …}
13
+ //
14
+ // Filter rules (shared with fetch-slice.mjs; also in README.md):
15
+ // - start AND end are English concepts (/c/en/…), sense tags stripped
16
+ // (/c/en/dog/n → /c/en/dog);
17
+ // - rel is one of the 34 canonical relations, minus the policy-filtered
18
+ // etymology/ExternalURL ones;
19
+ // - at least ONE endpoint's bare term is in the ~90-term tech seed list
20
+ // (fetch-slice.mjs SEED_TERMS);
21
+ // - dedupe by (start, rel, end), keeping the higher weight;
22
+ // - budget (~1.4 MB of JSONL), TWO-TIER: assertions whose relation MAPS to
23
+ // an ACE-OWL pattern (conceptnet-map.toml, ace != "none") are kept first
24
+ // (weight-descending); ace="none" relations (RelatedTo, Synonym, …) fill
25
+ // whatever budget remains — they never crowd out seedable facts;
26
+ // - final order (rel, start, end) for deterministic diffs.
27
+ // Stats land on stderr; the JSONL lands on stdout.
28
+
29
+ import { createInterface } from "node:readline";
30
+ import { SEED_TERMS, CANONICAL_RELS, FILTERED_RELS, bareEnTerm } from "./fetch-slice.mjs";
31
+ import { loadMap } from "../../src/corpus/conceptnet.mjs";
32
+
33
+ const MAX_BYTES = 1_400_000; // committed-slice budget (hard cap 1.5 MB)
34
+ const SEEDS = new Set(SEED_TERMS);
35
+ const termOf = (uri) => uri.slice("/c/en/".length);
36
+
37
+ const byKey = new Map(); // "start rel end" -> row
38
+ let scanned = 0;
39
+ const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
40
+ for await (const line of rl) {
41
+ scanned += 1;
42
+ const cols = line.split("\t");
43
+ if (cols.length < 5) continue;
44
+ const rel = cols[1];
45
+ if (!CANONICAL_RELS.has(rel) || FILTERED_RELS.has(rel)) continue;
46
+ const start = bareEnTerm(cols[2]);
47
+ const end = bareEnTerm(cols[3]);
48
+ if (!start || !end || start === end) continue;
49
+ if (!SEEDS.has(termOf(start)) && !SEEDS.has(termOf(end))) continue;
50
+ let info = {};
51
+ try {
52
+ info = JSON.parse(cols[4]);
53
+ } catch {
54
+ /* a malformed info column loses us weight/surfaceText, not the edge */
55
+ }
56
+ const row = { start, rel, end, weight: Number(info.weight) || 1 };
57
+ if (info.surfaceText) row.surfaceText = String(info.surfaceText);
58
+ const key = `${start} ${rel} ${end}`;
59
+ const prev = byKey.get(key);
60
+ if (!prev || row.weight > prev.weight) byKey.set(key, row);
61
+ }
62
+
63
+ // budget-trim: mappable relations first, then none-rows — each tier
64
+ // weight-descending, so the strongest seedable facts always survive
65
+ const map = await loadMap();
66
+ const byWeight = (a, b) =>
67
+ b.weight - a.weight || a.rel.localeCompare(b.rel) || a.start.localeCompare(b.start) || a.end.localeCompare(b.end);
68
+ const all = [...byKey.values()];
69
+ const mappable = all.filter((r) => map.get(r.rel)?.ace !== "none").sort(byWeight);
70
+ const unmappable = all.filter((r) => map.get(r.rel)?.ace === "none").sort(byWeight);
71
+ const kept = [];
72
+ let bytes = 0;
73
+ for (const row of [...mappable, ...unmappable]) {
74
+ const line = JSON.stringify(row) + "\n";
75
+ if (bytes + line.length > MAX_BYTES) continue;
76
+ bytes += line.length;
77
+ kept.push(row);
78
+ }
79
+ kept.sort((a, b) => a.rel.localeCompare(b.rel) || a.start.localeCompare(b.start) || a.end.localeCompare(b.end));
80
+
81
+ for (const row of kept) process.stdout.write(JSON.stringify(row) + "\n");
82
+
83
+ const perRel = new Map();
84
+ for (const r of kept) perRel.set(r.rel, (perRel.get(r.rel) || 0) + 1);
85
+ const keptMappable = kept.filter((r) => map.get(r.rel)?.ace !== "none").length;
86
+ console.error(`scanned ${scanned} dump lines; matched ${all.length} unique en→en seed assertions `
87
+ + `(${mappable.length} mappable + ${unmappable.length} ace=none); `
88
+ + `kept ${kept.length} (${keptMappable} mappable + ${kept.length - keptMappable} none) in ${bytes} bytes`);
89
+ for (const [rel, n] of [...perRel.entries()].sort((a, b) => b[1] - a[1])) console.error(` ${rel}: ${n}`);