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
4 changes: 3 additions & 1 deletion docs/en/adapter-capability-matrix.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Adapter Capability Matrix

This page locks the adapter-capability contract for `v0.9.0-beta Second Adapter Validation`.
This page is a portability/projection matrix for adapter implementations, layered on top of the canonical API stability contract defined in [Extension and Maintenance Contracts](./extension-contracts.md).

It does not define a second API-stability standard, and it does not grant adapter-specific runtime APIs beyond the canonical seam.

`WPF` is adapter 2. The milestone exists to validate one second official adapter on top of the existing canonical session/runtime route; it does not introduce adapter-specific runtime APIs or a second host-facing runtime model.

Expand Down
21 changes: 21 additions & 0 deletions docs/en/extension-contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

This document publishes the contract around surface stability, compatibility retirement, extension precedence, and lane ownership.

The public SDK contract is canonical-first: shipped stability is defined by `CreateSession`-based runtime/session APIs in `AsterGraph.Editor`; all other surfaces are compatibility or adapter-projection support layered on top.

## Stability Tiers

### Stable canonical surfaces
Expand Down Expand Up @@ -29,6 +31,25 @@ This document publishes the contract around surface stability, compatibility ret

Use the retained surfaces only as migration bridges. New work should start on the stable canonical surfaces above, with [Host Integration](./host-integration.md) as the route map.

## Package-level contract inventory

- `AsterGraph.Abstractions`
- Stable canonical contracts: session/query abstractions and DTO/snapshot-shape contracts for the canonical seam
- Compatibility-only shims: legacy query/migration helpers where a runtime-first route exists
- Hosted composition helper: none
- `AsterGraph.Core`
- Stable canonical contracts: runtime/session support dependencies and implementation behavior needed to run the canonical contract
- Compatibility-only shims: none published as stable public API in this phase
- Hosted composition helper: none
- `AsterGraph.Editor`
- Stable canonical surfaces: `AsterGraphEditorFactory.CreateSession(...)`, `IGraphEditorSession`, and canonical diagnostics/inspection contracts
- Compatibility-only shims: `IGraphEditorQueries.GetCompatibleTargets(...)`, `CompatiblePortTarget` when hosted adapters still need migration bridges
- Hosted composition helper: not a source of hosted UI composition itself; helper is adapter-owned
- `AsterGraph.Avalonia`
- Stable hosted composition helper: `AsterGraphEditorFactory.Create(...)` (hosted UI composition entry point)
- Stable canonical route access: uses canonical `CreateSession(...)`/`IGraphEditorSession` seam for all routed operations
- Compatibility-only shims: avoid adding new host-layer contracts until parity is shipped in that adapter

## Extension Precedence

- plugin trust is host-owned and runs before activation
Expand Down
30 changes: 16 additions & 14 deletions docs/zh-CN/adapter-capability-matrix.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Adapter Capability Matrix

这页文档锁定 `v0.9.0-beta Second Adapter Validation` 的 adapter capability 合同。默认对新接入宿主的 onboarding 仍然是 Avalonia-first:WPF 仅用于同一条 canonical session/runtime 路线的 adapter-2 可移植性验证,不会形成第二条上手路径。
这页文档锁定 `v0.9.0-beta Second Adapter Validation` 的 adapter capability 合同。
它不是第二套 API 稳定定义,而是在 [extension contracts](./extension-contracts.md) 已定义的 canonical 稳定合同之上,给出 Avalonia/WPF 的 portability / projection 能力边界。
默认对新接入宿主的 onboarding 仍然是 Avalonia-first:WPF 仅用于同一条 canonical session/runtime 路线的 adapter-2 可移植性验证,不会形成第二条上手路径。

`WPF` 是 adapter 2。这个里程碑的目标是在现有 canonical session/runtime 路线上验证第二个官方 adapter,而不是新增 adapter 专属 runtime API,也不是再开一条新的宿主运行时路线。

Expand All @@ -19,11 +21,11 @@

