Skip to content

Commit 703923a

Browse files
committed
Update new-dmn-check skill to use proper inverse pattern
1 parent 0d8911c commit 703923a

1 file changed

Lines changed: 17 additions & 1 deletion

File tree

.claude/commands/new-dmn-check.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,22 @@ If a match is found, warn the user and stop. The name must be globally unique.
5555
- `tSituation` item definition includes only the fields the check actually reads (keep it minimal — don't copy BDT's full tSituation).
5656
- If a `tSituation` field is itself a complex type (e.g. `simpleChecks`), define a **local** version of that nested type containing only the specific properties this check uses. Reference the local type, not the BDT one. Example: if the check reads only `situation.simpleChecks.ownerOccupant`, define a local `tSimpleChecks` with just `ownerOccupant: boolean`, and use `typeRef="tSimpleChecks"` in `tSituation` (not `BDT.tSimpleChecks`).
5757

58+
### Inverse Check Pattern
59+
60+
If the new check is the logical inverse of an **existing** check (e.g. `NoTenYearTaxAbatement` is the inverse of `TenYearTaxAbatement`), model it by importing and negating — do **not** duplicate the logic:
61+
62+
1. Add a third import for the sibling check DMN (e.g. `xmlns:included3="{siblingNamespace}"` and a `<dmn:import>` element).
63+
2. Add a `<dmn:knowledgeRequirement>` in the `checkResult` decision referencing the sibling's Decision Service id: `href="{siblingNamespace}#{siblingServiceId}"`.
64+
3. Write the FEEL expression as: `not({SiblingAlias}.{SiblingCheckName}Service(situation: situation))` — or include `parameters: parameters` if the sibling takes parameters.
65+
4. In DMNDI, add a `<dmndi:DMNShape>` for the imported service (using `dmnElementRef="included3:{siblingServiceId}"`) and a `<dmndi:DMNEdge>` for the knowledge requirement edge. Place the imported service shape above and to the right of the main service box.
66+
5. The sibling check's namespace URI and Decision Service id can be found in its DMN file — read it before generating.
67+
68+
**Example**: `no-ten-year-tax-abatement.dmn` imports `ten-year-tax-abatement.dmn` and evaluates:
69+
```
70+
not(TenYearTaxAbatement.TenYearTaxAbatementService(situation: situation))
71+
```
72+
This mirrors `person-not-enrolled-in-benefit.dmn` which imports `person-enrolled-in-benefit.dmn`.
73+
5874
### Template A — Simple Literal Expression
5975

6076
Use when the FEEL logic is a single expression with no intermediate values needed.
@@ -423,7 +439,7 @@ After writing all files, print:
423439
2. **Service name** — must be exactly `{CheckName}Service`. No variations.
424440
3. **File name** — kebab-case, `.dmn` extension (e.g. `person-min-income.dmn`).
425441
4. **Namespace-qualified references** — when calling imported BKMs or decisions, always prefix with the import alias (e.g. `Age.as of date(...)`, `BDT.tCheckResponse`).
426-
5. **No circular imports** — checks import BDT.dmn and their category base module only; they must not import other checks.
442+
5. **No circular imports** — checks import BDT.dmn and their category base module, and may also import one sibling check when implementing the "inverse check" pattern (see Step 3). They must never create cycles (A imports B imports A).
427443
6. **BDT import path** — relative to the check file: `../BDT.dmn` for `checks/{category}/` files.
428444
7. **Fresh UUIDs** — generate a new UUID v4 for every `id` attribute. Never reuse UUIDs from example files.
429445
8. **tSituation is local and minimal** — define only the `situation` fields this check actually reads. Do not copy BDT's full tSituation definition. If a field's type is itself complex (e.g. `simpleChecks`), define a local version of that nested type too, containing only the specific properties used. Never reference BDT's version of a nested type (e.g. `BDT.tSimpleChecks`) when a local minimal definition suffices.

0 commit comments

Comments
 (0)