Using passive-mode scenario chains to grow abstraction semantics

Conceptual basis
In passive mode the system can generalize concrete episodic experience into abstraction semantic structures. Key idea: chains of related EP frames hold "condition → action → effect" patterns that can be projected into semanticStructure of abstract images.

Algorithm: growing semanticStructure from EP chains

Stage 1: Detect scenario chains in EP

javascript
function extractScenarioChainsFromEpisodes(maxChainLength = 5) {
    var chains = [];
    var episodes = global.Episodes || [];

    // Look for runs of frames with nonzero effect
    for (var i = 0; i < episodes.length; i++) {
        var frame = episodes[i];
        if (!frame || typeof frame.effect !== 'number' || frame.effect === 0) continue;

        var chain = [frame];
        var currentPerceptionNode = frame.perceptionNodeId;

        // Look for chain continuations (same perceptionNodeId or parent nodes)
        for (var j = i + 1; j < episodes.length && chain.length < maxChainLength; j++) {
            var nextFrame = episodes[j];
            if (!nextFrame) break;

            // Frame linkage criteria:
            var isRelated = (
                nextFrame.perceptionNodeId === currentPerceptionNode ||  // same branch
                isParentNode(nextFrame.perceptionNodeId, currentPerceptionNode) ||  // parent branch
                (nextFrame.stimulusImageId === frame.actionImageId)  // stimulus = prior action
            );

            if (isRelated && typeof nextFrame.effect === 'number') {
                chain.push(nextFrame);
                currentPerceptionNode = nextFrame.perceptionNodeId;
            }
        }

        if (chain.length >= 2) {
            chains.push({
                startIndex: i,
                frames: chain,
                totalEffect: chain.reduce(function(sum, f) { return sum + (f.effect || 0); }, 0),
                perceptionNodeId: chain[0].perceptionNodeId
            });
        }
    }

    return chains;
}

Stage 2: Extract patterns from chains

javascript
function extractPatternsFromChain(chain) {
    var patterns = [];

    for (var i = 0; i < chain.frames.length; i++) {
        var frame = chain.frames[i];

        // Pattern for perception abstraction
        if (frame.stimulusImageId) {
            var absPerceptionId = global.findAbstractPerceptionRecordId(
                frame.perceptionNodeId,
                frame.stimulusImageId
            );

            if (absPerceptionId) {
                patterns.push({
                    type: 'perception',
                    abstractId: absPerceptionId,
                    perceptionNodeId: frame.perceptionNodeId,
                    situationId: frame.situationId || 0,
                    ruleKind: 'episodic',
                    stimulusImageId: frame.stimulusImageId,
                    actionImageId: frame.actionImageId || null,
                    effect: frame.effect,
                    responseStimulusImageId: frame.responseStimulusImageId || null,
                    chainPosition: i,
                    chainTotalEffect: chain.totalEffect
                });
            }
        }

        // Pattern for action abstraction
        if (frame.actionImageId) {
            var absActionId = global.findAbstractActionRecordId(
                frame.perceptionNodeId,
                frame.actionImageId
            );

            if (absActionId) {
                patterns.push({
                    type: 'action',
                    abstractId: absActionId,
                    perceptionNodeId: frame.perceptionNodeId,
                    situationId: frame.situationId || 0,
                    ruleKind: 'episodic',
                    stimulusImageId: frame.stimulusImageId || null,
                    actionImageId: frame.actionImageId,
                    effect: frame.effect,
                    responseStimulusImageId: frame.responseStimulusImageId || null,
                    chainPosition: i,
                    chainTotalEffect: chain.totalEffect
                });
            }
        }
    }

    return patterns;
}

Stage 3: Update abstraction semanticStructure

javascript
function updateAbstractSemanticStructureFromPatterns(patterns) {
    var updatedCount = 0;

    for (var p = 0; p < patterns.length; p++) {
        var pattern = patterns[p];
        var absRecord = null;

        if (pattern.type === 'perception') {
            absRecord = global.Info_findAbstractPerceptionImage(pattern.abstractId);
        } else if (pattern.type === 'action') {
            absRecord = global.Info_findAbstractActionImage(pattern.abstractId);
        }

        if (!absRecord || !absRecord.semanticStructure) continue;

        var existingFrameIndex = -1;
        var frames = absRecord.semanticStructure.frames || [];

        for (var f = 0; f < frames.length; f++) {
            var fr = frames[f];
            if (fr.perceptionNodeId === pattern.perceptionNodeId &&
                fr.situationId === pattern.situationId) {
                existingFrameIndex = f;
                break;
            }
        }

        var newFrame = {
            perceptionNodeId: pattern.perceptionNodeId,
            situationId: pattern.situationId,
            ruleKind: pattern.ruleKind,
            stimulusImageId: pattern.stimulusImageId,
            actionImageId: pattern.actionImageId,
            effect: pattern.effect,
            responseStimulusImageId: pattern.responseStimulusImageId,
            updatedAt: Date.now(),
            chainEffect: pattern.chainTotalEffect,
            chainPosition: pattern.chainPosition
        };

        if (existingFrameIndex >= 0) {
            var existing = frames[existingFrameIndex];
            existing.effect = (existing.effect + pattern.effect) / 2;
            if (!existing.chainEffect || pattern.chainTotalEffect > existing.chainEffect) {
                existing.chainEffect = pattern.chainTotalEffect;
            }
            existing.updatedAt = Date.now();
        } else {
            frames.push(newFrame);
            updatedCount++;
        }

        absRecord.semanticStructure.frames = frames;
        global.memDirty = true;
    }

    return updatedCount;
}

