◆ NFRGate / Rule Reference
🛡️ Code verification for the AI era

Every rule your merges are held to.

NFRGate catches missing logs, metrics, traces, and reliability gaps — static analysis plus LLM judgment, gating CI/CD before they ever reach production.

$pip install nfrgate
16Rules enforced
4NFR categories
4Languages
Python Java Go Rust preview

How it works

The same loop SonarQube popularized for code quality — applied to non-functional requirements, with every confidence number measured, not guessed.

1

A pull request opens

The CI job reads only the diff — changed lines in Python, Java, Go, and Rust (preview) files.

2

Every change is checked

Static rules for logs, metrics, traces, and reliability, plus an optional LLM review for what no static rule can see.

3

Each finding is routed

By measured confidence and the service's criticality — a merge is only blocked at 0.85+ confidence.

Auto-passHuman reviewBlock merge

See it catch real problems

Ordinary code with common observability gaps — and exactly what NFRGate reports on it.

payments/client.py
1import logging2import requests34logger = logging.getLogger(__name__)567def charge(order):8    try:9        resp = requests.post("https://api.example.com/charge", json=order)10        return resp.json()11    except Exception:12        pass
  • FAILL1No swallowed exceptionsline 11

    Empty or pass-through handler (bare `pass` or a no-op re-raise) — the exception is swallowed with no log entry.

    confidence 0.71→ Flagged for human review
  • FAILL2Structured error logsline 11

    No logging call found in this except block.

    confidence 0.78→ Flagged for human review

Not a mock-up: these findings were produced by running NFRGate's own analyzer on this code when this page was built, and routed as they would be for a tier1 service. The tick on each confidence bar marks the 0.85 blocking threshold.

See what your team sees

One comment per PR/MR, updated on every push — not a wall of separate bot comments.

Pull Request #482 · payments-service Example
🤖 nfrgate-bot commented

NFR Gate — Static Analysis

2 fail (2 blocking) · 6 pass · 1 unclear across 4 changed files.

CRITICALR1payments/client.py:88outbound call has no timeout configured
HIGHT1payments/client.py:88call not wrapped in a trace span
PASSL2payments/client.py:102structured error log present

Drops into the CI you already run

Complete, runnable job definitions — not just the invocation line. Both read the diff, post the comment, and fail the job on a blocking violation.

.github/workflows/nfrgate.yml

name: NFRGate

on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read
  pull-requests: write   # needed to post/update the PR comment

jobs:
  nfrgate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0   # full history -- pr_gate.py diffs base...head, a shallow clone can't resolve an arbitrary base SHA

      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - run: pip install nfrgate

      - name: Run NFRGate
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: python -m nfr_gate.ci.pr_gate

Coverage at a glance

Static rules implemented per language and category — computed from the rule registry itself.

Language📝 Logs📊 Metrics🛡️ Reliability🔍 Traces
Python4/43/43/44/4
Java4/43/43/44/4
Go4/43/43/44/4
Rust preview4/43/43/44/4

M4, R4 are judged by the LLM review from the PR/MR text, in every language.

Rule Reference

Every rubric criterion this platform checks: what it checks, why, and (where a static evaluator exists) exactly how, per language.

Category
Severity
Language

📝 logs
L1highNo swallowed exceptions Go Java Python Rust
L2mediumStructured error logs Go Java Python Rust
L3mediumSeverity matches reality Go Java Python Rust
L4mediumCorrelatable with traces Go Java Python Rust
📊 metrics
M1highLatency is measurable Go Java Python Rust
M2highOutcome is measurable Go Java Python Rust
M3highCardinality is bounded Go Java Python Rust
🛡️ reliability
R1criticalTimeouts are explicit Go Java Python Rust
R2criticalRetries back off Go Java Python Rust
R3highDegradation is defined Go Java Python Rust
🔍 traces
T1highSpans on external calls Go Java Python Rust
T2mediumSpans carry useful attributes Go Java Python Rust
T3highContext propagates Go Java Python Rust
T4mediumErrors marked on the span Go Java Python Rust

No rules match these filters.

Frequently asked questions

What does NFRGate check?

16 rules across logs, metrics, traces, and reliability — things like swallowed exceptions, missing timeouts, and external calls without trace spans. Every rule has its own page in the rule reference.

Which languages does it support?

Static analysis covers Python, Java, and Go, plus Rust in preview: Rust findings aren't calibrated yet, so every one is routed to a human reviewer rather than blocking. A few judgment-call criteria are assessed by the optional LLM review from the PR/MR text, regardless of language.

Will it block my merges?

Only when a check fails with at least 0.85 measured confidence, on a medium, high, critical-severity rule, for a service that isn't tier0. Everything else is posted as a finding for human review — nothing is silently dropped. A tier0 (customer-critical) service always goes to a human.

Do I need an LLM or an API key?

No. Static analysis, routing, and blocking work out of the box. The LLM review is optional: it defaults to a local Ollama model, or you can set NFR_GATE_LLM_BACKEND=anthropic with an ANTHROPIC_API_KEY.

Is my code sent anywhere?

Static analysis runs entirely inside your own CI job — no code leaves it.

The LLM review defaults to a local Ollama model, so nothing leaves your infrastructure either. Only if you set NFR_GATE_LLM_BACKEND=anthropic are the diff and the PR/MR title and description sent to Anthropic's API for assessment.

Findings go only where you point them: the comment on your own PR/MR, your own findings database (NFR_GATE_DATABASE_URL), and Slack or Jira if you configure those.

Does it work on GitHub-hosted and GitLab shared runners?

Yes — the job definitions in the guide run on standard hosted runners. A hosted runner can't reach a local Ollama model, so for the LLM review there use the Anthropic backend or a self-hosted runner.

How do I try it?

pip install nfrgate, then add the GitHub Actions or GitLab CI job from the user guide — or click Setup help at the bottom right for a step-by-step walkthrough.