Problem
Frontend flows across Studio, CLI playground, scripting, workflow runs, and GAgentService capabilities currently handle async backend writes in feature-specific ways.
The backend is intentionally eventually consistent: commands are accepted before read models catch up. Without a shared frontend strategy, each screen decides differently whether to poll, subscribe, refresh, show pending state, retry invoke, or treat a stale read model as failure.
This makes the product behavior fragile and encourages backend APIs to hide eventual consistency by polling read models inside application services.
Current symptoms
Representative frontend/product flows:
- Workflow and draft-run flows can consume streaming events.
- Script save returns an accepted response plus a save-observation endpoint, and the UI waits/refreshes in custom logic.
- Runtime read models expose freshness fields such as
StateVersion, LastEventId, and UpdatedAt, but UI handling is not standardized.
- Binding/invoke flows need to distinguish
accepted, observed, and ready to invoke instead of assuming an immediate follow-up query or invoke is safe.
Goal
Define a shared frontend operation strategy for all async write flows:
- Submit command.
- Receive an accepted operation handle.
- Prefer stream observation when available.
- Otherwise use observe/readiness endpoint when available.
- Otherwise refresh read model and evaluate freshness fields.
- Render honest UI states: pending, running, stale/read-model-catching-up, completed, failed, timed out.
Proposed frontend shape
Create a small operation client/hook/helper that can consume backend hints without requiring every capability to use the same transport:
commandId
correlationId
- resource/actor identity
observeUrl
streamUrl
readModelUrl
- optional expected version/event/command marker
- timeout and retry policy
Expected behavior:
accepted is not displayed as completed.
- A stale or missing read model immediately after write is treated as pending/catching-up, not a hard failure unless the backend observation says failed.
- Terminal stream/observe failure is surfaced as failure.
- Read-model freshness fields are displayed or logged when useful for debugging.
- Pages do not implement ad-hoc sleep loops with inconsistent intervals and timeout semantics.
Non-goals
- Do not require all operations to stream.
- Do not hide backend failures indefinitely behind spinners.
- Do not create frontend-owned shadow facts or local registries as a substitute for read models.
- Do not introduce a large state-management framework only for this problem.
Acceptance criteria
- Inventory current Studio/CLI async flows for workflow run, script save/run/evolution, service binding/invoke, and GAgent draft-run.
- Define a minimal frontend operation helper contract and state machine.
- Update at least one stream-based flow and one observe/readmodel-based flow to use the shared helper.
- Ensure UI copy/states distinguish accepted, observed, ready, stale/catching-up, completed, failed, and timed out.
- Coordinate expected backend response fields with the backend contract issue.
Related follow-up
Coordinate with backend issue #592 and the summary governance issue so frontend behavior and backend API semantics are documented together.
Problem
Frontend flows across Studio, CLI playground, scripting, workflow runs, and GAgentService capabilities currently handle async backend writes in feature-specific ways.
The backend is intentionally eventually consistent: commands are accepted before read models catch up. Without a shared frontend strategy, each screen decides differently whether to poll, subscribe, refresh, show pending state, retry invoke, or treat a stale read model as failure.
This makes the product behavior fragile and encourages backend APIs to hide eventual consistency by polling read models inside application services.
Current symptoms
Representative frontend/product flows:
StateVersion,LastEventId, andUpdatedAt, but UI handling is not standardized.accepted,observed, andready to invokeinstead of assuming an immediate follow-up query or invoke is safe.Goal
Define a shared frontend operation strategy for all async write flows:
Proposed frontend shape
Create a small operation client/hook/helper that can consume backend hints without requiring every capability to use the same transport:
commandIdcorrelationIdobserveUrlstreamUrlreadModelUrlExpected behavior:
acceptedis not displayed as completed.Non-goals
Acceptance criteria
Related follow-up
Coordinate with backend issue #592 and the summary governance issue so frontend behavior and backend API semantics are documented together.