Skip to content
23 changes: 15 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,21 @@ All AI agents and contributors must follow these rules when writing, reviewing,
- Use `@.ai/environment/tools.raw.yaml` only when you need the full collected facts behind the AI-facing hints.
- Prefer the project-relevant tools listed there instead of assuming every installed system tool is fair game.
- If the real environment differs from the inventory, use the project-relevant installed tool and report the mismatch.
- When working in WSL against this repository's Windows-backed worktree, prefer Windows Git from WSL (for example
`git.exe`) instead of the Linux `git` binary.
- If a Git command in WSL fails with a worktree-style “not a git repository” path translation error, rerun it with the
Windows Git executable and treat that as the repository-default Git path for the rest of the task.
- If the shell does not currently resolve `git.exe` to the host Windows Git installation, prepend that installation's
command directory to `PATH` and reset shell command hashing for the current session before continuing.
- After resolving the host Windows Git path, prefer an explicit session-local binding for subsequent commands so the
shell does not fall back to Linux `/usr/bin/git` later in the same WSL session.
- When working in WSL against this repository's Windows-backed worktree, first prefer Linux `git` with an explicit
`--git-dir=<repo>/.git/worktrees/<worktree-name>` and `--work-tree=<worktree-root>` binding for every repository
command. Treat that explicit binding as higher priority than `git.exe`, because it avoids WSL worktree path
translation mistakes and still works in sessions where Windows `.exe` execution is unavailable.
- If a plain Linux `git` command in WSL fails with a worktree-style “not a git repository” path translation error,
rerun it with the explicit `--git-dir` / `--work-tree` binding before trying `git.exe`.
- Only prefer Windows Git from WSL (for example `git.exe`) when that executable is both resolvable and executable in the
current session, and when the explicit Linux `git` binding is unavailable or has already failed.
- If the shell resolves `git.exe` but the current WSL session cannot execute it cleanly (for example `Exec format
error`), keep using the explicit Linux `git` binding for the rest of the task instead of retrying Windows Git.
- If the shell does not currently resolve `git.exe` to the host Windows Git installation and you still need Windows Git
as a fallback, prepend that installation's command directory to `PATH` and reset shell command hashing for the
current session before continuing.
- After resolving either strategy, prefer a session-local binding or command wrapper for subsequent Git commands so the
shell does not silently fall back to the wrong repository context later in the same WSL session.

## Git Workflow Rules

Expand Down
55 changes: 39 additions & 16 deletions GFramework.Core.Abstractions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

`GFramework.Core.Abstractions` 承载 `Core` 运行时对应的接口、枚举和值对象,用来定义跨模块协作边界。

它只描述契约,不提供默认的架构、事件、状态、资源或 IoC 实现;这些实现都在 `GFramework.Core` 中。

## 什么时候单独依赖它

- 你在做插件、适配层或扩展包,只想依赖契约,不想把完整运行时拉进来
Expand All @@ -20,32 +22,53 @@

## 契约地图

