@polycode-projects/the-mechanical-code-talker 0.4.0 → 0.6.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,253 @@
1
+ #!/usr/bin/env node
2
+ // corpus/tier2/generate.mjs — the TIER-2 specialised-corpus generator + manifest
3
+ // writer. NOT part of the product path — a maintainer tool. Offline, $0.
4
+ //
5
+ // Tier-2 corpuses are LANGUAGE- or DOMAIN-specific fact sets (aws, python,
6
+ // java, …) that tmct fetches/generates into `.tmct/` at init time so it can
7
+ // "expand into a concept for an applicable codebase". They are NOT shipped in
8
+ // the npm package the way the tier-1 ConceptNet slice is — they are opt-in,
9
+ // selected per repo. See ../README.md for the full tier-1/2/3 policy.
10
+ //
11
+ // Every tier-2 corpus is written in the EXACT tier-1 fact shape
12
+ // (corpus/conceptnet/slice.jsonl): one JSON object per line,
13
+ // {"start":"/c/en/<term>","rel":"/r/<Rel>","end":"/c/en/<concept>","weight":N,"surfaceText":"…"}
14
+ // with `rel` drawn ONLY from the mapped relations in
15
+ // src/corpus/conceptnet-map.toml, so a tier-2 file loads through the very same
16
+ // loadSlice()/toFacts() path as the tier-1 slice (this file's --verify proves
17
+ // it). The Wave-2 tier-2 SEEDER (see ../README.md) is what stamps the right
18
+ // provenance (`corpus:tier2:<id> /r/…`) instead of the conceptnet default.
19
+ //
20
+ // node corpus/tier2/generate.mjs # (re)write every <id>.jsonl + manifest.json
21
+ // node corpus/tier2/generate.mjs --verify # generate + assert each file loads & seeds cleanly
22
+ //
23
+ // To ADD a specialised corpus: add an entry to CORPUSES below (a list of
24
+ // [subject, relation, concept] triples, optionally [.., surfaceText]) and
25
+ // re-run. Curated sets are authored here so they stay reviewable and diffable;
26
+ // a corpus too large to curate by hand is a `fetch` manifest entry instead
27
+ // (network, opt-in — see fetchCorpus() and ../README.md).
28
+
29
+ import { readFile, writeFile } from "node:fs/promises";
30
+ import { createHash } from "node:crypto";
31
+ import { fileURLToPath } from "node:url";
32
+ import { dirname, join } from "node:path";
33
+
34
+ const HERE = dirname(fileURLToPath(import.meta.url));
35
+
36
+ // A curated triple is [subject, rel, concept] or [subject, rel, concept, weight].
37
+ // `rel` MUST be a mapped (ace != "none") relation in conceptnet-map.toml so the
38
+ // fact actually seeds. Terms are lowercase snake_case; the loader's termText()
39
+ // turns "/c/en/hash_table" into "hash table". Keep terms <= 3 words (the tier-1
40
+ // quality-filter rule) — curated data is clean by construction.
41
+ export const CORPUSES = {
42
+ aws: {
43
+ kind: "domain",
44
+ description: "Amazon Web Services core services and primitives (S3, Lambda, DynamoDB, EC2, IAM, SQS) mapped to general cloud/CS concepts.",
45
+ facts: [
46
+ ["aws", "/r/IsA", "cloud_platform"],
47
+ ["aws", "/r/IsA", "cloud"],
48
+ ["aws", "/r/CapableOf", "host_applications"],
49
+ // S3
50
+ ["s3", "/r/IsA", "object_storage"],
51
+ ["s3", "/r/IsA", "storage_service"],
52
+ ["s3", "/r/PartOf", "aws"],
53
+ ["s3", "/r/HasA", "bucket"],
54
+ ["s3", "/r/UsedFor", "storing_files"],
55
+ ["s3", "/r/CapableOf", "store_objects"],
56
+ ["bucket", "/r/IsA", "container"],
57
+ ["bucket", "/r/PartOf", "s3"],
58
+ ["bucket", "/r/UsedFor", "storing_objects"],
59
+ // Lambda
60
+ ["lambda", "/r/IsA", "compute_service"],
61
+ ["lambda", "/r/IsA", "function"],
62
+ ["lambda", "/r/PartOf", "aws"],
63
+ ["lambda", "/r/UsedFor", "running_code"],
64
+ ["lambda", "/r/CapableOf", "run_code"],
65
+ ["lambda", "/r/HasProperty", "serverless"],
66
+ // DynamoDB
67
+ ["dynamodb", "/r/IsA", "database"],
68
+ ["dynamodb", "/r/IsA", "nosql_database"],
69
+ ["dynamodb", "/r/PartOf", "aws"],
70
+ ["dynamodb", "/r/HasA", "table"],
71
+ ["dynamodb", "/r/UsedFor", "storing_data"],
72
+ ["dynamodb", "/r/HasProperty", "managed"],
73
+ // EC2
74
+ ["ec2", "/r/IsA", "compute_service"],
75
+ ["ec2", "/r/IsA", "virtual_machine"],
76
+ ["ec2", "/r/PartOf", "aws"],
77
+ ["ec2", "/r/HasA", "instance"],
78
+ ["ec2", "/r/UsedFor", "running_servers"],
79
+ // IAM
80
+ ["iam", "/r/IsA", "access_control"],
81
+ ["iam", "/r/PartOf", "aws"],
82
+ ["iam", "/r/UsedFor", "managing_permissions"],
83
+ ["iam", "/r/HasA", "role"],
84
+ ["iam", "/r/HasA", "policy"],
85
+ // SQS + queue
86
+ ["sqs", "/r/IsA", "message_queue"],
87
+ ["sqs", "/r/IsA", "queue"],
88
+ ["sqs", "/r/PartOf", "aws"],
89
+ ["sqs", "/r/UsedFor", "decoupling_services"],
90
+ ["queue", "/r/IsA", "data_structure"],
91
+ ],
92
+ },
93
+
94
+ python: {
95
+ kind: "language",
96
+ description: "Python language constructs and stdlib types mapped to the shared CS concept vocabulary (list->array, dict->hash table, …).",
97
+ facts: [
98
+ ["python", "/r/IsA", "programming_language"],
99
+ ["python", "/r/HasProperty", "interpreted"],
100
+ ["python", "/r/HasProperty", "dynamically_typed"],
101
+ ["python", "/r/UsedFor", "scripting"],
102
+ // built-in types → shared concepts
103
+ ["list", "/r/IsA", "array"],
104
+ ["list", "/r/IsA", "sequence"],
105
+ ["list", "/r/IsA", "data_structure"],
106
+ ["dict", "/r/IsA", "hash_table"],
107
+ ["dict", "/r/IsA", "dictionary"],
108
+ ["dict", "/r/IsA", "mapping"],
109
+ ["tuple", "/r/IsA", "sequence"],
110
+ ["tuple", "/r/HasProperty", "immutable"],
111
+ ["set", "/r/IsA", "collection"],
112
+ ["set", "/r/HasProperty", "unordered"],
113
+ ["str", "/r/IsA", "string"],
114
+ // language constructs
115
+ ["decorator", "/r/IsA", "function"],
116
+ ["decorator", "/r/UsedFor", "modifying_functions"],
117
+ ["generator", "/r/IsA", "iterator"],
118
+ ["generator", "/r/UsedFor", "lazy_evaluation"],
119
+ ["comprehension", "/r/IsA", "expression"],
120
+ ["comprehension", "/r/UsedFor", "building_collections"],
121
+ ["exception", "/r/IsA", "error"],
122
+ ["module", "/r/IsA", "file"],
123
+ ["package", "/r/IsA", "module"],
124
+ ["method", "/r/IsA", "function"],
125
+ // tooling / runtime
126
+ ["pip", "/r/IsA", "package_manager"],
127
+ ["pip", "/r/UsedFor", "installing_packages"],
128
+ ["gil", "/r/IsA", "lock"],
129
+ ["gil", "/r/PartOf", "interpreter"],
130
+ ["cpython", "/r/IsA", "interpreter"],
131
+ ],
132
+ },
133
+
134
+ java: {
135
+ kind: "language",
136
+ description: "Java language and JVM constructs mapped to the shared CS concept vocabulary (ArrayList->list, HashMap->hash table, …).",
137
+ facts: [
138
+ ["java", "/r/IsA", "programming_language"],
139
+ ["java", "/r/HasProperty", "compiled"],
140
+ ["java", "/r/HasProperty", "statically_typed"],
141
+ ["java", "/r/UsedFor", "building_applications"],
142
+ // types → shared concepts
143
+ ["arraylist", "/r/IsA", "list"],
144
+ ["arraylist", "/r/IsA", "data_structure"],
145
+ ["hashmap", "/r/IsA", "hash_table"],
146
+ ["hashmap", "/r/IsA", "dictionary"],
147
+ ["hashmap", "/r/IsA", "map"],
148
+ ["interface", "/r/IsA", "type"],
149
+ ["interface", "/r/IsA", "contract"],
150
+ ["class", "/r/IsA", "type"],
151
+ ["object", "/r/IsA", "instance"],
152
+ // JVM / runtime
153
+ ["jvm", "/r/IsA", "virtual_machine"],
154
+ ["jvm", "/r/UsedFor", "running_bytecode"],
155
+ ["jvm", "/r/CapableOf", "execute_bytecode"],
156
+ ["bytecode", "/r/IsA", "code"],
157
+ ["garbage_collector", "/r/PartOf", "jvm"],
158
+ ["garbage_collector", "/r/UsedFor", "freeing_memory"],
159
+ // packaging / tooling
160
+ ["jar", "/r/IsA", "archive"],
161
+ ["jar", "/r/IsA", "file"],
162
+ ["jar", "/r/UsedFor", "packaging_classes"],
163
+ ["maven", "/r/IsA", "build_tool"],
164
+ ["maven", "/r/IsA", "package_manager"],
165
+ ["gradle", "/r/IsA", "build_tool"],
166
+ // language features
167
+ ["thread", "/r/IsA", "process"],
168
+ ["thread", "/r/UsedFor", "concurrency"],
169
+ ["generics", "/r/UsedFor", "type_safety"],
170
+ ["annotation", "/r/IsA", "metadata"],
171
+ ["exception", "/r/IsA", "error"],
172
+ ["method", "/r/IsA", "function"],
173
+ ],
174
+ },
175
+ };
176
+
177
+ const conceptUri = (term) => `/c/en/${term}`;
178
+ const humanize = (term) => term.replace(/_/g, " ");
179
+
180
+ /** One curated triple → a tier-1-shaped slice row. */
181
+ export function toRow([subject, rel, concept, weight = 1]) {
182
+ return {
183
+ start: conceptUri(subject),
184
+ rel,
185
+ end: conceptUri(concept),
186
+ weight,
187
+ surfaceText: `[[${humanize(subject)}]] ${rel.replace("/r/", "")} [[${humanize(concept)}]]`,
188
+ };
189
+ }
190
+
191
+ /** Curated corpus id → its JSONL text (deterministic order = authored order). */
192
+ export function corpusJsonl(id) {
193
+ return CORPUSES[id].facts.map((f) => JSON.stringify(toRow(f))).join("\n") + "\n";
194
+ }
195
+
196
+ const sha256 = (text) => createHash("sha256").update(text).digest("hex");
197
+
198
+ // ---- network-fetch path (opt-in, offline-by-default) -----------------------
199
+ // A tier-2 corpus too large to curate by hand is declared in the manifest with
200
+ // { "source": { "kind": "fetch", "url": "...", "sha256": "..." } } and pulled by
201
+ // a Wave-2 fetch step. This helper is the reference implementation — it is NEVER
202
+ // called without an explicit --allow-network flag (the product default is $0,
203
+ // offline). No sample corpus uses it; the three samples are all `curated`.
204
+ export async function fetchCorpus(url, expectedSha) {
205
+ const res = await fetch(url, { headers: { accept: "application/x-ndjson,application/jsonl" } });
206
+ if (!res.ok) throw new Error(`fetch ${url}: HTTP ${res.status}`);
207
+ const text = await res.text();
208
+ const got = sha256(text);
209
+ if (expectedSha && got !== expectedSha) throw new Error(`checksum mismatch for ${url}: ${got} != ${expectedSha}`);
210
+ return text;
211
+ }
212
+
213
+ async function main() {
214
+ const verify = process.argv.includes("--verify");
215
+ const manifest = { version: 1, generated: "by corpus/tier2/generate.mjs", corpuses: [] };
216
+
217
+ for (const [id, spec] of Object.entries(CORPUSES)) {
218
+ const text = corpusJsonl(id);
219
+ await writeFile(join(HERE, `${id}.jsonl`), text);
220
+ manifest.corpuses.push({
221
+ id,
222
+ kind: spec.kind,
223
+ description: spec.description,
224
+ source: { kind: "curated", tool: "corpus/tier2/generate.mjs" },
225
+ file: `${id}.jsonl`,
226
+ facts: spec.facts.length,
227
+ bytes: Buffer.byteLength(text),
228
+ sha256: sha256(text),
229
+ license: "MPL-2.0",
230
+ });
231
+ console.error(` ${id}: ${spec.facts.length} facts, ${Buffer.byteLength(text)} bytes`);
232
+ }
233
+
234
+ const manifestText = JSON.stringify(manifest, null, 2) + "\n";
235
+ await writeFile(join(HERE, "manifest.json"), manifestText);
236
+ console.error(`wrote manifest.json (${manifest.corpuses.length} corpuses)`);
237
+
238
+ if (verify) {
239
+ const { loadSlice, loadMap, toFacts } = await import("../../src/corpus/conceptnet.mjs");
240
+ const map = await loadMap();
241
+ for (const c of manifest.corpuses) {
242
+ const assertions = await loadSlice(join(HERE, c.file));
243
+ const facts = toFacts(assertions, map); // throws on any unmapped rel
244
+ if (assertions.length !== c.facts) throw new Error(`${c.id}: loadSlice count ${assertions.length} != ${c.facts}`);
245
+ if (facts.length !== c.facts) throw new Error(`${c.id}: ${c.facts - facts.length} fact(s) did not seed (ace=none rel?)`);
246
+ console.error(` verify ${c.id}: ${assertions.length} assertions load, all ${facts.length} seed cleanly`);
247
+ }
248
+ console.error("verify: OK — every tier-2 corpus loads and seeds through the tier-1 path");
249
+ }
250
+ }
251
+
252
+ const isMain = process.argv[1] && import.meta.url === new URL(`file://${process.argv[1]}`).href;
253
+ if (isMain) await main();
@@ -0,0 +1,31 @@
1
+ {"start":"/c/en/java","rel":"/r/IsA","end":"/c/en/programming_language","weight":1,"surfaceText":"[[java]] IsA [[programming language]]"}
2
+ {"start":"/c/en/java","rel":"/r/HasProperty","end":"/c/en/compiled","weight":1,"surfaceText":"[[java]] HasProperty [[compiled]]"}
3
+ {"start":"/c/en/java","rel":"/r/HasProperty","end":"/c/en/statically_typed","weight":1,"surfaceText":"[[java]] HasProperty [[statically typed]]"}
4
+ {"start":"/c/en/java","rel":"/r/UsedFor","end":"/c/en/building_applications","weight":1,"surfaceText":"[[java]] UsedFor [[building applications]]"}
5
+ {"start":"/c/en/arraylist","rel":"/r/IsA","end":"/c/en/list","weight":1,"surfaceText":"[[arraylist]] IsA [[list]]"}
6
+ {"start":"/c/en/arraylist","rel":"/r/IsA","end":"/c/en/data_structure","weight":1,"surfaceText":"[[arraylist]] IsA [[data structure]]"}
7
+ {"start":"/c/en/hashmap","rel":"/r/IsA","end":"/c/en/hash_table","weight":1,"surfaceText":"[[hashmap]] IsA [[hash table]]"}
8
+ {"start":"/c/en/hashmap","rel":"/r/IsA","end":"/c/en/dictionary","weight":1,"surfaceText":"[[hashmap]] IsA [[dictionary]]"}
9
+ {"start":"/c/en/hashmap","rel":"/r/IsA","end":"/c/en/map","weight":1,"surfaceText":"[[hashmap]] IsA [[map]]"}
10
+ {"start":"/c/en/interface","rel":"/r/IsA","end":"/c/en/type","weight":1,"surfaceText":"[[interface]] IsA [[type]]"}
11
+ {"start":"/c/en/interface","rel":"/r/IsA","end":"/c/en/contract","weight":1,"surfaceText":"[[interface]] IsA [[contract]]"}
12
+ {"start":"/c/en/class","rel":"/r/IsA","end":"/c/en/type","weight":1,"surfaceText":"[[class]] IsA [[type]]"}
13
+ {"start":"/c/en/object","rel":"/r/IsA","end":"/c/en/instance","weight":1,"surfaceText":"[[object]] IsA [[instance]]"}
14
+ {"start":"/c/en/jvm","rel":"/r/IsA","end":"/c/en/virtual_machine","weight":1,"surfaceText":"[[jvm]] IsA [[virtual machine]]"}
15
+ {"start":"/c/en/jvm","rel":"/r/UsedFor","end":"/c/en/running_bytecode","weight":1,"surfaceText":"[[jvm]] UsedFor [[running bytecode]]"}
16
+ {"start":"/c/en/jvm","rel":"/r/CapableOf","end":"/c/en/execute_bytecode","weight":1,"surfaceText":"[[jvm]] CapableOf [[execute bytecode]]"}
17
+ {"start":"/c/en/bytecode","rel":"/r/IsA","end":"/c/en/code","weight":1,"surfaceText":"[[bytecode]] IsA [[code]]"}
18
+ {"start":"/c/en/garbage_collector","rel":"/r/PartOf","end":"/c/en/jvm","weight":1,"surfaceText":"[[garbage collector]] PartOf [[jvm]]"}
19
+ {"start":"/c/en/garbage_collector","rel":"/r/UsedFor","end":"/c/en/freeing_memory","weight":1,"surfaceText":"[[garbage collector]] UsedFor [[freeing memory]]"}
20
+ {"start":"/c/en/jar","rel":"/r/IsA","end":"/c/en/archive","weight":1,"surfaceText":"[[jar]] IsA [[archive]]"}
21
+ {"start":"/c/en/jar","rel":"/r/IsA","end":"/c/en/file","weight":1,"surfaceText":"[[jar]] IsA [[file]]"}
22
+ {"start":"/c/en/jar","rel":"/r/UsedFor","end":"/c/en/packaging_classes","weight":1,"surfaceText":"[[jar]] UsedFor [[packaging classes]]"}
23
+ {"start":"/c/en/maven","rel":"/r/IsA","end":"/c/en/build_tool","weight":1,"surfaceText":"[[maven]] IsA [[build tool]]"}
24
+ {"start":"/c/en/maven","rel":"/r/IsA","end":"/c/en/package_manager","weight":1,"surfaceText":"[[maven]] IsA [[package manager]]"}
25
+ {"start":"/c/en/gradle","rel":"/r/IsA","end":"/c/en/build_tool","weight":1,"surfaceText":"[[gradle]] IsA [[build tool]]"}
26
+ {"start":"/c/en/thread","rel":"/r/IsA","end":"/c/en/process","weight":1,"surfaceText":"[[thread]] IsA [[process]]"}
27
+ {"start":"/c/en/thread","rel":"/r/UsedFor","end":"/c/en/concurrency","weight":1,"surfaceText":"[[thread]] UsedFor [[concurrency]]"}
28
+ {"start":"/c/en/generics","rel":"/r/UsedFor","end":"/c/en/type_safety","weight":1,"surfaceText":"[[generics]] UsedFor [[type safety]]"}
29
+ {"start":"/c/en/annotation","rel":"/r/IsA","end":"/c/en/metadata","weight":1,"surfaceText":"[[annotation]] IsA [[metadata]]"}
30
+ {"start":"/c/en/exception","rel":"/r/IsA","end":"/c/en/error","weight":1,"surfaceText":"[[exception]] IsA [[error]]"}
31
+ {"start":"/c/en/method","rel":"/r/IsA","end":"/c/en/function","weight":1,"surfaceText":"[[method]] IsA [[function]]"}
@@ -0,0 +1,48 @@
1
+ {
2
+ "version": 1,
3
+ "generated": "by corpus/tier2/generate.mjs",
4
+ "corpuses": [
5
+ {
6
+ "id": "aws",
7
+ "kind": "domain",
8
+ "description": "Amazon Web Services core services and primitives (S3, Lambda, DynamoDB, EC2, IAM, SQS) mapped to general cloud/CS concepts.",
9
+ "source": {
10
+ "kind": "curated",
11
+ "tool": "corpus/tier2/generate.mjs"
12
+ },
13
+ "file": "aws.jsonl",
14
+ "facts": 39,
15
+ "bytes": 4802,
16
+ "sha256": "7ab3e656bc4bc717be3c50d97af030e8592d6597cde182b15390a1dfaca9755a",
17
+ "license": "MPL-2.0"
18
+ },
19
+ {
20
+ "id": "python",
21
+ "kind": "language",
22
+ "description": "Python language constructs and stdlib types mapped to the shared CS concept vocabulary (list->array, dict->hash table, …).",
23
+ "source": {
24
+ "kind": "curated",
25
+ "tool": "corpus/tier2/generate.mjs"
26
+ },
27
+ "file": "python.jsonl",
28
+ "facts": 30,
29
+ "bytes": 3794,
30
+ "sha256": "009245d024357bc4285e967fba486e32349ccec8fbe2796ba13011cb2be4c19c",
31
+ "license": "MPL-2.0"
32
+ },
33
+ {
34
+ "id": "java",
35
+ "kind": "language",
36
+ "description": "Java language and JVM constructs mapped to the shared CS concept vocabulary (ArrayList->list, HashMap->hash table, …).",
37
+ "source": {
38
+ "kind": "curated",
39
+ "tool": "corpus/tier2/generate.mjs"
40
+ },
41
+ "file": "java.jsonl",
42
+ "facts": 31,
43
+ "bytes": 3920,
44
+ "sha256": "d089426833c393f6f1574fe75c4ac94a1483ee80f72f79bd7fd32aaaa24a6e44",
45
+ "license": "MPL-2.0"
46
+ }
47
+ ]
48
+ }
@@ -0,0 +1,30 @@
1
+ {"start":"/c/en/python","rel":"/r/IsA","end":"/c/en/programming_language","weight":1,"surfaceText":"[[python]] IsA [[programming language]]"}
2
+ {"start":"/c/en/python","rel":"/r/HasProperty","end":"/c/en/interpreted","weight":1,"surfaceText":"[[python]] HasProperty [[interpreted]]"}
3
+ {"start":"/c/en/python","rel":"/r/HasProperty","end":"/c/en/dynamically_typed","weight":1,"surfaceText":"[[python]] HasProperty [[dynamically typed]]"}
4
+ {"start":"/c/en/python","rel":"/r/UsedFor","end":"/c/en/scripting","weight":1,"surfaceText":"[[python]] UsedFor [[scripting]]"}
5
+ {"start":"/c/en/list","rel":"/r/IsA","end":"/c/en/array","weight":1,"surfaceText":"[[list]] IsA [[array]]"}
6
+ {"start":"/c/en/list","rel":"/r/IsA","end":"/c/en/sequence","weight":1,"surfaceText":"[[list]] IsA [[sequence]]"}
7
+ {"start":"/c/en/list","rel":"/r/IsA","end":"/c/en/data_structure","weight":1,"surfaceText":"[[list]] IsA [[data structure]]"}
8
+ {"start":"/c/en/dict","rel":"/r/IsA","end":"/c/en/hash_table","weight":1,"surfaceText":"[[dict]] IsA [[hash table]]"}
9
+ {"start":"/c/en/dict","rel":"/r/IsA","end":"/c/en/dictionary","weight":1,"surfaceText":"[[dict]] IsA [[dictionary]]"}
10
+ {"start":"/c/en/dict","rel":"/r/IsA","end":"/c/en/mapping","weight":1,"surfaceText":"[[dict]] IsA [[mapping]]"}
11
+ {"start":"/c/en/tuple","rel":"/r/IsA","end":"/c/en/sequence","weight":1,"surfaceText":"[[tuple]] IsA [[sequence]]"}
12
+ {"start":"/c/en/tuple","rel":"/r/HasProperty","end":"/c/en/immutable","weight":1,"surfaceText":"[[tuple]] HasProperty [[immutable]]"}
13
+ {"start":"/c/en/set","rel":"/r/IsA","end":"/c/en/collection","weight":1,"surfaceText":"[[set]] IsA [[collection]]"}
14
+ {"start":"/c/en/set","rel":"/r/HasProperty","end":"/c/en/unordered","weight":1,"surfaceText":"[[set]] HasProperty [[unordered]]"}
15
+ {"start":"/c/en/str","rel":"/r/IsA","end":"/c/en/string","weight":1,"surfaceText":"[[str]] IsA [[string]]"}
16
+ {"start":"/c/en/decorator","rel":"/r/IsA","end":"/c/en/function","weight":1,"surfaceText":"[[decorator]] IsA [[function]]"}
17
+ {"start":"/c/en/decorator","rel":"/r/UsedFor","end":"/c/en/modifying_functions","weight":1,"surfaceText":"[[decorator]] UsedFor [[modifying functions]]"}
18
+ {"start":"/c/en/generator","rel":"/r/IsA","end":"/c/en/iterator","weight":1,"surfaceText":"[[generator]] IsA [[iterator]]"}
19
+ {"start":"/c/en/generator","rel":"/r/UsedFor","end":"/c/en/lazy_evaluation","weight":1,"surfaceText":"[[generator]] UsedFor [[lazy evaluation]]"}
20
+ {"start":"/c/en/comprehension","rel":"/r/IsA","end":"/c/en/expression","weight":1,"surfaceText":"[[comprehension]] IsA [[expression]]"}
21
+ {"start":"/c/en/comprehension","rel":"/r/UsedFor","end":"/c/en/building_collections","weight":1,"surfaceText":"[[comprehension]] UsedFor [[building collections]]"}
22
+ {"start":"/c/en/exception","rel":"/r/IsA","end":"/c/en/error","weight":1,"surfaceText":"[[exception]] IsA [[error]]"}
23
+ {"start":"/c/en/module","rel":"/r/IsA","end":"/c/en/file","weight":1,"surfaceText":"[[module]] IsA [[file]]"}
24
+ {"start":"/c/en/package","rel":"/r/IsA","end":"/c/en/module","weight":1,"surfaceText":"[[package]] IsA [[module]]"}
25
+ {"start":"/c/en/method","rel":"/r/IsA","end":"/c/en/function","weight":1,"surfaceText":"[[method]] IsA [[function]]"}
26
+ {"start":"/c/en/pip","rel":"/r/IsA","end":"/c/en/package_manager","weight":1,"surfaceText":"[[pip]] IsA [[package manager]]"}
27
+ {"start":"/c/en/pip","rel":"/r/UsedFor","end":"/c/en/installing_packages","weight":1,"surfaceText":"[[pip]] UsedFor [[installing packages]]"}
28
+ {"start":"/c/en/gil","rel":"/r/IsA","end":"/c/en/lock","weight":1,"surfaceText":"[[gil]] IsA [[lock]]"}
29
+ {"start":"/c/en/gil","rel":"/r/PartOf","end":"/c/en/interpreter","weight":1,"surfaceText":"[[gil]] PartOf [[interpreter]]"}
30
+ {"start":"/c/en/cpython","rel":"/r/IsA","end":"/c/en/interpreter","weight":1,"surfaceText":"[[cpython]] IsA [[interpreter]]"}
@@ -16,14 +16,22 @@
16
16
  # chosen to commute so finish() is idempotent: finish(finish(x)) === finish(x).
