@polycode-projects/the-mechanical-code-talker 1.5.5 → 1.8.4

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.
Files changed (45) hide show
  1. package/README.md +123 -14
  2. package/ROADMAP.md +233 -1392
  3. package/bin/tmct.mjs +479 -98
  4. package/corpus/README.md +3 -0
  5. package/corpus/generated/README.md +43 -0
  6. package/corpus/generated/ace-surface-variants.jsonl +17 -0
  7. package/corpus/generated/manifest.json +9 -0
  8. package/corpus/tier2/generate.mjs +14668 -0
  9. package/corpus/tier2/human-examples-large.jsonl +1928 -0
  10. package/corpus/tier2/human-examples-medium.jsonl +356 -0
  11. package/corpus/tier2/human-examples.jsonl +120 -0
  12. package/corpus/tier2/human-large.jsonl +12001 -0
  13. package/corpus/tier2/human-medium.jsonl +944 -0
  14. package/corpus/tier2/human.jsonl +664 -0
  15. package/corpus/tier2/manifest.json +42 -0
  16. package/package.json +14 -8
  17. package/src/answer-variants.json +47 -0
  18. package/src/answer-variants.mjs +67 -0
  19. package/src/ask-browser-entry.mjs +34 -0
  20. package/src/ask-browser.bundle.js +5095 -0
  21. package/src/ask-vocab.mjs +93 -8
  22. package/src/ask.mjs +451 -49
  23. package/src/chat.mjs +1273 -137
  24. package/src/cli-args.mjs +164 -0
  25. package/src/codegraph.mjs +170 -32
  26. package/src/extensions.mjs +100 -19
  27. package/src/grammar/ace.mjs +85 -3
  28. package/src/grammar/lexicon-core.json +9531 -63
  29. package/src/grammar/lexicon.mjs +58 -8
  30. package/src/graph-merge.mjs +114 -0
  31. package/src/index.mjs +14 -0
  32. package/src/init.mjs +40 -14
  33. package/src/interpret/normalize.mjs +75 -1
  34. package/src/interpret/strategies/grammar.mjs +10 -0
  35. package/src/interpret/strategies/keywords.mjs +20 -0
  36. package/src/interpret/strategies/noise-strip.mjs +73 -4
  37. package/src/memory/core.mjs +466 -8
  38. package/src/router/goal-reasoner.mjs +41 -7
  39. package/src/router/guardrail.mjs +37 -7
  40. package/src/router/resolver.mjs +50 -4
  41. package/src/sessions.mjs +5 -1
  42. package/src/source.mjs +54 -1
  43. package/src/syllogise.mjs +398 -27
  44. package/src/toml-config.mjs +13 -4
  45. package/src/viz.mjs +541 -0
package/src/ask-vocab.mjs CHANGED
@@ -324,17 +324,37 @@ const TRAILING_DISCOURSE_TAG_RE = new RegExp(
324
324
  `\\s+(?:${TRAILING_DISCOURSE_TAG.join("|")})\\s*[?.!]*$`, "i",
325
325
  );
326
326
 
