Skip to content

Repository files navigation

conversation-guard

A pure, deterministic decision engine for evaluating whether a conversation is worth continuing — framed as a network protocol between two endpoints.

Instead of debating what you're talking about, conversation-guard models how the exchange behaves: fallacy patterns, communication biases, energy cost, escalation, and whether the other party can accept nuance or only a boolean "you are right" payload.

No side effects. No hardcoded topics. Same inputs always produce the same output.

Why this exists

Most online arguments fail for structural reasons, not factual ones. People loop on bad-faith tactics, drain your attention, or need validation rather than refutation. This library encodes those patterns as explicit rules so you (or an upstream tool) can choose a tactic before sinking more time.

The HTTP status metaphor is intentional: conversations have contracts, timeouts, rejected payloads, and acceptable response codes.

Quick start

import { evaluateDiscussionState } from "./conversationGuard";
import type {
  InterlocutorProfile,
  ConversationState,
} from "./types/types";

const person: InterlocutorProfile = {
  knowledgeLevel: 25,
  confidenceLevel: 90,
  acceptsNuance: false,
  requiresBooleanTruePayload: true,
  reciprocityScore: 15,
  correctionReceptivity: 10,
  performativeCuriosity: true,
};

const state: ConversationState = {
  topicComplexity: 75,
  fallaciesDetected: ["StrawMan"],
  biasesDetected: ["Sealioning"],
  timeWastedMinutes: 6,
  myCurrentEnergy: 35,
  escalationTrend: "rising",
  claimDensityPerMinute: 5,
};

const result = evaluateDiscussionState(person, state);
// {
//   action: "ABORT_CONNECTION",
//   httpStatusCode: 408,
//   reason: "Request flood: claim density exceeded processing window without state advance."
// }

Project layout

conversation-guard/
├── conversationGuard.ts   # Core evaluator — priority-ordered rule chain
├── types/
│   └── types.ts           # Fallacy, CommunicationBias, profile & state interfaces
├── helpers/
│   └── helpers.ts         # Profile/pattern predicates used by the rule chain
└── package.json
Module Responsibility
conversationGuard.ts Single public entry: evaluateDiscussionState
types/types.ts Shared types for inputs and strategy output
helpers/helpers.ts Reusable checks (isGishGallop, isRigidEndpoint, etc.)

API

evaluateDiscussionState(person, state)

Evaluates the current conversation and returns a StrategyPayload.

Parameters

  • personInterlocutorProfile: stable traits of the other party
  • stateConversationState: dynamic signals from the ongoing exchange

ReturnsStrategyPayload:

Field Type Meaning
action ENGAGE | PIVOT_TO_CURIOSITY | SMILE_AND_NOD | ABORT_CONNECTION Recommended tactic
httpStatusCode number Semantic status (see below)
reason string Human-readable rationale for logging or UI

Actions

Action When to use it
ENGAGE Productive exchange — teach, debate, or validate as appropriate
PIVOT_TO_CURIOSITY Redirect with questions instead of direct correction or debate
SMILE_AND_NOD Low-cost acknowledgment to preserve energy (gray-rock / pacify)
ABORT_CONNECTION End the conversation — further exchange is net-negative

HTTP status codes

Code Meaning in this model
100 Continue — healthy or appropriate engagement
200 OK — passive/minimal response (energy preservation)
202 Accepted — redirect in progress (curiosity pivot)
406 Not acceptable — bad-faith or rigid contract violation
408 Request timeout — sunk cost or claim flood without progress

Input model

InterlocutorProfile

Describes the remote endpoint's behavioral contract.

Field Range Description
knowledgeLevel 0–100 Actual grasp of the subject
confidenceLevel 0–100 Assertiveness / volume of claims
acceptsNuance boolean Can process "both can be true"
requiresBooleanTruePayload boolean Only accepts total agreement
reciprocityScore 0–100 Acknowledges your points / asks back
correctionReceptivity 0–100 Facts land vs. trigger escalation
performativeCuriosity boolean Feigned curiosity (sealioning / JAQ)

A rigid endpoint is someone with requiresBooleanTruePayload: true and acceptsNuance: false. Many abort rules target this profile.

ConversationState

Describes the live session.

