Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
3a52aab
Add Generic Event Sourcing and ReadModel Requirements Documentation
loning Feb 23, 2026
07c4668
Add Provider-Based ReadModel Architecture and Elasticsearch/InMemory …
loning Feb 23, 2026
08c1ce2
Enhance Event Sourcing and Add Neo4j Provider Support
loning Feb 23, 2026
fb9a113
Enhance Event Sourcing with State Event Appliers and Transition Matchers
loning Feb 23, 2026
b2d8763
Implement CI Guard for Direct State Mutation in GAgentBase
loning Feb 23, 2026
c340f0e
Add File-Based Event Store and Update Docker Compose for Providers
loning Feb 23, 2026
45b6d9d
Enhance Event Sourcing with Automatic Snapshots and Event Compaction
loning Feb 23, 2026
9b820f4
Implement Event Store Compaction and Deactivation Hooks
loning Feb 23, 2026
0984e46
Refactor Workflow Projection Registration and Enhance ReadModel Provi…
loning Feb 23, 2026
413d369
Enhance CI Workflow with Path Filtering and New Job Structure
loning Feb 23, 2026
7a31e4a
Add Prepare Runner Action and Update CI Workflows
loning Feb 23, 2026
c433e16
Enhance RoleGAgent with Event Sourcing and Replay Contract Tests
loning Feb 23, 2026
0bd186e
Implement Garnet Event Store for Production Persistence
loning Feb 23, 2026
8b9892a
Merge branch 'feat/generic-event-sourcing-elasticsearch-readmodel' of…
loning Feb 23, 2026
d6d875e
Enhance CI Workflow with Orleans Garnet Persistence Integration Job
loning Feb 23, 2026
7223228
Update CI Workflow and Documentation for Split Test Guards
loning Feb 23, 2026
719f425
Enhance Event Sourcing Architecture and CI Workflow
loning Feb 23, 2026
67bdc14
Enhance CI Workflow and Projection ReadModel Architecture
loning Feb 23, 2026
f4fa6b0
Add Full Solution Regression Test to CI Workflow
loning Feb 23, 2026
26f40a7
Add Audit Scorecard for ReadModel Index Architecture
loning Feb 24, 2026
7fe6160
Add ReadModel Graph Relations Refactor Blueprint and Related Abstract…
loning Feb 24, 2026
cdebcbc
Refactor ReadModel Graph Relations and Enhance Projection Architecture
loning Feb 24, 2026
ba6da81
Merge pull request #14 from aevatarAI/feat/readmodel-graph-relations
loning Feb 24, 2026
dceaaa3
Refactor Elasticsearch Provider and Enhance ReadModel Architecture
loning Feb 24, 2026
148046d
Refactor Projection Architecture and Introduce Store Selection Mechanism
loning Feb 24, 2026
cf03a23
Refactor Projection Abstractions and Introduce Core/Stores Separation
loning Feb 24, 2026
4b55344
Refactor Projection Abstractions and Update Global Usings
loning Feb 24, 2026
cae5229
Remove Deprecated Audit Scorecard Documents
loning Feb 24, 2026
c824b36
Add Projection ReadModel Refactor Plan and Audit Scorecard
loning Feb 24, 2026
5b18a6b
Refactor Projection ReadModel Architecture and Enhance Provider Capab…
loning Feb 24, 2026
6da09aa
Enhance Projection Architecture with New Runtime Abstractions and Pro…
loning Feb 24, 2026
70a5682
Refactor Projection ReadModel and Provider Architecture for Enhanced …
loning Feb 24, 2026
b61134b
Refactor Projection ReadModel Architecture and Streamline Provider Se…
loning Feb 24, 2026
651a1b1
Refactor Neo4j Provider and Update Projection ReadModel Documentation
loning Feb 24, 2026
ff4c8e2
Refactor Projection ReadModel and Update Audit Scorecard Documentation
loning Feb 24, 2026
ffb36c5
Enhance Projection ReadModel with Primary Query Provider and Edge Man…
loning Feb 24, 2026
7be347b
Refactor Projection ReadModel and Enhance Provider Registration
loning Feb 24, 2026
2e473fb
Refactor Projection ReadModel and Enhance Metadata Handling
loning Feb 24, 2026
22f4aaf
Refactor Projection Ownership Management and Update Interfaces
loning Feb 24, 2026
be1abf6
Add Projection Storage Architecture Audit Scorecard
loning Feb 24, 2026
cd141f9
Enhance Projection Storage Architecture Documentation
loning Feb 24, 2026
4c5613e
Refactor Projection Store Interfaces and Update Dependency Injection
loning Feb 24, 2026
3c967fd
Remove Outdated Projection Store and Audit Scorecard Documentation
loning Feb 24, 2026
a0b6a78
Enhance Projection ReadModel and Update Dependency Injection
loning Feb 24, 2026
7900b53
Add State Mirror Projection and Update Dependency Injection
loning Feb 24, 2026
b871575
Refactor Elasticsearch Projection Document Store and Enhance Support …
loning Feb 24, 2026
a545aa8
Implement projection reliability fixes and update architecture audit …
eanzhao Feb 25, 2026
5f9fda4
Add strict architecture audit report for PR #13 and update temperatur…
loning Feb 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/actions/prepare-runner/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Prepare Runner
description: Setup .NET SDK, cache NuGet packages, and optionally install ripgrep.
inputs:
setup-dotnet:
description: Whether to install .NET SDK from global.json.
required: false
default: "true"
cache-nuget:
description: Whether to cache ~/.nuget/packages.
required: false
default: "true"
install-ripgrep:
description: Whether to install ripgrep when missing.
required: false
default: "false"
runs:
using: composite
steps:
- name: Setup .NET
if: ${{ inputs.setup-dotnet == 'true' }}
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json

