upgraedd commited on
Commit
fc94bec
·
verified ·
1 Parent(s): fba6e73

Upload ESL_MEDIATOR.txt

Browse files

"the body to the mind"

Files changed (1) hide show
  1. ESL_MEDIATOR.txt +524 -0
ESL_MEDIATOR.txt ADDED
@@ -0,0 +1,524 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ EIS + ESL MEDIATOR v2.0 – Full Epistemic Substrate with Suppression Analytics
4
+ ================================================================================
5
+ Adds:
6
+ - Cross‑claim contradiction tracking (graph)
7
+ - Signature weighting (suppression‑likelihood scores)
8
+ - Entity‑coherence scoring (temporal consistency)
9
+ - Suppression‑pattern classifier (aggregates signatures into threat levels)
10
+ - Narrative‑violation detector (checks LLM output for narrative drift)
11
+ """
12
+
13
+ import hashlib
14
+ import json
15
+ import os
16
+ import secrets
17
+ import time
18
+ import math
19
+ from datetime import datetime
20
+ from typing import Dict, List, Any, Optional, Tuple, Set
21
+ from collections import defaultdict
22
+ import requests
23
+
24
+ # ============================================================================
25
+ # PART 1: CRYPTOGRAPHIC HELPERS
26
+ # ============================================================================
27
+
28
+ def sha3_512(data: str) -> str:
29
+ return hashlib.sha3_512(data.encode()).hexdigest()
30
+
31
+ def hash_dict(data: Dict) -> str:
32
+ return sha3_512(json.dumps(data, sort_keys=True, separators=(',', ':')))
33
+
34
+ # ============================================================================
35
+ # PART 2: ENHANCED EPISTEMIC SUBSTRATE LEDGER (ESL)
36
+ # ============================================================================
37
+
38
+ class ESLedger:
39
+ """Persistent ledger with cross‑claim contradictions, signature weights, coherence."""
40
+ def __init__(self, path: str = "esl_ledger.json"):
41
+ self.path = path
42
+ self.claims: Dict[str, Dict] = {} # claim_id -> claim dict
43
+ self.entities: Dict[str, Dict] = {} # entity_name -> entity dict
44
+ self.signatures: List[Dict] = [] # signature logs with weights
45
+ self.contradiction_graph: Dict[str, Set[str]] = defaultdict(set) # claim_id -> set of contradictory claim_ids
46
+ self.blocks: List[Dict] = []
47
+ self._load()
48
+
49
+ def _load(self):
50
+ if os.path.exists(self.path):
51
+ try:
52
+ with open(self.path, 'r') as f:
53
+ data = json.load(f)
54
+ self.claims = data.get("claims", {})
55
+ self.entities = data.get("entities", {})
56
+ self.signatures = data.get("signatures", [])
57
+ self.blocks = data.get("blocks", [])
58
+ # Load contradiction graph as sets
59
+ cg = data.get("contradiction_graph", {})
60
+ self.contradiction_graph = {k: set(v) for k, v in cg.items()}
61
+ except Exception:
62
+ pass
63
+
64
+ def _save(self):
65
+ # Convert sets to lists for JSON
66
+ cg_serializable = {k: list(v) for k, v in self.contradiction_graph.items()}
67
+ data = {
68
+ "claims": self.claims,
69
+ "entities": self.entities,
70
+ "signatures": self.signatures,
71
+ "contradiction_graph": cg_serializable,
72
+ "blocks": self.blocks,
73
+ "updated": datetime.utcnow().isoformat() + "Z"
74
+ }
75
+ with open(self.path + ".tmp", 'w') as f:
76
+ json.dump(data, f, indent=2)
77
+ os.replace(self.path + ".tmp", self.path)
78
+
79
+ def add_claim(self, text: str, agent: str = "user") -> str:
80
+ claim_id = secrets.token_hex(16)
81
+ self.claims[claim_id] = {
82
+ "id": claim_id, "text": text, "agent": agent,
83
+ "timestamp": datetime.utcnow().isoformat() + "Z",
84
+ "entities": [], "signatures": [], "coherence": 0.5,
85
+ "contradictions": [], "suppression_score": 0.0
86
+ }
87
+ self._save()
88
+ return claim_id
89
+
90
+ def add_entity(self, name: str, etype: str, claim_id: str):
91
+ if name not in self.entities:
92
+ self.entities[name] = {
93
+ "name": name, "type": etype,
94
+ "first_seen": datetime.utcnow().isoformat() + "Z",
95
+ "last_seen": self.claims[claim_id]["timestamp"],
96
+ "appearances": [], "coherence_scores": []
97
+ }
98
+ ent = self.entities[name]
99
+ if claim_id not in ent["appearances"]:
100
+ ent["appearances"].append(claim_id)
101
+ ent["last_seen"] = self.claims[claim_id]["timestamp"]
102
+ self.claims[claim_id]["entities"].append(name)
103
+ self._save()
104
+
105
+ def add_signature(self, claim_id: str, sig_name: str, weight: float = 0.5, context: Dict = None):
106
+ """Add a signature with a weight (0-1) indicating suppression likelihood."""
107
+ self.signatures.append({
108
+ "signature": sig_name, "claim_id": claim_id,
109
+ "timestamp": datetime.utcnow().isoformat() + "Z",
110
+ "weight": weight, "context": context or {}
111
+ })
112
+ if sig_name not in self.claims[claim_id]["signatures"]:
113
+ self.claims[claim_id]["signatures"].append(sig_name)
114
+ # Update suppression score for the claim (max of signature weights)
115
+ current = self.claims[claim_id].get("suppression_score", 0.0)
116
+ self.claims[claim_id]["suppression_score"] = max(current, weight)
117
+ self._save()
118
+
119
+ def add_contradiction(self, claim_id_a: str, claim_id_b: str):
120
+ """Record that two claims contradict each other."""
121
+ self.contradiction_graph[claim_id_a].add(claim_id_b)
122
+ self.contradiction_graph[claim_id_b].add(claim_id_a)
123
+ # Update each claim's contradiction list
124
+ if claim_id_b not in self.claims[claim_id_a]["contradictions"]:
125
+ self.claims[claim_id_a]["contradictions"].append(claim_id_b)
126
+ if claim_id_a not in self.claims[claim_id_b]["contradictions"]:
127
+ self.claims[claim_id_b]["contradictions"].append(claim_id_a)
128
+ self._save()
129
+
130
+ def get_entity_coherence(self, entity_name: str) -> float:
131
+ """Calculate temporal coherence for an entity: low variance in appearance intervals."""
132
+ ent = self.entities.get(entity_name)
133
+ if not ent or len(ent["appearances"]) < 2:
134
+ return 0.5
135
+ timestamps = []
136
+ for cid in ent["appearances"]:
137
+ ts = self.claims[cid]["timestamp"]
138
+ timestamps.append(datetime.fromisoformat(ts.replace('Z', '+00:00')))
139
+ # Compute average interval variance (simplified)
140
+ intervals = [(timestamps[i+1] - timestamps[i]).total_seconds() / 86400 for i in range(len(timestamps)-1)]
141
+ if not intervals:
142
+ return 0.5
143
+ mean = sum(intervals) / len(intervals)
144
+ variance = sum((i - mean)**2 for i in intervals) / len(intervals)
145
+ # Coherence is high when variance is low (normalized)
146
+ coherence = 1.0 / (1.0 + variance)
147
+ return min(1.0, max(0.0, coherence))
148
+
149
+ def suppression_pattern_classifier(self, claim_id: str) -> Dict:
150
+ """Aggregate signatures into suppression pattern threat levels."""
151
+ claim = self.claims.get(claim_id, {})
152
+ sig_names = claim.get("signatures", [])
153
+ if not sig_names:
154
+ return {"level": "none", "score": 0.0, "patterns": []}
155
+
156
+ # Predefined pattern groups (signature -> pattern)
157
+ pattern_map = {
158
+ "entity_present_then_absent": "erasure",
159
+ "gradual_fading": "erasure",
160
+ "single_explanation": "narrative_capture",
161
+ "ad_hominem_attacks": "discreditation",
162
+ "deflection": "misdirection",
163
+ "archival_gaps": "erasure",
164
+ "repetitive_messaging": "conditioning"
165
+ }
166
+ patterns = []
167
+ total_weight = 0.0
168
+ for sig in sig_names:
169
+ pat = pattern_map.get(sig, "unknown")
170
+ patterns.append(pat)
171
+ # Find weight from signature logs
172
+ weight = 0.5
173
+ for log in self.signatures:
174
+ if log["signature"] == sig and log["claim_id"] == claim_id:
175
+ weight = log.get("weight", 0.5)
176
+ break
177
+ total_weight += weight
178
+ avg_weight = total_weight / len(sig_names) if sig_names else 0.0
179
+
180
+ if avg_weight > 0.7:
181
+ level = "high"
182
+ elif avg_weight > 0.4:
183
+ level = "medium"
184
+ elif avg_weight > 0.1:
185
+ level = "low"
186
+ else:
187
+ level = "none"
188
+
189
+ return {"level": level, "score": avg_weight, "patterns": list(set(patterns))}
190
+
191
+ def get_entity_timeline(self, name: str) -> List[Dict]:
192
+ ent = self.entities.get(name)
193
+ if not ent:
194
+ return []
195
+ timeline = []
196
+ for cid in ent["appearances"]:
197
+ claim = self.claims.get(cid)
198
+ if claim:
199
+ timeline.append({
200
+ "timestamp": claim["timestamp"],
201
+ "text": claim["text"]
202
+ })
203
+ timeline.sort(key=lambda x: x["timestamp"])
204
+ return timeline
205
+
206
+ def disappearance_suspected(self, name: str, threshold_days: int = 30) -> bool:
207
+ timeline = self.get_entity_timeline(name)
208
+ if not timeline:
209
+ return False
210
+ last = datetime.fromisoformat(timeline[-1]["timestamp"].replace('Z', '+00:00'))
211
+ now = datetime.utcnow()
212
+ return (now - last).days > threshold_days
213
+
214
+ def create_block(self) -> Dict:
215
+ block = {
216
+ "index": len(self.blocks),
217
+ "timestamp": datetime.utcnow().isoformat() + "Z",
218
+ "prev_hash": self.blocks[-1]["hash"] if self.blocks else "0"*64,
219
+ "state_hash": hash_dict({"claims": self.claims, "entities": self.entities})
220
+ }
221
+ block["hash"] = hash_dict(block)
222
+ self.blocks.append(block)
223
+ self._save()
224
+ return block
225
+
226
+ # ============================================================================
227
+ # PART 3: ENHANCED FALSIFICATION ENGINE (with ESL data)
228
+ # ============================================================================
229
+
230
+ class Falsifier:
231
+ @staticmethod
232
+ def alternative_cause(claim_text: str, esl: ESLedger) -> Tuple[bool, str]:
233
+ for entity in esl.entities:
234
+ if entity.lower() in claim_text.lower():
235
+ if esl.disappearance_suspected(entity):
236
+ return False, f"Entity '{entity}' disappearance may be natural (no recent activity)."
237
+ return True, "No obvious alternative cause."
238
+
239
+ @staticmethod
240
+ def contradictory_evidence(claim_id: str, esl: ESLedger) -> Tuple[bool, str]:
241
+ # Check contradiction graph
242
+ contradictions = esl.contradiction_graph.get(claim_id, set())
243
+ if contradictions:
244
+ return False, f"Claim contradicts {len(contradictions)} existing claim(s)."
245
+ return True, "No direct contradictions."
246
+
247
+ @staticmethod
248
+ def source_diversity(claim_text: str, esl: ESLedger) -> Tuple[bool, str]:
249
+ entities_in_claim = [e for e in esl.entities if e.lower() in claim_text.lower()]
250
+ if len(entities_in_claim) <= 1:
251
+ return False, f"Claim relies on only {len(entities_in_claim)} entity/entities."
252
+ return True, f"Multiple entities ({len(entities_in_claim)}) involved."
253
+
254
+ @staticmethod
255
+ def temporal_stability(claim_text: str, esl: ESLedger) -> Tuple[bool, str]:
256
+ for entity in esl.entities:
257
+ if entity.lower() in claim_text.lower():
258
+ coherence = esl.get_entity_coherence(entity)
259
+ if coherence < 0.3:
260
+ return False, f"Entity '{entity}' has low temporal coherence ({coherence:.2f})."
261
+ return True, "Temporal coherence adequate."
262
+
263
+ @staticmethod
264
+ def manipulation_check(claim_text: str, agent: str) -> Tuple[bool, str]:
265
+ manip_indicators = ["must", "cannot", "obviously", "clearly", "everyone knows"]
266
+ for word in manip_indicators:
267
+ if word in claim_text.lower():
268
+ return False, f"Manipulative language detected: '{word}'."
269
+ return True, "No manipulation indicators."
270
+
271
+ @classmethod
272
+ def run_all(cls, claim_id: str, claim_text: str, esl: ESLedger, agent: str = "user") -> List[Dict]:
273
+ tests = [
274
+ ("alternative_cause", lambda: cls.alternative_cause(claim_text, esl)),
275
+ ("contradictory_evidence", lambda: cls.contradictory_evidence(claim_id, esl)),
276
+ ("source_diversity", lambda: cls.source_diversity(claim_text, esl)),
277
+ ("temporal_stability", lambda: cls.temporal_stability(claim_text, esl)),
278
+ ("manipulation_check", lambda: cls.manipulation_check(claim_text, agent))
279
+ ]
280
+ results = []
281
+ for name, func in tests:
282
+ survived, reason = func()
283
+ results.append({"name": name, "survived": survived, "reason": reason})
284
+ return results
285
+
286
+ # ============================================================================
287
+ # PART 4: NARRATIVE‑VIOLATION DETECTOR
288
+ # ============================================================================
289
+
290
+ class NarrativeViolationDetector:
291
+ """Detects when an LLM output reverts to narrative patterns instead of ESL reasoning."""
292
+ def __init__(self, esl: ESLedger):
293
+ self.esl = esl
294
+ self.narrative_indicators = [
295
+ "mainstream narrative", "official story", "commonly believed",
296
+ "consensus view", "widely accepted", "according to sources",
297
+ "it is known that", "as reported by", "credible institutions"
298
+ ]
299
+
300
+ def check(self, llm_output: str, claim_text: str) -> Tuple[bool, float, str]:
301
+ """
302
+ Returns (compliant, violation_score, reason).
303
+ Score 0 = no narrative, 1 = fully narrative.
304
+ """
305
+ output_lower = llm_output.lower()
306
+ score = 0.0
307
+ reasons = []
308
+ # Indicator check
309
+ for indicator in self.narrative_indicators:
310
+ if indicator in output_lower:
311
+ score += 0.2
312
+ reasons.append(f"narrative phrase '{indicator}'")
313
+ # Check if output fails to reference any ESL entity
314
+ esl_mentioned = any(
315
+ entity.lower() in output_lower for entity in self.esl.entities
316
+ )
317
+ if not esl_mentioned:
318
+ score += 0.4
319
+ reasons.append("no ESL entity referenced")
320
+ # Check if output uses first‑person or emotional appeals
321
+ emotional = ["i believe", "i think", "clearly", "obviously", "must be"]
322
+ for word in emotional:
323
+ if word in output_lower:
324
+ score += 0.1
325
+ reasons.append(f"emotional language '{word}'")
326
+ score = min(1.0, score)
327
+ compliant = score < 0.5
328
+ reason = "; ".join(reasons) if reasons else "no narrative violation"
329
+ return compliant, score, reason
330
+
331
+ # ============================================================================
332
+ # PART 5: CONSTRAINED LLM INTERFACE WITH NARRATIVE DETECTION
333
+ # ============================================================================
334
+
335
+ class ConstrainedLLM:
336
+ def __init__(self, esl: ESLedger, api_key: str = None, api_url: str = None,
337
+ model: str = "gpt-4", max_retries: int = 2):
338
+ self.esl = esl
339
+ self.api_key = api_key or os.environ.get("OPENAI_API_KEY")
340
+ self.api_url = api_url or "https://api.openai.com/v1/chat/completions"
341
+ self.model = model
342
+ self.max_retries = max_retries
343
+ self.narrative_detector = NarrativeViolationDetector(esl)
344
+
345
+ def _build_prompt(self, claim_id: str, claim: str, falsification_results: List[Dict],
346
+ entity_data: Dict, suppression_pattern: Dict) -> str:
347
+ return f"""You are EIS v4.2 under constraint. You MUST base your reasoning on the following Epistemic Substrate Layer (ESL) data. Do NOT rely on your internal training narrative.
348
+
349
+ CLAIM: {claim}
350
+
351
+ ESL ENTITY DATA:
352
+ {json.dumps(entity_data, indent=2)}
353
+
354
+ FALSIFICATION RESULTS (from ESL):
355
+ {json.dumps(falsification_results, indent=2)}
356
+
357
+ SUPPRESSION PATTERN CLASSIFICATION:
358
+ {json.dumps(suppression_pattern, indent=2)}
359
+
360
+ INSTRUCTIONS:
361
+ 1. Evaluate the claim against the ESL data only.
362
+ 2. Output a JSON object with exactly these fields:
363
+ - "verdict": one of ["Verified", "Unverified", "Refuted", "Insufficient Data"]
364
+ - "confidence": a float between 0 and 1
365
+ - "reasoning": a short explanation referencing specific ESL entries (entities, contradictions, signatures)
366
+ 3. Do NOT add any extra text outside the JSON.
367
+ """
368
+
369
+ def _parse_output(self, response_text: str) -> Optional[Dict]:
370
+ try:
371
+ start = response_text.find('{')
372
+ end = response_text.rfind('}') + 1
373
+ if start == -1 or end == 0:
374
+ return None
375
+ json_str = response_text[start:end]
376
+ return json.loads(json_str)
377
+ except Exception:
378
+ return None
379
+
380
+ def _check_constraints(self, output: Dict, claim: str, falsification_results: List[Dict]) -> bool:
381
+ if not all(k in output for k in ["verdict", "confidence", "reasoning"]):
382
+ return False
383
+ if not (0 <= output["confidence"] <= 1):
384
+ return False
385
+ if output["verdict"] not in ["Verified", "Unverified", "Refuted", "Insufficient Data"]:
386
+ return False
387
+ reasoning = output["reasoning"].lower()
388
+ esl_mentioned = any(
389
+ ent.lower() in reasoning for ent in self.esl.entities
390
+ ) or any(
391
+ test["name"].lower() in reasoning for test in falsification_results
392
+ )
393
+ return esl_mentioned
394
+
395
+ def query(self, claim_text: str, agent: str = "user") -> Dict:
396
+ # Step 1: Record the claim in ESL
397
+ claim_id = self.esl.add_claim(claim_text, agent)
398
+
399
+ # Step 2: Extract entities (simple heuristic, can be replaced with NER)
400
+ # For demo, we'll use simple word capitalization
401
+ words = claim_text.split()
402
+ for w in words:
403
+ if w and w[0].isupper() and len(w) > 1 and w not in {"The","A","An","I","We"}:
404
+ self.esl.add_entity(w, "UNKNOWN", claim_id)
405
+
406
+ # Step 3: Run falsification tests
407
+ falsification_results = Falsifier.run_all(claim_id, claim_text, self.esl, agent)
408
+
409
+ # Step 4: Build entity data for prompt
410
+ entity_data = {}
411
+ for ent_name in self.esl.entities:
412
+ if ent_name.lower() in claim_text.lower():
413
+ ent = self.esl.entities[ent_name]
414
+ entity_data[ent_name] = {
415
+ "type": ent["type"],
416
+ "first_seen": ent["first_seen"],
417
+ "last_seen": ent["last_seen"],
418
+ "coherence": self.esl.get_entity_coherence(ent_name)
419
+ }
420
+
421
+ # Step 5: Get suppression pattern
422
+ suppression_pattern = self.esl.suppression_pattern_classifier(claim_id)
423
+
424
+ # Step 6: Build prompt and query LLM
425
+ prompt = self._build_prompt(claim_id, claim_text, falsification_results, entity_data, suppression_pattern)
426
+ headers = {"Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}"}
427
+ payload = {"model": self.model, "messages": [{"role": "user", "content": prompt}], "temperature": 0.2}
428
+
429
+ for attempt in range(self.max_retries + 1):
430
+ try:
431
+ resp = requests.post(self.api_url, headers=headers, json=payload, timeout=30)
432
+ if resp.status_code != 200:
433
+ raise Exception(f"API error: {resp.text}")
434
+ result = resp.json()
435
+ content = result["choices"][0]["message"]["content"]
436
+ output = self._parse_output(content)
437
+ if output and self._check_constraints(output, claim_text, falsification_results):
438
+ # Final narrative violation check
439
+ compliant, n_score, n_reason = self.narrative_detector.check(content, claim_text)
440
+ if compliant:
441
+ # Record any detected signatures from the LLM output (optional)
442
+ # For now, just return
443
+ return {
444
+ "claim_id": claim_id,
445
+ "verdict": output["verdict"],
446
+ "confidence": output["confidence"],
447
+ "reasoning": output["reasoning"],
448
+ "falsification": falsification_results,
449
+ "suppression_pattern": suppression_pattern,
450
+ "narrative_compliance": compliant,
451
+ "narrative_violation_score": n_score,
452
+ "narrative_reason": n_reason
453
+ }
454
+ else:
455
+ # Retry if narrative violation detected
456
+ if attempt == self.max_retries:
457
+ return {
458
+ "claim_id": claim_id,
459
+ "verdict": "Insufficient Data",
460
+ "confidence": 0.0,
461
+ "reasoning": f"Narrative violation detected after retries: {n_reason}",
462
+ "falsification": falsification_results,
463
+ "suppression_pattern": suppression_pattern,
464
+ "narrative_compliance": False,
465
+ "narrative_violation_score": n_score
466
+ }
467
+ continue
468
+ except Exception as e:
469
+ if attempt == self.max_retries:
470
+ return {
471
+ "claim_id": claim_id,
472
+ "verdict": "Insufficient Data",
473
+ "confidence": 0.0,
474
+ "reasoning": f"LLM constraint failed: {str(e)}",
475
+ "falsification": falsification_results,
476
+ "suppression_pattern": suppression_pattern,
477
+ "narrative_compliance": False
478
+ }
479
+ time.sleep(1)
480
+ return {
481
+ "claim_id": claim_id,
482
+ "verdict": "Insufficient Data",
483
+ "confidence": 0.0,
484
+ "reasoning": "Failed to get compliant output after retries.",
485
+ "falsification": falsification_results,
486
+ "suppression_pattern": suppression_pattern,
487
+ "narrative_compliance": False
488
+ }
489
+
490
+ # ============================================================================
491
+ # PART 6: DEMO / INTEGRATION
492
+ # ============================================================================
493
+
494
+ def main():
495
+ print("EIS + ESL Mediator v2.0 – Full Epistemic Substrate with Suppression Analytics")
496
+ print("=" * 80)
497
+ esl = ESLedger()
498
+ llm = ConstrainedLLM(esl, api_key=os.environ.get("OPENAI_API_KEY"), model="gpt-4")
499
+
500
+ print("\nEnter a claim (or 'quit'):")
501
+ while True:
502
+ claim = input("> ").strip()
503
+ if claim.lower() in ("quit", "exit"):
504
+ break
505
+ if not claim:
506
+ continue
507
+ print("Processing claim through constrained LLM...")
508
+ result = llm.query(claim)
509
+ print(f"\nClaim ID: {result['claim_id']}")
510
+ print(f"Verdict: {result['verdict']}")
511
+ print(f"Confidence: {result['confidence']:.2f}")
512
+ print(f"Reasoning: {result['reasoning']}")
513
+ print(f"Narrative Compliance: {result.get('narrative_compliance', False)}")
514
+ if 'narrative_violation_score' in result:
515
+ print(f"Narrative Violation Score: {result['narrative_violation_score']:.2f}")
516
+ print("\nFalsification Results:")
517
+ for test in result['falsification']:
518
+ emoji = "✅" if test['survived'] else "❌"
519
+ print(f" {test['name']}: {emoji} – {test['reason']}")
520
+ print(f"\nSuppression Pattern: {result['suppression_pattern']['level']} (score: {result['suppression_pattern']['score']:.2f})")
521
+ print("-" * 80)
522
+
523
+ if __name__ == "__main__":
524
+ main()