Field Description
topicComplexity 0–100 — keeps rules topic-agnostic
fallaciesDetected Detected bad-faith argument patterns
biasesDetected Detected communication biases
timeWastedMinutes Duration of the current loop
myCurrentEnergy 0–100 — your internal battery
escalationTrend 'stable' | 'rising' | 'falling'
claimDensityPerMinute Proxy for gish-gallop volume (≥ 4 triggers)

Detectable fallacies

StrawMan · MotteAndBailey · WeaponizedVulnerability · MovingGoalposts · AdHominem · Whataboutism · GishGallop

Detectable communication biases

DunningKruger · Sealioning · GishGallop · HostileAttribution · BackfireRisk · VentingNotDebating · ConfirmationLoop · IllusorySuperiority · ConversationalNarcissism

Decision pipeline

Rules run in strict priority order. The first match wins.

flowchart TD
    A[evaluateDiscussionState] --> B{Timeout / claim flood?}
    B -->|yes| ABORT[ABORT_CONNECTION 408]
    B -->|no| C{Rigid endpoint + toxic signals?}
    C -->|yes| ABORT2[ABORT_CONNECTION 406]
    C -->|no| D{Low energy?}
    D -->|yes| NOD[SMILE_AND_NOD 200]
    D -->|no| E{Venting?}
    E -->|yes| ENG[ENGAGE 100]
    E -->|no| F{Backfire / gish / confirmation / narcissism?}
    F -->|pivot path| PIV[PIVOT_TO_CURIOSITY 202]
    F -->|conserve| NOD2[SMILE_AND_NOD 200]
    F -->|no| G{Genuine learner / humble expert?}
    G -->|yes| ENG2[ENGAGE 100]
    G -->|no| H{Dunning-Kruger profile?}
    H -->|receptive| ENG3[ENGAGE 100]
    H -->|not receptive| PIV2[PIVOT_TO_CURIOSITY 202]
    H -->|no| I{Rigid endpoint remaining?}
    I -->|yes| PIV3[PIVOT_TO_CURIOSITY 202]
    I -->|no| FALL[ENGAGE 100 — healthy default]
Loading

Rule summary (priority order)

  1. Sunk cost — 10+ minutes with no nuance → abort (408)
  2. Sustained gish gallop — high claim density for 5+ minutes → abort (408)
  3. Rigid endpoint + fallacies → abort (406)
  4. Sealioning on rigid endpoint → abort (406)
  5. Hostile attribution + rising escalation on rigid endpoint → abort (406)
  6. Weaponized vulnerability on rigid endpoint → abort (406)
  7. Low energy on rigid endpoint or hostile attribution → smile and nod (200)
  8. Venting not debating → engage with validation, not correction (100)
  9. Backfire risk → nod if low receptivity/energy, else pivot (200 / 202)
  10. Gish gallop (first offense) → pivot to single-thread focus (202)
  11. Confirmation loop → pivot with falsifiability question (202)
  12. Conversational narcissism / low reciprocity → nod or pivot by energy (200 / 202)
  13. Genuine learner → engage and teach (100)
  14. Humble expert → peer-mode engage (100)
  15. Dunning-Kruger → engage if receptive, else pivot (100 / 202)
  16. Rigid endpoint with energy left → curiosity pivot before full debate (202)
  17. Fallback → healthy peer exchange (100)

Helper predicates

helpers/helpers.ts exports the building blocks used inside the rule chain. Useful if you're building detection upstream and want to mirror the same definitions:

  • isRigidEndpoint(person)
  • isGishGallop(person, state)
  • isSealioning(person, state)
  • isDunningKruger(person, state)
  • isGenuineLearner(person)
  • isHumbleExpert(person)
  • hasBias(biases, ...targets)
  • hasFallacy(fallacies, ...targets)

Design principles

  • Pure function — no I/O, no globals, no randomness
  • Topic-agnostic — complexity is a scalar, not a subject label
  • Energy-aware — your battery is a first-class input
  • Priority-ordered — safety and timeouts beat engagement optimism
  • Learner-safe — genuine learners are explicitly protected from Dunning-Kruger misrouting

License

ISC · @luke_official

About

Pure deterministic decision engine for evaluating whether a conversation is worth continuing

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages