Skip to content

ground_notcoexistence instantiates NotCoExistence with the same operand twice #34

Description

@askalot-io

Bug

nl2ltl/engines/grounding.py:

def ground_notcoexistence(connectors: Dict[str, float]) -> Set[Template]:
    if len(list(connectors)) >= 2:
        return {
            NotCoExistence(
                Atomic(decapitalize(list(connectors)[1])),
                Atomic(decapitalize(list(connectors)[1])),   # <-- [1] twice
            )
        }

Both operands are built from list(connectors)[1], so any two-symbol grounding produces a degenerate self-pair. Reproduction:

>>> from nl2ltl.engines.utils import _get_formulas
>>> _get_formulas("notcoexistence", {"reject_request": 1.0, "escalate_to_human": 1.0})
{(NotCoExistence escalate_to_human escalate_to_human)}

Expected: (NotCoExistence reject_request escalate_to_human).

The resulting LTLf, F(x) -> ~F(x), is equivalent to G(!x) — "x never happens" — which silently changes the meaning of the translated requirement (we caught it because a round-trip paraphrase of the formula no longer matched the input sentence).

Fix

Atomic(decapitalize(list(connectors)[0])),
Atomic(decapitalize(list(connectors)[1])),

Observed on nl2ltl from PyPI (Python 3.13). Found while building a Claude-backed custom Engine for translating agent-guardrail policies to DECLARE. Can send a PR if useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions