DOCS / CONFIGURATION

Structured rules

Match typed incident fields with all/any/not conditions, comparisons, quantifiers, and required evidence—deterministically ranked and fully explainable.

PHASE 1 · PRE-1.0PYTHON 3.11+EDIT ON GITHUB ↗

Rule document

Each file contains one strict kind: DiagnosisRule. Evaluation is local, deterministic, and model-free. all requires every condition, any requires at least one when present, and not requires every listed condition to be false.

yaml
apiVersion: lumis.dev/v1
kind: DiagnosisRule
metadata:
  name: missing-required-column
  version: "1"
spec:
  priority: 100
  match:
    all:
      - field: log.text
        contains: KeyError
      - field: schema.diff.removed_count
        greaterThan: 0
      - field: components.references
        anyElement:
          prefix: dbt.model.
    any:
      - field: component.type
        equals: transformation
      - field: labels.pipeline_domain
        equals: data
    not:
      - field: incident.status
        equals: resolved
  diagnosis:
    classification: schema_change
    severity: high
    summary: A required field was unavailable.
    hypothesis: The upstream schema or normalization mapping changed.
    confidence: 0.8
    confirmedFacts:
      - The current schema contains at least one removed field.
    missingEvidence:
      - Previous successful schema
      - Upstream change record
  evidence:
    required: [schema_diff]
  recommendedNextSteps:
    - Compare the current and previous successful schemas.
  suggestedPlaybook: investigate_schema_contract

Operators and quantifiers

OperatorBehavior
containsCase-insensitive substring comparison.
equalsExact string, number, or boolean comparison.
prefixCase-sensitive string prefix.
matchesRegexPython regular-expression search, validated when the rule loads.
greaterThan / greaterThanOrEqual / lessThan / lessThanOrEqualNumeric comparison.
anyElement / allElementsExplicit quantifiers wrapping one scalar operator for list-valued fields.

Fields use dot paths (log.text, schema.diff.removed_count); callers may supply nested mappings or literal dotted keys. Empty lists fail both quantifiers, lists are limited to 100 scalar elements, and nested collections or oversized lists fail closed rather than being flattened or coerced to strings. Every condition defines exactly one operator—ambiguity fails validation.

Required evidence

spec.evidence.required is a hard match precondition: the rule cannot win until every required kind is supplied. spec.diagnosis.missingEvidence is different—it records follow-up context that would strengthen, contradict, or confirm an already-matched hypothesis. A value cannot appear in both lists.

Ranking and explanation

Matching candidates rank by descending priority, then descending specificity, then stable input order. Specificity weights all conditions twice, then counts any, not, and required-evidence entries. Every candidate—winner or not—exposes rule ID and version, priority, specificity, matched and failed conditions, missing required evidence, and evidence references. Quantified condition explanations include bounded actual values and matched element indexes.

python
from pathlib import Path

from lumis_sdk.adapters.deterministic import diagnose_structured
from lumis_sdk.config import load_diagnosis_rule
from lumis_sdk.domain import EvidenceItem

rule = load_diagnosis_rule(Path("rules/missing-required-column.yml"))
result = diagnose_structured(
    fields={
        "log": {"text": "ERROR KeyError: customer_id"},
        "schema": {"diff": {"removed_count": 1}},
        "component": {"type": "transformation"},
        "incident": {"status": "open"},
    },
    rules=[rule],
    evidence=[
        EvidenceItem(
            id="schema-diff-1",
            source="schema-registry",
            kind="schema_diff",
            detail="customer_id was removed",
            confidence=1.0,
            reference="schema://orders/current-vs-previous",
        )
    ],
)

if result.winner:
    print(result.winner.rule_id, result.selection_reason)
    print(result.winner.matched_conditions)
else:
    print(result.candidates[0].failed_conditions)

Validation and fixture testing

shell
lumis rules validate --config lumis.yml
lumis rules test --rule rules/schema-change.yml --input fixtures/schema-change.json

Fixture input contains a fields object and an optional evidence array of EvidenceItem objects. The command emits JSON suitable for CI assertions and editor integrations; input is bounded to one MiB and no network or model call is made.

Migrating from all_contains

  • Create one DiagnosisRule file per legacy rule; use metadata.name as the old id and metadata.version as the old version.
  • Replace every all_contains term with an all condition on log.text.
  • Move diagnosis fields under spec.diagnosis.
  • Replace adopter-side list flattening with explicit anyElement or allElements conditions.
  • Add required evidence and structured conditions where reliable signals exist.
  • Test matching, non-matching, empty and oversized lists, missing evidence, and tie fixtures.
  • Swap the project rule file list only after the complete collection passes—mixing engines is rejected.