orchestrata_ultimate.factory.detectors.models
Reference › orchestrata_ultimate › factory › detectors › models
models defines the frozen data types of the C3 lexical and structural detector set (SPEC-033 row B22, ADR-0029). Tier names the three tiers by what they do: BLOCKING, ADVISORY and QUESTION. RuleMeta is static metadata for a rule (id, tier, provenance and an optional published precision). Finding is one detector hit with its line, span, matched text, message, weight, fingerprint and an optional question; Finding.new derives the fingerprint with finding_fingerprint, which hashes the rule id and the normalised context line with sha256, so a dismissal survives line moves. RATIONALE_WEIGHT (0.5) is the weight given to findings inside a rationale clause. DetectorReport holds findings, dismissed and files_scanned. It deliberately has no field such as complete or passed: under ADR-0011 no detector issues a completeness verdict, and the caller decides what to do with the list. The engine, rules, c1_bridge and decision phase modules import it.
At a glance
| Source | src/orchestrata_ultimate/factory/detectors/models.py |
| Lines of code | 124 |
| Classes | 4 |
| Functions | 1 |
| Imports (internal) | orchestrata_ultimate.factory.assumptions.models |
| Imported by | orchestrata_ultimate.factory.decision.phase, orchestrata_ultimate.factory.detectors.c1_bridge, orchestrata_ultimate.factory.detectors.engine, orchestrata_ultimate.factory.detectors.rules, scripts.factory_detectors |
| Tests that import it | tests/factory/test_detector_engine.py, tests/factory/test_detector_models.py, tests/factory/test_detector_rules.py |
Class diagram
Dependency diagram
API
Classes
Tier (enum)
Bases: StrEnum · Line 24
The three detector tiers, named by what they DO (ADR-0029).
| Member | Value |
|---|---|
BLOCKING |
'blocking' |
ADVISORY |
'advisory' |
QUESTION |
'question' |
RuleMeta (dataclass)
Decorators: dataclass(frozen=True) · Line 37
Static metadata for one detector rule.
| Attribute | Type | Default |
|---|---|---|
rule_id |
str |
|
tier |
Tier |
|
provenance |
str |
|
published_precision |
float | None |
Finding (dataclass)
Decorators: dataclass(frozen=True) · Line 66
One detector hit.
| Attribute | Type | Default |
|---|---|---|
rule_id |
str |
|
tier |
Tier |
|
line |
int |
|
span |
tuple[int, int] |
|
matched_text |
str |
|
message |
str |
|
weight |
float |
|
fingerprint |
str |
|
question |
str | None |
None |
| Method | Signature | Summary |
|---|---|---|
new classmethod |
new(*, rule_id: str, tier: Tier, line: int, span: tuple[int, int], matched_text: str, message: str, context_line: str, weight: float = 1.0, question: str | None = None) -> Finding |
Build a :class:Finding, deriving its fingerprint from context_line. |
DetectorReport (dataclass)
Decorators: dataclass(frozen=True) · Line 114
The result of one :func:~...engine.run_detectors call.
| Attribute | Type | Default |
|---|---|---|
findings |
list[Finding] |
|
dismissed |
list[Finding] |
|
files_scanned |
list[str] |
Functions
| Function | Signature | Summary |
|---|---|---|
finding_fingerprint |
finding_fingerprint(rule_id: str, context_line: str) -> str |
sha256 hex of rule_id|normalized(context_line). |
Source
"""Data model for the SPEC-033 C3 lexical/structural detector set (B22, ADR-0029).
Every dataclass here is frozen. Note what is deliberately **absent**:
:class:`DetectorReport` carries no field named anything like
``complete``/``ready``/``passed`` — ADR-0011's boundary is that no detector,
in any tier, ever issues a completeness verdict. A finding is an indicator;
callers (the CLI's ``--tier1-gate``, or a human reviewer) decide what to do
with the list.
"""
from __future__ import annotations
import hashlib
from dataclasses import dataclass
from enum import StrEnum
from orchestrata_ultimate.factory.assumptions.models import normalize
# Global rule 3 (ADR-0029): findings inside a rationale clause ("so that...")
# are ~2x denser and empirically less relevant -- down-weight, never suppress.
RATIONALE_WEIGHT = 0.5
class Tier(StrEnum):
"""The three detector tiers, named by what they DO (ADR-0029)."""
#: May fail a gate (``tier1_gate``). Every Tier-1 rule measures >=0.70
#: published precision.
BLOCKING = "blocking"
#: Reported, never blocking.
ADVISORY = "advisory"
#: Produces questions for the ADR-0024 C1 cascade. Never a verdict.
QUESTION = "question"
@dataclass(frozen=True)
class RuleMeta:
"""Static metadata for one detector rule.
``published_precision`` is ``None`` where no measurement exists in the
literature this detector set is derived from (Femmer et al. JSS 2017 /
ISO 29148 §5.2.7 / Berry, Kamsties & Krieger) -- never invent one.
"""
rule_id: str
tier: Tier
provenance: str
published_precision: float | None
def finding_fingerprint(rule_id: str, context_line: str) -> str:
"""sha256 hex of ``rule_id|normalized(context_line)``.
Shares :func:`orchestrata_ultimate.factory.assumptions.models.normalize`
with the assumption ledger so the same "what counts as the same text"
rule applies everywhere in the factory. This is the identity a
:class:`~orchestrata_ultimate.factory.detectors.engine.Blacklist` entry
dismisses -- re-running the detectors over unchanged text always
reproduces the same fingerprint.
"""
normalized = normalize(context_line)
return hashlib.sha256(f"{rule_id}|{normalized}".encode()).hexdigest()
@dataclass(frozen=True)
class Finding:
"""One detector hit. An indicator, never a verdict.
``weight`` is 1.0 normally, :data:`RATIONALE_WEIGHT` inside a rationale
clause (global rule 3). ``question`` is populated for Tier-3 findings
only (they feed :mod:`orchestrata_ultimate.factory.detectors.c1_bridge`);
it is ``None`` for Tier 1/2.
"""
rule_id: str
tier: Tier
line: int
span: tuple[int, int]
matched_text: str
message: str
weight: float
fingerprint: str
question: str | None = None
@classmethod
def new(
cls,
*,
rule_id: str,
tier: Tier,
line: int,
span: tuple[int, int],
matched_text: str,
message: str,
context_line: str,
weight: float = 1.0,
question: str | None = None,
) -> Finding:
"""Build a :class:`Finding`, deriving its fingerprint from ``context_line``."""
return cls(
rule_id=rule_id,
tier=tier,
line=line,
span=span,
matched_text=matched_text,
message=message,
weight=weight,
fingerprint=finding_fingerprint(rule_id, context_line),
question=question,
)
@dataclass(frozen=True)
class DetectorReport:
"""The result of one :func:`~...engine.run_detectors` call.
``dismissed`` holds findings a :class:`~...engine.Blacklist` recognized
-- they are never silently dropped, only relocated out of ``findings``.
Deliberately NO completeness/readiness field (see module docstring).
"""
findings: list[Finding]
dismissed: list[Finding]
files_scanned: list[str]