orchestrata_ultimate.verification.requirements.requirements_parser

Reference › orchestrata_ultimate › verification › requirements › requirements_parser

RequirementsParser is the front door of the pipeline: it turns natural-language requirements into Constraint objects. It is pattern-based, not LLM-based. Four module-level lists of compiled, case-insensitive regular expressions, one per constraint type, map phrases to predicate names. Performance patterns recognise phrases such as "respond within N ms", latency under N ms, throughput of at least N and memory under N MB (predicates like response_time_max_ms and memory_usage_max_mb). Quality patterns cover test coverage of at least N percent, passing lint and complete documentation. Security patterns cover SQL injection, secrets, credentials or passwords in code, and XSS. Functional patterns cover file existence, compilable code and defined dependencies.

extract_performance, extract_quality, extract_security and extract_functional each take the first match of each pattern and build a constraint whose description is the matched text. Performance and quality constraints carry the captured integer as the expected value (true when the pattern has no capture); security and functional constraints expect true. parse runs all four in that order and concatenates the results. Text that matches nothing yields an empty list. The predicates line up with the checkpoint criteria, and the output feeds the Prolog generator and the evaluator.

At a glance

Source src/orchestrata_ultimate/verification/requirements/requirements_parser.py
Lines of code 184
Classes 1
Functions 0
Imports (internal) orchestrata_ultimate.core.base.traces, orchestrata_ultimate.verification.types
Imported by none
Tests that import it tests/generated_recovery/test_verification_requirements_requirements_parser.py, tests/verification/test_requirements.py, tests/verification/test_small_modules.py

Class diagram

Class diagram orchestrata_ultimate.verification.requirements.requirements_parser

Dependency diagram

Dependency diagram orchestrata_ultimate.verification.requirements.requirements_parser

API

Classes

RequirementsParser

Decorators: traces(spec='035', story='US-001', reqs=['REQ-035-US-001-005', 'REQ-035-US-001-011', 'REQ-035-US-001-015']) · Line 68

Parses natural language requirements into Constraint objects.

Method Signature Summary
parse parse(text: str) -> list[Constraint] Parse text into a list of constraints.
extract_performance extract_performance(text: str) -> list[Constraint] Extract performance constraints.
extract_quality extract_quality(text: str) -> list[Constraint] Extract quality constraints.
extract_security extract_security(text: str) -> list[Constraint] Extract security constraints.
extract_functional extract_functional(text: str) -> list[Constraint] Extract functional constraints.

Source

Permalink: https://gitlab.com/MSamy/orchestrata-ultimate-architecture/-/blob/a4cbc2bdf/src/orchestrata_ultimate/verification/requirements/requirements_parser.py

"""Parse natural language requirements into formal constraints."""

import logging
import re

from orchestrata_ultimate.core.base.traces import traces
from orchestrata_ultimate.verification.types import Constraint, ConstraintType

logger = logging.getLogger(__name__)

# Pattern matchers for common constraint types
PERFORMANCE_PATTERNS = [
    (re.compile(r"respond\s+within\s+(\d+)\s*ms", re.I), "response_time_max_ms"),
    (
        re.compile(r"latency\s+(?:under|below|less than)\s+(\d+)\s*ms", re.I),
        "latency_max_ms",
    ),
    (
        re.compile(r"throughput\s+(?:at least|minimum|min)\s+(\d+)", re.I),
        "throughput_min",
    ),
    (
        re.compile(r"memory\s+(?:under|below|less than)\s+(\d+)\s*MB", re.I),
        "memory_usage_max_mb",
    ),
]

QUALITY_PATTERNS = [
    (
        re.compile(r"(?:test\s+)?coverage\s+(?:at least|minimum|>=?)\s*(\d+)%", re.I),
        "test_coverage_percentage",
    ),
    (re.compile(r"lint(?:ing)?\s+(?:passes|clean|no errors)", re.I), "linting_passes"),
    (
        re.compile(r"documentation\s+(?:complete|exists|present)", re.I),
        "documentation_complete",
    ),
]