17
17
  #
18
18
  # SEQUENCING (PLAN_RESPONSE_FINISHING.md, "one grammar rule per tuning cycle"):
19
- # only ARTICLE-SELECTION is live this cycle it fixes a genuine defect with a
20
- # narrow, safe blast radius. AGREEMENT, CAPITALISATION, LIST and TERMINAL are
21
- # fully implemented and golden-tested IN ISOLATION, but PARKED (enabled=false):
22
- # each rewrites established product bytes (tmct's lowercase openers and repeated
23
- # "and" joins are an intentional VOICE, not a grammar defect), so activating them
24
- # is a per-rule tuning-cycle decision with its own bench + showcase reconcile,
25
- # not a blanket flip. `enabled=false` keeps them inert in finish(); the goldens
26
- # force-enable each rule to prove its behaviour independent of the live flag.
19
+ # LIVE as of cycle 005: ARTICLE-SELECTION (cycle 4), plus the two SAFE defect
20
+ # fixes TERMINAL-PUNCTUATION and SUBJECT-VERB-AGREEMENT each byte-stable when
21
+ # neutral, no product-voice change. CAPITALISATION and LIST are fully implemented
22
+ # and golden-tested IN ISOLATION but remain PARKED (enabled=false). The cycle-006
23
+ # judged A/B was assessed and DROPPED: `capitalise` rewrites the sentence-initial
24
+ # char, which regresses ~10 frozen v1 cases.jsonl whose case-sensitive answerMatch
25
+ # pins lowercase openers ("can't count", "no symbol matching", "assuming you meant",
26
+ # …) the same sacred-case collision that reverted the voice-nit; and `list` has
27
+ # zero 3-item "X and Y and Z" targets in the judged set (a no-op). Deferred to a
28
+ # post-arc case-set refresh where the openers can be re-pinned deliberately. They
29
+ # rewrite established product bytes (tmct's
30
+ # lowercase openers and repeated "and" joins are an intentional VOICE, not a
31
+ # grammar defect), so activating them is a per-rule tuning-cycle decision with
32
+ # its own bench + showcase reconcile, not a blanket flip. `enabled=false` keeps
33
+ # them inert in finish(); the goldens force-enable each rule to prove its
34
+ # behaviour independent of the live flag.
27
35
 