| Label | 含义 |
| --- | --- |
| `supported` | 该 adapter 已经能通过文档说明的主支持路线,在 canonical session/query 路线上提供对应 stock surface |
| `partial` | 能力仍然建立在同一条 canonical session/query / host 自有 projection 路线上,但该 adapter 还存在明确范围限制或缺少某个 stock projection |
| `fallback` | 宿主继续停留在同一条 canonical session/query + host 自有投影路线,通过已文档化的 path / sample / proof harness 改走更底层路径,而不是依赖新一套 adapter 专属 runtime API |
| `Supported` | 该 adapter 已经能通过文档说明的主支持路线,在 canonical session/query 路线上提供对应 stock surface |
| `Partial` | 能力仍然建立在同一条 canonical session/query + host 自有 projection 路线上,但该 adapter 还存在明确范围限制或缺少某个 stock projection |
| `Fallback` | 宿主继续停留在同一条 canonical session/query + host 自有 projection 路线上,通过已文档化的 path / sample / proof harness 改走更底层路径,而不是依赖新一套 adapter 专属 runtime API |

retained 迁移不是 `fallback`。retained 仍然只是 legacy host 的 compatibility bridge。
retained 迁移不是 `Fallback`。retained 仍然只是 legacy host 的 compatibility bridge。

## Matrix Categories

Expand All @@ -41,20 +43,20 @@ retained 迁移不是 `fallback`。retained 仍然只是 legacy host 的 compati

## Fallback Rule

`fallback` 不是“退回 retained MVVM”,也不允许引入 `WPF` 专属 runtime API。它的含义是:宿主仍然停留在同一条 canonical session/query + host 自有投影 seam 上,只是临时改走已经被 sample 或 proof harness 证明过的更底层路径。
`Fallback` 不是“退回 retained MVVM”,也不允许引入 `WPF` 专属 runtime API。它的含义是:宿主仍然停留在同一条 canonical session/query + host 自有 projection seam 上,只是临时改走已经被 sample 或 proof harness 证明过的更底层路径。

公开 beta 对外文案 `must not exceed` 下面这些行级状态。只要 WPF 某一行仍是 `partial` 或 `fallback`,release note 和公开文档就必须把这个缺口写明,不能暗示已经对齐。
公开 beta 对外文案 `must not exceed` 下面这些行级状态。只要 WPF 某一行仍是 `Partial` 或 `Fallback`,release note 和公开文档就必须把这个缺口写明,不能暗示已经对齐。

## Phase 157 能力矩阵

