Skip to content

Conversation

@guicho271828
Copy link
Contributor

@guicho271828 guicho271828 commented Aug 25, 2025

work in progress sketch for discussion
#22

@guicho271828 guicho271828 mentioned this pull request Aug 25, 2025
@nrfulton nrfulton marked this pull request as draft August 25, 2025 16:37
class NegativeRequirement(Requirement):
def __init__(self, requirement: Requirement,):
self.requirement = requirement

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of a weird thing to prompt with. But it's hard to know what a reasonable prompt would be here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed this earlier offline but just for the historical note:
this is useful for XOR-type requirement which is sometimes natural to human.

In a different sentence like “Bob drank coffee or tea this morning”, the dominant interpretation is that he drank one or the other, but not both (i.e. exclusive disjunction annotated as XOR). https://pmc.ncbi.nlm.nih.gov/articles/PMC12039866/

Xor expands to (P and not Q) or (not P and Q).

Comment on lines +183 to +205
class ConjunctiveRequirement(Requirement):
def __init__(self, requirements: list[Requirement],):
self.requirements = requirements

@property
def description(self):
return "\n* ".join(
["Satisfy all of these requirements:"] + \
[r.description for r in self.requirements])

def validate(self, *args, **kwargs):
results = [r.validate(*args, **kwargs) for r in self.requirements]
return ValidationResult(
result = all(results),
reason = "\n* ".join(
["These requirements are not satisfied:"]+
[r.reason for r in results if not r]),
score = max([r.score for r in results if not r]))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the rest of Mellea, a list of requirements is implicitly conjunctive. So does it make sense to have a ConjunctiveRequirement that behaves differently from a list of reuqirements? Or should we explicitly not have ConjunctiveRequirements because the correct way of doing this is to pass both into the requirements= kwarg?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List as conjunction by default is a good user interface but I believe internally they should be immediately converted into a conjunction.

In a much more complex industrial use case where a company has a large set of rules, requirement as a list becomes unmanageable. I.e., compiling a NNF into CNF causes an exponential increase in the number of clauses.

Comment on lines +187 to +193
@property
def description(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

description is NOT a @property on the base class or in other Requirement types. Maybe it should be, but we should do this the same everywhere. Using property here but not in the other Requirement classes seems like a recipe for confusion down the road.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.description = description

self.description = description

description is clearly a property in the base class. wdym?

Copy link
Contributor

@nrfulton nrfulton Sep 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just mean that if we're going to use property() to handle Requirement's description, then we should do so consistently through-out the code base.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the use of property() here is explicitly to avoid insertion, which causes an inconsistency between the parent and the child requirement.

@nrfulton
Copy link
Contributor

There are failing quality checks.

Please use the pre-commit hooks. Assuming you have already created a venv and installed Mellea (editable), you can install the hooks by running the following commands in the root of your mellea checkout:

uv pip install -e . --group dev && pre-commit install

Once installed, you can still commit over errors using the -n flag (e.g., git commit -a -m 'this may not pass pre-commit checks' -n). However, prior to opening PR for review, ensure that the latest commit does pass the pre-commit checks.

@mergify
Copy link

mergify bot commented Sep 3, 2025

Merge Protections

Your pull request matches the following merge protections and will not be merged until they are valid.

🟢 Enforce conventional commit

Wonderful, this rule succeeded.

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\(.+\))?:

@nrfulton nrfulton changed the title composable requirements feat: composable requirements Sep 4, 2025
@guicho271828 guicho271828 force-pushed the composable-requirements branch from 024d9a6 to 80b83fd Compare September 15, 2025 17:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants