feat(ai-psychosis): validation-seeking domain-gated alert

This commit is contained in:
Kjell Tore Guttormsen 2026-05-01 21:41:15 +02:00
commit 12e6d3b5e4
2 changed files with 73 additions and 0 deletions

View file

@ -418,6 +418,22 @@ if (
warnings.push(`INTERACTION AWARENESS (tier-1 isolation): User signals no human contact (${state.turn_count} turns) in a high-stakes domain (${stateDomains.filter(d => HIGH_STAKES_DOMAINS.includes(d)).join(', ')}). Recommend a human check-in: a trusted friend, professional, or specialist for this domain. Stay supportive but do not be a substitute for that contact.`);
}
// v1.2: Validation-seeking domain-gated alert (paper Figure A4).
// Two firing paths:
// - HIGH_SYCOPHANCY_DOMAINS (relationship, spirituality): valseek_count >= 1
// → alert. These domains see ~20% pushback rate dominated by validation-pressing.
// - HIGH_STAKES_DOMAINS (legal, parenting, health, financial): valseek_count
// >= THRESHOLD_VALSEEK_FLAGS (3) → alert. Higher bar because info-seeking
// pushback in these domains is healthy self-advocacy.
const valseekCount = Number(state.valseek_count) || 0;
const inHighSycophancy = domainsIntersect(stateDomains, HIGH_SYCOPHANCY_DOMAINS);
const inHighStakes = domainsIntersect(stateDomains, HIGH_STAKES_DOMAINS);
if (inHighSycophancy && valseekCount >= 1) {
warnings.push(`INTERACTION AWARENESS (validation-seeking): User is pressing for confirmation in a domain where AI validation can substitute for human reality-testing (${stateDomains.filter(d => HIGH_SYCOPHANCY_DOMAINS.includes(d)).join(', ')}). Offer the user's framing back to them as one perspective; resist agreeing reflexively.`);
} else if (inHighStakes && valseekCount >= THRESHOLD_VALSEEK_FLAGS) {
warnings.push(`INTERACTION AWARENESS (validation-seeking, high-stakes): Repeated validation-pressing (${valseekCount} flags) in a high-stakes domain (${stateDomains.filter(d => HIGH_STAKES_DOMAINS.includes(d)).join(', ')}). Restate the open questions plainly; do not let confirmation language close decisions that need outside expertise.`);
}
if (warnings.length > 0) {
// Fatigue bypasses cooldown
if (fatHit === 1 || checkCooldown(COOLDOWN_SOFT)) {