@polycode-projects/the-mechanical-code-talker 1.10.4 → 1.10.6

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/chat.mjs +45 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polycode-projects/the-mechanical-code-talker",
3
- "version": "1.10.4",
3
+ "version": "1.10.6",
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.",
package/src/chat.mjs CHANGED
@@ -5503,7 +5503,42 @@ async function factReadBack(memoryDir, query, envelope, miss, graph = null, focu
5503
5503
  }
5504
5504
  }
5505
5505
  }
5506
- return null; // no remembered fact the honest miss stands (never a guessed "no")
5506
+ // Every yes-chase and the disjoint "no" above missed. The old
5507
+ // unconditional decline here fell through to the structural "couldn't
5508
+ // parse this as a graph question" wall — actively misleading for a KNOWN
5509
+ // subject, twice over: the question DID parse, and the wall's hint
5510
+ // suggests the exact shape the user just typed. When the subject has
5511
+ // remembered isa-family facts, answer with an honest, specific miss that
5512
+ // cites what IS remembered instead. An unknown subject still declines to
5513
+ // the standing wall/teach-hint path — and this never guesses a "no".
5514
+ // The SUBJECT'S OWN variants only — subjCandidates was augmented above
5515
+ // with the graph entity's class noun (the CLASS↔INSTANCE bridge), and
5516
+ // filtering on it here would cite facts about that noun ("class ⊑
5517
+ // component") as if they were facts about the asked subject ("Widget").
5518
+ const directSubjVariants = factTermVariants(normFactTerm, isaAsk[1]);
5519
+ const knownSubjectIsa = isa.filter((f) => directSubjVariants.has(f.subject)).sort(byTrust);
5520
+ const subjectWord = isaAsk[1].trim();
5521
+ const kindWord = stripTrailingDiscourseTag(isaAsk[2]).trim();
5522
+ if (knownSubjectIsa.length) {
5523
+ const shown = knownSubjectIsa.slice(0, 3).map(renderFactLine).join("; ");
5524
+ return {
5525
+ text: `I can't confirm that — nothing I remember says ${subjectWord} is a ${kindWord}. I do know: ${shown}. If it's true, teach me: "${subjectWord} is a kind of ${kindWord}".`,
5526
+ replace: true,
5527
+ miss: true, // still a MISS in the turn record — honest wording, not an answer
5528
+ };
5529
+ }
5530
+ // Subject with NO isa facts: only divert when it's mentioned NOWHERE at
5531
+ // all (no fact row on either side, no code entity by id OR class noun) —
5532
+ // a subject known via OTHER predicates ("ahab is male") or the code graph
5533
+ // keeps the old decline, so nothing downstream is ever shadowed.
5534
+ if (!ent && !noun && !rows.some((f) => subjCandidates.has(f.subject) || subjCandidates.has(f.object))) {
5535
+ return {
5536
+ text: `I can't confirm that — I don't know "${subjectWord}" at all yet. If it's true, teach me: "${subjectWord} is a kind of ${kindWord}".`,
5537
+ replace: true,
5538
+ miss: true,
5539
+ };
5540
+ }
5541
+ return null; // the honest miss stands (never a guessed "no")
5507
5542
  }
5508
5543
 
5509
5544
  // (a1c-i) CARDINALITY MONOTONICITY — "does every X have at least N Y" over
@@ -7105,6 +7140,7 @@ async function runAsk(query, { config, source, graph, focus, last, templates, me
7105
7140
  if (memoryDir) {
7106
7141
  bareMetaHit = (await factAnswer(memoryDir, gateQuery, envelope, miss, biasByBundle, cache))
7107
7142
  ?? (await factReadBack(memoryDir, gateQuery, envelope, miss, graph, newFocus?.label, biasByBundle, cache));
7143
+ if (bareMetaHit?.miss) bareMetaHit = null; // an honest-miss return never diverts the gate
7108
7144
  // A bare "what is X" with NO taught fact but a KNOWN curated corpus term
7109
7145
  // ("what is cache", no article) needs the same "only diverts on a REAL
7110
7146
  // hit" treatment — curatedDefinitionAnswer otherwise only ever runs once
@@ -7175,8 +7211,14 @@ async function runAsk(query, { config, source, graph, focus, last, templates, me
7175
7211
  ?? (await factReadBack(memoryDir, query, envelope, miss, graph, newFocus?.label, biasByBundle, cache));
7176
7212
  if (fact) {
7177
7213
  answer = fact.replace ? fact.text : `${answer}\n${fact.text}`;
7178
- via = "fact";
7179
- recordMiss = false;
7214
+ // A fact-lane return flagged `miss` is an HONEST MISS in better words
7215
+ // (the isa ladder's "I can't confirm that" closers) — the turn record
7216
+ // keeps miss=true and via stays untouched, so miss-rate metrics and
7217
+ // recall's own miss-gated lanes see it exactly like the wall it replaced.
7218
+ if (!fact.miss) {
7219
+ via = "fact";
7220
+ recordMiss = false;
7221
+ }
7180
7222
  if (fact.pending) factPending = fact.pending; // a truncated fact list → paginable remainder
7181
7223
  if (typeof fact.trust === "number") entailedTrust = fact.trust; // live-chase trust (see the `entailedTrust` declaration above)
7182
7224
  note(trace, `lane: (3) memory facts — factAnswer/factReadBack matched (memoryDir=${memoryDir})`);