Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,18 @@ jobs:
- name: Build
run: dotnet build GFramework.sln -c Release --no-restore

- name: Pack published modules
run: |
rm -rf ./packages
dotnet pack GFramework.sln \
-c Release \
--no-restore \
-o ./packages \
-p:IncludeSymbols=false
Comment thread
greptile-apps[bot] marked this conversation as resolved.

- name: Validate packed modules
run: bash scripts/validate-packed-modules.sh ./packages

# 运行单元测试,输出TRX格式结果到TestResults目录
# 顺序执行各测试项目,避免并发 dotnet test 进程导致“TRX 全绿但 step 仍返回失败”的假红状态
- name: Test All Projects
Expand Down
36 changes: 1 addition & 35 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,41 +82,7 @@ jobs:
-p:IncludeSymbols=false

- name: Validate packed modules
run: |
set -euo pipefail

expected_packages=(
"GeWuYou.GFramework"
"GeWuYou.GFramework.Core"
"GeWuYou.GFramework.Core.Abstractions"
"GeWuYou.GFramework.Core.SourceGenerators"
"GeWuYou.GFramework.Cqrs"
"GeWuYou.GFramework.Cqrs.Abstractions"
"GeWuYou.GFramework.Cqrs.SourceGenerators"
"GeWuYou.GFramework.Ecs.Arch"
"GeWuYou.GFramework.Ecs.Arch.Abstractions"
"GeWuYou.GFramework.Game"
"GeWuYou.GFramework.Game.Abstractions"
"GeWuYou.GFramework.Game.SourceGenerators"
"GeWuYou.GFramework.Godot"
"GeWuYou.GFramework.Godot.SourceGenerators"
)

mapfile -t actual_packages < <(
find ./packages -maxdepth 1 -type f -name '*.nupkg' -printf '%f\n' \
| sed -E 's/\.[0-9][0-9A-Za-z.-]*\.nupkg$//' \
| sort -u
)

printf '%s\n' "${expected_packages[@]}" | sort > expected-packages.txt
printf '%s\n' "${actual_packages[@]}" | sort > actual-packages.txt

echo "Expected packages:"
cat expected-packages.txt
echo "Actual packages:"
cat actual-packages.txt

diff -u expected-packages.txt actual-packages.txt
run: bash scripts/validate-packed-modules.sh ./packages

- name: Validate runtime-generator package boundaries
run: python3 scripts/validate-runtime-generator-boundaries.py --package-dir ./packages
Expand Down
3 changes: 3 additions & 0 deletions GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<!-- Keep benchmark infrastructure out of the published NuGet package set. -->
<IsPackable>false</IsPackable>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ CQRS 迁移与收敛。

## 当前恢复点

- 恢复点编号:`CQRS-REWRITE-RP-090`
- 恢复点编号:`CQRS-REWRITE-RP-091`
- 当前阶段:`Phase 8`
- 当前 PR 锚点:`PR #326`
- 当前 PR 锚点:`待创建`
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
- 当前结论:
- `GFramework.Cqrs` 已完成对外部 `Mediator` 的生产级替代,当前主线已从“是否可替代”转向“仓库内部收口与能力深化顺序”
- `dispatch/invoker` 生成前移已扩展到 request / stream 路径,`RP-077` 已补齐 request invoker provider gate 与 stream gate 对称的 descriptor / descriptor entry runtime 合同回归
Expand All @@ -26,11 +26,15 @@ CQRS 迁移与收敛。
- 当前 `RP-088` 已补齐 request invoker reflection / generated-provider 对照,开始直接量化 dispatcher 预热 generated descriptor 的收益
- 当前 `RP-089` 已补齐 stream invoker reflection / generated-provider 对照,使 generated descriptor 预热收益从 request 扩展到 stream 路径
- 当前 `RP-090` 已收敛 `PR #326` benchmark review:统一 benchmark 最小宿主构建、冻结 GFramework 容器、限制 MediatR 扫描范围,并恢复 request startup cold-start 对照
- `ai-plan` active 入口现以 `PR #326` 和 `RP-090` 为唯一权威恢复锚点;`PR #323`、`PR #307` 与其他更早阶段细节均以下方归档或说明为准
- 当前 `RP-091` 已把 benchmark 项目发布面隔离与包清单校验前移到 PR:`GFramework.Cqrs.Benchmarks` 明确保持不可打包,`publish.yml` 与 `ci.yml` 复用同一份 packed-modules 校验脚本
- `ai-plan` active 入口现以 `RP-091` 为最新恢复锚点;`PR #326`、`PR #323`、`PR #307` 与其他更早阶段细节均以下方归档或说明为准

