()
| 318 | } |
| 319 | |
| 320 | function loadGenes() { |
| 321 | ensureGenesSeeded(); |
| 322 | const jsonGenes = readJsonIfExists(genesPath(), getDefaultGenes()).genes || []; |
| 323 | const jsonlGenes = []; |
| 324 | try { |
| 325 | const p = path.join(getGepAssetsDir(), 'genes.jsonl'); |
| 326 | if (fs.existsSync(p)) { |
| 327 | const raw = fs.readFileSync(p, 'utf8'); |
| 328 | raw.split('\n').forEach(line => { |
| 329 | if (line.trim()) { |
| 330 | try { |
| 331 | const parsed = JSON.parse(line); |
| 332 | if (parsed && parsed.type === 'Gene') jsonlGenes.push(parsed); |
| 333 | } catch(e) {} |
| 334 | } |
| 335 | }); |
| 336 | } |
| 337 | } catch(e) { |
| 338 | console.warn('[AssetStore] Failed to read genes.jsonl:', e && e.message || e); |
| 339 | } |
| 340 | |
| 341 | // Combine and deduplicate by ID (JSONL takes precedence). Do NOT pass loaded |
| 342 | // genes through createGene() — that would synthesize default fields |
| 343 | // (epigenetic_marks, learning_history, anti_patterns, summary, |
| 344 | // schema_version) on legacy genes that pre-date those fields, which would |
| 345 | // change their content hash and invalidate any previously-computed |
| 346 | // asset_id. Read paths must preserve on-disk gene shapes byte-for-byte; |
| 347 | // callers that need normalized fields should call createGene() explicitly |
| 348 | // (and write back via upsertGene which recomputes asset_id). |
| 349 | const combined = [...jsonGenes, ...jsonlGenes]; |
| 350 | const unique = new Map(); |
| 351 | combined.forEach(g => { |
| 352 | if (g && g.id) unique.set(String(g.id), g); |
| 353 | }); |
| 354 | return Array.from(unique.values()); |
| 355 | } |
| 356 | |
| 357 | function loadCapsules() { |
| 358 | const legacy = readJsonIfExists(capsulesPath(), getDefaultCapsules()).capsules || []; |
no test coverage detected