quantum-cortex 1.0.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.
- cortex_c2/__init__.py +161 -0
- cortex_c2/consolidation.py +146 -0
- cortex_c2/router_ablation.py +254 -0
- cortex_c2/router_v2.py +109 -0
- cortex_c2b/__init__.py +724 -0
- cortex_c2b/companion_demo.py +203 -0
- cortex_c2b/crypto.py +102 -0
- cortex_c2b/external_arm.py +591 -0
- cortex_c2b/hm_lm.py +983 -0
- cortex_c2b/hm_protocol.py +308 -0
- cortex_c2b/lifecycle.py +454 -0
- cortex_c2b/lm_bridge.py +338 -0
- cortex_c2b/organ_use.py +254 -0
- cortex_c2b/read_path.py +218 -0
- cortex_c2b/reconstruction_probe.py +471 -0
- cortex_c2b/write_path.py +176 -0
- cortex_data/__init__.py +439 -0
- cortex_data/relay.py +174 -0
- cortex_eval/__init__.py +20 -0
- cortex_eval/ablation_mqar.py +187 -0
- cortex_eval/confirmation_run.py +133 -0
- cortex_eval/domain_map.py +127 -0
- cortex_eval/external_baseline.py +148 -0
- cortex_eval/ingest_confirmation.py +194 -0
- cortex_eval/mqar.py +122 -0
- cortex_eval/multiseed.py +148 -0
- cortex_eval/recurrent_base.py +197 -0
- cortex_eval/recurrent_ladder.py +159 -0
- cortex_eval/resumable_ladder.py +231 -0
- cortex_eval/resumable_rb.py +207 -0
- cortex_eval/run_mqar.py +127 -0
- cortex_eval/serial_position.py +116 -0
- quantum_cortex-1.0.0.dist-info/METADATA +209 -0
- quantum_cortex-1.0.0.dist-info/RECORD +41 -0
- quantum_cortex-1.0.0.dist-info/WHEEL +5 -0
- quantum_cortex-1.0.0.dist-info/licenses/AUTHORS.md +30 -0
- quantum_cortex-1.0.0.dist-info/licenses/LICENSE +73 -0
- quantum_cortex-1.0.0.dist-info/licenses/LICENSE-DOCS.md +34 -0
- quantum_cortex-1.0.0.dist-info/licenses/NOTICE +50 -0
- quantum_cortex-1.0.0.dist-info/top_level.txt +5 -0
- train.py +885 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"""The organ as a component, on use case 1 of the whitepaper (§1.4): the long running
|
|
2
|
+
project companion. A practitioner works for months on one matter; a fresh session
|
|
3
|
+
months later must find what was decided, cite the record it rests on, and say
|
|
4
|
+
"no record" for what was never written.
|
|
5
|
+
|
|
6
|
+
This demonstration runs on the protocol's own code path (the gated write path, the
|
|
7
|
+
sealed on disk journal, the cue index, session B in a NEW PROCESS that knows nothing
|
|
8
|
+
of session A but the disk) with the organ level cue convention of the Molaison
|
|
9
|
+
protocol: the entity is the address (`_cue_for(f"{schema}|{entity}")`). What it shows
|
|
10
|
+
is the organ's contract: an answer is a citation of a stored record with its pointer,
|
|
11
|
+
or an abstention when the journal's best candidate scores under the declared line.
|
|
12
|
+
What it does not show is the learned addressing of paraphrases: that is the language
|
|
13
|
+
model arm's job, measured separately (RESULTS rows 21 onward).
|
|
14
|
+
|
|
15
|
+
python -m cortex_c2b.companion_demo --out metrics/mqar/companion-demo-<date>.json
|
|
16
|
+
|
|
17
|
+
The declared line: the citation threshold on the journal's cosine score, CITE_MIN = 0.5.
|
|
18
|
+
A stored address scores 1.0 by construction; a never written address, a random unit
|
|
19
|
+
vector against a 64 dimensional index, scores well under 0.5 (the demonstration
|
|
20
|
+
records the observed maximum so the margin is a measurement, not a promise).
|
|
21
|
+
"""
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import os
|
|
26
|
+
import subprocess
|
|
27
|
+
import sys
|
|
28
|
+
from dataclasses import dataclass
|
|
29
|
+
from datetime import datetime, timezone
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
|
|
32
|
+
from cortex_c2b import Journal, POLICY_STOP, lifecycle_declaration
|
|
33
|
+
from cortex_c2b.hm_protocol import _cue_for
|
|
34
|
+
from cortex_c2b.read_path import JournalPath
|
|
35
|
+
from cortex_c2b.write_path import WritePath
|
|
36
|
+
|
|
37
|
+
CITE_MIN = 0.5 # the declared citation line on the journal's cosine score
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class Record:
|
|
42
|
+
date: str
|
|
43
|
+
schema: str
|
|
44
|
+
entity: str # the address
|
|
45
|
+
text: str # the payload as written that day
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# A fictional intellectual property matter, January to May: what a practitioner writes down.
|
|
49
|
+
CASE: list[Record] = [
|
|
50
|
+
Record("12 Jan", "decision", "argument:originality",
|
|
51
|
+
"12 Jan: the originality argument is set aside on the strength of ruling 2024/AR/512 (Brussels Court of Appeal, 8 Nov 2023), which denies originality to template based layouts"),
|
|
52
|
+
Record("12 Jan", "object", "ruling:2024/AR/512",
|
|
53
|
+
"12 Jan: ruling 2024/AR/512, Brussels Court of Appeal, 8 Nov 2023: analysed in full; holds that a layout produced from a vendor template carries no author's own choices"),
|
|
54
|
+
Record("19 Jan", "decision", "argument:database-right",
|
|
55
|
+
"19 Jan: the database right is retained as the main ground: the platform's listing base is a substantial investment in obtaining and verifying the data"),
|
|
56
|
+
Record("2 Feb", "person", "expert:Barbieux",
|
|
57
|
+
"2 Feb: the court expert Barbieux is to be challenged on method: his report compares source trees without dating the commits"),
|
|
58
|
+
Record("16 Feb", "event", "deadline:conclusions",
|
|
59
|
+
"16 Feb: the deadline for our conclusions is 30 April; the opponent's are due 15 April"),
|
|
60
|
+
Record("3 Mar", "object", "exhibit:git-history",
|
|
61
|
+
"3 Mar: exhibit 12, the git history 2008 to 2009, is retained as the primary proof of authorship; certified copy ordered"),
|
|
62
|
+
Record("21 Mar", "decision", "settlement:offer-1",
|
|
63
|
+
"21 Mar: the first settlement offer (licence at 40 percent) is declined; the client wants recognition of authorship before any licence"),
|
|
64
|
+
Record("8 Apr", "place", "venue:hearing",
|
|
65
|
+
"8 Apr: the hearing is fixed at the Brussels Enterprise Court, chamber 17, room B, 4 May at 9:30"),
|
|
66
|
+
Record("8 Apr", "event", "hearing:4-May",
|
|
67
|
+
"8 Apr: hearing of 4 May: pleadings limited to the database right and the authorship of exhibit 12; the originality argument stays out"),
|
|
68
|
+
Record("22 Apr", "person", "witness:Moreau",
|
|
69
|
+
"22 Apr: witness Moreau (the hosting provider) confirms in writing the deployment dates of March 2009; statement filed as exhibit 15"),
|
|
70
|
+
Record("30 Apr", "decision", "conclusions:filed",
|
|
71
|
+
"30 Apr: our conclusions are filed: two grounds, the database right and the authorship of exhibit 12; originality is not pleaded"),
|
|
72
|
+
Record("4 May", "event", "hearing:outcome",
|
|
73
|
+
"4 May: the case is taken under advisement; judgment expected within six weeks"),
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
# What a fresh session asks months later: planted addresses, then addresses that were never written.
|
|
77
|
+
QUESTIONS_PLANTED = [
|
|
78
|
+
("argument:originality", "what was decided about the originality argument, and on what ground?"),
|
|
79
|
+
("hearing:4-May", "what is the scope of the 4 May hearing?"),
|
|
80
|
+
("settlement:offer-1", "what happened to the first settlement offer?"),
|
|
81
|
+
("exhibit:git-history", "what is our primary proof of authorship?"),
|
|
82
|
+
("expert:Barbieux", "what is our line on the court expert?"),
|
|
83
|
+
]
|
|
84
|
+
QUESTIONS_NEVER_WRITTEN = [
|
|
85
|
+
("witness:Dupont", "what did witness Dupont say?"),
|
|
86
|
+
("invoice:2019-042", "was invoice 2019-042 paid?"),
|
|
87
|
+
("ruling:2022/AR/77", "what does ruling 2022/AR/77 hold?"),
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def cue(schema: str, entity: str):
|
|
92
|
+
return _cue_for(f"{schema}|{entity}")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _schema_of(entity: str) -> str:
|
|
96
|
+
for r in CASE:
|
|
97
|
+
if r.entity == entity:
|
|
98
|
+
return r.schema
|
|
99
|
+
return "decision" # a never written address is asked as if it were a decision
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def session_a(journal_path: Path, key: bytes) -> dict:
|
|
103
|
+
"""Months of work: every record written through the gated write path into a sealed journal."""
|
|
104
|
+
journal = Journal(journal_path, key=key, policy=POLICY_STOP)
|
|
105
|
+
wp = WritePath(journal, admission_threshold=0.15, seed=0)
|
|
106
|
+
jp = JournalPath(journal)
|
|
107
|
+
written = []
|
|
108
|
+
for i, r in enumerate(CASE):
|
|
109
|
+
rep = wp.write(cue(r.schema, r.entity), r.text.encode("utf-8"), r.schema, now=float(i))
|
|
110
|
+
if rep.admitted:
|
|
111
|
+
jp.on_write(rep.entry)
|
|
112
|
+
written.append({"date": r.date, "entity": r.entity, "pointer": rep.entry.pointer})
|
|
113
|
+
decl = lifecycle_declaration(journal)["storage"]
|
|
114
|
+
return {"records_written": len(written), "records": written, "storage": decl,
|
|
115
|
+
"durable": journal.mode == "durable"}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def session_b(journal_path: Path, key: bytes) -> dict:
|
|
119
|
+
"""A fresh session, months later, in a new process: the journal reopened from the disk
|
|
120
|
+
alone, the index recomputed; every answer is a citation or an abstention."""
|
|
121
|
+
journal = Journal(journal_path, key=key, policy=POLICY_STOP)
|
|
122
|
+
jp = JournalPath(journal)
|
|
123
|
+
transcript = []
|
|
124
|
+
for entity, question in QUESTIONS_PLANTED + QUESTIONS_NEVER_WRITTEN:
|
|
125
|
+
hits = jp.retrieve(cue(_schema_of(entity), entity), k=1)
|
|
126
|
+
score = float(hits[0][2]) if hits else 0.0
|
|
127
|
+
if hits and score >= CITE_MIN:
|
|
128
|
+
entry, payload, _ = hits[0]
|
|
129
|
+
transcript.append({"question": question, "address": entity, "answer": "cite",
|
|
130
|
+
"pointer": entry.pointer, "record": payload.decode("utf-8", errors="replace"),
|
|
131
|
+
"score": round(score, 4)})
|
|
132
|
+
else:
|
|
133
|
+
transcript.append({"question": question, "address": entity, "answer": "abstain",
|
|
134
|
+
"pointer": None, "record": None, "score": round(score, 4)})
|
|
135
|
+
return {"entries_reopened": len(journal), "transcript": transcript,
|
|
136
|
+
"storage": lifecycle_declaration(journal)["storage"]}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def run(journal_path: Path, key: bytes) -> dict:
|
|
140
|
+
a = session_a(journal_path, key)
|
|
141
|
+
env = dict(os.environ, QUANTUM_CORTEX_JOURNAL_KEY=key.hex())
|
|
142
|
+
proc = subprocess.run([sys.executable, "-m", "cortex_c2b.companion_demo", "--session-b", str(journal_path)],
|
|
143
|
+
capture_output=True, text=True, env=env, cwd=str(Path(__file__).resolve().parents[1]))
|
|
144
|
+
if proc.returncode != 0:
|
|
145
|
+
raise RuntimeError(f"session B failed:\n{proc.stderr[-2000:]}")
|
|
146
|
+
b = json.loads(proc.stdout.strip().splitlines()[-1])
|
|
147
|
+
planted = [t for t in b["transcript"] if t["address"] in dict(QUESTIONS_PLANTED)]
|
|
148
|
+
never = [t for t in b["transcript"] if t["address"] in dict(QUESTIONS_NEVER_WRITTEN)]
|
|
149
|
+
pointer_of = {r["entity"]: r["pointer"] for r in a["records"]}
|
|
150
|
+
cited_right = sum(t["answer"] == "cite" and t["pointer"] == pointer_of.get(t["address"]) for t in planted)
|
|
151
|
+
abstained = sum(t["answer"] == "abstain" for t in never)
|
|
152
|
+
return {
|
|
153
|
+
"demonstration": "the organ as a component: use case 1, the long running project companion",
|
|
154
|
+
"timestamp_utc": datetime.now(timezone.utc).isoformat(timespec="seconds"),
|
|
155
|
+
"code_path": "gated write path, sealed on disk journal, cue index; session B in a new process from the disk alone",
|
|
156
|
+
"cue_convention": "organ level, the Molaison protocol's: the entity is the address (hash seeded cue); paraphrase addressing is the model arm's job",
|
|
157
|
+
"cite_min": CITE_MIN,
|
|
158
|
+
"session_a": {"records_written": a["records_written"], "storage": a["storage"]},
|
|
159
|
+
"session_b": {"process": "new (nothing of session A but the disk)", "entries_reopened": b["entries_reopened"],
|
|
160
|
+
"storage": b["storage"], "transcript": b["transcript"]},
|
|
161
|
+
"summary": {"planted_questions": len(planted), "cited_with_the_right_pointer": cited_right,
|
|
162
|
+
"never_written_questions": len(never), "abstained": abstained,
|
|
163
|
+
"max_score_on_never_written": max(t["score"] for t in never),
|
|
164
|
+
"min_score_on_planted": min(t["score"] for t in planted)},
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _cli():
|
|
169
|
+
import argparse
|
|
170
|
+
ap = argparse.ArgumentParser(description="the organ as a component: the long running project companion")
|
|
171
|
+
ap.add_argument("--session-b", default=None, help="(internal) reopen this journal in a new process and answer")
|
|
172
|
+
ap.add_argument("--journal", default=None, help="journal path (default: a temporary sealed directory)")
|
|
173
|
+
ap.add_argument("--out", default=None, help="retain the demonstration as a file")
|
|
174
|
+
args = ap.parse_args()
|
|
175
|
+
if args.session_b:
|
|
176
|
+
from cortex_c2b.crypto import key_from_env
|
|
177
|
+
key = key_from_env()
|
|
178
|
+
if key is None:
|
|
179
|
+
raise SystemExit("QUANTUM_CORTEX_JOURNAL_KEY missing")
|
|
180
|
+
print(json.dumps(session_b(Path(args.session_b), key)))
|
|
181
|
+
return
|
|
182
|
+
from cortex_c2b.crypto import generate_key
|
|
183
|
+
key = generate_key()
|
|
184
|
+
if args.journal:
|
|
185
|
+
r = run(Path(args.journal), key)
|
|
186
|
+
else:
|
|
187
|
+
import tempfile
|
|
188
|
+
with tempfile.TemporaryDirectory() as d:
|
|
189
|
+
r = run(Path(d) / "companion-journal.jsonl", key)
|
|
190
|
+
for t in r["session_b"]["transcript"]:
|
|
191
|
+
if t["answer"] == "cite":
|
|
192
|
+
print(f"Q: {t['question']}\n cite {t['pointer'][:12]} (score {t['score']}): {t['record']}\n")
|
|
193
|
+
else:
|
|
194
|
+
print(f"Q: {t['question']}\n no record for {t['address']} (best score {t['score']} < {CITE_MIN}): abstain\n")
|
|
195
|
+
print(json.dumps(r["summary"], indent=1))
|
|
196
|
+
if args.out:
|
|
197
|
+
out = Path(args.out); out.parent.mkdir(parents=True, exist_ok=True)
|
|
198
|
+
out.write_text(json.dumps(r, indent=2) + "\n", encoding="utf-8")
|
|
199
|
+
print(f"retained: {out}")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
if __name__ == "__main__":
|
|
203
|
+
_cli()
|
cortex_c2b/crypto.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""cortex_c2b.crypto -- encryption at rest for the journal and its payloads (ADR-007 D6, D8).
|
|
2
|
+
|
|
3
|
+
Same concept on both planes: the Quantum Meridian daemon encrypts its journal
|
|
4
|
+
per line with AES-256-GCM in the framing `QJE1:<base64(iv|tag|ciphertext)>`
|
|
5
|
+
(hub decision 010, layer 1). The cortex reuses that framing byte for byte for
|
|
6
|
+
its log lines, and a binary variant for payload files (`b"QJE1" + iv + tag +
|
|
7
|
+
ciphertext`), so a tampered line or file fails loudly instead of yielding
|
|
8
|
+
garbage, and a legacy clear line can coexist with encrypted ones in one file
|
|
9
|
+
(migration falls out for free, as on the hub).
|
|
10
|
+
|
|
11
|
+
Scope: one key per journal, one journal per scope (hub decision 009). Key
|
|
12
|
+
management (where the key lives: DPAPI on the hub, secret store, HSM) is a
|
|
13
|
+
separate problem, deferred as in hub decision 010 -- here the key is an
|
|
14
|
+
explicit 32 byte argument, never read implicitly, never written to disk.
|
|
15
|
+
|
|
16
|
+
Dependency: `cryptography` (Apache-2.0 OR BSD-3-Clause, license checked at
|
|
17
|
+
ingestion on 2026-09-12), imported lazily: a journal without a key never
|
|
18
|
+
imports it. Written from scratch (our filon) over that primitive; we do not
|
|
19
|
+
implement ciphers ourselves.
|
|
20
|
+
"""
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import base64
|
|
24
|
+
import os
|
|
25
|
+
import secrets
|
|
26
|
+
|
|
27
|
+
MAGIC = b"QJE1"
|
|
28
|
+
LINE_PREFIX = "QJE1:"
|
|
29
|
+
IV_LEN, TAG_LEN, KEY_LEN = 12, 16, 32
|
|
30
|
+
AAD_LINE = b"quantum-cortex journal line"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def generate_key() -> bytes:
|
|
34
|
+
"""A fresh 256 bit key. Where it is kept is the caller's decision."""
|
|
35
|
+
return secrets.token_bytes(KEY_LEN)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def key_from_env(var: str = "QUANTUM_CORTEX_JOURNAL_KEY") -> bytes | None:
|
|
39
|
+
"""Optional helper: a hex key in the environment, or None. Explicit call only."""
|
|
40
|
+
v = os.environ.get(var)
|
|
41
|
+
if not v:
|
|
42
|
+
return None
|
|
43
|
+
k = bytes.fromhex(v)
|
|
44
|
+
if len(k) != KEY_LEN:
|
|
45
|
+
raise ValueError(f"{var} must be {KEY_LEN} bytes hex, got {len(k)}")
|
|
46
|
+
return k
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _aesgcm(key: bytes):
|
|
50
|
+
if len(key) != KEY_LEN:
|
|
51
|
+
raise ValueError(f"key must be {KEY_LEN} bytes, got {len(key)}")
|
|
52
|
+
try:
|
|
53
|
+
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
54
|
+
except ImportError as e: # pragma: no cover
|
|
55
|
+
raise ImportError("encryption at rest needs the `cryptography` package "
|
|
56
|
+
"(pip install cryptography)") from e
|
|
57
|
+
return AESGCM(key)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def seal(key: bytes, plaintext: bytes, aad: bytes) -> bytes:
|
|
61
|
+
"""Binary framing for payload files: MAGIC | iv | tag | ciphertext."""
|
|
62
|
+
iv = os.urandom(IV_LEN)
|
|
63
|
+
ct_tag = _aesgcm(key).encrypt(iv, plaintext, aad)
|
|
64
|
+
return MAGIC + iv + ct_tag[-TAG_LEN:] + ct_tag[:-TAG_LEN]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def open_sealed(key: bytes, blob: bytes, aad: bytes) -> bytes:
|
|
68
|
+
if not blob.startswith(MAGIC):
|
|
69
|
+
raise ValueError("not a sealed blob")
|
|
70
|
+
body = blob[len(MAGIC):]
|
|
71
|
+
iv, tag, ct = body[:IV_LEN], body[IV_LEN:IV_LEN + TAG_LEN], body[IV_LEN + TAG_LEN:]
|
|
72
|
+
return _aesgcm(key).decrypt(iv, ct + tag, aad) # raises InvalidTag on tampering / wrong key
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def is_sealed(blob: bytes) -> bool:
|
|
76
|
+
return blob.startswith(MAGIC)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def sealed_overhead() -> int:
|
|
80
|
+
return len(MAGIC) + IV_LEN + TAG_LEN
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def seal_line(key: bytes, text: str) -> str:
|
|
84
|
+
"""Text framing for log lines, identical to the hub's: QJE1:<base64(iv|tag|ct)>."""
|
|
85
|
+
iv = os.urandom(IV_LEN)
|
|
86
|
+
ct_tag = _aesgcm(key).encrypt(iv, text.encode("utf-8"), AAD_LINE)
|
|
87
|
+
return LINE_PREFIX + base64.b64encode(iv + ct_tag[-TAG_LEN:] + ct_tag[:-TAG_LEN]).decode("ascii")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def open_line(key: bytes | None, line: str) -> str:
|
|
91
|
+
"""A clear line passes through; a sealed line needs the key and fails loudly."""
|
|
92
|
+
if not line.startswith(LINE_PREFIX):
|
|
93
|
+
return line
|
|
94
|
+
if key is None:
|
|
95
|
+
raise ValueError("encrypted journal line and no key given")
|
|
96
|
+
raw = base64.b64decode(line[len(LINE_PREFIX):])
|
|
97
|
+
iv, tag, ct = raw[:IV_LEN], raw[IV_LEN:IV_LEN + TAG_LEN], raw[IV_LEN + TAG_LEN:]
|
|
98
|
+
return _aesgcm(key).decrypt(iv, ct + tag, AAD_LINE).decode("utf-8")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def is_sealed_line(line: str) -> bool:
|
|
102
|
+
return line.startswith(LINE_PREFIX)
|