28
36
  # 1. Article selection — a/an by the following word's phonetic onset. The live
29
37
  # defect this fixes: the assert echo "every module is a artifact" -> "an
@@ -48,7 +56,7 @@ vowel_sound_consonants = ["hour", "honest", "honour", "honor", "heir", "herb"]
48
56
  [[rule]]
49
57
  id = "subject-verb-agreement"
50
58
  kind = "agreement"
51
- enabled = false # PARKEDimplemented + golden-tested, not live this cycle
59
+ enabled = true # LIVE (cycle 005) structure-driven existential agreement, byte-stable when neutral
52
60
  registers = []
53
61
  description = "existential copula agrees with the following count/plurality"
54
62
  singular = ["is", "was", "has"]
@@ -83,7 +91,7 @@ separator = ", "
83
91
  [[rule]]
84
92
  id = "terminal-punctuation"
85
93
  kind = "terminal"
86
- enabled = false # PARKEDimplemented + golden-tested, not live this cycle
94
+ enabled = true # LIVE (cycle 005) pure defect fix, narrowest blast radius (trailing doubled stop)
87
95
  registers = []
88
96
  description = "collapse a run of trailing sentence stops to a single stop"
89
97
  stops = [".", "!", "?"]
@@ -62,6 +62,8 @@
62
62
  {"id":"conversational-farewell","class":"conversational","register":"friendly","template":"Bye — flushing the session log. Come back with a question any time."}
