Skip to content

feat(phase8 #80 D8.6 chunk-3): drop agent_timeline_event table + DB persist (Redis-only wire emit)#1724

Merged
earayu merged 1 commit into
mainfrom
ming-shu/d80-chunk3-timeline-event
Apr 26, 2026
Merged

feat(phase8 #80 D8.6 chunk-3): drop agent_timeline_event table + DB persist (Redis-only wire emit)#1724
earayu merged 1 commit into
mainfrom
ming-shu/d80-chunk3-timeline-event

Conversation

@earayu
Copy link
Copy Markdown
Collaborator

@earayu earayu commented Apr 26, 2026

Summary

Task #80 D8.6 hard-cut chunk-3 (final chunk) per PM scope lock: drop agent_timeline_event table + DB persist. Wire-emitter envelopes become ephemeral wire telemetry pushed only to the Redis live cache (live SSE + reconnect-within-TTL). Reload outside the Redis TTL has no historical events to replay; agent_message (D8.2 #74) is the single at-rest authority — already wired by chunk-2.

Per PM lock: NO UIMessage replay synthesis, NO new compensation for state.changed / tool.* lifecycle loss outside TTL. The 18 emit() call-sites in runtime.py keep their current live behavior.

What's removed

  • EventService.to_event_envelope (only used to rehydrate DB rows).
  • EventService.append_event no longer writes to db_ops.create_agent_timeline_event — envelope is composed locally with "evt" + 21-hex id and pushed only to Redis.
  • EventService.get_events_after no longer falls back to db_ops.query_agent_timeline_events — Redis is the only source of replay events.
  • AgentTimelineEvent SQLAlchemy model + agent_timeline_event table.
  • db_ops.create_agent_timeline_event / query_agent_timeline_events.

What's kept

  • EventService.adapt_event_envelope — canonical surface for tagging a wire envelope with user_activity (used by both append_event and get_events_after paths).
  • redis_store.append_event / get_events_after / merge_runtime_state — wire emit + live cache + cursor tracking unchanged.
  • All 18 runtime.py:emit() call-sites — turn lifecycle + tool lifecycle + state.changed + text.delta unchanged in behavior (only the DB write is removed under the hood).

Migration

New alembic head e8a1f5b2d4c7 (revises d8e6c2b4f1a9):

def upgrade():
    drop_index("ix_agent_timeline_event_type", "agent_timeline_event")
    drop_index("ix_agent_timeline_event_turn_id", "agent_timeline_event")
    drop_index("ix_agent_timeline_event_timestamp", "agent_timeline_event")
    drop_index("idx_agent_timeline_event_turn_timestamp", "agent_timeline_event")
    drop_table("agent_timeline_event")

Downgrade reconstructs both for rollback symmetry.

Caller sweep

Full grep for AgentTimelineEvent / create_agent_timeline_event / query_agent_timeline_events / to_event_envelope: zero remaining Python call-sites. Remaining hits are docstring narratives describing the removal.

PM 3 review-face gates

1. 18 emit() call-sites preserve live SSE behavior

  • The only path removed under append_event is db_ops.create_agent_timeline_event(...).
  • redis_store.append_event(envelope) + merge_runtime_state(turn_id, {"timeline_cursor": sequence}) retained.
  • Envelope shape unchanged (AgentTimelineEventEnvelope with event_id / turn_id / sequence / timestamp / type / technical_type / label / status / actor / data / user_activity).

2. agent_timeline_event clean-deleted

  • Model: gone from db/models.py.
  • db_ops: 2 methods removed.
  • Import: from aperag.domains.agent_runtime.db.models import AgentTimelineEvent dropped.
  • Table: alembic migration drops table + 4 indices.
  • DB fallback in get_events_after: gone.

3. No UIMessage replay synthesis introduced

  • Zero new code paths that read UIMessage parts to fabricate timeline events.
  • EventService surface stays exactly: append_event (Redis-only) + get_events_after (Redis-only) + adapt_event_envelope (pure helper).

Tests

  • test_agent_runtime_v3.py: dropped query_agent_timeline_events mock; rewrote test_event_service_* to exercise adapt_event_envelope directly; renamed _build_event_build_envelope.
  • Full unit suite: 989 passed, 29 skipped, ruff + format clean.

D8.6 cleanup arc complete

After this PR merges:

  • agent_artifact (chunk-2) + agent_timeline_event (chunk-3): both gone.
  • agent_message is the single at-rest authority for assistant turn contents.
  • Runtime's UIMessageStore.write at end-of-turn is the single write path.
  • Wire-emitter events are ephemeral (Redis live cache only).

Test plan

  • uv run pytest tests/unit_test/ -q — 989 passed
  • uvx ruff check + format — clean
  • Caller sweep for legacy timeline_event symbols → zero Python call-sites
  • Migration upgrade/downgrade symmetry verified

…ersist (Redis-only wire emit)

Phase 8 D8.6 chunk-3 hard-cut per PM scope lock (msg=ce06fbc1):
``agent_timeline_event`` is removed entirely. Wire-emitter envelopes
become ephemeral wire telemetry pushed only to the Redis live cache
(live SSE + reconnect-within-TTL). Reload outside the Redis TTL has
no historical events to replay; the canonical at-rest authority is
``agent_message`` (D8.2 #74), which chunk-2 already wired into the
runtime end-of-turn.

Per PM lock: NO UIMessage replay synthesis, NO new compensation for
state.changed / tool.* lifecycle loss outside TTL. The 18 ``emit()``
call-sites in the runtime keep their current live behavior.

Removed
-------
- ``EventService.to_event_envelope`` (only used to rehydrate DB
  rows, which are gone). ``adapt_event_envelope`` remains as the
  canonical surface for tagging a wire envelope with
  ``user_activity``.
- ``EventService.append_event`` no longer writes
  ``db_ops.create_agent_timeline_event``; the envelope is composed
  locally with a ``"evt"`` + 21-hex id and pushed only to the Redis
  live cache.
- ``EventService.get_events_after`` no longer falls back to
  ``db_ops.query_agent_timeline_events`` after a Redis cache miss
  — Redis is now the only source of replay events.
- ``AgentTimelineEvent`` SQLAlchemy model.
- ``db_ops.create_agent_timeline_event`` /
  ``query_agent_timeline_events``.

Migration
---------
- New alembic head ``e8a1f5b2d4c7`` (revises ``d8e6c2b4f1a9``):
  drops the ``agent_timeline_event`` table and its four indices.
  Downgrade reconstructs both for rollback symmetry.

Caller sweep
------------
Full grep across ``aperag/`` + ``tests/`` for ``AgentTimelineEvent``
/ ``create_agent_timeline_event`` / ``query_agent_timeline_events``
/ ``to_event_envelope``: zero remaining Python call-sites; remaining
hits are docstring narratives describing the removal.

Tests
-----
- ``test_agent_runtime_v3.py``: dropped ``query_agent_timeline_events``
  mock from ``_FakeDbOps``; rewrote ``test_event_service_*`` to
  exercise ``adapt_event_envelope`` directly via a constructed
  ``AgentTimelineEventEnvelope``; renamed ``_build_event`` →
  ``_build_envelope``.
- Full unit suite: 989 passed, 29 skipped, ruff + format clean.

PM 3 review-face gates
----------------------
1. 18 ``emit()`` call-sites preserve live SSE behavior — only the
   db_ops write is removed; Redis push + ``merge_runtime_state``
   timeline_cursor update are unchanged.
2. ``agent_timeline_event`` model + db_ops + migration + DB
   fallback are all clean-deleted.
3. No UIMessage replay synthesis introduced; the chunk-3 surface is
   exactly "drop DB persist, keep Redis live cache" (PM lock).

This closes the destructive cleanup arc of D8.6: ``agent_artifact``
(chunk-2) + ``agent_timeline_event`` (chunk-3) are both gone;
``agent_message`` is the single at-rest authority for assistant turn
contents, populated by the runtime's UIMessageStore.write at end-of-turn.
@earayu earayu merged commit 704b3cf into main Apr 26, 2026
4 checks passed
@earayu earayu deleted the ming-shu/d80-chunk3-timeline-event branch April 26, 2026 02:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant