@polycode-projects/the-mechanical-code-talker 0.9.9 → 0.9.11

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/ROADMAP.md CHANGED
@@ -82,13 +82,13 @@ In priority order (full detail and measured targets in `HANDOVER.md`):
82
82
  unscoped lister shows matches. Found dogfooding a 191k-entity monorepo graph.
83
83
  3. **Bug 7.** A modal auxiliary ("should") survives the fuzzy-correction cascade and misreads as
84
84
  "hold". The diagnosed fix is adding modals to `STOPWORDS`.
85
- 4. **`PLAN_TMCT_ECOSYSTEM_INTEGRATION.md`.** A separate concurrent session is drafting this
86
- 3-part tmct/bedrock-meter/marginalia integration plan. Check for completion and finalize.
87
- 5. **`PLAN_CODE.md`'s sign-off decision.** Track 1 (rule/frame synthesis) is the lowest-risk
88
- candidate; decide with the operator whether to greenlight it.
89
- 6. Smaller chat-feel residuals from the 0.8.2 confirmation playtest, the Track-1 trio (pronoun,
90
- temporal, discourse-count, measured red sets), and `edgesOfKind` memoization for monorepo-scale
91
- latency. (The version bump plus push is done — see "Now" above.)
85
+ 4. ~~`PLAN_TMCT_ECOSYSTEM_INTEGRATION.md`~~ **shipped** see "Now" above.
86
+ 5. ~~`PLAN_CODE.md` Track 1 sign-off~~ **signed off and shipped** — see "Now" above.
87
+ 6. **Still open**: the function-grain forward-shape gap (Bug C+D's grain resolution doesn't
88
+ cover the "forward" traversal shape), 8 remaining temporal red ids (each a distinct small
89
+ grammar gap), the un-flagged `C1:presupposition`/`C2:garden-path` regression, the
90
+ `edgesOfKind` by-subject/by-object endpoint indices (memoization itself is done). Full
91
+ detail in `HANDOVER.md`.
92
92
  7. **`SKILL_PLAYTEST_SPRINT.md`, in progress.** A capped, delegated, chained playtest loop (each
93
93
  round a background chat session against `examples/mini-webapp`, appraised and fixed+shipped
94
94
  live). Rounds 1-3 shipped 3 real fixes (0.9.3-0.9.5); cap raised from 3 to 8 rounds mid-run;
@@ -650,13 +650,45 @@ outward from high-trust premises (the provenance primitive) toward novel, releva
650
650
  timestamping each so recency and novelty stay computable. The mechanics are the easy half
651
651
  (bounded forward chaining materializes entailments; backward chaining from frequent query shapes
652
652
  pre-derives likely answers). **The residual hard half is still the FRAME PROBLEM / relevance
