YAshhh29 opened a new pull request, #71575:
URL: https://github.com/apache/airflow/pull/71575

   When durable execution replays a cached model response or tool result, it 
compares a fingerprint of the current request against the fingerprint stored 
with the cache entry. Requests that cannot be serialized to JSON fingerprint as 
`None`, and `None == None` is `True` — so the guard passed for precisely the 
requests it could not verify, and a stale entry was replayed.
   
   ```diff
   -            if cached_fingerprint == fingerprint:
   +            if fingerprint is not None and cached_fingerprint == 
fingerprint:
   ```
   
   **This is a behaviour change, not only a bug fix.** A step whose request 
cannot be fingerprinted now re-runs live on retry rather than replaying, which 
costs a model call. The existing code was ambiguous about which behaviour was 
intended: `fingerprint.py` logged *"cached responses for this step replay 
without verification"* (fail open), while the `reason=` branch immediately 
below the comparison explains *"entry predates fingerprinting or the request 
could not be fingerprinted"* — a message that could never be reached, because 
that case short-circuited into the replay path. This PR resolves the 
contradiction in favour of not replaying what cannot be verified, and documents 
the contract in `agent.rst`.
   
   ### Behaviour before and after
   
   The screenshots below drive the real `CachingModel` and `CachingToolset` 
directly (no pytest, no mocked guard). Each run prints the guard line straight 
out of `caching_model.py`, so the version under test is visible in the output. 
The scenario is identical in both: a cached answer for Q3 revenue is stored 
with a `None` fingerprint, then the step is retried with a request about Q4 
revenue that also cannot be fingerprinted.
   
   **Before — guard as it is on `main`**
   
   <img width="1506" height="651" alt="image" 
src="https://github.com/user-attachments/assets/c2418e4f-5b10-46a5-ba59-cc9a54b3b012";
 />
   
   The cached Q3 answer is returned in response to the Q4 question, with `live 
calls: 0` and `replayed steps: 1`. The model is never consulted, and nothing 
verified that the two requests matched.
   
   **After — guard with this PR**
   
   <img width="1485" height="678" alt="image" 
src="https://github.com/user-attachments/assets/92d7949c-7872-43d8-9aeb-d2179df207a1";
 />
   
   The unverifiable step runs live: `live calls: 1`, `replayed steps: 0`, and 
the answer matches the question that was actually asked.
   
   ### Testing
   
   `test_unverifiable_current_request_treated_as_miss` and 
`test_unverifiable_current_call_treated_as_miss` fail without the change and 
pass with it.
   
   | `providers/common/ai/tests/unit/common/ai/durable` | result |
   | --- | --- |
   | guard as it is on `main` | `2 failed, 85 passed` |
   | guard with this PR | `87 passed` |
   
   ---
   
   ##### Was generative AI tooling used to co-author this PR?
   
   - [X] Yes — GitHub Copilot (Claude Opus 5)
   
   Generated-by: GitHub Copilot (Claude Opus 5) following [the 
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to