| 目录 | 作用 |
| 目录族 | 作用 |
| --- | --- |
| `Architectures/` | `IArchitecture`、模块、阶段监听与服务管理契约 |
| `Command/` / `Query/` | 旧版命令与查询执行器接口 |
| `Controller/` | `IController` |
| `Events/` | 事件契约、解绑接口与传播上下文 |
| `Model/` / `Systems/` / `Utility/` | 核心组件接口 |
| `State/` / `StateManagement/` | 状态机、Store、reducer、selector 契约 |
| `Property/` | `IBindableProperty` 与只读属性接口 |
| `Resource/` | 资源管理与释放策略契约 |
| `Localization/` | 本地化表、格式化与异常类型 |
| `Logging/` | logger、log entry、factory 相关契约 |
| `Ioc/` | `IIocContainer` |
| `Lifecycle/` | 初始化 / 销毁生命周期契约 |
| `Coroutine/` | 时间源、yield 指令与协程状态枚举 |
| `Pause/` | 暂停栈、token 与状态事件 |
| `Storage/` / `Serializer/` / `Versioning/` | 通用存储、序列化与版本化契约 |
| `Architectures/` `Lifecycle/` `Registries/` | `IArchitecture`、上下文、模块、服务模块、阶段监听、注册表基类与生命周期契约 |
| `Bases/` `Controller/` `Model/` `Systems/` `Utility/` `Rule/` | 组件角色接口、优先级 / key 值对象、上下文感知约束与扩展边界 |
| `Command/` `Query/` `Cqrs/` | 旧版命令 / 查询执行器接口,以及 `ICqrsRuntime` 这类新请求模型接线契约 |
| `Events/` `Property/` `State/` `StateManagement/` | 事件总线、解绑对象、可绑定属性、状态机、Store / reducer / middleware 契约 |
| `Coroutine/` `Time/` `Pause/` `Concurrency/` | 协程状态、时间源、暂停栈、键控异步锁和统计对象 |
| `Resource/` `Pool/` `Logging/` `Localization/` | 资源句柄、对象池、日志、日志工厂、本地化表与格式化契约 |
| `Configuration/` `Environment/` | 配置管理器、环境对象与运行时环境访问契约 |
| `Data/` `Serializer/` `Storage/` `Versioning/` | 数据装载、序列化、存储与版本化契约 |
| `Enums/` `Properties/` | 架构阶段枚举,以及架构 / logger 相关属性键 |

## XML 覆盖基线

截至 `2026-04-22`,已按顶层目录对 `GFramework.Core.Abstractions` 的公开 / 内部类型声明做过一轮轻量盘点;当前契约目录族的类型声明都已带
XML 注释。这里记录的是类型族级基线,成员级契约细节仍需要在后续波次继续审计。

| 类型族 | 基线状态 | 代表类型 |
| --- | --- | --- |
| `Architectures/` `Lifecycle/` `Registries/` | `20/20` 个类型声明已带 XML 注释 | `IArchitecture`、`IArchitectureContext`、`IServiceModule`、`KeyValueRegistryBase<TKey, TValue>` |
| `Command/` `Query/` `Cqrs/` | `10/10` 个类型声明已带 XML 注释 | `ICommandExecutor`、`IAsyncQueryExecutor`、`ICqrsRuntime` |
| `Events/` `Property/` `State/` `StateManagement/` | `25/25` 个类型声明已带 XML 注释 | `IEventBus`、`IBindableProperty<T>`、`IStateMachine`、`IStore<TState>` |
| `Coroutine/` `Time/` `Pause/` `Concurrency/` | `17/17` 个类型声明已带 XML 注释 | `IYieldInstruction`、`ITimeProvider`、`IPauseStackManager`、`IAsyncKeyLockManager` |
| `Resource/` `Pool/` `Logging/` `Localization/` | `27/27` 个类型声明已带 XML 注释 | `IResourceManager`、`IObjectPoolSystem`、`ILogger`、`ILocalizationManager` |
| `Configuration/` `Environment/` `Data/` `Serializer/` `Storage/` `Versioning/` | `7/7` 个类型声明已带 XML 注释 | `IConfigurationManager`、`IEnvironment`、`ILoadableFrom<T>`、`ISerializer`、`IStorage` |
| `Bases/` `Controller/` `Model/` `Systems/` `Utility/` `Rule/` `Enums/` `Properties/` | `19/19` 个类型声明已带 XML 注释 | `IPrioritized`、`IController`、`IModel`、`ISystem`、`IContextUtility`、`ArchitecturePhase` |

完整 inventory 与阅读顺序见 `docs/zh-CN/abstractions/core-abstractions.md`。

## 采用建议

- 框架消费者通常同时安装 `GFramework.Core` 与 `GFramework.Core.Abstractions`
- 若你只需要对接口编程,可以仅引用本包,再在应用层自行提供实现
- 若你在写上层模块,优先把公共契约放在 `*.Abstractions`,实现放在对应 runtime 包

## 重点 XML 关注点

如果你在做契约审计、模块拆分或测试替身,优先看这些类型族的 XML 文档:

- 架构与模块入口:`IArchitecture`、`IArchitectureContext`、`IServiceModule`
- 运行时基础设施:`IIocContainer`、`ILogger`、`IResourceManager`、`IConfigurationManager`
- 状态与并发能力:`IStateMachine`、`IStore`、`IAsyncKeyLockManager`、`ITimeProvider`
- 迁移与组合边界:`ICommandExecutor`、`IQueryExecutor`、`ICqrsRuntime`