- name: Cache NuGet Packages
if: ${{ inputs.cache-nuget == 'true' }}
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('global.json', 'Directory.Build.props', 'Directory.Packages.props', '**/*.csproj', '**/*.props', '**/*.targets') }}
restore-keys: |
${{ runner.os }}-nuget-

- name: Ensure ripgrep
if: ${{ inputs.install-ripgrep == 'true' }}
shell: bash
run: |
if ! command -v rg >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y ripgrep
fi
237 changes: 209 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,81 @@ on:
- cron: "0 3 * * *"
workflow_dispatch:

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
fast-build-test:
changes:
if: github.event_name != 'schedule'
runs-on: ubuntu-latest
outputs:
core_code: ${{ steps.filter.outputs.core_code }}
projection_provider: ${{ steps.filter.outputs.projection_provider }}
kafka_runtime: ${{ steps.filter.outputs.kafka_runtime }}
event_sourcing: ${{ steps.filter.outputs.event_sourcing }}
steps:
- uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json

- name: Install ripgrep
run: |
sudo apt-get update
sudo apt-get install -y ripgrep
fetch-depth: 0

- name: Restore
run: dotnet restore aevatar.slnx --nologo
- name: Detect Changed Paths
id: filter
uses: dorny/paths-filter@v3
with:
filters: |
core_code:
- 'src/**'
- 'test/**'
- 'aevatar.slnx'
- 'aevatar.*.slnf'
- 'Directory.Build.props'
- 'Directory.Packages.props'
- 'global.json'
- 'tools/ci/**'
- '.github/workflows/ci.yml'
projection_provider:
- 'docker-compose.projection-providers.yml'
- 'src/Aevatar.CQRS.Projection.*/**'
- 'src/Aevatar.CQRS.Projection.Core/**'
- 'src/workflow/Aevatar.Workflow.Projection/**'
- 'src/workflow/extensions/Aevatar.Workflow.Extensions.Hosting/**'
- 'src/workflow/Aevatar.Workflow.Infrastructure/DependencyInjection/WorkflowCapabilityServiceCollectionExtensions.cs'
- 'test/Aevatar.CQRS.Projection.Core.Tests/**'
- 'test/Aevatar.Workflow.Host.Api.Tests/**'
- 'tools/ci/projection_provider_e2e_smoke.sh'
- '.github/workflows/ci.yml'
kafka_runtime:
- 'docker-compose.yml'
- 'src/Aevatar.Foundation.Runtime*/**'
- 'test/Aevatar.Foundation.Runtime.Hosting.Tests/**'
- '.github/workflows/ci.yml'
event_sourcing:
- 'src/Aevatar.Foundation.Core/**'
- 'src/Aevatar.Foundation.Runtime/**'
- 'src/Aevatar.Foundation.Runtime.Implementations.Orleans/**'
- 'src/Aevatar.Foundation.Runtime.Persistence.Implementations.Garnet/**'
- 'test/Aevatar.Foundation.Core.Tests/**'
- 'test/Aevatar.Foundation.Runtime.Hosting.Tests/**'
- 'tools/ci/event_sourcing_regression.sh'
- 'tools/ci/orleans_garnet_persistence_smoke.sh'
- 'tools/ci/architecture_guards.sh'
- '.github/workflows/ci.yml'

