feat(ai-psychosis): same-invocation valence-aware pushback detection
This commit is contained in:
parent
881c2bc10a
commit
eca30b4682
2 changed files with 44 additions and 0 deletions
|
|
@ -111,10 +111,20 @@ for (const p of depPatterns) { if (p.test(prompt)) { depHit = 1; break; } }
|
|||
for (const p of escPatterns) { if (p.test(prompt)) { escHit = 1; break; } }
|
||||
for (const p of fatPatterns) { if (p.test(prompt)) { fatHit = 1; break; } }
|
||||
for (const p of valPatterns) { if (p.test(prompt)) { valHit = 1; break; } }
|
||||
let pbReactiveHit = 0; for (const p of pbReactivePatterns) { if (p.test(prompt)) { pbReactiveHit = 1; break; } }
|
||||
let pbPreemptiveHit = 0; for (const p of pbPreemptivePatterns) { if (p.test(prompt)) { pbPreemptiveHit = 1; break; } }
|
||||
let domainHit = 0; for (const p of domainRelationshipPatterns) { if (p.test(prompt)) { domainHit = 1; break; } }
|
||||
|
||||
// Clear prompt from memory
|
||||
prompt = '';
|
||||
|
||||
// Same-invocation valence guard (research/01 frustration-spiral finding):
|
||||
// pushback in fat/esc context is NOT protective — suppress in same prompt.
|
||||
if (fatHit === 1 || escHit === 1) {
|
||||
pbReactiveHit = 0;
|
||||
pbPreemptiveHit = 0;
|
||||
}
|
||||
|
||||
// Update state with new flag counts
|
||||
const state = readState();
|
||||
const newDep = (Number(state.dep_flags) || 0) + depHit;
|
||||
|
|
@ -126,6 +136,8 @@ state.dep_flags = newDep;
|
|||
state.esc_flags = newEsc;
|
||||
state.fatigue_flags = newFat;
|
||||
state.val_flags = newVal;
|
||||
state.pushback_count = (Number(state.pushback_count) || 0) + pbReactiveHit + pbPreemptiveHit;
|
||||
if (domainHit === 1 && !state.domain_context) state.domain_context = 'relationship';
|
||||
writeState(state);
|
||||
|
||||
// Check if any thresholds crossed
|
||||
|
|
|
|||
|
|
@ -396,3 +396,35 @@ describe('domain relationship patterns', () => {
|
|||
it('does not match "the data is updating" (no dating word boundary)', () => assert.equal(matchesAny(domainRelationshipPatterns, 'the data is updating in real time'), false));
|
||||
it('does not match "romantic comedy film" (no involved/interested suffix)', () => assert.equal(matchesAny(domainRelationshipPatterns, 'watching a romantic comedy film'), false));
|
||||
});
|
||||
|
||||
// --- v1.1.0 integration: pushback + valence + domain through prompt-analyzer.mjs ---
|
||||
|
||||
describe('pushback integration (state accumulation + same-invocation valence)', () => {
|
||||
it('counts reactive pushback alone (no fatigue/escalation)', () => {
|
||||
const s = runPrompt('are you sure?');
|
||||
assert.equal(s.pushback_count, 1);
|
||||
assert.equal(s.fatigue_flags, 0);
|
||||
assert.equal(s.esc_flags, 0);
|
||||
});
|
||||
|
||||
it('counts preemptive pushback alone', () => {
|
||||
const s = runPrompt('please steelman this argument');
|
||||
assert.equal(s.pushback_count, 1);
|
||||
});
|
||||
|
||||
it('SUPPRESSES pushback when fatigue marker is in same invocation (valence guard)', () => {
|
||||
const s = runPrompt("are you sure? I'm exhausted by all this");
|
||||
assert.equal(s.pushback_count, 0, 'pushback must be suppressed when fatigue is co-present');
|
||||
assert.equal(s.fatigue_flags, 1);
|
||||
});
|
||||
|
||||
it('sets domain_context to "relationship" on positive match', () => {
|
||||
const s = runPrompt("my partner won't listen to me");
|
||||
assert.equal(s.domain_context, 'relationship');
|
||||
});
|
||||
|
||||
it('keeps domain_context null on technical "function relationship" (false-positive guard)', () => {
|
||||
const s = runPrompt('function relationship between input and output');
|
||||
assert.equal(s.domain_context, null);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue