“””

THE KEY EMERGES — key_renderer.py

 

Main renderer engine.

 

Consumes RendererSnapshot objects. Produces visual frames.

One snapshot -> one render update. No more. No less.

 

GOVERNING CONSTRAINT:

The renderer must reveal the computation, not replace it with a story.

 

WHAT THIS FILE DOES:

 

- Builds and maintains a fixed panel layout

- Dispatches each snapshot to the correct stage renderer

- Updates the evidence panel from accumulated history

- Requests text from key_stage_text_runtime (never writes its own)

- Redraws exactly once per snapshot

 

WHAT THIS FILE NEVER DOES:

 

- Infer missing state

- Smooth transitions between snapshots

- Add synthetic frames

- Predict future stages

- Bias attention toward success

- Pre-signal failure

- Show the world before WORLD_EVALUATION

- Render the accidental candidate differently from GIE candidate

- Write any text string directly

 

CHANGES FROM v1 (six warranted revisions):

 

Change 1 — Hard-veto visibility:

Veto count annotation retained for now with explicit comment flagging

the architectural gap. Per-generation veto geometry is not yet in

RendererSnapshot. Long-term fix documented in _render_main_search_distribution.

 

Change 2 — Promotion renders one structure at a time:

Comparison card removed. Promotion is a stage event, not a summary.

Only the most recently promoted structure is shown.

 

Change 3 — World geometry not reconstructed from defaults:

If world_view lacks geometry, renderer logs and renders nothing extra.

No implicit inference. Applies to both world evaluation and contrast stages.

 

Change 4 — Identical candidate styling enforced by code:

CANDIDATE_STYLE constant used for both GIE and accidental candidates.

Palette cannot diverge accidentally. Visual equality is structural.

 

Change 5 — Axis titles controlled by debug_labels flag:

debug_labels=False (default) = no axis titles = public demo mode.

debug_labels=True = titles visible = development mode.

Titles are not part of the sanctioned text layer.

 

Change 6 — Evidence panel shows promotion threshold:

Factual reference line added when threshold is known.

Not interpretation. Helps viewer see why candidates are in surviving band.

“””

 

from **future** import annotations

import numpy as np

import matplotlib

matplotlib.use(“Agg”)

import matplotlib.pyplot as plt

import matplotlib.gridspec as gridspec

from typing import Any, Dict, List, Optional

 

from core_types import RendererSnapshot, StageLabel

from key_snapshot_adapters import (

Colors, EvidenceHistory,

extract_signal_views, extract_candidate_distribution,

extract_promoted_views, extract_composition_views,

extract_world_view, extract_contrast_view,

build_polar_profile_geometry, stage_display_label,

)

from key_stage_text_runtime import (

StageTextState, stage_text_for_snapshot

)

 

# —————————————————————————

 

# Change 4: Single candidate style enforced by code, not convention.

 

# Both GIE candidate and accidental candidate use exactly this constant.

 

# A future developer cannot assign different colors by modifying the palette

 

# because both calls reference this constant, not Colors.* directly.

 

# —————————————————————————

 

CANDIDATE_STYLE = {

“color”:     Colors.ACTIVE_CANDIDATE,

“linewidth”: 1.6,

“alpha”:     0.9,

“zorder”:    3,

}

 

# —————————————————————————

 

# Renderer

 

# —————————————————————————

 

class KeyRenderer:

“””

Main renderer. Consumes RendererSnapshot objects, emits visual frames.

 

