If you ask an AI engineer today how to build an app that detects when developers disagree, most of them are likely to propose something like this:
"Take the entire team Slack transcript, feed it into a giant system prompt with GPT-4, and ask: 'Did anyone say something contradictory?'"
When we started designing Isolyne for Shipaton 2026, we tested that exact approach. It was a disaster.
Here is why prompt-based conflict detection fails in the real world:
For Isolyne, we established a non-negotiable architectural law: The LLM interprets natural language into structured signals, but it NEVER evaluates team alignment.
Alignment detection belongs to pure, deterministic math.
We split our intelligence pipeline into two distinct layers with an ironclad boundary:
[ Natural Language Chat ]
│
▼
"We're going with Postgres for the database"
│
▼
┌───────────────────────────────────────────────────────────┐
│ LAYER 1: THE INTERPRETER (Gemini 1.5 Flash) │
│ │
│ Extracts structured schema ONLY: │
│ { topic: "Database", choice: "PostgreSQL" } │
└─────────────────────────────┬─────────────────────────────┘
│
(Appends Immutable Signal)
│
▼
┌───────────────────────────────────────────────────────────┐
│ LAYER 2: THE CQRS EVALUATOR (Pure TypeScript) │
│ │
│ Replays State ──► Set Theory ──► Deterministic Gaps │
│ │
│ • Consensus Gaps (Contradictory Choices) │
│ • Ownership Gaps (Decisions floating without an Owner) │
└───────────────────────────────────────────────────────────┘
Once Layer 1 extracts a structured decision, Layer 2 evaluates shared reality using pure mathematical detectors.
A Consensus Gap occurs when two or more team members state incompatible choices for the same topic.
Instead of asking an AI if the choices conflict, our ConsensusGapDetector runs in O(N) time using standard hash maps and sets:
import { GapDetector } from './GapDetector';
import { RealityState } from '../domain/RealityState';
import { AwarenessGap } from '../domain/AwarenessGap';
export class ConsensusGapDetector implements GapDetector {
detect(state: RealityState): AwarenessGap | null {
const topicDecisions = new Map<
string,
Array<{
actorId: string;
choice: string;
verbatim?: string;
}>
>();
// 1. Group active beliefs by topic
for (const dec of state.decisions) {
if (!topicDecisions.has(dec.topic)) {
topicDecisions.set(dec.topic, []);
}
topicDecisions.get(dec.topic)!.push({
actorId: dec.actorId,
choice: dec.choice,
verbatim: dec.verbatim
});
}
// 2. Mathematically evaluate unique choices per topic
for (const [topic, decisions] of topicDecisions.entries()) {
const uniqueChoices = new Set(decisions.map(d => d.choice));
// If more than 1 choice exists for a single topic, flag a potential conflict
if (uniqueChoices.size > 1) {
const safeTopic = topic
.replace(/[^a-zA-Z0-9]/g, '_')
.toLowerCase();
return {
id: `gap_consensus_${safeTopic}`, // Stable ID supports alert deduplication
type: 'consensus_gap',
hiddenReality: `Your team is running with different assumptions about ${topic}. Aligning now will save hours of rework.`,
evidence: decisions,
topic
};
}
}
return null;
}
}
id: gap_consensus_${safeTopic})Notice the ID formula: gap_consensus_database.
In a distributed or event-sourced app, if two users evaluate the state at the exact same moment, generating random UUIDs could create duplicate alerts on screen. Because our gap IDs are derived deterministically from the topic name, the evaluation pipeline produces a stable identifier for the same normalized topic.
The storage or UI layer can then use that identifier to deduplicate alerts. Topic normalization and collision handling still matter because different topic names can produce the same sanitized value.
Not all team risks are disagreements. The most dangerous architectural drift often happens when a critical decision is floating with nobody accountable for it.
Our OwnershipGapDetector ensures that as soon as a squad expands beyond a solo founder, decisions must have an assigned owner:
export class OwnershipGapDetector implements GapDetector {
detect(state: RealityState): AwarenessGap | null {
// If the team has multiple members but no project lead is assigned
if (state.members.length > 1 && !state.ownership.ownerId) {
return {
id: `gap_ownership_${state.members.join('_')}`,
type: 'ownership_gap',
hiddenReality:
'The project decisions are floating without an owner. Assigning one ensures it won\'t block the team.',
evidence: []
};
}
return null;
}
}
Because our gap detection is mathematical rather than probabilistic:
uniqueChoices.size === 1. The radar stays calm and completely silent.┌────────────────────────────────────────────────────────────┐
│ ⚠️ DRIFT DETECTED: Database Assumptions Incompatible │
│ │
│ Evidence: │
│ • Alice: "We're going with Postgres for the database." │
│ → Extracted choice: PostgreSQL │
│ • Bob: "Let's use Mongo for rapid prototyping." │
│ → Extracted choice: MongoDB │
│ │
│ [ Choose PostgreSQL ] [ Choose MongoDB ] [ Discuss ] │
└────────────────────────────────────────────────────────────┘
Once a team resolves a consensus gap by tapping [ Choose PostgreSQL ], Isolyne records an immutable alignment_agree signal.
Through our RevenueCat Pro tier, isolyne_pro transforms these resolved gaps into a polished, exportable Architectural Decision Record (ADR).
While free users get unlimited real-time drift protection to keep their hackathon builds safe, Pro subscribers unlock the complete audit trail of how their architectural consensus was formed—monetizing the record of how you shipped without ever paywalling safety.