| Matrix row | Avalonia | WPF | 证据锚点 | WPF 的 fallback 规则 |
| --- | --- | --- | --- | --- |
| Canonical runtime/session route | `supported` | `supported` | `CreateSession(...)`、`HOST_SAMPLE_OK`、`CONSUMER_SAMPLE_OK`、`DEMO_OK`、`HELLOWORLD_WPF_OK` | 无。canonical seam 不变;自定义 shell 时保持 canonical runtime/session 路线不变。 |
| Hosted full editor shell | `supported` | `partial` | `tools/AsterGraph.Starter.Avalonia`、`tools/AsterGraph.HelloWorld.Avalonia`、`tools/AsterGraph.Starter.Wpf`、`tools/AsterGraph.HelloWorld.Wpf` | 宿主负责组装 shell;当 stock 级别不足时将 `AsterGraph.Wpf.Controls.GraphEditorView`(来自 `AsterGraphWpfViewFactory`)当普通内容控件使用。 |
| Standalone surfaces | `supported` | `partial` | Avalonia 有独立 canvas/inspector/minimap 工厂;WPF 目前仅在 `tools/AsterGraph.Starter.Wpf` 与 `tools/AsterGraph.HelloWorld.Wpf` 里验证 `GraphEditorView` | 通过 `IGraphEditorSession` 快照在 host 层自建 canvas / inspector / minimap 类表面。 |
| Command and tool projection | `supported` | `partial` | `COMMAND_SURFACE_OK`、`CONSUMER_SAMPLE_OK`,以及 `HELLOWORLD_WPF_OK`(WPF proof 会输出 `COMMAND_SURFACE_OK`) | 走 canonical session 的共享 command descriptor(`GetCommandDescriptors`)并由 host action rail 做映射,不引入 WPF 专属 command 运行时。 |
| Authoring presentation | `supported` | `partial` | `DEMO_OK`(完整作者态能力证明)与 WPF shell 的 inspector 摘要显示 | 用 host 的 WPF 表现层按 session/query 快照投影 node/edge/inspector/parameter chrome。 |
| Platform integration | `supported` | `partial` | `HOST_SAMPLE_OK` 的 runtime seam 校验 + `AsterGraph.Wpf` 的基础 platform seam 绑定 | focus/clipboard/pointer/wheel/theme/host-context 由 host 实现并通过兼容 seam 注入,不引入 adapter 级 runtime 语义。 |
| Proof and sample coverage | `supported` | `supported` | `HOST_SAMPLE_OK`、`CONSUMER_SAMPLE_OK`、`DEMO_OK`、`COMMAND_SURFACE_OK`、`HELLOWORLD_WPF_OK` | 无。 |
| Canonical runtime/session route | `Supported` | `Supported` | `CreateSession(...)`、`HOST_SAMPLE_OK`、`CONSUMER_SAMPLE_OK`、`DEMO_OK`、`HELLOWORLD_WPF_OK` | 无。canonical seam 不变;自定义 shell 时保持 canonical runtime/session 路线不变。 |
| Hosted full editor shell | `Supported` | `Partial` | `tools/AsterGraph.Starter.Avalonia`、`tools/AsterGraph.HelloWorld.Avalonia`、`tools/AsterGraph.Starter.Wpf`、`tools/AsterGraph.HelloWorld.Wpf` | 宿主负责组装 shell;当 stock 级别不足时将 `AsterGraph.Wpf.Controls.GraphEditorView`(来自 `AsterGraphWpfViewFactory`)当普通内容控件使用。 |
| Standalone surfaces | `Supported` | `Partial` | Avalonia 有独立 canvas/inspector/minimap 工厂;WPF 目前仅在 `tools/AsterGraph.Starter.Wpf` 与 `tools/AsterGraph.HelloWorld.Wpf` 里验证 `GraphEditorView` | 通过 `IGraphEditorSession` 快照在 host 层自建 canvas / inspector / minimap 类表面。 |
| Command and tool projection | `Supported` | `Partial` | `COMMAND_SURFACE_OK`、`CONSUMER_SAMPLE_OK`,以及 `HELLOWORLD_WPF_OK`(WPF proof 会输出 `COMMAND_SURFACE_OK`) | 走 canonical session 的共享 command descriptor(`GetCommandDescriptors`)并由 host action rail 做映射,不引入 WPF 专属 command 运行时。 |
| Authoring presentation | `Supported` | `Partial` | `DEMO_OK`(完整作者态能力证明)与 WPF shell 的 inspector 摘要显示 | 用 host 的 WPF 表现层按 session/query 快照投影 node/edge/inspector/parameter chrome。 |
| Platform integration | `Supported` | `Partial` | `HOST_SAMPLE_OK` 的 runtime seam 校验 + `AsterGraph.Wpf` 的基础 platform seam 绑定 | focus/clipboard/pointer/wheel/theme/host-context 由 host 实现并通过兼容 seam 注入,不引入 adapter 级 runtime 语义。 |
| Proof and sample coverage | `Supported` | `Supported` | `HOST_SAMPLE_OK`、`CONSUMER_SAMPLE_OK`、`DEMO_OK`、`COMMAND_SURFACE_OK`、`HELLOWORLD_WPF_OK` | 无。 |

路线与能力地图看 [Host Integration](./host-integration.md),adapter 边界看 [Architecture](./architecture.md),当前 Avalonia-first 的上手路径看 [Quick Start](./quick-start.md)。
17 changes: 14 additions & 3 deletions docs/zh-CN/extension-contracts.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# 扩展与维护契约

这份文档发布 surface stability、compatibility retirement、extension precedence 与 lane ownership 的契约。
它不引入新的 API 稳定语义,只定义当前发布边界里 canonical-runtime 与已承诺 hosted 形态的优先级。

## 稳定性层级

Expand All @@ -27,16 +28,26 @@
- `CompatiblePortTarget`
- 其他已经存在 runtime-first 替代物的旧 MVVM 形状 helper

retained surface 只应当作为迁移桥接使用。新工作应该从上面的 stable canonical surfaces 起步,并配合 [Host Integration](./host-integration.md) 做路线选择。
`retained` 与 `compatibility-only` 属于迁移路径,不是可长期扩展的“新功能落点”。
新工作应优先从 `Stable canonical surfaces` 起步,必要时经 `AsterGraphAvaloniaViewFactory` 经由 `AsterGraphEditorFactory.Create(...)` 组合 hosted UI,并与 [Host Integration](./host-integration.md) 对齐。

## 包级稳定性边界(`AsterGraph` 发布边界)

