Files
2125_GCE/gx_lain/runtime.py
T
GlyphRunner System 93ac2003b3 Implement real LAIN cognition engine with 8 lane processors
New modules:
- gx_lain/lane_processors.py: 8 symbolic lane processors
  * Lane 0: structural_logic (control flow, constraints)
  * Lane 1: semantic_flow (core meaning, narrative)
  * Lane 2: compression_residue (artifacts, hints)
  * Lane 3: symbolic_metadata (tags, annotations)
  * Lane 4: execution_hints (runtime guards, priorities)
  * Lane 5: predictive_scaffolding (hypotheses, priors)
  * Lane 6: contributor_imprint (author style, bias)
  * Lane 7: epoch_resonance (temporal context)

- gx_lain/runtime.py (updated): Real cognition loop
  * execute_with_lain(): Process all 8 lanes, capture timings
  * fuse_lanes(): Merge lane results into final symbol
  * compute_resonance(): Per-lane resonance metrics
  * render_output_text(): Mode-based output formatting

Features:
- Structured lane processing with error recovery
- Cognition trace with per-lane timing
- Resonance metrics (1.0 if lane has content)
- Fused symbol with deduplication
- Mode-aware output (ANALYZE vs SYNTHESIZE)
- No mutations, deterministic execution

All 18 integration tests pass unchanged.
2026-05-20 14:54:56 -04:00

