Skip to content

[Bug]: universal_algebra operations accept invalid cross-field inputs that raise backend exceptions #2132

Description

@morluto

Observed behavior

Two universal_algebra operations accept requests that pass request-model validation but raise untyped backend ValueError exceptions during domain execution.

universal_algebra.quotient.compute — empty and partial partitions

The QuotientRequest model accepts an empty partition tuple partition = (). The backend then raises ValueError: partition is not a congruence. A partition that does not cover all carrier elements (e.g., partition = [[0]] for a two-element carrier) is also accepted by the model and raises the same backend error.

universal_algebra.equation.profile.computevariable_count too small

The EquationProfileRequest model accepts variable_count = 1 even when the left equation tree references variable_id = 1. The backend then raises ValueError: incomplete assignment.

Reproduction

from jacobian.catalog.catalog import Catalog
from jacobian.dispatch import invoke_operation

catalog = Catalog.open()

# --- quotient with empty partition ---

base = {
    "algebra": {
        "carrier": ["0", "1"],
        "operations": [
            {"operation_id": "and", "arity": 2},
            {"operation_id": "or", "arity": 2},
        ],
        "tables": [[0, 0, 0, 1], [0, 1, 1, 1]],
    },
    "partition": [],
}

result = invoke_operation(
    "universal_algebra.quotient.compute",
    base,
    catalog,
)
# ValueError: partition is not a congruence
# --- equation.profile with variable_count too small ---

base = {
    "algebra": {
        "carrier": ["0", "1"],
        "operations": [
            {"operation_id": "and", "arity": 2},
            {"operation_id": "or", "arity": 2},
        ],
        "tables": [[0, 0, 0, 1], [0, 1, 1, 1]],
    },
    "left": {
        "nodes": [
            {"kind": "variable", "variable_id": 0, "operation": None, "children": []},
            {"kind": "variable", "variable_id": 1, "operation": None, "children": []},
            {"kind": "application", "variable_id": None, "operation": 0, "children": [0, 1]},
        ],
        "root": 2,
    },
    "right": {
        "nodes": [
            {"kind": "variable", "variable_id": 0, "operation": None, "children": []},
        ],
        "root": 0,
    },
    "variable_count": 1,  # should be 2
}

result = invoke_operation(
    "universal_algebra.equation.profile.compute",
    base,
    catalog,
)
# ValueError: incomplete assignment

Expected behavior

Every request accepted by the public model should either return a typed result or be rejected during validation. The contract for these two operations should validate:

  • QuotientRequest: The partition must be non-empty, must cover all carrier elements, and each block must contain valid carrier indices.
  • EquationProfileRequest: variable_count must be at least one more than the maximum variable_id referenced in the left and right equation trees.

Environment

  • Jacobian revision: be54c78
  • Python: 3.12.13
  • OS: Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions