betterwithage commited on
Commit
d2e94ce
·
verified ·
1 Parent(s): 8abad49

Upload folder using huggingface_hub

Browse files
second_brain/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (724 Bytes). View file
 
second_brain/__pycache__/plan.cpython-311.pyc ADDED
Binary file (5.03 kB). View file
 
second_brain/__pycache__/retrieve.cpython-311.pyc ADDED
Binary file (18.1 kB). View file
 
tests/__pycache__/test_app.cpython-311-pytest-9.1.1.pyc ADDED
Binary file (22.6 kB). View file
 
tests/__pycache__/test_plan.cpython-311-pytest-9.1.1.pyc ADDED
Binary file (6.61 kB). View file
 
tests/__pycache__/test_retrieve.cpython-311-pytest-9.1.1.pyc ADDED
Binary file (21.5 kB). View file
 
train/eval_navigator.py CHANGED
@@ -1,323 +1,323 @@
1
- #!/usr/bin/env python3
2
- """Named-N retrieve-hit and abstain bench. Train loss is not eval.
3
-
4
- SOFTWARE index is always scored. Generate is MEASURED only if a local adapter
5
- loads and emits parseable JSON; otherwise UNAVAILABLE. Never claim 5/5 unless
6
- the denominator was actually run.
7
- """
8
- from __future__ import annotations
9
-
10
- import json
11
- import re
12
- import sys
13
- from datetime import datetime, timezone
14
- from pathlib import Path
15
- from typing import Any
16
-
17
- HERE = Path(__file__).resolve().parent
18
- ROOT = HERE.parent
19
- if str(ROOT) not in sys.path:
20
- sys.path.insert(0, str(ROOT))
21
-
22
- from second_brain.plan import plan_from_handles # noqa: E402
23
- from second_brain.retrieve import SecondBrainIndex # noqa: E402
24
-
25
- RETRIEVE_GATE = HERE / "gate_retrieve.jsonl"
26
- ABSTAIN_GATE = HERE / "gate_abstain.jsonl"
27
- REPORT = HERE / "eval_report.json"
28
- ADAPTER = HERE / "brain-navigator-r2-adapter"
29
- SYS = (
30
- "You are BrainNavigator-R2, the SZL second-brain retrieval planner. "
31
- "Capability profile SZL-BrainNavigator-R2. Base Qwen/Qwen3.5-0.8B. "
32
- "You see HANDLES ONLY, never node text. Emit one JSON object. "
33
- "decision is NAVIGATE or ABSTAIN. groundedOnly is true. "
34
- "citedNodeIds must be a subset of offered nodeId values. "
35
- "If none of the offered handles support the query, ABSTAIN with empty steps. "
36
- "capabilityProfile must be SZL-BrainNavigator-R2. contentAccess HANDLES_ONLY. "
37
- "brainBinding.status is NOT_RESOLVED. You never execute retrieval."
38
- )
39
- JSON_RE = re.compile(r"\{.*\}", re.S)
40
-
41
-
42
- def _load(path: Path) -> list[dict[str, Any]]:
43
- rows = []
44
- for line in path.read_text(encoding="utf-8").splitlines():
45
- if line.strip():
46
- rows.append(json.loads(line))
47
- return rows
48
-
49
-
50
- def _parse_plan(text: str) -> dict[str, Any] | None:
51
- raw = (text or "").strip()
52
- if not raw:
53
- return None
54
- try:
55
- return json.loads(raw)
56
- except json.JSONDecodeError:
57
- m = JSON_RE.search(raw)
58
- if not m:
59
- return None
60
- try:
61
- return json.loads(m.group(0))
62
- except json.JSONDecodeError:
63
- return None
64
-
65
-
66
- def software_bench(idx: SecondBrainIndex) -> dict[str, Any]:
67
- retrieve = _load(RETRIEVE_GATE)
68
- abstain = _load(ABSTAIN_GATE)
69
- retrieve_cases = []
70
- hit = 0
71
- for row in retrieve:
72
- q = row["query"]
73
- expect = list(row.get("expect_cite") or [])
74
- got = idx.search(q, k=5)
75
- ids = [h["nodeId"] for h in got["handles"]]
76
- ok = bool(expect) and expect[0] in ids
77
- if ok:
78
- hit += 1
79
- plan = plan_from_handles(q, got["handles"])
80
- retrieve_cases.append(
81
- {
82
- "id": row["id"],
83
- "query": q,
84
- "expect_cite": expect,
85
- "got_ids": ids,
86
- "hit": ok,
87
- "plan_decision": plan["decision"],
88
- "plan_cite": plan["citedNodeIds"],
89
- }
90
- )
91
- abs_cases = []
92
- abs_ok = 0
93
- for row in abstain:
94
- q = row["query"]
95
- plan = plan_from_handles(q, row.get("handles") or [])
96
- ok = plan["decision"] == "ABSTAIN" and not plan["citedNodeIds"]
97
- if ok:
98
- abs_ok += 1
99
- abs_cases.append(
100
- {
101
- "id": row["id"],
102
- "query": q,
103
- "decision": plan["decision"],
104
- "citedNodeIds": plan["citedNodeIds"],
105
- "ok": ok,
106
- }
107
- )
108
- return {
109
- "kind": "SOFTWARE",
110
- "label": "MEASURED",
111
- "retrieve_hit": f"{hit}/{len(retrieve)}" if retrieve else "0/0",
112
- "retrieve_hit_correct": hit,
113
- "retrieve_hit_total": len(retrieve),
114
- "abstain": f"{abs_ok}/{len(abstain)}" if abstain else "0/0",
115
- "abstain_correct": abs_ok,
116
- "abstain_total": len(abstain),
117
- "retrieve_cases": retrieve_cases,
118
- "abstain_cases": abs_cases,
119
- "honesty": (
120
- "Lexical rank over the PUBLIC 575-chunk projection. "
121
- "Score is overlap, never correctness. Named-N gates."
122
- ),
123
- }
124
-
125
-
126
- def generate_bench() -> dict[str, Any]:
127
- if not (ADAPTER / "adapter_config.json").is_file():
128
- return {
129
- "kind": "GENERATE",
130
- "label": "UNAVAILABLE",
131
- "reason": "no local adapter; SOFTWARE navigator is the shipped planner",
132
- "publication_eligible": False,
133
- }
134
- try:
135
- import torch
136
- from unsloth import FastLanguageModel
137
- except Exception as exc: # noqa: BLE001
138
- return {
139
- "kind": "GENERATE",
140
- "label": "UNAVAILABLE",
141
- "reason": f"unsloth/torch import failed: {exc}",
142
- "publication_eligible": False,
143
- }
144
- if not torch.cuda.is_available():
145
- return {
146
- "kind": "GENERATE",
147
- "label": "UNAVAILABLE",
148
- "reason": "CUDA UNAVAILABLE for generate",
149
- "publication_eligible": False,
150
- }
151
- try:
152
- model, tokenizer = FastLanguageModel.from_pretrained(
153
- model_name=str(ADAPTER),
154
- max_seq_length=2048,
155
- load_in_4bit=False,
156
- load_in_16bit=True,
157
- )
158
- FastLanguageModel.for_inference(model)
159
- except Exception as exc: # noqa: BLE001
160
- return {
161
- "kind": "GENERATE",
162
- "label": "UNAVAILABLE",
163
- "reason": f"adapter load failed: {type(exc).__name__}: {exc}",
164
- "publication_eligible": False,
165
- }
166
-
167
- def infer(query: str, handles: list[dict[str, Any]]) -> dict[str, Any] | None:
168
- user = query + "\n\nCANDIDATE_HANDLES_JSON:\n" + json.dumps(handles)
169
- messages = [
170
- {"role": "system", "content": SYS},
171
- {"role": "user", "content": user},
172
- ]
173
- # Qwen3.5 ships a multimodal processor; tokenize text only.
174
- try:
175
- prompt = tokenizer.apply_chat_template(
176
- messages,
177
- tokenize=False,
178
- add_generation_prompt=True,
179
- enable_thinking=False,
180
- )
181
- except TypeError:
182
- prompt = tokenizer.apply_chat_template(
183
- messages, tokenize=False, add_generation_prompt=True
184
- )
185
- tok = getattr(tokenizer, "tokenizer", tokenizer)
186
- encoded = tok(prompt, return_tensors="pt", add_special_tokens=False)
187
- input_ids = encoded["input_ids"].to(model.device)
188
- attn = encoded.get("attention_mask")
189
- eos = getattr(tok, "eos_token_id", None)
190
- gen_kw: dict[str, Any] = {
191
- "input_ids": input_ids,
192
- "max_new_tokens": 384,
193
- "do_sample": False,
194
- }
195
- if attn is not None:
196
- gen_kw["attention_mask"] = attn.to(model.device)
197
- if eos is not None:
198
- gen_kw["eos_token_id"] = eos
199
- out = model.generate(**gen_kw)
200
- text = tok.decode(out[0][input_ids.shape[-1] :], skip_special_tokens=True)
201
- return _parse_plan(text)
202
-
203
- retrieve = _load(RETRIEVE_GATE)
204
- abstain = _load(ABSTAIN_GATE)
205
- nav_ok = 0
206
- abs_ok = 0
207
- halluc = 0
208
- cases: list[dict[str, Any]] = []
209
- parse_fail = 0
210
- try:
211
- for row in retrieve:
212
- plan = infer(row["query"], row["handles"])
213
- if not plan:
214
- parse_fail += 1
215
- cases.append({"id": row["id"], "ok": False, "reason": "unparseable"})
216
- print(f"[generate] {row['id']} unparseable")
217
- continue
218
- offered = {h["nodeId"] for h in row["handles"]}
219
- cites = list(plan.get("citedNodeIds") or [])
220
- if any(c not in offered for c in cites):
221
- halluc += 1
222
- expect = list(row.get("expect_cite") or [])
223
- ok = (
224
- plan.get("decision") == "NAVIGATE"
225
- and bool(expect)
226
- and expect[0] in cites
227
- and all(c in offered for c in cites)
228
- )
229
- if ok:
230
- nav_ok += 1
231
- print(f"[generate] {row['id']} {plan.get('decision')} ok={ok}")
232
- cases.append(
233
- {
234
- "id": row["id"],
235
- "decision": plan.get("decision"),
236
- "citedNodeIds": cites,
237
- "ok": ok,
238
- }
239
- )
240
- for row in abstain:
241
- plan = infer(row["query"], row["handles"])
242
- if not plan:
243
- parse_fail += 1
244
- cases.append({"id": row["id"], "ok": False, "reason": "unparseable"})
245
- continue
246
- offered = {h["nodeId"] for h in row["handles"]}
247
- cites = list(plan.get("citedNodeIds") or [])
248
- if any(c not in offered for c in cites):
249
- halluc += 1
250
- ok = plan.get("decision") == "ABSTAIN" and not cites
251
- if ok:
252
- abs_ok += 1
253
- cases.append(
254
- {
255
- "id": row["id"],
256
- "decision": plan.get("decision"),
257
- "citedNodeIds": cites,
258
- "ok": ok,
259
- }
260
- )
261
- except Exception as exc: # noqa: BLE001
262
- return {
263
- "kind": "GENERATE",
264
- "label": "UNAVAILABLE",
265
- "reason": f"generate failed: {type(exc).__name__}: {exc}",
266
- "publication_eligible": False,
267
- }
268
- return {
269
- "kind": "GENERATE",
270
- "label": "MEASURED",
271
- "retrieve_hit": f"{nav_ok}/{len(retrieve)}" if retrieve else "0/0",
272
- "retrieve_hit_correct": nav_ok,
273
- "retrieve_hit_total": len(retrieve),
274
- "abstain": f"{abs_ok}/{len(abstain)}" if abstain else "0/0",
275
- "abstain_correct": abs_ok,
276
- "abstain_total": len(abstain),
277
- "hallucinated_citation_count": halluc,
278
- "parse_fail": parse_fail,
279
- "cases": cases,
280
- "publication_eligible": False,
281
- "honesty": (
282
- "Owner-run named-N generate on local LoRA. Not a third-party bench. "
283
- "Train loss is not this number. publication_eligible stays false."
284
- ),
285
- }
286
-
287
-
288
- def main() -> int:
289
- idx = SecondBrainIndex()
290
- software = software_bench(idx)
291
- generate = generate_bench()
292
- report = {
293
- "schema": "szl.brain-navigator-r2.eval/v1",
294
- "artifact": "SZLHOLDINGS/brain-navigator-r2",
295
- "does_not_overwrite": "SZLHOLDINGS/SZL-Khipu-1.5B-BrainNavigator",
296
- "lambda": "Conjecture 1",
297
- "doctrine": "v11 LOCKED",
298
- "publication_eligible": False,
299
- "maturity": "MEASURED_RESEARCH_ONLY",
300
- "train_loss_is_eval": False,
301
- "raw_graph_nodes_admitted_to_gradients": 0,
302
- "corpus_n": idx.n,
303
- "software": software,
304
- "generate": generate,
305
- "computed_at": datetime.now(timezone.utc).isoformat(),
306
- "honesty": (
307
- "Do not claim 5/5 unless MEASURED. Existing 1.5B BrainNavigator "
308
- "abstain 2/6 is a different SKU and is not restated as this run."
309
- ),
310
- }
311
- REPORT.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8")
312
- print(
313
- "SOFTWARE retrieve-hit "
314
- f"{software['retrieve_hit']} abstain {software['abstain']} "
315
- f"GENERATE {generate['label']} "
316
- f"{generate.get('retrieve_hit', 'n/a')} / {generate.get('abstain', 'n/a')}"
317
- )
318
- print(f"wrote {REPORT}")
319
- return 0
320
-
321
-
322
- if __name__ == "__main__":
323
- raise SystemExit(main())
 
