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.
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.
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."
// }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.) |
Evaluates the current conversation and returns a StrategyPayload.
Parameters
person—InterlocutorProfile: stable traits of the other partystate—ConversationState: dynamic signals from the ongoing exchange
Returns — StrategyPayload:
| 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 |
| 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 |
| 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 |
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.
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) |
StrawMan · MotteAndBailey · WeaponizedVulnerability · MovingGoalposts · AdHominem · Whataboutism · GishGallop
DunningKruger · Sealioning · GishGallop · HostileAttribution · BackfireRisk · VentingNotDebating · ConfirmationLoop · IllusorySuperiority · ConversationalNarcissism
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]
- Sunk cost — 10+ minutes with no nuance → abort (
408) - Sustained gish gallop — high claim density for 5+ minutes → abort (
408) - Rigid endpoint + fallacies → abort (
406) - Sealioning on rigid endpoint → abort (
406) - Hostile attribution + rising escalation on rigid endpoint → abort (
406) - Weaponized vulnerability on rigid endpoint → abort (
406) - Low energy on rigid endpoint or hostile attribution → smile and nod (
200) - Venting not debating → engage with validation, not correction (
100) - Backfire risk → nod if low receptivity/energy, else pivot (
200/202) - Gish gallop (first offense) → pivot to single-thread focus (
202) - Confirmation loop → pivot with falsifiability question (
202) - Conversational narcissism / low reciprocity → nod or pivot by energy (
200/202) - Genuine learner → engage and teach (
100) - Humble expert → peer-mode engage (
100) - Dunning-Kruger → engage if receptive, else pivot (
100/202) - Rigid endpoint with energy left → curiosity pivot before full debate (
202) - Fallback → healthy peer exchange (
100)
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)
- 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
ISC · @luke_official