## 对应文档

- 抽象接口栏目:[`../docs/zh-CN/abstractions/index.md`](../docs/zh-CN/abstractions/index.md)
- Core 抽象页:[`../docs/zh-CN/abstractions/core-abstractions.md`](../docs/zh-CN/abstractions/core-abstractions.md)
- Core 运行时入口:[`../GFramework.Core/README.md`](../GFramework.Core/README.md)
- API 参考入口:[`../docs/zh-CN/api-reference/index.md`](../docs/zh-CN/api-reference/index.md)
32 changes: 29 additions & 3 deletions GFramework.Core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@

- `Architecture` 与 `ArchitectureContext`
- `Model` / `System` / `Utility` 运行时
- 旧版 `Command` / `Query` 执行器
- 事件、属性、状态机、状态管理
- 资源、日志、协程、并发、环境与本地化
- 旧版 `Command` / `Query` 执行器,以及与新版 `CQRS` runtime 的接线入口
- 事件、属性、状态机、状态管理、规则与上下文扩展
- 资源、对象池、日志、协程、并发、环境、配置与本地化
- 服务模块管理、时间提供器与默认的 IoC 容器适配

它不负责:

Expand All @@ -37,22 +38,45 @@
| 目录 | 作用 |
| --- | --- |
| `Architectures/` | 架构入口、上下文、生命周期、模块安装与组件注册 |
| `Services/` | 服务模块注册、生命周期协调与模块管理 |
| `Command/` | 旧版命令执行器与同步 / 异步命令基类 |
| `Query/` | 旧版查询执行器与同步 / 异步查询基类 |
| `Events/` | 事件总线、事件作用域、统计与过滤 |
| `Property/` | `BindableProperty<T>` 与相关解绑对象 |
| `State/` | 状态机与状态切换事件 |
| `StateManagement/` | Store、selector、middleware 与状态诊断 |
| `Coroutine/` | 协程调度、快照、统计与优先级 |
| `Time/` | 默认时间提供器与协程时间源 |
| `Resource/` | 资源缓存、句柄和释放策略 |
| `Pool/` | 对象池系统与常用池化辅助实现 |
| `Logging/` | logger、factory、配置与组合日志器 |
| `Ioc/` | 基于 `Microsoft.Extensions.DependencyInjection` 的容器适配 |
| `Concurrency/` | 键控异步锁与统计 |
| `Configuration/` | 配置管理器与配置监听解绑对象 |
| `Environment/` | 运行环境对象与上下文环境扩展 |
| `Pause/` | 暂停栈和暂停范围 |
| `Localization/` | 本地化表与格式化入口 |
| `Rule/` | `ContextAwareBase` 等上下文感知基类 |
| `Functional/` | `Option`、`Result` 等轻量函数式工具 |
| `Extensions/` | 上下文与集合等扩展方法 |

## XML 覆盖基线

截至 `2026-04-22`,已按顶层目录对 `GFramework.Core` 的公开 / 内部类型声明做过一轮轻量盘点;当前主目录族的类型声明都已带
XML 注释。这里先保留阅读基线,成员级 ``<param>`` / ``<returns>`` / 生命周期语义审计仍属于后续治理项。