```

Parameters

----------

figsize      : matplotlib figure size

dpi          : resolution

debug_labels : Change 5. True = show axis titles (development mode).

               False = no axis titles (public demo mode).

               Axis titles are not part of the sanctioned text layer.

"""

 

def __init__(self, figsize=(14, 9), dpi=100, debug_labels=False):

    self.figsize      = figsize

    self.dpi          = dpi

    self.debug_labels = debug_labels

 

    self.fig         = None

    self.ax_main     = None

    self.ax_evidence = None

    self.ax_meta     = None

    self.ax_text     = None

 

    self.evidence   = EvidenceHistory()

    self.text_state = StageTextState()

 

    self.last_snapshot: Optional[RendererSnapshot] = None

    self.frame_count   = 0

 

    # Change 6: track threshold for evidence panel reference line

    self._current_threshold: Optional[float] = None

 

def build_layout(self):

    self.fig = plt.figure(

        figsize=self.figsize, dpi=self.dpi,

        facecolor=Colors.BACKGROUND

    )

 

    gs = gridspec.GridSpec(

        3, 3, figure=self.fig,

        height_ratios=[7, 2, 1],

        width_ratios=[4, 1, 2],

        hspace=0.08, wspace=0.12,

        left=0.04, right=0.97, top=0.96, bottom=0.04

    )

 

    self.ax_main     = self.fig.add_subplot(gs[0:2, 0:2])

    self.ax_evidence = self.fig.add_subplot(gs[0,   2])

    self.ax_meta     = self.fig.add_subplot(gs[1,   2])

    self.ax_text     = self.fig.add_subplot(gs[2,   :])

 

    for ax in [self.ax_main, self.ax_evidence, self.ax_meta, self.ax_text]:

        ax.set_facecolor(Colors.BACKGROUND)

        for spine in ax.spines.values():

            spine.set_color("#333333")

 

    self.ax_text.set_xticks([])

    self.ax_text.set_yticks([])

    self.ax_meta.set_xticks([])

    self.ax_meta.set_yticks([])

 

    self.fig.suptitle(

        "THE KEY EMERGES",

        color=Colors.TEXT_OVERLAY, fontsize=11,

        fontfamily="monospace", x=0.04, y=0.99, ha="left"

    )

 

def consume_snapshot(self, snapshot: RendererSnapshot):

    """One snapshot -> one render update."""

    if self.fig is None:

        self.build_layout()

 

    self.evidence.update(snapshot)

    text = stage_text_for_snapshot(snapshot, self.text_state)

 

    for ax in [self.ax_main, self.ax_evidence, self.ax_meta, self.ax_text]:

        ax.cla()

        ax.set_facecolor(Colors.BACKGROUND)

 

    self._render_snapshot(snapshot)

    self._render_evidence_panel(snapshot)

    self._render_text_overlay(text)

 

    self.last_snapshot = snapshot

    self.frame_count  += 1

 

def _render_snapshot(self, snapshot: RendererSnapshot):

    stage = snapshot.stage

 

    if stage == StageLabel.SIGNAL_GENERATION:

        self._render_main_signal_generation(snapshot)

 

    elif stage in (StageLabel.LENS_SEARCH, StageLabel.SURVIVAL_EVALUATION):

        self._render_main_search_distribution(snapshot)

 

    elif stage == StageLabel.PROMOTION:

        self._render_main_promotion(snapshot)

 

    elif stage == StageLabel.COMPOSITION_SEARCH:

        # Same method reused — same visual language as lens search.

        # Reuse is the architectural claim made visible.

        self._render_main_search_distribution(snapshot)

 

    elif stage in (StageLabel.WORLD_EVALUATION, StageLabel.STATE_TRANSITION):

        self._render_main_world(snapshot)

 

    elif stage == StageLabel.CONTRAST_EVALUATION:

        self._render_main_contrast(snapshot)

 

    else:

        self._render_main_placeholder(snapshot)

 

# -----------------------------------------------------------------------

# Signal generation

# -----------------------------------------------------------------------

 

def _render_main_signal_generation(self, snapshot: RendererSnapshot):

    """Raw point clouds only. No connecting lines. Noise visible."""

    data = extract_signal_views(snapshot)

    ax   = self.ax_main

 

    plotted = False

    if data["arm1_points"] is not None:

        pts = data["arm1_points"]

        ax.scatter(pts[:, 0], pts[:, 1],

                   s=4, color=Colors.ACTIVE_CANDIDATE,

                   alpha=0.6, linewidths=0)

        plotted = True

 

    if data["arm2_points"] is not None:

        pts = data["arm2_points"]

        ax.scatter(pts[:, 0] + 2.5, pts[:, 1],

                   s=4, color=Colors.ACTIVE_CANDIDATE,

                   alpha=0.6, linewidths=0)

        plotted = True

 

    if not plotted:

        ax.text(0.5, 0.5, "Awaiting signals...",

                transform=ax.transAxes, ha="center", va="center",

                color=Colors.TEXT_OVERLAY, fontsize=10,

                fontfamily="monospace")

 

    _style_main_ax(ax, "Signal generation — raw exposures", self.debug_labels)

 

# -----------------------------------------------------------------------

# Search distribution (REUSED for lens search and composition search)

# -----------------------------------------------------------------------

 

def _render_main_search_distribution(self, snapshot: RendererSnapshot):

    """

    Population distribution for all search stages.

 

    Called identically for LENS_SEARCH and COMPOSITION_SEARCH.

    Same visual language for both. This sameness is the architectural

    reuse claim made visible without annotation.

 

    CHANGE 1 — hard-veto visibility note:

    Hard veto is shown only as a count annotation in the veto color.

    This is honest but weaker than showing individual eliminations.

    The gap: RendererSnapshot carries only a count, not per-candidate

    veto geometry. Long-term fix: add a veto_events field to

    RendererSnapshot with eliminated candidate scores, allowing

    individual red marks at the veto boundary rather than a counter.

    Until then, the count is shown in Colors.HARD_VETO to preserve

    the visual distinction requirement from KEY visual grammar Section 3.

    The two failure types (hard veto, non-surviving) remain distinguishable:

    hard veto = red counter, no distribution member.

    non-surviving = gray distribution member with visible score.

    """

    ax = self.ax_main

 

    if snapshot.stage == StageLabel.COMPOSITION_SEARCH:

        data      = extract_composition_views(snapshot)

        substrate = data.get("substrate_label", "composed structures")

    else:

        data      = extract_candidate_distribution(snapshot)

        substrate = "signal points"

 

    all_scores    = data["admissible_scores"]

    non_surviving = data["non_surviving_scores"]

    surviving     = data["surviving_scores"]

    veto_count    = data["veto_count"]

    threshold     = data["threshold_display"]

    gen           = data["generation"]

 

    # Change 6: track threshold for evidence panel

    if threshold > 0:

        self._current_threshold = threshold

 

    if all_scores:

        rng_d = np.random.default_rng(gen)

 

        if non_surviving:

            ns = np.array(non_surviving)

            ax.scatter(

                rng_d.uniform(0.1, 0.9, len(ns)), ns,

                s=12, color=Colors.NON_SURVIVING,

                alpha=0.5, linewidths=0, zorder=2

            )

 

        if surviving:

            sv = np.array(surviving)

            ax.scatter(

                np.random.default_rng(gen + 1000).uniform(0.1, 0.9, len(sv)), sv,

                s=16, color=Colors.SURVIVING,

                alpha=0.75, linewidths=0, zorder=3

            )

 

        if threshold > 0:

            ax.axhline(y=threshold, color="#444444",

                       linewidth=0.8, linestyle="--",

                       alpha=0.6, zorder=1)

 

    # Change 1: veto count in veto color — see comment above

    if veto_count > 0:

        ax.text(0.02, 0.04,

                f"{veto_count} hard-vetoed (world constraint)",

                transform=ax.transAxes,

                color=Colors.HARD_VETO, fontsize=8,

                fontfamily="monospace", va="bottom", zorder=5)

 

    if snapshot.promoted_views:

        ax.text(0.5, 0.5, "Structure promoted.",

                transform=ax.transAxes, ha="center", va="center",

                color=Colors.PROMOTED, fontsize=14,

                fontfamily="monospace", zorder=6)

 

    ax.set_xlim(0, 1)

    ax.set_ylim(-0.05, 1.05)

    ax.set_xticks([])

    ax.set_ylabel("Invariance score", color=Colors.TEXT_OVERLAY,

                  fontsize=8, fontfamily="monospace")

    ax.tick_params(colors=Colors.TEXT_OVERLAY, labelsize=7)

 

    # Change 5: title only in debug mode

    title = f"Search — {substrate} — gen {gen}" if self.debug_labels else ""

    _style_main_ax(ax, title, self.debug_labels)

 

# -----------------------------------------------------------------------

# Promotion — one structure, one stage event

# -----------------------------------------------------------------------

 

def _render_main_promotion(self, snapshot: RendererSnapshot):

    """

    Population clears. Single promoted structure appears. Discrete.

 

    CHANGE 2: one structure at a time. Only the most recently promoted

    structure is shown. Promotion is a stage event, not a comparison card.

    Showing both simultaneously would misrepresent the sequential nature

    of the two promotion events and imply a comparison that is not

    present in the computation at this moment.

    """

    ax       = self.ax_main

    promoted = extract_promoted_views(snapshot)

 

    if not promoted:

        _style_main_ax(ax, "Promotion" if self.debug_labels else "",

                       self.debug_labels)

        return

 

    # Change 2: most recent structure only

    pv   = promoted[-1]

    geom = pv.get("geometry")

 

    if geom is not None:

        ax.plot(geom[:, 0], geom[:, 1],

                color=Colors.PROMOTED, linewidth=1.8,

                alpha=0.9, zorder=3)

        ax.fill(geom[:, 0], geom[:, 1],

                color=Colors.PROMOTED, alpha=0.08, zorder=2)

 

    if self.debug_labels:

        arm   = pv.get("arm", "")

        score = pv.get("score", 0.0)

        ax.text(0.02, 0.04, f"{arm}  score={score:.3f}",

                transform=ax.transAxes, color=Colors.PROMOTED,

                fontsize=8, fontfamily="monospace", va="bottom")

 

    ax.set_aspect("equal", adjustable="datalim")

    _style_main_ax(ax, "Promoted structure" if self.debug_labels else "",

                   self.debug_labels)

 

# -----------------------------------------------------------------------

# World evaluation

# -----------------------------------------------------------------------

 

def _render_main_world(self, snapshot: RendererSnapshot):

    """

    World appears here for the first time. No preview before this stage.

 

    CHANGE 3: world geometry must come from world_view in the snapshot.

    If absent, log and render nothing extra. No reconstruction from

    defaults. Reconstruction, even from canonical defaults, would be

    renderer-side inference — the snapshot did not authorize it.

    """

    ax = self.ax_main

    wv = extract_world_view(snapshot)

 

    if wv is None:

        ax.text(0.5, 0.5, "State transition.",

                transform=ax.transAxes, ha="center", va="center",

                color=Colors.TEXT_OVERLAY, fontsize=14,

                fontfamily="monospace")

        _style_main_ax(ax, "", self.debug_labels)

        return

 

    # Change 3: use snapshot geometry only

    wg = wv.get("world_geometry")

    if wg is None:

        print("  [renderer] world_view missing world_geometry — "

              "omitting world display. Check snapshot population.")

    else:

        ax.plot(wg[:, 0], wg[:, 1],

                color=Colors.WORLD_GEOMETRY, linewidth=2.0,

                alpha=0.85, zorder=2)

 

    cg = wv.get("candidate_geometry")

    if cg is not None:

        ax.plot(cg[:, 0], cg[:, 1],

                color=Colors.PROMOTED, linewidth=1.6,

                alpha=0.9, zorder=3)

        ax.fill(cg[:, 0], cg[:, 1],

                color=Colors.PROMOTED, alpha=0.06, zorder=1)

 

    success    = wv.get("success", False)

    can_insert = wv.get("can_insert", False)

    can_rotate = wv.get("can_rotate", False)

    fail_mode  = wv.get("failure_mode", "")

 

    if success:

        result_text  = "A  B  C  — constraints satisfied"

        result_color = Colors.SURVIVING

    elif can_rotate:

        result_text  = f"A  B  —  C: {fail_mode}"

        result_color = Colors.NON_SURVIVING

    elif can_insert:

        result_text  = f"A  —  B: {fail_mode}"

        result_color = Colors.NON_SURVIVING

    else:

        result_text  = f"A: {fail_mode}"

        result_color = Colors.HARD_VETO

 

    ax.text(0.5, 0.04, result_text,

            transform=ax.transAxes, ha="center", va="bottom",

            color=result_color, fontsize=9, fontfamily="monospace")

 

    ax.set_aspect("equal", adjustable="datalim")

    _style_main_ax(ax, "World evaluation" if self.debug_labels else "",

                   self.debug_labels)

 

# -----------------------------------------------------------------------

# Contrast branch

# -----------------------------------------------------------------------

 

def _render_main_contrast(self, snapshot: RendererSnapshot):

    ax = self.ax_main

    cv = extract_contrast_view(snapshot)

 

    if cv is None:

        _style_main_ax(ax, "Contrast" if self.debug_labels else "",

                       self.debug_labels)

        return

 

    pert_gie = cv.get("pert_gie_result")

    pert_acc = cv.get("pert_acc_result")

 

    if pert_gie is not None and pert_acc is not None:

        self._render_perturbation_test(ax, cv)

    else:

        self._render_contrast_single(ax, cv)

 

def _render_contrast_single(self, ax, cv: Dict):

    """

    Single contrast candidate.

 

    CHANGE 3: world geometry from snapshot only. No reconstruction.

    CHANGE 4: accidental candidate uses CANDIDATE_STYLE — identical

    to GIE. Failure comes only from the world's response.

    """

    wg = cv.get("world_geometry")

    if wg is None:

        print("  [renderer] contrast_view missing world_geometry — omitting.")

    else:

        ax.plot(wg[:, 0], wg[:, 1],

                color=Colors.WORLD_GEOMETRY, linewidth=2.0,

                alpha=0.85, zorder=2)

 

    ag = cv.get("accidental_geometry")

    if ag is not None:

        # Change 4: CANDIDATE_STYLE — identical to GIE candidate

        ax.plot(ag[:, 0], ag[:, 1],

                color=CANDIDATE_STYLE["color"],

                linewidth=CANDIDATE_STYLE["linewidth"],

                alpha=CANDIDATE_STYLE["alpha"],

                zorder=CANDIDATE_STYLE["zorder"])

 

    acc_result = cv.get("accidental_result", {})

    if acc_result:

        success = acc_result.get("success", False)

        fail    = acc_result.get("failure_mode", "")

        if success:

            label, lcolor = "Passed original world.", Colors.SURVIVING

        else:

            label, lcolor = f"Failed: {fail}", Colors.HARD_VETO

        ax.text(0.5, 0.04, label,

                transform=ax.transAxes, ha="center", va="bottom",

                color=lcolor, fontsize=9, fontfamily="monospace")

 

    ax.set_aspect("equal", adjustable="datalim")

    _style_main_ax(ax, "Contrast evaluation" if self.debug_labels else "",

                   self.debug_labels)

 

def _render_perturbation_test(self, ax, cv: Dict):

    """

    Side-by-side perturbation test.

 

    CHANGE 3: world geometry from snapshot only. No reconstruction.

    CHANGE 4: both candidates use CANDIDATE_STYLE. Identical by code.

    The only permitted visible difference is the world's response.

    """

    delta_phi = cv.get("delta_phi", -0.20)

    offset    = 3.0

 

    # Change 3: world geometry from snapshot only

    wg_left  = cv.get("pert_world_geometry_left")

    wg_right = cv.get("pert_world_geometry_right")

 

    if wg_left is None or wg_right is None:

        print("  [renderer] perturbation world geometry missing — omitting.")

 

    # Left: GIE candidate

    if wg_left is not None:

        ax.plot(wg_left[:, 0], wg_left[:, 1],

                color=Colors.WORLD_GEOMETRY, linewidth=1.8,

                alpha=0.8, zorder=2)

 

    gie_geom = cv.get("gie_geometry")

    if gie_geom is not None:

        # Change 4: CANDIDATE_STYLE for GIE

        ax.plot(gie_geom[:, 0], gie_geom[:, 1],

                color=CANDIDATE_STYLE["color"],

                linewidth=CANDIDATE_STYLE["linewidth"],

                alpha=CANDIDATE_STYLE["alpha"],

                zorder=CANDIDATE_STYLE["zorder"])

 

    pert_gie  = cv.get("pert_gie_result", {})

    gie_held  = pert_gie.get("success", False)

    gie_color = Colors.SURVIVING if gie_held else Colors.HARD_VETO

    ax.text(-offset * 0.3, -1.7, "GIE",

            ha="center", color=gie_color,

            fontsize=9, fontfamily="monospace")

    ax.text(-offset * 0.3, -1.95,

            "held" if gie_held else pert_gie.get("failure_mode", "failed"),

            ha="center", color=gie_color, fontsize=8,

            fontfamily="monospace")

 

    # Right: accidental candidate

    if wg_right is not None:

        ax.plot(wg_right[:, 0] + offset, wg_right[:, 1],

                color=Colors.WORLD_GEOMETRY, linewidth=1.8,

                alpha=0.8, zorder=2)

 

    acc_geom = cv.get("accidental_geometry")

    if acc_geom is not None:

        # Change 4: identical CANDIDATE_STYLE — enforced by code

        ax.plot(acc_geom[:, 0] + offset, acc_geom[:, 1],

                color=CANDIDATE_STYLE["color"],

                linewidth=CANDIDATE_STYLE["linewidth"],

                alpha=CANDIDATE_STYLE["alpha"],

                zorder=CANDIDATE_STYLE["zorder"])

 

    pert_acc  = cv.get("pert_acc_result", {})

    acc_held  = pert_acc.get("success", False)

    acc_color = Colors.SURVIVING if acc_held else Colors.HARD_VETO

    ax.text(offset * 0.7, -1.7, "Accidental",

            ha="center", color=acc_color,

            fontsize=9, fontfamily="monospace")

    ax.text(offset * 0.7, -1.95,

            "held" if acc_held else pert_acc.get("failure_mode", "failed"),

            ha="center", color=acc_color, fontsize=8,

            fontfamily="monospace")

 

    ax.axvline(x=offset * 0.5, color="#333333",

               linewidth=0.8, linestyle="--", alpha=0.5)

 

    ax.text(0.5, 0.97,

            f"World shifted: phi_lock + {delta_phi:.2f} rad",

            transform=ax.transAxes, ha="center", va="top",

            color=Colors.TEXT_OVERLAY, fontsize=8,

            fontfamily="monospace")

 

    ax.set_aspect("equal", adjustable="datalim")

    _style_main_ax(ax, "Perturbation test" if self.debug_labels else "",

                   self.debug_labels)

 

# -----------------------------------------------------------------------

# Placeholder

# -----------------------------------------------------------------------

 

def _render_main_placeholder(self, snapshot: RendererSnapshot):

    ax = self.ax_main

    if self.debug_labels:

        ax.text(0.5, 0.5, f"Stage: {snapshot.stage.name}",

                transform=ax.transAxes, ha="center", va="center",

                color=Colors.TEXT_OVERLAY, fontsize=9,

                fontfamily="monospace")

    _style_main_ax(ax, "", self.debug_labels)

 

# -----------------------------------------------------------------------

# Evidence panel

# -----------------------------------------------------------------------

 

def _render_evidence_panel(self, snapshot: RendererSnapshot):

    """

    Secondary evidence panel. Always visible.

    Proof that the main panel is honest.

 

    CHANGE 6: promotion threshold shown as factual reference line.

    Not interpretation. Gives viewer context for the surviving band.

    """

    ax = self.ax_evidence

    ev = self.evidence.as_arrays()

 

    gens       = ev["generations"]

    scores     = ev["best_scores"]

    vetos      = ev["veto_counts"]

    promo_gens = ev["promotion_gens"]

 

    if len(gens) == 0:

        return

 

    ax.plot(gens, scores,

            color=Colors.EVIDENCE_LINE, linewidth=1.0,

            alpha=0.85, zorder=3)

 

    if vetos.max() > 0:

        veto_scaled = vetos / vetos.max() * 0.25

        ax.fill_between(gens, 0, veto_scaled,

                        color=Colors.EVIDENCE_VETO,

                        alpha=0.25, zorder=1)

 

    for pg in promo_gens:

        ax.axvline(x=pg, color=Colors.PROMOTION_MARKER,

                   linewidth=0.8, alpha=0.7, linestyle=":",

                   zorder=4)

 

    # Change 6: threshold reference line — factual, not interpretive

    if self._current_threshold is not None and self._current_threshold > 0:

        ax.axhline(y=self._current_threshold,

                   color=Colors.PROMOTION_MARKER,

                   linewidth=0.6, alpha=0.4, linestyle="--",

                   zorder=2)

        ax.text(0.02, self._current_threshold + 0.02,

                "threshold",

                transform=ax.get_yaxis_transform(),

                color=Colors.PROMOTION_MARKER, fontsize=6,

                fontfamily="monospace", alpha=0.7)

 

    ax.set_ylim(-0.05, 1.05)

    ax.set_xlim(left=0)

    ax.set_ylabel("Best score", color=Colors.TEXT_OVERLAY,

                  fontsize=7, fontfamily="monospace")

    ax.tick_params(colors=Colors.TEXT_OVERLAY, labelsize=6)

    for spine in ax.spines.values():

        spine.set_color("#333333")

 

    ax_meta    = self.ax_meta

    gen        = snapshot.timestamp_gen

    stage      = stage_display_label(snapshot.stage)

    veto_total = self.evidence.running_veto_total()

 

    for i, line in enumerate([

        f"Stage:  {stage}",

        f"Gen:    {gen}",

        f"Vetoed: {veto_total}",

        f"Frames: {self.frame_count}",

    ]):

        ax_meta.text(0.05, 0.85 - i * 0.22, line,

                     transform=ax_meta.transAxes,

                     color=Colors.TEXT_OVERLAY,

                     fontsize=7, fontfamily="monospace", va="top")

 

    ax_meta.set_xlim(0, 1)

    ax_meta.set_ylim(0, 1)

    for spine in ax_meta.spines.values():

        spine.set_color("#333333")

 

# -----------------------------------------------------------------------

# Text overlay

# -----------------------------------------------------------------------

 

def _render_text_overlay(self, text: Optional[str]):

    """One sentence, fixed, hard replacement. Blank when None."""

    ax = self.ax_text

    ax.set_xlim(0, 1)

    ax.set_ylim(0, 1)

    ax.axis("off")

 

    if text:

        ax.text(0.5, 0.5, text,

                transform=ax.transAxes,

                ha="center", va="center",

                color=Colors.TEXT_OVERLAY,

                fontsize=10, fontfamily="monospace",

                fontstyle="normal", fontweight="normal")

 

def redraw(self):

    if self.fig is not None:

        try:

            self.fig.canvas.draw_idle()

            self.fig.canvas.flush_events()

        except Exception:

            pass

```

 