63
63
  {"id":"orientation-friendly","class":"orientation","register":"friendly","template":"I answer questions about THIS codebase's structure — imports, calls, definitions,\nhistory and counts. For example:\n which modules import walk.mjs\n what calls buildContextBundle\n how many classes are there\n/help for commands, /stats for an overview of the graph."}
64
64
  {"id":"miss-no-previous-answer","class":"miss","register":"friendly","template":"No previous answer to expand yet — ask me a question first, then say \"why\" or \"say more\"."}
65
+ {"id":"conversational-greeting-empty","class":"conversational","register":"friendly","template":"Hi. There's no code graph loaded here yet — point me at your code with `--repo <path>` or run `tmct init`. Meanwhile I know some general vocabulary — try \"what is a cache\". /help for commands."}
66
+ {"id":"orientation-empty","class":"orientation","register":"friendly","template":"There's no code graph loaded here, so I can't answer structure questions (imports, calls, definitions) yet.\nPoint me at your code with `--repo <path>` or run `tmct init` to index this repo.\nI do know some general vocabulary — try \"what is a cache\". /help for commands, /memory for what I remember."}
65
67
  {"id":"technical-density","class":"count","register":"technical","template":"{subject} carries {count} {noun} across {scope} — a concentration well above what a codebase of this size typically sustains ({provenance})."}
