@polycode-projects/the-mechanical-code-talker 6.0.20 → 6.0.22

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 (38) hide show
  1. package/README.md +5 -15
  2. package/bin/tmct.mjs +8 -3
  3. package/package.json +1 -5
  4. package/src/adapters/memory/core.mjs +108 -96
  5. package/src/adapters/memory/corpus-bands.mjs +6 -0
  6. package/src/domain/agent-traits.mjs +1 -1
  7. package/src/domain/answer-variants.json +1 -1
  8. package/src/domain/cli-verbs.mjs +1 -0
  9. package/src/domain/memory/causal-stability.mjs +22 -5
  10. package/src/domain/memory/fact-order.mjs +3 -3
  11. package/src/domain/memory/provenance-time.mjs +35 -0
  12. package/src/domain/memory/retraction.mjs +3 -5
  13. package/src/domain/memory/trust.mjs +11 -11
  14. package/src/domain/news-feed.mjs +1 -1
  15. package/src/domain/seeded-random.mjs +6 -6
  16. package/src/services/adventure.mjs +10 -41
  17. package/src/services/chat-page-viz.mjs +12 -1111
  18. package/src/services/chat-session.mjs +20 -6
  19. package/src/services/chat.mjs +269 -197
  20. package/src/services/extract-facts.mjs +1 -1
  21. package/src/services/import-file.mjs +1 -1
  22. package/src/services/mud-viz.mjs +21 -1082
  23. package/src/services/mudiii-viz.mjs +0 -4
  24. package/src/services/news.mjs +44 -24
  25. package/src/services/pill-complete.mjs +5 -8
  26. package/src/services/predator-prey.mjs +3 -5
  27. package/src/surfaces/web/memory-ask-browser.bundle.js +107 -107
  28. package/src/surfaces/web/mud-browser-entry.mjs +8 -48
  29. package/test-benchmarks/agentbench/README.md +7 -10
  30. package/src/adapters/p2p/webrtc-transport.mjs +0 -169
  31. package/src/domain/p2p/facts.mjs +0 -102
  32. package/src/domain/p2p/peer-id.mjs +0 -47
  33. package/src/domain/p2p/provenance-relabel.mjs +0 -37
  34. package/src/domain/p2p/sync-filter.mjs +0 -43
  35. package/src/domain/p2p/wire.mjs +0 -126
  36. package/src/services/p2p-room.mjs +0 -848
  37. package/src/services/share-overlay-viz.mjs +0 -623
  38. package/src/surfaces/web/p2p-browser-entry.mjs +0 -39
@@ -24,10 +24,6 @@
24
24
  // scenario swaps those first two calls for `.bootRiver(...)` once and
25
25
  // `.applyRiver(...)` per crossing; the same stage draws the river.
26
26
  //
27
- // Deliberately absent, all P2P (mud.html's #statePill, share/join buttons,
28
- // the share overlay, the wave button): this is the 1-player page. A later
29
- // document adds sharing back from the same bundle.
30
- //
31
27
  // The page publishes through the ONE `globalThis.tmct` surface
32
28
  // (tmct-surface.mjs), never a page-scoped bag of its own, and
33
29
  // `createTicker`/`createSerialQueue` are spliced into the page script from
@@ -953,47 +953,67 @@ async function ingestResearchArticle(ctx, term, provider, article) {
953
953
  return { facts: distinct.size, derived };
954
954
  }
955
955
 
956
- // The one band this fallback reads. WordNet is dictionary content — real
957
- // words, not news entities — so it grounds the everyday nouns a headline
958
- // mentions in passing ("harbor", "senator") without ever costing a KB round
959
- // trip on those.
960
- const BAND_TERM_LOOKUP_BAND = "wordnet-complete";
956
+ // The bands this fallback reads. All three are reference content — dictionary
957
+ // senses and everyday commonsense edges, not news entities — so they ground
958
+ // the ordinary nouns a headline mentions in passing ("harbor", "senator",
959
+ // "penguin") without ever costing a KB round trip on those.
960
+ const BAND_TERM_LOOKUP_BANDS = Object.freeze(["child", "conceptnet", "wordnet-complete"]);
961
961
  const BAND_TERM_LOOKUP_LIMIT = 50;
962
962
  // A local DynamoDB Query has no courtesy throttle and nothing external to
963
963
  // protect, but it still has to return: the enrich cycle shares the same wall
964
964
  // budget every other phase does, and this runs once per candidate term. A