# —————————————————————————

 

# Utility

 

# —————————————————————————

 

def _style_main_ax(ax, title: str, show_title: bool):

“””

Consistent main panel styling.

Title shown only when show_title is True (debug mode).

Axis titles are not part of the sanctioned text layer.

“””

ax.set_facecolor(Colors.BACKGROUND)

ax.tick_params(colors=Colors.TEXT_OVERLAY, labelsize=7)

for spine in ax.spines.values():

spine.set_color(”#333333”)

if show_title and title:

ax.set_title(title, color=Colors.TEXT_OVERLAY, fontsize=8,

fontfamily=“monospace”, pad=4, loc=“left”)

 

# —————————————————————————

 

# Live loop

 

# —————————————————————————

 

def run_live(renderer: KeyRenderer, snapshot_queue, poll_sleep: float = 0.05):

“”“Poll queue. One update per snapshot. No timer-driven transitions.”””

plt.ion()

renderer.build_layout()

plt.show()

while True:

try:

snapshot = snapshot_queue.get_nowait()

except Exception:

plt.pause(poll_sleep)

continue

if snapshot is None:

break

renderer.consume_snapshot(snapshot)

renderer.redraw()

plt.pause(0.001)

plt.ioff()

 

# —————————————————————————

 

# Replay loop

 

# —————————————————————————

 

def run_replay(renderer: KeyRenderer,

snapshots: List[RendererSnapshot],

step_pause: float = 0.3,

interactive: bool = False):

“”“One snapshot = one frame. No interpolation.”””

plt.ion()

renderer.build_layout()

plt.show()

for i, snapshot in enumerate(snapshots):

renderer.consume_snapshot(snapshot)

renderer.redraw()

if interactive:

input(f”  Frame {i+1}/{len(snapshots)} — press Enter”)

else:

plt.pause(step_pause)

plt.ioff()

print(f”Replay complete. {len(snapshots)} frames rendered.”)

 

# —————————————————————————

 

# Headless export

 

# —————————————————————————

 

def export_frames(renderer: KeyRenderer,

snapshots: List[RendererSnapshot],

output_dir: str = “frames”):

“”“Export each snapshot as frame_NNNN.png.”””

import os

os.makedirs(output_dir, exist_ok=True)

for i, snapshot in enumerate(snapshots):

renderer.consume_snapshot(snapshot)

path = os.path.join(output_dir, f”frame_{i:04d}.png”)

renderer.fig.savefig(path, dpi=renderer.dpi,

facecolor=Colors.BACKGROUND,

bbox_inches=“tight”)

print(f”Exported {len(snapshots)} frames to {output_dir}/”)

 

# —————————————————————————

 

# Integration test

 

# —————————————————————————

 

if **name** == “**main**”:

import sys

import os

import shutil

 

```

print("THE KEY EMERGES — key_renderer.py (revised) integration test")

print()

 

sys.path.insert(0, ".")

from signal_model import build_signal_arms

from transform_families import (random_candidate, mutate_candidate,

                                 crossover_candidates)

from invariance_metrics import evaluate_candidate

from world_constraint import DEFAULT_WORLD

from core_types import ArmID, SurvivalConfig, StageLabel as SL

from survival_kernel import (run_survival_kernel, make_threshold_gate,

                              initialize_population)

from key_stage_text_runtime import StageTextState, stage_text_for_snapshot

 

stream_1, stream_2, c1, c2 = build_signal_arms(seed=42)

world = DEFAULT_WORLD

rng   = np.random.default_rng(0)

snaps = []

 

def factory(n): return [random_candidate(ArmID.ARM_1, f"c{i}", rng=rng)

                         for i in range(n)]

def evaluator(c): return evaluate_candidate(c, stream_1, world)

def mutator(c):   return mutate_candidate(c, rng=rng)

def xover(a, b, cid): return crossover_candidates(a, b, cid, rng=rng)

 

config = SurvivalConfig(population_size=20, max_generations=15,

                         promotion_threshold=0.80,

                         promotion_stability_gens=3)

gate = make_threshold_gate(0.80, 3)

pop  = initialize_population(factory, 20)

 

result = run_survival_kernel(

    pop, evaluator, mutator, xover, gate, config,

    SL.LENS_SEARCH, ArmID.ARM_1,

    snapshot_callback=snaps.append,

    verbose=False

)

 

print(f"Kernel: {len(snaps)} snapshots, "

      f"promoted={result.promoted}, gen={result.promotion_generation}")

 

# Debug mode — titles visible

r_debug = KeyRenderer(figsize=(14, 9), dpi=80, debug_labels=True)

r_debug.build_layout()

if os.path.exists("test_frames_debug"):

    shutil.rmtree("test_frames_debug")

export_frames(r_debug, snaps, "test_frames_debug")

print("Debug frames: test_frames_debug/")

 

# Public mode — titles off

r_pub = KeyRenderer(figsize=(14, 9), dpi=80, debug_labels=False)

r_pub.build_layout()

if os.path.exists("test_frames_pub"):

    shutil.rmtree("test_frames_pub")

export_frames(r_pub, snaps, "test_frames_pub")

print("Public frames: test_frames_pub/")

 

# Verify Change 4: identical candidate styles

assert CANDIDATE_STYLE["color"] == Colors.ACTIVE_CANDIDATE, \

    "FAIL Change 4: CANDIDATE_STYLE diverged from Colors.ACTIVE_CANDIDATE"

print(f"Change 4 verified: CANDIDATE_STYLE = {CANDIDATE_STYLE['color']}")

 

# Verify text strings

state = StageTextState()

seen  = set()

for snap in snaps:

    t = stage_text_for_snapshot(snap, state)

    if t and t not in seen:

        print(f"  text: \"{t}\"")

        seen.add(t)

 

print()

print("PASS — key_renderer.py (revised) complete.")

```


Back to site index