@polycode-projects/the-mechanical-code-talker 1.9.2 → 1.10.1
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 +441 -202
- package/bin/tmct.mjs +126 -1
- package/package.json +4 -2
- package/src/answer-variants.mjs +8 -36
- package/src/ask-browser-entry.mjs +5 -23
- package/src/ask-browser.bundle.js +1 -2
- package/src/ask-nlp.mjs +9 -23
- package/src/ask-vocab.mjs +139 -589
- package/src/ask.mjs +627 -1729
- package/src/chat.mjs +1684 -2872
- package/src/cli-args.mjs +14 -28
- package/src/codegraph.mjs +236 -644
- package/src/completions/complete.mjs +18 -62
- package/src/completions/graph-adapter.mjs +14 -60
- package/src/completions/group.mjs +12 -68
- package/src/completions/infer.mjs +38 -126
- package/src/completions/prune.mjs +17 -70
- package/src/completions/rank.mjs +16 -69
- package/src/completions/search.mjs +8 -31
- package/src/concept.mjs +32 -88
- package/src/conformance.mjs +11 -15
- package/src/corpus/conceptnet.mjs +31 -89
- package/src/corpus/templates.mjs +19 -45
- package/src/corpus/unknown-ingest.mjs +31 -92
- package/src/embed.mjs +10 -22
- package/src/extensions.mjs +50 -154
- package/src/finish.mjs +35 -91
- package/src/grammar/ace.mjs +16 -40
- package/src/grammar/assert.mjs +1 -1
- package/src/grammar/lexicon-core.json +1 -1
- package/src/grammar/lexicon.mjs +9 -27
- package/src/graph-merge.mjs +2 -3
- package/src/hash.mjs +6 -14
- package/src/index.mjs +6 -10
- package/src/init.mjs +38 -125
- package/src/interpret/fuzzy.mjs +10 -29
- package/src/interpret/merge.mjs +9 -27
- package/src/interpret/normalize.mjs +137 -585
- package/src/interpret/pipeline.mjs +23 -71
- package/src/interpret/strategies/ace.mjs +7 -31
- package/src/interpret/strategies/constructions.mjs +14 -41
- package/src/interpret/strategies/grammar.mjs +21 -60
- package/src/interpret/strategies/keywords.mjs +42 -131
- package/src/interpret/strategies/noise-strip.mjs +18 -89
- package/src/memory/bias.mjs +11 -54
- package/src/memory/blocks.mjs +18 -69
- package/src/memory/core.mjs +171 -591
- package/src/memory/fold.mjs +0 -0
- package/src/memory/inspect.mjs +7 -25
- package/src/memory/shacl.mjs +10 -39
- package/src/memory/trust.mjs +26 -127
- package/src/memory-ask-browser-entry.mjs +7 -30
- package/src/memory-ask-browser.bundle.js +1 -1
- package/src/paraphrase.mjs +20 -53
- package/src/planning.mjs +15 -157
- package/src/prose-nlp.mjs +4 -17
- package/src/prose.mjs +19 -67
- package/src/providers/bootstrap.mjs +1 -2
- package/src/providers/fixture.mjs +1 -2
- package/src/providers/graph-service.mjs +28 -59
- package/src/repository-interface.mjs +6 -8
- package/src/router/drive.mjs +183 -0
- package/src/router/goal-reasoner.mjs +66 -231
- package/src/router/guardrail.mjs +20 -58
- package/src/router/planner.mjs +15 -46
- package/src/router/registry.mjs +13 -43
- package/src/router/resolver.mjs +46 -131
- package/src/router/results.mjs +231 -0
- package/src/schema-docs.mjs +10 -27
- package/src/server-http.mjs +10 -19
- package/src/server.mjs +22 -28
- package/src/sessions.mjs +15 -30
- package/src/source-slice.mjs +5 -7
- package/src/source.mjs +10 -20
- package/src/syllogise.mjs +187 -575
- package/src/telemetry.mjs +3 -3
- package/src/toml-config.mjs +4 -4
- package/src/tui/app.mjs +9 -19
- package/src/viz.mjs +66 -123
- package/src/wink-model.mjs +10 -24
package/src/ask-vocab.mjs
CHANGED
|
@@ -1,76 +1,19 @@
|
|
|
1
|
-
// ask-vocab.mjs — the
|
|
2
|
-
// hint, and renderer noun forms
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
// phrasings
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
// calls" contract this repo holds at every layer (extraction through query).
|
|
18
|
-
|
|
19
|
-
/** relation token -> { comment, verbs[] }. Every phrase in `verbs` must be
|
|
20
|
-
* something a developer would plausibly type asking about THIS relation in
|
|
21
|
-
* THIS codebase's terms — not a synonym so generic it risks matching an
|
|
22
|
-
* unrelated question (see the file-level comment; judgment calls on omitted
|
|
23
|
-
* phrases are logged inline below, not silently dropped).
|
|
24
|
-
*
|
|
25
|
-
* Register spread (2026-07-02, ELIZA/PARRY-style breadth, PLAN_MECHANICAL_CHAT.md
|
|
26
|
-
* §3.5): each relation's `verbs` list deliberately spans formal, neutral, and
|
|
27
|
-
* casual/colloquial phrasings — not just formal synonyms — because the value of
|
|
28
|
-
* a keyword-spotting matcher is SURFACE-FORM tolerance for the same underlying
|
|
29
|
-
* intent, not narrow correctness. Registers are grouped with an inline comment
|
|
30
|
-
* per relation rather than a per-phrase tag (kept flat, matching marginalia's
|
|
31
|
-
* `verbs: [...]` shape) since ask.mjs only needs phrase -> kind, never the
|
|
32
|
-
* register itself. A misparsed casual phrase costs nothing beyond an honest
|
|
33
|
-
* object-miss (resolveObject never guesses), so breadth here is genuinely low-risk. */
|
|
34
|
-
// REVERSE inherits phrasings (Seonix Batch 2 Fix 2) — "is X a superclass of Y" /
|
|
35
|
-
// "is X a parent class of Y" name the SAME `inherits` relation as the forward
|
|
36
|
-
// "is X a subclass of Y" verbs above, but with subject/object semantically
|
|
37
|
-
// SWAPPED: the questioner's X is the base, not the derived class. The "a"-forms
|
|
38
|
-
// (below) are folded into RELATIONS.inherits.verbs so VERB_TO_KIND maps them to
|
|
39
|
-
// kind "inherits" exactly like every forward verb — every existing
|
|
40
|
-
// inherits-consuming template/renderer keeps working unmodified — but ALSO kept
|
|
41
|
-
// as this separate exported list so the strategies that build "ask" shapes
|
|
42
|
-
// (subject-before/object-after by regex capture POSITION, not semantic
|
|
43
|
-
// direction — see grammar.mjs T1 and keywords.mjs's decomposition) can detect a
|
|
44
|
-
// reverse verb and swap subject/object at parse time, before evaluation ever
|
|
45
|
-
// sees it.
|
|
46
|
-
//
|
|
47
|
-
// Bare "superclass"/"superclasses" (single word, no "is … of" wrapper) are ALSO
|
|
48
|
-
// folded in: keyword-spot's decomposition (keywords.mjs) finds a verb phrase as
|
|
49
|
-
// a CONTIGUOUS run of words, and the interrogative word order ("is Base a
|
|
50
|
-
// superclass of Widget") puts the subject BETWEEN "is" and "a superclass of",
|
|
51
|
-
// breaking that contiguity for the 4-word phrase — exactly mirroring why the
|
|
52
|
-
// forward direction already carries bare "subclass"/"subclasses" alongside its
|
|
53
|
-
// own "is a subclass of" (both above, in RELATIONS.inherits.verbs): the bare
|
|
54
|
-
// stem is what actually lets keyword-spot's decomposition recognize the
|
|
55
|
-
// aux-first question form ("is Foo a subclass of Bar" only resolves today via
|
|
56
|
-
// that same bare "subclass" stem — see grammar.mjs T1's own comment).
|
|
57
|
-
//
|
|
58
|
-
// The "the"-DEFINITE forms ("is the superclass of", "are the superclass of",
|
|
59
|
-
// "is the parent class of") are named in INHERITS_REVERSE_VERBS below (the
|
|
60
|
-
// caller-requested literal set) but deliberately NOT folded into
|
|
61
|
-
// RELATIONS.inherits.verbs / VERB_TO_KIND: ask.mjs's CONTENT_VOCAB is built by
|
|
62
|
-
// splitting every VERB_TO_KIND key into its individual words (wordsOf), so a
|
|
63
|
-
// verb phrase containing the bare word "the" would leak "the" itself into
|
|
64
|
-
// CONTENT_VOCAB — and the progressive-relaxation cascade's NOISE-STRIP layer
|
|
65
|
-
// treats anything in CONTENT_VOCAB as un-strippable content, not noise. Verified
|
|
66
|
-
// live: folding the "the"-forms in broke test/ask-cascade.test.mjs's pinned
|
|
67
|
-
// NOISE-STRIP/DROP-UNMATCHED/SYNONYM-NORMALISE cases (each expects "the" to stay
|
|
68
|
-
// strippable) and test/chatflow-tier2.test.mjs's ESL-pronoun case, all of which
|
|
69
|
-
// rely on the pre-existing invariant that NO verb phrase in this file's tables
|
|
70
|
-
// ever contains the bare word "the" (confirmed true before this change). So the
|
|
71
|
-
// "the"-forms stay honest misses for now — "is a superclass of"/"are a
|
|
72
|
-
// superclass of" (the forms this Batch's own tests exercise) work; reinstating
|
|
73
|
-
// the "the"-forms would need a CONTENT_VOCAB fix first, out of this fix's scope.
|
|
1
|
+
// ask-vocab.mjs — the closed, curated vocabulary `ask.mjs`'s grammar, rephrase
|
|
2
|
+
// hint, and renderer noun forms derive from. No NLP library or lemmatiser:
|
|
3
|
+
// plain phrase lists feeding the same fixed-precedence regex grammar.
|
|
4
|
+
|
|
5
|
+
/** relation token -> { comment, verbs[] }. Each `verbs` list spans formal,
|
|
6
|
+
* neutral, and casual phrasings of the same relation; a misparse costs
|
|
7
|
+
* nothing beyond an honest object-miss (resolveObject never guesses). */
|
|
8
|
+
// Reverse `inherits` phrasings ("is X a superclass of Y") name the same
|
|
9
|
+
// relation as the forward verbs above but with subject/object swapped, so
|
|
10
|
+
// they're kept in INHERITS_REVERSE_VERB_LIST too: strategies that build "ask"
|
|
11
|
+
// shapes use it to detect a reverse verb and swap subject/object at parse
|
|
12
|
+
// time. The "the"-definite forms ("is the superclass of") are deliberately
|
|
13
|
+
// NOT folded into RELATIONS.inherits.verbs/VERB_TO_KIND: CONTENT_VOCAB is
|
|
14
|
+
// built by splitting every VERB_TO_KIND key into words, and no verb phrase
|
|
15
|
+
// here may contain the bare word "the" without breaking the relaxation
|
|
16
|
+
// cascade's noise-strip pass — so those forms stay honest misses.
|
|
74
17
|
const INHERITS_REVERSE_VERB_LIST = [
|
|
75
18
|
"is a superclass of",
|
|
76
19
|
"are a superclass of",
|
|
@@ -83,30 +26,25 @@ export const RELATIONS = {
|
|
|
83
26
|
imports: {
|
|
84
27
|
comment: "Module -> Module: subject's import graph references object (usesComplexType).",
|
|
85
28
|
verbs: [
|
|
86
|
-
// formal/neutral ("uses
|
|
87
|
-
//
|
|
29
|
+
// formal/neutral ("uses code from" stays here: its phrasing is
|
|
30
|
+
// specifically import-flavored)
|
|
88
31
|
"couples to", "couple to", "depends on", "imports", "import",
|
|
89
32
|
"relies on", "rely on", "requires", "require", "references", "reference",
|
|
90
33
|
"pulls in", "pull in", "built on", "builds on", "build on", "uses code from",
|
|
91
34
|
// casual/colloquial
|
|
92
35
|
"grabs", "grab", "pulls from", "pull from", "leans on", "lean on",
|
|
93
36
|
"is wired to", "are wired to", "is hooked up to", "are hooked up to",
|
|
94
|
-
// gerund (g-drop normalization turns dialectal "importin'" into this
|
|
37
|
+
// gerund (g-drop normalization turns dialectal "importin'" into this)
|
|
95
38
|
"importing",
|
|
96
39
|
],
|
|
97
40
|
},
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
// graph, so ask.mjs traverses it as imports + calls + callsSymbol together
|
|
101
|
-
// (KIND_UNIONS there). The verbs moved here FROM imports — "which modules use X"
|
|
102
|
-
// still answers with the importing modules (the asked Module grain filters the
|
|
103
|
-
// union down to module-grain subjects), and "what uses <function>" now also
|
|
104
|
-
// reaches the symbol-grain callers instead of silently ignoring them.
|
|
41
|
+
// query-side union, not a stored predicate: ask.mjs traverses "uses" as
|
|
42
|
+
// imports + calls + callsSymbol together (KIND_UNIONS).
|
|
105
43
|
uses: {
|
|
106
44
|
comment: "query-side union: imports (Module->Module) + calls (Module->Module) + callsSymbol (fn->fn).",
|
|
107
45
|
verbs: [
|
|
108
46
|
"uses", "use", "used by", "makes use of", "make use of",
|
|
109
|
-
// gerund (g-drop normalization
|
|
47
|
+
// gerund (g-drop normalization)
|
|
110
48
|
"using",
|
|
111
49
|
],
|
|
112
50
|
},
|
|
@@ -119,7 +57,7 @@ export const RELATIONS = {
|
|
|
119
57
|
"calls", "call", "runs", "run", "executes", "execute",
|
|
120
58
|
// casual/colloquial
|
|
121
59
|
"hits", "hit", "triggers", "trigger", "fires", "fire", "kicks off", "kick off",
|
|
122
|
-
// gerund (g-drop normalization turns dialectal "callin'" into this
|
|
60
|
+
// gerund (g-drop normalization turns dialectal "callin'" into this)
|
|
123
61
|
"calling",
|
|
124
62
|
],
|
|
125
63
|
},
|
|
@@ -128,7 +66,7 @@ export const RELATIONS = {
|
|
|
128
66
|
verbs: [
|
|
129
67
|
"defines", "define", "declares", "declare",
|
|
130
68
|
"has", "have", "holds", "hold",
|
|
131
|
-
// gerund (g-drop normalization
|
|
69
|
+
// gerund (g-drop normalization)
|
|
132
70
|
"defining",
|
|
133
71
|
],
|
|
134
72
|
},
|
|
@@ -137,7 +75,7 @@ export const RELATIONS = {
|
|
|
137
75
|
verbs: [
|
|
138
76
|
"contains", "contain", "lives in", "live in", "is defined in", "are defined in",
|
|
139
77
|
"is part of", "are part of", "sits in", "sit in", "sits inside", "sit inside",
|
|
140
|
-
// gerund (g-drop normalization
|
|
78
|
+
// gerund (g-drop normalization)
|
|
141
79
|
"containing",
|
|
142
80
|
],
|
|
143
81
|
},
|
|
@@ -146,7 +84,7 @@ export const RELATIONS = {
|
|
|
146
84
|
verbs: [
|
|
147
85
|
"tests", "test", "covers", "cover", "verifies", "verify", "exercises", "exercise",
|
|
148
86
|
"checks", "check", "makes sure of", "make sure of",
|
|
149
|
-
// gerund (g-drop normalization
|
|
87
|
+
// gerund (g-drop normalization)
|
|
150
88
|
"testing",
|
|
151
89
|
],
|
|
152
90
|
},
|
|
@@ -154,32 +92,14 @@ export const RELATIONS = {
|
|
|
154
92
|
comment: "Class -> Class: subject's declared base resolves to object (subclassOf).",
|
|
155
93
|
verbs: [
|
|
156
94
|
"inherits from", "inherit from",
|
|
157
|
-
// bare "inherits"/"inherit" (Tier 6 playtest, §3b surface-variation axis):
|
|
158
|
-
// this list's own SIBLING verb "extends"/"extend" already works bare, with
|
|
159
|
-
// no "from" required, but "inherits"/"inherit" — arguably the MORE common
|
|
160
|
-
// everyday phrasing of the two ("TaskController inherits Controller",
|
|
161
|
-
// "does TaskController inherit Controller") — had no bare form at all,
|
|
162
|
-
// only the "... from" variant. VERB_ALT's longest-first sort (already
|
|
163
|
-
// relied on elsewhere in this file for the same reason) means "inherits
|
|
164
|
-
// from"/"inherit from" still win whenever "from" actually follows, so
|
|
165
|
-
// this is purely additive.
|
|
166
95
|
"inherits", "inherit",
|
|
167
96
|
"extends", "extend", "subclasses", "subclass",
|
|
168
97
|
"derives from", "derive from", "is a subclass of", "are a subclass of",
|
|
169
98
|
"is a kind of", "are a kind of", "is built off", "are built off",
|
|
170
99
|
"is built on top of", "are built on top of",
|
|
171
|
-
// gerund
|
|
172
|
-
//
|
|
173
|
-
// Both the two-word "inheriting from" (so "from" is consumed into the verb
|
|
174
|
-
// phrase, not the object term) and the bare "inheriting" (the single token
|
|
175
|
-
// the gerund-lead check reads) are listed; longest-match-first prefers the
|
|
176
|
-
// two-word form when "from" follows.
|
|
100
|
+
// gerund, incl. compositional grammar's gerund-led boolean gate
|
|
101
|
+
// ("classes inheriting from Base but not tested")
|
|
177
102
|
"extending", "inheriting from", "inheriting", "subclassing", "extends from",
|
|
178
|
-
// REVERSE phrasings (Seonix Batch 2 Fix 2, see INHERITS_REVERSE_VERB_LIST's own
|
|
179
|
-
// comment above): "is/are a|the superclass/parent class of" — folded in here so
|
|
180
|
-
// VERB_TO_KIND maps them to "inherits" like every other verb in this list; the
|
|
181
|
-
// subject/object SWAP their direction requires is handled at parse time by the
|
|
182
|
-
// strategies that build the "ask" shape, not here.
|
|
183
103
|
...INHERITS_REVERSE_VERB_LIST,
|
|
184
104
|
],
|
|
185
105
|
},
|
|
@@ -190,28 +110,15 @@ export const RELATIONS = {
|
|
|
190
110
|
"was changed in", "were changed in", "was edited in", "were edited in",
|
|
191
111
|
"was modified by", "were modified by", "was tweaked in", "were tweaked in",
|
|
192
112
|
"got changed in", "got edited in",
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
// "what did commit <sha> touch", "which functions changed in <sha>", "which
|
|
196
|
-
// changes landed in commit <sha>", "what was touched by commit <sha>". Bare
|
|
197
|
-
// "touch" completes the touched/touches pair for the "did … touch" auxiliary
|
|
198
|
-
// form; the "by"/"in" phrases are the passive/locative counterparts of forms
|
|
199
|
-
// already above (curated per register spread, not a thesaurus dump).
|
|
113
|
+
// the same touch relation asked from the commit's side ("what did
|
|
114
|
+
// commit <sha> touch")
|
|
200
115
|
"touch", "touched by", "modified by", "changed by", "changed in",
|
|
201
116
|
"landed in", "land in",
|
|
202
|
-
//
|
|
203
|
-
//
|
|
204
|
-
// touch questions when the object is a commit — the sha-shaped object keeps
|
|
205
|
-
// them from firing on structural questions ("is X in the graph" has no verb
|
|
206
|
-
// match anyway). Judgment call: "is in" omitted — too generic without the
|
|
207
|
-
// past-tense anchor and risks matching containment phrasings.
|
|
117
|
+
// "was in"/"went into" only read as touch questions against a
|
|
118
|
+
// sha-shaped object
|
|
208
119
|
"was in", "were in", "went into", "included in",
|
|
209
|
-
// when-question forms (2026-07-02 query families): "when was X last
|
|
210
|
-
// updated/edited" — bare past participles that only read naturally in the
|
|
211
|
-
// temporal shape; the when template routes them, but they are ordinary
|
|
212
|
-
// touches verbs so "which modules were updated ..." keeps working too.
|
|
213
120
|
"updated", "edited",
|
|
214
|
-
// gerund (g-drop normalization
|
|
121
|
+
// gerund (g-drop normalization)
|
|
215
122
|
"touching",
|
|
216
123
|
],
|
|
217
124
|
},
|
|
@@ -222,17 +129,7 @@ export const RELATIONS = {
|
|
|
222
129
|
"change alongside", "shares commits with", "share commits with",
|
|
223
130
|
"tends to change together with", "tend to change together with",
|
|
224
131
|
"moves together with", "move together with",
|
|
225
|
-
// Track-1 trio (temporal lever): the bare "changed/change together with" form
|
|
226
|
-
// (no "tends to"/"tend to" prefix) was missing outright — "which modules
|
|
227
|
-
// changed together with X" fell through to the "touch(ed)" verb instead (a
|
|
228
|
-
// Commit->Module kind, structurally unable to match a Module subject), always
|
|
229
|
-
// producing a confidently-empty answer regardless of real cochange data.
|
|
230
132
|
"changed together with", "change together with", "changes together with",
|
|
231
|
-
// Present-tense bare form (Seonix Batch 4/5 follow-up): only the past tense
|
|
232
|
-
// "changed with" existed above — "what changes with X"/"what usually changes
|
|
233
|
-
// with X" fell through entirely (ENTITY_TO_TYPE's own "changes"->"Change"
|
|
234
|
-
// pseudo-type noun risked consuming the word first; see parseRelationalOrQualified's
|
|
235
|
-
// guard against exactly that in ask.mjs).
|
|
236
133
|
"changes with", "change with", "tends to change with", "tend to change with",
|
|
237
134
|
"usually changes with",
|
|
238
135
|
],
|
|
@@ -241,37 +138,23 @@ export const RELATIONS = {
|
|
|
241
138
|
comment: "Module -> exported symbol: subject's public API surface (__all__/export list).",
|
|
242
139
|
verbs: [
|
|
243
140
|
"exports", "export", "re-exports", "re-export", "passes through", "pass through",
|
|
244
|
-
// API-surface phrasing (2026-07-02 query families): "what does <module>
|
|
245
|
-
// expose". Bare "exposed" is NOT listed — the lemma tier maps it here when
|
|
246
|
-
// an adapter is present, and "how does the API get exposed" has no
|
|
247
|
-
// traversal either way (pinned as an honest miss in the tests).
|
|
248
141
|
"exposes", "expose",
|
|
249
|
-
// gerund (g-drop normalization
|
|
142
|
+
// gerund (g-drop normalization)
|
|
250
143
|
"exporting",
|
|
251
144
|
],
|
|
252
145
|
},
|
|
253
146
|
};
|
|
254
147
|
|
|
255
|
-
/** The closed set of reverse `inherits` verb phrasings a strategy
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
* comment above INHERITS_REVERSE_VERB_LIST, right before RELATIONS, for the full
|
|
259
|
-
* story). Every phrase here EXCEPT the three "the"-definite forms is ALSO folded
|
|
260
|
-
* into RELATIONS.inherits.verbs (so VERB_TO_KIND routes it to kind "inherits"
|
|
261
|
-
* like any other inherits verb) — the "the"-forms are named here for
|
|
262
|
-
* completeness (matching the originally-specified closed set) but are not yet
|
|
263
|
-
* reachable through VERB_TO_KIND, so a strategy will never actually see one as
|
|
264
|
-
* a matched verb; keeping them in this list is harmless and future-proofs the
|
|
265
|
-
* swap check for whenever the CONTENT_VOCAB constraint is lifted. */
|
|
148
|
+
/** The closed set of reverse `inherits` verb phrasings a strategy checks to
|
|
149
|
+
* decide whether to swap subject/object. The three "the"-definite forms are
|
|
150
|
+
* named here but not reachable through VERB_TO_KIND (see above). */
|
|
266
151
|
export const INHERITS_REVERSE_VERBS = Object.freeze([
|
|
267
152
|
...INHERITS_REVERSE_VERB_LIST,
|
|
268
153
|
"is the superclass of", "are the superclass of", "is the parent class of",
|
|
269
154
|
]);
|
|
270
155
|
|
|
271
|
-
// ---- where/when/mentions markers
|
|
272
|
-
//
|
|
273
|
-
// X mentioned"), so ask.mjs routes them by these marker words instead of
|
|
274
|
-
// VERB_TO_KIND. Closed lists, same curation discipline as everything above. ----
|
|
156
|
+
// ---- where/when/mentions markers: these questions carry no relation verb,
|
|
157
|
+
// so ask.mjs routes them by marker word instead of VERB_TO_KIND. ----
|
|
275
158
|
|
|
276
159
|
/** Definition-location markers: "where is X <marker>" (or bare "where is X"). */
|
|
277
160
|
export const WHERE_MARKERS = Object.freeze(["defined", "declared", "located", "implemented"]);
|
|
@@ -279,16 +162,11 @@ export const WHERE_MARKERS = Object.freeze(["defined", "declared", "located", "i
|
|
|
279
162
|
/** Prose-mention markers: "where is X <marker>" -> the prose/mentions surface. */
|
|
280
163
|
export const MENTION_MARKERS = Object.freeze(["mentioned", "referenced"]);
|
|
281
164
|
|
|
282
|
-
// ---- trailing scope filler
|
|
283
|
-
//
|
|
284
|
-
// the graph/codebase ITSELF, not onto any additional term: "what is a Module in
|
|
285
|
-
// this graph" means exactly "what is a Module", not a literal lookup of the glued
|
|
286
|
-
// phrase "Module in this graph". Closed and curated like every other table here —
|
|
287
|
-
// an unlisted trailing clause is left alone (an honest literal lookup), never
|
|
288
|
-
// silently swallowed by a general heuristic. ----
|
|
165
|
+
// ---- trailing scope filler: "what is a Module in this graph" resolves the
|
|
166
|
+
// same term as "what is a Module". ----
|
|
289
167
|
|
|
290
|
-
/** Trailing filler clauses stripped from the
|
|
291
|
-
* case-insensitive, before the term is used as a lookup key. */
|
|
168
|
+
/** Trailing filler clauses stripped from the end of a captured meta-whatis
|
|
169
|
+
* object, case-insensitive, before the term is used as a lookup key. */
|
|
292
170
|
export const TRAILING_SCOPE_FILLER = Object.freeze([
|
|
293
171
|
"in this graph", "in the graph", "in this codebase", "in the codebase",
|
|
294
172
|
"in this repo", "in the repo", "here",
|
|
@@ -298,58 +176,30 @@ const TRAILING_SCOPE_FILLER_RE = new RegExp(
|
|
|
298
176
|
`\\s+(?:${TRAILING_SCOPE_FILLER.join("|")})\\s*[?.!]*$`, "i",
|
|
299
177
|
);
|
|
300
178
|
|
|
301
|
-
/** Strip
|
|
302
|
-
*
|
|
303
|
-
* same term as "what is a Module". Applied once, not in a loop: no worked phrasing
|
|
304
|
-
* stacks two filler clauses. Every TRAILING_SCOPE_FILLER entry is plain words (no
|
|
305
|
-
* regex metacharacters), so no escaping is needed building the alternation. */
|
|
179
|
+
/** Strip one trailing scope-filler clause off the end of a captured
|
|
180
|
+
* meta-whatis object. Applied once: no worked phrasing stacks two. */
|
|
306
181
|
export function stripTrailingScopeFiller(text) {
|
|
307
182
|
return text.replace(TRAILING_SCOPE_FILLER_RE, "").trim();
|
|
308
183
|
}
|
|
309
184
|
|
|
310
|
-
/** Trailing bare discourse tags
|
|
311
|
-
*
|
|
312
|
-
* an otherwise-bare follow-up ("how many of those then"). A "what is X"
|
|
313
|
-
* meta-whatis question wasn't tolerant of this yet: "what is a component
|
|
314
|
-
* then" captured the literal unknown term "component then" instead of
|
|
315
|
-
* "component" (HANDOVER.md 2026-07-10, item 8). Stripped the same
|
|
316
|
-
* closed-list way as TRAILING_SCOPE_FILLER, just above. "too" (playtest
|
|
317
|
-
* sprint round 2): "is UserController a validator too then" — a STACKED
|
|
318
|
-
* pair of trailing tags — needed both "too" added to the set AND the strip
|
|
319
|
-
* applied twice (below), since a single pass only ever removes the
|
|
320
|
-
* outermost tag. */
|
|
185
|
+
/** Trailing bare discourse tags ("how many of those then"). "too" can stack
|
|
186
|
+
* ("is UserController a validator too then"), hence the double pass below. */
|
|
321
187
|
export const TRAILING_DISCOURSE_TAG = Object.freeze(["then", "though", "too"]);
|
|
322
188
|
|
|
323
189
|
const TRAILING_DISCOURSE_TAG_RE = new RegExp(
|
|
324
190
|
`\\s+(?:${TRAILING_DISCOURSE_TAG.join("|")})\\s*[?.!]*$`, "i",
|
|
325
191
|
);
|
|
326
192
|
|
|
327
|
-
/** Trailing
|
|
328
|
-
* explain")
|
|
329
|
-
* space-led tag, no comma): an ESL follow-on clause tacked onto a
|
|
330
|
-
* meta-whatis term after a comma, meaning "please explain [it]", not part of
|
|
331
|
-
* the term itself (BENCHMARK_CONVERSATION_1.7.0.md routed backlog C1). Closed
|
|
332
|
-
* and curated exactly like TRAILING_DISCOURSE_TAG — anchored on a LITERAL
|
|
333
|
-
* comma immediately before the tag, so this can never fire mid-phrase and
|
|
334
|
-
* can never touch a term that merely contains a comma for some other reason
|
|
335
|
-
* (no real code identifier ends in ", please explain" or ", explain"). */
|
|
193
|
+
/** Trailing comma-delimited discourse clauses ("what is a class, please
|
|
194
|
+
* explain"), anchored on a literal comma so this never fires mid-phrase. */
|
|
336
195
|
export const TRAILING_DISCOURSE_CLAUSE = Object.freeze(["please explain", "explain"]);
|
|
337
196
|
|
|
338
197
|
const TRAILING_DISCOURSE_CLAUSE_RE = new RegExp(
|
|
339
198
|
`,\\s*(?:${TRAILING_DISCOURSE_CLAUSE.join("|")})\\s*[?.!]*$`, "i",
|
|
340
199
|
);
|
|
341
200
|
|
|
342
|
-
/** Strip trailing
|
|
343
|
-
*
|
|
344
|
-
* above) off the end of a captured meta-whatis term — "what is a component
|
|
345
|
-
* then" resolves the same term as "what is a component", and "what is a
|
|
346
|
-
* class, please explain" resolves the same term as "what is a class".
|
|
347
|
-
* Applied up to twice (a stacked "too then"/"then too" is the only worked
|
|
348
|
-
* case that ever needs a second pass; no phrasing seen so far stacks a
|
|
349
|
-
* third), mirroring stripTrailingScopeFiller's own single-clause discipline
|
|
350
|
-
* for the common single-tag case while still covering the rarer
|
|
351
|
-
* double-tag one. The comma-clause strip runs each pass too, so "class,
|
|
352
|
-
* please explain then" (an unworked but plausible stack) still resolves. */
|
|
201
|
+
/** Strip trailing discourse tags and comma-delimited clauses off a captured
|
|
202
|
+
* meta-whatis term. Applied up to twice for a stacked "too then". */
|
|
353
203
|
export function stripTrailingDiscourseTag(text) {
|
|
354
204
|
let out = text;
|
|
355
205
|
for (let pass = 0; pass < 2; pass += 1) {
|
|
@@ -369,37 +219,14 @@ export const VERB_TO_KIND = Object.freeze(
|
|
|
369
219
|
),
|
|
370
220
|
);
|
|
371
221
|
|
|
372
|
-
/** "what is a kind of X" / "what is a subclass of X" collision fix
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
* animal"), the sentence isn't asking to define the noun phrase "kind of
|
|
381
|
-
* animal"; it's the exact same question as "what inherits from animal", just
|
|
382
|
-
* phrased with the verb's own "is a" lead instead of "inherits". keyword-spot
|
|
383
|
-
* (keywords.mjs) already reads it that way, unambiguously — the meta reading
|
|
384
|
-
* is the spurious one, and it collides with keyword-spot's correct reading to
|
|
385
|
-
* manufacture a needless {ambiguousParse} tie (interpret/merge.mjs) over a
|
|
386
|
-
* phrasing the engine itself just used a turn earlier. Derived from
|
|
387
|
-
* VERB_TO_KIND (not hand-duplicated) so any future plain "is a/are a X of"
|
|
388
|
-
* verb phrase added to RELATIONS is covered automatically, without touching
|
|
389
|
-
* this file again.
|
|
390
|
-
*
|
|
391
|
-
* Deliberately EXCLUDES every INHERITS_REVERSE_VERBS entry ("is a superclass
|
|
392
|
-
* of", "is a parent class of") even though they match the same "is a
|
|
393
|
-
* <continuation>" shape: those verbs' subject/object are semantically
|
|
394
|
-
* SWAPPED relative to storage direction (see INHERITS_REVERSE_VERB_LIST's own
|
|
395
|
-
* comment above) — "what is a superclass of X" asks a FORWARD question
|
|
396
|
-
* (X's own supertype), not this reverse-by-object listing, and keyword-spot's
|
|
397
|
-
* decomposition only applies that swap in the two-sided "ask" shape (verb
|
|
398
|
-
* between a subject AND an object), not this "reverse"-only afterText-only
|
|
399
|
-
* shape. Suppressing the meta reading for these too would trade one honest
|
|
400
|
-
* {ambiguousParse} wall for a confusing WRONG answer (a reverse-by-object
|
|
401
|
-
* lookup with the direction backwards) — a separate, pre-existing gap in
|
|
402
|
-
* keywords.mjs, out of this fix's scope. */
|
|
222
|
+
/** "what is a kind of X" / "what is a subclass of X" collision fix: some
|
|
223
|
+
* inherits verbs are themselves phrased "is a <continuation>", which would
|
|
224
|
+
* otherwise collide with grammar.mjs's literal meta-whatis reading and
|
|
225
|
+
* manufacture a spurious {ambiguousParse}. Derived from VERB_TO_KIND so any
|
|
226
|
+
* future "is a/are a X of" verb is covered automatically. Excludes
|
|
227
|
+
* INHERITS_REVERSE_VERBS: those verbs' subject/object are swapped relative
|
|
228
|
+
* to storage direction, so suppressing their meta reading would produce a
|
|
229
|
+
* wrong answer instead of an honest ambiguity. */
|
|
403
230
|
const NON_REVERSE_VERB = (v) => !INHERITS_REVERSE_VERBS.includes(v);
|
|
404
231
|
export const ARTICLE_RELATION_CONTINUATIONS = Object.freeze([
|
|
405
232
|
...new Set(
|
|
@@ -415,24 +242,13 @@ export const ENTITY_TO_TYPE = Object.freeze({
|
|
|
415
242
|
function: "Function", functions: "Function",
|
|
416
243
|
method: "Method", methods: "Method",
|
|
417
244
|
class: "Class", classes: "Class",
|
|
418
|
-
// "mod"/"mods" (HANDOVER.md 2026-07-10 item 10): a rushed-dev abbreviation
|
|
419
|
-
// prefix ("mod store.mjs imports") used to land in disambiguation instead of
|
|
420
|
-
// resolving cleanly, since nothing recognized "mod" as this same Module noun
|
|
421
|
-
// — same alias-of-Module trade "file"/"files" already make just above.
|
|
422
245
|
module: "Module", modules: "Module", mod: "Module", mods: "Module", file: "Module", files: "Module",
|
|
423
246
|
attribute: "Attribute", attributes: "Attribute", field: "Attribute", fields: "Attribute",
|
|
424
247
|
variable: "GlobalVariable", variables: "GlobalVariable", global: "GlobalVariable", globals: "GlobalVariable",
|
|
425
|
-
// "
|
|
426
|
-
//
|
|
427
|
-
//
|
|
428
|
-
//
|
|
429
|
-
// the given side. Mapped to the pseudo-type "Change" (not a node class): ask.mjs's
|
|
430
|
-
// traverse() reads it as a wildcard over the touch traversal's results rather than
|
|
431
|
-
// aliasing it to ONE real class and silently dropping the other grain of the
|
|
432
|
-
// answer. Listed BEFORE commit/commits: findPhrase (ask.mjs) takes the first
|
|
433
|
-
// same-length phrase in table order, so in "which changes touch commit <sha>" the
|
|
434
|
-
// entity slot must consume "changes" and leave "commit <sha>" intact as the
|
|
435
|
-
// object term.
|
|
248
|
+
// "Change" is a pseudo-type, not a node class: ask.mjs's traverse() reads it
|
|
249
|
+
// as a wildcard over touch-traversal results (module or symbol grain).
|
|
250
|
+
// Listed before commit/commits since findPhrase takes the first
|
|
251
|
+
// same-length match in table order.
|
|
436
252
|
change: "Change", changes: "Change",
|
|
437
253
|
commit: "Commit", commits: "Commit",
|
|
438
254
|
});
|
|
@@ -442,18 +258,11 @@ export const MODIFIER_TO_KIND = Object.freeze({
|
|
|
442
258
|
transitively: "transitive", indirectly: "transitive",
|
|
443
259
|
});
|
|
444
260
|
|
|
445
|
-
// ---- reversible-passive participles
|
|
446
|
-
//
|
|
447
|
-
//
|
|
448
|
-
//
|
|
449
|
-
//
|
|
450
|
-
// VERB_TO_KIND would silently re-route "where is X defined" and other queries. This
|
|
451
|
-
// table is consulted ONLY by the keyword strategy's passive path, which has already
|
|
452
|
-
// confirmed a passive auxiliary AND an agent-marking "by" — so an active query is never
|
|
453
|
-
// affected. Most common participles ("imported"/"tested"/"called"/"covered") already
|
|
454
|
-
// reach VERB_TO_KIND via the lemma tier; this table backfills the two families the lemma
|
|
455
|
-
// tier can't (defines/inherits) plus the obvious siblings, so the passive works
|
|
456
|
-
// adapter-free too. ----
|
|
261
|
+
// ---- reversible-passive participles: past participles -> relation kind, for
|
|
262
|
+
// the agent-marked passive "X is <participle> by Y". Kept separate from
|
|
263
|
+
// VERB_TO_KIND because these aren't standalone active verbs ("defined" would
|
|
264
|
+
// otherwise clobber the WHERE_MARKERS routing); only consulted once a passive
|
|
265
|
+
// auxiliary + agent-marking "by" is confirmed. ----
|
|
457
266
|
export const PASSIVE_PARTICIPLE_TO_KIND = Object.freeze({
|
|
458
267
|
imported: "imports", called: "calls", used: "uses",
|
|
459
268
|
tested: "tests", covered: "tests", verified: "tests", exercised: "tests", checked: "tests",
|
|
@@ -464,12 +273,8 @@ export const PASSIVE_PARTICIPLE_TO_KIND = Object.freeze({
|
|
|
464
273
|
touched: "touches", changed: "touches", modified: "touches", edited: "touches", updated: "touches",
|
|
465
274
|
});
|
|
466
275
|
|
|
467
|
-
// ----
|
|
468
|
-
//
|
|
469
|
-
// and the independent keyword-spotting strategy see the same normalized text —
|
|
470
|
-
// this table is not owned by either). Small and code-question-scoped, not a
|
|
471
|
-
// general slang dictionary — every entry here exists because it appears in an
|
|
472
|
-
// actual worked example this file's matcher must handle. ----
|
|
276
|
+
// ---- normalization: contractions/informal spellings expanded before parsing,
|
|
277
|
+
// shared by both parse strategies. ----
|
|
473
278
|
export const CONTRACTIONS = Object.freeze({
|
|
474
279
|
"ain't": "is not", "aint": "is not",
|
|
475
280
|
"isn't": "is not", "isnt": "is not",
|
|
@@ -487,28 +292,15 @@ export const CONTRACTIONS = Object.freeze({
|
|
|
487
292
|
"gimme": "give me",
|
|
488
293
|
});
|
|
489
294
|
|
|
490
|
-
// ---- misspellings and wrong words
|
|
491
|
-
//
|
|
492
|
-
//
|
|
493
|
-
//
|
|
494
|
-
//
|
|
495
|
-
// these tables exist so a typo'd or misused word maps to canonical language
|
|
496
|
-
// deterministically, ahead of (and more precisely than) ask.mjs's bounded
|
|
497
|
-
// edit-distance fallback. ask.mjs's correction regex refuses to rewrite a word
|
|
498
|
-
// glued to a dotted extension ("revision.mjs" stays a module name), since
|
|
499
|
-
// WRONG_WORDS entries are real English words that plausibly name modules; a
|
|
500
|
-
// bare standalone token that happens to be a real identifier remains the
|
|
501
|
-
// accepted residual exposure, same as CONTRACTIONS. ----
|
|
295
|
+
// ---- misspellings and wrong words: corrections, not synonyms — restore the
|
|
296
|
+
// canonical form before parsing (word-boundary, longest key first,
|
|
297
|
+
// case-insensitive), ahead of ask.mjs's bounded edit-distance fallback. The
|
|
298
|
+
// correction regex refuses to rewrite a word glued to a dotted extension
|
|
299
|
+
// ("revision.mjs" stays a module name). ----
|
|
502
300
|
|
|
503
|
-
/** Curated
|
|
504
|
-
* verbs, and
|
|
505
|
-
*
|
|
506
|
-
* always the canonical word. Judgment calls logged: "calss" maps to "class" (the
|
|
507
|
-
* doubled-s slip of "class"), NOT "calls", though both are edit-distance 1 — the
|
|
508
|
-
* exact tie the generic fuzzy tier must refuse to break; a curated table is where
|
|
509
|
-
* that call is made deliberately. "dose" is a real English word, but at a word
|
|
510
|
-
* boundary in this closed question grammar ("dose X import Y") the intent is
|
|
511
|
-
* unambiguous. */
|
|
301
|
+
/** Curated typos of this vocabulary's own keywords: entity nouns, relation
|
|
302
|
+
* verbs, and grammar anchor words (which/what/does/the). Values are always
|
|
303
|
+
* the canonical word. */
|
|
512
304
|
export const MISSPELLINGS = Object.freeze({
|
|
513
305
|
// entity nouns
|
|
514
306
|
"funtion": "function", "funtions": "functions",
|
|
@@ -531,14 +323,7 @@ export const MISSPELLINGS = Object.freeze({
|
|
|
531
323
|
"inherts": "inherits", "inheirts": "inherits",
|
|
532
324
|
"extands": "extends", "extneds": "extends",
|
|
533
325
|
"depnds": "depends",
|
|
534
|
-
"touchs": "touches", "tuoches": "touches", "touhced": "touched",
|
|
535
|
-
// "touchd" (BENCHMARK_CONVERSATION_1.7.0.md routed backlog C3): the
|
|
536
|
-
// dropped-vowel slip of "touched" — distinct from "touhced" above
|
|
537
|
-
// (transposed letters), same curated-typo discipline.
|
|
538
|
-
"touchd": "touched",
|
|
539
|
-
// WHERE_MARKERS typo (0.9.13 Tier-1 playtest): "defined" itself had no typo
|
|
540
|
-
// entry, so "where is it defned" fell through to the bare-object search path
|
|
541
|
-
// instead of the where-shape ("no module matching 'it defned' found").
|
|
326
|
+
"touchs": "touches", "tuoches": "touches", "touhced": "touched", "touchd": "touched",
|
|
542
327
|
"defned": "defined",
|
|
543
328
|
"chagned": "changed", "chnaged": "changed",
|
|
544
329
|
"chagnes": "changes", "chnages": "changes",
|
|
@@ -547,45 +332,14 @@ export const MISSPELLINGS = Object.freeze({
|
|
|
547
332
|
"tets": "tests",
|
|
548
333
|
// grammar anchor words
|
|
549
334
|
"whcih": "which", "wich": "which", "whihc": "which",
|
|
550
|
-
// "
|
|
551
|
-
//
|
|
552
|
-
// (unlike which/what/does/the above), so a plain dropped/transposed letter
|
|
553
|
-
// fell straight through resolveObject and hit either the grammar wall or a
|
|
554
|
-
// bogus "no module matching 'it defined'" search. "were" (the missing-h
|
|
555
|
-
// homophone slip) is NOT curated here — it's a real word already load-bearing
|
|
556
|
-
// as the TEMPORAL_AUX auxiliary ("when were the modules last touched"), so
|
|
557
|
-
// that one typo is handled by its own anchored phrasing frame instead
|
|
558
|
-
// (normalize.mjs PHRASING_FRAMES) to avoid clobbering the legitimate reading.
|
|
335
|
+
// "were" (the missing-h homophone slip of "where") is NOT curated here —
|
|
336
|
+
// it's a load-bearing TEMPORAL_AUX word ("when were the modules touched").
|
|
559
337
|
"wehre": "where", "whre": "where",
|
|
560
|
-
// "wat" (chatbench cycle 2, tf-wat-calls): the internet-casual spelling of
|
|
561
|
-
// "what" — neither curated noise nor a restorable trigger typo, so "wat calls
|
|
562
|
-
// fnAlpha" used to die as "couldn't resolve one of the terms". Restored here
|
|
563
|
-
// so BOTH parse strategies and the relaxation cascade see the canonical
|
|
564
|
-
// anchor; the correction regex's dotted-extension guard keeps a module
|
|
565
|
-
// literally named "wat.mjs" untouched, same residual trade as every entry.
|
|
566
338
|
"waht": "what", "wat": "what",
|
|
567
|
-
// "dat" (BENCHMARK_CONVERSATION_1.7.0.md routed backlog C3): the internet-
|
|
568
|
-
// casual spelling of "that" — same register as "wat"/"waht" just above,
|
|
569
|
-
// curated rather than left to the generic fuzzy tier since "that" is a
|
|
570
|
-
// load-bearing anchor word throughout this grammar (TEACH_RE's own
|
|
571
|
-
// "remember that X", relative-clause objects, etc).
|
|
572
339
|
"dat": "that",
|
|
573
340
|
"dose": "does", "doess": "does",
|
|
574
341
|
"teh": "the",
|
|
575
|
-
|
|
576
|
-
// or list trigger used to be DROPPED as unmatched by the relaxation cascade, losing
|
|
577
|
-
// the aggregate/list INTENT entirely ("how manyn classes" → the count was lost);
|
|
578
|
-
// curated here so the intended trigger is restored BEFORE parsing (the general
|
|
579
|
-
// bounded fuzzy path in ask.mjs's cascade is the backstop for uncurated typos).
|
|
580
|
-
"manyn": "many", "mnay": "many", "amny": "many", "mnany": "many",
|
|
581
|
-
// "hwo" (Tier 6 playtest, §3b typo axis): a transposed-letter typo of "how" —
|
|
582
|
-
// "hwo many classes are there" used to lose the aggregate/list trigger
|
|
583
|
-
// outright ("how many" only reads as a count trigger when both words are
|
|
584
|
-
// exact), same failure class as "manyn"/"mnay" just above, one word to the
|
|
585
|
-
// left of it. "how" is grammar-owned via AGGREGATE_TRIGGERS' own "how many"/
|
|
586
|
-
// "how much" entries (test/ask-vocab.test.mjs's canonical-value check
|
|
587
|
-
// splits those multi-word triggers into individual words).
|
|
588
|
-
"hwo": "how",
|
|
342
|
+
"manyn": "many", "mnay": "many", "amny": "many", "mnany": "many", "hwo": "how",
|
|
589
343
|
"coutn": "count", "conut": "count", "cuont": "count", "ocunt": "count",
|
|
590
344
|
"numer": "number", "nubmer": "number", "numbr": "number", "nmuber": "number",
|
|
591
345
|
"lst": "list", "lsit": "list", "ilst": "list",
|
|
@@ -594,12 +348,9 @@ export const MISSPELLINGS = Object.freeze({
|
|
|
594
348
|
"funtcions": "functions", "funciton": "function", "funcitons": "functions",
|
|
595
349
|
});
|
|
596
350
|
|
|
597
|
-
/** Words used
|
|
598
|
-
* term —
|
|
599
|
-
*
|
|
600
|
-
* Only mapped where intent is unambiguous in a code-graph question; words
|
|
601
|
-
* deliberately NOT mapped are logged in the omitted-on-purpose block at the end
|
|
602
|
-
* of this file. */
|
|
351
|
+
/** Words used incorrectly but with clear intent, mapped to the canonical
|
|
352
|
+
* schema term — corrections of usage, not alternative names (hence not in
|
|
353
|
+
* ENTITY_TO_TYPE). */
|
|
603
354
|
export const WRONG_WORDS = Object.freeze({
|
|
604
355
|
// neither a folder nor a directory grain exists in this graph — in "which
|
|
605
356
|
// folders import X" the only honest referent is the module/file grain.
|
|
@@ -614,63 +365,28 @@ export const WRONG_WORDS = Object.freeze({
|
|
|
614
365
|
"property": "attribute", "properties": "attributes",
|
|
615
366
|
});
|
|
616
367
|
|
|
617
|
-
/** Trailing g-drop ("callin'", "hittin'")
|
|
618
|
-
*
|
|
619
|
-
*
|
|
620
|
-
* apostrophe are real English words far more often than dropped g's
|
|
621
|
-
* ("cabin", "robin", "chin", "twin") — restoring those would be a false
|
|
622
|
-
* positive the anchored templates never had to worry about. No trailing
|
|
623
|
-
* `\b` after the apostrophe: `'` is a non-word character, so a `\b` there
|
|
624
|
-
* can never match the (non-word) whitespace/end-of-string that follows —
|
|
625
|
-
* the apostrophe itself already delimits the word, a second boundary check
|
|
626
|
-
* after it is redundant and unmatchable. */
|
|
368
|
+
/** Trailing g-drop ("callin'", "hittin'"): -in' -> -ing. The apostrophe is
|
|
369
|
+
* required — bare "-in" endings are real words far more often than dropped
|
|
370
|
+
* g's ("cabin", "robin", "twin"). */
|
|
627
371
|
export const G_DROP = /\b([a-z]{3,})in'/gi;
|
|
628
372
|
|
|
629
373
|
/** Words stripped during normalization/keyword-spotting once they carry no
|
|
630
|
-
* grammatical weight
|
|
631
|
-
*
|
|
632
|
-
* relation verb, entity noun, or modifier (those are checked first).
|
|
633
|
-
* Bare "you" (0.9.14 Tier-2 playtest, §3b ESL angle): a non-native word-order
|
|
634
|
-
* slip ("please you tell me what is Class", "you tell me what is Class") left
|
|
635
|
-
* a leading "you" that "could you"/"can you"/"would you" don't cover (those
|
|
636
|
-
* are anchored WRAPPERS requiring the verb-first order) — the leftover
|
|
637
|
-
* pronoun broke the bare "what is Class" no-article count reading, which
|
|
638
|
-
* (unlike the "what is a Class" meta form) requires the WHOLE normalized
|
|
639
|
-
* string to match, not just a substring. "you" carries no grammatical weight
|
|
640
|
-
* in this code-graph grammar (never a real entity/relation term), so it is
|
|
641
|
-
* safe to strip anywhere, same trade as every other word in this list. */
|
|
374
|
+
* grammatical weight — greetings, politeness, hedges, discourse fillers.
|
|
375
|
+
* Never strips a relation verb, entity noun, or modifier. */
|
|
642
376
|
export const FILLER_WORDS = Object.freeze([
|
|
643
377
|
"um", "uh", "erm", "so", "like", "yo", "hey", "bru", "bro", "fam", "mate",
|
|
644
378
|
"please", "could you", "can you", "would you", "tell me", "i wonder",
|
|
645
379
|
"just wondering", "quickly", "real quick", "kinda", "sorta",
|
|
646
380
|
"btw", "by the way", "you",
|
|
647
|
-
// "quick q" (BENCHMARK_CONVERSATION_1.8.14.md item 11): the casual abbreviated
|
|
648
|
-
// sibling of GREETING_PREAMBLE_RE's own "quick question" clause (normalize.mjs)
|
|
649
|
-
// — that frame requires a delimiter immediately after the greeting word
|
|
650
|
-
// ("hey, quick question - …"), so it never matches "hey quick q, …" (no
|
|
651
|
-
// delimiter between "hey" and "quick q"). Filler-stripping instead — this
|
|
652
|
-
// list is matched word-boundary-anywhere, not anchored — closes the gap
|
|
653
|
-
// without needing GREETING_PREAMBLE_RE's own stricter delimiter-position
|
|
654
|
-
// shape.
|
|
655
381
|
"quick q",
|
|
656
382
|
]);
|
|
657
383
|
|
|
658
|
-
/** Deictic/pronoun terms
|
|
659
|
-
*
|
|
660
|
-
* spotting; wired from the graph viewer's currently-selected node, when the
|
|
661
|
-
* chat panel is asking "about" whatever the user last clicked). With no
|
|
662
|
-
* context available (the bare CLI surface), these produce an honest
|
|
663
|
-
* "which node does 'this' refer to?" miss — never a guess. */
|
|
384
|
+
/** Deictic/pronoun terms resolved against an optional `contextId` (the graph
|
|
385
|
+
* viewer's currently-selected node). With no context, an honest miss. */
|
|
664
386
|
export const CONTEXT_PRONOUNS = Object.freeze(["this", "it", "that", "here", "this one", "that one"]);
|
|
665
387
|
|
|
666
|
-
// ----
|
|
667
|
-
//
|
|
668
|
-
// affirmative form of the SAME question (not a general negation-scope parser
|
|
669
|
-
// — ELIZA/PARRY's own scope discipline: a handful of recognized frames, not
|
|
670
|
-
// an attempt at full logical negation handling). Each frame is tried in
|
|
671
|
-
// order; the first match rewrites the whole string and normalization stops
|
|
672
|
-
// (a second negation frame firing on an already-rewritten string would be a
|
|
673
|
-
// design smell, not a feature). ----
|
|
388
|
+
// ---- negation frames: a small set of double-negative / negative-rhetorical
|
|
389
|
+
// constructions, normalized to the affirmative form. First match wins. ----
|
|
674
390
|
export const NEGATION_FRAMES = Object.freeze([
|
|
675
391
|
// "there ain't nothin' calling it" / "there isn't nothing that calls it"
|
|
676
392
|
// -> "what calls it"
|
|
@@ -683,18 +399,9 @@ export const NEGATION_FRAMES = Object.freeze([
|
|
|
683
399
|
{ re: /\b(?:nobody|nothing|no one)\s+(\S.*?)(?:,?\s+does\s+it\??|,?\s+do\s+they\??)?$/i, to: (m) => `what ${m[1]}` },
|
|
684
400
|
]);
|
|
685
401
|
|
|
686
|
-
// ---- commit-content frames
|
|
687
|
-
//
|
|
688
|
-
//
|
|
689
|
-
// frames run), "what went into <sha>", "what made it into commit <sha>" all mean
|
|
690
|
-
// the canonical commit-subject question "what did <sha> touch", so they are
|
|
691
|
-
// REWRITTEN to it before either parse strategy runs: the same mechanism and scope
|
|
692
|
-
// discipline as NEGATION_FRAMES (a small closed pattern set, first match wins),
|
|
693
|
-
// which also makes both strategies parse the family for free. The sha-shaped tail
|
|
694
|
-
// is REQUIRED so these frames only ever fire on an actual commit reference: over a
|
|
695
|
-
// non-sha object ("what was in walk.mjs") the frame does not match and the text is
|
|
696
|
-
// left for the ordinary grammar to handle as it already does, rather than being
|
|
697
|
-
// bent into a commit-subject touches query that would then blank. ----
|
|
402
|
+
// ---- commit-content frames: "what was in commit <sha>" etc. rewrite to the
|
|
403
|
+
// canonical "what did <sha> touch" before either parse strategy runs. The
|
|
404
|
+
// sha-shaped tail keeps this from firing on a non-commit object. ----
|
|
698
405
|
export const COMMIT_CONTENT_FRAMES = Object.freeze([
|
|
699
406
|
// "what was in commit ef74e44e25c8" / "what is in ef74e44e" / "what's in commit <sha>"
|
|
700
407
|
{ re: /^what\s+(?:is|was|were|are)\s+in\s+((?:commit\s+)?[0-9a-f]{7,40})\??$/i, to: (m) => `what did ${m[1]} touch` },
|
|
@@ -704,49 +411,29 @@ export const COMMIT_CONTENT_FRAMES = Object.freeze([
|
|
|
704
411
|
{ re: /^what\s+made\s+it\s+into\s+((?:commit\s+)?[0-9a-f]{7,40})\??$/i, to: (m) => `what did ${m[1]} touch` },
|
|
705
412
|
]);
|
|
706
413
|
|
|
707
|
-
// ----
|
|
708
|
-
//
|
|
709
|
-
//
|
|
710
|
-
// phrases don't name a graph relation kind for edgesOfKind to traverse, they name
|
|
711
|
-
// "explain this term" intent. Adding them to VERB_TO_KIND would make
|
|
712
|
-
// parseKeywordSpot's decomposition matcher independently derive a *different* shape
|
|
713
|
-
// ("forward", the only shape its before-only-text case produces) for the very same
|
|
714
|
-
// sentence the anchored meta template resolves to shape:"meta" — a spurious strategy
|
|
715
|
-
// DISAGREEMENT (ambiguousParse) on every meta question. So this table is read directly
|
|
716
|
-
// by ask.mjs's own meta template, never merged into the shared verb tables. ----
|
|
414
|
+
// ---- meta-vocabulary: trigger phrases for "what does cochange mean"-style
|
|
415
|
+
// term-explanation questions. Kept out of RELATIONS/VERB_TO_KIND — these name
|
|
416
|
+
// "explain this term" intent, not a graph relation to traverse. ----
|
|
717
417
|
export const META_MEANING_VERBS = Object.freeze([
|
|
718
418
|
"mean", "means", "stand for", "stands for", "signify", "signifies",
|
|
719
419
|
"represent", "represents", "refer to", "refers to",
|
|
720
420
|
]);
|
|
721
421
|
|
|
722
|
-
// ----
|
|
723
|
-
//
|
|
724
|
-
//
|
|
725
|
-
//
|
|
726
|
-
// superlatives, and anaphora — that compose the SAME closed clause vocabulary
|
|
727
|
-
// (RELATIONS/ENTITY_TO_TYPE above) into multi-hop / set-algebra queries. The
|
|
728
|
-
// grammar COMPOSES the closed vocabulary; it never opens it. Every table here is
|
|
729
|
-
// curated + closed, same discipline as everything above: a marker the tables don't
|
|
730
|
-
// carry is an honest miss, never a guess. ----
|
|
422
|
+
// ---- compositional grammar vocabulary — ask.mjs's parseComposite reads these
|
|
423
|
+
// to recognize relative clauses, boolean connectives, qualifiers, aggregates,
|
|
424
|
+
// superlatives, and anaphora that compose RELATIONS/ENTITY_TO_TYPE into
|
|
425
|
+
// multi-hop / set-algebra queries. ----
|
|
731
426
|
|
|
732
|
-
/** Relative-clause introducers: "<noun> that/which/who <predicate>".
|
|
733
|
-
*
|
|
734
|
-
*
|
|
735
|
-
* so position, not mere presence, decides. This gates the nested/relative and
|
|
736
|
-
* same-subject boolean shapes: their absence is exactly what keeps the bare
|
|
737
|
-
* reverse-template query "which classes extends Base and couples to logging" out
|
|
738
|
-
* of the compositional path (it stays the existing two-strategy ambiguous parse). */
|
|
427
|
+
/** Relative-clause introducers: "<noun> that/which/who <predicate>". Read as
|
|
428
|
+
* a relative pronoun only after a noun and before a predicate — "that" is
|
|
429
|
+
* also a CONTEXT_PRONOUN, so position decides. */
|
|
739
430
|
export const RELATIVE_PRONOUNS = Object.freeze(["that", "which", "who"]);
|
|
740
431
|
|
|
741
|
-
/** Placeholder object nouns
|
|
742
|
-
*
|
|
743
|
-
* result set. Mapped to entityType null (any grain); a real entity noun in the
|
|
744
|
-
* same slot ("what calls modules that import X") narrows the grain instead. */
|
|
432
|
+
/** Placeholder object nouns ("what calls something that imports X"): name no
|
|
433
|
+
* entity, stand in for the inner clause's result set (entityType null). */
|
|
745
434
|
export const PLACEHOLDER_NOUNS = Object.freeze([
|
|
746
435
|
"something", "anything", "everything", "somethings", "things", "thing",
|
|
747
436
|
"entities", "entity", "nodes", "node", "stuff", "code",
|
|
748
|
-
// "symbol(s)" is a grain-agnostic stand-in for any code entity — "exported
|
|
749
|
-
// symbols of X" means whatever X defines, at any grain, filtered by the qualifier.
|
|
750
437
|
"symbol", "symbols",
|
|
751
438
|
]);
|
|
752
439
|
|
|
@@ -761,14 +448,10 @@ export const BOOLEAN_CONNECTIVES = Object.freeze({
|
|
|
761
448
|
"or": "union",
|
|
762
449
|
});
|
|
763
450
|
|
|
764
|
-
/** Subject
|
|
765
|
-
* attributes/edges the graph already carries
|
|
766
|
-
*
|
|
767
|
-
*
|
|
768
|
-
* the tests edge set (tested/untested). `isAbstract` is never populated by any
|
|
769
|
-
* extractor today (codegraph.mjs says so) — "abstract methods" therefore honestly
|
|
770
|
-
* returns an empty set, not an error, exactly like any other zero-hit answer. An
|
|
771
|
-
* UNKNOWN qualifier is an honest miss naming these supported ones (ask.mjs). */
|
|
451
|
+
/** Subject qualifiers (adjectives) -> a post-filter over the result set, read
|
|
452
|
+
* off attributes/edges the graph already carries. `isAbstract` is never
|
|
453
|
+
* populated by any extractor today, so "abstract methods" honestly returns
|
|
454
|
+
* an empty set, not an error. */
|
|
772
455
|
export const QUALIFIERS = Object.freeze({
|
|
773
456
|
public: { via: "visibility", value: "public" },
|
|
774
457
|
private: { via: "visibility", value: "private" },
|
|
@@ -785,59 +468,24 @@ export const QUALIFIERS = Object.freeze({
|
|
|
785
468
|
});
|
|
786
469
|
|
|
787
470
|
/** Aggregate/count triggers: "how many <kind> …", "count <kind>s", "number of
|
|
788
|
-
* <kind>".
|
|
789
|
-
*
|
|
790
|
-
*
|
|
791
|
-
* ("how many"/"number of"), a neutral/imperative ("count"/"count up"), and a
|
|
792
|
-
* quantity ("quantity of"/"total number of") register a developer actually types.
|
|
793
|
-
* Judgement calls, kept OUT deliberately: bare "tally"/"sum"/"total" — those are
|
|
794
|
-
* already mapped to "count" by CASCADE_SYNONYMS (ask.mjs's relaxation layer), and a
|
|
795
|
-
* cascade test asserts "tally the classes" reaches the count via that synonym path,
|
|
796
|
-
* so promoting them to direct triggers here would both duplicate the mapping and
|
|
797
|
-
* break that test; and single-word "total"/"sum" would false-match identifier
|
|
798
|
-
* fragments ("total price", "sum of squares") the count intent never meant. */
|
|
471
|
+
* <kind>". Bare "tally"/"sum"/"total" are deliberately excluded — they're
|
|
472
|
+
* identifier-fragment risks ("total price") and stay CASCADE_SYNONYMS-mapped
|
|
473
|
+
* instead. */
|
|
799
474
|
export const AGGREGATE_TRIGGERS = Object.freeze([
|
|
800
|
-
// formal ("the number of classes" reaches "number of" once the cascade strips the
|
|
801
|
-
// leading article — keeping the trigger list clear of "the" so it never enters
|
|
802
|
-
// CONTENT_VOCAB and blocks the article's own noise-strip)
|
|
803
475
|
"how many", "how much", "how many of", "number of",
|
|
804
476
|
"total number of", "quantity of",
|
|
805
|
-
// "<measure> of <kind>" cardinality forms (widened net, cycle W2P): count = sum = total
|
|
806
|
-
// = tally = number of. The bare single words (sum/total/tally) stay CASCADE_SYNONYMS-
|
|
807
|
-
// mapped to "count" (identifier-fragment risk without the "of" anchor — see that table's
|
|
808
|
-
// note); the multi-word "of" forms are safe to promote to direct triggers because the
|
|
809
|
-
// trailing "of <kind>" pins them to a cardinality question, not a stray identifier.
|
|
810
477
|
"tally of", "sum of", "total of", "amount of",
|
|
811
|
-
// neutral / imperative (bare "tally"/"sum"/"total" stay CASCADE_SYNONYMS-mapped so the
|
|
812
|
-
// "tally the classes" relaxation path — pinned by a cascade test — is preserved).
|
|
813
478
|
"count", "count up", "count of", "tot up",
|
|
814
479
|
]);
|
|
815
480
|
|
|
816
|
-
/**
|
|
817
|
-
*
|
|
818
|
-
*
|
|
819
|
-
*
|
|
820
|
-
* trailing scope/predicate narrows it, and an unknown kind after a clear list trigger
|
|
821
|
-
* is an honest miss naming the kinds. Two registers, wide-but-deliberate (the operator's
|
|
822
|
-
* "err toward inclusion", bounded by the file-header discipline: a phrase earns its
|
|
823
|
-
* place only if it genuinely means "enumerate these" and won't false-match an unrelated
|
|
824
|
-
* identifier — parseList further requires a real entity kind to follow, so a stray
|
|
825
|
-
* "show"/"name" in another question is never seized):
|
|
826
|
-
* · IMPERATIVE — "<verb> [me/us] [the] <kind>". Bare determiners/objects (the/a/all/
|
|
827
|
-
* me/us) after the verb are skipped by parseList's LIST_SKIP, so only the verb stem
|
|
828
|
-
* is listed here (not every "... the"/"... all" inflection).
|
|
829
|
-
* · INTERROGATIVE — "what/which are [the] <kind>"; the bare "what <kind>"/"which
|
|
830
|
-
* <kind>" (+ optional "are there") form is handled directly in parseList, not here.
|
|
831
|
-
* Kept OUT on purpose: "tell me" / "give me" collide only where normalizeQuery already
|
|
832
|
-
* strips them as FILLER_WORDS ("tell me the classes" → "the classes"), so "tell me" is
|
|
833
|
-
* omitted (it never survives to parseList); "gimme" is omitted because CONTRACTIONS
|
|
834
|
-
* rewrites it to "give me" before parseList runs. */
|
|
481
|
+
/** List triggers ("list functions", "show me the classes"). Read by
|
|
482
|
+
* ask.mjs's parseList: a trigger followed by an entity kind noun lists that
|
|
483
|
+
* class; an unknown kind is an honest miss. "tell me"/"gimme" are omitted —
|
|
484
|
+
* both normalize away before parseList runs. */
|
|
835
485
|
export const LIST_TRIGGERS = Object.freeze([
|
|
836
|
-
// imperative — "<verb> [me/us] [the] <kind>"
|
|
837
486
|
"list", "show", "show me", "show us", "display", "print", "print out",
|
|
838
487
|
"dump", "enumerate", "name", "give me", "get me", "spit out", "rattle off",
|
|
839
488
|
"run down", "run through", "ls",
|
|
840
|
-
// interrogative — "what/which are [the] <kind>"
|
|
841
489
|
"what are", "which are",
|
|
842
490
|
]);
|
|
843
491
|
|
|
@@ -851,13 +499,8 @@ export const SUPERLATIVE_EXTREMES = Object.freeze({
|
|
|
851
499
|
});
|
|
852
500
|
|
|
853
501
|
/** Degree-metric nouns for superlatives ("which module has the most <noun>") ->
|
|
854
|
-
* {kind, dir}
|
|
855
|
-
*
|
|
856
|
-
* where it is the object (its importers/callers/tests). "connections"/"edges"/
|
|
857
|
-
* "connected" is the total (both directions, all structural kinds). A `sibling`
|
|
858
|
-
* fine-grained kind is added to the tally when present (callers include the
|
|
859
|
-
* symbol-grain callsSymbol edges, not just module-coarse calls); a `filter`
|
|
860
|
-
* restricts the counted objects to one class ("methods"). */
|
|
502
|
+
* {kind, dir}. dir "out" counts the ranked entity as subject; "in" as object.
|
|
503
|
+
* `sibling` adds a fine-grained kind to the tally; `filter` restricts to one class. */
|
|
861
504
|
export const EDGE_NOUN_TO_METRIC = Object.freeze({
|
|
862
505
|
imports: { kind: "imports", dir: "out" },
|
|
863
506
|
dependencies: { kind: "imports", dir: "out" },
|
|
@@ -874,12 +517,7 @@ export const EDGE_NOUN_TO_METRIC = Object.freeze({
|
|
|
874
517
|
connections: { kind: "*", dir: "both" },
|
|
875
518
|
edges: { kind: "*", dir: "both" },
|
|
876
519
|
connected: { kind: "*", dir: "both" },
|
|
877
|
-
// participle degree-nouns
|
|
878
|
-
// depended-on / most used <module>" ranks by IN-degree — how many things import/depend
|
|
879
|
-
// on/use it — the ARGMAX-by-degree intent a developer expresses with a passive
|
|
880
|
-
// participle rather than the noun ("importers"). "depended" catches "depended-on" /
|
|
881
|
-
// "depended on" (both tokenize to a bare "depended"); "used" folds the symbol-grain
|
|
882
|
-
// callsSymbol callers in alongside importers so "most used" reads as most-relied-upon.
|
|
520
|
+
// participle degree-nouns rank by in-degree, same intent as "importers" etc
|
|
883
521
|
imported: { kind: "imports", dir: "in" },
|
|
884
522
|
"depended-on": { kind: "imports", dir: "in" },
|
|
885
523
|
depended: { kind: "imports", dir: "in" },
|
|
@@ -887,13 +525,9 @@ export const EDGE_NOUN_TO_METRIC = Object.freeze({
|
|
|
887
525
|
called: { kind: "calls", dir: "in", sibling: "callsSymbol" },
|
|
888
526
|
});
|
|
889
527
|
|
|
890
|
-
/** Metric nouns whose edge kind targets exactly
|
|
891
|
-
*
|
|
892
|
-
*
|
|
893
|
-
* metric but no explicit entity noun ("what most needs a test", vs. the fully
|
|
894
|
-
* explicit "which MODULE has the most tests"). Deliberately small: a metric like
|
|
895
|
-
* "calls"/"connections" targets more than one class, so it is NOT listed here —
|
|
896
|
-
* those keep requiring an explicit entity noun, same as before this table existed. */
|
|
528
|
+
/** Metric nouns whose edge kind targets exactly one entity class — lets
|
|
529
|
+
* parseSuperlative default `entityType` when no explicit noun is given
|
|
530
|
+
* ("what most needs a test"). */
|
|
897
531
|
export const METRIC_IMPLIES_ENTITY = Object.freeze({
|
|
898
532
|
tests: "Module",
|
|
899
533
|
test: "Module",
|
|
@@ -912,119 +546,35 @@ export const ANAPHORA_TRIGGERS = Object.freeze(["those", "them", "these"]);
|
|
|
912
546
|
* the asked entity type narrows the result. */
|
|
913
547
|
export const MEMBERSHIP_KINDS = Object.freeze(["contains", "defines"]);
|
|
914
548
|
|
|
915
|
-
// ----
|
|
916
|
-
//
|
|
917
|
-
//
|
|
918
|
-
//
|
|
919
|
-
// it never invents a term or guesses an entity, and it bottoms out in the same honest
|
|
920
|
-
// rephrase hint. Every entry is hand-curated with inline provenance, same "closed is
|
|
921
|
-
// deliberate" ethos as everything above: a word these tables don't carry is left for
|
|
922
|
-
// the honest miss, never a general-English stoplist that would silently eat a real
|
|
923
|
-
// code term. ----
|
|
549
|
+
// ---- progressive-relaxation cascade vocabulary: the tables ask.mjs's
|
|
550
|
+
// relaxParse reads when the direct parse of a query would miss. Only ever
|
|
551
|
+
// drops noise/unmatched words or normalises a near-canonical word; never
|
|
552
|
+
// invents a term or guesses an entity. ----
|
|
924
553
|
|
|
925
|
-
/** Politeness
|
|
926
|
-
*
|
|
927
|
-
*
|
|
928
|
-
* qualifier, aggregate/superlative trigger, …) and does NOT resolve to a graph entity
|
|
929
|
-
* (ask.mjs guards both), so a module literally named "show" or "the" is never eaten.
|
|
930
|
-
* This is a SUPERSET of the multi-word politeness FILLER_WORDS strips up-front during
|
|
931
|
-
* normalization: those handle "could you"/"tell me"/"please" before either parse runs;
|
|
932
|
-
* these single tokens catch what a spoken-style question keeps AFTER that pass — the
|
|
933
|
-
* bare vocative ("matey"), the article ("the"/"a"), and the presentation frame words
|
|
934
|
-
* ("show"/"me"/"list") that the compositional grammar already skips as FRAME_WORDS but
|
|
935
|
-
* the keyword-spotting strategy does not, so an un-stripped "show me" otherwise
|
|
936
|
-
* decomposes to a bogus ask{subject:"show me"}. Curated, not a general stoplist:
|
|
937
|
-
* question words (what/which/…), connectives (and/or), and pronouns (this/it/that)
|
|
938
|
-
* are deliberately ABSENT — they carry grammatical weight and must survive. */
|
|
554
|
+
/** Politeness/filler/vocative/presentation-frame tokens the cascade may strip
|
|
555
|
+
* one at a time on a miss — never a content-vocabulary word, and never a
|
|
556
|
+
* token that resolves to a graph entity (ask.mjs guards both). */
|
|
939
557
|
export const CASCADE_NOISE = Object.freeze([
|
|
940
|
-
|
|
941
|
-
// the aggregate/where parsers already tolerate a stray "the"/"a", so stripping is
|
|
942
|
-
// belt-and-braces, not load-bearing)
|
|
943
|
-
"the", "a", "an", "some",
|
|
944
|
-
// "what OTHER classes inherit from Controller" — "other" is a vague determiner
|
|
945
|
-
// like "some", not a qualifying adjective; without this it was misread as a
|
|
946
|
-
// fuzzy find TERM ("no classes found matching 'other'") instead of falling
|
|
947
|
-
// through to the ordinary reverse-inherits parse (fast-loop round 6 finding).
|
|
948
|
-
"other",
|
|
949
|
-
// topic lead-in filler — "what about the modules", "how about classes": "about"
|
|
950
|
-
// carries no graph meaning here, so stripping it lets the bare kind noun surface for
|
|
951
|
-
// the cascade's bare-kind-noun terminal rule (ask.mjs). ("what"/"how" are structural
|
|
952
|
-
// question words the drop-pass keeps; only the "about" between them and the kind is
|
|
953
|
-
// noise.) A module literally named "about" is safe-listed by relaxParse's resolvesExact
|
|
954
|
-
// guard, same as every other noise token.
|
|
955
|
-
"about",
|
|
956
|
-
// politeness / hedges (single-token; multi-word "could you"/"please" etc. are
|
|
957
|
-
// FILLER_WORDS, stripped earlier during normalization)
|
|
558
|
+
"the", "a", "an", "some", "other", "about",
|
|
958
559
|
"please", "pls", "plz", "kindly", "just", "simply", "maybe", "perhaps",
|
|
959
560
|
"thanks", "thank", "ta", "cheers",
|
|
960
|
-
// greetings a question sometimes opens with (chat.mjs owns standalone greetings;
|
|
961
|
-
// here they're only stripped when embedded in an otherwise-real question)
|
|
962
561
|
"hi", "hello", "hey", "yo", "hiya", "howdy", "ok", "okay",
|
|
963
|
-
// vocatives / terms of address (the "matey" of the worked example, and its kin)
|
|
964
562
|
"matey", "mate", "buddy", "pal", "dude", "man", "bro", "bru", "fam",
|
|
965
563
|
"friend", "sir", "maam", "folks", "guys", "everyone", "dear",
|
|
966
|
-
// the product's OWN name used as an address (chatbench cycle 2, ns-hey-tmct:
|
|
967
|
-
// "hey tmct, what calls fnAlpha thanks") — a vocative like "matey", stripped
|
|
968
|
-
// by the same rules: relaxParse's resolvesExact guard still protects a module
|
|
969
|
-
// literally named "tmct", and noise-strip's template/keyword-spot acceptance
|
|
970
|
-
// bounds the cost of a mid-question strip to an honest object-miss.
|
|
971
564
|
"tmct",
|
|
972
|
-
// presentation frames — the keyword-spotting strategy's blind spot: the
|
|
973
|
-
// compositional grammar skips these as FRAME_WORDS, but "show me what imports X"
|
|
974
|
-
// otherwise decomposes (via keyword-spot) to ask{subject:"show me"}. Stripping
|
|
975
|
-
// them on a miss recovers the underlying reverse/forward question. ("count" is NOT
|
|
976
|
-
// here — it is an aggregate trigger; "find"/"search" are here as presentation
|
|
977
|
-
// verbs, not the tmct_search tool, which ask.mjs never dispatches.)
|
|
978
565
|
"show", "tell", "give", "list", "find", "me", "us", "lemme",
|
|
979
566
|
]);
|
|
980
567
|
|
|
981
|
-
/** Near-canonical words the cascade
|
|
982
|
-
* unmatched tokens are gone
|
|
983
|
-
*
|
|
984
|
-
* actually types already live in RELATIONS/ENTITY_TO_TYPE (and "uses"/"depends on" are
|
|
985
|
-
* mapped there); this table only closes the gap for the count family, whose triggers
|
|
986
|
-
* (AGGREGATE_TRIGGERS) don't include the "tally the classes"/"total number of classes"
|
|
987
|
-
* register. Each key is also kept OUT of the drop pass (ask.mjs treats a synonym key as
|
|
988
|
-
* meaningful) so it survives to be normalised rather than dropped as unmatched. The
|
|
989
|
-
* rewrite is guarded by ask.mjs (never applied to a token that resolves to a graph
|
|
990
|
-
* entity), so a symbol named "total" is never bent into "count". */
|
|
568
|
+
/** Near-canonical words the cascade rewrites to the closed vocabulary once
|
|
569
|
+
* noise/unmatched tokens are gone. Kept tiny: only closes the count-family
|
|
570
|
+
* gap ("tally the classes") that AGGREGATE_TRIGGERS doesn't cover. */
|
|
991
571
|
export const CASCADE_SYNONYMS = Object.freeze({
|
|
992
572
|
tally: "count", tallies: "count", sum: "count", total: "count", totals: "count",
|
|
993
573
|
});
|
|
994
574
|
|
|
995
|
-
/** Explicit help
|
|
996
|
-
* shows the rephrase hint
|
|
997
|
-
* demand) rather than pretending to answer or running the relaxation loop. A closed
|
|
998
|
-
* set matched against the whole normalized query only, so "which functions call help"
|
|
999
|
-
* (a real question about a symbol named "help") is untouched. Standalone greetings and
|
|
1000
|
-
* the chat "/help" command are chat.mjs's own surface; this is the bare CLI ask()
|
|
1001
|
-
* entry point's equivalent. */
|
|
575
|
+
/** Explicit help/orientation requests: when the whole query is one of these,
|
|
576
|
+
* ask.mjs shows the rephrase hint directly. */
|
|
1002
577
|
export const HELP_TRIGGERS = Object.freeze([
|
|
1003
578
|
"help", "help me", "how do i ask", "how do i use this", "what can i ask",
|
|
1004
579
|
"what can you ask", "usage", "commands", "examples", "syntax", "options",
|
|
1005
580
|
]);
|
|
1006
|
-
|
|
1007
|
-
// ---- omitted-on-purpose (judgment calls, not oversights) -------------------
|
|
1008
|
-
// "runs"/"executes" (calls) are common English words with many non-code
|
|
1009
|
-
// senses — accepted anyway, formal-template AND keyword-spotting alike,
|
|
1010
|
-
// because a misparse costs nothing beyond an honest object-miss
|
|
1011
|
-
// (resolveObject never guesses); the risk is bounded by the render layer,
|
|
1012
|
-
// not by narrowing the vocabulary.
|
|
1013
|
-
// NOT added: "needs"/"wants" for imports (too weakly code-specific — "which
|
|
1014
|
-
// modules need auth" reads as a feature request, not a graph query, in a way
|
|
1015
|
-
// "which modules depend on auth" doesn't); "wraps"/"decorates" for calls (a
|
|
1016
|
-
// real but distinct relationship codegraph.mjs doesn't classify separately —
|
|
1017
|
-
// adding the phrase would silently misroute it onto plain call edges);
|
|
1018
|
-
// "belongs to" for contains (already claimed by a hypothetical membership
|
|
1019
|
-
// verb elsewhere — kept out to avoid a future collision if one is added).
|
|
1020
|
-
// NOT added: a cochange gerund ("co-changing with") — every cochange phrase
|
|
1021
|
-
// is already 2-3 words with its own internal "-ing"/"-s" (e.g. "changes
|
|
1022
|
-
// alongside"), so g-drop normalization has no bare stem to dialectally
|
|
1023
|
-
// contract in the first place; only relations with a genuinely bare-verb
|
|
1024
|
-
// casual form ("call", "touch") needed one.
|
|
1025
|
-
// WRONG_WORDS not mapped (judgment calls): "script(s)" (routinely names a real
|
|
1026
|
-
// module/identifier — rewriting it could corrupt an object term, and file/files
|
|
1027
|
-
// already covers the honest synonym); "package(s)" (a genuinely coarser grain
|
|
1028
|
-
// this graph doesn't model — mapping it to module would silently answer a
|
|
1029
|
-
// different question than the one asked); "fn" (too short and too often a real
|
|
1030
|
-
// identifier fragment to rewrite at a word boundary).
|