965
965
  // slow or hung Query loses the race and reads as a miss — a timeout is a
966
966
  // miss, never a guess — rather than stalling the whole cycle behind it.
967
+ // The bands are read in parallel against one deadline, so the budget buys
968
+ // every band at once: each is a single-partition begins_with read of its own,
969
+ // and the worst case stays one timeout however many bands there are.
967
970
  const BAND_TERM_LOOKUP_TIMEOUT_MS = 750;
968
971
 
969
- /** `term`'s rows from the wordnet-complete band, as `{subject, predicate,
970
- * object, provenance}` triples ready for `appendFacts` — or `[]` when the
971
- * band carries nothing for it, the query errors, or it doesn't return in
972
- * time. `ctx.providers.queryBandTerm` is absent on the browser surface and
973
- * in most tests, so this is a no-op there by construction, not a special
974
- * case here. */
975
- async function groundTermFromBand(ctx, term) {
976
- const queryBandTerm = ctx.providers?.queryBandTerm;
977
- if (typeof queryBandTerm !== "function") return [];
978
- const timeout = new Promise((resolve) => { setTimeout(() => resolve(null), BAND_TERM_LOOKUP_TIMEOUT_MS); });
972
+ /** `term`'s rows from one band, as `{subject, predicate, object, provenance}`
973
+ * triples — or `[]` when the band carries nothing for it or the Query
974
+ * throws. A band that fails is a band with nothing to say, so the others'
975
+ * rows survive it. */
976
+ async function bandTermFacts(queryBandTerm, band, term) {
979
977
  let response;
980
978
  try {
981
- response = await Promise.race([
982
- queryBandTerm({ band: BAND_TERM_LOOKUP_BAND, term, limit: BAND_TERM_LOOKUP_LIMIT }),
983
- timeout,
984
- ]);
979
+ response = await queryBandTerm({ band, term, limit: BAND_TERM_LOOKUP_LIMIT });
985
980
  } catch {
986
981
  return [];
987
982
  }
988
- if (!response) return [];
989
983
  const facts = [];
990
- for (const row of response.rows || []) {
984
+ for (const row of response?.rows || []) {
991
985
  const fact = factFromBandRow(row);
992
986
  if (fact) facts.push(fact);
993
987
  }
994
988
  return facts;
995
989
  }
996
990
 
991
+ /** `term`'s rows from every band, as `{subject, predicate, object,
992
+ * provenance}` triples ready for `appendFacts` — or `[]` when no band
993
+ * carries it. Each band's Query races the SAME deadline, so a band that
994
+ * hangs costs the cycle one timeout rather than one per band, and the bands
995
+ * that answered inside it keep their rows. A fact both a band and the seed
996
+ * already hold arrives with the band's own provenance, so it corroborates
997
+ * rather than duplicating. `ctx.providers.queryBandTerm` is absent on the
998
+ * browser surface and in most tests, so this is a no-op there by
999
+ * construction, not a special case here. */
1000
+ async function groundTermFromBand(ctx, term) {
1001
+ const queryBandTerm = ctx.providers?.queryBandTerm;
1002
+ if (typeof queryBandTerm !== "function") return [];
1003
+ let deadlineTimer;
1004
+ const deadline = new Promise((resolve) => {
1005
+ deadlineTimer = setTimeout(() => resolve(null), BAND_TERM_LOOKUP_TIMEOUT_MS);
1006
+ });
1007
+ try {
1008
+ const perBand = await Promise.all(BAND_TERM_LOOKUP_BANDS.map(
1009
+ (band) => Promise.race([bandTermFacts(queryBandTerm, band, term), deadline]),
1010
+ ));
1011
+ return perBand.flatMap((facts) => facts || []);
1012
+ } finally {
1013
+ clearTimeout(deadlineTimer);
1014
+ }
1015
+ }
1016
+
997
1017
  /** Grounds `term` from `facts` — a band's own rows, already resolved
998
1018
  * `{subject, predicate, object, provenance}` triples with no article prose
999
1019
  * to walk, so this skips straight to append + syllogise rather than
@@ -1084,10 +1104,10 @@ export async function enrichTopTerms(ctx, { limit } = {}) {
1084
1104
  if (aborted) { markTerm(ledger, entry.term, "pending", nowVal); break; }
1085
1105
  if (!hit) {
1086
1106
  // Every configured KB source came back empty (or none is configured) —
1087
- // try the wordnet-complete band before giving up. It's another source
1088
- // the resolver can reach, not a replacement for the KB walk above: a
1107
+ // try the corpus bands before giving up. They're another source the
1108
+ // resolver can reach, not a replacement for the KB walk above: a
1089
1109
  // headline's proper nouns still need a KB lookup, but its everyday
1090
- // vocabulary is often already sitting in the band.
1110
+ // vocabulary is often already sitting in a band.
1091
1111
  const bandFacts = await groundTermFromBand(ctx, entry.term);
1092
1112
  if (bandFacts.length) {
1093
1113
  const res = await ingestBandFacts(ctx, bandFacts);
@@ -32,8 +32,7 @@
32
32
  // these exact names, because createPillComplete calls the other two by bare
33
33
  // name at runtime and that call only resolves if all three sit as siblings
34
34
  // in the same inline script. `pillCompleteMarkup` is different: it is a
35
- // markup BUILDER, the same role `shareOverlayHtml` plays in
36
- // share-overlay-viz.mjs — it runs once, server/module-side, to produce the
35
+ // markup BUILDER it runs once, server/module-side, to produce the
37
36
  // initial HTML string a page embeds, and is never spliced into the client
38
37
  // script. That is the only reason it may (and does) import `escapeHtml`.
39
38
  //
@@ -189,10 +188,9 @@ export function matchPills(candidates, typed, opts = {}) {
189
188
  * caller can `getElementById` them right after inserting this markup, before
190
189
  * constructing `createPillComplete`.
191
190
  *
192
- * Runs once at page-render time (module- or server-side), the same role
193
- * `shareOverlayHtml` plays in share-overlay-viz.mjs it is NOT one of the
194
- * three functions an adopting page splices into its inline script, so it is
195
- * the one export in this module allowed to import `escapeHtml`.
191
+ * Runs once at page-render time (module- or server-side) it is NOT one of
192
+ * the three functions an adopting page splices into its inline script, so it
193
+ * is the one export in this module allowed to import `escapeHtml`.
196
194
  */
197
195
  export function pillCompleteMarkup({ inputId, inputHtml }) {
198
196
  const esc = escapeHtml;
@@ -446,8 +444,7 @@ export function createPillComplete({ input, ghostEl, statusEl, railEl, getCandid
446
444
  * the one exception: it is structural, not a themed colour choice — the
447
445
  * ghost text sits in a layer BEHIND the input, so the input has to be
448
446
  * see-through for the ghost's suffix to read at all. Themed through `--pc-*`
449
- * custom properties defaulting to the site's shared tokens, the way
450
- * share-overlay-viz.mjs's `--so-*` variables do.
447
+ * custom properties defaulting to the site's shared tokens.
451
448
  */
452
449
  export const PILL_COMPLETE_CSS = `
453
450
  .pc-field {
@@ -168,9 +168,7 @@ const MUDIII_STATE_PREDICATE_SET = new Set([
168
168
  * board, who put it there, and the class and model a mid-play mint needs. */
169
169
  export const MUDIII_STATE_PREDICATES = Object.freeze([...MUDIII_STATE_PREDICATE_SET].sort());
170
170
 
171
- /** Whether `predicate` carries live town-square state. The P2P sync filter
172
- * reads this to tell a fact a turn produced from the page chrome around it.
173
- * Pure. */
171
+ /** Whether `predicate` carries live town-square state. Pure. */
174
172
  export function isMudiiiStatePredicate(predicate) {
175
173
  const p = String(predicate || "");
176
174
  return MUDIII_STATE_PREDICATE_SET.has(p) || EXIT_PREDICATE_RE.test(p);
@@ -204,8 +202,8 @@ export function seededSpawnCell(options, { layoutName, epoch = 0, turn = 0, id }
204
202
  *
205
203
  * Rows rank by the (epoch, turn) pair, exactly as adventure.mjs's
206
204
  * foldWorldState does, so a recast can never be outranked by the run it
207
- * replaced: a peer's turn-9 snapshot from before the recast loses to a turn-1
208
- * snapshot written after it. An unstamped row carries no stamp of its own and
205
+ * replaced: a turn-9 row written before the recast loses to a turn-1 row
206
+ * written after it. An unstamped row carries no stamp of its own and
209
207
  * ranks as turn 0 of the CURRENT epoch — the world pack's own rows are
210
208
  * exactly the state a fresh run starts from.
211
209
  *