feat(stage0): close native smoke acceptance gate
This commit is contained in:
+35
-14
@@ -48,7 +48,7 @@ jobs:
|
||||
--locked
|
||||
|
||||
stage0-matrix:
|
||||
name: Stage 0-2 CI (${{ matrix.os }})
|
||||
name: Stage 0 CI (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
@@ -73,22 +73,43 @@ jobs:
|
||||
run: cargo install cargo-deny --version 0.19.9 --locked
|
||||
- name: Run canonical CI gate
|
||||
run: cargo xtask ci
|
||||
- name: Record native Vulkan smoke status
|
||||
if: always()
|
||||
shell: bash
|
||||
- name: Run native Vulkan smoke
|
||||
run: >
|
||||
cargo run -p fparkan-vulkan-smoke --locked --
|
||||
--platform "${{ matrix.smoke_platform }}"
|
||||
--out "target/fparkan/native-smoke/${{ runner.os }}.json"
|
||||
--status blocked
|
||||
--probe-surface
|
||||
--reason "native Vulkan smoke runner is not enabled on this CI lane yet"
|
||||
- name: Upload acceptance evidence
|
||||
--out "target/fparkan/native-smoke/${{ matrix.smoke_platform }}.json"
|
||||
- name: Upload acceptance audit
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: stage-0-2-acceptance-${{ matrix.os }}
|
||||
path: |
|
||||
target/fparkan/acceptance/stage-0-2-audit.json
|
||||
target/fparkan/native-smoke/*.json
|
||||
name: stage-0-acceptance-${{ matrix.os }}
|
||||
path: target/fparkan/acceptance/stage-0-audit.json
|
||||
if-no-files-found: error
|
||||
- name: Upload native smoke report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: native-smoke-${{ matrix.smoke_platform }}
|
||||
path: target/fparkan/native-smoke/*.json
|
||||
if-no-files-found: error
|
||||
|
||||
native-smoke-audit:
|
||||
name: Native smoke audit
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
needs: stage0-matrix
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
- uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537
|
||||
with:
|
||||
toolchain: 1.87.0
|
||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||
with:
|
||||
pattern: native-smoke-*
|
||||
path: target/fparkan/native-smoke-artifacts
|
||||
merge-multiple: true
|
||||
- name: Aggregate native smoke reports
|
||||
run: >
|
||||
cargo xtask native-smoke audit
|
||||
--dir target/fparkan/native-smoke-artifacts
|
||||
|
||||
Generated
+1
@@ -717,6 +717,7 @@ dependencies = [
|
||||
"fparkan-platform",
|
||||
"fparkan-platform-winit",
|
||||
"fparkan-render-vulkan",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -63,6 +63,40 @@ FPARKAN_CORPORA_MANIFEST=/private/tmp/fparkan-corpora.toml \
|
||||
cargo xtask acceptance report --suite licensed --stage 5
|
||||
```
|
||||
|
||||
## Stage 0 Vulkan smoke
|
||||
|
||||
Локальный Stage 0 smoke запускает реальный `winit` lifecycle и Vulkan triangle path с включёнными validation layers. Успешный прогон обязан:
|
||||
|
||||
- отрисовать 300 кадров;
|
||||
- выполнить как минимум один реальный resize;
|
||||
- пересоздать swapchain после resize;
|
||||
- завершиться без validation warnings/errors.
|
||||
|
||||
Команда запуска:
|
||||
|
||||
```bash
|
||||
cargo run -p fparkan-vulkan-smoke --locked -- \
|
||||
--out target/fparkan/native-smoke/local.json
|
||||
```
|
||||
|
||||
Перед запуском убедитесь, что на машине доступен Vulkan loader и рабочий ICD:
|
||||
|
||||
- macOS: установлены Vulkan SDK и MoltenVK; если используется нестандартная установка, проверьте `VK_ICD_FILENAMES`, `VK_LAYER_PATH` и наличие `VK_LAYER_KHRONOS_validation`.
|
||||
- Linux: установлен `libvulkan` и драйвер/ICD (`mesa-vulkan-drivers`, Lavapipe или vendor GPU stack); smoke нужно запускать из активной графической сессии X11/Wayland.
|
||||
- Windows: установлен Vulkan runtime от GPU vendor или LunarG Vulkan SDK; validation layer должен быть доступен из активного runtime.
|
||||
|
||||
Для полного локального closure gate используйте:
|
||||
|
||||
```bash
|
||||
cargo xtask ci
|
||||
```
|
||||
|
||||
GitHub workflow дополнительно собирает три platform reports и проверяет их aggregate gate:
|
||||
|
||||
```bash
|
||||
cargo xtask native-smoke audit --dir target/fparkan/native-smoke-artifacts
|
||||
```
|
||||
|
||||
## Contributing & Support
|
||||
|
||||
Проект активно поддерживается и открыт для contribution. Issues и pull requests можно создавать в обоих репозиториях:
|
||||
|
||||
@@ -27,15 +27,14 @@ use fparkan_platform::{
|
||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::dpi::PhysicalSize as WinitPhysicalSize;
|
||||
use std::sync::OnceLock;
|
||||
use std::time::Instant;
|
||||
use winit::event::{Event, MouseButton, WindowEvent};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use winit::platform::scancode::PhysicalKeyExtScancode;
|
||||
use winit::window::{Window, WindowId};
|
||||
use winit::window::Window;
|
||||
|
||||
static NEXT_WINDOW_HANDLE_ID: AtomicU64 = AtomicU64::new(1);
|
||||
static CLOCK_START: OnceLock<Instant> = OnceLock::new();
|
||||
const DEFAULT_SMOKE_WIDTH: u32 = 1280;
|
||||
const DEFAULT_SMOKE_HEIGHT: u32 = 720;
|
||||
|
||||
@@ -49,10 +48,8 @@ pub struct WinitClock;
|
||||
|
||||
impl MonotonicClock for WinitClock {
|
||||
fn now(&self) -> MonotonicInstant {
|
||||
let duration = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap_or_default();
|
||||
MonotonicInstant(duration.as_millis().try_into().unwrap_or(u64::MAX))
|
||||
let elapsed = CLOCK_START.get_or_init(Instant::now).elapsed();
|
||||
MonotonicInstant(elapsed.as_millis().try_into().unwrap_or(u64::MAX))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,113 +184,6 @@ impl WinitWindowPlan {
|
||||
}
|
||||
}
|
||||
|
||||
/// Native smoke window creation result.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct WinitSmokeWindowProbe {
|
||||
/// Validated creation plan.
|
||||
pub plan: WinitWindowPlan,
|
||||
/// Captured window descriptor.
|
||||
pub window: WinitWindow,
|
||||
}
|
||||
|
||||
impl WinitSmokeWindowProbe {
|
||||
/// Returns raw native handles captured from the native window.
|
||||
#[must_use]
|
||||
pub fn native_handles(&self) -> Option<NativeWindowHandles> {
|
||||
self.window.native_handles()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a native smoke window, captures raw handles, then exits the event loop.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`PlatformError`] when the plan is invalid, the event loop/window
|
||||
/// cannot be created, or raw native handles are unavailable.
|
||||
pub fn probe_smoke_window() -> Result<WinitSmokeWindowProbe, PlatformError> {
|
||||
let plan = WinitWindowPlan::smoke().validate()?;
|
||||
let event_loop = EventLoop::new().map_err(|err| PlatformError::Backend {
|
||||
context: "winit event loop",
|
||||
message: err.to_string(),
|
||||
})?;
|
||||
let mut app = SmokeWindowApp::new(plan);
|
||||
event_loop
|
||||
.run_app(&mut app)
|
||||
.map_err(|err| PlatformError::Backend {
|
||||
context: "winit event loop",
|
||||
message: err.to_string(),
|
||||
})?;
|
||||
app.into_probe()
|
||||
}
|
||||
|
||||
struct SmokeWindowApp {
|
||||
plan: WinitWindowPlan,
|
||||
window: Option<WinitWindow>,
|
||||
error: Option<String>,
|
||||
}
|
||||
|
||||
impl SmokeWindowApp {
|
||||
const fn new(plan: WinitWindowPlan) -> Self {
|
||||
Self {
|
||||
plan,
|
||||
window: None,
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_probe(self) -> Result<WinitSmokeWindowProbe, PlatformError> {
|
||||
if let Some(message) = self.error {
|
||||
return Err(PlatformError::Backend {
|
||||
context: "winit smoke window",
|
||||
message,
|
||||
});
|
||||
}
|
||||
let window = self.window.ok_or_else(|| PlatformError::Backend {
|
||||
context: "winit smoke window",
|
||||
message: "event loop exited before creating a window".to_string(),
|
||||
})?;
|
||||
if self.plan.requires_native_handles && window.native_handles().is_none() {
|
||||
return Err(PlatformError::Backend {
|
||||
context: "winit smoke window",
|
||||
message: "native window/display handles are unavailable".to_string(),
|
||||
});
|
||||
}
|
||||
Ok(WinitSmokeWindowProbe {
|
||||
plan: self.plan,
|
||||
window,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ApplicationHandler for SmokeWindowApp {
|
||||
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||
if self.window.is_some() || self.error.is_some() {
|
||||
event_loop.exit();
|
||||
return;
|
||||
}
|
||||
let attributes = Window::default_attributes()
|
||||
.with_title("FParkan Vulkan smoke")
|
||||
.with_inner_size(WinitPhysicalSize::new(self.plan.width, self.plan.height));
|
||||
match event_loop.create_window(attributes) {
|
||||
Ok(window) => {
|
||||
self.window = Some(WinitWindow::from_window(&window));
|
||||
}
|
||||
Err(err) => {
|
||||
self.error = Some(err.to_string());
|
||||
}
|
||||
}
|
||||
event_loop.exit();
|
||||
}
|
||||
|
||||
fn window_event(
|
||||
&mut self,
|
||||
_event_loop: &ActiveEventLoop,
|
||||
_window_id: WindowId,
|
||||
_event: WindowEvent,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Minimal window view over a `winit` window.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct WinitWindow {
|
||||
@@ -323,7 +213,7 @@ impl WinitWindow {
|
||||
focused: true,
|
||||
minimized: false,
|
||||
occluded: false,
|
||||
native_handles: native_handles(window),
|
||||
native_handles: window_native_handles(window),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,7 +274,9 @@ impl WindowPort for WinitWindow {
|
||||
}
|
||||
}
|
||||
|
||||
fn native_handles(window: &Window) -> Option<NativeWindowHandles> {
|
||||
/// Extracts raw handles from a live `winit::Window`.
|
||||
#[must_use]
|
||||
pub fn window_native_handles(window: &Window) -> Option<NativeWindowHandles> {
|
||||
let display = window.display_handle().ok()?.as_raw();
|
||||
let window = window.window_handle().ok()?.as_raw();
|
||||
Some(NativeWindowHandles { display, window })
|
||||
@@ -454,33 +346,12 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smoke_window_app_requires_created_native_window() {
|
||||
let app = SmokeWindowApp::new(WinitWindowPlan::smoke());
|
||||
fn monotonic_clock_uses_process_local_epoch() {
|
||||
let clock = WinitClock;
|
||||
let first = clock.now();
|
||||
let second = clock.now();
|
||||
|
||||
assert!(matches!(
|
||||
app.into_probe(),
|
||||
Err(PlatformError::Backend {
|
||||
context: "winit smoke window",
|
||||
..
|
||||
})
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smoke_window_app_rejects_synthetic_window_without_native_handles() {
|
||||
let mut app = SmokeWindowApp::new(WinitWindowPlan::smoke());
|
||||
app.window = Some(WinitWindow::synthetic(
|
||||
DEFAULT_SMOKE_WIDTH,
|
||||
DEFAULT_SMOKE_HEIGHT,
|
||||
));
|
||||
|
||||
assert!(matches!(
|
||||
app.into_probe(),
|
||||
Err(PlatformError::Backend {
|
||||
context: "winit smoke window",
|
||||
..
|
||||
})
|
||||
));
|
||||
assert!(second >= first);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 in_color;
|
||||
layout(location = 0) out vec4 out_color;
|
||||
|
||||
void main() {
|
||||
out_color = vec4(in_color, 1.0);
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,11 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 in_position;
|
||||
layout(location = 1) in vec3 in_color;
|
||||
|
||||
layout(location = 0) out vec3 out_color;
|
||||
|
||||
void main() {
|
||||
out_color = in_color;
|
||||
gl_Position = vec4(in_position, 0.0, 1.0);
|
||||
}
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,7 @@ use fparkan_render::{
|
||||
DrawCommand, DrawId, GpuMaterialId, GpuMeshId, IndexRange, RenderBackend, RenderCommand,
|
||||
RenderCommandList, RenderPhase,
|
||||
};
|
||||
use fparkan_render_vulkan::VulkanBackend;
|
||||
use fparkan_render_vulkan::VulkanPlanningBackend;
|
||||
use fparkan_runtime::{
|
||||
create, frame, load_mission, loaded_mission_assets, EngineConfig, EngineMode, EngineServices,
|
||||
MissionAssets, MissionRequest,
|
||||
@@ -71,7 +71,7 @@ fn run(args: &[String]) -> Result<String, String> {
|
||||
)
|
||||
.map_err(|err| err.to_string())?;
|
||||
|
||||
let mut backend = VulkanBackend::new();
|
||||
let mut backend = VulkanPlanningBackend::new();
|
||||
let _request = WinitWindow::default_render_request();
|
||||
let window = WinitWindow::synthetic(1280, 720);
|
||||
let _ = window.drawable_size();
|
||||
|
||||
@@ -9,6 +9,7 @@ repository.workspace = true
|
||||
fparkan-platform = { path = "../../crates/fparkan-platform" }
|
||||
fparkan-platform-winit = { path = "../../adapters/fparkan-platform-winit" }
|
||||
fparkan-render-vulkan = { path = "../../adapters/fparkan-render-vulkan" }
|
||||
winit = "0.30"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
+356
-1425
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@ S0-ARCH-007 covered cargo xtask ci runs fmt, policy, workspace test, clippy, rus
|
||||
S0-ARCH-008 covered cargo xtask policy rejects moving Rust toolchains and workspace rust-version drift
|
||||
S0-ARCH-009 covered .github/workflows/ci.yml runs a pinned MSRV backend-neutral crate job
|
||||
S0-ARCH-010 covered cargo xtask acceptance audit emits commit_sha, rust_toolchain, and msrv metadata into the JSON artifact
|
||||
S0-ARCH-011 blocked cargo run -p fparkan-vulkan-smoke emits explicit per-platform blocked artifacts until real Vulkan 300-frame validation=0 runner is available
|
||||
S0-ARCH-011 covered .github/workflows/ci.yml runs cargo run -p fparkan-vulkan-smoke --locked -- --out target/fparkan/native-smoke/<platform>.json and cargo xtask native-smoke audit enforces passed 300-frame reports with measured resize/recreate and validation=0
|
||||
S0-DIAG-001 covered cargo test -p fparkan-diagnostics --offline diagnostic_chain_preserves_context
|
||||
S0-DIAG-002 covered cargo test -p fparkan-diagnostics --offline json_is_stable
|
||||
S0-CORPUS-001 covered cargo test -p fparkan-corpus --offline deterministic_traversal_is_creation_order_independent
|
||||
|
||||
|
@@ -0,0 +1,68 @@
|
||||
# Stage 0 acceptance IDs
|
||||
|
||||
`L0-COPYRIGHT-001`
|
||||
`L0-P1-001`
|
||||
`L0-P1-002`
|
||||
`L0-P2-001`
|
||||
`L0-P2-002`
|
||||
`S0-ARCH-001`
|
||||
`S0-ARCH-002`
|
||||
`S0-ARCH-003`
|
||||
`S0-ARCH-004`
|
||||
`S0-ARCH-005`
|
||||
`S0-ARCH-006`
|
||||
`S0-ARCH-007`
|
||||
`S0-ARCH-008`
|
||||
`S0-ARCH-009`
|
||||
`S0-ARCH-010`
|
||||
`S0-ARCH-011`
|
||||
`S0-DIAG-001`
|
||||
`S0-DIAG-002`
|
||||
`S0-CORPUS-001`
|
||||
`S0-CORPUS-002`
|
||||
`S0-CORPUS-003`
|
||||
`S0-CORPUS-004`
|
||||
`S0-CORPUS-005`
|
||||
`S0-CORPUS-006`
|
||||
`S0-CLI-001`
|
||||
`S0-CLI-002`
|
||||
`S0-PLAT-001`
|
||||
`S0-PLAT-002`
|
||||
`S0-PLAT-003`
|
||||
`S0-PLAT-004`
|
||||
`S0-VK-001`
|
||||
`S0-VK-002`
|
||||
`S0-VK-003`
|
||||
`S0-VK-004`
|
||||
`S0-VK-005`
|
||||
`S0-VK-006`
|
||||
`S0-VK-007`
|
||||
`S0-VK-008`
|
||||
`S0-VK-009`
|
||||
`S0-VK-010`
|
||||
`S0-VK-011`
|
||||
`S0-VK-012`
|
||||
`S0-VK-013`
|
||||
`S0-VK-014`
|
||||
`S0-VK-015`
|
||||
`S0-VK-016`
|
||||
`S0-VK-017`
|
||||
`S0-VK-018`
|
||||
`S0-VK-019`
|
||||
`S0-VK-020`
|
||||
`S0-VK-021`
|
||||
`S0-VK-022`
|
||||
`S0-VK-023`
|
||||
`S0-VK-024`
|
||||
`S0-VK-025`
|
||||
`S0-VK-026`
|
||||
`S0-VK-027`
|
||||
`S0-VK-028`
|
||||
`S0-VK-029`
|
||||
`S0-VK-030`
|
||||
`S0-VK-031`
|
||||
`S0-VK-032`
|
||||
`S0-VK-033`
|
||||
`S0-VK-034`
|
||||
`S0-LIMIT-001`
|
||||
`S0-LIMIT-002`
|
||||
+28
-16
@@ -34,9 +34,9 @@ use std::process::Command;
|
||||
const CORPORA_MANIFEST_ENV: &str = "FPARKAN_CORPORA_MANIFEST";
|
||||
const PART1_ROOT_ENV: &str = "FPARKAN_CORPUS_PART1_ROOT";
|
||||
const PART2_ROOT_ENV: &str = "FPARKAN_CORPUS_PART2_ROOT";
|
||||
const CI_ACCEPTANCE_ROADMAP: &str = "fixtures/acceptance/stage_0_2_roadmap.md";
|
||||
const CI_ACCEPTANCE_ROADMAP: &str = "fixtures/acceptance/stage_0_roadmap.md";
|
||||
const CI_ACCEPTANCE_COVERAGE: &str = "fixtures/acceptance/coverage.tsv";
|
||||
const CI_ACCEPTANCE_REPORT: &str = "target/fparkan/acceptance/stage-0-2-audit.json";
|
||||
const CI_ACCEPTANCE_REPORT: &str = "target/fparkan/acceptance/stage-0-audit.json";
|
||||
const STAGE_PACKAGE_MANIFEST: &str = "fixtures/acceptance/stage_packages.toml";
|
||||
const REQUIRED_NATIVE_SMOKE_PLATFORMS: &[&str] = &["linux", "macos", "windows"];
|
||||
const APPROVED_REGISTRY_SOURCE: &str = "registry+https://github.com/rust-lang/crates.io-index";
|
||||
@@ -193,16 +193,16 @@ fn run_cargo_fmt_check() -> Result<(), String> {
|
||||
|
||||
fn run_cargo_deny() -> Result<(), String> {
|
||||
let cargo_deny = std::env::var_os("CARGO_DENY").unwrap_or_else(|| "cargo-deny".into());
|
||||
let version_output = Command::new(&cargo_deny)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.map_err(|err| {
|
||||
format!(
|
||||
"cargo-deny is required; install cargo-deny {PINNED_CARGO_DENY_VERSION} or set {ALLOW_SUPPLY_CHAIN_FALLBACK_ENV}=1 for the built-in fallback: {err}"
|
||||
)
|
||||
})?;
|
||||
let version_output = match Command::new(&cargo_deny).arg("--version").output() {
|
||||
Ok(output) => output,
|
||||
Err(err) => {
|
||||
return handle_cargo_deny_fallback(&format!(
|
||||
"failed to run cargo-deny --version: {err}"
|
||||
));
|
||||
}
|
||||
};
|
||||
if !version_output.status.success() {
|
||||
return handle_cargo_deny_fallback(format!(
|
||||
return handle_cargo_deny_fallback(&format!(
|
||||
"cargo-deny --version exited with {}",
|
||||
version_output.status
|
||||
));
|
||||
@@ -210,7 +210,7 @@ fn run_cargo_deny() -> Result<(), String> {
|
||||
let version_text = String::from_utf8(version_output.stdout)
|
||||
.map_err(|err| format!("cargo-deny --version produced invalid UTF-8: {err}"))?;
|
||||
if !version_text.contains(PINNED_CARGO_DENY_VERSION) {
|
||||
return handle_cargo_deny_fallback(format!(
|
||||
return handle_cargo_deny_fallback(&format!(
|
||||
"cargo-deny version mismatch: expected {PINNED_CARGO_DENY_VERSION}, found {}",
|
||||
version_text.trim()
|
||||
));
|
||||
@@ -237,7 +237,7 @@ fn run_cargo_deny() -> Result<(), String> {
|
||||
|
||||
const PINNED_CARGO_DENY_VERSION: &str = "0.19.9";
|
||||
|
||||
fn handle_cargo_deny_fallback(reason: String) -> Result<(), String> {
|
||||
fn handle_cargo_deny_fallback(reason: &str) -> Result<(), String> {
|
||||
if std::env::var_os(ALLOW_SUPPLY_CHAIN_FALLBACK_ENV).is_some() {
|
||||
eprintln!(
|
||||
"{reason}; running built-in supply-chain policy fallback because {ALLOW_SUPPLY_CHAIN_FALLBACK_ENV} is set"
|
||||
@@ -1605,6 +1605,7 @@ fn validate_native_smoke_report(
|
||||
expect_u64_at_least(platform, report, "frames", 300, failures);
|
||||
expect_u64_at_least(platform, report, "resize_count", 1, failures);
|
||||
expect_u64_at_least(platform, report, "swapchain_recreate_count", 1, failures);
|
||||
expect_u64_field(platform, report, "validation_warning_count", 0, failures);
|
||||
expect_u64_field(platform, report, "validation_error_count", 0, failures);
|
||||
expect_nonempty_string(platform, report, "commit_sha", failures);
|
||||
expect_string_field(
|
||||
@@ -1889,6 +1890,10 @@ fn build_acceptance_audit(
|
||||
let mut missing = Vec::new();
|
||||
let mut by_stage = BTreeMap::new();
|
||||
let mut coverage_evidence = BTreeMap::new();
|
||||
let required_scopes = required
|
||||
.iter()
|
||||
.filter_map(|id| id.get(0..2).map(ToString::to_string))
|
||||
.collect::<BTreeSet<_>>();
|
||||
|
||||
for id in required {
|
||||
let stage = id
|
||||
@@ -1909,7 +1914,12 @@ fn build_acceptance_audit(
|
||||
|
||||
let unknown_coverage = coverage
|
||||
.keys()
|
||||
.filter(|id| !required.contains(*id))
|
||||
.filter(|id| {
|
||||
!required.contains(*id)
|
||||
&& id
|
||||
.get(0..2)
|
||||
.is_some_and(|scope| required_scopes.contains(scope))
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
@@ -2367,7 +2377,7 @@ mod tests {
|
||||
},
|
||||
),
|
||||
(
|
||||
"S9-UNKNOWN-001".to_string(),
|
||||
"S0-ARCH-099".to_string(),
|
||||
CoverageEntry {
|
||||
status: CoverageStatus::Partial,
|
||||
evidence: "bad id".to_string(),
|
||||
@@ -2383,7 +2393,7 @@ mod tests {
|
||||
assert_eq!(audit.blocked, ["L5-RG40-001"]);
|
||||
assert_eq!(audit.omitted, ["L3-DEVICE-001"]);
|
||||
assert_eq!(audit.missing, ["S0-ARCH-002"]);
|
||||
assert_eq!(audit.unknown_coverage, ["S9-UNKNOWN-001"]);
|
||||
assert_eq!(audit.unknown_coverage, ["S0-ARCH-099"]);
|
||||
assert_eq!(audit.by_stage.get("S0"), Some(&2));
|
||||
assert_eq!(
|
||||
audit.strict_failures(),
|
||||
@@ -2436,6 +2446,7 @@ mod tests {
|
||||
"frames": 300,
|
||||
"resize_count": 1,
|
||||
"swapchain_recreate_count": 1,
|
||||
"validation_warning_count": 0,
|
||||
"validation_error_count": 0,
|
||||
"shader_manifest_hash": "dd293e4ff08ffca1c037900d08b0ffd415db39f238b4fcdde46468fa049b679c",
|
||||
"vulkan_loader_status": "available",
|
||||
@@ -2474,6 +2485,7 @@ mod tests {
|
||||
"frames": 0,
|
||||
"resize_count": 0,
|
||||
"swapchain_recreate_count": 0,
|
||||
"validation_warning_count": null,
|
||||
"validation_error_count": null,
|
||||
"shader_manifest_hash": "dd293e4ff08ffca1c037900d08b0ffd415db39f238b4fcdde46468fa049b679c",
|
||||
"vulkan_loader_status": "unavailable",
|
||||
|
||||
Reference in New Issue
Block a user