Science Validation — wetSpring

Rendered from 01-science-validation.ipynb

Science Validation — wetSpring

wetSpring is the life-science and analytical-chemistry spring for the ecoPrimals ecosystem. It exposes 19 IPC science methods spanning microbial ecology, bioinformatics, pharmacology (Gonzales JAK/IL panel), Anderson localization physics, and kinetics — all validated against published papers through a Paper → Rust → NUCLEUS primal composition chain.

This notebook loads frozen validation results and visualizes the science method surface, test distribution, and validation chain evidence.

Data sources: experiments/results/science_validation.json, gonzales_domain.json

Reproduce: cargo test --workspace in the wetSpring repository. See primals.eco/lab/springs/wetspring.


For other springs: adapt this pattern by loading your own IPC method catalog and validation chain data. The cell structure (load → tier detect → visualize → summary) is the template. Your domain methods replace the science methods listed here.

import os, json, struct, socket
from pathlib import Path

RESULTS = Path('..') / 'experiments' / 'results'

def load(name):
    with open(RESULTS / name) as f:
        return json.load(f)

# Tier detection
TIER = 'frozen'
IPC_SOCKET = os.environ.get('WETSPRING_IPC_SOCKET')

def ipc_call(method, params=None):
    """JSON-RPC call to barracuda IPC — active in Tier 2."""
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    sock.connect(IPC_SOCKET)
    req = json.dumps({'jsonrpc': '2.0', 'method': method, 'params': params or {}, 'id': 1})
    payload = req.encode()
    sock.sendall(struct.pack('<I', len(payload)) + payload)
    length = struct.unpack('<I', sock.recv(4))[0]
    data = sock.recv(length)
    sock.close()
    return json.loads(data)['result']

if IPC_SOCKET and os.path.exists(IPC_SOCKET):
    try:
        ipc_call('health.check')
        TIER = 'live_ipc'
        print(f'Tier 2 ACTIVE — live IPC via {IPC_SOCKET}')
    except Exception:
        print('Tier 2 socket found but not responding — using frozen data')
else:
    print(f'Tier 1 — frozen data (no IPC socket)')

sci = load('science_validation.json')
gonz = load('gonzales_domain.json')

print(f'Version: {sci["version"]}')
print(f'Tests: {sci["tests"]["passed"]}/{sci["tests"]["total"]} passed')
print(f'Binaries: {sci["binaries"]["total"]} ({sci["binaries"]["validate"]} validators)')
print(f'Science methods: {len(sci["ipc_handlers"]["science_methods"])}')
print(f'Sovereign fallbacks: {sci["validation_chain"]["sovereign_fallbacks"]}')

Science Method Categories

wetSpring’s 19 science IPC methods are organized into 6 domain categories. Each method maps to a validated barracuda library function — no math is duplicated in the dispatch layer.

import matplotlib
import matplotlib.pyplot as plt

cats = sci['science_method_categories']
cat_names = list(cats.keys())
cat_counts = [len(cats[c]['methods']) for c in cat_names]
labels = [n.replace('_', ' ').title() for n in cat_names]

fig, axes = plt.subplots(1, 2, figsize=(15, 5))

palette = ['#3498db', '#9b59b6', '#2ecc71', '#e74c3c', '#f39c12', '#1abc9c']

# Bar chart of method counts per category
ax = axes[0]
bars = ax.bar(range(len(cat_names)), cat_counts, color=palette)
ax.set_xticks(range(len(cat_names)))
ax.set_xticklabels(labels, rotation=30, ha='right', fontsize=9)
ax.set_ylabel('IPC Methods')
ax.set_title(f'Science Methods by Category — {sum(cat_counts)} total')
for bar, val in zip(bars, cat_counts):
    ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.1,
            str(val), ha='center', va='bottom', fontsize=11, fontweight='bold')

# Pie chart of test categories
test_cats = sci['tests']['categories']
tc_names = [k.replace('_', ' ').title() for k in test_cats]
tc_vals = [test_cats[k]['tests'] for k in test_cats]
ax = axes[1]
wedges, texts, autotexts = ax.pie(
    tc_vals, labels=None, autopct='%1.0f%%',
    colors=palette[:len(tc_vals)], startangle=90, pctdistance=0.82)
for t in autotexts:
    t.set_fontsize(9)
ax.legend(tc_names, loc='center left', bbox_to_anchor=(1, 0.5), fontsize=9)
ax.set_title(f'Test Suite — {sci["tests"]["total"]} tests, 0 failed')

plt.suptitle(f'wetSpring {sci["version"]}: {sum(cat_counts)} Science Methods, '
             f'{sci["tests"]["total"]} Tests — {sci["validation"]}',
             fontsize=13, fontweight='bold')
plt.tight_layout()
plt.savefig('/tmp/wetspring_01_methods.png', dpi=150, bbox_inches='tight')
plt.show()

