@polycode-projects/the-mechanical-code-talker 2.3.0 → 2.5.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 +127 -28
- package/ROADMAP.md +3 -2
- package/bin/tmct.mjs +17 -90
- package/corpus/LICENSES.json +19 -4
- package/corpus/README.md +48 -0
- package/corpus/generated/README.md +24 -9
- package/corpus/generated/ace-surface-variants.jsonl +4 -1
- package/corpus/generated/manifest.json +4 -4
- package/corpus/prose/manifest.json +512 -0
- package/corpus/prose/sqlite/LICENSE-NOTICE +53 -0
- package/corpus/prose/sqlite/arch.txt +213 -0
- package/corpus/prose/sqlite/atomiccommit.txt +1117 -0
- package/corpus/prose/sqlite/faq.txt +473 -0
- package/corpus/prose/sqlite/fileformat.txt +1589 -0
- package/corpus/prose/sqlite/lang_createtable.txt +1339 -0
- package/corpus/prose/sqlite/lang_insert.txt +580 -0
- package/corpus/prose/sqlite/lang_select.txt +3293 -0
- package/corpus/prose/sqlite/optoverview.txt +908 -0
- package/corpus/prose/sqlite/queryplanner.txt +447 -0
- package/corpus/prose/sqlite/transactional.txt +41 -0
- package/corpus/prose/sqlite/wal.txt +567 -0
- package/corpus/prose/sqlite/whentouse.txt +300 -0
- package/corpus/prose/wikipedia/Apple.txt +4 -0
- package/corpus/prose/wikipedia/Attempto_Controlled_English.txt +169 -0
- package/corpus/prose/wikipedia/Automated_planning_and_scheduling.txt +67 -0
- package/corpus/prose/wikipedia/Bee.txt +7 -0
- package/corpus/prose/wikipedia/Bird.txt +8 -0
- package/corpus/prose/wikipedia/Bone.txt +4 -0
- package/corpus/prose/wikipedia/Book.txt +7 -0
- package/corpus/prose/wikipedia/Bread.txt +6 -0
- package/corpus/prose/wikipedia/Butterfly.txt +6 -0
- package/corpus/prose/wikipedia/Car.txt +1 -0
- package/corpus/prose/wikipedia/Cat.txt +1 -0
- package/corpus/prose/wikipedia/Child.txt +3 -0
- package/corpus/prose/wikipedia/City.txt +2 -0
- package/corpus/prose/wikipedia/Clock.txt +2 -0
- package/corpus/prose/wikipedia/Cooking.txt +1 -0
- package/corpus/prose/wikipedia/Description_logic.txt +660 -0
- package/corpus/prose/wikipedia/Doctor.txt +6 -0
- package/corpus/prose/wikipedia/Dog.txt +4 -0
- package/corpus/prose/wikipedia/Eagle.txt +4 -0
- package/corpus/prose/wikipedia/Emotion.txt +9 -0
- package/corpus/prose/wikipedia/Eye.txt +5 -0
- package/corpus/prose/wikipedia/Family.txt +3 -0
- package/corpus/prose/wikipedia/Farm.txt +4 -0
- package/corpus/prose/wikipedia/Fear.txt +4 -0
- package/corpus/prose/wikipedia/First-order_logic.txt +1518 -0
- package/corpus/prose/wikipedia/Fish.txt +10 -0
- package/corpus/prose/wikipedia/Flower.txt +3 -0
- package/corpus/prose/wikipedia/Food.txt +10 -0
- package/corpus/prose/wikipedia/Grass.txt +9 -0
- package/corpus/prose/wikipedia/Hand.txt +2 -0
- package/corpus/prose/wikipedia/Happiness.txt +3 -0
- package/corpus/prose/wikipedia/Heart.txt +4 -0
- package/corpus/prose/wikipedia/Horse.txt +4 -0
- package/corpus/prose/wikipedia/House.txt +6 -0
- package/corpus/prose/wikipedia/Human.txt +4 -0
- package/corpus/prose/wikipedia/Insect.txt +6 -0
- package/corpus/prose/wikipedia/Interactive_fiction.txt +112 -0
- package/corpus/prose/wikipedia/Knowledge.txt +5 -0
- package/corpus/prose/wikipedia/Knowledge_representation_and_reasoning.txt +87 -0
- package/corpus/prose/wikipedia/LICENSE-NOTICE +94 -0
- package/corpus/prose/wikipedia/Language.txt +10 -0
- package/corpus/prose/wikipedia/Learning.txt +4 -0
- package/corpus/prose/wikipedia/Mammal.txt +3 -0
- package/corpus/prose/wikipedia/Memory.txt +5 -0
- package/corpus/prose/wikipedia/Milk.txt +1 -0
- package/corpus/prose/wikipedia/Mountain.txt +1 -0
- package/corpus/prose/wikipedia/Natural_language_processing.txt +211 -0
- package/corpus/prose/wikipedia/Ostrich.txt +2 -0
- package/corpus/prose/wikipedia/Owl.txt +2 -0
- package/corpus/prose/wikipedia/Penguin.txt +2 -0
- package/corpus/prose/wikipedia/Plant.txt +5 -0
- package/corpus/prose/wikipedia/Rain.txt +1 -0
- package/corpus/prose/wikipedia/Resource_Description_Framework.txt +184 -0
- package/corpus/prose/wikipedia/River.txt +1 -0
- package/corpus/prose/wikipedia/School.txt +8 -0
- package/corpus/prose/wikipedia/Sea.txt +1 -0
- package/corpus/prose/wikipedia/Semantic_Web.txt +114 -0
- package/corpus/prose/wikipedia/Semantic_reasoner.txt +29 -0
- package/corpus/prose/wikipedia/Snow.txt +5 -0
- package/corpus/prose/wikipedia/Sun.txt +5 -0
- package/corpus/prose/wikipedia/Teacher.txt +4 -0
- package/corpus/prose/wikipedia/Team.txt +3 -0
- package/corpus/prose/wikipedia/Text-based_game.txt +17 -0
- package/corpus/prose/wikipedia/Tool.txt +4 -0
- package/corpus/prose/wikipedia/Tree.txt +7 -0
- package/corpus/prose/wikipedia/Weather.txt +4 -0
- package/corpus/prose/wikipedia/Web_Ontology_Language.txt +133 -0
- package/corpus/prose/wikipedia/Wind.txt +8 -0
- package/corpus/prose/wikipedia/Writing.txt +5 -0
- package/corpus/seon/README.md +1 -0
- package/corpus/tier2/generate.mjs +18 -18
- package/corpus/tier2/manifest.json +3 -3
- package/data/games/hanoi-3.txt +8 -2
- package/package.json +24 -5
- package/src/adapters/corpus-lanes.mjs +13 -0
- package/src/adapters/graph-build.mjs +5 -7
- package/src/adapters/import-closure.mjs +28 -0
- package/src/adapters/memory/blocks.mjs +5 -4
- package/src/adapters/memory/core.mjs +78 -5
- package/src/adapters/memory/shacl.mjs +12 -0
- package/src/adapters/providers/graph-service.mjs +12 -5
- package/src/adapters/tracked-files.mjs +17 -0
- package/src/domain/ask-vocab.mjs +2 -0
- package/src/domain/ask.mjs +225 -13
- package/src/domain/cli-verbs.mjs +201 -0
- package/src/domain/codegraph.mjs +142 -56
- package/src/domain/completions/graph-adapter.mjs +1 -1
- package/src/domain/completions/group.mjs +3 -17
- package/src/domain/completions/infer.mjs +4 -13
- package/src/domain/completions/rank.mjs +6 -19
- package/src/domain/grammar/lexicon-core.json +1 -1
- package/src/domain/hash.mjs +36 -13
- package/src/domain/interpret/fuzzy.mjs +7 -2
- package/src/domain/interpret/normalize.mjs +9 -0
- package/src/domain/interpret/strategies/keywords.mjs +19 -9
- package/src/domain/memory/capability.mjs +22 -3
- package/src/domain/memory/touched-facts.mjs +17 -0
- package/src/domain/module-paths.mjs +9 -0
- package/src/domain/persona/tiers.mjs +1 -1
- package/src/domain/planning.mjs +37 -0
- package/src/domain/prose.mjs +10 -2
- package/src/domain/relative-specifiers.mjs +12 -0
- package/src/domain/router/registry.mjs +3 -2
- package/src/domain/router/results.mjs +5 -18
- package/src/domain/seeded-random.mjs +33 -0
- package/src/domain/syllogise.mjs +10 -7
- package/src/domain/text-stats.mjs +31 -0
- package/src/services/chat.mjs +720 -182
- package/src/services/extract-facts.mjs +155 -0
- package/src/services/import-file.mjs +2 -2
- package/src/services/ledger-viz.mjs +6 -1
- package/src/services/sentences.mjs +26 -0
- package/src/surfaces/web/memory-ask-browser.bundle.js +11390 -360
- package/src/tools/graph-load.mjs +7 -1
- package/src/tools/readme-docs.mjs +113 -0
- package/src/tools/schema-docs.mjs +2 -2
- package/corpus/namenet/generate.mjs +0 -309
- package/corpus/wordnet/generate.mjs +0 -332
- package/src/adapters/prose-tokens.mjs +0 -98
- package/src/adapters/wordnet-source.mjs +0 -70
- package/src/domain/corpus-matrix.mjs +0 -87
- package/src/domain/inflect.mjs +0 -67
- package/src/domain/licences.mjs +0 -68
- package/src/domain/markdown-links.mjs +0 -55
- package/src/domain/persona/codegen.mjs +0 -123
- package/src/domain/publish-gate.mjs +0 -41
- package/src/domain/schemaorg/turtle.mjs +0 -25
- package/src/domain/semcor/parse.mjs +0 -87
- package/src/domain/version-stamp.mjs +0 -36
- package/src/domain/wordnet/yaml.mjs +0 -133
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Fact rows one write touched — created, or re-asserted with a new
|
|
3
|
+
* provenance entry — diffed by (id → provenance) across a before/after pair of
|
|
4
|
+
* readFactRows() snapshots.
|
|
5
|
+
*
|
|
6
|
+
* Provenance is the key because a re-assertion of a fact that is already stored
|
|
7
|
+
* changes nothing else about the row: appendFact unions the new provenance in
|
|
8
|
+
* by id, so a row whose provenance string moved is a row this write reached.
|
|
9
|
+
*
|
|
10
|
+
* Not every write produces a touched row, and that is the honest answer rather
|
|
11
|
+
* than a gap: the rule-teach shapes (compose2/filter/recursive) store a Rule,
|
|
12
|
+
* not a Fact, so they touch no Fact row and are correctly reported as none.
|
|
13
|
+
*/
|
|
14
|
+
export function touchedFactRows(before, after) {
|
|
15
|
+
const provenanceBefore = new Map(before.map((r) => [r.id, r.provenance]));
|
|
16
|
+
return after.filter((r) => provenanceBefore.get(r.id) !== r.provenance);
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// module-paths.mjs — classifying a module by its path, for the graph builders and
|
|
2
|
+
// the rankers that read what they build.
|
|
3
|
+
|
|
4
|
+
/** Does this module path (or a lowercased path-shaped label) belong to test code?
|
|
5
|
+
* Covers `test/` and `tests/` segments, Python's `test_*.py` convention, and
|
|
6
|
+
* .NET's `*.Tests` assembly suffix. Case-sensitive: callers holding mixed-case
|
|
7
|
+
* paths lowercase first. */
|
|
8
|
+
export const isTestPath = (p) =>
|
|
9
|
+
/(^|\/)tests?\//.test(p) || /(^|\/)test_[^/]*\.py$/.test(p) || /\.tests(\.|$)/.test(p);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
//
|
|
5
5
|
// Pure throughout — these read in-memory maps a caller loaded from disk, so
|
|
6
6
|
// they are testable with no WordNet clone present. The loading lives in
|
|
7
|
-
//
|
|
7
|
+
// scripts/lib/wordnet-source.mjs, the fact targets and the run itself in
|
|
8
8
|
// scripts/build-persona-tiers.mjs.
|
|
9
9
|
|
|
10
10
|
// human-base's own category roots, plus every hypernym TARGET term Small's
|
package/src/domain/planning.mjs
CHANGED
|
@@ -83,3 +83,40 @@ export function findReachableSet(startState, applyActions, { maxDepth = 50, stat
|
|
|
83
83
|
}
|
|
84
84
|
return results;
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Bounded, cycle-safe breadth-first walk that yields one array of newly-visited
|
|
89
|
+
* successor items per depth level (depths 1..maxDepth), starting from `start`
|
|
90
|
+
* which is pre-marked visited and never yielded. `successorsOf(id)` returns the
|
|
91
|
+
* successor items of a node id; `keyOf(item)` is the identity used to dedup and
|
|
92
|
+
* to seed the next frontier (default: the item itself is its own key).
|
|
93
|
+
*
|
|
94
|
+
* Each yielded level is in discovery order; a caller that needs a stable order
|
|
95
|
+
* sorts it. Empty levels are yielded too (the walk stops once a frontier is
|
|
96
|
+
* empty), so a caller collecting per-depth batches should skip empty ones.
|
|
97
|
+
*
|
|
98
|
+
* @template T
|
|
99
|
+
* @param {*} start
|
|
100
|
+
* @param {(id: *) => Iterable<T>} successorsOf
|
|
101
|
+
* @param {{ maxDepth?: number, keyOf?: (item: T) => * }} [opts]
|
|
102
|
+
* @returns {Generator<T[]>}
|
|
103
|
+
*/
|
|
104
|
+
export function* bfsLevels(start, successorsOf, { maxDepth = 8, keyOf = (x) => x } = {}) {
|
|
105
|
+
const visited = new Set([start]);
|
|
106
|
+
let frontier = [start];
|
|
107
|
+
for (let depth = 1; depth <= maxDepth && frontier.length; depth += 1) {
|
|
108
|
+
const level = [];
|
|
109
|
+
const nextFrontier = [];
|
|
110
|
+
for (const id of frontier) {
|
|
111
|
+
for (const item of successorsOf(id) || []) {
|
|
112
|
+
const key = keyOf(item);
|
|
113
|
+
if (visited.has(key)) continue;
|
|
114
|
+
visited.add(key);
|
|
115
|
+
level.push(item);
|
|
116
|
+
nextFrontier.push(key);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
frontier = nextFrontier;
|
|
120
|
+
yield level;
|
|
121
|
+
}
|
|
122
|
+
}
|
package/src/domain/prose.mjs
CHANGED
|
@@ -4,8 +4,6 @@
|
|
|
4
4
|
// `prose_tokens` attribute (self-describing) and inverted into
|
|
5
5
|
// `entities.proseIndex` (word -> ids) for O(1) lookup.
|
|
6
6
|
|
|
7
|
-
// Exported so src/domain/completions/group.mjs can filter splitIdentifierWords'
|
|
8
|
-
// output (which doesn't apply this list itself) down to real content words.
|
|
9
7
|
export const STOPWORDS = new Set(
|
|
10
8
|
("a an and or but the of to in on at for with from by as is are was were be been being " +
|
|
11
9
|
"it its this that these those i you he she they we me my your our do does did not no " +
|
|
@@ -57,6 +55,16 @@ export function proseTokensFor({ name, doc } = {}) {
|
|
|
57
55
|
return [...set].sort();
|
|
58
56
|
}
|
|
59
57
|
|
|
58
|
+
/** A real content word: plain alphanumerics, no stopword. Tokenizers that re-admit
|
|
59
|
+
* stopwords (splitIdentifierWords, tokenizeBlock) narrow their output through this —
|
|
60
|
+
* unfiltered, shared stopwords alone would relate or cluster almost any two texts. */
|
|
61
|
+
export const isContentToken = (t) => /^[a-z0-9]+$/.test(t) && !STOPWORDS.has(t);
|
|
62
|
+
|
|
63
|
+
/** Wrap a block tokenizer so it yields only content tokens. */
|
|
64
|
+
export function makeContentTokens(tokenizeBlock) {
|
|
65
|
+
return (text) => tokenizeBlock(text).filter(isContentToken);
|
|
66
|
+
}
|
|
67
|
+
|
|
60
68
|
/** Attach a `prose_tokens` attribute to every individual, from its (decomposed)
|
|
61
69
|
* name and captured doc text — except Commit, whose `label` is a truncated
|
|
62
70
|
* SHA, not a decomposable identifier: it tokenizes `message` instead. Mutates
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// The relative import/export specifiers in a module's source text, unique and
|
|
2
|
+
// in first-seen order. Relative only: bare specifiers (wink-nlp) and node
|
|
3
|
+
// builtins are somebody else's concern — an import map, a shim. Covers the
|
|
4
|
+
// three forms a specifier arrives in: after a from keyword (static import and
|
|
5
|
+
// re-export), a dynamic import call, and a bare side-effect import.
|
|
6
|
+
const RELATIVE_SPECIFIER = /(?:\bfrom\s*|\bimport\s*\(\s*|\bimport\s+)["'](\.[^"']*)["']/g;
|
|
7
|
+
|
|
8
|
+
export function relativeSpecifiers(text) {
|
|
9
|
+
const specs = new Set();
|
|
10
|
+
for (const [, specifier] of text.matchAll(RELATIVE_SPECIFIER)) specs.add(specifier);
|
|
11
|
+
return [...specs];
|
|
12
|
+
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
const PREFIXES = Object.freeze({
|
|
13
13
|
cap: "urn:tmct:cap#", // the capability/operator vocabulary (this module)
|
|
14
|
+
taught: "urn:tmct:taught#", // taught-action operators + their world-state predicates (taught.mjs)
|
|
14
15
|
mgx: "urn:tmct:mgx#", // tmct's code-graph predicates (imports/calls/tests/…)
|
|
15
16
|
seon: "http://se-on.org/ontologies/seon.owl#", // software-evolution ontology classes
|
|
16
17
|
});
|
|
@@ -28,8 +29,8 @@ export const VOCAB = Object.freeze({
|
|
|
28
29
|
// name a graph entity the resolver must prove RESOLVES before the call fires.
|
|
29
30
|
export const KINDS = Object.freeze({
|
|
30
31
|
Symbol: "seon:CodeEntity", // any code symbol: function/method/class/module/attribute
|
|
31
|
-
Module: "
|
|
32
|
-
Class: "seon:
|
|
32
|
+
Module: "mgx:Module", // SEON has no JS-module class (its nearest are Namespace/main:File); owned
|
|
33
|
+
Class: "seon:ClassType", // SEON's real class for a class definition
|
|
33
34
|
Query: "cap:FreeText", // lexical search string — no resolution precondition
|
|
34
35
|
Kind: "cap:KindFilter", // enum: function|class|method|… (search filter)
|
|
35
36
|
Package: "cap:PackageName", // optional architecture-scope filter
|
|
@@ -27,11 +27,9 @@
|
|
|
27
27
|
// dispatchTool render* functions edge-for-edge.
|
|
28
28
|
|
|
29
29
|
import { impactClosure, edgesOfKind, siteOf } from "../codegraph.mjs";
|
|
30
|
+
import { bfsLevels } from "../planning.mjs";
|
|
30
31
|
import { uniqSort } from "./set-algebra.mjs";
|
|
31
|
-
|
|
32
|
-
// A test-path label, mirroring codegraph.mjs's private isTestLabel (untested view).
|
|
33
|
-
const isTestLabel = (s) =>
|
|
34
|
-
/(^|\/)tests?\//.test(s) || /(^|\/)test_[^/]*\.py$/.test(s) || /\.tests(\.|$)/.test(s);
|
|
32
|
+
import { isTestPath } from "../module-paths.mjs";
|
|
35
33
|
|
|
36
34
|
/** The module id an individual belongs to — a Module is itself; a fine symbol maps
|
|
37
35
|
* through its site span (`mod:<path>`), else an `fn:<path>#name` id. Mirrors the
|
|
@@ -56,7 +54,7 @@ export function untestedModules(graph) {
|
|
|
56
54
|
graph.individuals
|
|
57
55
|
.filter((i) => (i.class || "") === "Module"
|
|
58
56
|
&& !testModules.has(i.id)
|
|
59
|
-
&& !
|
|
57
|
+
&& !isTestPath(String(i.label).toLowerCase())
|
|
60
58
|
&& !covered.has(i.id))
|
|
61
59
|
.map((i) => i.label),
|
|
62
60
|
);
|
|
@@ -165,19 +163,8 @@ function subclassesLabels(graph, ind) {
|
|
|
165
163
|
childrenOf.get(e.object).push({ id: e.subject, label: e.subjectLabel || e.subject });
|
|
166
164
|
}
|
|
167
165
|
const labels = [];
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
for (let depth = 1; depth <= 8 && frontier.length; depth += 1) {
|
|
171
|
-
const next = [];
|
|
172
|
-
for (const id of frontier) {
|
|
173
|
-
for (const c of childrenOf.get(id) || []) {
|
|
174
|
-
if (visited.has(c.id)) continue;
|
|
175
|
-
visited.add(c.id);
|
|
176
|
-
labels.push(c.label);
|
|
177
|
-
next.push(c.id);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
frontier = next;
|
|
166
|
+
for (const level of bfsLevels(ind.id, (id) => childrenOf.get(id) || [], { maxDepth: 8, keyOf: (c) => c.id })) {
|
|
167
|
+
for (const c of level) labels.push(c.label);
|
|
181
168
|
}
|
|
182
169
|
return uniqSort(labels);
|
|
183
170
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// seeded-random.mjs — the single home for tmct's seedable, platform-stable
|
|
2
|
+
// pseudo-randomness: a mulberry32 generator and a Fisher-Yates shuffle driven by
|
|
3
|
+
// it. Both are pure arithmetic (no I/O, no imports), so a seed reproduces the
|
|
4
|
+
// same sequence on every machine and every run.
|
|
5
|
+
//
|
|
6
|
+
// The bench case generators (infbench, chatbench's graded pool) draw their
|
|
7
|
+
// committed fixtures through these, so the byte sequence they produce is part of
|
|
8
|
+
// those artifacts' identity: two callers on one seed must shuffle identically or
|
|
9
|
+
// the committed cases.jsonl / graded pool drift. That is the same reason the
|
|
10
|
+
// content-address hashes live once in hash.mjs beside this file — a deterministic
|
|
11
|
+
// primitive shared across writers has exactly one definition.
|
|
12
|
+
|
|
13
|
+
/** mulberry32 PRNG — small, seedable, deterministic across platforms. */
|
|
14
|
+
export function mulberry32(seed) {
|
|
15
|
+
let a = seed >>> 0;
|
|
16
|
+
return () => {
|
|
17
|
+
a = (a + 0x6d2b79f5) >>> 0;
|
|
18
|
+
let t = a;
|
|
19
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
20
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
21
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Fisher-Yates over a copy, driven by the supplied rng. */
|
|
26
|
+
export function seededShuffle(arr, rng) {
|
|
27
|
+
const out = [...arr];
|
|
28
|
+
for (let i = out.length - 1; i > 0; i -= 1) {
|
|
29
|
+
const j = Math.floor(rng() * (i + 1));
|
|
30
|
+
[out[i], out[j]] = [out[j], out[i]];
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
package/src/domain/syllogise.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// syllogise.mjs — tmct's speculative-inference engine, growing toward
|
|
2
2
|
// tier-5 "the Syllogist". Offline, deterministic: forward-chains entailments
|
|
3
3
|
// over the OWL-labelled memory graph so a future query-time MISS becomes a
|
|
4
|
-
// lookup. `syllogise()` (the
|
|
4
|
+
// lookup. `syllogise()` (the materialising pass) only runs as the explicit
|
|
5
5
|
// `npx tmct syllogise` batch job; the pure kernels below may also be reused
|
|
6
6
|
// for a small, bounded, read-only live check without writing anything.
|
|
7
7
|
//
|
|
@@ -61,7 +61,7 @@ export const ENTAILED_DISJOINT_PROVENANCE = `entailed:${CAX_DW_RULE}`;
|
|
|
61
61
|
export const CAX_DW_RULE_CONFIDENCE = 0.95;
|
|
62
62
|
|
|
63
63
|
/** cls-svf1: x P y, y rdf:type C2, R owl:onProperty P, R owl:someValuesFrom
|
|
64
|
-
* C2 |= x rdf:type R (OWL 2 RL Table
|
|
64
|
+
* C2 |= x rdf:type R (OWL 2 RL Table 6). `owl:onProperty`'s stored value and
|
|
65
65
|
* a taught property edge's predicate differ in casing (normFactTerm'd vs.
|
|
66
66
|
* raw vocabulary spelling), so the kernel below normalizes both before
|
|
67
67
|
* comparing. */
|
|
@@ -311,7 +311,7 @@ export function deriveDisjointViolations(typeEdges, subClassEdges, disjointEdges
|
|
|
311
311
|
|
|
312
312
|
/**
|
|
313
313
|
* PURE cls-svf1: x P y, y rdf:type C2, R owl:onProperty P, R
|
|
314
|
-
* owl:someValuesFrom C2 |= x rdf:type R (OWL 2 RL Table
|
|
314
|
+
* owl:someValuesFrom C2 |= x rdf:type R (OWL 2 RL Table 6). `propertyEdges`
|
|
315
315
|
* is every taught/prior-entailed object-property assertion (raw predicate
|
|
316
316
|
* spelling); `restrictionEdges` is each restriction node's (property, target)
|
|
317
317
|
* declaration. `y`'s type is lifted through its full ⊑-ancestor closure, so
|
|
@@ -659,7 +659,7 @@ export function findConsistencyViolations(typeEdges, subClassEdges, disjointEdge
|
|
|
659
659
|
* Run one bounded speculative pass over the memory graph under `repoDir`.
|
|
660
660
|
* Forward-chains the five rules in order — scm-sco, cax-sco, cax-dw,
|
|
661
661
|
* cls-svf1, scm-svf1 — each seeing the prior rules' conclusions from this
|
|
662
|
-
* same pass, and
|
|
662
|
+
* same pass, and materialises each new conclusion via `appendFacts` with its
|
|
663
663
|
* `entailed:*` provenance. Trust rides the entailed hook
|
|
664
664
|
* (`min(premiseTrusts) x ruleConfidence`) when premises are resolvable in the
|
|
665
665
|
* pre-pass snapshot, else falls back to the bare entailed prior.
|
|
@@ -764,7 +764,7 @@ export async function syllogise(repoDir, { depth = 32, budget = 50, focus = null
|
|
|
764
764
|
subject: d.subject, predicate: TYPE_PREDICATE, object: d.object,
|
|
765
765
|
provenance: ENTAILED_TYPE_PROVENANCE,
|
|
766
766
|
// The ⊑ premise is cited as the DIRECT via⊑object edge even when the
|
|
767
|
-
// taught chain is multi-hop: scm-sco
|
|
767
|
+
// taught chain is multi-hop: scm-sco materialises that edge (this same
|
|
768
768
|
// pass or an earlier one), and retraction re-VERIFIES every candidate
|
|
769
769
|
// anyway, so a citation left dangling by budget truncation is inert.
|
|
770
770
|
justification: [
|
|
@@ -969,14 +969,17 @@ function buildSurvivorDerivabilityCheck(rows) {
|
|
|
969
969
|
}
|
|
970
970
|
|
|
971
971
|
/**
|
|
972
|
-
* A scoped retraction slice:
|
|
972
|
+
* A scoped retraction slice: DRed (delete-and-rederive; Gupta, Mumick &
|
|
973
|
+
* Subrahmanian, SIGMOD 1993), NOT JTMS. It recomputes the MATERIALISATION —
|
|
974
|
+
* where a JTMS would recompute belief labels — so a store that moves rows is
|
|
975
|
+
* DRed by construction.
|
|
973
976
|
* Retracting `subject ⊑ object` removes the fact, then cascades to any
|
|
974
977
|
* purely-entailed fact — across all five rules' conclusions — whose persisted
|
|
975
978
|
* justification cites a removed id. Each candidate is VERIFIED (re-derivable
|
|
976
979
|
* from the surviving facts, not just "cited a removed id") before it is
|
|
977
980
|
* actually removed, since a fact can have a second, independent derivation
|
|
978
981
|
* path (a⊑b⊑d AND a⊑c⊑d both license a⊑d) that a bare delete-by-justification
|
|
979
|
-
* walk would wrongly discard. Repeats in rounds — a removed mid-chain link
|
|
982
|
+
* walk would wrongly discard. This over-delete-then-re-verify IS DRed's shape. Repeats in rounds — a removed mid-chain link
|
|
980
983
|
* can ripple — bounded by `budget` (max facts examined+removed) and `depth`
|
|
981
984
|
* (max cascade rounds).
|
|
982
985
|
*
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// text-stats.mjs — pure token-frequency statistics shared by the ranking tiers.
|
|
2
|
+
// Deterministic, no model calls. The IDF weight log(1 + N/(1+df)) is near-zero
|
|
3
|
+
// for tokens present in almost every document and grows for rare ones.
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Inverse-document-frequency weight for a token seen in `df` of `N` documents.
|
|
7
|
+
* @param {number} N document count
|
|
8
|
+
* @param {number} df document frequency of the token
|
|
9
|
+
* @returns {number}
|
|
10
|
+
*/
|
|
11
|
+
export function idfWeight(N, df) {
|
|
12
|
+
return Math.log(1 + N / (1 + df));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* IDF over a document set given as an `id -> tokens` map. Document frequency
|
|
17
|
+
* counts each document once per distinct token; N is the document count.
|
|
18
|
+
*
|
|
19
|
+
* @param {Record<string, string[]>} idsToTokens
|
|
20
|
+
* @returns {{ N: number, df: Map<string, number>, idf: (t: string) => number }}
|
|
21
|
+
*/
|
|
22
|
+
export function idfOver(idsToTokens) {
|
|
23
|
+
const ids = Object.keys(idsToTokens || {});
|
|
24
|
+
const N = ids.length;
|
|
25
|
+
const df = new Map();
|
|
26
|
+
for (const id of ids) {
|
|
27
|
+
for (const t of new Set(idsToTokens[id])) df.set(t, (df.get(t) || 0) + 1);
|
|
28
|
+
}
|
|
29
|
+
const idf = (t) => idfWeight(N, df.get(t) || 0);
|
|
30
|
+
return { N, df, idf };
|
|
31
|
+
}
|