| 类型族 | 基线状态 | 代表类型 |
| --- | --- | --- |
| `Architectures/` `Services/` | `22/22` 个类型声明已带 XML 注释 | `Architecture`、`ArchitectureContext`、`ArchitectureLifecycle`、`ServiceModuleManager` |
| `Command/` `Query/` | `15/15` 个类型声明已带 XML 注释 | `CommandExecutor`、`AsyncQueryExecutor`、`AbstractCommand<TInput>`、`AbstractQuery<TResult>` |
| `Events/` `Property/` `State/` `StateManagement/` | `29/29` 个类型声明已带 XML 注释 | `EventBus`、`BindableProperty<T>`、`StateMachine`、`Store<TState>` |
| `Coroutine/` `Time/` `Pause/` `Concurrency/` | `43/43` 个类型声明已带 XML 注释 | `CoroutineScheduler`、`CoroutineHandle`、`PauseStackManager`、`AsyncKeyLockManager` |
| `Resource/` `Pool/` | `8/8` 个类型声明已带 XML 注释 | `ResourceManager`、`AutoReleaseStrategy`、`AbstractObjectPoolSystem<TKey, TObject>` |
| `Logging/` `Localization/` `Configuration/` `Environment/` `Ioc/` | `31/31` 个类型声明已带 XML 注释 | `ConsoleLogger`、`LocalizationManager`、`ConfigurationManager`、`DefaultEnvironment`、`MicrosoftDiContainer` |
| `Model/` `Systems/` `Utility/` `Rule/` `Extensions/` `Functional/` | `34/34` 个类型声明已带 XML 注释 | `AbstractModel`、`AbstractSystem`、`NumericDisplayFormatter`、`ContextAwareBase`、`Result<T>` |

完整的模块化阅读顺序和 inventory 说明见 `docs/zh-CN/core/index.md`。

## 最小接入路径

