Repository navigation
Description
Search before asking
- I searched existing issues for duplicates; related work is linked below where applicable.
Description
This is a child issue of #1055.
Problem
Event identity and lineage are framework metadata, but callers can populate upstreamEventId/upstreamActionName (Python: upstream_event_id/upstream_action_name) before emission. ActionTask.finalizeOutputEvents currently overwrites existing lineage, including during replay. Silent replacement obscures the public contract and lets invalid user declarations pass the send boundary.
Python Event IDs are immutable, but assignment errors only provide the generic frozen-field diagnostic rather than guidance for reconstructing an Event with an existing identity.
Proposed direction
- Validate user-originated emission in Java/Python
sendEvent/send_eventand reject prepopulated framework-owned lineage with an actionable error. User business metadata belongs inattributes. - Preserve the existing output-versus-trigger identity invariant and align its behavior across native and cross-language paths.
- Keep legitimate deserialization, replay, and typed reconstruction able to preserve identity and lineage. Distinguish these internal paths from a new user emission; do not apply a blanket rejection to restored framework events.
- For Python immutable-ID assignment, explain when to use
reconstruct_from(event)instead of only reportingField is frozen.
Acceptance criteria
- Preset lineage fails clearly at user emission instead of being silently overwritten; valid emissions receive correct framework lineage.
- Java/Python and cross-language tests cover normal emission, invalid identity/lineage, typed reconstruction, and recovery/replay.
- Documentation distinguishes framework identity/lineage, user attributes, and reconstruction.
Related: #1125 covers built-in event restoration; this issue covers ownership and validation at emission.
Relevant code: Java/Python Event, RunnerContext implementations, and runtime/.../operator/ActionTask.java.
Are you willing to submit a PR?
- I'm willing to submit a PR!
Activity
sangkyoonnam commentedon Oct 8, 2026
I'd like to take this one, following #1197 in the same #1055 set.
The check would go in
RunnerContextImpl.sendEvent, which every user emission reaches, Python included throughsendEventJson. An event that arrives there withupstreamEventIdorupstreamActionNameset fails with an error that points toattributes.ActionTask.finalizeOutputEventskeeps binding lineage as it does today. Outputs restored from the action state don't go throughsendEvent: they keep their IDs, andfinalizeOutputEventsbinds their lineage to the replayed trigger. The operator setsAgentRunBeginEvent's lineage itself. Python'ssend_eventwould run the same check before serializing, so the error names the Python field, and the frozen-ID error would mentionreconstruct_from.A typed reconstruction (
fromEvent/reconstruct_from) keeps the source's ID and lineage, so sending one that carries lineage is rejected too; one without lineage still meets the existing self-loop check at finalization if it is the trigger. The docs would say that a new emission starts from a fresh event. Could you assign it to me?wenjin272 commentedon Oct 9, 2026
Thanks for picking this up. The proposed approach sounds good to me. Looking forward to the PR.