Let check_availability use what the reactive half saw

The watchlist is read before answering, so a crossing that happened twenty
minutes ago is part of the answer.

It also fixes a contradiction the agent was publishing: the catalog domain
caches reads for 60 seconds, so an agent woken by an event reads a figure taken
up to a minute earlier — it answered "68 in stock, above the threshold" and
"it crossed the threshold, from 68" in the same sentence. A movement is the
catalog's own dated statement; a read is an undated copy. The dated one wins,
and the answer says so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Stéphane Tailland
2026-08-31 08:18:59 +02:00
parent 33d811fa68
commit 245415e7c6
2 changed files with 78 additions and 2 deletions
+46
View File
@@ -89,6 +89,52 @@ and through the A2A facade, `escalate: true` becomes a task in state **failed**
rather than a completed one — the honest shape for "a human has to look at
this".
### It now knows what the reactive half saw
`check-availability` reads the watchlist before answering, so a crossing that
happened twenty minutes ago is part of the answer:
```
"Peut-on promettre S12_1099 ?"
→ "No — 1968 Ford Mustang (S12_1099) is down to 8 … It crossed the threshold
at 06:18:24 (driven by orders), from 68."
```
"It fell below this afternoon, under demand" is a different decision from "it
has been sitting below for a month", and only the event carries that.
The watchlist is read over an in-cluster call to the stock-watch workflow's own
webhook — its data lives in that workflow and there is no other way in. The node
is `onError: continueRegularOutput`: an availability answer must not depend on
the watchlist being up.
### A dated fact beats an undated read
The two figures can disagree, and when they do the **read** is the wrong one.
This was not theoretical — the agent answered, in one sentence:
```
"68 in stock, above the reorder threshold of 50 … It crossed the threshold, from 68."
```
The catalog domain caches reads for **60 seconds**. An agent woken by an event
reacts in seconds and then reads a figure taken up to a minute earlier. A
movement is the catalog's own *dated* statement that stock went from X to Y; a
read is an undated copy. So the movement wins, and the answer says the basis
changed:
```
Basis: the latest stock movement, which is more recent than the catalog read
```
Measured after the fix, with the cache deliberately warmed at 38 and the true
stock moved to 8 inside the window: the answer said **8**.
This only helps a reference the reactive half is already watching. For any
other, the read stands with whatever staleness it has, and nothing in the
workflow can tell — which is worth remembering before treating any single read
as current.
## approvisionnement-periodic-reorder
The periodic half. A schedule trigger at 06:00, deliberately periodic rather
File diff suppressed because one or more lines are too long