Validation Chain

Every scientific result in wetSpring traces through a 5-stage validation chain: Source Paper → Public Data Ingestion → Rust Validation → guideStone → NUCLEUS Composition. The chain is pure Rust — only the external data is not Rust.

stages = sci['validation_chain']['stages']
stage_labels = [
    'Source\nPaper (DOI)',
    'Public Data\nIngestion',
    'Rust\nValidation',
    'guideStone\nScenarios',
    'NUCLEUS\nComposition'
]
stage_status = ['#2ecc71', '#2ecc71', '#2ecc71', '#2ecc71', '#f39c12']
stage_notes = [
    'Gonzales 2014\nDOI: 10.1111/jvp.12065',
    'ChEMBL + PubChem\nvia NestGate',
    '35/35 checks\nvalidate_gonzales_ic50_s79',
    '29/29 checks\nwetspring_gonzales_guidestone',
    'Deployment gap\n(primals not running)'
]

fig, ax = plt.subplots(figsize=(16, 4))
for i, (label, color, note) in enumerate(zip(stage_labels, stage_status, stage_notes)):
    x = i * 3
    rect = plt.Rectangle((x, 0.5), 2.4, 2, facecolor=color, alpha=0.3, edgecolor=color, linewidth=2)
    ax.add_patch(rect)
    ax.text(x + 1.2, 1.9, label, ha='center', va='center', fontsize=10, fontweight='bold')
    ax.text(x + 1.2, 0.9, note, ha='center', va='center', fontsize=8, color='#555')
    if i < len(stages) - 1:
        ax.annotate('', xy=(x + 2.6, 1.5), xytext=(x + 2.4, 1.5),
                    arrowprops=dict(arrowstyle='->', color='#555', lw=2))

ax.set_xlim(-0.5, len(stages) * 3)
ax.set_ylim(0, 3)
ax.axis('off')
ax.set_title('Validation Chain — Paper → Rust → NUCLEUS (pure primal composition)',
             fontsize=13, fontweight='bold', pad=15)
plt.tight_layout()
plt.savefig('/tmp/wetspring_01_chain.png', dpi=150, bbox_inches='tight')
plt.show()

Key Validators

Three key validation binaries exercise the Gonzales pipeline end-to-end.

validators = sci['key_validators']
v_names = list(validators.keys())
v_checks = [validators[v]['checks'] for v in v_names]
v_colors = ['#2ecc71' if validators[v]['status'] == 'PASS' else '#e74c3c' for v in v_names]
v_labels = [n.replace('_', ' ').title() for n in v_names]

fig, ax = plt.subplots(figsize=(10, 4))
bars = ax.barh(v_labels, v_checks, color=v_colors)
ax.set_xlabel('Checks')
ax.set_title('Key Validators — All PASS')
for bar, val, name in zip(bars, v_checks, v_names):
    ax.text(bar.get_width() + 0.5, bar.get_y() + bar.get_height()/2,
            f'{val}/{val} PASS', va='center', fontsize=10)

# Tier 2: compare live method surface
if TIER == 'live_ipc':
    live_caps = ipc_call('capability.list')
    frozen_methods = set(sci['ipc_handlers']['science_methods'])
    live_methods = set(live_caps.get('science', []))
    parity = frozen_methods == live_methods
    ax.text(0.5, -0.15, f'Tier 2 parity: {"MATCH" if parity else "MISMATCH"} '
            f'(frozen={len(frozen_methods)}, live={len(live_methods)})',
            transform=ax.transAxes, fontsize=10, ha='center',
            color='#2ecc71' if parity else '#e74c3c', fontweight='bold')

plt.tight_layout()
plt.savefig('/tmp/wetspring_01_validators.png', dpi=150, bbox_inches='tight')
plt.show()

Validation Summary

ComponentChecksStatus
Science methods (19 IPC)19 dispatch routesPASS
Test suite (workspace)1,902/1,902 passedPASS
Gonzales IC50 (Table 1)35/35 PASSPASS
Provenance chain (Exp310)19/19 PASSPASS
NUCLEUS live (Exp311)11/11 PASSPASS
Sovereign fallbacks0PASS

All 19 science methods validate against published papers through the Paper → Rust → NUCLEUS chain. Structured gap reports surface when deployment primals are unavailable.


Provenance: All results are content-addressed via BLAKE3 hashes, tracked in rhizoCrypt DAG sessions, committed to the loamSpine ledger, and witnessed with ed25519 signatures via sweetGrass braid.

Evolution: This is Tier 1 (frozen data). Tier 2 (live IPC parity) activates when WETSPRING_IPC_SOCKET is set. Tier 3 (full primal composition with provenance) is the gAIa artifact target.

Reproduce: See primals.eco/lab/reproduce

Source: ecoPrimals/wetSpring