- name: Build
run: dotnet build aevatar.slnx --nologo --no-restore --tl:off -m:1 -p:UseSharedCompilation=false -p:NuGetAudit=false
fast-gates:
if: github.event_name != 'schedule' && (github.event_name == 'workflow_dispatch' || needs.changes.outputs.core_code == 'true')
needs: changes
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4

- name: Coverage Quality Guard
env:
COVERAGE_LINE_THRESHOLD: "85"
COVERAGE_BRANCH_THRESHOLD: "72"
run: bash tools/ci/coverage_quality_guard.sh
- name: Prepare Runner
uses: ./.github/actions/prepare-runner
with:
setup-dotnet: "false"
cache-nuget: "false"
install-ripgrep: "true"

- name: Architecture Guards (full-scan + projection route mapping)
env:
Expand All @@ -51,11 +98,103 @@ jobs:
- name: Test Stability Guards
run: bash tools/ci/test_stability_guards.sh

- name: Solution Split Test Guards
env:
SPLIT_TEST_NO_RESTORE: "1"
SPLIT_TEST_NO_BUILD: "1"
run: bash tools/ci/solution_split_test_guards.sh
full-solution-regression:
if: github.event_name == 'pull_request' && needs.changes.outputs.core_code == 'true'
needs: changes
runs-on: ubuntu-latest
timeout-minutes: 55
steps:
- uses: actions/checkout@v4

- name: Prepare Runner
uses: ./.github/actions/prepare-runner

- name: Restore and Build
run: bash tools/ci/restore_and_build.sh

- name: Full Solution Regression Test
run: |
dotnet test aevatar.slnx \
--nologo \
--tl:off \
-m:1 \
-p:UseSharedCompilation=false \
-p:NuGetAudit=false \
--no-build

split-test-guards:
if: |
github.event_name == 'workflow_dispatch' ||
github.event_name == 'schedule' ||
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev'))
runs-on: ubuntu-latest
timeout-minutes: 35
strategy:
fail-fast: false
matrix:
solution_filter:
- aevatar.foundation.slnf
- aevatar.ai.slnf
- aevatar.cqrs.slnf
- aevatar.workflow.slnf
- aevatar.hosting.slnf
- aevatar.distributed.slnf
steps:
- uses: actions/checkout@v4

- name: Prepare Runner
uses: ./.github/actions/prepare-runner

- name: Run split test guard (${{ matrix.solution_filter }})
run: |
dotnet test "${{ matrix.solution_filter }}" \
--nologo \
--tl:off \
-m:1 \
-p:UseSharedCompilation=false \
-p:NuGetAudit=false

projection-provider-e2e:
if: |
github.event_name != 'schedule' && (
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) ||
needs.changes.outputs.projection_provider == 'true'
)
needs:
- changes
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v4

- name: Prepare Runner
uses: ./.github/actions/prepare-runner
with:
install-ripgrep: "true"

- name: Projection Provider E2E Smoke Test
run: bash tools/ci/projection_provider_e2e_smoke.sh

kafka-transport-integration:
if: |
github.event_name != 'schedule' && (
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) ||
needs.changes.outputs.kafka_runtime == 'true'
)
needs:
- changes
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4

- name: Prepare Runner
uses: ./.github/actions/prepare-runner

- name: Restore and Build
run: bash tools/ci/restore_and_build.sh

- name: Start Kafka for Distributed Integration Test
run: docker compose up -d kafka
Expand Down Expand Up @@ -94,6 +233,50 @@ jobs:
if: always()
run: docker compose down --volumes --remove-orphans