```bash
Expand Down Expand Up @@ -80,5 +104,7 @@ dotnet add package GeWuYou.GFramework.Core.Abstractions
## 对应文档

- Core 栏目:[`../docs/zh-CN/core/index.md`](../docs/zh-CN/core/index.md)
- Core 抽象层:[`../docs/zh-CN/abstractions/core-abstractions.md`](../docs/zh-CN/abstractions/core-abstractions.md)
- API 参考入口:[`../docs/zh-CN/api-reference/index.md`](../docs/zh-CN/api-reference/index.md)
- CQRS:[`../docs/zh-CN/core/cqrs.md`](../docs/zh-CN/core/cqrs.md)
- 入门指南:[`../docs/zh-CN/getting-started/index.md`](../docs/zh-CN/getting-started/index.md)
Original file line number Diff line number Diff line change
Expand Up @@ -1144,13 +1144,28 @@ private readonly record struct ReflectedImplementationRegistrationSpec(
string HandlerInterfaceDisplayName,
string HandlerInterfaceLogName);

/// <summary>
/// 标记某条 handler 注册语句在生成阶段采用的表达策略。
/// </summary>
/// <remarks>
/// 该枚举只服务于输出排序与代码分支选择,用来保证生成注册器在“直接注册”
/// “反射实现类型查找”和“精确运行时类型解析”之间保持稳定顺序。
/// </remarks>
private enum OrderedRegistrationKind
{
Direct,
ReflectedImplementation,
PreciseReflected
}

/// <summary>
/// 描述生成注册器中某个运行时类型引用的构造方式。
/// </summary>
/// <remarks>
/// 某些 handler 服务类型可以直接以 <c>typeof(...)</c> 输出,某些则需要在运行时补充
/// 反射查找、数组/指针封装或泛型实参重建。该记录把这些差异收敛为统一的递归结构,
/// 供源码输出阶段生成稳定的类型解析语句。
/// </remarks>
private sealed record RuntimeTypeReferenceSpec(
string? TypeDisplayName,
string? ReflectionTypeMetadataName,
Expand All @@ -1161,18 +1176,27 @@ private sealed record RuntimeTypeReferenceSpec(
RuntimeTypeReferenceSpec? GenericTypeDefinitionReference,
ImmutableArray<RuntimeTypeReferenceSpec> GenericTypeArguments)
{
/// <summary>
/// 创建一个可直接通过 <c>typeof(...)</c> 表达的类型引用。
/// </summary>
public static RuntimeTypeReferenceSpec FromDirectReference(string typeDisplayName)
{
return new RuntimeTypeReferenceSpec(typeDisplayName, null, null, null, 0, null, null,
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
}

/// <summary>
/// 创建一个需要从当前消费端程序集反射解析的类型引用。
/// </summary>
public static RuntimeTypeReferenceSpec FromReflectionLookup(string reflectionTypeMetadataName)
{
return new RuntimeTypeReferenceSpec(null, reflectionTypeMetadataName, null, null, 0, null, null,
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
}

/// <summary>
/// 创建一个需要从被引用程序集反射解析的类型引用。
/// </summary>
public static RuntimeTypeReferenceSpec FromExternalReflectionLookup(
string reflectionAssemblyName,
string reflectionTypeMetadataName)
Expand All @@ -1182,18 +1206,27 @@ public static RuntimeTypeReferenceSpec FromExternalReflectionLookup(
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
}

/// <summary>
/// 创建一个数组类型引用。
/// </summary>
public static RuntimeTypeReferenceSpec FromArray(RuntimeTypeReferenceSpec elementTypeReference, int arrayRank)
{
return new RuntimeTypeReferenceSpec(null, null, null, elementTypeReference, arrayRank, null, null,
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
}

/// <summary>
/// 创建一个指针类型引用。
/// </summary>
public static RuntimeTypeReferenceSpec FromPointer(RuntimeTypeReferenceSpec pointedAtTypeReference)
{
return new RuntimeTypeReferenceSpec(null, null, null, null, 0, pointedAtTypeReference, null,
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
}

/// <summary>
/// 创建一个封闭泛型类型引用。
/// </summary>
public static RuntimeTypeReferenceSpec FromConstructedGeneric(
RuntimeTypeReferenceSpec genericTypeDefinitionReference,
ImmutableArray<RuntimeTypeReferenceSpec> genericTypeArguments)
Expand Down
38 changes: 38 additions & 0 deletions GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -651,32 +651,70 @@ public static GeneratedRegistrationResult WithReflectionFallback(
}
}

/// <summary>
/// 描述某个程序集在生成注册器之后仍需运行时补扫的 handler 元数据。
/// </summary>
/// <remarks>
/// 该对象把“是否存在精确 fallback 类型列表”与“是否只能回退到整程序集扫描”收敛为同一份内部状态,
/// 供注册流水线后续阶段统一判断。
/// </remarks>
private sealed class ReflectionFallbackMetadata(IReadOnlyList<Type> types)
{
/// <summary>
/// 获取需要通过运行时反射补充注册的 handler 类型集合。
/// </summary>
public IReadOnlyList<Type> Types { get; } = types ?? throw new ArgumentNullException(nameof(types));

/// <summary>
/// 获取当前是否持有精确的 fallback 类型清单。
/// </summary>
public bool HasExplicitTypes => Types.Count > 0;
}

/// <summary>
/// 描述单个程序集在注册阶段提取到的 generated registry 与 reflection fallback 元数据。
/// </summary>
private sealed class AssemblyRegistrationMetadata(
IReadOnlyList<Type> registryTypes,
ReflectionFallbackMetadata? reflectionFallbackMetadata)
{
/// <summary>
/// 获取程序集上声明的 generated registry 类型集合。
/// </summary>
public IReadOnlyList<Type> RegistryTypes { get; } =
registryTypes ?? throw new ArgumentNullException(nameof(registryTypes));

/// <summary>
/// 获取该程序集是否还要求运行时补充 reflection fallback。
/// </summary>
public ReflectionFallbackMetadata? ReflectionFallbackMetadata { get; } = reflectionFallbackMetadata;
}

/// <summary>
/// 缓存 generated registry 激活所需的类型判定结果与工厂委托。
/// </summary>
/// <remarks>
/// 该缓存把“是否实现契约”“是否为抽象类型”“是否已构建激活委托”封装为不可变快照,
/// 避免对同一 registry 类型重复执行反射分析。
/// </remarks>
private sealed class RegistryActivationMetadata(
bool implementsRegistryContract,
bool isAbstract,
Func<ICqrsHandlerRegistry>? factory)
{
/// <summary>
/// 获取目标类型是否实现了 <see cref="ICqrsHandlerRegistry" />。
/// </summary>
public bool ImplementsRegistryContract { get; } = implementsRegistryContract;

/// <summary>
/// 获取目标类型是否为抽象类型。
/// </summary>
public bool IsAbstract { get; } = isAbstract;

/// <summary>
/// 获取可用于实例化 registry 的工厂委托。
/// </summary>
public Func<ICqrsHandlerRegistry>? Factory { get; } = factory;
}
}
Loading
Loading