Selective vulnerability of entorhinal cortex layer II neurons in AD¶
Notebook ID: nb-sda-2026-04-01-gap-004 · Analysis: sda-2026-04-01-gap-004 · Generated: 2026-04-10
Research question¶
Why do entorhinal cortex layer II stellate neurons die first in AD? Their unique electrophysiological properties, grid cell function, and high metabolic demand may contribute, but the molecular basis of selective vulnerability is unknown.
Approach¶
This notebook is generated programmatically from real Forge tool calls and SciDEX debate data. Code cells load cached evidence bundles from data/forge_cache/seaad/*.json and query live data from scidex.db. Re-run python3 scripts/regenerate_notebooks.py --analysis sda-2026-04-01-gap-004 --force to refresh.
7 hypotheses were generated and debated. The knowledge graph has 117 edges.
Debate Summary¶
Quality score: 0.6 · Rounds: 6 · Personas: Theorist, Skeptic, Domain_Expert, Clinical_Trialist, Medicinal_Chemist, Synthesizer
1. Forge tool provenance¶
import json, sys, sqlite3
from pathlib import Path
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
matplotlib.rcParams['figure.dpi'] = 110
matplotlib.rcParams['figure.facecolor'] = 'white'
REPO = Path('.').resolve()
sys.path.insert(0, str(REPO))
CACHE_SUB = 'seaad'
CACHE = REPO / 'data' / 'forge_cache' / CACHE_SUB
def load(name):
p = CACHE / f'{name}.json'
if p.exists():
return json.loads(p.read_text())
return {}
db_path = Path('/home/ubuntu/scidex/scidex.db')
try:
db = sqlite3.connect(str(db_path))
prov = pd.read_sql_query('''
SELECT skill_id, status, COUNT(*) AS n_calls,
ROUND(AVG(duration_ms),0) AS mean_ms
FROM tool_calls
WHERE created_at >= date('now','-30 days')
GROUP BY skill_id, status
ORDER BY n_calls DESC
''', db)
db.close()
prov['tool'] = prov['skill_id'].str.replace('tool_', '', regex=False)
print(f'{len(prov)} tool-call aggregates (last 30 days):')
prov[['tool','status','n_calls','mean_ms']].head(20)
except Exception as e:
print(f'Provenance unavailable: {e}')
77 tool-call aggregates (last 30 days):
2. Target gene annotations¶
ann_rows = []
for g in ['MCU', 'RELN']:
mg = load(f'mygene_{g}')
hpa = load(f'hpa_{g}')
if not mg and not hpa:
ann_rows.append({'gene': g, 'name': '—', 'protein_class': '—',
'disease_involvement': '—'})
continue
ann_rows.append({
'gene': g,
'name': (mg.get('name') or '')[:55],
'protein_class': ', '.join((hpa.get('protein_class') or [])[:2])[:55]
if isinstance(hpa.get('protein_class'), list)
else str(hpa.get('protein_class') or '—')[:55],
'disease_involvement': ', '.join((hpa.get('disease_involvement') or [])[:2])[:55]
if isinstance(hpa.get('disease_involvement'), list)
else str(hpa.get('disease_involvement') or '')[:55],
})
pd.DataFrame(ann_rows)
| gene | name | protein_class | disease_involvement | |
|---|---|---|---|---|
| 0 | MCU | — | — | — |
| 1 | RELN | — | — | — |
3. GO Biological Process enrichment (Enrichr)¶
go_bp = load('enrichr_GO_Biological_Process')
if isinstance(go_bp, list) and go_bp:
go_df = pd.DataFrame(go_bp[:10])[['term','p_value','odds_ratio','genes']]
go_df['p_value'] = go_df['p_value'].apply(lambda p: f'{p:.2e}')
go_df['odds_ratio'] = go_df['odds_ratio'].round(1)
go_df['term'] = go_df['term'].str[:60]
go_df['n_hits'] = go_df['genes'].apply(len)
go_df['genes'] = go_df['genes'].apply(lambda g: ', '.join(g))
go_df[['term','n_hits','p_value','odds_ratio','genes']]
else:
print('No GO:BP enrichment data')
# Visualize top GO BP enrichment
go_bp = load('enrichr_GO_Biological_Process')
if isinstance(go_bp, list) and go_bp:
top = go_bp[:8]
terms = [t['term'][:45] for t in top][::-1]
neglogp = [-np.log10(max(t['p_value'], 1e-300)) for t in top][::-1]
fig, ax = plt.subplots(figsize=(9, 4.5))
ax.barh(terms, neglogp, color='#4fc3f7')
ax.set_xlabel('-log10(p-value)')
ax.set_title('Top GO:BP enrichment (Enrichr)')
ax.grid(axis='x', alpha=0.3)
plt.tight_layout(); plt.show()
else:
print('No GO:BP data to plot')
4. KEGG pathway enrichment¶
kegg = load('enrichr_KEGG_Pathways')
if isinstance(kegg, list) and kegg:
kegg_df = pd.DataFrame(kegg[:10])[['term','p_value','odds_ratio','genes']]
kegg_df['genes'] = kegg_df['genes'].apply(lambda g: ', '.join(g))
kegg_df['p_value'] = kegg_df['p_value'].apply(lambda p: f'{p:.2e}')
kegg_df['odds_ratio'] = kegg_df['odds_ratio'].round(1)
kegg_df
else:
print('No KEGG enrichment data')
No KEGG enrichment data
5. STRING protein interaction network¶
ppi = load('string_network')
if isinstance(ppi, list) and ppi:
ppi_df = pd.DataFrame(ppi).sort_values('score', ascending=False)
display_cols = [c for c in ['protein1','protein2','score','escore','tscore'] if c in ppi_df.columns]
print(f'{len(ppi_df)} STRING edges')
ppi_df[display_cols].head(20)
else:
print('No STRING edges returned')
11 STRING edges
# Network figure
ppi = load('string_network')
if isinstance(ppi, list) and ppi:
import math
nodes = sorted({p for e in ppi for p in (e['protein1'], e['protein2'])})
n = len(nodes)
pos = {n_: (math.cos(2*math.pi*i/n), math.sin(2*math.pi*i/n)) for i, n_ in enumerate(nodes)}
fig, ax = plt.subplots(figsize=(7, 7))
for e in ppi:
x1,y1 = pos[e['protein1']]; x2,y2 = pos[e['protein2']]
ax.plot([x1,x2],[y1,y2], color='#888', alpha=0.3+0.5*e['score'],
linewidth=0.5+2*e['score'])
for name,(x,y) in pos.items():
ax.scatter([x],[y], s=450, color='#ffd54f', edgecolors='#333', zorder=3)
ax.annotate(name, (x,y), ha='center', va='center', fontsize=8, fontweight='bold', zorder=4)
ax.set_aspect('equal'); ax.axis('off')
ax.set_title(f'STRING PPI network ({len(ppi)} edges)')
plt.tight_layout(); plt.show()
else:
print('No STRING data to visualize')
6. Reactome pathway footprint¶
pw_rows = []
for g in ['MCU', 'RELN']:
pws = load(f'reactome_{g}')
if isinstance(pws, list):
pw_rows.append({'gene': g, 'n_pathways': len(pws),
'top_pathway': (pws[0]['name'] if pws else '—')[:70]})
else:
pw_rows.append({'gene': g, 'n_pathways': 0, 'top_pathway': '—'})
pd.DataFrame(pw_rows).sort_values('n_pathways', ascending=False)
| gene | n_pathways | top_pathway | |
|---|---|---|---|
| 0 | MCU | 0 | — |
| 1 | RELN | 0 | — |
7. Allen Brain Atlas ISH regional expression¶
ish_rows = []
for g in ['MCU', 'RELN']:
ish = load(f'allen_ish_{g}')
regions = ish.get('regions') or [] if isinstance(ish, dict) else []
ish_rows.append({
'gene': g,
'n_ish_regions': len(regions),
'top_region': (regions[0].get('structure','') if regions else '—')[:45],
'top_energy': round(regions[0].get('expression_energy',0), 2) if regions else None,
})
pd.DataFrame(ish_rows)
| gene | n_ish_regions | top_region | top_energy | |
|---|---|---|---|---|
| 0 | MCU | 0 | — | — |
| 1 | RELN | 0 | — | — |
8. Hypothesis ranking (7 hypotheses)¶
hyp_data = [('HCN1-Mediated Resonance Frequency Stabilization Therapy', 0.594), ('Perforant Path Presynaptic Terminal Protection Strategy', 0.585), ('Grid Cell-Specific Metabolic Reprogramming via IDH2 Enh', 0.583), ('Tau-Independent Microtubule Stabilization via MAP6 Enha', 0.582), ('Astrocytic Lactate Shuttle Enhancement for Grid Cell Bi', 0.582), ('Mitochondrial Calcium Buffering Enhancement via MCU Mod', 0.573), ('Reelin-Mediated Cytoskeletal Stabilization Protocol', 0.558)]
titles = [h[0] for h in hyp_data][::-1]
scores = [h[1] for h in hyp_data][::-1]
fig, ax = plt.subplots(figsize=(10, max(8, len(titles)*0.4)))
colors = ['#ef5350' if s >= 0.6 else '#ffa726' if s >= 0.5 else '#66bb6a' for s in scores]
ax.barh(range(len(titles)), scores, color=colors)
ax.set_yticks(range(len(titles))); ax.set_yticklabels(titles, fontsize=7)
ax.set_xlabel('Composite Score'); ax.set_title('Selective vulnerability of entorhinal cortex layer II neurons in AD')
ax.grid(axis='x', alpha=0.3)
plt.tight_layout(); plt.show()
9. Score dimension heatmap (top 10)¶
labels = ['HCN1-Mediated Resonance Frequency Stabil', 'Perforant Path Presynaptic Terminal Prot', 'Grid Cell-Specific Metabolic Reprogrammi', 'Tau-Independent Microtubule Stabilizatio', 'Astrocytic Lactate Shuttle Enhancement f', 'Mitochondrial Calcium Buffering Enhancem', 'Reelin-Mediated Cytoskeletal Stabilizati']
matrix = np.array([[0.8, 0.7, 0.4, 0.5, 0.436, 0.6, 0.5, 0.9, 0.2], [0.7, 0.8, 0.7, 0.6, 0.523, 0.7, 0.8, 0.8, 0.8], [0.8, 0.5, 0.3, 0.3, 0.509, 0.4, 0.4, 0.7, 0.2], [0.8, 0.7, 0.6, 0.7, 0.05, 0.6, 0.7, 0.7, 0.5], [0.7, 0.6, 0.4, 0.4, 0.524, 0.4, 0.5, 0.6, 0.4], [0.6, 0.5, 0.3, 0.3, 0.688, 0.5, 0.4, 0.8, 0.1], [0.9, 0.4, 0.6, 0.6, 0.675, 0.5, 0.6, 0.3, 0.5]])
dims = ['novelty_score', 'feasibility_score', 'impact_score', 'mechanistic_plausibility_score', 'clinical_relevance_score', 'data_availability_score', 'reproducibility_score', 'druggability_score', 'safety_profile_score']
if matrix.size:
fig, ax = plt.subplots(figsize=(10, 5))
im = ax.imshow(matrix, cmap='RdYlGn', aspect='auto', vmin=0, vmax=1)
ax.set_xticks(range(len(dims)))
ax.set_xticklabels([d.replace('_score','').replace('_',' ').title() for d in dims],
rotation=45, ha='right', fontsize=8)
ax.set_yticks(range(len(labels))); ax.set_yticklabels(labels, fontsize=7)
ax.set_title('Score dimensions — top hypotheses')
plt.colorbar(im, ax=ax, shrink=0.8)
plt.tight_layout(); plt.show()
else:
print('No score data available')
10. PubMed evidence per hypothesis¶
Hypothesis 1: HCN1-Mediated Resonance Frequency Stabilization Therapy¶
Target genes: HCN1 · Composite score: 0.594
Molecular Mechanism and Rationale
The hyperpolarization-activated cyclic nucleotide-gated channel 1 (HCN1) represents a critical molecular determinant of intrinsic neuronal excitability, particularly within entorhinal cortex (EC) layer II stellate neurons that serve as the primary input to hippocampal circuits. HCN1 channels generate the hyperpolarization-activated current (Ih), which produces a characteristic depolarizing "sag" during hyperpolarizing current injections and establishes the
hid = 'h-d40d2659'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 2: Perforant Path Presynaptic Terminal Protection Strategy¶
Target genes: PPARGC1A · Composite score: 0.585
Molecular Mechanism and Rationale
The perforant path represents one of the most metabolically demanding neuronal projections in the central nervous system, consisting of exceptionally long axons extending from layer II stellate neurons in the entorhinal cortex (EC) to granule cells in the hippocampal dentate gyrus. These axons can span distances exceeding 10 millimeters in humans, requiring robust mitochondrial networks and efficient ATP production to maintain synaptic transmission and axon
hid = 'h-76888762'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 3: Grid Cell-Specific Metabolic Reprogramming via IDH2 Enhancement¶
Target genes: IDH2 · Composite score: 0.583
Molecular Mechanism and Rationale
Grid cells in layer II of the entorhinal cortex represent one of the brain's most metabolically demanding neuronal populations due to their continuous spatial computation and persistent theta-frequency firing patterns. These specialized neurons maintain hexagonal firing fields that require sustained high-frequency oscillations at 4-12 Hz, creating extraordinary metabolic stress that may contribute to their selective vulnerability in neurodegenerative diseas
hid = 'h-57862f8a'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 4: Tau-Independent Microtubule Stabilization via MAP6 Enhancement¶
Target genes: MAP6 · Composite score: 0.582
Tau-independent microtubule stabilization via MAP6 (also known as STOP protein — Stable Tubule Only Polypeptide) enhancement proposes compensating for tau loss-of-function by upregulating an alternative microtubule-stabilizing protein. This strategy addresses a critical but underappreciated aspect of tauopathies: while pathological tau aggregation receives therapeutic attention, the loss of tau's normal microtubule-stabilizing function equally contributes to neurodegeneration through cytoskeleta
hid = 'h-e12109e3'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 5: Astrocytic Lactate Shuttle Enhancement for Grid Cell Bioenergetics¶
Target genes: SLC16A2 · Composite score: 0.582
Molecular Mechanism and Rationale
Grid cells in layer II of the entorhinal cortex (EC) exhibit unique firing patterns that create a hexagonal spatial coordinate system, fundamental to spatial navigation and memory formation. These neurons maintain continuous high-frequency firing during active navigation, creating extraordinary metabolic demands that exceed those of typical cortical neurons by 3-4 fold. The hypothesis centers on enhancing the astrocyte-neuron lactate shuttle (ANLS) specific
hid = 'h-5ff6c5ca'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 6: Mitochondrial Calcium Buffering Enhancement via MCU Modulation¶
Target genes: MCU · Composite score: 0.573
Molecular Mechanism and Rationale
The mitochondrial calcium uniporter (MCU) represents a critical nexus in cellular bioenergetics and calcium homeostasis, particularly in neurons with high metabolic demands such as layer II stellate neurons of the entorhinal cortex. These neurons exhibit distinctive electrophysiological properties, including high-frequency firing patterns and extensive dendritic arborizations that create extraordinary calcium handling requirements. The MCU complex, comprisi
hid = 'h-aa8b4952'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 7: Reelin-Mediated Cytoskeletal Stabilization Protocol¶
Target genes: RELN · Composite score: 0.558
Molecular Mechanism and Rationale
The reelin signaling pathway represents a critical molecular framework for maintaining neuronal architecture and synaptic integrity in the entorhinal cortex, particularly within layer II stellate neurons that serve as the cellular substrate for grid cell function. Reelin, encoded by the RELN gene, is a large extracellular glycoprotein (388 kDa) that functions as a key regulator of neuronal positioning during development and synaptic plasticity in the adult
hid = 'h-d2df6eaf'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
11. Knowledge graph edges (117 total)¶
edge_data = [{'source': 'MAP6', 'relation': 'regulates', 'target': 'microtubule_stabilization', 'strength': 0.8}, {'source': 'microtubule_stabilization', 'relation': 'enables', 'target': 'axonal_transport', 'strength': 0.8}, {'source': 'axonal_transport', 'relation': 'prevents', 'target': 'neurodegeneration_protection', 'strength': 0.8}, {'source': 'PPARGC1A', 'relation': 'encodes', 'target': 'PGC1A_protein', 'strength': 0.8}, {'source': 'PGC1A_protein', 'relation': 'activates', 'target': 'mitochondrial_biogenesis', 'strength': 0.8}, {'source': 'mitochondrial_biogenesis', 'relation': 'promotes', 'target': 'perforant_path_protection', 'strength': 0.8}, {'source': 'RELN', 'relation': 'encodes', 'target': 'reelin_protein', 'strength': 0.8}, {'source': 'reelin_protein', 'relation': 'phosphorylates', 'target': 'DAB1', 'strength': 0.8}, {'source': 'DAB1', 'relation': 'promotes', 'target': 'cytoskeletal_stability', 'strength': 0.8}, {'source': 'HCN1', 'relation': 'encodes', 'target': 'HCN1_channel', 'strength': 0.8}, {'source': 'HCN1_channel', 'relation': 'mediates', 'target': 'membrane_resonance', 'strength': 0.8}, {'source': 'membrane_resonance', 'relation': 'enables', 'target': 'grid_cell_oscillations', 'strength': 0.8}, {'source': 'entorhinal_cortex_layer_II', 'relation': 'early_vulnerability', 'target': 'alzheimers_disease', 'strength': 0.8}, {'source': 'MAP6', 'relation': 'regulates', 'target': 'Tau-Independent Microtubule St', 'strength': 0.7}, {'source': 'PPARGC1A', 'relation': 'regulates', 'target': 'Perforant Path Presynaptic Ter', 'strength': 0.7}, {'source': 'RELN', 'relation': 'regulates', 'target': 'Reelin-Mediated Cytoskeletal S', 'strength': 0.7}, {'source': 'HCN1', 'relation': 'regulates', 'target': 'HCN1-Mediated Resonance Freque', 'strength': 0.7}, {'source': 'SLC16A2', 'relation': 'regulates', 'target': 'Astrocytic Lactate Shuttle Enh', 'strength': 0.7}, {'source': 'IDH2', 'relation': 'regulates', 'target': 'Grid Cell-Specific Metabolic R', 'strength': 0.7}, {'source': 'MCU', 'relation': 'regulates', 'target': 'Mitochondrial Calcium Bufferin', 'strength': 0.7}, {'source': 'Tau-Independent Microtubule St', 'relation': 'therapeutic_target', 'target': "Alzheimer's Disease", 'strength': 0.65}, {'source': 'Perforant Path Presynaptic Ter', 'relation': 'therapeutic_target', 'target': "Alzheimer's Disease", 'strength': 0.65}, {'source': 'Reelin-Mediated Cytoskeletal S', 'relation': 'therapeutic_target', 'target': "Alzheimer's Disease", 'strength': 0.65}, {'source': 'HCN1-Mediated Resonance Freque', 'relation': 'therapeutic_target', 'target': "Alzheimer's Disease", 'strength': 0.65}, {'source': 'Astrocytic Lactate Shuttle Enh', 'relation': 'therapeutic_target', 'target': "Alzheimer's Disease", 'strength': 0.65}]
if edge_data:
pd.DataFrame(edge_data).head(25)
else:
print('No KG edge data available')
12. Caveats¶
This notebook uses real Forge tool calls cached from live APIs, but:
- Enrichment is against curated gene-set libraries, not genome-wide screens
- STRING/Reactome/HPA/MyGene reflect curated knowledge
- PubMed literature is search-relevance ranked, not systematic review
The cached evidence bundle is the minimum viable real-data analysis for this topic.