SECURITY_PATTERNS = [
    (re.compile(r"no\s+sql\s+injection", re.I), "no_sql_injection_vulnerabilities"),
    (
        re.compile(r"no\s+(?:secrets?|credentials?|passwords?)\s+in\s+code", re.I),
        "secrets_not_in_code",
    ),
    (re.compile(r"no\s+xss", re.I), "no_xss_vulnerabilities"),
]

FUNCTIONAL_PATTERNS = [
    (re.compile(r"file\s+(?:exists?|must exist)", re.I), "file_exists"),
    (re.compile(r"code\s+compiles?", re.I), "code_compiles"),
    (
        re.compile(r"dependencies?\s+(?:defined|resolved|installed)", re.I),
        "dependencies_defined",
    ),
]


@traces(
    spec="035",
    story="US-001",
    reqs=[
        "REQ-035-US-001-005",
        "REQ-035-US-001-011",
        "REQ-035-US-001-015",
    ],
)
class RequirementsParser:
    """Parses natural language requirements into Constraint objects."""

    @traces(
        spec="035",
        story="US-001",
        reqs=[
            "REQ-035-US-001-001",
            "REQ-035-US-001-002",
            "REQ-035-US-001-006",
            "REQ-035-US-001-012",
            "REQ-035-US-001-021",
            "REQ-035-US-001-023",
            "REQ-035-US-001-024",
        ],
    )
    def parse(self, text: str) -> list[Constraint]:
        """Parse text into a list of constraints."""
        constraints = []
        constraints.extend(self.extract_performance(text))
        constraints.extend(self.extract_quality(text))
        constraints.extend(self.extract_security(text))
        constraints.extend(self.extract_functional(text))
        return constraints

    @traces(
        spec="035",
        story="US-001",
        reqs=["REQ-035-US-001-015", "REQ-035-US-001-022"],
    )
    def extract_performance(self, text: str) -> list[Constraint]:
        """Extract performance constraints."""
        results = []
        for pattern, predicate in PERFORMANCE_PATTERNS:
            match = pattern.search(text)
            if match:
                value = (
                    int(match.group(1))
                    if match.lastindex and match.lastindex >= 1
                    else True
                )
                results.append(
                    Constraint(
                        type=ConstraintType.PERFORMANCE,
                        predicate=predicate,
                        expected=value,
                        description=match.group(0).strip(),
                    )
                )
        return results

    @traces(
        spec="035", story="US-001", reqs=["REQ-035-US-001-005", "REQ-035-US-001-015"]
    )
    def extract_quality(self, text: str) -> list[Constraint]:
        """Extract quality constraints."""
        results = []
        for pattern, predicate in QUALITY_PATTERNS:
            match = pattern.search(text)
            if match:
                value = (
                    int(match.group(1))
                    if match.lastindex and match.lastindex >= 1
                    else True
                )
                results.append(
                    Constraint(
                        type=ConstraintType.QUALITY,
                        predicate=predicate,
                        expected=value,
                        description=match.group(0).strip(),
                    )
                )
        return results

    @traces(spec="035", story="US-001", reqs=["REQ-035-US-001-015"])
    def extract_security(self, text: str) -> list[Constraint]:
        """Extract security constraints."""
        results = []
        for pattern, predicate in SECURITY_PATTERNS:
            match = pattern.search(text)
            if match:
                results.append(
                    Constraint(
                        type=ConstraintType.SECURITY,
                        predicate=predicate,
                        expected=True,
                        description=match.group(0).strip(),
                    )
                )
        return results

    @traces(
        spec="035",
        story="US-001",
        reqs=[
            "REQ-035-US-001-003",
            "REQ-035-US-001-004",
            "REQ-035-US-001-013",
            "REQ-035-US-001-014",
        ],
    )
    def extract_functional(self, text: str) -> list[Constraint]:
        """Extract functional constraints."""
        results = []
        for pattern, predicate in FUNCTIONAL_PATTERNS:
            match = pattern.search(text)
            if match:
                results.append(
                    Constraint(
                        type=ConstraintType.FUNCTIONAL,
                        predicate=predicate,
                        expected=True,
                        description=match.group(0).strip(),
                    )
                )
        return results