finos / finos/architecture-as-code

A pattern decision cannot select one candidate when two candidates share a unique-id

Open
#3,058 0 comments 0 reactions 1 assignee Claimed by @YoofiTT96 View on GitHub
Dominant language
TypeScript
Stars
399
Forks
138
Avg merge
2d 6h
Merged PRs (30d)
38

Description

## Bug Report

A slot is one entry in a pattern's `prefixItems` array. A slot can hold a `oneOf` or an `anyOf` array. Each entry in that array is a candidate. A pattern decision selects a candidate by its `unique-id`.

Two candidates in one slot can declare the same `unique-id`. That id then names two candidates. A decision cannot select only one of them. The pattern declares an option that the pattern cannot express.

The rule `unique-ids-must-be-unique-in-pattern` does not report this. The rule reads only the bare `prefixItems` entries. The rule does not read the candidates in a slot. Therefore `calm validate` accepts the pattern.

### Steps to Reproduce:
1. Write a pattern with two candidates in one slot. Give both candidates the `unique-id` `cache`.

```json
{
"properties": {
"nodes": {
"type": "array",
"prefixItems": [
{
"anyOf": [
{ "properties": { "unique-id": { "const": "cache" }, "name": { "const": "Redis" } } },
{ "properties": { "unique-id": { "const": "cache" }, "name": { "const": "Memcached" } } }
]
}
]
},
"relationships": { "type": "array", "prefixItems": [] }
}
}
```

2. Run `calm validate` against the pattern.

### Expected Result:
`calm validate` reports a duplicate `unique-id`. The rule reports that error today for two bare `prefixItems` nodes with one id.

### Actual Result:
`calm validate` reports no error. The tool accepts the pattern.

### Consequences
Each consumer finds a candidate by its `unique-id`. Each consumer therefore gets the same ambiguous result.

`calm generate` selects both candidates for the id `cache`. The command writes two nodes with one id:

```json
[{"unique-id":"cache","name":"Redis"},{"unique-id":"cache","name":"Memcached"}]
```

`calm validate` then rejects that architecture. It reports `unique-ids-must-be-unique-in-architecture`. This error names the architecture and a different rule. The error does not name the pattern slot. The author must find the cause without help.

The CALM Hub visualiser draws two nodes with the id `cache`. ReactFlow does not define the result for two nodes with one id. The pattern differ and the Spectral rules also match on `unique-id`.

### `oneOf` has the same defect
Change `anyOf` to `oneOf` in the pattern above. The output stays the same. `oneOf` permits exactly one candidate in the slot. The defect is not the number of nodes. The decision has no id that selects one candidate and not the other.

### Scope
| Declaration site | The rule reads it today |
|---|---|
| `nodes`, `relationships` and interfaces as bare `prefixItems` entries | yes |
| the same, as candidates in a slot's `oneOf` or `anyOf` | no |

The rule misses an interface id on a candidate node for the same reason.

### Environment:
`shared` (`@finos/calm-shared`), `src/spectral/functions/pattern/ids-are-unique.ts`. I reproduced the defect on `main` at `0034591f`.

### Additional Context:
I found this defect during the design work for #2859. This defect is not part of that work. A pattern that uses no `items` catalog can show it. Therefore this issue and its fix stay separate. The two behaviour changes then keep separate release notes.

The fix changes behaviour. A pattern from outside this repository can declare duplicate ids in a slot. `calm validate` accepts that pattern today. `calm validate` rejects it after the fix. No pattern in this repository changes its result. I checked all 25 pattern files against the new queries.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.