66
68
  {"id":"technical-comparison","class":"count","register":"technical","template":"At {count} {noun}, {subject} sits {comparison} the comparable-project baseline, a divergence that reflects deliberate structure rather than measurement noise ({provenance})."}
67
69
  {"id":"technical-superlative","class":"count","register":"technical","template":"No {noun} in {scope} is more {metric} than {subject}; it leads the next candidate by a clear margin of {count} ({provenance})."}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polycode-projects/the-mechanical-code-talker",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "The Mechanical Code Talker (tmct) — a tolerant, offline, $0 chat surface that guides you toward precision queries about a software repository. ELIZA/PARRY-style but domain-obsessed with code. No model calls; no codebase index of its own.",
@@ -48,7 +48,12 @@
48
48
  "./relationKind": "./src/codegraph.mjs",
49
49
  "./impactClosure": "./src/codegraph.mjs",
50
50
  "./dispatchTool": "./src/server.mjs",
51
- "./fetchEntities": "./src/source.mjs"
51
+ "./fetchEntities": "./src/source.mjs",
52
+ "./repository-interface": "./src/repository-interface.mjs",
53
+ "./graph-service": "./src/providers/graph-service.mjs",
54
+ "./providers/fixture": "./src/providers/fixture.mjs",
55
+ "./providers/bootstrap": "./src/providers/bootstrap.mjs",
56
+ "./conformance": "./src/conformance.mjs"
52
57
  },
