@polycode-projects/the-mechanical-code-talker 1.10.13 → 1.11.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.
- package/README.md +115 -101
- package/ROADMAP.md +17 -4
- package/bin/tmct.mjs +115 -9
- package/data/games/crates.txt +24 -0
- package/data/games/hanoi-3.txt +30 -0
- package/package.json +1 -1
- package/src/ask-browser.bundle.js +129 -398
- package/src/chat.mjs +613 -13
- package/src/domain.mjs +271 -0
- package/src/import-file.mjs +86 -0
- package/src/init.mjs +46 -1
- package/src/ledger-viz.mjs +613 -0
- package/src/memory/core.mjs +80 -16
- package/src/memory/shacl.mjs +17 -7
- package/src/memory-ask-browser-entry.mjs +4 -2
- package/src/memory-ask-browser.bundle.js +5157 -1165
- package/src/plan-viz.mjs +410 -0
- package/src/router/guardrail.mjs +5 -0
- package/src/router/registry.mjs +55 -11
- package/src/router/taught.mjs +73 -0
- package/src/sentences.mjs +19 -0
- package/src/viz-theme.mjs +50 -0
- package/src/viz.mjs +2 -2
- package/src/wink-model.mjs +12 -6
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
var createRequireFromPath = unavailable("createRequireFromPath");
|
|
63
63
|
var spawnSync = unavailable("spawnSync");
|
|
64
64
|
var createInterface = unavailable("createInterface");
|
|
65
|
+
var createServer = unavailable("createServer");
|
|
65
66
|
var DatabaseSync = unavailable("DatabaseSync");
|
|
66
67
|
|
|
67
68
|
// node-stub:node:path
|
|
@@ -92,6 +93,7 @@
|
|
|
92
93
|
var createRequireFromPath2 = unavailable2("createRequireFromPath");
|
|
93
94
|
var spawnSync2 = unavailable2("spawnSync");
|
|
94
95
|
var createInterface2 = unavailable2("createInterface");
|
|
96
|
+
var createServer2 = unavailable2("createServer");
|
|
95
97
|
var DatabaseSync2 = unavailable2("DatabaseSync");
|
|
96
98
|
|
|
97
99
|
// node-stub:node:url
|
|
@@ -121,6 +123,7 @@
|
|
|
121
123
|
var createRequireFromPath3 = unavailable3("createRequireFromPath");
|
|
122
124
|
var spawnSync3 = unavailable3("spawnSync");
|
|
123
125
|
var createInterface3 = unavailable3("createInterface");
|
|
126
|
+
var createServer3 = unavailable3("createServer");
|
|
124
127
|
var DatabaseSync3 = unavailable3("DatabaseSync");
|
|
125
128
|
|
|
126
129
|
// node-stub:node:fs/promises
|
|
@@ -149,6 +152,7 @@
|
|
|
149
152
|
var createRequireFromPath4 = unavailable4("createRequireFromPath");
|
|
150
153
|
var spawnSync4 = unavailable4("spawnSync");
|
|
151
154
|
var createInterface4 = unavailable4("createInterface");
|
|
155
|
+
var createServer4 = unavailable4("createServer");
|
|
152
156
|
var DatabaseSync4 = unavailable4("DatabaseSync");
|
|
153
157
|
|
|
154
158
|
// src/memory/trust.mjs
|
|
@@ -198,11 +202,36 @@
|
|
|
198
202
|
var RULE_KIND_COMPOSE2 = "compose2";
|
|
199
203
|
var RULE_KIND_FILTER = "filter";
|
|
200
204
|
var RULE_KIND_RECURSIVE = "recursive";
|
|
201
|
-
var
|
|
205
|
+
var RULE_KIND_ACTION_SIGNATURE = "action-signature";
|
|
206
|
+
var RULE_KIND_ACTION_PRECOND = "action-precond";
|
|
207
|
+
var RULE_KIND_ACTION_EFFECT = "action-effect";
|
|
208
|
+
var RULE_KINDS = Object.freeze([
|
|
209
|
+
RULE_KIND_COMPOSE2,
|
|
210
|
+
RULE_KIND_FILTER,
|
|
211
|
+
RULE_KIND_RECURSIVE,
|
|
212
|
+
RULE_KIND_ACTION_SIGNATURE,
|
|
213
|
+
RULE_KIND_ACTION_PRECOND,
|
|
214
|
+
RULE_KIND_ACTION_EFFECT
|
|
215
|
+
]);
|
|
202
216
|
var RULE_SLOT_SPEC = {
|
|
203
217
|
[RULE_KIND_COMPOSE2]: [["base1", "mgx:ruleBase1"], ["base2", "mgx:ruleBase2"]],
|
|
204
218
|
[RULE_KIND_FILTER]: [["base", "mgx:ruleBase1"], ["property", "mgx:ruleFilterProperty"]],
|
|
205
|
-
[RULE_KIND_RECURSIVE]: [["baseCase", "mgx:ruleBaseCase"], ["recStep", "mgx:ruleRecStep"]]
|
|
219
|
+
[RULE_KIND_RECURSIVE]: [["baseCase", "mgx:ruleBaseCase"], ["recStep", "mgx:ruleRecStep"]],
|
|
220
|
+
[RULE_KIND_ACTION_SIGNATURE]: [
|
|
221
|
+
["subjectClass", "mgx:ruleActionSubjectClass"],
|
|
222
|
+
["targetClass", "mgx:ruleActionTargetClass"]
|
|
223
|
+
],
|
|
224
|
+
[RULE_KIND_ACTION_PRECOND]: [
|
|
225
|
+
["shape", "mgx:ruleActionPrecondShape"],
|
|
226
|
+
["predicate", "mgx:ruleActionPrecondPredicate"],
|
|
227
|
+
["role", "mgx:ruleActionPrecondRole"],
|
|
228
|
+
["scope", "mgx:ruleActionPrecondScope"]
|
|
229
|
+
],
|
|
230
|
+
[RULE_KIND_ACTION_EFFECT]: [
|
|
231
|
+
["predicate", "mgx:ruleActionEffectPredicate"],
|
|
232
|
+
["subjectRole", "mgx:ruleActionEffectSubject"],
|
|
233
|
+
["objectRole", "mgx:ruleActionEffectObject"]
|
|
234
|
+
]
|
|
206
235
|
};
|
|
207
236
|
|
|
208
237
|
// src/codegraph.mjs
|
|
@@ -228,10 +257,7 @@
|
|
|
228
257
|
relations,
|
|
229
258
|
truncated,
|
|
230
259
|
generatedAt: payload?.generated_at || null,
|
|
231
|
-
//
|
|
232
|
-
// byte-identical from the payload so ask.mjs's resolveObject can consult it as a
|
|
233
|
-
// fallback tier without reaching back into the raw payload itself. {} when the
|
|
234
|
-
// build had prose disabled or the payload predates this field.
|
|
260
|
+
// word -> [individual ids]; {} when prose was disabled at build time
|
|
235
261
|
proseIndex: payload?.proseIndex || {}
|
|
236
262
|
};
|
|
237
263
|
}
|
|
@@ -246,9 +272,7 @@
|
|
|
246
272
|
"seon:hassupertype": "inherits",
|
|
247
273
|
"mgx:changecoupledwith": "cochange",
|
|
248
274
|
"mgx:reexports": "reexports",
|
|
249
|
-
//
|
|
250
|
-
// These stay SEPARATE kinds from the module-coarse "touches"/"calls" so the impact
|
|
251
|
-
// closure (module-coarse) is unchanged.
|
|
275
|
+
// symbol-level edges stay separate kinds so the module-coarse impact closure is unchanged
|
|
252
276
|
"mgx:touchessymbol": "touchesSymbol",
|
|
253
277
|
"mgx:callssymbol": "callsSymbol",
|
|
254
278
|
// legacy tokens (pre-realign graphs) — kept so a stale artifact still classifies
|
|
@@ -261,20 +285,12 @@
|
|
|
261
285
|
"mg:defines": "defines",
|
|
262
286
|
"mg:tests": "tests",
|
|
263
287
|
"mg:touches": "touches",
|
|
264
|
-
// memory-graph predicates
|
|
265
|
-
// itself as its own kind name (no module-rollup abbreviation needed, unlike
|
|
266
|
-
// imports/calls) so adjacencyForKinds/edgesOfKind can walk the memory graph too.
|
|
288
|
+
// memory-graph predicates map to themselves so adjacencyForKinds/edgesOfKind can walk them too
|
|
267
289
|
"mgx:saidinsession": "saidInSession",
|
|
268
290
|
"mgx:inreplyto": "inReplyTo",
|
|
269
291
|
"mgx:statedby": "statedBy",
|
|
270
292
|
"mgx:canonicalisedfrom": "canonicalisedFrom",
|
|
271
|
-
//
|
|
272
|
-
// deriveFactTermGraph (below) synthesizes on every Fact — Fact -> its own
|
|
273
|
-
// subject/object Term individual. Without these a walk seeded on a Fact (the
|
|
274
|
-
// default mostRecentIndividual seed right after a teach turn) could never
|
|
275
|
-
// reach the term graph at all. Distinct from the per-predicate kinds below
|
|
276
|
-
// (an open-ended, DYNAMIC set — see relationKind's "factrel:" branch), these
|
|
277
|
-
// two are fixed and few, so a plain PROP_KIND row is the simplest fit.
|
|
293
|
+
// structural links deriveFactTermGraph synthesizes on every Fact (Fact -> its own subject/object Term)
|
|
278
294
|
"mgx:factsubjectterm": "factSubjectTerm",
|
|
279
295
|
"mgx:factobjectterm": "factObjectTerm"
|
|
280
296
|
};
|
|
@@ -723,8 +739,8 @@
|
|
|
723
739
|
imports: {
|
|
724
740
|
comment: "Module -> Module: subject's import graph references object (usesComplexType).",
|
|
725
741
|
verbs: [
|
|
726
|
-
// formal/neutral ("uses
|
|
727
|
-
//
|
|
742
|
+
// formal/neutral ("uses code from" stays here: its phrasing is
|
|
743
|
+
// specifically import-flavored)
|
|
728
744
|
"couples to",
|
|
729
745
|
"couple to",
|
|
730
746
|
"depends on",
|
|
@@ -753,17 +769,12 @@
|
|
|
753
769
|
"are wired to",
|
|
754
770
|
"is hooked up to",
|
|
755
771
|
"are hooked up to",
|
|
756
|
-
// gerund (g-drop normalization turns dialectal "importin'" into this
|
|
772
|
+
// gerund (g-drop normalization turns dialectal "importin'" into this)
|
|
757
773
|
"importing"
|
|
758
774
|
]
|
|
759
775
|
},
|
|
760
|
-
//
|
|
761
|
-
//
|
|
762
|
-
// graph, so ask.mjs traverses it as imports + calls + callsSymbol together
|
|
763
|
-
// (KIND_UNIONS there). The verbs moved here FROM imports — "which modules use X"
|
|
764
|
-
// still answers with the importing modules (the asked Module grain filters the
|
|
765
|
-
// union down to module-grain subjects), and "what uses <function>" now also
|
|
766
|
-
// reaches the symbol-grain callers instead of silently ignoring them.
|
|
776
|
+
// query-side union, not a stored predicate: ask.mjs traverses "uses" as
|
|
777
|
+
// imports + calls + callsSymbol together (KIND_UNIONS).
|
|
767
778
|
uses: {
|
|
768
779
|
comment: "query-side union: imports (Module->Module) + calls (Module->Module) + callsSymbol (fn->fn).",
|
|
769
780
|
verbs: [
|
|
@@ -772,7 +783,7 @@
|
|
|
772
783
|
"used by",
|
|
773
784
|
"makes use of",
|
|
774
785
|
"make use of",
|
|
775
|
-
// gerund (g-drop normalization
|
|
786
|
+
// gerund (g-drop normalization)
|
|
776
787
|
"using"
|
|
777
788
|
]
|
|
778
789
|
},
|
|
@@ -798,7 +809,7 @@
|
|
|
798
809
|
"fire",
|
|
799
810
|
"kicks off",
|
|
800
811
|
"kick off",
|
|
801
|
-
// gerund (g-drop normalization turns dialectal "callin'" into this
|
|
812
|
+
// gerund (g-drop normalization turns dialectal "callin'" into this)
|
|
802
813
|
"calling"
|
|
803
814
|
]
|
|
804
815
|
},
|
|
@@ -813,7 +824,7 @@
|
|
|
813
824
|
"have",
|
|
814
825
|
"holds",
|
|
815
826
|
"hold",
|
|
816
|
-
// gerund (g-drop normalization
|
|
827
|
+
// gerund (g-drop normalization)
|
|
817
828
|
"defining"
|
|
818
829
|
]
|
|
819
830
|
},
|
|
@@ -832,7 +843,7 @@
|
|
|
832
843
|
"sit in",
|
|
833
844
|
"sits inside",
|
|
834
845
|
"sit inside",
|
|
835
|
-
// gerund (g-drop normalization
|
|
846
|
+
// gerund (g-drop normalization)
|
|
836
847
|
"containing"
|
|
837
848
|
]
|
|
838
849
|
},
|
|
@@ -851,7 +862,7 @@
|
|
|
851
862
|
"check",
|
|
852
863
|
"makes sure of",
|
|
853
864
|
"make sure of",
|
|
854
|
-
// gerund (g-drop normalization
|
|
865
|
+
// gerund (g-drop normalization)
|
|
855
866
|
"testing"
|
|
856
867
|
]
|
|
857
868
|
},
|
|
@@ -860,15 +871,6 @@
|
|
|
860
871
|
verbs: [
|
|
861
872
|
"inherits from",
|
|
862
873
|
"inherit from",
|
|
863
|
-
// bare "inherits"/"inherit" (Tier 6 playtest, §3b surface-variation axis):
|
|
864
|
-
// this list's own SIBLING verb "extends"/"extend" already works bare, with
|
|
865
|
-
// no "from" required, but "inherits"/"inherit" — arguably the MORE common
|
|
866
|
-
// everyday phrasing of the two ("TaskController inherits Controller",
|
|
867
|
-
// "does TaskController inherit Controller") — had no bare form at all,
|
|
868
|
-
// only the "... from" variant. VERB_ALT's longest-first sort (already
|
|
869
|
-
// relied on elsewhere in this file for the same reason) means "inherits
|
|
870
|
-
// from"/"inherit from" still win whenever "from" actually follows, so
|
|
871
|
-
// this is purely additive.
|
|
872
874
|
"inherits",
|
|
873
875
|
"inherit",
|
|
874
876
|
"extends",
|
|
@@ -885,22 +887,13 @@
|
|
|
885
887
|
"are built off",
|
|
886
888
|
"is built on top of",
|
|
887
889
|
"are built on top of",
|
|
888
|
-
// gerund
|
|
889
|
-
//
|
|
890
|
-
// Both the two-word "inheriting from" (so "from" is consumed into the verb
|
|
891
|
-
// phrase, not the object term) and the bare "inheriting" (the single token
|
|
892
|
-
// the gerund-lead check reads) are listed; longest-match-first prefers the
|
|
893
|
-
// two-word form when "from" follows.
|
|
890
|
+
// gerund, incl. compositional grammar's gerund-led boolean gate
|
|
891
|
+
// ("classes inheriting from Base but not tested")
|
|
894
892
|
"extending",
|
|
895
893
|
"inheriting from",
|
|
896
894
|
"inheriting",
|
|
897
895
|
"subclassing",
|
|
898
896
|
"extends from",
|
|
899
|
-
// REVERSE phrasings (Seonix Batch 2 Fix 2, see INHERITS_REVERSE_VERB_LIST's own
|
|
900
|
-
// comment above): "is/are a|the superclass/parent class of" — folded in here so
|
|
901
|
-
// VERB_TO_KIND maps them to "inherits" like every other verb in this list; the
|
|
902
|
-
// subject/object SWAP their direction requires is handled at parse time by the
|
|
903
|
-
// strategies that build the "ask" shape, not here.
|
|
904
897
|
...INHERITS_REVERSE_VERB_LIST
|
|
905
898
|
]
|
|
906
899
|
},
|
|
@@ -923,13 +916,8 @@
|
|
|
923
916
|
"were tweaked in",
|
|
924
917
|
"got changed in",
|
|
925
918
|
"got edited in",
|
|
926
|
-
//
|
|
927
|
-
//
|
|
928
|
-
// "what did commit <sha> touch", "which functions changed in <sha>", "which
|
|
929
|
-
// changes landed in commit <sha>", "what was touched by commit <sha>". Bare
|
|
930
|
-
// "touch" completes the touched/touches pair for the "did … touch" auxiliary
|
|
931
|
-
// form; the "by"/"in" phrases are the passive/locative counterparts of forms
|
|
932
|
-
// already above (curated per register spread, not a thesaurus dump).
|
|
919
|
+
// the same touch relation asked from the commit's side ("what did
|
|
920
|
+
// commit <sha> touch")
|
|
933
921
|
"touch",
|
|
934
922
|
"touched by",
|
|
935
923
|
"modified by",
|
|
@@ -937,23 +925,15 @@
|
|
|
937
925
|
"changed in",
|
|
938
926
|
"landed in",
|
|
939
927
|
"land in",
|
|
940
|
-
//
|
|
941
|
-
//
|
|
942
|
-
// touch questions when the object is a commit — the sha-shaped object keeps
|
|
943
|
-
// them from firing on structural questions ("is X in the graph" has no verb
|
|
944
|
-
// match anyway). Judgment call: "is in" omitted — too generic without the
|
|
945
|
-
// past-tense anchor and risks matching containment phrasings.
|
|
928
|
+
// "was in"/"went into" only read as touch questions against a
|
|
929
|
+
// sha-shaped object
|
|
946
930
|
"was in",
|
|
947
931
|
"were in",
|
|
948
932
|
"went into",
|
|
949
933
|
"included in",
|
|
950
|
-
// when-question forms (2026-07-02 query families): "when was X last
|
|
951
|
-
// updated/edited" — bare past participles that only read naturally in the
|
|
952
|
-
// temporal shape; the when template routes them, but they are ordinary
|
|
953
|
-
// touches verbs so "which modules were updated ..." keeps working too.
|
|
954
934
|
"updated",
|
|
955
935
|
"edited",
|
|
956
|
-
// gerund (g-drop normalization
|
|
936
|
+
// gerund (g-drop normalization)
|
|
957
937
|
"touching"
|
|
958
938
|
]
|
|
959
939
|
},
|
|
@@ -971,19 +951,9 @@
|
|
|
971
951
|
"tend to change together with",
|
|
972
952
|
"moves together with",
|
|
973
953
|
"move together with",
|
|
974
|
-
// Track-1 trio (temporal lever): the bare "changed/change together with" form
|
|
975
|
-
// (no "tends to"/"tend to" prefix) was missing outright — "which modules
|
|
976
|
-
// changed together with X" fell through to the "touch(ed)" verb instead (a
|
|
977
|
-
// Commit->Module kind, structurally unable to match a Module subject), always
|
|
978
|
-
// producing a confidently-empty answer regardless of real cochange data.
|
|
979
954
|
"changed together with",
|
|
980
955
|
"change together with",
|
|
981
956
|
"changes together with",
|
|
982
|
-
// Present-tense bare form (Seonix Batch 4/5 follow-up): only the past tense
|
|
983
|
-
// "changed with" existed above — "what changes with X"/"what usually changes
|
|
984
|
-
// with X" fell through entirely (ENTITY_TO_TYPE's own "changes"->"Change"
|
|
985
|
-
// pseudo-type noun risked consuming the word first; see parseRelationalOrQualified's
|
|
986
|
-
// guard against exactly that in ask.mjs).
|
|
987
957
|
"changes with",
|
|
988
958
|
"change with",
|
|
989
959
|
"tends to change with",
|
|
@@ -1000,13 +970,9 @@
|
|
|
1000
970
|
"re-export",
|
|
1001
971
|
"passes through",
|
|
1002
972
|
"pass through",
|
|
1003
|
-
// API-surface phrasing (2026-07-02 query families): "what does <module>
|
|
1004
|
-
// expose". Bare "exposed" is NOT listed — the lemma tier maps it here when
|
|
1005
|
-
// an adapter is present, and "how does the API get exposed" has no
|
|
1006
|
-
// traversal either way (pinned as an honest miss in the tests).
|
|
1007
973
|
"exposes",
|
|
1008
974
|
"expose",
|
|
1009
|
-
// gerund (g-drop normalization
|
|
975
|
+
// gerund (g-drop normalization)
|
|
1010
976
|
"exporting"
|
|
1011
977
|
]
|
|
1012
978
|
}
|
|
@@ -1073,10 +1039,6 @@
|
|
|
1073
1039
|
methods: "Method",
|
|
1074
1040
|
class: "Class",
|
|
1075
1041
|
classes: "Class",
|
|
1076
|
-
// "mod"/"mods" (HANDOVER.md 2026-07-10 item 10): a rushed-dev abbreviation
|
|
1077
|
-
// prefix ("mod store.mjs imports") used to land in disambiguation instead of
|
|
1078
|
-
// resolving cleanly, since nothing recognized "mod" as this same Module noun
|
|
1079
|
-
// — same alias-of-Module trade "file"/"files" already make just above.
|
|
1080
1042
|
module: "Module",
|
|
1081
1043
|
modules: "Module",
|
|
1082
1044
|
mod: "Module",
|
|
@@ -1091,17 +1053,10 @@
|
|
|
1091
1053
|
variables: "GlobalVariable",
|
|
1092
1054
|
global: "GlobalVariable",
|
|
1093
1055
|
globals: "GlobalVariable",
|
|
1094
|
-
// "
|
|
1095
|
-
//
|
|
1096
|
-
//
|
|
1097
|
-
//
|
|
1098
|
-
// the given side. Mapped to the pseudo-type "Change" (not a node class): ask.mjs's
|
|
1099
|
-
// traverse() reads it as a wildcard over the touch traversal's results rather than
|
|
1100
|
-
// aliasing it to ONE real class and silently dropping the other grain of the
|
|
1101
|
-
// answer. Listed BEFORE commit/commits: findPhrase (ask.mjs) takes the first
|
|
1102
|
-
// same-length phrase in table order, so in "which changes touch commit <sha>" the
|
|
1103
|
-
// entity slot must consume "changes" and leave "commit <sha>" intact as the
|
|
1104
|
-
// object term.
|
|
1056
|
+
// "Change" is a pseudo-type, not a node class: ask.mjs's traverse() reads it
|
|
1057
|
+
// as a wildcard over touch-traversal results (module or symbol grain).
|
|
1058
|
+
// Listed before commit/commits since findPhrase takes the first
|
|
1059
|
+
// same-length match in table order.
|
|
1105
1060
|
change: "Change",
|
|
1106
1061
|
changes: "Change",
|
|
1107
1062
|
commit: "Commit",
|
|
@@ -1208,13 +1163,7 @@
|
|
|
1208
1163
|
"touchs": "touches",
|
|
1209
1164
|
"tuoches": "touches",
|
|
1210
1165
|
"touhced": "touched",
|
|
1211
|
-
// "touchd" (BENCHMARK_CONVERSATION_1.7.0.md routed backlog C3): the
|
|
1212
|
-
// dropped-vowel slip of "touched" — distinct from "touhced" above
|
|
1213
|
-
// (transposed letters), same curated-typo discipline.
|
|
1214
1166
|
"touchd": "touched",
|
|
1215
|
-
// WHERE_MARKERS typo (0.9.13 Tier-1 playtest): "defined" itself had no typo
|
|
1216
|
-
// entry, so "where is it defned" fell through to the bare-object search path
|
|
1217
|
-
// instead of the where-shape ("no module matching 'it defned' found").
|
|
1218
1167
|
"defned": "defined",
|
|
1219
1168
|
"chagned": "changed",
|
|
1220
1169
|
"chnaged": "changed",
|
|
@@ -1228,50 +1177,20 @@
|
|
|
1228
1177
|
"whcih": "which",
|
|
1229
1178
|
"wich": "which",
|
|
1230
1179
|
"whihc": "which",
|
|
1231
|
-
// "
|
|
1232
|
-
//
|
|
1233
|
-
// (unlike which/what/does/the above), so a plain dropped/transposed letter
|
|
1234
|
-
// fell straight through resolveObject and hit either the grammar wall or a
|
|
1235
|
-
// bogus "no module matching 'it defined'" search. "were" (the missing-h
|
|
1236
|
-
// homophone slip) is NOT curated here — it's a real word already load-bearing
|
|
1237
|
-
// as the TEMPORAL_AUX auxiliary ("when were the modules last touched"), so
|
|
1238
|
-
// that one typo is handled by its own anchored phrasing frame instead
|
|
1239
|
-
// (normalize.mjs PHRASING_FRAMES) to avoid clobbering the legitimate reading.
|
|
1180
|
+
// "were" (the missing-h homophone slip of "where") is NOT curated here —
|
|
1181
|
+
// it's a load-bearing TEMPORAL_AUX word ("when were the modules touched").
|
|
1240
1182
|
"wehre": "where",
|
|
1241
1183
|
"whre": "where",
|
|
1242
|
-
// "wat" (chatbench cycle 2, tf-wat-calls): the internet-casual spelling of
|
|
1243
|
-
// "what" — neither curated noise nor a restorable trigger typo, so "wat calls
|
|
1244
|
-
// fnAlpha" used to die as "couldn't resolve one of the terms". Restored here
|
|
1245
|
-
// so BOTH parse strategies and the relaxation cascade see the canonical
|
|
1246
|
-
// anchor; the correction regex's dotted-extension guard keeps a module
|
|
1247
|
-
// literally named "wat.mjs" untouched, same residual trade as every entry.
|
|
1248
1184
|
"waht": "what",
|
|
1249
1185
|
"wat": "what",
|
|
1250
|
-
// "dat" (BENCHMARK_CONVERSATION_1.7.0.md routed backlog C3): the internet-
|
|
1251
|
-
// casual spelling of "that" — same register as "wat"/"waht" just above,
|
|
1252
|
-
// curated rather than left to the generic fuzzy tier since "that" is a
|
|
1253
|
-
// load-bearing anchor word throughout this grammar (TEACH_RE's own
|
|
1254
|
-
// "remember that X", relative-clause objects, etc).
|
|
1255
1186
|
"dat": "that",
|
|
1256
1187
|
"dose": "does",
|
|
1257
1188
|
"doess": "does",
|
|
1258
1189
|
"teh": "the",
|
|
1259
|
-
// aggregate/list TRIGGER words (2026-07-02, trigger-typo work) — a typo of a count
|
|
1260
|
-
// or list trigger used to be DROPPED as unmatched by the relaxation cascade, losing
|
|
1261
|
-
// the aggregate/list INTENT entirely ("how manyn classes" → the count was lost);
|
|
1262
|
-
// curated here so the intended trigger is restored BEFORE parsing (the general
|
|
1263
|
-
// bounded fuzzy path in ask.mjs's cascade is the backstop for uncurated typos).
|
|
1264
1190
|
"manyn": "many",
|
|
1265
1191
|
"mnay": "many",
|
|
1266
1192
|
"amny": "many",
|
|
1267
1193
|
"mnany": "many",
|
|
1268
|
-
// "hwo" (Tier 6 playtest, §3b typo axis): a transposed-letter typo of "how" —
|
|
1269
|
-
// "hwo many classes are there" used to lose the aggregate/list trigger
|
|
1270
|
-
// outright ("how many" only reads as a count trigger when both words are
|
|
1271
|
-
// exact), same failure class as "manyn"/"mnay" just above, one word to the
|
|
1272
|
-
// left of it. "how" is grammar-owned via AGGREGATE_TRIGGERS' own "how many"/
|
|
1273
|
-
// "how much" entries (test/ask-vocab.test.mjs's canonical-value check
|
|
1274
|
-
// splits those multi-word triggers into individual words).
|
|
1275
1194
|
"hwo": "how",
|
|
1276
1195
|
"coutn": "count",
|
|
1277
1196
|
"conut": "count",
|
|
@@ -1338,14 +1257,6 @@
|
|
|
1338
1257
|
"btw",
|
|
1339
1258
|
"by the way",
|
|
1340
1259
|
"you",
|
|
1341
|
-
// "quick q" (BENCHMARK_CONVERSATION_1.8.14.md item 11): the casual abbreviated
|
|
1342
|
-
// sibling of GREETING_PREAMBLE_RE's own "quick question" clause (normalize.mjs)
|
|
1343
|
-
// — that frame requires a delimiter immediately after the greeting word
|
|
1344
|
-
// ("hey, quick question - …"), so it never matches "hey quick q, …" (no
|
|
1345
|
-
// delimiter between "hey" and "quick q"). Filler-stripping instead — this
|
|
1346
|
-
// list is matched word-boundary-anywhere, not anchored — closes the gap
|
|
1347
|
-
// without needing GREETING_PREAMBLE_RE's own stricter delimiter-position
|
|
1348
|
-
// shape.
|
|
1349
1260
|
"quick q"
|
|
1350
1261
|
]);
|
|
1351
1262
|
var CONTEXT_PRONOUNS = Object.freeze(["this", "it", "that", "here", "this one", "that one"]);
|
|
@@ -1394,8 +1305,6 @@
|
|
|
1394
1305
|
"node",
|
|
1395
1306
|
"stuff",
|
|
1396
1307
|
"code",
|
|
1397
|
-
// "symbol(s)" is a grain-agnostic stand-in for any code entity — "exported
|
|
1398
|
-
// symbols of X" means whatever X defines, at any grain, filtered by the qualifier.
|
|
1399
1308
|
"symbol",
|
|
1400
1309
|
"symbols"
|
|
1401
1310
|
]);
|
|
@@ -1423,33 +1332,22 @@
|
|
|
1423
1332
|
uncovered: { via: "tested", value: false }
|
|
1424
1333
|
});
|
|
1425
1334
|
var AGGREGATE_TRIGGERS = Object.freeze([
|
|
1426
|
-
// formal ("the number of classes" reaches "number of" once the cascade strips the
|
|
1427
|
-
// leading article — keeping the trigger list clear of "the" so it never enters
|
|
1428
|
-
// CONTENT_VOCAB and blocks the article's own noise-strip)
|
|
1429
1335
|
"how many",
|
|
1430
1336
|
"how much",
|
|
1431
1337
|
"how many of",
|
|
1432
1338
|
"number of",
|
|
1433
1339
|
"total number of",
|
|
1434
1340
|
"quantity of",
|
|
1435
|
-
// "<measure> of <kind>" cardinality forms (widened net, cycle W2P): count = sum = total
|
|
1436
|
-
// = tally = number of. The bare single words (sum/total/tally) stay CASCADE_SYNONYMS-
|
|
1437
|
-
// mapped to "count" (identifier-fragment risk without the "of" anchor — see that table's
|
|
1438
|
-
// note); the multi-word "of" forms are safe to promote to direct triggers because the
|
|
1439
|
-
// trailing "of <kind>" pins them to a cardinality question, not a stray identifier.
|
|
1440
1341
|
"tally of",
|
|
1441
1342
|
"sum of",
|
|
1442
1343
|
"total of",
|
|
1443
1344
|
"amount of",
|
|
1444
|
-
// neutral / imperative (bare "tally"/"sum"/"total" stay CASCADE_SYNONYMS-mapped so the
|
|
1445
|
-
// "tally the classes" relaxation path — pinned by a cascade test — is preserved).
|
|
1446
1345
|
"count",
|
|
1447
1346
|
"count up",
|
|
1448
1347
|
"count of",
|
|
1449
1348
|
"tot up"
|
|
1450
1349
|
]);
|
|
1451
1350
|
var LIST_TRIGGERS = Object.freeze([
|
|
1452
|
-
// imperative — "<verb> [me/us] [the] <kind>"
|
|
1453
1351
|
"list",
|
|
1454
1352
|
"show",
|
|
1455
1353
|
"show me",
|
|
@@ -1467,7 +1365,6 @@
|
|
|
1467
1365
|
"run down",
|
|
1468
1366
|
"run through",
|
|
1469
1367
|
"ls",
|
|
1470
|
-
// interrogative — "what/which are [the] <kind>"
|
|
1471
1368
|
"what are",
|
|
1472
1369
|
"which are"
|
|
1473
1370
|
]);
|
|
@@ -1501,12 +1398,7 @@
|
|
|
1501
1398
|
connections: { kind: "*", dir: "both" },
|
|
1502
1399
|
edges: { kind: "*", dir: "both" },
|
|
1503
1400
|
connected: { kind: "*", dir: "both" },
|
|
1504
|
-
// participle degree-nouns
|
|
1505
|
-
// depended-on / most used <module>" ranks by IN-degree — how many things import/depend
|
|
1506
|
-
// on/use it — the ARGMAX-by-degree intent a developer expresses with a passive
|
|
1507
|
-
// participle rather than the noun ("importers"). "depended" catches "depended-on" /
|
|
1508
|
-
// "depended on" (both tokenize to a bare "depended"); "used" folds the symbol-grain
|
|
1509
|
-
// callsSymbol callers in alongside importers so "most used" reads as most-relied-upon.
|
|
1401
|
+
// participle degree-nouns rank by in-degree, same intent as "importers" etc
|
|
1510
1402
|
imported: { kind: "imports", dir: "in" },
|
|
1511
1403
|
"depended-on": { kind: "imports", dir: "in" },
|
|
1512
1404
|
depended: { kind: "imports", dir: "in" },
|
|
@@ -1520,27 +1412,12 @@
|
|
|
1520
1412
|
var ANAPHORA_TRIGGERS = Object.freeze(["those", "them", "these"]);
|
|
1521
1413
|
var MEMBERSHIP_KINDS = Object.freeze(["contains", "defines"]);
|
|
1522
1414
|
var CASCADE_NOISE = Object.freeze([
|
|
1523
|
-
// articles / vague determiners (kept OUT of content vocab so they're strippable;
|
|
1524
|
-
// the aggregate/where parsers already tolerate a stray "the"/"a", so stripping is
|
|
1525
|
-
// belt-and-braces, not load-bearing)
|
|
1526
1415
|
"the",
|
|
1527
1416
|
"a",
|
|
1528
1417
|
"an",
|
|
1529
1418
|
"some",
|
|
1530
|
-
// "what OTHER classes inherit from Controller" — "other" is a vague determiner
|
|
1531
|
-
// like "some", not a qualifying adjective; without this it was misread as a
|
|
1532
|
-
// fuzzy find TERM ("no classes found matching 'other'") instead of falling
|
|
1533
|
-
// through to the ordinary reverse-inherits parse (fast-loop round 6 finding).
|
|
1534
1419
|
"other",
|
|
1535
|
-
// topic lead-in filler — "what about the modules", "how about classes": "about"
|
|
1536
|
-
// carries no graph meaning here, so stripping it lets the bare kind noun surface for
|
|
1537
|
-
// the cascade's bare-kind-noun terminal rule (ask.mjs). ("what"/"how" are structural
|
|
1538
|
-
// question words the drop-pass keeps; only the "about" between them and the kind is
|
|
1539
|
-
// noise.) A module literally named "about" is safe-listed by relaxParse's resolvesExact
|
|
1540
|
-
// guard, same as every other noise token.
|
|
1541
1420
|
"about",
|
|
1542
|
-
// politeness / hedges (single-token; multi-word "could you"/"please" etc. are
|
|
1543
|
-
// FILLER_WORDS, stripped earlier during normalization)
|
|
1544
1421
|
"please",
|
|
1545
1422
|
"pls",
|
|
1546
1423
|
"plz",
|
|
@@ -1553,8 +1430,6 @@
|
|
|
1553
1430
|
"thank",
|
|
1554
1431
|
"ta",
|
|
1555
1432
|
"cheers",
|
|
1556
|
-
// greetings a question sometimes opens with (chat.mjs owns standalone greetings;
|
|
1557
|
-
// here they're only stripped when embedded in an otherwise-real question)
|
|
1558
1433
|
"hi",
|
|
1559
1434
|
"hello",
|
|
1560
1435
|
"hey",
|
|
@@ -1563,7 +1438,6 @@
|
|
|
1563
1438
|
"howdy",
|
|
1564
1439
|
"ok",
|
|
1565
1440
|
"okay",
|
|
1566
|
-
// vocatives / terms of address (the "matey" of the worked example, and its kin)
|
|
1567
1441
|
"matey",
|
|
1568
1442
|
"mate",
|
|
1569
1443
|
"buddy",
|
|
@@ -1580,18 +1454,7 @@
|
|
|
1580
1454
|
"guys",
|
|
1581
1455
|
"everyone",
|
|
1582
1456
|
"dear",
|
|
1583
|
-
// the product's OWN name used as an address (chatbench cycle 2, ns-hey-tmct:
|
|
1584
|
-
// "hey tmct, what calls fnAlpha thanks") — a vocative like "matey", stripped
|
|
1585
|
-
// by the same rules: relaxParse's resolvesExact guard still protects a module
|
|
1586
|
-
// literally named "tmct", and noise-strip's template/keyword-spot acceptance
|
|
1587
|
-
// bounds the cost of a mid-question strip to an honest object-miss.
|
|
1588
1457
|
"tmct",
|
|
1589
|
-
// presentation frames — the keyword-spotting strategy's blind spot: the
|
|
1590
|
-
// compositional grammar skips these as FRAME_WORDS, but "show me what imports X"
|
|
1591
|
-
// otherwise decomposes (via keyword-spot) to ask{subject:"show me"}. Stripping
|
|
1592
|
-
// them on a miss recovers the underlying reverse/forward question. ("count" is NOT
|
|
1593
|
-
// here — it is an aggregate trigger; "find"/"search" are here as presentation
|
|
1594
|
-
// verbs, not the tmct_search tool, which ask.mjs never dispatches.)
|
|
1595
1458
|
"show",
|
|
1596
1459
|
"tell",
|
|
1597
1460
|
"give",
|
|
@@ -1818,40 +1681,21 @@
|
|
|
1818
1681
|
}
|
|
1819
1682
|
var PHRASING_FRAMES = Object.freeze([
|
|
1820
1683
|
// MEMBERS-of-class → "what does X contain".
|
|
1821
|
-
// "what functions are in Task", "what methods are inside X", "what attributes are in X"
|
|
1822
1684
|
{ re: /^what\s+(?:functions?|methods?|members?|attributes?|fields?|properties)\s+(?:are|is)\s+(?:in|inside|within)\s+(?:the\s+)?(.+?)\??$/i, to: (m) => `what does ${m[1]} contain` },
|
|
1823
|
-
// "what functions does Task have", "what methods does X have"
|
|
1824
1685
|
{ re: /^what\s+(?:functions?|methods?|members?|attributes?|fields?|properties)\s+(?:does|do)\s+(.+?)\s+have\??$/i, to: (m) => `what does ${m[1]} contain` },
|
|
1825
|
-
// "what are the members of X", "what are the methods in X"
|
|
1826
1686
|
{ re: /^what\s+are\s+(?:the\s+)?(?:functions?|methods?|members?|attributes?|fields?|properties)\s+(?:of|in|inside|within)\s+(?:the\s+)?(.+?)\??$/i, to: (m) => `what does ${m[1]} contain` },
|
|
1827
|
-
// "members of X", "methods of X", "contents of X"
|
|
1828
1687
|
{ re: /^(?:the\s+)?(?:members?|methods?|attributes?|contents)\s+of\s+(?:the\s+)?(.+?)\??$/i, to: (m) => `what does ${m[1]} contain` },
|
|
1829
|
-
// "what's in X" / "what is in X" (contraction already expanded; sha handled above)
|
|
1830
1688
|
{ re: /^what\s+is\s+(?:in|inside)\s+(?:the\s+)?(.+?)\??$/i, to: (m) => `what does ${m[1]} contain` },
|
|
1831
|
-
//
|
|
1832
|
-
// "besides what I already know" drill-down after a members-of-class answer.
|
|
1833
|
-
// Distinct from the "what else does X <verb>" family (which the compositional
|
|
1834
|
-
// grammar already tolerates, dropping "else" as noise on its own): the "is
|
|
1835
|
-
// in" idiom is NOT a compositional marker, so parseComposite never sees it and
|
|
1836
|
-
// "what else is in X" fell through to the strategies with NO candidate at all
|
|
1837
|
-
// (neither recognizes the bare "is in" idiom once "else" sits in front of it).
|
|
1838
|
-
// The only rescue was the relaxation cascade's drop-unmatched layer — but that
|
|
1839
|
-
// layer refuses to accept a relaxed reading that still renders an honest EMPTY
|
|
1840
|
-
// , so a genuinely empty class ("what else is in
|
|
1841
|
-
// Task.complete" — a method, no members) bottomed out at the bare grammar
|
|
1842
|
-
// wall instead of the specific "no contains edges" receipt. Routing this
|
|
1843
|
-
// frame onto the SAME direct "what does X contain" path the plain "what is
|
|
1844
|
-
// in X" frame above already uses sidesteps the cascade's conservative gate
|
|
1845
|
-
// entirely, so a real empty is reported honestly instead of walled.
|
|
1689
|
+
// "what else is in X" drill-down after a members-of-class answer.
|
|
1846
1690
|
{ re: /^what\s+else\s+is\s+(?:in|inside)\s+(?:the\s+)?(.+?)\??$/i, to: (m) => `what does ${m[1]} contain` },
|
|
1847
1691
|
// WHERE-DEFINED → "where is X defined". PAST TENSE ONLY ("what defined X", "what
|
|
1848
1692
|
// declared X"): the PRESENT "what defines X" already parses as a reverse-defines
|
|
1849
|
-
// query (the module defining symbol X
|
|
1850
|
-
//
|
|
1693
|
+
// query (the module defining symbol X), so rewriting it would change that
|
|
1694
|
+
// receipt. The past-tense form is the one that hit the wall.
|
|
1851
1695
|
{ re: /^what\s+(?:defined|declared)\s+(?:the\s+)?(?:function\s+|method\s+|class\s+|module\s+|variable\s+|constant\s+)?(.+?)\??$/i, to: (m) => `where is ${m[1]} defined` },
|
|
1852
1696
|
// "where's X defined" (the "where's" contraction is not in the contraction table)
|
|
1853
1697
|
{ re: /^where'?s\s+(?:the\s+)?(.+?)\s+(defined|declared|located|implemented)\??$/i, to: (m) => `where is ${m[1]} ${m[2]}` },
|
|
1854
|
-
// "were is X defined" (
|
|
1698
|
+
// "were is X defined" (the missing-h typo of "where").
|
|
1855
1699
|
// NOT curated as a blanket MISSPELLINGS entry — "were" is a real word already
|
|
1856
1700
|
// load-bearing as the TEMPORAL_AUX auxiliary ("when were the modules last
|
|
1857
1701
|
// touched"), so a global word-boundary rewrite would clobber that reading.
|
|
@@ -1860,33 +1704,15 @@
|
|
|
1860
1704
|
// temporal query produces ("were" as an auxiliary never leads directly into
|
|
1861
1705
|
// a bare "is").
|
|
1862
1706
|
{ re: /^were\s+is\s+(?:the\s+)?(.+?)\s+(defined|declared|located|implemented)\??$/i, to: (m) => `where is ${m[1]} ${m[2]}` },
|
|
1863
|
-
// PREDICATIVE QUALIFIER → the ATTRIBUTIVE form
|
|
1864
|
-
//
|
|
1865
|
-
//
|
|
1866
|
-
// slot — "untested modules", "public methods" — but a developer just as naturally
|
|
1867
|
-
// asks the PREDICATIVE "which modules are untested" / "what functions are tested",
|
|
1868
|
-
// which hit the grammar wall (and, worse, the wall's own hint SUGGESTED "which
|
|
1869
|
-
// functions are tested" — a shape it could not then answer). Rewriting the
|
|
1870
|
-
// predicative "<which|what> <kind> are <QUALIFIER>" to "<QUALIFIER> <kind>" routes
|
|
1871
|
-
// it onto the working attributive filter. Closed to the known qualifier adjectives
|
|
1872
|
-
// (not a general "… are X" catch), and the QUALIFIER must sit immediately after
|
|
1873
|
-
// are/is, so "which modules are NOT tested" never matches here — that keeps its own
|
|
1874
|
-
// set-complement handler (matchNegationSet, downstream in ask.mjs's parseNegation).
|
|
1707
|
+
// PREDICATIVE QUALIFIER ("which modules are untested") → the ATTRIBUTIVE form
|
|
1708
|
+
// ("untested modules") the grammar already answers. The QUALIFIER must sit
|
|
1709
|
+
// immediately after are/is, so "…are NOT tested" keeps its own set-complement handler.
|
|
1875
1710
|
{
|
|
1876
1711
|
re: /^(?:which|what)\s+(?:the\s+|all\s+)?([a-z][a-z-]*?)\s+(?:are|is)\s+(public|private|protected|static|abstract|constant|exported|re-?exported|tested|covered|untested|uncovered)\??$/i,
|
|
1877
1712
|
to: (m) => `${m[2].toLowerCase()} ${m[1].toLowerCase()}`
|
|
1878
1713
|
},
|
|
1879
|
-
// BARE COVERAGE SURVEY
|
|
1880
|
-
//
|
|
1881
|
-
// asks the survey the plainest way — "what is untested", "what's not tested",
|
|
1882
|
-
// "what isn't covered", "what is covered" — with NO entity noun at all, so the
|
|
1883
|
-
// predicative-qualifier frame above (which needs a KIND between what/which and
|
|
1884
|
-
// are/is) can't catch it, and it fell through to a soft wall ("no module matching
|
|
1885
|
-
// 'not'…" / the "I answer questions…" orientation). Default the surveyed kind to
|
|
1886
|
-
// modules (the same set "which modules are not tested" / "untested modules" return)
|
|
1887
|
-
// and fold the negation into the qualifier (not tested → untested, not covered →
|
|
1888
|
-
// uncovered). Anchored with no object, so "what tests cover X" / "what is a test"
|
|
1889
|
-
// never match here.
|
|
1714
|
+
// BARE COVERAGE SURVEY, no entity kind ("what is untested") → defaults the
|
|
1715
|
+
// surveyed kind to modules and folds the negation into the qualifier.
|
|
1890
1716
|
{
|
|
1891
1717
|
re: /^what\s+(?:is|are)\s+(not\s+)?(tested|untested|covered|uncovered)\??$/i,
|
|
1892
1718
|
to: (m) => {
|
|
@@ -1895,61 +1721,23 @@
|
|
|
1895
1721
|
return `${flipped} modules`;
|
|
1896
1722
|
}
|
|
1897
1723
|
},
|
|
1898
|
-
// CO-CHANGE →
|
|
1899
|
-
// cochange verb synonyms (ask-vocab.mjs) include "co-changes with" / "moves
|
|
1900
|
-
// together with" / "tends to change together with", but NOT the plainest form a
|
|
1901
|
-
// developer types — the one the README itself prints and the relation renders as:
|
|
1902
|
-
// "what does X change together with" / "what changes together with X". Both hit a
|
|
1903
|
-
// dead-end ("couldn't resolve one of the terms" / the grammar wall); rewriting them
|
|
1904
|
-
// onto "what co-changes with X" routes them to the working change-coupling query.
|
|
1724
|
+
// CO-CHANGE → "what co-changes with X" (the plainest phrasing a developer types).
|
|
1905
1725
|
{ re: /^what\s+does\s+(.+?)\s+changes?\s+together\s+with\??$/i, to: (m) => `what co-changes with ${m[1]}` },
|
|
1906
1726
|
{ re: /^what\s+changes?\s+together\s+with\s+(.+?)\??$/i, to: (m) => `what co-changes with ${m[1]}` },
|
|
1907
|
-
// AUTHORSHIP →
|
|
1908
|
-
// commit
|
|
1909
|
-
// synonyms a developer reaches for next — "who wrote X", "who authored X", "who is
|
|
1910
|
-
// the author of X" — and every one of them hit the grammar wall. tmct has no
|
|
1911
|
-
// separate authorship edge; "touched" IS the authorship signal (the churn commits
|
|
1912
|
-
// carry the author), so these are true synonyms of "who touched X", not a new
|
|
1913
|
-
// capability. Anaphora rides through untouched ("who wrote it" → "who touched it").
|
|
1914
|
-
// SHA GUARD (0.8.2 feel wave): a COMMIT object is NOT a synonym — "who is the
|
|
1915
|
-
// author of abc1234" rewritten to "who touched abc1234" dumps the commit's
|
|
1916
|
-
// touch-SET instead of naming its author. The negative lookahead refuses the
|
|
1917
|
-
// rewrite when the object is a bare (optionally "commit "-prefixed) 7-40 char
|
|
1918
|
-
// hex sha, leaving the un-rewritten form for the author lane to consume;
|
|
1919
|
-
// file/symbol objects (anything non-sha, e.g. "deadbeef.mjs") keep the rewrite.
|
|
1727
|
+
// AUTHORSHIP → "who touched X" (tmct's touch edge IS the authorship signal).
|
|
1728
|
+
// A commit sha object is excluded — that dumps the commit's touch-set, not its author.
|
|
1920
1729
|
{ re: /^who\s+(?:wrote|authored)\s+(?:the\s+)?(?!(?:commit\s+)?[0-9a-f]{7,40}\??$)(.+?)\??$/i, to: (m) => `who touched ${m[1]}` },
|
|
1921
1730
|
{ re: /^who\s+is\s+the\s+authors?\s+of\s+(?:the\s+)?(?!(?:commit\s+)?[0-9a-f]{7,40}\??$)(.+?)\??$/i, to: (m) => `who touched ${m[1]}` },
|
|
1922
|
-
// HAS-TESTS →
|
|
1923
|
-
//
|
|
1924
|
-
// "No — no defines edge found from X to <whatever resolves>" receipt; "is X
|
|
1925
|
-
// tested" traverses tests edges from the WRONG side (subject = X). Both mean
|
|
1926
|
-
// the coverage question "what tests X" — rewrite onto it. Closed to a
|
|
1927
|
-
// tests/coverage object ("does X have methods/members" stays the members
|
|
1928
|
-
// family) and refuses any "not" in the subject span, so the set-complement
|
|
1929
|
-
// negations ("is X not tested") keep their own handler downstream.
|
|
1731
|
+
// HAS-TESTS → "what tests X" (the coverage question). Refuses "not" in the
|
|
1732
|
+
// subject so set-complement negations keep their own downstream handler.
|
|
1930
1733
|
{ re: /^(?:does|do)\s+(?!.*\bnot\b)(.+?)\s+have\s+(?:any\s+)?(?:tests?|test\s+coverage|coverage)\??$/i, to: (m) => `what tests ${m[1]}` },
|
|
1931
1734
|
{ re: /^(?:is|are)\s+(?!.*\bnot\b)(.+?)\s+tested\??$/i, to: (m) => `what tests ${m[1]}` },
|
|
1932
|
-
// NEEDS-TESTS → the untested-module survey.
|
|
1933
|
-
// testing" is the plainest way to ask which modules are uncovered, and it hit the
|
|
1934
|
-
// grammar wall ("no module matching 'needs'…"). Route it onto the same attributive
|
|
1935
|
-
// survey the bare "what is untested" frame lands on. Closed to the tests/coverage
|
|
1936
|
-
// object, so it can't swallow a general "what needs X".
|
|
1735
|
+
// NEEDS-TESTS → the untested-module survey.
|
|
1937
1736
|
{ re: /^what\s+needs\s+(?:to\s+be\s+)?(?:a\s+)?(?:tested|tests?|testing|coverage|covering)\??$/i, to: () => "untested modules" },
|
|
1938
|
-
// DOES-X-VERB-ANYTHING-ELSE →
|
|
1939
|
-
//
|
|
1940
|
-
//
|
|
1941
|
-
//
|
|
1942
|
-
// "something" [else] is a placeholder standing in for "the rest of the list",
|
|
1943
|
-
// not a real object term, but the two parse strategies disagreed on the SPAN
|
|
1944
|
-
// (grammar kept "anything else" whole as the object, keyword-spot dropped
|
|
1945
|
-
// "anything" and kept only "else"), landing on the {ambiguousParse} surface —
|
|
1946
|
-
// two nonsense readings offered as if one might be right. "what does X <verb>"
|
|
1947
|
-
// is the exact working canonical shape (see the MEMBERS-of-class frames above),
|
|
1948
|
-
// so rewriting the whole closed pattern onto it sidesteps the disagreement
|
|
1949
|
-
// instead of teaching either strategy's tokenizer to special-case "else".
|
|
1950
|
-
// Anchored to the closed VERB_TO_KIND vocabulary so it can never swallow a
|
|
1951
|
-
// genuine named object that happens to start with "any"/"some" (only the bare
|
|
1952
|
-
// placeholder nouns "anything"/"something", optionally trailed by "else", match).
|
|
1737
|
+
// DOES-X-VERB-ANYTHING-ELSE → "what does X <verb>" (drops the placeholder
|
|
1738
|
+
// "anything/something else" object, which otherwise made the two parse
|
|
1739
|
+
// strategies disagree on the span). Anchored to VERB_TO_KIND so it can't
|
|
1740
|
+
// swallow a real object that happens to start with "any"/"some".
|
|
1953
1741
|
{
|
|
1954
1742
|
re: new RegExp(`^(?:do|does)\\s+(.+?)\\s+(${VERB_ALTERNATION})\\s+(?:anything|something)(?:\\s+else)?\\??$`, "i"),
|
|
1955
1743
|
to: (m) => `what does ${m[1]} ${m[2]}`
|
|
@@ -1964,7 +1752,6 @@
|
|
|
1964
1752
|
}
|
|
1965
1753
|
var NEGATION_SET_RE = new RegExp(
|
|
1966
1754
|
"^(?:which|what|who|list|show(?:\\s+me)?|find|give\\s+me)?\\s*(?:the\\s+|all\\s+)?([a-z][a-z-]*)\\s+(?:(?:that|which|who)\\s+)?(?:(?:do|does|did|are|is|was|were|have|has)\\s+)?not\\s+(.+)$",
|
|
1967
|
-
// the negation marker + (2) the predicate
|
|
1968
1755
|
"i"
|
|
1969
1756
|
);
|
|
1970
1757
|
function matchNegationSet(text) {
|
|
@@ -2005,15 +1792,8 @@
|
|
|
2005
1792
|
"nothing",
|
|
2006
1793
|
"one",
|
|
2007
1794
|
"any",
|
|
2008
|
-
// temporal filler in when-questions ("when was X last touched") — a symbol
|
|
2009
|
-
// literally named "last" would be the accepted residual cost, same trade as
|
|
2010
|
-
// every other stopword.
|
|
2011
1795
|
"last",
|
|
2012
|
-
//
|
|
2013
|
-
// X typically call") — found live: "usually" glued onto the object term instead of
|
|
2014
|
-
// being stripped, corrupting resolution ("src/core/store.mjs usually" instead of
|
|
2015
|
-
// the module alone). Same trade as every other stopword: a symbol literally named
|
|
2016
|
-
// "usually" would be the accepted residual cost.
|
|
1796
|
+
// temporal filler ("when was X last touched")
|
|
2017
1797
|
"usually",
|
|
2018
1798
|
"typically",
|
|
2019
1799
|
"generally",
|
|
@@ -2021,12 +1801,7 @@
|
|
|
2021
1801
|
"often",
|
|
2022
1802
|
"commonly",
|
|
2023
1803
|
"mostly",
|
|
2024
|
-
//
|
|
2025
|
-
// this set, "should" reached the cascade's bounded fuzzy-correction step and landed
|
|
2026
|
-
// within edit distance of the unrelated closed-vocab word "hold" ("defines" synonym,
|
|
2027
|
-
// ask-vocab.mjs), corrupting the whole query into "what hold i at". Same trade as
|
|
2028
|
-
// every other stopword: a symbol literally named "should" would be the accepted
|
|
2029
|
-
// residual cost.
|
|
1804
|
+
// frequency-adverb filler
|
|
2030
1805
|
"should",
|
|
2031
1806
|
"would",
|
|
2032
1807
|
"could",
|
|
@@ -2035,6 +1810,7 @@
|
|
|
2035
1810
|
"shall",
|
|
2036
1811
|
"might",
|
|
2037
1812
|
"must"
|
|
1813
|
+
// modal auxiliaries
|
|
2038
1814
|
]);
|
|
2039
1815
|
var splitWords = (text) => String(text).replace(/\?+\s*$/, "").replace(/,/g, " ").split(/\s+/).filter(Boolean);
|
|
2040
1816
|
var wordsOf = (arr) => arr.flatMap((p) => String(p).toLowerCase().split(" "));
|
|
@@ -2095,21 +1871,9 @@
|
|
|
2095
1871
|
var MODIFIER_ALT = Object.keys(MODIFIER_TO_KIND).sort((a, b) => b.length - a.length).map(escapeRegex).join("|");
|
|
2096
1872
|
var META_ALT = META_MEANING_VERBS.slice().sort((a, b) => b.length - a.length).map(escapeRegex).join("|");
|
|
2097
1873
|
var TEMPLATES = [
|
|
2098
|
-
// T1 ASK: "does X import Y"
|
|
2099
|
-
//
|
|
2100
|
-
//
|
|
2101
|
-
// "did" joins does/do for the past-tense commit forms ("did commit <sha> touch X").
|
|
2102
|
-
// REVERSE VERB SWAP (Seonix Batch 2 Fix 2): this template fixes subject/object by regex
|
|
2103
|
-
// capture POSITION, not by the verb's semantic direction — fine for every forward verb
|
|
2104
|
-
// ("subclass of", "imports", …), but "is X a superclass of Y" MEANS the reverse of "is X
|
|
2105
|
-
// a subclass of Y" (Y inherits from X, not X from Y). INHERITS_REVERSE_VERBS (ask-vocab.mjs)
|
|
2106
|
-
// is the closed set of such reverse phrasings; when the matched verb is one of them,
|
|
2107
|
-
// subject/object are swapped here, once, at parse time — so downstream evaluation (ask.mjs)
|
|
2108
|
-
// sees "is Y a subclass of X" and needs zero changes of its own. (In practice this exact
|
|
2109
|
-
// regex only ever matches a does/do/did lead, so "is …" phrasings actually reach the "ask"
|
|
2110
|
-
// shape via keywords.mjs's decomposition strategy instead — that strategy applies the same
|
|
2111
|
-
// swap for the same reason; this branch is kept for any does/do/did-led phrasing that names
|
|
2112
|
-
// a reverse verb, and for structural symmetry with that sibling strategy.)
|
|
1874
|
+
// T1 ASK: "does X import Y" -> Yes/No. REVERSE VERB SWAP: a semantically-reverse
|
|
1875
|
+
// verb ("superclass of") means the opposite of its forward counterpart, so
|
|
1876
|
+
// INHERITS_REVERSE_VERBS (ask-vocab.mjs) swaps subject/object here at parse time.
|
|
2113
1877
|
{
|
|
2114
1878
|
name: "ask",
|
|
2115
1879
|
re: new RegExp(`^(?:does|do|did)\\s+(.+?)\\s+(${VERB_ALT})\\s+(.+?)\\??$`, "i"),
|
|
@@ -2122,7 +1886,7 @@
|
|
|
2122
1886
|
return { shape: "ask", entityType: null, modifier: "direct", kind, subject, object };
|
|
2123
1887
|
}
|
|
2124
1888
|
},
|
|
2125
|
-
// T2 reverse: "which <entity> [<modifier>] <verb> <object>"
|
|
1889
|
+
// T2 reverse: "which <entity> [<modifier>] <verb> <object>".
|
|
2126
1890
|
{
|
|
2127
1891
|
name: "reverse",
|
|
2128
1892
|
re: new RegExp(`^which\\s+(${ENTITY_ALT})\\s+(?:(${MODIFIER_ALT})\\s+)?(${VERB_ALT})\\s+(.+?)\\??$`, "i"),
|
|
@@ -2147,40 +1911,17 @@
|
|
|
2147
1911
|
object: m[1].trim()
|
|
2148
1912
|
})
|
|
2149
1913
|
},
|
|
2150
|
-
// T4 meta: "what does <term> mean" — a question about the
|
|
2151
|
-
//
|
|
2152
|
-
//
|
|
2153
|
-
// starts "what does/do", but T3 only fires when the tail is a relation VERB_ALT
|
|
2154
|
-
// phrase ("import"/"calls"/…), which "mean"/"means"/etc never are (disjoint tables —
|
|
2155
|
-
// ask-vocab.mjs's file comment explains why they're kept separate), so the two never
|
|
2156
|
-
// actually compete for the same input.
|
|
1914
|
+
// T4 meta: "what does <term> mean" — a question about the graph's own vocabulary,
|
|
1915
|
+
// not a graph traversal. VERB_ALT and META_ALT are disjoint tables, so this never
|
|
1916
|
+
// competes with T3 for the same input.
|
|
2157
1917
|
{
|
|
2158
1918
|
name: "meta-mean",
|
|
2159
1919
|
re: new RegExp(`^what\\s+(?:does|do|is|are)\\s+(.+?)\\s+(?:${META_ALT})\\??$`, "i"),
|
|
2160
1920
|
build: (m) => ({ shape: "meta", entityType: null, modifier: "direct", kind: "meta", object: m[1].trim() })
|
|
2161
1921
|
},
|
|
2162
|
-
// T5 meta: "what is a/an <term>" — the
|
|
2163
|
-
//
|
|
2164
|
-
//
|
|
2165
|
-
// imported above (function/method/class/module/attribute/variable/change/commit,
|
|
2166
|
-
// singular and plural) — build() returns null (same "this template didn't actually
|
|
2167
|
-
// match, keep scanning" contract T8/"when" below already relies on — see
|
|
2168
|
-
// parseAnchored's own docblock) when the bare form's object isn't one of those
|
|
2169
|
-
// closed terms, so the scan falls through exactly as if this template had not
|
|
2170
|
-
// matched at all. This keeps "what is a doohickey"/"widget"/"gizmo" (still routed
|
|
2171
|
-
// here via the WITH-article, fully unrestricted `(.+?)` path — pinned to resolve as
|
|
2172
|
-
// an honest meta miss downstream, ask-combo.test.mjs/chat-readback.test.mjs) working
|
|
2173
|
-
// unmodified, while ALSO keeping the two pinned bare-form honest misses intact:
|
|
2174
|
-
// "what is the meaning of this codebase" (ask.test.mjs/ask-dual-strategy.test.mjs)
|
|
2175
|
-
// and "what is exposed" (ask.test.mjs:840) both have bare objects absent from
|
|
2176
|
-
// ENTITY_TO_TYPE, so build() still rejects them and they still fall through to null.
|
|
2177
|
-
// Fix 3: stripTrailingScopeFiller (ask-vocab.mjs) trims a curated trailing clause
|
|
2178
|
-
// ("what is a Module in this graph" -> "Module") off the object before it's
|
|
2179
|
-
// returned, so a scoping tail never corrupts the lookup term either the bare-form
|
|
2180
|
-
// check above or downstream resolution/rendering perform. HANDOVER.md 2026-07-10
|
|
2181
|
-
// item 8: stripTrailingDiscourseTag trims a bare trailing "then"/"though" the
|
|
2182
|
-
// same way ("what is a component then" -> "component") — applied first, since a
|
|
2183
|
-
// discourse tag sits outermost when both happen to stack.
|
|
1922
|
+
// T5 meta: "what is a/an <term>" — the bare (no-article) form is restricted to
|
|
1923
|
+
// the closed ENTITY_TO_TYPE vocabulary (build() -> null otherwise, falling
|
|
1924
|
+
// through); the WITH-article form is unrestricted.
|
|
2184
1925
|
{
|
|
2185
1926
|
name: "meta-whatis",
|
|
2186
1927
|
re: new RegExp(`^what\\s+(?:is|are)\\s+(?:(an?)\\s+)?(.+?)\\??$`, "i"),
|
|
@@ -2194,8 +1935,8 @@
|
|
|
2194
1935
|
return { shape: "meta", entityType: null, modifier: "direct", kind: "meta", object: stripTrailingScopeFiller(object) };
|
|
2195
1936
|
}
|
|
2196
1937
|
},
|
|
2197
|
-
// T6 mention: "where is <term> mentioned/referenced" — the prose/mentions surface
|
|
2198
|
-
//
|
|
1938
|
+
// T6 mention: "where is <term> mentioned/referenced" — the prose/mentions surface.
|
|
1939
|
+
// Tried BEFORE T7: T7's trailing marker is optional,
|
|
2199
1940
|
// so without this ordering it would swallow the mention question and lose the
|
|
2200
1941
|
// marker that distinguishes "locate the definition" from "list the prose mentions".
|
|
2201
1942
|
{
|
|
@@ -2221,19 +1962,19 @@
|
|
|
2221
1962
|
re: new RegExp(`^when\\s+(?:did|does|do|was|were|is)\\s+(.+?)\\s+(?:last\\s+)?(${VERB_ALT})\\??$`, "i"),
|
|
2222
1963
|
build: (m) => VERB_TO_KIND[m[2].toLowerCase()] === "touches" ? { shape: "when", entityType: null, modifier: "direct", kind: "touches", object: m[1].trim() } : null
|
|
2223
1964
|
},
|
|
2224
|
-
// T9 commit-history NP
|
|
2225
|
-
//
|
|
2226
|
-
//
|
|
2227
|
-
//
|
|
1965
|
+
// T9 commit-history NP: "the commit history of X" / "commit history for X" —
|
|
1966
|
+
// an NP form of T8's SAME "when did X change" intent; reuses shape="when"
|
|
1967
|
+
// verbatim so evaluation/rendering are byte-identical, only the recognizer
|
|
1968
|
+
// surface differs.
|
|
2228
1969
|
{
|
|
2229
1970
|
name: "commit-history",
|
|
2230
1971
|
re: /^(?:the\s+)?commit\s+history\s+(?:of|for)\s+(.+?)\??$/i,
|
|
2231
1972
|
build: (m) => ({ shape: "when", entityType: null, modifier: "direct", kind: "touches", object: m[1].trim() })
|
|
2232
1973
|
},
|
|
2233
|
-
// T10 cochange-partners NP
|
|
2234
|
-
//
|
|
2235
|
-
//
|
|
2236
|
-
//
|
|
1974
|
+
// T10 cochange-partners NP: "cochange partners of X" — an NP form of the
|
|
1975
|
+
// existing "which modules cochange with X" verb-phrase shape (ask-vocab.mjs's
|
|
1976
|
+
// cochange verb table); reuses shape="reverse"/kind="cochange" so evaluation
|
|
1977
|
+
// is byte-identical.
|
|
2237
1978
|
{
|
|
2238
1979
|
name: "cochange-partners",
|
|
2239
1980
|
re: /^co-?change\s+partners\s+(?:of|for|with)\s+(.+?)\??$/i,
|
|
@@ -2608,6 +2349,7 @@
|
|
|
2608
2349
|
var createRequireFromPath5 = unavailable5("createRequireFromPath");
|
|
2609
2350
|
var spawnSync5 = unavailable5("spawnSync");
|
|
2610
2351
|
var createInterface5 = unavailable5("createInterface");
|
|
2352
|
+
var createServer5 = unavailable5("createServer");
|
|
2611
2353
|
var DatabaseSync5 = unavailable5("DatabaseSync");
|
|
2612
2354
|
|
|
2613
2355
|
// src/answer-variants.mjs
|
|
@@ -2669,13 +2411,7 @@
|
|
|
2669
2411
|
Attribute: ["attribute", "attributes"],
|
|
2670
2412
|
GlobalVariable: ["variable", "variables"],
|
|
2671
2413
|
Commit: ["commit", "commits"],
|
|
2672
|
-
// "Change" is ask-vocab.mjs's pseudo-type (a wildcard over the touch traversal's
|
|
2673
|
-
// results, never a node class) — it still needs noun forms for zero-hit templates.
|
|
2674
2414
|
Change: ["change", "changes"],
|
|
2675
|
-
// Memory-graph classes (memory/core.mjs) — real noun forms for the dynamic
|
|
2676
|
-
// class count/list fallback (PLAN_BREADTH_FIRST_NLU.md (d), see
|
|
2677
|
-
// dynamicClassQuery below) so "2 facts." reads naturally instead of falling
|
|
2678
|
-
// back to the generic "2 results.".
|
|
2679
2415
|
Fact: ["fact", "facts"],
|
|
2680
2416
|
Utterance: ["utterance", "utterances"],
|
|
2681
2417
|
Session: ["session", "sessions"],
|
|
@@ -3675,24 +3411,20 @@
|
|
|
3675
3411
|
return traverse(graph, ast.clause, opts).matches || [];
|
|
3676
3412
|
case "allOfClass":
|
|
3677
3413
|
return graph.individuals.filter((i) => i.class === ast.entityType);
|
|
3678
|
-
//
|
|
3679
|
-
//
|
|
3680
|
-
// cascade's result, transparently flattened (the "related, not exact" framing
|
|
3681
|
-
// is a top-level RENDER concern — evalComposite's dedicated "find" handling
|
|
3682
|
-
// below, not this generic embedding).
|
|
3414
|
+
// Predicate-find as a set atom: the narrow-then-broaden cascade's result,
|
|
3415
|
+
// transparently flattened ("related, not exact" is a render concern).
|
|
3683
3416
|
case "find": {
|
|
3684
3417
|
const { narrow, broad } = computeFind(graph, ast.entityType, ast.term);
|
|
3685
3418
|
return narrow.length ? narrow : broad;
|
|
3686
3419
|
}
|
|
3687
|
-
//
|
|
3688
|
-
//
|
|
3689
|
-
// differences off allOfClass to yield "modules that import nothing".
|
|
3420
|
+
// Subjects with any edge of a kind; an existential negation differences
|
|
3421
|
+
// this off allOfClass to yield "modules that import nothing".
|
|
3690
3422
|
case "existsEdge": {
|
|
3691
3423
|
const subs = new Set(kindsFor(ast.kind).flatMap((k) => edgesOfKind2(graph, k)).map((e) => e.subject));
|
|
3692
3424
|
return graph.individuals.filter((i) => subs.has(i.id) && (!ast.entityType || i.class === ast.entityType));
|
|
3693
3425
|
}
|
|
3694
|
-
//
|
|
3695
|
-
//
|
|
3426
|
+
// Forward complement: the verb's object-grain universe minus what the
|
|
3427
|
+
// subject reaches via that verb ("what doesn't it import").
|
|
3696
3428
|
case "forwardComplement": {
|
|
3697
3429
|
const r = resolveTermOrContext(graph, ast.subjectTerm, opts && opts.contextId);
|
|
3698
3430
|
if (!r.match) return [];
|
|
@@ -3709,11 +3441,9 @@
|
|
|
3709
3441
|
const ids = new Set(evalSet(graph, ast.inner, opts).map((i) => i.id));
|
|
3710
3442
|
return forwardOverSet(graph, ast.kind, ids);
|
|
3711
3443
|
}
|
|
3712
|
-
//
|
|
3713
|
-
//
|
|
3714
|
-
//
|
|
3715
|
-
// previous answer" miss, same as evalAnaphora's own no-prev branch; this is only
|
|
3716
|
-
// reached with a real, non-empty `prev` in hand.
|
|
3444
|
+
// The previous list-shaped answer's own id set. Only reached with a real,
|
|
3445
|
+
// non-empty `prev` — the no-`prev` case is intercepted earlier as an
|
|
3446
|
+
// honest "needs a previous answer" miss.
|
|
3717
3447
|
case "prevSet": {
|
|
3718
3448
|
const prev = opts && opts.prev;
|
|
3719
3449
|
return Array.isArray(prev) ? prev.map((id) => graph.byId.get(id)).filter(Boolean) : [];
|
|
@@ -5293,6 +5023,7 @@ ${result.branches.map((b, i) => `${i + 1}) ${b.candidate.label}: ${b.rendered.co
|
|
|
5293
5023
|
const base = { node: "allOfClass", entityType };
|
|
5294
5024
|
return listM ? { node: "list", entityType, base, scoped: false } : { node: "count", entityType, base };
|
|
5295
5025
|
}
|
|
5026
|
+
var BARE_META_WHATIS_RE = /^what\s+(?:is|are)\s+(?:an?\s+)?(.+?)[?.!\s]*$/i;
|
|
5296
5027
|
function ask(graph, query, { contextId = null, nlp = void 0, prev = null } = {}) {
|
|
5297
5028
|
if (isHelpRequest(query)) {
|
|
5298
5029
|
return {
|
|
@@ -5338,6 +5069,17 @@ ${result.branches.map((b, i) => `${i + 1}) ${b.candidate.label}: ${b.rendered.co
|
|
|
5338
5069
|
}
|
|
5339
5070
|
}
|
|
5340
5071
|
}
|
|
5072
|
+
if (parsed === null && rendered.miss && !rendered.ambiguous) {
|
|
5073
|
+
const bareM = String(query || "").trim().match(BARE_META_WHATIS_RE);
|
|
5074
|
+
const bareTerm = bareM?.[1]?.trim();
|
|
5075
|
+
if (bareTerm && !/\s+(?:for|about)$/i.test(bareTerm)) {
|
|
5076
|
+
const bareParsed = parseQuery(`what is a ${bareTerm}`, { nlp });
|
|
5077
|
+
if (bareParsed?.shape === "meta") {
|
|
5078
|
+
result = traverse(graph, bareParsed, { contextId, prev });
|
|
5079
|
+
rendered = render(bareParsed, result);
|
|
5080
|
+
}
|
|
5081
|
+
}
|
|
5082
|
+
}
|
|
5341
5083
|
let content = relaxed && !rendered.miss && relaxed.to !== relaxed.from ? `read as "${relaxed.to}" \u2014 ${rendered.content}` : rendered.content;
|
|
5342
5084
|
if (!relaxed && !rendered.miss && !rendered.ambiguous && directFull.alternates.length) {
|
|
5343
5085
|
const answered = directFull.alternates.map((a) => {
|
|
@@ -5358,13 +5100,6 @@ ${lines.join("\n")}`;
|
|
|
5358
5100
|
tmct_ask: {
|
|
5359
5101
|
mechanical: true,
|
|
5360
5102
|
parsed: parsed && !parsed.ambiguousParse ? parsed : null,
|
|
5361
|
-
// PLAN_BREADTH_FIRST_NLU.md §Track 6 (operator directive): the canonical
|
|
5362
|
-
// restatement of what the request was understood to mean, ALWAYS present
|
|
5363
|
-
// when anything parsed at all — not gated on ambiguity/miss the way the
|
|
5364
|
-
// ambiguity-branch labels are. `english` is the human-readable gloss in
|
|
5365
|
-
// tmct's own phrasing; `machine` is the same fact in a compact,
|
|
5366
|
-
// machine-parsable notation (a plain `shape(kind, args...)` call form).
|
|
5367
|
-
// Both are read straight off `parsed` — never generated.
|
|
5368
5103
|
canonical: canonicalOf(parsed),
|
|
5369
5104
|
matches: (result.matches || []).map((m) => ({
|
|
5370
5105
|
id: m.id,
|
|
@@ -5375,16 +5110,12 @@ ${lines.join("\n")}`;
|
|
|
5375
5110
|
traversal: result.traversal || null,
|
|
5376
5111
|
miss: !!rendered.miss,
|
|
5377
5112
|
ambiguous: !!rendered.ambiguous,
|
|
5378
|
-
//
|
|
5379
|
-
//
|
|
5380
|
-
// dropped/normalised to reach an answer. A caller can assert relaxed===null to
|
|
5381
|
-
// prove the cascade never touched a direct hit.
|
|
5113
|
+
// null when the direct parse was used as-is; a caller can assert
|
|
5114
|
+
// relaxed===null to prove the cascade never touched a direct hit.
|
|
5382
5115
|
relaxed,
|
|
5383
|
-
//
|
|
5384
|
-
//
|
|
5385
|
-
//
|
|
5386
|
-
// resolved a typo'd term (the rendered content also announces it: "assuming you
|
|
5387
|
-
// meant <label>"); null for every literal-identifier tier.
|
|
5116
|
+
// "prose" (tier-4 prose-index fallback) or "fuzzy" (tier-5 bounded
|
|
5117
|
+
// edit-distance, announced in the content as "assuming you meant …");
|
|
5118
|
+
// null for every literal-identifier tier.
|
|
5388
5119
|
matchedVia: result.matchedVia || null,
|
|
5389
5120
|
...rendered.ambiguous ? { candidates: rendered.candidates } : {}
|
|
5390
5121
|
}
|