- `AsterGraph.Abstractions`:稳定发布 node / provider / 插件契约,适合作为 contract-first 集成入口。
- `AsterGraph.Core`:当前用于 `GraphDocument`、序列化、兼容层与迁移辅助,不替代 `Editor.Session` 的 canonical 运行时语义。
- `AsterGraph.Editor`:canonical runtime/session owner,承载运行时主语义与稳定交互面;新增能力优先从这里落地。
- `AsterGraph.Avalonia`:当前唯一 shipped 的官方 adapter,提供 `Create(...)` 与默认 shell/standalone composition 组合面,不构成第二套运行时 API。

canonical-first 指导是:先从 `AsterGraph.Editor` 的 canonical surface 做新功能,再决定是否叠加 `AsterGraph.Avalonia`;`retained` 只用于迁移,不是默认起点。

## 扩展优先级

- plugin trust 由 host 决定,并且发生在 activation 之前
- plugin localization 先组合,host localization 最后覆盖
- plugin node presentation 先组合,host presentation 覆盖最终字段,合并型 adornment 继续累积
- plugin command 通过 canonical session command descriptor pipeline 注册;如果和 stock command 撞 id,stock command 继续保留执行权
- runtime/session menu 当前仍以 stock descriptor 投影为主,并继续向共享 command source 收敛
- retained `GraphEditorViewModel.BuildContextMenu(...)` 仍是 compatibility host 的最终 override 点
- runtime/session menu 当前仍以 stock descriptor 投影为主,并继续向共享 command source 收敛
- retained `GraphEditorViewModel.BuildContextMenu(...)` 仍是 compatibility host 的最终 override 点

## Lane Ownership

Expand Down
50 changes: 46 additions & 4 deletions tests/AsterGraph.Demo.Tests/DemoProofReleaseSurfaceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ public void SecondAdapterDocs_LockWpfAdapterMatrixContractAcrossLanguages()
var quickStartZh = ReadRepoFile("docs/zh-CN/quick-start.md");
var adapterMatrix = ReadRepoFile("docs/en/adapter-capability-matrix.md");
var adapterMatrixZh = ReadRepoFile("docs/zh-CN/adapter-capability-matrix.md");
var extensionContracts = ReadRepoFile("docs/en/extension-contracts.md");
var extensionContractsZh = ReadRepoFile("docs/zh-CN/extension-contracts.md");