53
58
  "files": [
54
59
  "bin/",
@@ -72,6 +77,9 @@
72
77
  "scripts": {
73
78
  "test": "node --test \"test/**/*.test.mjs\"",
74
79
  "chat": "node bin/tmct.mjs",
80
+ "chat:repo": "node bin/tmct.mjs chat --repo",
81
+ "example:mini": "node bin/tmct.mjs chat --repo examples/mini-webapp",
82
+ "example:polyglot": "node bin/tmct.mjs chat --repo examples/polyglot",
75
83
  "chatbench:run": "node chatbench/run.mjs",
76
84
  "chatbench:judge": "node chatbench/judge.mjs",
77
85
  "audit": "npm audit --audit-level=high",
package/src/ask-vocab.mjs CHANGED
@@ -529,7 +529,14 @@ export const AGGREGATE_TRIGGERS = Object.freeze([
529
529
  // CONTENT_VOCAB and blocks the article's own noise-strip)
530
530
  "how many", "how much", "how many of", "number of",
531
531
  "total number of", "quantity of",
532
- // neutral / imperative
532
+ // "<measure> of <kind>" cardinality forms (widened net, cycle W2P): count = sum = total
533
+ // = tally = number of. The bare single words (sum/total/tally) stay CASCADE_SYNONYMS-
534
+ // mapped to "count" (identifier-fragment risk without the "of" anchor — see that table's
535
+ // note); the multi-word "of" forms are safe to promote to direct triggers because the
536
+ // trailing "of <kind>" pins them to a cardinality question, not a stray identifier.
537
+ "tally of", "sum of", "total of", "amount of",
538
+ // neutral / imperative (bare "tally"/"sum"/"total" stay CASCADE_SYNONYMS-mapped so the
539
+ // "tally the classes" relaxation path — pinned by a cascade test — is preserved).
533
540
  "count", "count up", "count of", "tot up",
534
541
  ]);
535
542
 
@@ -593,6 +600,17 @@ export const EDGE_NOUN_TO_METRIC = Object.freeze({
593
600
  connections: { kind: "*", dir: "both" },
594
601
  edges: { kind: "*", dir: "both" },
595
602
  connected: { kind: "*", dir: "both" },
603
+ // participle degree-nouns (widened net, cycle W2P): "the most imported / most
604
+ // depended-on / most used <module>" ranks by IN-degree — how many things import/depend
605
+ // on/use it — the ARGMAX-by-degree intent a developer expresses with a passive
606
+ // participle rather than the noun ("importers"). "depended" catches "depended-on" /
607
+ // "depended on" (both tokenize to a bare "depended"); "used" folds the symbol-grain
608
+ // callsSymbol callers in alongside importers so "most used" reads as most-relied-upon.
609
+ imported: { kind: "imports", dir: "in" },
610
+ "depended-on": { kind: "imports", dir: "in" },
611
+ depended: { kind: "imports", dir: "in" },
612
+ used: { kind: "imports", dir: "in", sibling: "callsSymbol" },
613
+ called: { kind: "calls", dir: "in", sibling: "callsSymbol" },
596
614
  });
597
615
 
598
616
  /** Anaphora triggers over the PREVIOUS result set (ask()'s `prev` id array):