## 当前活跃事实

- 当前分支对应 `PR #326`,状态为 `OPEN`
- 当前分支为 `fix/package-validation-guard`
- `GFramework.Cqrs.Benchmarks` 作为 benchmark 基础设施项目,必须持续排除在 NuGet / GitHub Packages 发布集合之外
- 发布工作流已有 packed modules 校验,但 PR 工作流此前没有等价的 solution pack 产物名单校验
- 本地 `dotnet pack GFramework.sln -c Release --no-restore -o <temp-dir>` 当前只产出 14 个预期包,未复现 benchmark `.nupkg`
- latest-head review 现仍有少量 open thread,但本地复核后,仍成立的问题已收敛到 benchmark 对照公平性、workflow 输入安全性与 active 文档压缩
- benchmark 场景现统一通过 `BenchmarkHostFactory` 构建最小宿主:GFramework 侧在 runtime 分发前显式 `Freeze()` 容器,MediatR 侧只扫描当前场景需要的 handler / behavior 类型
- `RequestStartupBenchmarks` 已恢复 `ColdStart_GFrameworkCqrs` 结果产出,不再命中 `No CQRS request handler registered`
Expand All @@ -41,12 +45,23 @@ CQRS 迁移与收敛。
## 当前风险

- 顶层 `GFramework.sln` / `GFramework.csproj` 在 WSL 下仍可能受 Windows NuGet fallback 配置影响,完整 solution 级验证成本高于模块级验证
- 若后续新增 benchmark / example / tooling 项目但未同步校验发布面,solution 级 `dotnet pack` 仍可能在 tag 发布前才暴露异常包
- `RequestStartupBenchmarks` 为了量化真正的单次 cold-start,引入了 `InvocationCount=1` / `UnrollFactor=1` 的专用 job;该配置会触发 BenchmarkDotNet 的 `MinIterationTime` 提示,后续若要做稳定基线比较,还需要决定是否引入批量外层循环或自定义 cold-start harness
- 仓库内部仍保留旧 `Command` / `Query` API、`LegacyICqrsRuntime` alias 与部分历史命名语义,后续若不继续分批收口,容易混淆“对外替代已完成”与“内部收口未完成”
- 若继续扩大 generated invoker 覆盖面,需要持续区分“可静态表达的合同”与 `PreciseReflectedRegistrationSpec` 等仍需保守回退的场景

## 最近权威验证

- `dotnet pack GFramework.sln -c Release --no-restore -o /tmp/gframework-pack-validation -p:IncludeSymbols=false`
- 结果:通过
- 备注:当前本地产物仅包含 14 个预期发布包,未生成 `GFramework.Cqrs.Benchmarks.*.nupkg`
- `bash scripts/validate-packed-modules.sh /tmp/gframework-pack-validation`
- 结果:通过
- 备注:共享脚本确认 actual package set 与预期 14 个发布包完全一致
- `dotnet build GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `python3 scripts/license-header.py --check`
- 结果:通过
- `dotnet run --project GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.csproj -c Release -- --filter "*RequestStartupBenchmarks*" --job short --warmupCount 1 --iterationCount 1 --launchCount 1`
- 结果:通过
- 备注:`ColdStart_GFrameworkCqrs` 已恢复出数,最新本地输出约 `220-292 us`,MediatR 对照约 `575-616 us`;当前仅剩 BenchmarkDotNet 对单次 cold-start 场景的 `MinIterationTime` 提示
Expand All @@ -64,9 +79,9 @@ CQRS 迁移与收敛。

## 下一推荐步骤

1. 重新运行 `$gframework-pr-review`,确认本轮 workflow / benchmark / active 文档修复是否已消化当前 latest-head open threads
2. 若 `PR #326` 仍剩基准语义类反馈,优先判断它们属于真实对照偏差还是有意保留的 benchmark 设计取舍
3. 若需要在 CI 中手动复核 benchmark,继续使用 workflow 的 `benchmark_filter` 输入按场景筛选,避免默认运行整个 benchmark 矩阵
1. 运行 `dotnet pack` 与新的 `scripts/validate-packed-modules.sh`,确认本轮共享校验脚本与 PR workflow 步骤在本地一致通过
2. 运行受影响的 Release build / 头部校验,确认 workflow 与脚本改动未引入新的命名、文件头或 shell 语法问题
3. 创建修复 PR 时,将重点放在“发布面保护前移到 PR”而不是“扩充 expected package 列表”

