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
56 changes: 53 additions & 3 deletions .github/workflows/rendering-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,40 @@ env:
CMAKE_BUILD_PARALLEL_LEVEL: "2"

jobs:
scope:
name: Validation scope
runs-on: ubuntu-latest
outputs:
profile: ${{ steps.select.outputs.profile }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Test and select validation scope
id: select
shell: pwsh
env:
BASE_REVISION: ${{ github.event.pull_request.base.sha || github.event.before }}
HEAD_REVISION: ${{ github.event.pull_request.head.sha || github.sha }}
FORCE_FULL: ${{ github.event_name == 'workflow_dispatch' }}
IS_PULL_REQUEST: ${{ github.event_name == 'pull_request' }}
run: |
./tests/ci/Test-ValidationScope.ps1
if ($env:FORCE_FULL -eq 'true' -or $env:BASE_REVISION -match '^0+$') {
$selection = ./tests/ci/Select-ValidationScope.ps1 -Full
} else {
git fetch --no-tags origin $env:BASE_REVISION $env:HEAD_REVISION
if ($LASTEXITCODE -ne 0) { throw 'The exact validation comparison could not be fetched.' }
$selection = ./tests/ci/Select-ValidationScope.ps1 -BaseRevision $env:BASE_REVISION -HeadRevision $env:HEAD_REVISION `
-PullRequest:($env:IS_PULL_REQUEST -eq 'true')
}
"profile=$($selection.profile)" >> $env:GITHUB_OUTPUT
'## Selected validation scope' >> $env:GITHUB_STEP_SUMMARY
($selection | ConvertTo-Json -Depth 5) >> $env:GITHUB_STEP_SUMMARY

managed:
needs: scope
if: needs.scope.outputs.profile == 'full'
name: Managed / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 90
Expand Down Expand Up @@ -103,6 +136,7 @@ jobs:
if-no-files-found: error

rendering:
needs: scope
if: github.event_name != 'workflow_dispatch' || inputs.native_product_acceptance
name: ${{ matrix.platform }}
runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -170,6 +204,7 @@ jobs:
run: |
dotnet restore entry/InnoEngine.Editor/InnoEngine.Editor.csproj -p:Configuration=Debug --disable-parallel -nr:false
if ($LASTEXITCODE -ne 0) { throw 'The Debug Editor dependency restore failed.' }
if ('${{ needs.scope.outputs.profile }}' -eq 'editor') { exit 0 }
dotnet restore entry/InnoEngine.Editor/InnoEngine.Editor.csproj -p:Configuration=Release --disable-parallel -nr:false
if ($LASTEXITCODE -ne 0) { throw 'The Release Editor dependency restore failed.' }
dotnet restore '${{ matrix.player_project }}' -p:Configuration=Release `
Expand Down Expand Up @@ -217,7 +252,7 @@ jobs:

- name: Build host Editor Release
id: native_release
if: ${{ !cancelled() && steps.native_debug.outcome == 'success' }}
if: ${{ !cancelled() && needs.scope.outputs.profile == 'full' && steps.native_debug.outcome == 'success' }}
shell: pwsh
run: |
dotnet run --project "entry/InnoEngine.Build/InnoEngine.Build.csproj" --no-build -- editor --configuration Release 2>&1 |
Expand Down Expand Up @@ -246,7 +281,12 @@ jobs:
if: ${{ !cancelled() && steps.build_entry.outcome == 'success' }}
shell: pwsh
run: |
dotnet build InnoEngine.sln --configuration SourceDebug --disable-build-servers -m:1 -nr:false `
$source = 'InnoEngine.sln'
if ('${{ needs.scope.outputs.profile }}' -eq 'editor') {
$source = Join-Path $PWD 'artifacts/acceptance/ci-build/contracts.slnf'
./tests/ci/New-ValidationSolutionFilter.ps1 -OutputPath $source
}
dotnet build $source --configuration SourceDebug --disable-build-servers -m:1 -nr:false `
-p:UseSharedCompilation=false '-bl:artifacts/acceptance/ci-build/source-debug.binlog' 2>&1 |
Tee-Object -FilePath 'artifacts/acceptance/ci-build/source-debug.log'
if ($LASTEXITCODE -ne 0) { throw 'SourceDebug build failed.' }
Expand All @@ -267,7 +307,7 @@ jobs:
run: dotnet run --project "entry/InnoEngine.Build/InnoEngine.Build.csproj" --no-build -- verify .

- name: Run complete test suite
if: ${{ !cancelled() && steps.source.outcome == 'success' && steps.player_contract.outcome == 'success' }}
if: ${{ needs.scope.outputs.profile == 'full' && !cancelled() && steps.source.outcome == 'success' && steps.player_contract.outcome == 'success' }}
shell: pwsh
run: |
$properties = Join-Path $PWD '${{ matrix.product_properties }}'
Expand All @@ -288,6 +328,16 @@ jobs:
if ($LASTEXITCODE -ne 0) { throw "Target test closure compilation failed." }
./tests/Invoke-IsolatedTests.ps1 -Configuration SourceDebug -Target '${{ matrix.build_target }}' -ProductProperties $properties

- name: Run affected Editor contract and workflow suites
if: ${{ needs.scope.outputs.profile == 'editor' && !cancelled() && steps.source.outcome == 'success' && steps.player_contract.outcome == 'success' }}
shell: pwsh
run: |
$output = Join-Path $env:RUNNER_TEMP 'InnoEditorChecks'
foreach ($profile in @('Contracts', 'Workflows')) {
./tests/Invoke-EditorUiAcceptance.ps1 -Profile $profile -EditorOnly `
-ArtifactsPath $output -ResultsDirectory 'artifacts/acceptance/ci-tests'
}

- name: Generate source-independent Player Support Pack
if: ${{ !cancelled() && steps.native_release.outcome == 'success' }}
shell: pwsh
Expand Down
6 changes: 6 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,3 +337,9 @@ public void AAA(
- Presentation preparation, drawing and publication form one owned operation. Reentry and retirement during that operation must fail before releasing resources. A callback failure ends only its owned native frame, preserves the original failure and never publishes partial draw data; it must not clear another context's stacks or lower native assertions.
- Native presentation fixtures must create and enter an `EditorUiSession`, explicitly compose their feature/presentation owners, and resolve the exact service under test. Asynchronous shutdown fixtures must retry the public Pending retirement protocol until owned cleanup completes; they cannot rely on continuation timing or remove resource-release assertions.
- Presentation input snapshots expose physical Core modifier semantics. Reverse native shortcut normalization at the presentation boundary using the owned context configuration; do not interpret normalized Control/Super flags as physical keys or add shared-layer OS detection. Native input fixtures explicitly select their conventions and cover both modifier policies and native modes.

- Content-sized modals prepare one coherent frame snapshot and measure it before opening. Explicitly sized resizable windows prepare after current native input establishes their content bounds. Never invoke arbitrary drawing callbacks twice for measurement or rely on the previous message height.
- Shared dialog widgets own text wrapping, progress, bounded body scrolling and action spacing. Domain callers consume those controls and shared metrics; they must not compensate with empty lines, arbitrary padding or a second scroll owner. Escape action behavior is explicit.
- Workflow progress and cancellation are bound to the original owner and operation identity. Late callbacks cannot overwrite a newer request or a cancellation state, and progress presentation cannot weaken publication or generation retirement.

- CI and local acceptance must follow the actual changed owners. Use scoped Editor verification for bounded UI changes; retain full verification for build, platform, backend, SDK, shared runtime or unknown owners. Record omitted checks explicitly and never bypass production validation to shorten CI.
17 changes: 17 additions & 0 deletions docs/architecture/EDITOR_UI_DESIGN_STANDARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,20 @@ Settings 的一次 Apply 复用单一 History transaction,所有 dirty owner
`EditorUiInput` 的 Control/Super 表示物理修饰键,不继承原生控件内部的快捷键归一化。呈现边界依据当前 Context 的键盘配置还原这些值,列表选择复用同一快照语义,平台仍通过 `EditorKeyboardPolicy` 选择 primary modifier。原生文本控件继续使用该 Context 的输入习惯;测试必须显式声明自己的键盘配置,并覆盖 Control/Super 与两种原生模式的组合,不能依赖 runner 的默认值。

最终报告分别评价架构、组织、状态与生命周期、抽象、复用、样式、扩展、交互、Undo/Redo、菜单和颗粒度;每项列出证据与限制。目录整齐、测试数量或正常启动不能代替视觉、输入、重复 reload、资源收敛和成对性能验收。

## 动态 Modal 的状态与尺寸

- 窗口尺寸、换行和绘制使用本帧同一快照,不依赖上一条消息的高度。
- 准备只读取和测量;实际动作由原领域 owner 校验 operation 后执行。禁止双次绘制回调测量。
- 统一 metrics 表达 padding、item spacing、按钮高度和字体尺度。业务 Modal 不通过额外空行、固定大高度或零散数字补偿布局。
- 消息与详情共用一个正文滚动 owner,操作行保持可达。Child 不重复承担父窗口已经提供的外层 padding。
- 明确区分声明尺寸、自适应尺寸及用户调整尺寸;部分指定尺寸也必须得到正确解释。
- 当前帧内容增长、缩短、空文本、动作变化及非整数尺度都属于必要回归。

### 按职责选择 CI 验收

Engine CI 根据完整 Git 变更集合选择检查,不能按 issue 编号或为了节省时间临时跳过失败项。仅涉及 Editor 创作层(包括脚本 reload owner)及对应测试、文档时使用 Editor 范围:Debug Editor、真实原生 smoke、Editor 契约与工作流、架构和 Wiki 检查。Release、NativeAOT 还原、十次热构建、其他领域完整测试及 Player Support Pack 留给完整范围。SDK、工程图、build、platform、backend、共享 Runtime 或未知 owner 的变化保守选择完整范围。手动工作流仍执行完整范围。

脚本 `tests/ci/Select-ValidationScope.ps1` 只编排验收,不改变生产构建或缓存校验。移动文件同时核对旧 owner 和新 owner;选择理由与省略项写入 GitHub job summary。Editor 范围不等于完整产品矩阵通过;完整源码和 Player contract 编译仍服务于当前架构/Wiki 的真实引用验证,不执行 Player 导出或 Support Pack 生产。

UI 范围的生产源码检查由当前 Solution 生成 169 个生产工程的 `.slnf`,引用闭包仍由 MSBuild 求值,不编译全部无关测试工程。只有通过完整 Git 差异证明为标准 SDK 工程中、相同无条件引用边的 `PrivateAssets=compile` 收紧时,才允许保留 Editor 范围;新增引用、包、TFM、SDK、条件或构建目标变化仍走完整范围。PR 使用 merge base,push 使用 before/head,避免把目标分支的无关改动混进 PR 检查。
Loading
Loading