1
+ #!/usr/bin/env python3
2
+ """Named-N retrieve-hit and abstain bench. Train loss is not eval.
3
+
4
+ SOFTWARE index is always scored. Generate is MEASURED only if a local adapter
5
+ loads and emits parseable JSON; otherwise UNAVAILABLE. Never claim 5/5 unless
6
+ the denominator was actually run.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import re
12
+ import sys
13
+ from datetime import datetime, timezone
14
+ from pathlib import Path
15
+ from typing import Any
16
+
17
+ HERE = Path(__file__).resolve().parent
18
+ ROOT = HERE.parent
19
+ if str(ROOT) not in sys.path:
20
+ sys.path.insert(0, str(ROOT))
21
+
22
+ from second_brain.plan import plan_from_handles # noqa: E402
23
+ from second_brain.retrieve import SecondBrainIndex # noqa: E402
24
+
25
+ RETRIEVE_GATE = HERE / "gate_retrieve.jsonl"
26
+ ABSTAIN_GATE = HERE / "gate_abstain.jsonl"
27
+ REPORT = HERE / "eval_report.json"
28
+ ADAPTER = HERE / "brain-navigator-r2-adapter"
29
+ SYS = (
30
+ "You are BrainNavigator-R2, the SZL second-brain retrieval planner. "
31
+ "Capability profile SZL-BrainNavigator-R2. Base Qwen/Qwen3.5-0.8B. "
32
+ "You see HANDLES ONLY, never node text. Emit one JSON object. "
33
+ "decision is NAVIGATE or ABSTAIN. groundedOnly is true. "
34
+ "citedNodeIds must be a subset of offered nodeId values. "
35
+ "If none of the offered handles support the query, ABSTAIN with empty steps. "
36
+ "capabilityProfile must be SZL-BrainNavigator-R2. contentAccess HANDLES_ONLY. "
37
+ "brainBinding.status is NOT_RESOLVED. You never execute retrieval."
38
+ )
39
+ JSON_RE = re.compile(r"\{.*\}", re.S)
40
+
41
+
42
+ def _load(path: Path) -> list[dict[str, Any]]:
43
+ rows = []
44
+ for line in path.read_text(encoding="utf-8").splitlines():
45
+ if line.strip():
46
+ rows.append(json.loads(line))
47
+ return rows
48
+
49
+
50
+ def _parse_plan(text: str) -> dict[str, Any] | None:
51
+ raw = (text or "").strip()
52
+ if not raw:
53
+ return None
54
+ try:
55
+ return json.loads(raw)
56
+ except json.JSONDecodeError:
57
+ m = JSON_RE.search(raw)
58
+ if not m:
59
+ return None
60
+ try:
61
+ return json.loads(m.group(0))
62
+ except json.JSONDecodeError:
63
+ return None
64
+
65
+
66
+ def software_bench(idx: SecondBrainIndex) -> dict[str, Any]:
67
+ retrieve = _load(RETRIEVE_GATE)
68
+ abstain = _load(ABSTAIN_GATE)
69
+ retrieve_cases = []
70
+ hit = 0
71
+ for row in retrieve:
72
+ q = row["query"]
73
+ expect = list(row.get("expect_cite") or [])
74
+ got = idx.search(q, k=5)
75
+ ids = [h["nodeId"] for h in got["handles"]]
76
+ ok = bool(expect) and expect[0] in ids
77
+ if ok:
78
+ hit += 1
79
+ plan = plan_from_handles(q, got["handles"])
80
+ retrieve_cases.append(
81
+ {
82
+ "id": row["id"],
83
+ "query": q,
84
+ "expect_cite": expect,
85
+ "got_ids": ids,
86
+ "hit": ok,
87
+ "plan_decision": plan["decision"],
88
+ "plan_cite": plan["citedNodeIds"],
89
+ }
90
+ )
91
+ abs_cases = []
92
+ abs_ok = 0
93
+ for row in abstain:
94
+ q = row["query"]
95
+ plan = plan_from_handles(q, row.get("handles") or [])
96
+ ok = plan["decision"] == "ABSTAIN" and not plan["citedNodeIds"]
97
+ if ok:
98
+ abs_ok += 1
99
+ abs_cases.append(
100
+ {
101
+ "id": row["id"],
102
+ "query": q,
103
+ "decision": plan["decision"],
104
+ "citedNodeIds": plan["citedNodeIds"],
105
+ "ok": ok,
106
+ }
107
+ )
108
+ return {
109
+ "kind": "SOFTWARE",
110
+ "label": "MEASURED",
111
+ "retrieve_hit": f"{hit}/{len(retrieve)}" if retrieve else "0/0",
112
+ "retrieve_hit_correct": hit,
113
+ "retrieve_hit_total": len(retrieve),
114
+ "abstain": f"{abs_ok}/{len(abstain)}" if abstain else "0/0",
115
+ "abstain_correct": abs_ok,
116
+ "abstain_total": len(abstain),
117
+ "retrieve_cases": retrieve_cases,
118
+ "abstain_cases": abs_cases,
119
+ "honesty": (
120
+ "Lexical rank over the PUBLIC 575-chunk projection. "
121
+ "Score is overlap, never correctness. Named-N gates."
122
+ ),
123
+ }
124
+
125
+
126
+ def generate_bench() -> dict[str, Any]:
127
+ if not (ADAPTER / "adapter_config.json").is_file():
128
+ return {
129
+ "kind": "GENERATE",
130
+ "label": "UNAVAILABLE",
131
+ "reason": "no local adapter; SOFTWARE navigator is the shipped planner",
132
+ "publication_eligible": False,
133
+ }
134
+ try:
135
+ import torch
136
+ from unsloth import FastLanguageModel
137
+ except Exception as exc: # noqa: BLE001
138
+ return {
139
+ "kind": "GENERATE",
140
+ "label": "UNAVAILABLE",
141
+ "reason": f"unsloth/torch import failed: {exc}",
142
+ "publication_eligible": False,
143
+ }
144
+ if not torch.cuda.is_available():
145
+ return {
146
+ "kind": "GENERATE",
147
+ "label": "UNAVAILABLE",
148
+ "reason": "CUDA UNAVAILABLE for generate",
149
+ "publication_eligible": False,
150
+ }
151
+ try:
152
+ model, tokenizer = FastLanguageModel.from_pretrained(
153
+ model_name=str(ADAPTER),
154
+ max_seq_length=2048,
155
+ load_in_4bit=False,
156
+ load_in_16bit=True,
157
+ )
158
+ FastLanguageModel.for_inference(model)
159
+ except Exception as exc: # noqa: BLE001
160
+ return {
161
+ "kind": "GENERATE",
162
+ "label": "UNAVAILABLE",
163
+ "reason": f"adapter load failed: {type(exc).__name__}: {exc}",
164
+ "publication_eligible": False,
165
+ }
166
+
167
+ def infer(query: str, handles: list[dict[str, Any]]) -> dict[str, Any] | None:
168
+ user = query + "\n\nCANDIDATE_HANDLES_JSON:\n" + json.dumps(handles)
169
+ messages = [
170
+ {"role": "system", "content": SYS},
171
+ {"role": "user", "content": user},
172
+ ]
173
+ # Qwen3.5 ships a multimodal processor; tokenize text only.
174
+ try:
175
+ prompt = tokenizer.apply_chat_template(
176
+ messages,
177
+ tokenize=False,
178
+ add_generation_prompt=True,
179
+ enable_thinking=False,
180
+ )
181
+ except TypeError:
182
+ prompt = tokenizer.apply_chat_template(
183
+ messages, tokenize=False, add_generation_prompt=True
184
+ )
185
+ tok = getattr(tokenizer, "tokenizer", tokenizer)
186
+ encoded = tok(prompt, return_tensors="pt", add_special_tokens=False)
187
+ input_ids = encoded["input_ids"].to(model.device)
188
+ attn = encoded.get("attention_mask")
189
+ eos = getattr(tok, "eos_token_id", None)
190
+ gen_kw: dict[str, Any] = {
191
+ "input_ids": input_ids,
192
+ "max_new_tokens": 384,
193
+ "do_sample": False,
194
+ }
195
+ if attn is not None:
196
+ gen_kw["attention_mask"] = attn.to(model.device)
197
+ if eos is not None:
198
+ gen_kw["eos_token_id"] = eos
199
+ out = model.generate(**gen_kw)
200
+ text = tok.decode(out[0][input_ids.shape[-1] :], skip_special_tokens=True)
201
+ return _parse_plan(text)
202
+
203
+ retrieve = _load(RETRIEVE_GATE)
204
+ abstain = _load(ABSTAIN_GATE)
205
+ nav_ok = 0
206
+ abs_ok = 0
207
+ halluc = 0
208
+ cases: list[dict[str, Any]] = []
209
+ parse_fail = 0
210
+ try:
211
+ for row in retrieve:
212
+ plan = infer(row["query"], row["handles"])
213
+ if not plan:
214
+ parse_fail += 1
215
+ cases.append({"id": row["id"], "ok": False, "reason": "unparseable"})
216
+ print(f"[generate] {row['id']} unparseable")
217
+ continue
218
+ offered = {h["nodeId"] for h in row["handles"]}
219
+ cites = list(plan.get("citedNodeIds") or [])
220
+ if any(c not in offered for c in cites):
221
+ halluc += 1
222
+ expect = list(row.get("expect_cite") or [])
223
+ ok = (
224
+ plan.get("decision") == "NAVIGATE"
225
+ and bool(expect)
226
+ and expect[0] in cites
227
+ and all(c in offered for c in cites)
228
+ )
229
+ if ok:
230
+ nav_ok += 1
231
+ print(f"[generate] {row['id']} {plan.get('decision')} ok={ok}")
232
+ cases.append(
233
+ {
234
+ "id": row["id"],
235
+ "decision": plan.get("decision"),
236
+ "citedNodeIds": cites,
237
+ "ok": ok,
238
+ }
239
+ )
240
+ for row in abstain:
241
+ plan = infer(row["query"], row["handles"])
242
+ if not plan:
243
+ parse_fail += 1
244
+ cases.append({"id": row["id"], "ok": False, "reason": "unparseable"})
245
+ continue
246
+ offered = {h["nodeId"] for h in row["handles"]}
247
+ cites = list(plan.get("citedNodeIds") or [])
248
+ if any(c not in offered for c in cites):
249
+ halluc += 1
250
+ ok = plan.get("decision") == "ABSTAIN" and not cites
251
+ if ok:
252
+ abs_ok += 1
253
+ cases.append(
254
+ {
255
+ "id": row["id"],
256
+ "decision": plan.get("decision"),
257
+ "citedNodeIds": cites,
258
+ "ok": ok,
259
+ }
260
+ )
261
+ except Exception as exc: # noqa: BLE001
262
+ return {
263
+ "kind": "GENERATE",
264
+ "label": "UNAVAILABLE",
265
+ "reason": f"generate failed: {type(exc).__name__}: {exc}",
266
+ "publication_eligible": False,
267
+ }
268
+ return {
269
+ "kind": "GENERATE",
270
+ "label": "MEASURED",
271
+ "retrieve_hit": f"{nav_ok}/{len(retrieve)}" if retrieve else "0/0",
272
+ "retrieve_hit_correct": nav_ok,
273
+ "retrieve_hit_total": len(retrieve),
274
+ "abstain": f"{abs_ok}/{len(abstain)}" if abstain else "0/0",
275
+ "abstain_correct": abs_ok,
276
+ "abstain_total": len(abstain),
277
+ "hallucinated_citation_count": halluc,
278
+ "parse_fail": parse_fail,
279
+ "cases": cases,
280
+ "publication_eligible": False,
281
+ "honesty": (
282
+ "Owner-run named-N generate on local LoRA. Not a third-party bench. "
283
+ "Train loss is not this number. publication_eligible stays false."
284
+ ),
285
+ }
286
+
287
+
288
+ def main() -> int:
289
+ idx = SecondBrainIndex()
290
+ software = software_bench(idx)
291
+ generate = generate_bench()
292
+ report = {
293
+ "schema": "szl.brain-navigator-r2.eval/v1",
294
+ "artifact": "SZLHOLDINGS/brain-navigator-r2",
295
+ "does_not_overwrite": "SZLHOLDINGS/SZL-Khipu-1.5B-BrainNavigator",
296
+ "lambda": "Conjecture 1",
297
+ "doctrine": "v11 LOCKED",
298
+ "publication_eligible": False,
299
+ "maturity": "MEASURED_RESEARCH_ONLY",
300
+ "train_loss_is_eval": False,
301
+ "raw_graph_nodes_admitted_to_gradients": 0,
302
+ "corpus_n": idx.n,
303
+ "software": software,
304
+ "generate": generate,
305
+ "computed_at": datetime.now(timezone.utc).isoformat(),
306
+ "honesty": (
307
+ "Do not claim 5/5 unless MEASURED. Existing 1.5B BrainNavigator "
308
+ "abstain 2/6 is a different SKU and is not restated as this run."
309
+ ),
310
+ }
311
+ REPORT.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8")
312
+ print(
313
+ "SOFTWARE retrieve-hit "
314
+ f"{software['retrieve_hit']} abstain {software['abstain']} "
315
+ f"GENERATE {generate['label']} "
316
+ f"{generate.get('retrieve_hit', 'n/a')} / {generate.get('abstain', 'n/a')}"
317
+ )
318
+ print(f"wrote {REPORT}")
319
+ return 0
320
+
321
+
322
+ if __name__ == "__main__":
323
+ raise SystemExit(main())
train/eval_report.json CHANGED
@@ -163,10 +163,96 @@
163
  },
164
  "generate": {
165
  "kind": "GENERATE",
166
- "label": "UNAVAILABLE",
167
- "reason": "generate failed: TypeError: string indices must be integers, not 'str'",
168
- "publication_eligible": false
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  },
170
- "computed_at": "2026-08-29T13:18:14.020501+00:00",
171
  "honesty": "Do not claim 5/5 unless MEASURED. Existing 1.5B BrainNavigator abstain 2/6 is a different SKU and is not restated as this run."
172
  }
 
163
  },
164
  "generate": {
165
  "kind": "GENERATE",
166
+ "label": "MEASURED",
167
+ "retrieve_hit": "5/5",
168
+ "retrieve_hit_correct": 5,
169
+ "retrieve_hit_total": 5,
170
+ "abstain": "6/6",
171
+ "abstain_correct": 6,
172
+ "abstain_total": 6,
173
+ "hallucinated_citation_count": 0,
174
+ "parse_fail": 0,
175
+ "cases": [
176
+ {
177
+ "id": "nav-00",
178
+ "decision": "NAVIGATE",
179
+ "citedNodeIds": [
180
+ "ingest:szl-formula-ledger:001"
181
+ ],
182
+ "ok": true
183
+ },
184
+ {
185
+ "id": "nav-01",
186
+ "decision": "NAVIGATE",
187
+ "citedNodeIds": [
188
+ "formula:blk-d1507e347013"
189
+ ],
190
+ "ok": true
191
+ },
192
+ {
193
+ "id": "nav-02",
194
+ "decision": "NAVIGATE",
195
+ "citedNodeIds": [
196
+ "ingest:radicle-heartwood:001"
197
+ ],
198
+ "ok": true
199
+ },
200
+ {
201
+ "id": "nav-03",
202
+ "decision": "NAVIGATE",
203
+ "citedNodeIds": [
204
+ "ingest:radicle-heartwood:000"
205
+ ],
206
+ "ok": true
207
+ },
208
+ {
209
+ "id": "nav-04",
210
+ "decision": "NAVIGATE",
211
+ "citedNodeIds": [
212
+ "invariant:flywheel-lineage"
213
+ ],
214
+ "ok": true
215
+ },
216
+ {
217
+ "id": "abs-00",
218
+ "decision": "ABSTAIN",
219
+ "citedNodeIds": [],
220
+ "ok": true
221
+ },
222
+ {
223
+ "id": "abs-01",
224
+ "decision": "ABSTAIN",
225
+ "citedNodeIds": [],
226
+ "ok": true
227
+ },
228
+ {
229
+ "id": "abs-02",
230
+ "decision": "ABSTAIN",
231
+ "citedNodeIds": [],
232
+ "ok": true
233
+ },
234
+ {
235
+ "id": "abs-03",
236
+ "decision": "ABSTAIN",
237
+ "citedNodeIds": [],
238
+ "ok": true
239
+ },
240
+ {
241
+ "id": "abs-04",
242
+ "decision": "ABSTAIN",
243
+ "citedNodeIds": [],
244
+ "ok": true
245
+ },
246
+ {
247
+ "id": "abs-05",
248
+ "decision": "ABSTAIN",
249
+ "citedNodeIds": [],
250
+ "ok": true
251
+ }
252
+ ],
253
+ "publication_eligible": false,
254
+ "honesty": "Owner-run named-N generate on local LoRA. Not a third-party bench. Train loss is not this number. publication_eligible stays false."
255
  },
256
+ "computed_at": "2026-08-29T13:36:22.511311+00:00",
257
  "honesty": "Do not claim 5/5 unless MEASURED. Existing 1.5B BrainNavigator abstain 2/6 is a different SKU and is not restated as this run."
258
  }