Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ dotnet test DesignPatterns.slnx -c Release
| DP083 | GenerateBuilder 重复步骤(生成器;同名 `[BuilderStep]` 重复) |

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

DP086 is updated for the Phase 2 assemble contract, but the DP080 row a few lines above still omits the async CancellationToken exemption that ADR-011 and docs/design/StepBuilder.md now document. Please align the DP080 registry wording (token skipped for step-name binding on async assemble) so AGENTS stays the single diagnostic registry.

| DP084 | GenerateBuilder 未知步骤引用(生成器;After/Before 指向不存在的步骤) |
| DP085 | GenerateBuilder holder 非法(生成器;`[GenerateBuilder]` 目标类型不合法) |
| DP086 | GenerateBuilder 装配契约不匹配(生成器;assemble 签名/重复标注非法) |
| DP086 | GenerateBuilder 装配契约不匹配(生成器;恰好一个 assemble,返回同步 `T` 或 `Task<T>`/`ValueTask<T>`;拒绝 void、裸 `Task`/`ValueTask`、多个 `CancellationToken`、重复标注) |
| DP087 | Work Graph 依赖环(生成器;DependsOn 形成 cycle) |
| DP088 | Work Graph 未知 DependsOn(生成器;引用未声明的 step id) |
| DP089 | Work Graph 重复 step id(生成器;同一 holder 下 Id 重复) |
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **Step Builder ADR-011 + Design Doc**: records async-assemble exclusivity (`Task<T>` / `ValueTask<T>` emits `BuildAsync` only; product type is the inner `T`; cancellation-token rules; DP086 covers the illegal contracts) without superseding ADR-010; Design Doc, ROADMAP, and the DP086 registry line now match the Phase 2 exit ([#327](https://github.com/Skymly/DesignPatterns/issues/327), Spec [#324](https://github.com/Skymly/DesignPatterns/issues/324)).
- **Work Graph Design Doc**: `docs/design/WorkGraph.md` documents dual-path API (`WorkGraphBuilder` / `[WorkGraph]`+`[WorkStep]` / Keys+`Create`), DP087–DP092, wave fail-fast execution, and non-goals vs Channel Pipeline / Composite parallel / Step Builder / TPL Dataflow; design index, ROADMAP F3 Top-3, and AGENTS pattern summary updated ([#312](https://github.com/Skymly/DesignPatterns/issues/312), Spec [#308](https://github.com/Skymly/DesignPatterns/issues/308)).
- **Work Graph generator**: `[WorkGraph]` / `[WorkGraph<TContext>]` + `[WorkStep]` drive `WorkGraphGenerator`, emitting `{Holder}WorkStepKeys` and `{Holder}WorkGraph.Create(resolver|dictionary)` that fills `WorkGraphBuilder`. Reports **DP087–DP092** (cycle, unknown DependsOn, duplicate id, self-dependency, unreachable Warning, contract mismatch); no MVP DI/Autofac emission ([#311](https://github.com/Skymly/DesignPatterns/issues/311), Spec [#308](https://github.com/Skymly/DesignPatterns/issues/308)).
- **Work Graph diagnostic IDs**: **DP087–DP092** for the Work Graph generator (dependency cycle, unknown DependsOn, duplicate step id, self-dependency, unreachable step Warning, contract/TContext mismatch); no unregistered-`IWorkStep` Analyzer in MVP; DP067–DP071 remain ADR-008-only ([#310](https://github.com/Skymly/DesignPatterns/issues/310), Spec [#308](https://github.com/Skymly/DesignPatterns/issues/308)).
Expand Down
3 changes: 2 additions & 1 deletion docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
| 名次 | 候选 | 说明 | 状态 |
|------|------|------|------|
| 1 | **Command Router** | MVP + 域内增强已落地:1:1 `SendAsync`/`TrySendAsync`/`SendStreamAsync`/`TrySendStreamAsync` + `[RegisterCommandHandler]`(含 `IStreamCommandHandler`)+ DP072–077 + pipeline(ADR-009)+ `AddCommandRouter` / Autofac `RegisterCommandRouter` + [Design Doc](design/CommandRouter.md)(#257–#265、#275–#277、#282–#283)。Samples #266;探索与 MediatR 的差异点见 Design Doc | [~] |
| 2 | **Builder**(Step Builder) | **MVP 完成**:`[GenerateBuilder]` / `[BuilderStep]` / `[BuilderAssemble]` + 泛型 type-state `{Holder}Builder`([ADR-010](adr/ADR-010-step-builder-type-state-markers.md))+ DP078–DP086 + [Design Doc](design/StepBuilder.md)(#288–#291)+ Samples [DesignPatterns.Samples#23](https://github.com/Skymly/DesignPatterns.Samples/issues/23) / [PR#24](https://github.com/Skymly/DesignPatterns.Samples/pull/24)。Spec [#287](https://github.com/Skymly/DesignPatterns/issues/287)。Phase 2+:async / DI / step validation | [x] |
| 2 | **Builder**(Step Builder) | **MVP 完成**:`[GenerateBuilder]` / `[BuilderStep]` / `[BuilderAssemble]` + 泛型 type-state `{Holder}Builder`([ADR-010](adr/ADR-010-step-builder-type-state-markers.md))+ DP078–DP086 + [Design Doc](design/StepBuilder.md)(#288–#291)+ Samples [DesignPatterns.Samples#23](https://github.com/Skymly/DesignPatterns.Samples/issues/23) / [PR#24](https://github.com/Skymly/DesignPatterns.Samples/pull/24)。Spec [#287](https://github.com/Skymly/DesignPatterns/issues/287)。Phase 2 async 已落地:`Task<T>` / `ValueTask<T>` assemble 只生成 `BuildAsync`([ADR-011](adr/ADR-011-step-builder-async-assemble.md);#325–#327,Spec [#324](https://github.com/Skymly/DesignPatterns/issues/324))。剩余 Phase 2+:DI / step validation。Async sample 仍待 [DesignPatterns.Samples#29](https://github.com/Skymly/DesignPatterns.Samples/issues/29) | [x] |
| 3 | **Fork–Join Work Graph** | **MVP 完成**:`IWorkStep` / `IWorkGraph` / `WorkGraphBuilder` + `[WorkGraph]` / `[WorkStep]` + `WorkGraphGenerator`(`{Holder}WorkStepKeys` + `Create`)+ DP087–DP092 + [Design Doc](design/WorkGraph.md)(#309–#312)+ Samples [DesignPatterns.Samples#25](https://github.com/Skymly/DesignPatterns.Samples/issues/25) / [PR#28](https://github.com/Skymly/DesignPatterns.Samples/pull/28)。Spec [#308](https://github.com/Skymly/DesignPatterns/issues/308)。Phase 2+:Dop / 追踪 / DI / 未注册 Analyzer | [x] |

#### 观望(已过硬门槛,未进 Top-3)
Expand Down Expand Up @@ -245,4 +245,5 @@ State 转换表 v1 已于 0.1.0-preview4 发布;v2(guard 委托、DI 集成
- F5+ Composite 树 schema 校验:`[CompositeSchema(MaxDepth, MaxNodes)]` 契约级约束 + `[CompositePart(AllowedChildTypes)]` 节点级约束 + DP063(max depth exceeded Warning)/ DP064(child type not allowed Error)/ DP065(node count exceeded Warning)。见 [ADR-007](adr/ADR-007-composite-tree-schema-validation.md)。
- 文档体系精简:移除 RFC / Spec / Plan / Review 仓内类型;Spec 合入 Design Doc;任务与审查改用 GitHub Issue / PR。见 [DOCUMENTATION.md](DOCUMENTATION.md)。
- F3 Step Builder MVP:`[GenerateBuilder]` / `[BuilderStep]` / `[BuilderAssemble]` + type-state `{Holder}Builder`(ADR-010)+ DP078–DP086 + Design Doc(#288–#291)+ Samples [DesignPatterns.Samples#23](https://github.com/Skymly/DesignPatterns.Samples/issues/23);Spec [#287](https://github.com/Skymly/DesignPatterns/issues/287)。
- F3 Step Builder Phase 2 async assemble:`Task<T>` / `ValueTask<T>` 只生成 type-state 门闩的 `BuildAsync`([ADR-011](adr/ADR-011-step-builder-async-assemble.md),不取代 ADR-010)+ DP086 文案(#325)+ 生成器(#326)+ Design Doc(#327)。Spec [#324](https://github.com/Skymly/DesignPatterns/issues/324)。Async sample 仍待 [DesignPatterns.Samples#29](https://github.com/Skymly/DesignPatterns.Samples/issues/29)。
- F3 Fork–Join Work Graph MVP:Runtime builder + 波次 fail-fast(#309)+ DP087–DP092(#310)+ Keys/`Create` 生成器(#311)+ Design Doc(#312)+ Samples [DesignPatterns.Samples#25](https://github.com/Skymly/DesignPatterns.Samples/issues/25) / [PR#28](https://github.com/Skymly/DesignPatterns.Samples/pull/28);Spec [#308](https://github.com/Skymly/DesignPatterns/issues/308)。
46 changes: 46 additions & 0 deletions docs/adr/ADR-011-step-builder-async-assemble.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# ADR-011: Step Builder async assemble exits through BuildAsync

| 字段 | 值 |
|------|-----|
| **状态** | Accepted |
| **日期** | 2026-09-26 |
| **关联 Issue** | [#324](https://github.com/Skymly/DesignPatterns/issues/324)(Spec)、[#325](https://github.com/Skymly/DesignPatterns/issues/325)–[#327](https://github.com/Skymly/DesignPatterns/issues/327) |

## 背景

[ADR-010](ADR-010-step-builder-type-state-markers.md) 把必填完备性锁在泛型 type-state 上,并把 async `Build` / assemble 列为 MVP 非目标。产品物化若需要 I/O,作者只能把 `[BuilderAssemble]` 保持同步,或绕过生成的 `{Holder}Builder`,从而失去同一套必填门闩。

需要在不改 type-state 证明模型、不新增运行时类型、不新开诊断 ID 的前提下,给装配出口一条 async 路径。

## 决策

Step Builder 的 **async 只发生在 assemble 出口**。ADR-010 仍是 type-state 与必填上限的决策,**不**被本 ADR 取代。本 ADR 解除 ADR-010 第 6 点里的 async `Build` / assemble 非目标,并只在 async 出口上收窄「产品类型 = assemble 返回类型」的表述。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

This paragraph both keeps ADR-010 as the type-state decision and “lifts” its §6 async non-goal / narrows §5 product-type wording. Under docs/DOCUMENTATION.md §2, Accepted ADR bodies are immutable and later changes are supposed to go through Superseded by. As written, ADR-010 §1/§5/§6 still contradict this page for anyone who does not also open ADR-011.

Please either (a) mark ADR-010’s status as partially superseded for those bullets, or (b) state here explicitly which ADR-010 bullets this ADR supersedes while type-state / the required-step cap remain. Silent coexistence of two Accepted ADRs with opposite async guidance is the main consistency risk.

1. **互斥出口**:每个 holder 仍恰好一个 `[BuilderAssemble]`。返回同步产品 `T` 时只生成 `Build()`;返回 BCL `Task<T>` 或 `ValueTask<T>` 时只生成 `BuildAsync`,**不**再生成 `Build()`。不允许同一 holder 同时暴露两个出口。其它返回类型(含自定义 awaitable)不是 async 出口,按同步产品类型生成 `Build()`;裸 `Task` / `ValueTask` 见第 5 点。
2. **返回类型跟随装配**:`BuildAsync` 的返回类型与 assemble 相同(`Task<T>` 或 `ValueTask<T>`)。不把 `ValueTask<T>` 包成 `Task<T>`,也不把任务拆成同步 `T`。
3. **产品类型**:async 时产品类型是内层 `T`,任务只是传输。同步时产品类型仍是 assemble 返回的 `T`(ADR-010)。生成器不发明映射,直接 `return` assemble 的任务或值任务,不额外制造 async 状态机。
4. **取消**:`BuildAsync` 始终带 `CancellationToken cancellationToken = default`。assemble 可以不接收 token,或接收至多一个 `CancellationToken`;若存在,生成器按该参数在 assemble 签名中的位置原样传入(按类型识别,不要求参数名为 `cancellationToken`)。该参数**不**参与步骤名绑定。同步 `Build()` 不接受 `CancellationToken`;同步 assemble 上的 `CancellationToken` 仍按普通参数做步名绑定(绑不到则 **DP080**)。
5. **非法契约仍用 DP086**(不新开诊断 ID):裸 `Task` / `ValueTask`、void、重复 `[BuilderAssemble]`、多于一个 `CancellationToken`(同步或 async),以及既有的不可访问实例装配。DP078–DP085 语义不变。
6. **type-state 不变**:必填步仍是 `NotSet` → `Set`;`BuildAsync` 与 `Build()` 一样,只在全部必填类型参数为 `Set` 时作为扩展方法存在。可选步、互斥组、`After` / `Before` 不因 async 放宽。必填上限仍为 8。
7. **仍非目标**:async `[BuilderStep]` / 可等待 fluent 链;async assemble 上的 sync-over-async `Build()`;MSDI / Autofac / `FromServices`;步骤参数校验诊断;互斥的 type-state 擦除;新 Analyzer / CodeFix;新运行时属性或类型。

## 后果

**正面**:

- I/O 装配可以留在生成 builder 的 type-state 门闩之后,不必绕过 `{Holder}Builder`
- 同步 schema 仍只有 `Build()`,既有调用点不变
- 不新增诊断 ID、不新增 Core 类型;DP086 文案覆盖合法与非法契约

**负面**:

- 同一 holder 不能同时提供同步与异步出口;需要两种出口时必须拆 holder
- 自定义 awaitable 不会变成 `BuildAsync`(有意:出口形状保持可判定)
- assemble 忽略取消时,`BuildAsync` 仍接受 token 但不转发;调用方不能从 `BuildAsync` 签名看出 token 是否被观察

## 参考

- [ADR-010](ADR-010-step-builder-type-state-markers.md) — type-state 与必填上限;本 ADR 不取代它
- [docs/design/StepBuilder.md](../design/StepBuilder.md)
- Spec [#324](https://github.com/Skymly/DesignPatterns/issues/324)
- 落地切片:#325(Diagnostics,DP086 文案)→ #326(SourceGenerators)→ #327(Docs)
3 changes: 2 additions & 1 deletion docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
| [ADR-008](ADR-008-singleton-lifecycle-diagnostics.md) | Singleton lifecycle diagnostics | Accepted | 2026-07-08 | — |
| [ADR-009](ADR-009-command-router-pipeline-onion.md) | Command Router pipeline uses Chain-like next onion | Accepted | 2026-07-28 | #264 / #275–#277 |
| [ADR-010](ADR-010-step-builder-type-state-markers.md) | Step Builder required completeness via generic type-state markers | Accepted | 2026-08-03 | #287 / #288–#291 |
| [ADR-011](ADR-011-step-builder-async-assemble.md) | Step Builder async assemble exits through BuildAsync | Accepted | 2026-09-26 | #324 / #325–#327 |

## 下一个可用编号

**ADR-011**
**ADR-012**
2 changes: 1 addition & 1 deletion docs/design/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@
| Event Aggregator | [EventAggregator.md](EventAggregator.md) | — |
| Command Router | [CommandRouter.md](CommandRouter.md) | — |
| State Transition Table | [StateTransitionTable.md](StateTransitionTable.md) | [ADR-005](../adr/ADR-005-state-transition-table.md) |
| Step Builder | [StepBuilder.md](StepBuilder.md) | [ADR-010](../adr/ADR-010-step-builder-type-state-markers.md) |
| Step Builder | [StepBuilder.md](StepBuilder.md) | [ADR-010](../adr/ADR-010-step-builder-type-state-markers.md)、[ADR-011](../adr/ADR-011-step-builder-async-assemble.md) |
| Fork–Join Work Graph | [WorkGraph.md](WorkGraph.md) | —(对照 [ADR-006](../adr/ADR-006-composite-parallel-traversal.md)) |
Loading
Loading