This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Monday, 08 December 2025
De meeste softwarearchitecturen gaan ervan uit dat het systeem statisch is. DiSE gaat ervan uit dat het systeem in leven is.
Opmerking: Dit is deel 4 in de serie "Cooking with DiSE." Deel 1, Deel 2: Afgestudeerde leerlingen, en Deel 3: Onbetrouwbare Goden voor achtergrond. Dit artikel is het architectonisch overzicht - en nu hebben we een werkende C# implementatie: meestallucid.botdetection.
Sleutelconcept: Gedrags-Routing. Deze architectuur maakt een nieuwe categorie - waar transparante, instelbare "teams" van detectoren en leersystemen reflexieve route verkeer op basis van geleerd gedragspatronen, niet statische regels. YARP Gateway, bots nooit uw backend bereiken. Of gebruik de middleware om gedragsrouting direct in uw app laag te bouwen.
Jarenlang hebben we software gebouwd zoals klokwerk: inputs, outputs, regels, pijpleidingen, testen, implementaties. Allemaal lineair, allemaal voorspelbaar.
Maar moderne systemen - vooral AI-augmented systemen - gedragen zich niet langer als klokken. Ze gedragen zich als ecosystemen:
Statische architecturen houden het niet bij. Je patcht een gat, drie verschijnen. Je richt één drempel af, iets anders breekt. Je reageert altijd, je past je nooit aan.
DiSE-architectuur (Directed Synthetic Evolution) behandelt software zoals biologen organismen behandelen: als iets dat zich moet aanpassen, zichzelf moet corrigeren en onder druk moet verbeteren.
Traditionele architectuur:
flowchart LR
B[Build] --> S[Ship] --> P[Patch] --> B
style B stroke:#6366f1,stroke-width:2px
style P stroke:#ef4444,stroke-width:2px
DiSE-architectuur:
flowchart LR
P[Perceive] --> E[Evaluate] --> M[Mutate] --> S[Select] --> P
style P stroke:#10b981,stroke-width:2px
style M stroke:#f59e0b,stroke-width:2px
style S stroke:#6366f1,stroke-width:2px
Een DiSE-systeem heeft vier essentiële gedragingen:
Gedrag Wat het doet . . Biologisch equivalent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . wat het . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |-----------|--------------|----------------------| | Perceïef Verzamel signalen uit de omgeving Sensory orgels | Evaluatie Score signalen tegen doelen Zenuwstelsel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . | Muteren Genereer varianten van strategieën . . Genetische mutatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . | Selecteren Hou wat werkt, wat niet weggooit Natuurlijke selectie
Dit is geen metafoor, dit is letterlijk hoe je systeem slimmer gedrag evolueert in de loop van de tijd.
meestallucid.botdetection is de eerste C# implementatie van DiSE principes. Laten we de architectuur volgen:
Het systeem maakt gebruik van een blackboard orkestator - detectoren dragen bij tot een gedeelde staat, waardoor andere detectoren als signalen zich ophopen:
// Detectors emit contributions (evidence), not verdicts
public sealed record DetectionContribution
{
public required string DetectorName { get; init; }
public required string Category { get; init; }
// Positive = bot signal, Negative = human signal
public required double ConfidenceDelta { get; init; }
public double Weight { get; init; } = 1.0;
public required string Reason { get; init; }
public BotType? BotType { get; init; }
// Signals for triggering other detectors
public ImmutableDictionary<string, object> Signals { get; init; }
}
Meerdere detectoren draaien in parallelle golven. Elk draagt een bewijsstuk. Het systeem ziet de omgeving door middel van vele lenzen:
// Wave 0: All detectors with no trigger conditions run in parallel
// Wave N: Detectors whose triggers are now satisfied run in parallel
while (waveNumber < MaxWaves && !cancellationToken.IsCancellationRequested)
{
var readyDetectors = availableDetectors
.Where(d => !ranDetectors.Contains(d.Name))
.Where(d => CanRun(d, state.Signals))
.ToList();
await ExecuteWaveAsync(readyDetectors, state, aggregator, ...);
// Check for early exit on high confidence
if (aggregator.ShouldEarlyExit)
break;
}
Bewijs aggregaten in een beslissing met behulp van sigmoid transformatie - dit goed gebruikt sterke signalen van hooggewicht detectoren:
private (double botProbability, double confidence) CalculateWeightedScore()
{
var weighted = _contributions
.Where(c => c.Weight > 0)
.Select(c => (delta: c.ConfidenceDelta, weight: c.Weight))
.ToList();
var weightedSum = weighted.Sum(w => w.delta * w.weight);
// Sigmoid maps any real number to (0, 1)
// Strong human signal (-3) → ~5% bot probability
// Neutral (0) → 50% bot probability
// Strong bot signal (+3) → ~95% bot probability
var botProbability = 1.0 / (1.0 + Math.Exp(-weightedSum));
return (botProbability, confidence);
}
De evaluatie is geen enkel model dat een beslissing neemt. gewogen consensus over meerdere gespecialiseerde detectoren - en cruciaal, als AI niet is uitgevoerd, de kans is geklemd om overmoedigheid te vermijden:
// CRITICAL: Clamp probability when AI hasn't run
var botProbability = aiRan
? rawBotProbability
: Math.Clamp(rawBotProbability, 0.20, 0.80);
Het systeem draait niet altijd alle detectoren.
// Early exit on verified bots (good or bad)
public static DetectionContribution VerifiedGoodBot(
string detector, string botName, string reason) => new()
{
DetectorName = detector,
Category = "Verification",
ConfidenceDelta = 0,
TriggerEarlyExit = true,
EarlyExitVerdict = EarlyExitVerdict.VerifiedGoodBot
};
In productie, verzoeken om een hoog vertrouwen te verlaten in minder dan 10 m na slechts 2-3 detectoren akkoord. De volledige pijpleiding loopt alleen voor onzekere gevallen.
Detectoren kunnen falen. Het systeem beschermt zichzelf:
// Circuit breaker per detector
private void RecordFailure(string detectorName)
{
var state = _circuitStates.GetOrAdd(detectorName, _ => new CircuitState());
state.FailureCount++;
state.LastFailure = DateTimeOffset.UtcNow;
if (state.FailureCount >= CircuitBreakerThreshold)
{
state.State = CircuitBreakerState.Open;
// Detector disabled until reset time passes
}
}
Foute detectoren zijn tijdelijk uitgeschakeld. Na een afkoeling worden ze opnieuw geprobeerd (halfopen toestand). selectiedruk op het niveau van de infrastructuur.
Wanneer het systeem detecteert met hoog vertrouwen, het leert door het publiceren aan de leerevenementenbus:
private void PublishLearningEvent(AggregatedEvidence result, ...)
{
var eventType = result.BotProbability >= 0.8
? LearningEventType.HighConfidenceDetection
: LearningEventType.FullDetection;
_learningBus.TryPublish(new LearningEvent
{
Type = eventType,
Confidence = result.Confidence,
Label = result.BotProbability >= 0.5,
Metadata = new Dictionary<string, object>
{
["botProbability"] = result.BotProbability,
["categoryBreakdown"] = result.CategoryBreakdown,
["contributingDetectors"] = result.ContributingDetectors
}
});
}
Dit voedt zich in de weight store, het bijwerken van de heuristische detector's geleerd gewichten in de tijd.
In plaats van een enkele "AI brain," gebruikt DiSE gelaagde cognitie:
flowchart TB
subgraph Fast["Fast Path (< 100ms)"]
H[Static Heuristics]
D[Detectors]
ML[Learned Heuristic Model]
end
subgraph Slow["Slow Path (Async)"]
LLM[Ollama LLM]
end
subgraph Learn["Learning Layer"]
W[Weight Store]
Rep[Reputation]
end
Fast --> |escalate uncertain| Slow
Slow --> |label| Learn
Learn --> |update weights| Fast
style Fast stroke:#10b981,stroke-width:2px
style Slow stroke:#6366f1,stroke-width:2px
style Learn stroke:#f59e0b,stroke-width:2px
Laag: Snelheid: Doel: Botdetectie Voorbeeld: |-------|-------|---------|----------------------| | Statische heuristiek Instinctieve reacties Bekende bot UA patronen | Detectoren * <10ms * Trait observation * * Header analysis, IP checks * | Learned Heuristic Dynamische classificatie Logistieke regressie met geleerde gewichten | LLM Het analyseren van nieuwe patronen | Leren Achtergrond Geheugenvorming Gewichtsupdates, reputatieveranderingen
Het belangrijkste inzicht: het systeem leert zijn eigen gewichten in real-time. Geen externe ML-modellen nodig. De heuristische detector begint met verstandige standaards en evolueert op basis van detectiefeedback.
Toekomst: ONNX modellen met RAG en inbedding zijn gepland voor v2. De huidige heuristische model output dient als gelabeld trainingsgegevens voor toekomstige modeltraining. De architectuur heeft al de "genetische" artefacten (bijdragen, gewichten, signalen) die het toevoegen van gerichte synthetische evolutie eenvoudig - het is ontworpen als een plugin punt.
Dit weerspiegelt biologische cognitie:
In plaats van een extern ML-model te verschepen, leert het systeem zijn eigen classifier met behulp van eenvoudige logistieke regressie met dynamische extractie:
public class HeuristicDetector : IDetector
{
// Default weights - sensible starting points
private static readonly Dictionary<string, float> DefaultWeights = new()
{
// Human-like patterns (negative = more likely human)
["hdr:accept-language"] = -0.6f,
["hdr:referer"] = -0.4f,
["fp:received"] = -0.7f, // Fingerprint = strong human signal
["fp:legitimate"] = -0.8f,
// Bot indicators (positive = more likely bot)
["ua:contains_bot"] = 0.9f,
["ua:headless"] = 0.8f,
["ua:selenium"] = 0.7f,
["ua:curl"] = 0.6f,
["accept:wildcard"] = 0.4f,
};
private (bool IsBot, double Probability) RunInference(Dictionary<string, float> features)
{
// Simple linear model: score = bias + Σ(feature * weight)
float score = _bias;
foreach (var (featureName, featureValue) in features)
{
var weight = _weights.TryGetValue(featureName, out var w)
? w
: DefaultNewFeatureWeight;
score += featureValue * weight;
}
// Sigmoid gives us probability
var probability = 1.0 / (1.0 + Math.Exp(-score));
return (probability > 0.5, probability);
}
}
Kenmerken worden dynamisch uit het verzoek en geaggregeerde bewijsmateriaal gehaald:
public static class HeuristicFeatureExtractor
{
public static Dictionary<string, float> ExtractFeatures(
HttpContext context,
AggregatedEvidence evidence)
{
var features = new Dictionary<string, float>();
// Request metadata
features["req:header_count"] = Math.Min(headers.Count / 20f, 1f);
features["req:cookie_count"] = Math.Min(cookies.Count / 10f, 1f);
// Header presence
features["hdr:accept-language"] = headers.ContainsKey("Accept-Language") ? 1f : 0f;
// UA patterns (dynamic - only present if detected)
if (ua.Contains("bot")) features["ua:contains_bot"] = 1f;
if (ua.Contains("selenium")) features["ua:selenium"] = 1f;
// Detector results (named by actual detector)
foreach (var contrib in evidence.Contributions)
features[$"det:{contrib.DetectorName}"] = contrib.ConfidenceDelta;
// Client-side fingerprint - STRONG human signal
if (hasFingerprint)
{
features["fp:received"] = 1f;
features["fp:legitimate"] = 1f;
}
return features;
}
}
Nieuwe functies automatisch krijgen standaard gewichten en leren na verloop van tijd. Het systeem ontdekt wat er toe doet.
Weights persist in SQLite en update via exponentieel bewegend gemiddelde:
public class SqliteWeightStore : IWeightStore
{
public async Task RecordObservationAsync(
string signatureType,
string signature,
bool wasBot,
double detectionConfidence,
CancellationToken ct = default)
{
// EMA update: weight = weight * (1 - α) + new_value * α
var alpha = 0.1; // Learning rate
var weightDelta = wasBot ? detectionConfidence : -detectionConfidence;
var sql = @"
INSERT INTO learned_weights (signature_type, signature, weight, ...)
VALUES (@type, @sig, @delta, ...)
ON CONFLICT(signature_type, signature) DO UPDATE SET
weight = weight * (1 - @alpha) + @delta * @alpha,
confidence = MIN(1.0, confidence + @conf * 0.01),
observation_count = observation_count + 1,
last_seen = @now
";
await ExecuteAsync(sql, ...);
}
}
Dit is mutatie door observatieElke detectie leert het systeem iets. Na verloop van tijd komen de gewichten samen naar optimale waarden voor uw specifieke verkeerspatronen.
In DiSE is hallucinatie geen insect, maar het generatieve substraat van evolutie.
Een hoge temperatuur LLM voorstellen tien varianten van een detectieregel is niet "hallucineren" - het is muteren van het genoom van het systeem:
public async Task<List<DetectionRule>> GenerateMutationsAsync(DetectionContext context)
{
var prompt = $"""
Given this traffic pattern:
{JsonSerializer.Serialize(context)}
Generate 5 variant detection rules that might catch similar patterns.
Return JSON array of rules with: pattern, weight, confidence.
Be creative. Some variants should be strict, some lenient.
""";
var response = await _ollama.GenerateAsync(new GenerateRequest
{
Model = "gemma3:1b",
Prompt = prompt,
Options = new RequestOptions { Temperature = 0.9 } // High creativity
});
return ParseRules(response.Response);
}
De mutaties worden vervolgens geëvalueerd aan de hand van historische gegevens:
public async Task<DetectionRule?> SelectFittestAsync(
List<DetectionRule> mutations,
List<LabeledRequest> testData)
{
var results = new List<(DetectionRule Rule, double Fitness)>();
foreach (var rule in mutations)
{
var tp = testData.Count(r => rule.Matches(r) && r.IsBot);
var fp = testData.Count(r => rule.Matches(r) && !r.IsBot);
var fn = testData.Count(r => !rule.Matches(r) && r.IsBot);
// F1 score as fitness
var precision = tp / (double)(tp + fp);
var recall = tp / (double)(tp + fn);
var f1 = 2 * (precision * recall) / (precision + recall);
results.Add((rule, f1));
}
return results.OrderByDescending(r => r.Fitness).First().Rule;
}
Alleen de fittest overleeft de productie. Dit verandert LLM's van broze chatbots in evolutionaire actoren.
In het centrum van DiSE bevindt zich de Beleidssysteem - benoemde configuraties die bepalen hoe detectie zich gedraagt:
{
"Policies": {
"fastpath": {
"Description": "Fast path + Heuristic for sync decisions",
"FastPath": ["UserAgent", "Header", "Ip", "Behavioral", "ClientSide", "Inconsistency", "VersionAge"],
"AiPath": ["Heuristic"],
"EscalateToAi": true,
"EarlyExitThreshold": 0.15,
"ImmediateBlockThreshold": 0.90,
"Weights": {
"ClientSide": 0.2,
"Heuristic": 1.5
},
"Transitions": [
{ "WhenRiskExceeds": 0.5, "WhenRiskBelow": 0.85, "GoTo": "demo" }
]
},
"demo": {
"Description": "Full pipeline sync for demonstration",
"FastPath": [],
"AiPath": [],
"BypassTriggerConditions": true,
"ForceSlowPath": true
}
}
}
Het beleid bepaalt:
Het systeem kan overgang tussen het beleid halverwege het verzoek. Onbepaalde snelle resultaten escaleren naar de volledige demo pijplijn. Dit is adaptieve routering - Het genoom reageert real-time op bewijs.
Je verstuurt geen statische configs. gedragssoorten die zich aanpassen aan het verkeer.
Elk DiSE-systeem optimaliseert tegen een fitnesslandschap:
public class FitnessEvaluator
{
public double Evaluate(GenomeConfig genome, EvaluationData data)
{
var fpRate = data.FalsePositives / (double)data.TotalHumans;
var fnRate = data.FalseNegatives / (double)data.TotalBots;
var latency = data.P99LatencyMs;
var cost = data.AiCallsPerRequest * _config.CostPerAiCall;
// Multi-objective fitness
return 1.0
- (fpRate * _config.FalsePositivePenalty) // Don't block humans
- (fnRate * _config.FalseNegativePenalty) // Don't miss bots
- (latency / _config.MaxLatencyMs) // Stay fast
- (cost / _config.MaxCostPerRequest); // Stay cheap
}
}
We optimaliseren niet alleen voor nauwkeurigheid. overleving in een dynamische omgeving.
Te veel AI → hoge kosten, slechte latentie. Te weinig AI → slechte detectie van nieuwe aanvallen. Te agressief → valse positieven, boze gebruikers. Te mild → botoverstromingen.
Het systeem moet een stabiel evenwicht vinden.
Een volwassen DiSE systeem verschuift AI van het hete pad:
flowchart TB
subgraph Early["Early Stage"]
AI1[AI handles most cases]
end
subgraph Middle["Middle Stage"]
AI2[AI handles edge cases]
H1[Heuristics handle common cases]
end
subgraph Mature["Mature Stage"]
AI3[AI teaches and mutates]
H2[Heuristics handle almost everything]
M[Memory provides context]
end
Early --> Middle --> Mature
style Early stroke:#ef4444,stroke-width:2px
style Middle stroke:#f59e0b,stroke-width:2px
style Mature stroke:#10b981,stroke-width:2px
Na verloop van tijd:
AI wordt:
Geen runtime afhankelijkheid, adaptieve steigers.
Met de YARP Gateway, deze architectuur maakt iets nieuws mogelijk: gedragsgeleiding.
Traditionele routering is statisch: pad → backend. Gedragsroutering is reflexief: verkeerskenmerken → dynamische routeringsbeslissingen.
flowchart LR
subgraph Gateway["YARP Gateway"]
D[Detector Team]
P[Policy Engine]
R[Router]
end
Traffic[Traffic] --> D
D --> P
P --> R
R -->|Human| App[Your App]
R -->|Bot| Block[403]
R -->|Uncertain| Challenge[Challenge]
R -->|Learning| Queue[Async Analysis]
style Gateway stroke:#10b981,stroke-width:2px
De kernbegrippen:
Dit is niet alleen "botdetectie aan de rand." Het is een nieuwe route primitief waar verkeersstromen worden gevormd door geleerd gedragspatronen, niet alleen statische regels.
De meeste technische culturen vrezen:
DiSE gebruikt deze als bouwmaterialen.
Statische systemen sterven. Evoluerende systemen overleven.
Elke industrie die te maken heeft met tegenstanders, drift, of schaal druk zal uiteindelijk nodig hebben architecturen als deze:
Laat me duidelijk zijn over wat dit niet is:
DiSE wordt gecontroleerd, verklarende evolutie:
Het is geregisseerd evolutie - geleid, niet willekeurig.
meestallucid.botdetection implementeert deze beginselen:
dotnet add package Mostlylucid.BotDetection
builder.Services.AddBotDetection();
app.UseBotDetection();
Configureren voor productie met leren ingeschakeld:
{
"BotDetection": {
"BotThreshold": 0.7,
"Policies": {
"default": {
"FastPath": ["UserAgent", "Header", "Ip", "Behavioral", "ClientSide", "Inconsistency", "VersionAge"],
"AiPath": ["Heuristic", "Llm"],
"EscalateToAi": true,
"EarlyExitThreshold": 0.85
}
},
"AiDetection": {
"Provider": "Heuristic",
"Heuristic": {
"Enabled": true,
"LoadLearnedWeights": true,
"EnableWeightLearning": true,
"LearningRate": 0.01
}
}
}
}
Kijk hoe het evolueert. De heuristische detector leert van elk verzoek, het bijwerken van zijn gewichten aan uw verkeerspatronen.
DiSE Architectuur is de verschuiving van software als machines naar software als organismen.
Het is de architectuur van:
Statische architecturen kunnen dynamische omgevingen niet bijhouden. Aanvallers evolueren. Gebruikers evolueren. Vereisten evolueren.
Systemen moeten ook evolueren.
Als je systemen wilt die alleen draaien, bouw ze dan op de oude manier. Als je systemen wilt overleven - bouw ze met DiSE.
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.