Configuration Reference
Guard configuration is JSON-based, embedded in each node's process element definition. The runtime resolves configs from cache, templates, or groups — with a 15-minute TTL.
Top-Level Structure
The root key is "guardRails" within a node's configuration JSON:
{
"guardRails": {
"groups": [
"default-guard-rail-group",
"standard-security-group"
],
"mandatoryGroups": [
"compliance-audit-group"
],
"individual": [
{ "name": "TimeoutGuard", ... },
{ "name": "RateLimitingGuard", ... }
]
}
}
| Key | Type | Description |
|---|---|---|
groups | string[] | Named groups of guards. Each group is a pre-registered list of guard configs resolved by GuardConfigResolver. |
mandatoryGroups | string[] | Groups that always run and cannot be disabled by node-level overrides. |
individual | object[] | Specific guard instances with per-node config. Merged with group configs. |
Individual Guard Entry Fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Guard name — must match IGuardRailExecutor.Name exactly (case-sensitive) |
enabled | bool | yes | false skips this guard entirely |
order | int? | no | Execution order within the phase. null = default sequential order |
enableDelayedEnforcement | bool | no | Guard runs but does not immediately block — violations are checked after execution completes |
failMode | string | no | "block" (default) or "allow" — override the guard's blocking behavior at node level |
config | object | no | Guard-specific settings. Schema depends on the guard (see below). |
Complete Example: Full Node Config
{
"guardRails": {
"groups": ["default-guard-rail-group"],
"mandatoryGroups": ["compliance-audit-group"],
"individual": [
// 1. Timeout: block if node takes more than 5 seconds
{
"name": "TimeoutGuard",
"enabled": true,
"order": 1,
"config": { "timeoutMs": 5000, "action": "block" }
},
// 2. Input validation: require userId and amount fields
{
"name": "InputValidationGuard",
"enabled": true,
"order": 2,
"config": {
"schema": {
"type": "object",
"required": ["userId", "amount"],
"properties": {
"userId": { "type": "string" },
"amount": { "type": "number" }
}
},
"strictMode": true
}
},
// 3. Rate limiting: 50 requests/second per tenant
{
"name": "RateLimitingGuard",
"enabled": true,
"order": 3,
"config": { "rps": 50, "window": 60, "scope": "tenant" }
},
// 4. Circuit breaker: open after 5 failures, recover after 60s
{
"name": "CircuitBreakerGuard",
"enabled": true,
"order": 4,
"config": { "threshold": 5, "timeout": 60000 }
},
// 5. PII detection (Pre): block if SSN/Email/Phone in input
{
"name": "PiiDetectionGuard",
"enabled": true,
"order": 5,
"config": { "sensitivityLevel": "medium" }
},
// 6. PII redaction (Post): mask PII in output
{
"name": "PiiRedactionGuard",
"enabled": true,
"config": { "redaction_method": "mask" }
}
]
}
}
Config Resolution Chain
When the runtime needs a guard config for a given node, GuardConfigResolver resolves it in this order:
Check cache
Cache key: guard-config:{tenantId}:{nodeKey}. 15-minute TTL. If hit, return immediately.
Check templates
In-memory dictionary of registered templates (case-insensitive). If found, validates TimeoutMs via IGuardTimeoutValidator, caches result, returns.
Not found
Logs a warning and returns null. The guard is skipped for this execution.
Group Resolution
Groups are registered at startup:
await resolver.RegisterGroupAsync("default-guard-rail-group", new[] {
"timeout-config",
"rate-limit-tenant-config",
"circuit-breaker-config"
});
// When a node references "default-guard-rail-group", it expands to all three configs
Mandatory groups run even if the individual guard entry has "enabled": false. They cannot be bypassed at the node level.
Timeout Validation (Design A.10)
TimeoutMs, GuardConfigResolver calls IGuardTimeoutValidator.ValidateBounds(guardId, timeoutMs) at resolution time. If the guard timeout exceeds the node's configured timeout, an InvalidOperationException is thrown during startup — not at runtime. This catches misconfiguration before any request is processed.
Configuration Cache
| Property | Value |
|---|---|
| TTL | 15 minutes |
| Key format | guard-config:{tenantId}:{nodeKey} |
| Invalidation | TTL expiry only — no explicit invalidation |
| Implementation | GuardConfigCache — in-memory Singleton |
| Multi-tenancy | TenantId in key ensures per-tenant isolation |
SetConfiguration Pattern
Every guard receives its resolved config before execution via:
// Called by GuardConfigResolver / GuardFactory at resolution time
public void SetConfiguration(IDictionary<string, object?> configuration)
{
_configuration = configuration ?? new Dictionary<string, object?>();
}
// Guards read settings during ExecuteAsync (never during construction)
private int TimeoutMs => _configuration.TryGetValue("timeoutMs", out var v) ? (int)v : 5000;