event-sourcing-regression:
if: |
github.event_name != 'schedule' && (
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) ||
needs.changes.outputs.event_sourcing == 'true'
)
needs:
- changes
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4

- name: Prepare Runner
uses: ./.github/actions/prepare-runner
with:
install-ripgrep: "true"

- name: EventSourcing Regression
run: bash tools/ci/event_sourcing_regression.sh

coverage-quality:
if: |
github.event_name == 'workflow_dispatch' ||
github.event_name == 'schedule' ||
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev'))
runs-on: ubuntu-latest
timeout-minutes: 35
steps:
- uses: actions/checkout@v4

- name: Prepare Runner
uses: ./.github/actions/prepare-runner

- name: Restore and Build
run: bash tools/ci/restore_and_build.sh

- name: Coverage Quality Guard
env:
COVERAGE_LINE_THRESHOLD: "85"
COVERAGE_BRANCH_THRESHOLD: "72"
run: bash tools/ci/coverage_quality_guard.sh

distributed-3node-smoke:
if: |
github.event_name == 'schedule' ||
Expand All @@ -104,10 +287,8 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Prepare Runner
uses: ./.github/actions/prepare-runner

- name: 3-Node Distributed Smoke Test
run: bash tools/ci/distributed_3node_smoke.sh
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ curl -X POST http://localhost:5000/api/chat \
| Orleans Transport | `ActorRuntime:Provider=Orleans` 默认仍走内置链路;可选 `ActorRuntime:Transport=Kafka` 启用 MassTransit/Kafka 传输插件。 | 生产按部署拓扑启用可插拔 transport,并统一由 stream/queue 层承载跨节点转发。 |
| Projection 启动并发(Ensure/Release) | 已由 `projection:{rootActorId}` 投影协调 Actor 串行裁决,不再依赖进程内 `SemaphoreSlim`。 | 分布式 Runtime 下继续依赖“同一 actorId 单激活 + 邮箱串行”保证并发互斥。 |
| LiveSink 绑定(Attach/Detach) | 已通过 `workflow-run:{actorId}:{commandId}` 事件流订阅/退订;不再依赖 `ProjectionContext` 内存 sink 列表。 | 在分布式 stream provider 下天然支持跨节点推送;生产需保障 provider 可用性与顺序语义。 |
| ReadModel 存储 | Workflow 默认 `InMemoryWorkflowExecutionReadModelStore`,可替换。 | 生产默认切换到持久化读模型存储,实现跨节点一致读。 |
| ReadModel 存储 | 默认通过 `Aevatar.CQRS.Projection.Providers.InMemory` 注册通用 InMemory Store,可按 Provider 机制替换。 | 生产默认切换到持久化读模型 Provider,实现跨节点一致读。 |
| 审计评分口径 | 以“当前已落地代码”为准评分。 | 目标态能力上线后,评分按实现结果重新审计。 |

下面这张图概括了「宿主(API + 运行时 + LLM + Connector)」与「Agent 树 + 工作流步骤」的关系。
Expand Down
3 changes: 2 additions & 1 deletion aevatar.cqrs.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"projects": [
"src\\Aevatar.CQRS.Core.Abstractions\\Aevatar.CQRS.Core.Abstractions.csproj",
"src\\Aevatar.CQRS.Core\\Aevatar.CQRS.Core.csproj",
"src\\Aevatar.CQRS.Projection.Abstractions\\Aevatar.CQRS.Projection.Abstractions.csproj",
"src\\Aevatar.CQRS.Projection.Core.Abstractions\\Aevatar.CQRS.Projection.Core.Abstractions.csproj",
"src\\Aevatar.CQRS.Projection.Stores.Abstractions\\Aevatar.CQRS.Projection.Stores.Abstractions.csproj",
"src\\Aevatar.CQRS.Projection.Core\\Aevatar.CQRS.Projection.Core.csproj",
"src\\Aevatar.Foundation.Projection\\Aevatar.Foundation.Projection.csproj",
"test\\Aevatar.CQRS.Core.Tests\\Aevatar.CQRS.Core.Tests.csproj",
Expand Down
Loading