327
- /** Strip trailing bare discourse tags (TRAILING_DISCOURSE_TAG, above) off the
328
- * end of a captured meta-whatis term "what is a component then" resolves
329
- * the same term as "what is a component". Applied up to twice (a stacked
330
- * "too then"/"then too" is the only worked case that ever needs a second
331
- * pass; no phrasing seen so far stacks a third), mirroring
332
- * stripTrailingScopeFiller's own single-clause discipline for the common
333
- * single-tag case while still covering the rarer double-tag one. */
327
+ /** Trailing COMMA-delimited discourse clauses ("what is a class, please
328
+ * explain") a distinct shape from TRAILING_DISCOURSE_TAG above (a bare
329
+ * space-led tag, no comma): an ESL follow-on clause tacked onto a
330
+ * meta-whatis term after a comma, meaning "please explain [it]", not part of
331
+ * the term itself (BENCHMARK_CONVERSATION_1.7.0.md routed backlog C1). Closed
332
+ * and curated exactly like TRAILING_DISCOURSE_TAG anchored on a LITERAL
333
+ * comma immediately before the tag, so this can never fire mid-phrase and
334
+ * can never touch a term that merely contains a comma for some other reason
335
+ * (no real code identifier ends in ", please explain" or ", explain"). */
336
+ export const TRAILING_DISCOURSE_CLAUSE = Object.freeze(["please explain", "explain"]);
337
+
338
+ const TRAILING_DISCOURSE_CLAUSE_RE = new RegExp(
339
+ `,\\s*(?:${TRAILING_DISCOURSE_CLAUSE.join("|")})\\s*[?.!]*$`, "i",
340
+ );
341
+
342
+ /** Strip trailing bare discourse tags (TRAILING_DISCOURSE_TAG, above) AND
343
+ * trailing comma-delimited discourse clauses (TRAILING_DISCOURSE_CLAUSE,
344
+ * above) off the end of a captured meta-whatis term — "what is a component
345
+ * then" resolves the same term as "what is a component", and "what is a
346
+ * class, please explain" resolves the same term as "what is a class".
347
+ * Applied up to twice (a stacked "too then"/"then too" is the only worked
348
+ * case that ever needs a second pass; no phrasing seen so far stacks a
349
+ * third), mirroring stripTrailingScopeFiller's own single-clause discipline
350
+ * for the common single-tag case while still covering the rarer
351
+ * double-tag one. The comma-clause strip runs each pass too, so "class,
352
+ * please explain then" (an unworked but plausible stack) still resolves. */
334
353
  export function stripTrailingDiscourseTag(text) {
335
354
  let out = text;
336
355
  for (let pass = 0; pass < 2; pass += 1) {
337
- const next = out.replace(TRAILING_DISCOURSE_TAG_RE, "").trim();
356
+ let next = out.replace(TRAILING_DISCOURSE_TAG_RE, "").trim();
357
+ next = next.replace(TRAILING_DISCOURSE_CLAUSE_RE, "").trim();
338
358
  if (next === out) break;
339
359
  out = next;
340
360
  }
@@ -349,6 +369,48 @@ export const VERB_TO_KIND = Object.freeze(
349
369
  ),
350
370
  );
351
371
 
