Context
Follow-up to #117 / #195. When AtlassianClient refreshes an access token mid-ingestion (401 → refresh → retry), the rotated {access_token, refresh_token, expires_at} lives only in the in-memory toolkit instance and is discarded when the run ends. The SPA's localStorage still holds the pre-refresh refresh_token.
For short ingestions (< 1h) this is invisible — Atlassian access tokens last ~1 hour and the SPA's own refreshAtlassianIfNeeded() covers the next session. For long ingestions (large Confluence spaces > 1h) the in-process refresh happens, the SPA never learns about it, and the next session may attempt to refresh with a stale refresh_token. Atlassian rotates refresh_tokens on every use, so the stale one returns 401 and the SPA forces the user to re-OAuth.
Acceptance
Out of scope
- Mid-run progress events do NOT carry tokens (avoid leaking via every SSE frame; one final event is enough).
- Git PAT does not need this — PATs don't rotate.
Notes
Parent
Follow-up to #117 / #195.
Context
Follow-up to #117 / #195. When
AtlassianClientrefreshes an access token mid-ingestion (401 → refresh → retry), the rotated{access_token, refresh_token, expires_at}lives only in the in-memory toolkit instance and is discarded when the run ends. The SPA'slocalStoragestill holds the pre-refresh refresh_token.For short ingestions (< 1h) this is invisible — Atlassian access tokens last ~1 hour and the SPA's own
refreshAtlassianIfNeeded()covers the next session. For long ingestions (large Confluence spaces > 1h) the in-process refresh happens, the SPA never learns about it, and the next session may attempt to refresh with a stale refresh_token. Atlassian rotates refresh_tokens on every use, so the stale one returns 401 and the SPA forces the user to re-OAuth.Acceptance
WikiService.generate()completes (success or partial), the SSEtask_status(completed)event payload includes the final in-memory{access_token, refresh_token, expires_at}if and only if the source_type is Atlassian-backed (confluenceorjira) and the toolkit's tokens have actually been rotated during the run.useConnections().saveAtlassian(...)with the merged connection so localStorage is up-to-date when the user next opens the dialog.TokenRedactionFilter. Add a unit test that asserts the completion-event payload renders as***in captured logs.# accepted limitationcomment inbackend/app/services/source_materializer.py(around lines 18-22) is removed; replace with a comment pointing to this issue's resolution.Out of scope
Notes
{wiki_id, page_count, execution_time}in the completion event. Need a small extension to the event Pydantic model.Parent
Follow-up to #117 / #195.