cortexm 0.3.0__py3-none-any.whl
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.
- context_m.py +17 -0
- cortexm/__init__.py +45 -0
- cortexm/accel.py +403 -0
- cortexm/api/__init__.py +0 -0
- cortexm/api/chaos.py +118 -0
- cortexm/api/memory.py +635 -0
- cortexm/bench/__init__.py +0 -0
- cortexm/bench/abilities.py +311 -0
- cortexm/bench/baselines.py +89 -0
- cortexm/bench/beam_loader.py +317 -0
- cortexm/bench/generator.py +376 -0
- cortexm/bench/harness.py +211 -0
- cortexm/bench/messy.py +218 -0
- cortexm/bench/micro.py +251 -0
- cortexm/bench/ood.py +443 -0
- cortexm/bench/run.py +137 -0
- cortexm/bridge/__init__.py +0 -0
- cortexm/bridge/dates.py +178 -0
- cortexm/bridge/decoders.py +204 -0
- cortexm/bridge/enrich.py +255 -0
- cortexm/bridge/extractor.py +316 -0
- cortexm/bridge/fallback.py +332 -0
- cortexm/bridge/onnx_runtime.py +158 -0
- cortexm/bridge/patterns.py +760 -0
- cortexm/bridge/ppr.py +104 -0
- cortexm/bridge/prefilter.py +188 -0
- cortexm/bridge/query_extract.py +420 -0
- cortexm/bridge/reader.py +1174 -0
- cortexm/bridge/rerank.py +204 -0
- cortexm/bridge/writer.py +492 -0
- cortexm/cli.py +295 -0
- cortexm/cognition/__init__.py +53 -0
- cortexm/cognition/abstraction.py +192 -0
- cortexm/cognition/analogy.py +159 -0
- cortexm/cognition/engine.py +204 -0
- cortexm/cognition/gaps.py +365 -0
- cortexm/cognition/scanner.py +204 -0
- cortexm/config.py +375 -0
- cortexm/cortexm.py +8 -0
- cortexm/enterprise/__init__.py +0 -0
- cortexm/enterprise/audit.py +178 -0
- cortexm/enterprise/governance.py +239 -0
- cortexm/errors.py +35 -0
- cortexm/features/__init__.py +0 -0
- cortexm/features/git.py +204 -0
- cortexm/features/prefetch.py +88 -0
- cortexm/features/zk.py +105 -0
- cortexm/federation/__init__.py +39 -0
- cortexm/federation/crdt.py +275 -0
- cortexm/federation/fabric.py +109 -0
- cortexm/federation/hlc.py +80 -0
- cortexm/federation/node.py +145 -0
- cortexm/federation/schema_report.py +73 -0
- cortexm/federation/transport.py +164 -0
- cortexm/index/__init__.py +19 -0
- cortexm/index/nsg.py +386 -0
- cortexm/mcp/__init__.py +0 -0
- cortexm/mcp/server.py +985 -0
- cortexm/metrics.py +62 -0
- cortexm/migrate/__init__.py +0 -0
- cortexm/migrate/importers.py +192 -0
- cortexm/provenance/__init__.py +78 -0
- cortexm/provenance/agent.py +214 -0
- cortexm/provenance/cose.py +201 -0
- cortexm/provenance/scitt.py +258 -0
- cortexm/provenance/vc.py +250 -0
- cortexm/security/__init__.py +0 -0
- cortexm/security/crypto.py +162 -0
- cortexm/security/hashes.py +140 -0
- cortexm/security/injection.py +149 -0
- cortexm/security/mind.py +154 -0
- cortexm/security/pii.py +265 -0
- cortexm/security/rbac.py +169 -0
- cortexm/security/sandbox.py +131 -0
- cortexm/security/zk_hamming.py +142 -0
- cortexm/security/zk_sql.py +485 -0
- cortexm/server/__init__.py +0 -0
- cortexm/server/metrics.py +88 -0
- cortexm/server/rest.py +936 -0
- cortexm/server/sparql.py +984 -0
- cortexm/text/__init__.py +0 -0
- cortexm/text/dissim.py +252 -0
- cortexm/text/embedder.py +155 -0
- cortexm/text/fuzzy.py +218 -0
- cortexm/text/idiolect.py +253 -0
- cortexm/text/labse.py +374 -0
- cortexm/text/tokenizer.py +79 -0
- cortexm/trace/__init__.py +0 -0
- cortexm/trace/blob_arena.py +277 -0
- cortexm/trace/consolidate.py +337 -0
- cortexm/trace/contradictions.py +69 -0
- cortexm/trace/dedup.py +114 -0
- cortexm/trace/edges.py +214 -0
- cortexm/trace/fact.py +121 -0
- cortexm/trace/fade.py +245 -0
- cortexm/trace/lifecycle.py +112 -0
- cortexm/trace/rebuild.py +173 -0
- cortexm/trace/rules.py +171 -0
- cortexm/trace/store.py +680 -0
- cortexm/trace/structural.py +183 -0
- cortexm/trace/tmt.py +335 -0
- cortexm/util.py +148 -0
- cortexm/vsa/__init__.py +0 -0
- cortexm/vsa/attribution.py +149 -0
- cortexm/vsa/cleanup.py +161 -0
- cortexm/vsa/codecs.py +397 -0
- cortexm/vsa/hologram_overlay.py +139 -0
- cortexm/vsa/index.py +163 -0
- cortexm/vsa/ops.py +149 -0
- cortexm/vsa/palace.py +446 -0
- cortexm/vsa/role_vectors.py +236 -0
- cortexm/vsa/slb.py +78 -0
- cortexm/vsa/tlsh_trie.py +137 -0
- cortexm/vsa/working_memory.py +249 -0
- cortexm-0.3.0.dist-info/METADATA +482 -0
- cortexm-0.3.0.dist-info/RECORD +120 -0
- cortexm-0.3.0.dist-info/WHEEL +5 -0
- cortexm-0.3.0.dist-info/entry_points.txt +2 -0
- cortexm-0.3.0.dist-info/licenses/LICENSE +190 -0
- cortexm-0.3.0.dist-info/top_level.txt +2 -0
cortexm/trace/rules.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""Datalog-lite rules engine — deterministic forward chaining.
|
|
2
|
+
|
|
3
|
+
The plan specifies a lightweight Datalog engine (not CLIPS) for
|
|
4
|
+
forward-chaining over the Trace. Rules use a tiny Datalog syntax::
|
|
5
|
+
|
|
6
|
+
head(X, Y) :- body1(X, Z), body2(Z, Y).
|
|
7
|
+
|
|
8
|
+
An atom ``rel(a, b)`` denotes the fact triple ``(a, rel, b)``.
|
|
9
|
+
Uppercase-initial tokens are variables. The engine joins body atoms
|
|
10
|
+
over active facts and materializes derived facts (``is_derived=True``)
|
|
11
|
+
which are themselves indexed in the VSA palace — inference bound into
|
|
12
|
+
the neuro-symbolic bridge, not bolted on.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import datetime as _dt
|
|
18
|
+
import re
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
|
|
21
|
+
from cortexm.trace.fact import Fact
|
|
22
|
+
from cortexm.trace.store import TraceStore
|
|
23
|
+
from cortexm.util import iso, new_id
|
|
24
|
+
|
|
25
|
+
RULE_RE = re.compile(r"^([\w]+)\s*\(([^)]*)\)\s*:-\s*(.+)$")
|
|
26
|
+
ATOM_RE = re.compile(r"([\w]+)\s*\(([^)]*)\)")
|
|
27
|
+
Arg = str
|
|
28
|
+
Atom = tuple[str, Arg, Arg] # (relation, subject_arg, value_arg)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _mk_atom(rel: str, args: str) -> Atom:
|
|
32
|
+
parts = [p.strip() for p in args.split(",") if p.strip()]
|
|
33
|
+
if len(parts) == 1:
|
|
34
|
+
return (rel, parts[0], "_")
|
|
35
|
+
if len(parts) == 2:
|
|
36
|
+
return (rel, parts[0], parts[1])
|
|
37
|
+
# 3-arg form: rel(subject, relation, value) — relation arg must equal rel
|
|
38
|
+
return (rel, parts[0], parts[2])
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def parse_rule(text: str) -> "Rule":
|
|
42
|
+
text = text.strip().rstrip(".")
|
|
43
|
+
m = RULE_RE.match(text)
|
|
44
|
+
if not m:
|
|
45
|
+
raise ValueError(f"invalid rule: {text!r}")
|
|
46
|
+
head = _mk_atom(m.group(1), m.group(2))
|
|
47
|
+
body = [_mk_atom(a.group(1), a.group(2)) for a in ATOM_RE.finditer(m.group(3))]
|
|
48
|
+
if not body:
|
|
49
|
+
raise ValueError(f"rule with empty body: {text!r}")
|
|
50
|
+
return Rule(head=head, body=body, source=text)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class Rule:
|
|
55
|
+
head: Atom
|
|
56
|
+
body: list[Atom]
|
|
57
|
+
source: str = ""
|
|
58
|
+
|
|
59
|
+
def render(self) -> str:
|
|
60
|
+
def atom(a):
|
|
61
|
+
return f"{a[0]}({a[1]}, {a[2]})"
|
|
62
|
+
return f"{atom(self.head)} :- {', '.join(atom(b) for b in self.body)}."
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
DEFAULT_RULES = [
|
|
66
|
+
parse_rule("reports_to(X, Y) :- manages(Y, X)."),
|
|
67
|
+
parse_rule("team_uses(X, L) :- member_of(X, T), uses(T, L)."),
|
|
68
|
+
parse_rule("lives_in(X, C) :- moved_to(X, C)."),
|
|
69
|
+
parse_rule("same_person(N, X) :- alias(X, N)."),
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class RuleEngine:
|
|
74
|
+
def __init__(self, store: TraceStore, rules: list[Rule] | None = None) -> None:
|
|
75
|
+
self.store = store
|
|
76
|
+
self.rules = rules if rules is not None else list(DEFAULT_RULES)
|
|
77
|
+
self._rel_cache: dict[str, list[Fact]] = {}
|
|
78
|
+
|
|
79
|
+
def _facts_of(self, rel: str) -> list[Fact]:
|
|
80
|
+
if rel not in self._rel_cache:
|
|
81
|
+
self._rel_cache[rel] = self.store.query_facts(relation=rel, active=True,
|
|
82
|
+
derived=False)
|
|
83
|
+
return self._rel_cache[rel]
|
|
84
|
+
|
|
85
|
+
def _join(self, rule: Rule) -> list[dict[str, str]]:
|
|
86
|
+
bindings: list[dict[str, str]] = [{}]
|
|
87
|
+
atoms = sorted(rule.body, key=lambda a: len(self._facts_of(a[0])))
|
|
88
|
+
for rel, s_arg, v_arg in atoms:
|
|
89
|
+
nxt: list[dict[str, str]] = []
|
|
90
|
+
for b in bindings:
|
|
91
|
+
for f in self._facts_of(rel):
|
|
92
|
+
# scope isolation: a rule joins premises from ONE user
|
|
93
|
+
# scope (None = global premise may join any scope).
|
|
94
|
+
bu = b.get("_user")
|
|
95
|
+
if bu is not None and f.user_id not in (None, bu):
|
|
96
|
+
continue
|
|
97
|
+
nb = dict(b)
|
|
98
|
+
if not self._bind(nb, s_arg, f.subject):
|
|
99
|
+
continue
|
|
100
|
+
if not self._bind(nb, v_arg, f.value):
|
|
101
|
+
continue
|
|
102
|
+
if f.user_id is not None:
|
|
103
|
+
nb["_user"] = f.user_id
|
|
104
|
+
nxt.append(nb)
|
|
105
|
+
bindings = nxt
|
|
106
|
+
if not bindings:
|
|
107
|
+
break
|
|
108
|
+
return bindings
|
|
109
|
+
|
|
110
|
+
@staticmethod
|
|
111
|
+
def _bind(b: dict[str, str], arg: str, val: str) -> bool:
|
|
112
|
+
if arg == "_":
|
|
113
|
+
return True
|
|
114
|
+
if arg[0].isupper():
|
|
115
|
+
if arg in b and b[arg] != val:
|
|
116
|
+
return False
|
|
117
|
+
b[arg] = val
|
|
118
|
+
return True
|
|
119
|
+
return arg == val
|
|
120
|
+
|
|
121
|
+
def _subst(self, head: Atom, b: dict[str, str]) -> tuple[str, str, str] | None:
|
|
122
|
+
rel, s_arg, v_arg = head
|
|
123
|
+
s = b.get(s_arg) if s_arg[0:1].isupper() else (s_arg if s_arg != "_" else None)
|
|
124
|
+
v = b.get(v_arg) if v_arg[0:1].isupper() else (v_arg if v_arg != "_" else None)
|
|
125
|
+
if not s or not v:
|
|
126
|
+
return None
|
|
127
|
+
return (s, rel, v)
|
|
128
|
+
|
|
129
|
+
def apply(self, now: _dt.datetime | None = None, max_iterations: int = 3) -> list[Fact]:
|
|
130
|
+
"""Run rules to fixpoint; return newly derived facts.
|
|
131
|
+
|
|
132
|
+
Derived facts inherit the USER SCOPE of their premises — without
|
|
133
|
+
this, ``team_uses(X, L) :- member_of(X, T), uses(T, L)`` derives a
|
|
134
|
+
fact under ``default`` that user0's reader can never see (scope
|
|
135
|
+
filter drops it), silently losing every multi-hop answer."""
|
|
136
|
+
now = now or _dt.datetime.now(_dt.timezone.utc)
|
|
137
|
+
derived_new: list[Fact] = []
|
|
138
|
+
seen: set[tuple] = set()
|
|
139
|
+
for _ in range(max_iterations):
|
|
140
|
+
added = 0
|
|
141
|
+
for rule in self.rules:
|
|
142
|
+
for b in self._join(rule):
|
|
143
|
+
sub = self._subst(rule.head, b)
|
|
144
|
+
if not sub:
|
|
145
|
+
continue
|
|
146
|
+
scope = b.get("_user") or "default"
|
|
147
|
+
s, rel, v = sub
|
|
148
|
+
key = (s, rel, v, scope)
|
|
149
|
+
if key in seen:
|
|
150
|
+
continue
|
|
151
|
+
seen.add(key)
|
|
152
|
+
if self.store.query_facts(subject=s, relation=rel, value=v,
|
|
153
|
+
user_id=scope, active=True):
|
|
154
|
+
continue
|
|
155
|
+
f = Fact(
|
|
156
|
+
id=new_id(), subject=s, relation=rel, value=v,
|
|
157
|
+
valid_from=iso(now)[:10], tx_from=iso(now),
|
|
158
|
+
user_id=scope,
|
|
159
|
+
confidence=0.75, memory_type="long_term",
|
|
160
|
+
is_derived=True,
|
|
161
|
+
provenance={"rule": rule.source, "bindings": b})
|
|
162
|
+
self.store.insert_fact(f)
|
|
163
|
+
derived_new.append(f)
|
|
164
|
+
self._rel_cache.pop(rel, None)
|
|
165
|
+
added += 1
|
|
166
|
+
if added == 0:
|
|
167
|
+
break
|
|
168
|
+
return derived_new
|
|
169
|
+
|
|
170
|
+
def invalidate(self) -> None:
|
|
171
|
+
self._rel_cache.clear()
|