372
+ /** "what is a kind of X" / "what is a subclass of X" collision fix (2026-07-11,
373
+ * live-repro: "boney is a dog" -> "what is a dog" -> "what is a kind of
374
+ * animal" hit a forced disambiguation wall instead of answering). grammar.mjs's
375
+ * T5 "meta-whatis" template reads "what is a/an <object>" as a literal
376
+ * glossary/term-definition question ("what is a Commit"). But some registered
377
+ * inherits verbs are THEMSELVES phrased "is a <continuation>" ("is a kind
378
+ * of", "is a subclass of" — RELATIONS.inherits.verbs above) — when the object
379
+ * T5 captures IS one of these continuations plus a real term ("kind of
380
+ * animal"), the sentence isn't asking to define the noun phrase "kind of
381
+ * animal"; it's the exact same question as "what inherits from animal", just
382
+ * phrased with the verb's own "is a" lead instead of "inherits". keyword-spot
383
+ * (keywords.mjs) already reads it that way, unambiguously — the meta reading
384
+ * is the spurious one, and it collides with keyword-spot's correct reading to
385
+ * manufacture a needless {ambiguousParse} tie (interpret/merge.mjs) over a
386
+ * phrasing the engine itself just used a turn earlier. Derived from
387
+ * VERB_TO_KIND (not hand-duplicated) so any future plain "is a/are a X of"
388
+ * verb phrase added to RELATIONS is covered automatically, without touching
389
+ * this file again.
390
+ *
391
+ * Deliberately EXCLUDES every INHERITS_REVERSE_VERBS entry ("is a superclass
392
+ * of", "is a parent class of") even though they match the same "is a
393
+ * <continuation>" shape: those verbs' subject/object are semantically
394
+ * SWAPPED relative to storage direction (see INHERITS_REVERSE_VERB_LIST's own
395
+ * comment above) — "what is a superclass of X" asks a FORWARD question
396
+ * (X's own supertype), not this reverse-by-object listing, and keyword-spot's
397
+ * decomposition only applies that swap in the two-sided "ask" shape (verb
398
+ * between a subject AND an object), not this "reverse"-only afterText-only
399
+ * shape. Suppressing the meta reading for these too would trade one honest
400
+ * {ambiguousParse} wall for a confusing WRONG answer (a reverse-by-object
401
+ * lookup with the direction backwards) — a separate, pre-existing gap in
402
+ * keywords.mjs, out of this fix's scope. */
403
+ const NON_REVERSE_VERB = (v) => !INHERITS_REVERSE_VERBS.includes(v);
404
+ export const ARTICLE_RELATION_CONTINUATIONS = Object.freeze([
405
+ ...new Set(
406
+ Object.keys(VERB_TO_KIND)
407
+ .filter(NON_REVERSE_VERB)
408
+ .map((v) => v.match(/^(?:is|are)\s+an?\s+(.+)$/i))
409
+ .filter(Boolean)
410
+ .map((m) => m[1].toLowerCase()),
411
+ ),
412
+ ]);
413
+
352
414
  export const ENTITY_TO_TYPE = Object.freeze({
353
415
  function: "Function", functions: "Function",
354
416
  method: "Method", methods: "Method",
@@ -470,6 +532,10 @@ export const MISSPELLINGS = Object.freeze({
470
532
  "extands": "extends", "extneds": "extends",
471
533
  "depnds": "depends",
472
534
  "touchs": "touches", "tuoches": "touches", "touhced": "touched",
535
+ // "touchd" (BENCHMARK_CONVERSATION_1.7.0.md routed backlog C3): the
536
+ // dropped-vowel slip of "touched" — distinct from "touhced" above
537
+ // (transposed letters), same curated-typo discipline.
538
+ "touchd": "touched",
473
539
  // WHERE_MARKERS typo (0.9.13 Tier-1 playtest): "defined" itself had no typo
474
540
  // entry, so "where is it defned" fell through to the bare-object search path
475
541
  // instead of the where-shape ("no module matching 'it defned' found").
@@ -498,6 +564,12 @@ export const MISSPELLINGS = Object.freeze({
498
564
  // anchor; the correction regex's dotted-extension guard keeps a module
499
565
  // literally named "wat.mjs" untouched, same residual trade as every entry.
500
566
  "waht": "what", "wat": "what",
567
+ // "dat" (BENCHMARK_CONVERSATION_1.7.0.md routed backlog C3): the internet-
568
+ // casual spelling of "that" — same register as "wat"/"waht" just above,
569
+ // curated rather than left to the generic fuzzy tier since "that" is a
570
+ // load-bearing anchor word throughout this grammar (TEACH_RE's own
571
+ // "remember that X", relative-clause objects, etc).
572
+ "dat": "that",
501
573
  "dose": "does", "doess": "does",
502
574
  "teh": "the",
503
575
  // aggregate/list TRIGGER words (2026-07-02, trigger-typo work) — a typo of a count
@@ -788,6 +860,7 @@ export const EDGE_NOUN_TO_METRIC = Object.freeze({
788
860
  methods: { kind: "contains", dir: "out", filter: "Method" },
789
861
  members: { kind: "contains", dir: "out" },
790
862
  tests: { kind: "tests", dir: "in" },
863
+ test: { kind: "tests", dir: "in" }, // singular ("needs a test") — same edge as plural "tests"
791
864
  subclasses: { kind: "inherits", dir: "in" },
792
865
  connections: { kind: "*", dir: "both" },
793
866
  edges: { kind: "*", dir: "both" },
@@ -805,6 +878,18 @@ export const EDGE_NOUN_TO_METRIC = Object.freeze({
805
878
  called: { kind: "calls", dir: "in", sibling: "callsSymbol" },
806
879
  });
807
880
 
881
+ /** Metric nouns whose edge kind targets exactly ONE entity class in this graph's
882
+ * ontology (only a Module is ever the object of a `tests` edge) — read by
883
+ * ask.mjs's parseSuperlative to default `entityType` when a superlative names a
884
+ * metric but no explicit entity noun ("what most needs a test", vs. the fully
885
+ * explicit "which MODULE has the most tests"). Deliberately small: a metric like
886
+ * "calls"/"connections" targets more than one class, so it is NOT listed here —
887
+ * those keep requiring an explicit entity noun, same as before this table existed. */
888
+ export const METRIC_IMPLIES_ENTITY = Object.freeze({
889
+ tests: "Module",
890
+ test: "Module",
891
+ });
892
+
808
893
  /** Anaphora triggers over the PREVIOUS result set (ask()'s `prev` id array):
809
894
  * "which of those/them/these …", "how many of those …". The pronoun refers to the
810
895
  * last answer's ids, not a graph term — with no prev supplied it is an honest miss