Skip to content

Persist timeline and A2A state in shared SQL storage - #1778

Open
groupthinking with Copilot wants to merge 3 commits into
mainfrom
copilot/groupthinking-1509-persist-timeline-a2a-state
Open

Persist timeline and A2A state in shared SQL storage#1778
groupthinking with Copilot wants to merge 3 commits into
mainfrom
copilot/groupthinking-1509-persist-timeline-a2a-state

Conversation

Copilot AI commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Canonical issue

Shared state for session timelines and A2A logs now lives in SQL instead of process-local JSON/in-memory storage, with Postgres URLs normalized onto psycopg and session writes guarded against lost updates.

Outcome

Session timeline events and A2A messages survive cross-instance access and share a single SQLite/Postgres-backed source of truth. Concurrent session metadata updates no longer clobber each other on stale writes.

Scope

  • Included:
    • Shared SQL store — adds SharedSQLStateStore for sessions, timeline events, and A2A messages
    • Timeline persistenceSessionOrchestrationManager reads/writes session state through shared SQL and imports legacy JSON session data once
    • A2A persistenceAgentOrchestrator records and rehydrates A2A log entries from shared SQL when a shared DB is configured
    • Postgres URL normalization — accepts postgres://, postgresql://, postgresql+asyncpg://, and postgresql+psycopg2://, normalizing to postgresql+psycopg://
    • Lost-update protection — session row updates use a version-checked compare-and-swap retry loop
    • Regression coverage — adds tests for cross-instance timeline persistence, cross-instance A2A persistence, and URL normalization
  • Explicitly excluded:
    • Alembic-managed schema/migration plumbing for these shared-state tables
    • Changes to Firestore-backed pipeline state
    • Broader repository-wide persistence refactors outside session timeline/A2A state

Risk

  • Risk level: medium
  • Failure mode:
    • Existing JSON session files remain readable, but new session timeline state moves to SQL; misconfigured shared DB URLs would fall back only where the caller does not provide a shared DB
    • Orchestrator A2A persistence is only active when shared DB configuration is present
  • Rollback:
    • Revert SharedSQLStateStore integration in the session orchestration manager and agent orchestrator; legacy JSON bootstrap path remains available in the manager

Verification

List exact automated and manual checks, tied to the current head SHA.

  • Focused tests — 1aac5e8: PYTHONPATH=src python3 -m pytest --no-cov tests/unit/test_session_orchestration.py tests/unit/test_agent_orchestrator.py tests/unit/test_antigravity_backend.py tests/unit/test_antigravity_orchestration.py -q
  • Required CI
  • Review threads resolved

Production evidence

Not applicable. This change is backend/shared-state persistence work; no production deployment or Vercel-specific runtime evidence was required to validate the behavior.

Agent handoff

  • One canonical issue is linked
  • No competing PR implements the same issue
  • Acceptance criteria are satisfied
  • Required checks pass on the current head
  • Human decision is requested only for product, security, irreversible infrastructure, or production approval
def save_session(self, session: dict[str, Any]) -> dict[str, Any]:
    current = conn.execute(
        select(self.sessions.c.payload, self.sessions.c.version)
        .where(self.sessions.c.session_id == session_id)
    ).mappings().first()

    result = conn.execute(
        update(self.sessions)
        .where(
            self.sessions.c.session_id == session_id,
            self.sessions.c.version == current["version"],
        )
        .values(version=current["version"] + 1, payload=serialized_payload)
    )

@vercel

vercel Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
v0-uvai Ready Ready Preview, v0 Sep 8, 2026 11:33pm UTC

Copilot AI and others added 2 commits September 8, 2026 23:31
Co-authored-by: groupthinking <154503486+groupthinking@users.noreply.github.com>
Co-authored-by: groupthinking <154503486+groupthinking@users.noreply.github.com>
Copilot AI changed the title [WIP] Persist timeline and A2A state in shared SQL storage Persist timeline and A2A state in shared SQL storage Sep 8, 2026
Copilot AI requested a review from groupthinking September 8, 2026 23:35
try:
conn.execute(
insert(self.sessions).values(
session_id=session_id,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

save_session performs a full-snapshot merge and an ineffective version check, so concurrent read-modify-write callers silently lose committed updates.

Fix on Vercel

@groupthinking
groupthinking requested a balanced review from Copilot and removed request for groupthinking September 9, 2026 18:40
@groupthinking
groupthinking marked this pull request as ready for review September 9, 2026 18:40
@groupthinking
groupthinking self-requested a review as a code owner September 9, 2026 18:40
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

🔍 PR Validation

⚠️ PR title should follow conventional commits format
⚠️ Large PR detected (562 lines changed)

@github-actions github-actions Bot added the python label Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 1aac5e8.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

None

@groupthinking groupthinking left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Make sure no super seeded issue

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The CAS still permits stale metadata clobbering, and several persistence paths have concurrency and operational reliability gaps.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds shared SQL persistence for session timelines and A2A messages.

Changes:

  • Introduces SQLite/PostgreSQL shared-state storage and URL normalization.
  • Integrates persistence into session and agent orchestration.
  • Adds cross-instance regression tests.
File summaries
File Description
src/youtube_extension/services/shared_sql_state.py Implements shared SQL storage.
src/youtube_extension/services/agents/adapters/agent_orchestrator.py Persists and retrieves A2A logs.
scripts/maintenance/session_orchestration_manager.py Moves session timelines to SQL.
tests/unit/test_agent_orchestrator.py Tests A2A persistence and URL normalization.
tests/unit/test_session_orchestration.py Tests cross-instance timeline updates.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 8
  • Review effort level: Balanced

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +168 to +169
merged = self._deserialize(current["payload"])
merged.update(payload)
Comment on lines +205 to +206
self._shared_state.save_session(session)
self._shared_state.append_timeline_event(session_id, initial_event)
Comment on lines +252 to 255
session = self._shared_state.get_session(session_id)
if not session or session.get("status") != "running":
logger.error(f"Session {session_id} is not active.")
return False
Comment on lines +73 to +82
if shared_database_url:
try:
self._shared_state = SharedSQLStateStore(
database_url=shared_database_url
)
except Exception as exc:
self.logger.warning("Shared A2A SQL state unavailable: %s", exc)
self._shared_state = None
else:
self._shared_state = None
"strategic_analysis": ["personality_agent", "strategy_agent"],
"chat_assistance": ["transcript_action"],
}
self._hydrate_a2a_log()
Comment on lines +191 to +195
if self.get_session(session["id"]) is not None:
continue
self.save_session(session)
for event in session.get("timeline", []):
self.append_timeline_event(session["id"], event)
Comment on lines +212 to +215
for payload in rows:
session = self._deserialize(payload)
session["timeline"] = self.list_timeline(session["id"])
sessions[session["id"]] = session
Comment on lines +118 to +119
assert manager_one.send_message(session["id"], "first update") is True
assert manager_two.send_message(session["id"], "second update") is True

Copilot AI commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Make sure no super seeded issue

Checked: issue #1509 is the only canonical issue tied to this PR, and PR #1778 is the only open PR linked to it. I didn’t find any competing or superseded implementation PR for the same issue.

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

Pull request created: #1840

Generated by pr-iteration-loop · copilot · auto · 98.5 AIC · ⌖ 20.8 AIC · ⊞ 12.1K

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Persist timeline and A2A state in shared SQL storage

3 participants