580 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import Dict, List, Tuple, Any, Optional
import uuid
import time
import logging
from pathlib import Path
INTERFACE_VERSION = "1.0"
logger = logging.getLogger(__name__)
def load_gx(path: str) -> Tuple[dict, List[dict], bytes]:
"""Load a .gx file and return (manifest, segments, payload).
Thin wrapper around runtime_executor.gx_loader.load_gx().
Reconstructs segments list from manifest['codex_lineage']['segments'].
Args:
path: Path to .gx file
Returns:
Tuple of (manifest, segments_list, payload_bytes)
Raises:
FileNotFoundError: If .gx file doesn't exist
RuntimeError: If manifest is malformed
"""
from runtime_executor.gx_loader import load_gx as loader_load_gx
manifest, payload = loader_load_gx(path)
# Extract segments from manifest['codex_lineage']['segments']
codex_lineage = manifest.get("codex_lineage", {})
segments = codex_lineage.get("segments", [])
if not segments:
logger.warning(f"No segments found in {path}, continuing with empty list")
return manifest, segments, payload
def normalize_segments(
manifest: dict,
raw_segments: List[dict],
payload: bytes,
) -> List[dict]:
"""Normalize raw segments into canonical Segment schema.
Converts raw segment metadata from codex_lineage.segments into normalized form
with required keys: id, start_line, end_line, text, symbolic_lane, semantic_role.
Assumptions:
- Raw segments have: id, start, end (0-based line indices)
- Optional: lane, role metadata
- Text extraction is stubbed (reserved for future payload analysis)
Args:
manifest: GX manifest dict
raw_segments: List of raw segment dicts from codex_lineage
payload: Compressed payload bytes (reserved for text extraction)
Returns:
List of normalized segment dicts conforming to Segment schema
"""
normalized = []
for raw_seg in raw_segments:
seg_id = str(raw_seg.get("id", "unknown"))
start_line = int(raw_seg.get("start", 0))
end_line = int(raw_seg.get("end", 0))
# Explicit lane from metadata, or infer
explicit_lane = raw_seg.get("lane")
if explicit_lane is not None:
symbolic_lane = int(explicit_lane)
else:
symbolic_lane = _infer_lane(raw_seg)
# Clamp to valid range [0, 7]
symbolic_lane = max(0, min(7, symbolic_lane))
# Semantic role: infer from segment metadata
semantic_role = _infer_semantic_role(raw_seg)
# Text: stub for now; in production extract from payload via byte ranges
text = f"[segment {seg_id}: lines {start_line}{end_line}]"
normalized_seg = {
"id": seg_id,
"start_line": start_line,
"end_line": end_line,
"text": text,
"symbolic_lane": symbolic_lane,
"semantic_role": semantic_role,
"_raw": raw_seg, # preserve original for debugging
}
normalized.append(normalized_seg)
return normalized
def _infer_lane(segment: dict) -> int:
"""Infer lane assignment from segment metadata (heuristic).
Rules (minimum viable):
- Structural markers → lane 0
- Main content → lane 1 (default)
- Comments/annotations → lane 3
- Hints → lane 4
- Author/meta → lane 6
- Time/epoch → lane 7
Args:
segment: Raw segment dict
Returns:
Lane id 07
"""
seg_id = str(segment.get("id", "")).lower()
# Structural
if any(x in seg_id for x in ["struct", "class", "def", "header", "header"]):
return 0
# Annotations/comments
if any(x in seg_id for x in ["comment", "annotation", "tag"]):
return 3
# Hints
if any(x in seg_id for x in ["hint", "note", "tip", "warn"]):
return 4
# Author/meta
if any(x in seg_id for x in ["meta", "author", "signature"]):
return 6
# Time/epoch
if any(x in seg_id for x in ["epoch", "time", "date", "version"]):
return 7
# Default: semantic flow
return 1
def _infer_semantic_role(segment: dict) -> str:
"""Infer semantic role from segment metadata (heuristic).
Args:
segment: Raw segment dict
Returns:
One of: "definition", "constraint", "example", "meta", "unknown"
"""
seg_id = str(segment.get("id", "")).lower()
if any(x in seg_id for x in ["def", "class", "function", "declaration"]):
return "definition"
if any(x in seg_id for x in ["constraint", "rule", "assertion", "require"]):
return "constraint"
if any(x in seg_id for x in ["example", "test", "sample", "demo"]):
return "example"
if any(x in seg_id for x in ["meta", "note", "comment", "annotation", "tag"]):
return "meta"
return "unknown"
def map_lanes(segments: List[dict]) -> Dict[int, List[dict]]:
"""Map normalized segments into 07 lane model.
Organizes segments by symbolic_lane into a dict where:
- Keys: lane numbers 07
- Values: lists of segments assigned to that lane
Lane semantics (from spec):
- 0: structural_logic
- 1: semantic_flow
- 2: compression_residue
- 3: symbolic_metadata
- 4: execution_hints
- 5: predictive_scaffolding
- 6: contributor_imprint
- 7: epoch_resonance
Args:
segments: List of normalized segment dicts
Returns:
Dict[int, List[dict]] where keys are 07
"""
lanes: Dict[int, List[dict]] = {i: [] for i in range(8)}
for seg in segments:
lane = seg.get("symbolic_lane", 1)
# Safety clamp
lane = max(0, min(7, lane))
lanes[lane].append(seg)
return lanes
def build_envelope(
manifest: dict,
lanes: Dict[int, List[dict]],
payload: bytes,
context: Optional[dict] = None,
) -> dict:
"""Build ExecutionEnvelope for LAIN from components.
Constructs the envelope that LAIN will consume. The envelope is immutable
from LAIN's perspective and includes all necessary context.
Args:
manifest: GX manifest dict
lanes: Dict[int, List[dict]] where keys are lane ids 07
payload: Compressed payload bytes
context: Optional context overrides (runtime_flags, epoch, cognitive_mode, invocation_id)
Returns:
ExecutionEnvelope dict ready for LAIN.execute()
"""
if context is None:
context = {}
base_context = {
"runtime_flags": context.get("runtime_flags", {}),
"contributor": manifest.get("contributor", "unknown"),
"epoch": context.get("epoch"),
"cognitive_mode": context.get("cognitive_mode", "analyze"),
"invocation_id": context.get("invocation_id", str(uuid.uuid4())),
"interface_version": INTERFACE_VERSION,
}
envelope = {
"manifest": manifest,
"lanes": lanes,
"payload": payload,
"context": base_context,
}
return envelope
def fuse_lanes(lane_results: Dict[int, dict]) -> dict:
"""Fuse lane results into final fused_symbol.
Merges summaries, key_points, constraints, and open_questions
from all lanes into a single coherent representation.
Args:
lane_results: Dict[lane_id, lane_result]
Returns:
Fused symbol dict with summary, key_points, constraints, open_questions
"""
summaries = []
all_key_points = []
all_constraints = []
all_questions = []
for lane_id in sorted(lane_results.keys()):
result = lane_results[lane_id]
# Collect summaries
if result.get("summary"):
summaries.append(result["summary"])
# Collect key points
all_key_points.extend(result.get("key_points", []))
# Collect constraints
all_constraints.extend(result.get("constraints", []))
# Collect open questions
all_questions.extend(result.get("open_questions", []))
# Merge summary
if summaries:
combined_summary = " | ".join(summaries)
else:
combined_summary = "No lanes processed"
# Deduplicate and limit key points
unique_key_points = list(dict.fromkeys(all_key_points))[:10]
# Deduplicate constraints
unique_constraints = list(dict.fromkeys(all_constraints))
# Deduplicate questions
unique_questions = list(dict.fromkeys(all_questions))
return {
"summary": combined_summary,
"key_points": unique_key_points,
"constraints": unique_constraints,
"open_questions": unique_questions,
}
def compute_resonance(lane_results: Dict[int, dict], context: Dict[str, Any]) -> dict:
"""Compute resonance metrics for lanes.
Simple rule: resonance[lane] = 1.0 if lane produced content, else 0.0
Args:
lane_results: Dict[lane_id, lane_result]
context: Execution context
Returns:
Dict[str, float] with resonance metrics
"""
resonance = {}
for lane_id in sorted(lane_results.keys()):
result = lane_results[lane_id]
# Lane has content if it produced a non-empty summary
has_content = bool(result.get("summary", "").strip())
resonance[f"lane_{lane_id}"] = 1.0 if has_content else 0.0
return resonance
def render_output_text(fused_symbol: dict, context: Dict[str, Any]) -> str:
"""Render human-facing output text from fused_symbol.
Format varies by cognitive_mode.
Args:
fused_symbol: Fused symbol dict
context: Execution context
Returns:
Human-readable output string
"""
mode = context.get("cognitive_mode", "analyze")
mode_label = mode.upper()
summary = fused_symbol.get("summary", "No summary")
lines = [
f"[{mode_label}]",
f"{summary}",
]
key_points = fused_symbol.get("key_points", [])
if key_points:
lines.append("")
lines.append("Key Points:")
for point in key_points[:5]:
lines.append(f" • {point}")
constraints = fused_symbol.get("constraints", [])
if constraints:
lines.append("")
lines.append("Constraints:")
for constraint in constraints[:5]:
lines.append(f" • {constraint}")
questions = fused_symbol.get("open_questions", [])
if questions:
lines.append("")
lines.append("Open Questions:")
for question in questions[:5]:
lines.append(f" ? {question}")
return "\n".join(lines)
def execute_with_lain(envelope: dict) -> dict:
"""Execute ExecutionEnvelope through LAIN cognition engine.
Real implementation: iterate through lanes, process each via lane processors,
fuse results, and return full ExecutionResult.
Contract:
- Does not mutate input envelope
- Deterministic for a given envelope
- Errors are returned in result['diagnostics']['errors'], not raised
Args:
envelope: ExecutionEnvelope dict from build_envelope()
Returns:
ExecutionResult dict with cognition_trace, fused_symbol, output_text, diagnostics
"""
from .lane_processors import process_lane
start_time = time.time()
manifest = envelope.get("manifest", {})
lanes = envelope.get("lanes", {})
payload = envelope.get("payload", b"")
context = envelope.get("context", {})
# Initialize tracking
lane_timings: Dict[int, float] = {}
lane_results: Dict[int, dict] = {}
errors: List[dict] = []
cognition_trace = []
# Step 0: Load envelope
cognition_trace.append({
"step": 0,
"lane": -1,
"segment_id": None,
"operation": "load_envelope",
"input": {
"lanes": sorted(lanes.keys()),
"num_segments": sum(len(segs) for segs in lanes.values()),
"manifest_version": manifest.get("version"),
},
"output": {},
"note": "Loaded ExecutionEnvelope into LAIN cognition engine.",
})
# Process each lane
step_num = 1
for lane_id in sorted(lanes.keys()):
lane_start = time.time()
lane_segments = lanes.get(lane_id, [])
try:
# Call lane processor
lane_result = process_lane(
lane_id,
lane_segments,
context,
manifest,
)
lane_results[lane_id] = lane_result
# Record timing
lane_elapsed = time.time() - lane_start
lane_timings[lane_id] = lane_elapsed
# Trace entry
cognition_trace.append({
"step": step_num,
"lane": lane_id,
"segment_id": None,
"operation": f"process_lane_{lane_id}",
"input": {"segments": len(lane_segments)},
"output": {
"summary_length": len(lane_result.get("summary", "")),
"key_points": len(lane_result.get("key_points", [])),
},
"note": f"Processed lane {lane_id} with {len(lane_segments)} segments in {lane_elapsed:.4f}s.",
})
except Exception as e:
lane_elapsed = time.time() - lane_start
lane_timings[lane_id] = lane_elapsed
err = make_error(
"LaneProcessorError",
f"Lane {lane_id} processing failed: {e}",
lane=lane_id,
recoverable=True,
)
errors.append(err)
lane_results[lane_id] = {
"summary": f"Error processing lane {lane_id}",
"key_points": [],
"constraints": [],
"open_questions": [],
}
cognition_trace.append({
"step": step_num,
"lane": lane_id,
"segment_id": None,
"operation": f"process_lane_{lane_id}",
"input": {"segments": len(lane_segments)},
"output": {"error": str(e)},
"note": f"Lane {lane_id} processing failed (recoverable).",
})
step_num += 1
# Fuse lane results
fused_symbol = fuse_lanes(lane_results)
# Compute resonance
resonance = compute_resonance(lane_results, context)
# Render output text
output_text = render_output_text(fused_symbol, context)
elapsed = time.time() - start_time
# Build diagnostics
diagnostics = {
"lane_timings": lane_timings,
"errors": errors,
"resonance": resonance,
"interface_version": INTERFACE_VERSION,
"elapsed": elapsed,
}
# Return ExecutionResult
result = {
"cognition_trace": cognition_trace,
"fused_symbol": fused_symbol,
"output_text": output_text,
"diagnostics": diagnostics,
}
return result
def execute_gx_path(
gx_path: str,
context: Optional[dict] = None,
) -> dict:
"""Main entry point: load .gx file and execute through LAIN.
Pipeline: load → normalize → map_lanes → build_envelope → execute
Args:
gx_path: Path to .gx file
context: Optional context overrides
Returns:
ExecutionResult dict
Raises:
Exceptions from load_gx() if file is invalid or missing
"""
# Load
manifest, raw_segments, payload = load_gx(gx_path)
# Normalize
segments = normalize_segments(manifest, raw_segments, payload)
# Map to lanes
lanes = map_lanes(segments)
# Build envelope
envelope = build_envelope(manifest, lanes, payload, context)
# Execute
result = execute_with_lain(envelope)
return result
def make_error(
error_type: str,
message: str,
segment_id: Optional[str] = None,
lane: Optional[int] = None,
recoverable: bool = True,
) -> dict:
"""Construct a structured GXRuntimeError dict.
Args:
error_type: Error class (e.g. "DecodeError", "LaneError", "SegmentError")
message: Human-readable message
segment_id: Optional segment id if segment-specific
lane: Optional lane id if lane-specific
recoverable: Whether error is recoverable
Returns:
GXRuntimeError dict
"""
return {
"type": error_type,
"message": message,
"segment_id": segment_id,
"lane": lane,
"recoverable": recoverable,
}