Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/spec/entities.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,8 @@ One outcome would have fitted exactly one real rule. Negative stock wants the wr

The total is recomputed from the guarded entity's own rows for the incoming record's key-tuple - excluding the record being updated - rather than read from the materialised aggregate, so the decision cannot race the aggregate's maintenance. The guarded entity must be the aggregate's own source.

A record with any of the aggregate's grouping keys unset **is not guarded at all**. It belongs to no key-tuple - the aggregate itself ignores such a row, and materialises no target row for it - so it contributes to no total and can breach no minimum: the write proceeds, nothing is refused, a `marker` reads as holding and a `setStatus` is not written. This is the guard's half of a rule the aggregate already states, and it keeps the two a pair of computations of the same total rather than of two different ones. A grouping key that must always be there is declared `required`, which is the better statement where it is true.

`outcome: task` stamps a flag; it does not create or route to a task. A workflow [decision](/spec/processes#decision-steps) reads the marker and routes the record - the two constructs compose, and the guard is the part that computes.

## Role-scoped field visibility — `visibleTo`
Expand Down
2 changes: 2 additions & 0 deletions docs/spec/glue.md
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,8 @@ postings:
- { Account: rule(receivableAccount), credit: "Amount" }
```

`rule.match` is a single `column: literal` selector, and the literal has to say something: it is matched against the rule row's own column as authored, so a blank one looks up the empty value, matches no rule row, and sends *every* source document to the unposted worklist while the model, the generation and the deployment all stay healthy. An absent or blank match value is an authoring error, reported when the intent is read. A rule *row* whose match column is empty is a different thing - an ordinary row of the rule table, matched by no non-blank literal.

### Conditional rule column

When the account column must be chosen by a **source value** — a payment posts to the bank account for a transfer, the cash account for cash — a single item row selects the rule column by a classifier instead of duplicating the row per case (the same `by` / `cases` / `default` shape a conditional value-copy uses). Quote it, since it carries colons and braces:
Expand Down