Stage 4: Passive-mode integration

javascript
// In goals.js: PassiveMode_processUnderstandingModels()
function PassiveMode_processUnderstandingModels() {
    if (!global.InfoPicture || global.InfoPicture.mode !== 'passive') return;

    var chains = extractScenarioChainsFromEpisodes(5);
    if (!chains || chains.length === 0) return;

    var allPatterns = [];
    for (var c = 0; c < chains.length; c++) {
        var patterns = extractPatternsFromChain(chains[c]);
        allPatterns = allPatterns.concat(patterns);
    }

    var updated = updateAbstractSemanticStructureFromPatterns(allPatterns);

    if (updated > 0 && typeof global.Consciousness_cycleAppendLog === 'function') {
        var mainCycle = global.Consciousness_getMainCycle();
        if (mainCycle) {
            global.Consciousness_cycleAppendLog(
                mainCycle,
                'Passive mode: updated ' + updated + ' semanticStructure frame(s) from ' +
                chains.length + ' EP chain(s) (' + allPatterns.length + ' pattern(s)).',
                global.cpuls,
                { force: true }
            );
        }
    }

    if (updated > 0 && typeof global.AbstractImages_flushIndexedDB === 'function') {
        global.AbstractImages_flushIndexedDB();
    }
}

Additional growth mechanisms

4.1: Prioritize chains by total effect

javascript
function prioritizeChainsByEffect(chains) {
    chains.sort(function(a, b) {
        if (a.totalEffect > 0 && b.totalEffect <= 0) return -1;
        if (a.totalEffect <= 0 && b.totalEffect > 0) return 1;
        return Math.abs(b.totalEffect) - Math.abs(a.totalEffect);
    });
    return chains.slice(0, 3);
}

4.2: Generalize to parent perception nodes

javascript
function generalizePatternToParentNodes(pattern) {
    var generalized = [pattern];
    var currentNodeId = pattern.perceptionNodeId;

    for (var level = 0; level < 3; level++) {
        var parentNode = global.PerceptionTree_getNode(currentNodeId);
        if (!parentNode || !parentNode.parentId || parentNode.parentId === 0) break;

        generalized.push({
            type: pattern.type,
            abstractId: pattern.abstractId,
            perceptionNodeId: parentNode.parentId,
            situationId: pattern.situationId,
            ruleKind: 'episodic_generalized',
            stimulusImageId: pattern.stimulusImageId,
            actionImageId: pattern.actionImageId,
            effect: pattern.effect * 0.7,
            chainPosition: pattern.chainPosition,
            chainTotalEffect: pattern.chainTotalEffect
        });

        currentNodeId = parentNode.parentId;
    }

    return generalized;
}

4.3: Merge duplicate semanticStructure frames

javascript
function mergeDuplicateSemanticFrames(absRecord) {
    if (!absRecord || !absRecord.semanticStructure ||
        !Array.isArray(absRecord.semanticStructure.frames)) {
        return 0;
    }

    var frames = absRecord.semanticStructure.frames;
    var merged = 0;
    var grouped = {};

    for (var i = 0; i < frames.length; i++) {
        var key = frames[i].perceptionNodeId + '|' + frames[i].situationId;
        if (!grouped[key]) {
            grouped[key] = [];
        }
        grouped[key].push(frames[i]);
    }

    var newFrames = [];
    for (var k in grouped) {
        var group = grouped[k];
        if (group.length === 1) {
            newFrames.push(group[0]);
        } else {
            var mergedFrame = Object.assign({}, group[0]);
            mergedFrame.effect = group.reduce(function(sum, f) {
                return sum + (f.effect || 0);
            }, 0) / group.length;
            mergedFrame.chainEffect = Math.max.apply(null,
                group.map(function(f) { return f.chainEffect || 0; })
            );
            newFrames.push(mergedFrame);
            merged++;
        }
    }

    absRecord.semanticStructure.frames = newFrames;
    return merged;
}

Integration points in existing code

Module | Function | Change
goals.js | PassiveMode_processUnderstandingModels() | Call extractScenarioChainsFromEpisodes() + updateAbstractSemanticStructureFromPatterns()
abstract_images.js | AbstractImages_cloneFromEpisodeFrame() | Add chainEffect, chainPosition on semanticStructure frames
episodic_memory.js | EpisodicMemory_onPulse() | episodesChanged flag to trigger passive processing
puls.js | sep_of_puls() | Call PassiveMode_processUnderstandingModels() only in passive mode
