Skip to content

Issue #376: Remove StreamingProxy participant double writes#1024

Open
louis4li wants to merge 2 commits into
devfrom
feat/2026-05-25_issue-376
Open

Issue #376: Remove StreamingProxy participant double writes#1024
louis4li wants to merge 2 commits into
devfrom
feat/2026-05-25_issue-376

Conversation

@louis4li
Copy link
Copy Markdown
Contributor

Issue

Closes #376 — Actorize StreamingProxy orchestration and remove participant double writes

Summary

  • Removes the separate StreamingProxy participant actor/store writer path.
  • Reads participants from the room actor current-state projection via a query port.
  • Keeps the remaining Nyx round-progression actorization as follow-up scope because this PR isolates the participant double-authority defect.

Verification

  • dotnet build aevatar.slnx --nologo
  • dotnet test test/Aevatar.AI.Tests/Aevatar.AI.Tests.csproj --nologo --no-build
  • dotnet test test/Aevatar.Studio.Tests/Aevatar.Studio.Tests.csproj --nologo --no-build
  • bash tools/ci/architecture_guards.sh
  • bash tools/ci/test_stability_guards.sh
  • git diff --check

Follow-up split candidates

  1. Actorize StreamingProxy Nyx round progression into room actor continuations.
  2. Add a participant read-model freshness contract only if a stable consumer needs version/timestamp visibility.

🤖 Generated by codex-implement-loop. Reviewer is a Claude subagent.

Use the room actor current-state projection as the participant read source and remove the separate participant actor/store writer.

Closes #376

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c5d389624f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -537,17 +524,6 @@ private static async Task<IResult> HandleJoinAsync(
};
await DispatchRoomEnvelopeAsync(actorDispatchPort, actor.Id, envelope, ct);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Activate room projection before dispatching join events

HandleJoinAsync now only dispatches GroupChatParticipantJoinedEvent and returns, but it never ensures the room current-state projection is active first. In this module, the current-state lease is only explicitly activated from StreamingProxyRoomSessionProjectionPort.EnsureProjectionAsync (chat/subscription path), so a join on a room that has not started chat/streaming can be published before any projector subscribes; per IProjectedActor contract this can silently drop materialization, and IStreamingProxyParticipantQueryPort will then return an empty participant list until some later event replays state. This is a user-visible regression for “join then list participants” flows.

Useful? React with 👍 / 👎.

@louis4li
Copy link
Copy Markdown
Contributor Author

Review of PR #1024 — round 1

Verdict: rework
Issue: #376 — Actorize StreamingProxy orchestration and remove participant double writes
Head: feat/2026-05-25_issue-376 @ c5d3896
Base: dev
Reviewed by: Claude subagent (codex-implement-loop)

Verdict rationale (one paragraph)

The PR correctly removes the separate StreamingProxy participant write path and moves participant listing onto a room current-state projection, but it leaves the other explicit half of issue #376 unchanged: StreamingProxyNyxParticipantCoordinator still owns the multi-round transcript, active participant set, round loop, failed-participant pruning, and continuation decisions in request-path service-local collections. Because the issue body's suggested direction says to move transcript / round progression / continuation decisions into StreamingProxyGAgent state and event handlers and reduce the coordinator to LLM/Nyx I/O adaptation only, this is not just a follow-up enhancement; it is an unmet acceptance note and must be reworked before pass.

Findings

F1 — Nyx round progression still lives in coordinator-local collections

  • Severity: blocking
  • Dimension: issue-intent
  • Location: agents/Aevatar.GAgents.StreamingProxy/StreamingProxyNyxParticipantCoordinator.cs:96-198
  • Evidence:
    var provider = _llmProviderFactory.GetProvider(NyxIdProviderName);
    var transcript = new List<(string Speaker, string Content)>();
    var activeParticipants = participants.ToList();
    var rounds = activeParticipants.Count > 1 ? StreamingProxyDefaults.MaxDiscussionRounds : 1;
    var totalSuccessfulReplies = 0;
    
    for (var round = 1; round <= rounds && activeParticipants.Count > 0; round++)
    {
        var successfulReplies = 0;
        var failedParticipants = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
        var roundParticipants = activeParticipants.ToList();
        ...
        transcript.Add((participant.DisplayName, content));
        ...
        if (failedParticipants.Count > 0)
        {
            activeParticipants = activeParticipants
                .Where(participant => !failedParticipants.Contains(participant.ParticipantId))
                .ToList();
        }
        ...
    }
  • Why it's a problem: The issue body explicitly identifies this as part of the defect: "StreamingProxyNyxParticipantCoordinator currently decides rounds, accumulates transcript, and prunes failed participants in middle-layer local state." Its suggested direction says: "Move transcript / round progression / continuation decisions into StreamingProxyGAgent state and event handlers" and "Reduce StreamingProxyNyxParticipantCoordinator to LLM/Nyx I/O adaptation only." The acceptance notes also require "No request-path business progression in coordinator-local collections." The diff only swaps participant writes for projection reads; the request-path coordinator still makes the progression decisions and stores the mutable run facts locally.
  • What would change your verdict: Move the transcript, active participant set, round counter, failure pruning, and continue/stop decisions into StreamingProxyGAgent state/event handling. The coordinator should only perform Nyx/LLM I/O for actor-issued work and return/publish the response through an actor continuation event carrying explicit correlation keys such as room/session/round/participant. Add tests that assert the room actor drives round advancement and failure pruning rather than StreamingProxyNyxParticipantCoordinator.GenerateRepliesAsync doing it synchronously in local collections.