653
- realization — unsolved in the general case and not pretended otherwise;** trust+novelty+relevance
654
- are the tractable approximation, not a solution. The plan's job is
655
- to make it TRACTABLE in tmct's narrow, closed world, not to solve it: usefulness is approximated
656
- from what the system actually gets asked (query-shape frequency), what connects to recent focus,
657
- what a cheap forward step yields that isn't already stored, and a hard
658
- budget (inference is bounded, its output trust-scored via the provenance primitive, and anything
659
- speculative is retractable and never outranks a stated fact). Everything else is deferred to the
653
+ realization — unsolved in the general case and not pretended otherwise.** This is not one problem
654
+ but two, of different hardness (full literature + citations in `PLAN_CAPABILITY_ROUTER.md`'s "The
655
+ open-world boundary" section):
656
+
657
+ - **The frame-*axiom* problem solved, inside a declared world.** McCarthy & Hayes named it in
658
+ 1969 ("Some Philosophical Problems from the Standpoint of Artificial Intelligence", *Machine
659
+ Intelligence* 4); Reiter's 1991 successor-state axioms and Kowalski & Sergot's 1986 event
660
+ calculus (*New Generation Computing* 4(1)) both solve the narrow reading — stating what changes
661
+ without enumerating what doesn't — inside a **declared** effect/predicate model. That's exactly
662
+ the OWL base the Syllogist forward-chains over: the axioms and rules are declared, so applying
663
+ them is mechanical, bounded, and already shipped (`src/syllogise.mjs`).
664
+ - **The relevance-*bounding* problem — genuinely open, and possibly not just unbuilt.** Given the
665
+ unbounded set of entailments a rich KB licenses, which ones are worth materializing *before
666
+ anyone asks* — without an oracle telling the pass what matters? That is McCarthy's deeper,
667
+ unsolved reading, and it has no known algorithm. It is also, independently, the central problem
668
+ a live cognitive-science literature has converged on: Vervaeke, Lillicrap & Richards ("Relevance
669
+ Realization and the Emerging Framework in Cognitive Science", *Journal of Logic and Computation*
670
+ 22(1):79–99, 2012) frame it as the pervasive problem cognitive science keeps rediscovering: Jaeger,
671
+ Riedl, Djedovic, Vervaeke & Walsh ("Naturalizing relevance realization: why agency and cognition
672
+ are fundamentally not computational", *Frontiers in Psychology*, 2024) go further and argue —
673
+ contestably, but rigorously, not as a popular-science claim — that relevance realization
674
+ *cannot* be an algorithmic process at all, by an analogy to Gödelian incompleteness. Take that as
675
+ a live, unresolved argument, not a proof: the honest position is that tmct doesn't know whether
676
+ this is "hard" or "impossible", and says so.
677
+
678
+ trust+novelty+relevance (query-shape frequency, recent-focus connectivity, a hard depth/budget
679
+ cap) are the **tractable approximation** the plan actually ships — a proxy for relevance, not a
680
+ solution to it, and openly so. **A speculative angle, still respecting no-LLM-in-product:** the
681
+ same bounded-region trick sketched for the router's open-world goal recognition
682
+ (`PLAN_CAPABILITY_ROUTER.md`) applies here. Instead of trying to bound relevance globally (the
683
+ open problem above), bound it *per query-shape*: a query shape already declares which
684
+ predicates/fluents it touches — it's how `parseQuery` resolves it — so restricting speculative
685
+ forward-chaining to premises reachable within N hops of an **observed** query shape's declared
686
+ predicates is a *structurally*-bounded relevance filter, not a learned or statistical one. It is
687
+ narrower than "what's relevant in general" (that stays open) but might be enough to keep
688
+ materialization from drifting into computing entailments nobody will ever ask about — trading
689
+ "relevant to anyone" (unsolved) for "relevant to what this system has actually been asked"
690
+ (a proxy, but a principled, deterministic one). This has not been built or measured; it is a
691
+ candidate for the plan's next spike, not a claimed result. Everything else is deferred to the
660
692
  plan's open questions, where the relevance problem is named as the open research risk it is.
661
693
 
662
694
  ### Open-source the ACE-OWL parser as a standalone library
@@ -811,7 +843,57 @@ critical build path:
811
843
  ## Phase LATER — recognized, deferred, not now
812
844
 
813
845
  Features we have deliberately shaped seams for but will not build until the phases above have
814
- earned them:
846
+ earned them. **Not everything below is deferred for the same reason** — the design horizon,
847
+ stated explicitly (2026-07-08 research pass):
848
+
849
+ ### The design horizon
850
+
851
+ **Before the horizon — known-how, not-yet-built, no research risk.** Sequencing or engineering
852
+ debt: the technique exists (in tmct's own prior work or the wider literature), building it is a
853
+ matter of scheduling and effort, not discovery. Everything shipped this session lives here, plus:
854
+ tone-of-voice adaptation (below — deliberately dropped by design choice, not unsolved);
855
+ tier-4 learn-on-miss (below — prerequisites not yet met, not research-blocked); `PLAN_CODE.md`
856
+ Tracks 2–4 (mutation search/repair, JS/HTML/CSS synthesis — APR and CEGIS are established
857
+ techniques); `PLAN_OSS_ACE_PARSER.md` (pure extraction/packaging); OWL 2 RL forward-chaining and
858
+ DL tableau consistency checking (`PLAN_INFERENCE_TESTING.md` stages 3–5 — the W3C's own OWL 2 RL
859
+ profile is a published, complete rule table; Pellet/HermiT/RDFox/Jena are real production
860
+ reasoners built on solved theory); RETE/incremental forward-chaining (same doc — Forgy 1982 is a
861
+ citable, portable algorithm); contingent/conformant planning under initial-state uncertainty
862
+ (`PLAN_CAPABILITY_ROUTER.md` — Bonet & Geffner 2000, Hoffmann & Brafman 2006, Petrick & Bacchus
863
+ 2002 all have working algorithms); ordinary closed-domain anaphora resolution (`nextFocus`,
864
+ already shipped, plus a real theoretical grounding available in Grosz/Joshi/Weinstein's centering
865
+ theory, 1995).
866
+
867
+ **After the horizon — genuinely unsolved in the field, or abandoned by the field in favor of
868
+ approaches tmct's no-LLM ethos rules out.** Named as real research targets, with citations, not
869
+ stop signs (full detail + full citation lists in each owning doc):
870
+ - **The frame problem / relevance realization** — the open-world planning boundary
871
+ (`PLAN_CAPABILITY_ROUTER.md`'s "The open-world boundary" section; this doc's tier-5 Syllogist
872
+ paragraph below). McCarthy & Hayes 1969 named it; Jaeger, Riedl, Djedovic, Vervaeke & Walsh
873
+ (2024) argue it may not be algorithmically solvable in the general case at all. Speculative
874
+ angle recorded: bounded (N+1) goal recognition — recognize declared goal 1..N, or reject to an
875
+ explicit "escalate" class, via parse-shape membership (the same mechanism Bug 8's domain gate
876
+ already uses) — not published anywhere found.
877
+ - **Symbolic (non-neural) dependency parsing at real coverage** — `PLAN_ADVANCED_GRAMMAR.md`
878
+ track (c). Largely abandoned by mainstream NLP research once neural parsers won CoNLL
879
+ 2017/2018, not disproven at any fixed data budget. Speculative angle: a hand-built,
880
+ closed-vocabulary disjunct/category dictionary (Link Grammar/CCG-style) scoped only to tmct's
881
+ own closed relation vocabulary, registered as another additive interpretation strategy.
882
+ - **Winograd-hard commonsense coreference** — `PLAN_ADVANCED_GRAMMAR.md` track (g). Genuinely
883
+ open without either massive statistical priors (ruled out) or a full commonsense KB (Cyc's
884
+ decades-long cautionary history). Speculative angle: tmct's own closed, complete graph makes a
885
+ *narrow slice* of Winograd-shaped ambiguity a graph-query-filtering problem rather than
886
+ open-domain commonsense reasoning — explicitly not the same as solving Winograd.
887
+ - **Bounded, incremental, trust-tiered, retraction-safe justification tracking** —
888
+ `PLAN_INFERENCE_TESTING.md`'s stage-3/4/5 discussion. Doyle's JTMS (1979) and de Kleer's ATMS
889
+ (1986) solve retraction; DRed/RDFox's Backward-Forward solve incremental Datalog maintenance;
890
+ nobody has published the specific combination with tmct's multi-trust-tier, hard-budget
891
+ requirement. Speculative angle: an ATMS-lite extension to `syllogise.mjs`'s currently-flat
892
+ provenance tag, sketched but unbuilt.
893
+
894
+ Every item above is honestly labeled speculative — a direction recorded so it isn't
895
+ re-discovered from scratch, not a committed build plan. None of it is scheduled; the phases above
896
+ this line are still the actual near-term work.
815
897
 
816
898
  ### Tone-of-voice adaptation (dropped from Phase 6, 2026-07-05)
817
899
  Per-voice synonym/phrase substitution over prose spans. Dropped because tmct's protected-span
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polycode-projects/the-mechanical-code-talker",
3
- "version": "0.9.9",
3
+ "version": "0.9.11",
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/ask-vocab.mjs CHANGED
@@ -157,6 +157,12 @@ export const RELATIONS = {
157
157
  "change alongside", "shares commits with", "share commits with",
158
158
  "tends to change together with", "tend to change together with",
159
159
  "moves together with", "move together with",
160
+ // Track-1 trio (temporal lever): the bare "changed/change together with" form
161
+ // (no "tends to"/"tend to" prefix) was missing outright — "which modules
162
+ // changed together with X" fell through to the "touch(ed)" verb instead (a
163
+ // Commit->Module kind, structurally unable to match a Module subject), always
164
+ // producing a confidently-empty answer regardless of real cochange data.
165
+ "changed together with", "change together with", "changes together with",
160
166
  ],
161
167
  },
162
168
  reexports: {
package/src/ask.mjs CHANGED
@@ -2159,6 +2159,21 @@ export function traverse(graph, parsed, { contextId = null, prev = null } = {})
2159
2159
  // Module individuals and a FINER entityType was asked for do we refine via `defines`
2160
2160
  // (imports) — never blindly treat an edge's subject id as if it were always a module id.
2161
2161
  let edges = kindsFor(kind).flatMap((k) => edgesOfKind(graph, k)).filter((e) => e.object === gObjMatch.id);
2162
+ // cochange (Module<->Module, mgx:changeCoupledWith) is a SYMMETRIC relation but
2163
+ // stored as ONE directed edge per pair (extractor convention, not a meaningful
2164
+ // subject/object direction) — "which modules cochange with X" must also match
2165
+ // when X is the STORED SUBJECT of the pair, reading the OTHER endpoint (Track-1
2166
+ // trio, temporal lever). Flip subject<->object on that side so the subjects-
2167
+ // collection loop below (which reads e.subject) picks up the partner uniformly;
2168
+ // the object-side match above is untouched, so an existing non-empty answer is
2169
+ // byte-identical.
2170
+ if (kind === "cochange") {
2171
+ edges = edges.concat(
2172
+ kindsFor(kind).flatMap((k) => edgesOfKind(graph, k))
2173
+ .filter((e) => e.subject === gObjMatch.id)
2174
+ .map((e) => ({ ...e, subject: e.object, object: e.subject })),
2175
+ );
2176
+ }
2162
2177
  let extNote = "";
2163
2178
  if (!edges.length && gObjMatch.class) {
2164
2179
  // Unresolved ext:<Name> endpoints with the SAME name as the resolved entity:
package/src/chat.mjs CHANGED
@@ -1530,6 +1530,23 @@ function renderFactLine(f) {
1530
1530
  return `i learned: ${factPhrase(f)}${cite}`;
1531
1531
  }
1532
1532
 
1533
+ /** PROOF-CHAIN RECEIPT (PLAN_INFERENCE_TESTING.md §4 stage 2; ROADMAP L788's
1534
+ * "renderable as a chain of thought in words"): render an ordered list of
1535
+ * premise Fact rows as one continuous argument — "cache is a kind of store;
1536
+ * store is a kind of component; so redis.mjs is a component" — each premise
1537
+ * cited via the SAME factPhrase + "(source: …)" convention renderFactLine
1538
+ * uses, just without its "you told me"/"i learned" framing (a chain reads as
1539
+ * one derivation, not a list of standalone recollections). The conclusion
1540
+ * clause is spelled directly from the first premise's subject and the last
1541
+ * premise's object — sound for any chain length, though today's only caller
1542
+ * (the live cax-sco/scm-sco chase below) ever passes exactly two. */
1543
+ function renderIsaChain(premises) {
1544
+ const step = (f) => `${factPhrase(f)}${f.provenance ? ` (source: ${f.provenance})` : ""}`;
1545
+ const first = premises[0];
1546
+ const last = premises[premises.length - 1];
1547
+ return `${premises.map(step).join("; ")}; so ${first.subject} is a ${last.object}`;
1548
+ }
1549
+
1533
1550
  /** Read every reified Fact out of the memory graph as plain {subject, predicate,
1534
1551
  * object, provenance} rows. Lazy + failure-tolerated: no memory → []. */
1535
1552
  async function memoryFacts(memoryDir) {
@@ -1892,6 +1909,40 @@ async function factReadBack(memoryDir, query, envelope, miss, graph = null) {
1892
1909
  };
1893
1910
  }
1894
1911
  }
1912
+ // LIVE cax-sco / scm-sco PROOF CHASE (PLAN_INFERENCE_TESTING.md INF-A2,
1913
+ // §4 stage 1): a direct isa fact and the graph inherits-bridge both
1914
+ // missed — chase a chain over TWO TAUGHT isa-family facts (§1's PARTIAL
1915
+ // note: "cax-sco over two TAUGHT facts is NOT implemented"; the band's own
1916
+ // "Rules needed" column: "⊑-chain of length 2") via syllogise.mjs's
1917
+ // findIsaChain, a rooted proof search built on the SAME two rule kernels,
1918
+ // LIVE and READ-ONLY (nothing is written — the offline `tmct syllogise`
1919
+ // batch pass, materializing the same two rules with `entailed:*`
1920
+ // provenance, is the persisting counterpart). Deliberately narrow, twice
1921
+ // over, to stay exactly in INF-A2's scope and not silently answer bands
1922
+ // this stage doesn't (yet) certify:
1923
+ // - maxHops:2 — a longer taught chain is INF-B2's multi-hop +
1924
+ // proof-chain-materialization territory (§4 stage 2 proper), which
1925
+ // INFBENCH pins as an honest ceiling until it lands — answering
1926
+ // "yes" there today would be graded FABRICATION, not credit.
1927
+ // - CORPUS-sourced edges excluded — the bulk background corpus band
1928
+ // (trust 0.7) can coincidentally chain two unrelated classes into a
1929
+ // technically-true-per-ConceptNet "yes" that has nothing to do with
1930
+ // what the OPERATOR taught; only operator/teach/entailed-sourced isa
1931
+ // facts are chased, matching "TAUGHT" in the gap's own name.
1932
+ const { findIsaChain, SUBCLASS_PREDICATE: SC_PREDICATE, TYPE_PREDICATE: RDF_TYPE_PREDICATE } = await import("./syllogise.mjs");
1933
+ const isTaught = (f) => !f.sourceTypes?.includes("corpus") && !f.sourceTypes?.includes("web");
1934
+ const chainSubClassRows = isa.filter((f) => f.predicate === SC_PREDICATE && isTaught(f));
1935
+ const chainTypeRows = isa.filter((f) => f.predicate === RDF_TYPE_PREDICATE && isTaught(f));
1936
+ const chainSubClassEdges = chainSubClassRows.map((f) => [f.subject, f.object]);
1937
+ const chainTypeEdges = chainTypeRows.map((f) => [f.subject, f.object]);
1938
+ const factForStep = (step) => (step.predicate === SC_PREDICATE ? chainSubClassRows : chainTypeRows)
1939
+ .find((f) => f.subject === step.subject && f.object === step.object);
1940
+ for (const subj of subjCandidates) {
1941
+ const chain = findIsaChain(subj, objVariants, chainTypeEdges, chainSubClassEdges, { maxHops: 2 });
1942
+ if (!chain) continue;
1943
+ const premises = chain.map(factForStep);
1944
+ if (premises.every(Boolean)) return { text: `yes — ${renderIsaChain(premises)}`, replace: true };
1945
+ }
1895
1946
  return null; // no remembered fact — the honest miss stands (never a guessed "no")
1896
1947
  }
1897
1948
 
@@ -2478,13 +2529,26 @@ async function runAsk(query, { config, source, graph, focus, last, templates, me
2478
2529
  note(trace, `lane: (1) META/SELF — bare self/session question recognized, answered via="${meta.via}"`);
2479
2530
  }
2480
2531
  }
2481
- if (!handled && miss && isConversational(query)) {
2532
+ if (!handled && miss && !envelope?.parsed && isConversational(query)) {
2482
2533
  // A conversational miss (a greeting, "what can you do", a very short non-code
2483
2534
  // line) gets the friendly orientation (module-aware: empty → --repo/tmct init).
2484
2535
  // Bug B1 (0.8.2 follow-up): this branch carries via:"template" and never
2485
2536
  // reaches the composed-only wall-shortening gate below, so a second
2486
2537
  // identical orientation-class turn used to repeat the full blurb verbatim —
2487
2538
  // collapse to a one-liner on that repeat, mirroring WALL_REPEAT_ONELINER.
2539
+ //
2540
+ // `!envelope?.parsed` (Track-1 trio, pronoun/focus binding — "biggest movable
2541
+ // mass"): isConversational() is a TEXT-ONLY heuristic (≤3 words, no code-ish
2542
+ // token) — it has no way to know the query already compiled to a real
2543
+ // structural AST shape. A pronoun-shortened follow-up ("who touched it"/
2544
+ // "that"/"this") is exactly 3 words and "touched" isn't in STRUCT_WORDS, so
2545
+ // isConversational used to fire AFTER ask() had already parsed the reverse
2546
+ // "touches" shape, resolved the pronoun off the focus, run the traversal, and
2547
+ // composed an honest (possibly empty) answer — discarding that correct answer
2548
+ // for the generic orientation wall. When envelope.parsed stood, the query WAS
2549
+ // structural (by construction, not word-count guesswork); its own composed
2550
+ // answer — hit, honest empty, or "it needs a referent" — is always more
2551
+ // truthful than the orientation card.
2488
2552
  const orientation = orientationAnswer(templates, graph);
2489
2553
  const repeat = last?.answer === orientation;
2490
2554
  answer = repeat ? ORIENTATION_REPEAT_ONELINER : orientation;
package/src/syllogise.mjs CHANGED
Binary file