foreach (var contents in new[]
{
Expand All @@ -298,6 +300,29 @@ public void SecondAdapterDocs_LockWpfAdapterMatrixContractAcrossLanguages()
Assert.Contains("WPF", contents, StringComparison.Ordinal);
}

foreach (var contents in new[] { extensionContracts, extensionContractsZh })
{
Assert.Contains("### Stable canonical surfaces", contents, StringComparison.Ordinal);
Assert.Contains("### Supported hosted-UI composition helper", contents, StringComparison.Ordinal);
Assert.Contains("### Retained migration surfaces", contents, StringComparison.Ordinal);
Assert.Contains("### Compatibility-only shims", contents, StringComparison.Ordinal);
Assert.Contains("AsterGraphEditorFactory.CreateSession(...)", contents, StringComparison.Ordinal);
Assert.Contains("IGraphEditorSession", contents, StringComparison.Ordinal);
Assert.Contains("AsterGraphEditorFactory.Create(...)", contents, StringComparison.Ordinal);
Assert.Contains("GraphEditorViewModel", contents, StringComparison.Ordinal);
Assert.Contains("GraphEditorView", contents, StringComparison.Ordinal);
Assert.Contains("GraphEditorViewModel.Session", contents, StringComparison.Ordinal);
Assert.Contains("GetCompatiblePortTargets(...)", contents, StringComparison.Ordinal);
Assert.Contains("IGraphEditorQueries.GetCompatibleTargets(...)", contents, StringComparison.Ordinal);
Assert.Contains("CompatiblePortTarget", contents, StringComparison.Ordinal);
Assert.Contains("stable canonical surfaces", contents, StringComparison.OrdinalIgnoreCase);
}

Assert.Contains("Use the retained surfaces only as migration bridges.", extensionContracts, StringComparison.Ordinal);
Assert.Contains("canonical-first 指导是", extensionContractsZh, StringComparison.Ordinal);
Assert.Contains("new work should start on the stable canonical surfaces", extensionContracts, StringComparison.OrdinalIgnoreCase);
Assert.Contains("新工作应优先从 `Stable canonical surfaces` 起步", extensionContractsZh, StringComparison.Ordinal);

foreach (var contents in new[] { readme, readmeZh, hostIntegration, hostIntegrationZh, architecture, architectureZh, projectStatus, projectStatusZh, alphaStatus, alphaStatusZh, quickStart, quickStartZh })
{
Assert.Contains("adapter-capability-matrix.md", contents, StringComparison.OrdinalIgnoreCase);
Expand All @@ -312,19 +337,36 @@ public void SecondAdapterDocs_LockWpfAdapterMatrixContractAcrossLanguages()
Assert.Contains("IGraphEditorSession", adapterMatrix, StringComparison.Ordinal);
Assert.Contains("AsterGraph.Editor", adapterMatrix, StringComparison.Ordinal);
Assert.Contains("adapter-specific runtime APIs", adapterMatrix, StringComparison.OrdinalIgnoreCase);
Assert.Contains("on top of the existing canonical session/runtime route", adapterMatrix, StringComparison.OrdinalIgnoreCase);
Assert.Contains("layered on the same runtime owner", adapterMatrix, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Matrix Vocabulary", adapterMatrix, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Matrix Categories", adapterMatrix, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Retained migration is not", adapterMatrix, StringComparison.Ordinal);
Assert.Contains("HELLOWORLD_WPF_OK", adapterMatrix, StringComparison.Ordinal);
Assert.Contains("COMMAND_SURFACE_OK", adapterMatrix, StringComparison.Ordinal);
Assert.Contains("HOST_SAMPLE_OK", adapterMatrix, StringComparison.Ordinal);
Assert.Contains("DEMO_OK", adapterMatrix, StringComparison.Ordinal);
Assert.Contains("Fallback Rule", adapterMatrix, StringComparison.Ordinal);
Assert.Contains("lower-level documented path", adapterMatrix, StringComparison.OrdinalIgnoreCase);
Assert.True(LineHasAdapterStatus(adapterMatrix, "Avalonia", "supported"));
Assert.True(LineHasAdapterStatus(adapterMatrix, "WPF", "partial"));
Assert.True(LineHasAdapterStatus(adapterMatrix, "WPF", "fallback"));

Assert.Contains("adapter 2", adapterMatrixZh, StringComparison.OrdinalIgnoreCase);
Assert.Contains("supported", adapterMatrixZh, StringComparison.Ordinal);
Assert.Contains("partial", adapterMatrixZh, StringComparison.Ordinal);
Assert.Contains("fallback", adapterMatrixZh, StringComparison.Ordinal);
Assert.Contains("must not exceed", adapterMatrix, StringComparison.OrdinalIgnoreCase);
Assert.Contains("supported", adapterMatrixZh, StringComparison.OrdinalIgnoreCase);
Assert.Contains("partial", adapterMatrixZh, StringComparison.OrdinalIgnoreCase);
Assert.Contains("fallback", adapterMatrixZh, StringComparison.OrdinalIgnoreCase);
Assert.Contains("must not exceed", adapterMatrixZh, StringComparison.OrdinalIgnoreCase);
Assert.Contains("must not exceed", adapterMatrixZh, StringComparison.OrdinalIgnoreCase);
Assert.Contains("同一条 canonical session/runtime 路线", adapterMatrixZh, StringComparison.Ordinal);
Assert.Contains("新增 adapter 专属 runtime API", adapterMatrixZh, StringComparison.Ordinal);
Assert.Contains("公开文档描述 Avalonia/WPF 支持情况时,只使用下面这三种标签", adapterMatrixZh, StringComparison.Ordinal);
Assert.Contains("Matrix Vocabulary", adapterMatrixZh, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Matrix Categories", adapterMatrixZh, StringComparison.OrdinalIgnoreCase);
Assert.Contains("HELLOWORLD_WPF_OK", adapterMatrixZh, StringComparison.Ordinal);
Assert.Contains("COMMAND_SURFACE_OK", adapterMatrixZh, StringComparison.Ordinal);
Assert.Contains("HOST_SAMPLE_OK", adapterMatrixZh, StringComparison.Ordinal);
Assert.Contains("DEMO_OK", adapterMatrixZh, StringComparison.Ordinal);
Assert.DoesNotContain("Phase 154", adapterMatrixZh, StringComparison.OrdinalIgnoreCase);
Assert.Contains("CreateSession(...)", adapterMatrixZh, StringComparison.Ordinal);
Assert.Contains("IGraphEditorSession", adapterMatrixZh, StringComparison.Ordinal);
Expand Down
Loading