## 活跃文档

Expand Down
16 changes: 16 additions & 0 deletions ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

## 2026-05-06

### 阶段:benchmark 发布面隔离与包清单校验前移(CQRS-REWRITE-RP-091)

- 针对 tag 发布中出现的 `GFramework.Cqrs.Benchmarks` 异常包名单,本轮先复核 benchmark 项目与 solution pack 的本地事实:
- `GFramework.Cqrs.Benchmarks.csproj` 已包含 `IsPackable=false` 与 `GeneratePackageOnBuild=false`
- 本地执行 `dotnet pack GFramework.sln -c Release --no-restore -o /tmp/gframework-sln-pack-probe -p:IncludeSymbols=false` 时,产物仅包含 14 个预期发布包
- 因此本轮不把 benchmark 包加入发布白名单,而是把“benchmark 永不发布”与“PR 前置完整包名单校验”同时固化
- 本轮决策:
- 为 `GFramework.Cqrs.Benchmarks` 补充注释,明确其 benchmark-only 的发布边界
- 新增 `scripts/validate-packed-modules.sh`,集中维护预期包集合与实际 `.nupkg` diff 逻辑
- `publish.yml` 改为调用共享脚本,避免发布工作流与 PR 工作流各自维护一份包名单
- `ci.yml` 新增 solution `dotnet pack` 与 packed modules 校验,把异常发布包从 tag 发布前移到普通 PR 阶段
- 预期结果:
- benchmark / example / tooling 一类新项目若意外进入发布面,会先在 PR 失败,而不是等到 tag 发布
- 发布与 PR 使用同一份包名单规则,减少后续名单漂移
- `GFramework.Cqrs.Benchmarks` 继续只服务于 benchmark workflow,不进入 NuGet / GitHub Packages

### 阶段:benchmark 对照宿主收敛与 startup cold-start 恢复(CQRS-REWRITE-RP-090)

- 使用 `$gframework-pr-review` 拉取 `PR #326` latest-head review 后,主线程确认仍有效的 benchmark 反馈集中在三类问题:
Expand Down
51 changes: 51 additions & 0 deletions scripts/validate-packed-modules.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# Copyright (c) 2025-2026 GeWuYou
# SPDX-License-Identifier: Apache-2.0

set -euo pipefail

package_dir="${1:-./packages}"

if [ ! -d "$package_dir" ]; then
echo "Package directory not found: $package_dir" >&2
exit 1
fi

expected_packages=(
"GeWuYou.GFramework"
"GeWuYou.GFramework.Core"
"GeWuYou.GFramework.Core.Abstractions"
"GeWuYou.GFramework.Core.SourceGenerators"
"GeWuYou.GFramework.Cqrs"
"GeWuYou.GFramework.Cqrs.Abstractions"
"GeWuYou.GFramework.Cqrs.SourceGenerators"
"GeWuYou.GFramework.Ecs.Arch"
"GeWuYou.GFramework.Ecs.Arch.Abstractions"
"GeWuYou.GFramework.Game"
"GeWuYou.GFramework.Game.Abstractions"
"GeWuYou.GFramework.Game.SourceGenerators"
"GeWuYou.GFramework.Godot"
"GeWuYou.GFramework.Godot.SourceGenerators"
)

work_dir="$(mktemp -d)"
trap 'rm -rf "$work_dir"' EXIT

expected_file="$work_dir/expected-packages.txt"
actual_file="$work_dir/actual-packages.txt"

mapfile -t actual_packages < <(
find "$package_dir" -maxdepth 1 -type f -name '*.nupkg' -printf '%f\n' \
| sed -E 's/\.[0-9][0-9A-Za-z.-]*\.nupkg$//' \
| sort -u
)
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Comment thread
greptile-apps[bot] marked this conversation as resolved.

printf '%s\n' "${expected_packages[@]}" | sort > "$expected_file"
printf '%s\n' "${actual_packages[@]}" > "$actual_file"

echo "Expected packages:"
cat "$expected_file"
echo "Actual packages:"
cat "$actual_file"

diff -u "$expected_file" "$actual_file"
Loading