wenjin272 opened a new pull request, #1351:
URL: https://github.com/apache/flink-agents/pull/1351

   Linked issue: #1084
   
   Depends on #1342 (currently open). This draft includes its three 
prerequisite commits; the final commit contains the follow-up described below. 
Once #1342 merges, this branch will be rebased to retain only the follow-up.
   
   ### Purpose of change
   
   Repeated equal-payload events in one input round must produce distinct 
chat/subagent calls as well as distinct durable action states. This follow-up 
applies the event occurrence identity to those calls and preserves it through 
suspension and recovery.
   
   #### Runtime flow
   
   `RuntimeIdentity` derives a root occurrence from the serialized business-key 
identity and input sequence, an Action execution ID from its triggering 
occurrence and action name, and an emitted occurrence from its producer 
execution and emission ordinal. `ActionTaskContextManager` binds the 
execution's emission counter and per-target call allocators to 
`RunnerContextImpl` on each task switch or continuation transfer.
   
   Events receive identity before enqueueing, including subgraph bootstraps 
dispatched before their parent finishes. Completion-time memory observation and 
synthesized failure events receive identity before persistence/dispatch. 
`ActionStateSerde` saves occurrence metadata with both triggering and output 
events. Completed-action replay reuses those saved identities.
   
   #### Key decisions
   
   - Put derivation in a shared runtime component so call allocation does not 
depend on ActionState storage.
   - Retain attributes in the ActionState event fingerprint for 
replay-divergence detection; use occurrence identity to distinguish 
equal-payload executions.
   - Generate call IDs from execution/target namespace, session ID and call 
ordinal, including caller-supplied sessions. A session ID alone cannot 
distinguish calls from different executions.
   - Require explicit occurrence metadata instead of a content-only fallback. 
Direct lower-level test fixtures now supply it.
   
   ### Behavioral Semantics
   
   #### Interaction decisions
   
   | Execution state | Identity behavior |
   |---|---|
   | Persistence disabled | Events and generated call IDs still use 
occurrence-based identity. |
   | Persistence enabled, fresh call | Bootstrap consumes an emission ordinal; 
completed outputs retain their IDs in ActionState. |
   | Parent suspends/resumes | The same emission and call counters continue 
across tasks, for continuation and parallel execution. |
   | Unfinished parent restarts, earlier graph result cached | Counters 
restart; replay still reserves the skipped bootstrap's ordinal before reusing 
its result. |
   | Completed Action replayed | Recorded output identities are preserved; 
filtered bootstrap events do not renumber remaining outputs. |
   
   #### Behavioral contracts
   
   Distinct equal-payload occurrences produce distinct downstream execution and 
generated call identities. Repeating the same deterministic execution 
reproduces its identity sequence. Explicit sessions can be continued across 
executions without generated call-ID collisions. Durable serialization 
preserves event occurrence IDs; ordinary Event JSON continues to omit them.
   
   #### Failure behavior
   
   Missing occurrence metadata fails immediately rather than falling back to 
content. Ordinary Java emission rejects an event whose occurrence ID is already 
assigned. Negative emission ordinals are rejected. State 
serialization/deserialization errors continue to propagate through the existing 
durable-state failure handling. This change adds no retries or provider-error 
handling.
   
   ### Tests
   
   | Contract | Coverage |
   |---|---|
   | Equal-payload triggers and multiple waits remain distinct without 
persistence | `RuntimeIdentityIntegrationTest`: chat/subagent, serial/parallel 
execution |
   | Replay reproduces identity and explicit sessions remain execution/target 
scoped | `RuntimeIdentityTest`, `DeterministicIdAllocatorTest`, 
`BaseSubagentSetupTest` |
   | Cached graph results preserve subsequent emission ordinals | 
`ChatDurableFutureTest` |
   | Identity survives durable serialization but stays out of ordinary JSON | 
`ActionStateSerdeTest`, `EventTest` |
   | Existing recovery and content-divergence behavior remains valid | 
`ChatCallTest`, `InternalSubagentRecoveryTest`, 
`ActionStateDivergenceRecoveryTest`, Kafka/Fluss recovery suites |
   | Missing metadata, reused assigned events and negative ordinals fail | 
`ActionStateUtilTest`, `RuntimeIdentityTest` |
   
   Validation: JDK 21 API/MCP/Plan/Runtime reactor tests (3,029 tests, 81 
skipped, no failures); clean JDK 11 focused regression build; subsequent 
identity/key-focused tests; Spotless and Apache RAT checks.
   
   Not verified: Python-only/cross-language E2E suites for this follow-up, 
external provider services, recovery across old/new ID formats, and integration 
with changes added to main since #1342's base. Deterministic emission/call 
order remains required; arbitrary user nondeterminism is not made replay-safe.
   
   <details>
   <summary>Implementation invariants and validation commands</summary>
   
   The emission allocator belongs to a logical Action execution. RunnerContext 
holds the active reference; context transfer retains that reference and a fresh 
restarted execution constructs a new one. Length-prefixed hash components keep 
tuple boundaries unambiguous. Public Event JSON ignores occurrence metadata; 
the ActionState-specific Jackson mixin explicitly restores that property for 
durable serialization.
   
   Targeted reactor builds use `mvn ... -pl runtime -am` to rebuild local API, 
MCP, Plan and Runtime artifacts together. The JDK 21 full run used 
`-Dtest=*Test,Test*`; JDK switches used `clean` to remove continuation 
overlays. Later focused runs covered `RuntimeIdentityTest`, 
`DeterministicIdAllocatorTest`, `ActionStateUtilTest`, 
`ActionStateUtilCrossClassLoaderTest` and `ActionStateDivergenceRecoveryTest`.
   
   </details>
   
   ### API
   
   Public API signatures are unchanged. Internal identity utility/allocator 
signatures change. Root, emitted and generated call IDs change; no migration of 
old persisted keys or IDs is provided. Ordinary Java emission now rejects 
already-assigned Event instances. Java and Python calls use the shared runtime 
identity path; Python Event's JSON shape is unchanged.
   
   ### Documentation
   
   - [ ] `doc-needed`
   - [x] `doc-not-needed`
   - [ ] `doc-included`
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   - [x] Yes
   - [ ] No
   
   Generated-by: Codex CLI 0.153.4 (GPT-6)
   


-- 
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