ai-slop-gate โ Canonical Architecture๏
Single source of truth:
ai_slop_gate_snapshot.json(v7.4.0) If this document diverges from the snapshot, the snapshot wins.
Stage: 6 (current) | Status: canonical
Architectural Principles๏
Principle |
Meaning |
|---|---|
No hidden logic |
Every decision is traceable to policy |
Policy is source of truth |
|
Compliance is a sidecar |
Runs alongside analysis, never inside it |
Engine is pure |
No IO, no printing, no exit calls |
CLI is thin |
Argument parsing and wiring only |
Tests lock contracts, not behavior |
Critical invariants, not implementation |
Cache is cost control, not performance |
LLM only, prevents duplicate token spend |
Execution Flow๏
CLI parses flags
โ Policy loaded and resolved
โ Providers collect or analyze inputs
โ LLM providers optionally wrapped by CachedProvider
โ Compliance sidecar optionally runs
โ Policy engine evaluates all observations
โ Decision produced (allow | advisory | blocking)
โ Reporters render output
โ Exit code derived from decision (0 | 1)
Directory Structure๏
ai_slop_gate/
โโโ cli/ # CLI entry points and subcommands (thin layer)
โ โโโ main.py # Entrypoint: python -m ai_slop_gate.cli.main
โ โโโ run.py # run command logic: run_analysis()
โ โโโ args.py # Argument parsing
โ โโโ context.py # Runtime context
โ โโโ logger.py # Logging setup
โ โโโ utils.py # CLI utilities
โโโ engine/
โ โโโ provider_factory.py # Instantiates providers from registry
โโโ domain/
โ โโโ observation.py # Observation dataclass (immutable)
โ โโโ decision.py # Decision dataclass (allow|advisory|blocking)
โ โโโ policy.py # PolicyRule dataclass
โ โโโ policy_engine.py # Evaluates observations โ Decision
โ โโโ checks.py # CheckReport
โ โโโ check_mapper.py # Maps checks to observations
โ โโโ signals.py # Signal definitions
โ โโโ contracts.py # Policy evaluation contracts
โ โโโ observation_factory.py
โ โโโ observation_result.py
โ โโโ compliance/ # Compliance sidecar
โ โโโ detector.py
โ โโโ enforcement.py
โ โโโ gateway.py
โ โโโ pipeline.py
โ โโโ profile_resolver.py
โ โโโ profiles.py
โ โโโ rules.py
โโโ providers/
โ โโโ base.py # BaseProvider ABC + ProviderObservation
โ โโโ registry.py # Provider registry
โ โโโ cached_provider.py # CachedProvider wrapper (LLM only)
โ โโโ rate_limit_guard.py
โ โโโ llm/
โ โ โโโ llm_provider.py # LlmProvider base (chunked file scanning)
โ โ โโโ gemini.py # GeminiProvider
โ โ โโโ groq.py # GroqProvider
โ โ โโโ ollama.py # OllamaProvider (local, no API key)
โ โ โโโ prompts/
โ โ โโโ gemini/deep.prompt
โ โ โโโ groq/deep.prompt
โ โ โโโ groq/fast.prompt
โ โ โโโ ollama/qwen.prompt
โ โ โโโ ollama/mistral.prompt
โ โโโ static/
โ โโโ static.py # StaticProvider (general)
โ โโโ static_security.py # StaticSecurityProvider
โ โโโ static_pipeline.py # StaticPipelineProvider
โ โโโ static_python.py # StaticPythonProvider
โ โโโ static_js.py # StaticJSProvider
โ โโโ static_ts_js.py # StaticTSJSProvider
โ โโโ static_docker.py # StaticDockerProvider
โ โโโ cpp_static.py # StaticCppProvider
โ โโโ csharp_static.py # StaticCSharpProvider
โ โโโ java_static.py # StaticJavaProvider
โ โโโ ruby_static.py # StaticRubyProvider
โ โโโ eslint.py # ESLintProvider (JS/TS rules)
โ โโโ k8s_static.py # KubernetesStaticProvider
โ โโโ k8s_runtime.py # K8sRuntimeProvider (kind: infra)
โ โโโ terraform_static.py # TerraformStaticProvider
โ โโโ terraform_plan.py # TerraformPlanProvider
โ โโโ supply_chain.py # SupplyChainProvider
โ โโโ trivy.py # TrivyProvider (CVE scanning)
โ โโโ sbom.py # SBOMProvider (Syft)
โ โโโ dead_code.py # DeadCodeProvider
โโโ reporters/
โ โโโ base.py # Reporter ABC
โ โโโ console.py # ConsoleReporter (stdout, human-readable)
โ โโโ github_pr.py # GitHubPRReporter (PR comments)
โ โโโ github_checks.py # GitHubChecksReporter (check-run annotations)
โ โโโ gitlab_mr.py # GitLabMRReporter (MR comments)
โ โโโ formatter.py # PR comment formatter
โโโ github/
โ โโโ pr_commenter.py # GitHub PR comment logic
โโโ cache/ # LLM response cache
โโโ rulesets/
โ โโโ eslint/ # ESLint rules for JS/TS
โ โโโ base.mjs
โ โโโ prod_safety.mjs
โ โโโ secrets.mjs
โโโ tests/
โโโ unit/
โโโ integration/
Core Contracts๏
ProviderObservation๏
Every provider must return this. It is immutable (frozen=True):
@dataclass(frozen=True)
class ProviderObservation:
provider: str
model: str
observations: List[Any] # list of Observation objects
raw_text: str
BaseProvider๏
class BaseProvider(ABC):
name: str
kind: str # "llm" | "static" | "infra"
@abstractmethod
def analyze(self, code: str, input_file: str = "") -> ProviderObservation:
# LLM: analyze PR diff or code snippet
...
@abstractmethod
def collect(self, base_path: str = ".") -> ProviderObservation:
# Static/infra: scan a directory
# LLM: delegates to LlmProvider.analyze_files() (chunked scan)
...
def analyze_pr(self, repo: str, pr_id: int, token: str) -> ProviderObservation:
# Optional: direct GitHub PR analysis
# Default raises NotImplementedError
...
Observation๏
@dataclass(frozen=True)
class Observation:
category: str # security | quality | architecture | ...
signal: str # snake_case identifier
confidence: float # 0.0 โ 1.0
message: str
severity: Optional[Severity]
evidence: Optional[Dict[str, Any]]
rule_id: Optional[str]
location: Optional[Location] # { file: str, line: Optional[int] }
Decision๏
@dataclass(frozen=True)
class Decision:
mode: DecisionMode # allow | advisory | blocking
reasons: List[str]
annotations: Optional[List[Annotation]]
Exit code mapping:
mode |
exit code |
|---|---|
|
0 |
|
0 |
|
1 |
Provider Inventory๏
LLM Providers (kind = "llm")๏
Class |
name |
Prompt files |
analyze_pr |
|---|---|---|---|
|
|
|
โ |
|
|
|
โ |
|
|
|
โ |
LLM providers support both analyze() (diff/snippet) and collect() (full repo via chunked scanning in LlmProvider.analyze_files()).
Static Providers (kind = "static")๏
Class |
name |
Language/Target |
|---|---|---|
|
|
General |
|
|
Security patterns |
|
|
CI/CD pipelines |
|
|
Python AST |
|
|
JavaScript |
|
|
TypeScript/JavaScript |
|
|
Dockerfile |
|
|
C++ |
|
|
C# |
|
|
Java |
|
|
Ruby |
|
|
JS/TS (ESLint rules) |
|
|
Kubernetes manifests |
|
|
Terraform HCL |
|
|
Terraform plan JSON |
|
|
Dependency risk |
|
|
CVE scanning |
|
|
SBOM generation (Syft) |
|
|
Unused code detection |
Infra Providers (kind = "infra")๏
Class |
name |
Target |
|---|---|---|
|
|
Kubernetes runtime |
Cache๏
Purpose: prevent repeated LLM token spending (not a performance cache)
Scope: LLM providers only โ never caches static providers
Integration: via
CachedProviderwrapperDefault location:
.ai-slop-cache/Cache key components:
provider_id+model+profile+policy_hash+normalized_input_fingerprintInvariant: same key must NEVER trigger an LLM call twice
Compliance Sidecar๏
Role: runs alongside analysis, never inside engine
Enabled by:
policy.compliance.enabledor--compliance/--compliance-onlyflagCapabilities: forbidden license detection (GPL, AGPL), secret detection, GDPR/DSGVO data residency enforcement
Profile |
Description |
|---|---|
|
inherits base compliance config |
|
enforces GPL/AGPL ban + EU residency |
|
blocking enforcement |
Reporters๏
Class |
Output |
Description |
|---|---|---|
|
stdout |
Human-readable, short or verbose mode |
|
GitHub PR |
Posts analysis as PR comment |
|
GitHub Checks |
Creates check-run with annotations |
|
GitLab MR |
Posts analysis as MR comment |
All reporters receive CheckReport and are provider-agnostic.
Non-Goals๏
Automatic code fixing
Code rewriting
Business logic inside CLI
Provider-specific policy logic
Caching for non-LLM providers