What's good

  • The separate IStreamingProxyParticipantStore write API and StreamingProxyParticipantGAgent/store actor path are removed from the PR diff, which addresses the participant double-write portion of the issue.
  • Participant listing now goes through IStreamingProxyParticipantQueryPort and reads StreamingProxyRoomCurrentStateDocument, aligning reads with a projection of the room actor state.
  • The new room current-state projector test verifies the committed room state is materialized with actor id, state version, event id, and typed protobuf StateRoot.

REVIEW_VERDICT:rework:coordinator still owns Nyx round progression

Move Nyx discussion progression into the room actor so the coordinator only performs participant LLM I/O.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@louis4li
Copy link
Copy Markdown
Contributor Author

Review of PR #1024 — round 2

Verdict: pass
Issue: #376 — Actorize StreamingProxy orchestration and remove participant double writes
Head: feat/2026-05-25_issue-376 @ 7922c06
Base: dev
Reviewed by: Claude subagent (codex-implement-loop)

Verdict rationale (one paragraph)

Round 2 resolves the prior blocking gap: the diff now moves Nyx discussion transcript, active participant pruning, round cursor, reply success/failure recording, and terminal continue/stop decisions into StreamingProxyGAgent typed protobuf state and event handlers, while StreamingProxyNyxParticipantCoordinator is reduced to provider discovery plus one Nyx/LLM participant work item that dispatches typed continuation events. The participant double-write portion remains addressed by removing IStreamingProxyParticipantStore, ActorBackedStreamingProxyParticipantStore, and StreamingProxyParticipantGAgent, and by reading participant lists from the room actor current-state projection through IStreamingProxyParticipantQueryPort. Sampled CLAUDE.md anti-patterns did not reveal new blocking violations: the only WriteActor hits in the PR diff are removed lines, and the new state/events are protobuf-defined rather than JSON/custom persisted payloads, matching the CLAUDE.md requirements that "Projection 运行态(会话、订阅、关联)必须由 Actor 或分布式状态承载" and "新增状态/事件/持久化载荷:先定义 .proto 并生成类型".

Findings

No blocking, comment, or nit findings.

What's good (mandatory on pass)

  • Round-1 F1 is resolved: StreamingProxyNyxParticipantCoordinator.GenerateRepliesAsync no longer owns transcript, activeParticipants, round loops, failed-participant pruning, or terminal status decisions; the replacement diff adds StreamingProxyGAgent.HandleNyxDiscussionRequested, HandleNyxParticipantReplySucceeded, HandleNyxParticipantReplyFailed, and ContinueNyxDiscussionAsync to drive that progression from actor state.
  • The participant double-write path is removed: IStreamingProxyParticipantStore, ActorBackedStreamingProxyParticipantStore, the StreamingProxyParticipantGAgent project, and join/delete/remove store writes are deleted, while participant listing now calls IStreamingProxyParticipantQueryPort.ListAsync against StreamingProxyRoomCurrentStateDocument.
  • Tests cover the changed semantics: new/updated tests assert actor-driven failed participant pruning, round advancement, coordinator non-progression behavior, single participant continuation events, endpoint query-port reads, and room current-state projection materialization.

Round comparison

  • Findings carried over from round 1: F1 (resolved)
  • New findings this round: none
  • Net direction: improving

REVIEW_VERDICT:pass:round progression actorized and participant double writes removed

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.

Actorize StreamingProxy orchestration and remove participant double writes

1 participant