chore: clarify planning acceptance semantics
This commit is contained in:
@@ -19,7 +19,7 @@
|
|||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
#![allow(clippy::print_stderr, clippy::print_stdout)]
|
#![allow(clippy::print_stderr, clippy::print_stdout)]
|
||||||
//! `FParkan` rendered game composition root.
|
//! `FParkan` render-planning composition root.
|
||||||
|
|
||||||
use fparkan_assets::PreparedVisual;
|
use fparkan_assets::PreparedVisual;
|
||||||
use fparkan_platform::WindowPort;
|
use fparkan_platform::WindowPort;
|
||||||
@@ -98,7 +98,7 @@ fn run(args: &[String]) -> Result<String, String> {
|
|||||||
let capture_report = backend.report();
|
let capture_report = backend.report();
|
||||||
|
|
||||||
Ok(format!(
|
Ok(format!(
|
||||||
"{{\"mission\":{},\"objects\":{},\"frames\":{},\"tick\":{},\"draws\":{},\"captures\":{},\"last_capture_bytes\":{},\"hash\":{}}}",
|
"{{\"report_kind\":\"render-planning\",\"backend\":\"vulkan-planning\",\"window\":\"synthetic\",\"mission\":{},\"objects\":{},\"frames\":{},\"tick\":{},\"draws\":{},\"submission_plans\":{},\"last_command_capture_bytes\":{},\"hash\":{}}}",
|
||||||
json_string(&args.mission),
|
json_string(&args.mission),
|
||||||
loaded.object_count,
|
loaded.object_count,
|
||||||
args.frames,
|
args.frames,
|
||||||
@@ -325,12 +325,12 @@ mod tests {
|
|||||||
RenderCase {
|
RenderCase {
|
||||||
root: "IS",
|
root: "IS",
|
||||||
mission: "MISSIONS/CAMPAIGN/CAMPAIGN.00/Mission.01/data.tma",
|
mission: "MISSIONS/CAMPAIGN/CAMPAIGN.00/Mission.01/data.tma",
|
||||||
expected: "{\"mission\":\"MISSIONS/CAMPAIGN/CAMPAIGN.00/Mission.01/data.tma\",\"objects\":33,\"frames\":1,\"tick\":1,\"draws\":33,\"captures\":1,\"last_capture_bytes\":810,\"hash\":\"ca17cc76e55c45e83c1c9c1c088e84bf1a698be91a7730943210fe27596af841\"}",
|
expected: "{\"report_kind\":\"render-planning\",\"backend\":\"vulkan-planning\",\"window\":\"synthetic\",\"mission\":\"MISSIONS/CAMPAIGN/CAMPAIGN.00/Mission.01/data.tma\",\"objects\":33,\"frames\":1,\"tick\":1,\"draws\":33,\"submission_plans\":1,\"last_command_capture_bytes\":810,\"hash\":\"ca17cc76e55c45e83c1c9c1c088e84bf1a698be91a7730943210fe27596af841\"}",
|
||||||
},
|
},
|
||||||
RenderCase {
|
RenderCase {
|
||||||
root: "IS2",
|
root: "IS2",
|
||||||
mission: "MISSIONS/Campaign/CAMPAIGN.00/Mission.02/data.tma",
|
mission: "MISSIONS/Campaign/CAMPAIGN.00/Mission.02/data.tma",
|
||||||
expected: "{\"mission\":\"MISSIONS/Campaign/CAMPAIGN.00/Mission.02/data.tma\",\"objects\":10,\"frames\":1,\"tick\":1,\"draws\":10,\"captures\":1,\"last_capture_bytes\":235,\"hash\":\"5d720b3ab690076a398a79a404850bbeaee2e33811b5bb570ec8a96d4a7a2fc4\"}",
|
expected: "{\"report_kind\":\"render-planning\",\"backend\":\"vulkan-planning\",\"window\":\"synthetic\",\"mission\":\"MISSIONS/Campaign/CAMPAIGN.00/Mission.02/data.tma\",\"objects\":10,\"frames\":1,\"tick\":1,\"draws\":10,\"submission_plans\":1,\"last_command_capture_bytes\":235,\"hash\":\"5d720b3ab690076a398a79a404850bbeaee2e33811b5bb570ec8a96d4a7a2fc4\"}",
|
||||||
},
|
},
|
||||||
] {
|
] {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
#![allow(clippy::print_stderr, clippy::print_stdout)]
|
#![allow(clippy::print_stderr, clippy::print_stdout)]
|
||||||
//! `FParkan` asset viewer composition root.
|
//! `FParkan` asset inspection composition root.
|
||||||
|
|
||||||
use fparkan_inspection::{
|
use fparkan_inspection::{
|
||||||
inspect_land_file, inspect_model_from_root, inspect_texture_from_root, ArchiveInspection,
|
inspect_land_file, inspect_model_from_root, inspect_texture_from_root, ArchiveInspection,
|
||||||
@@ -68,14 +68,14 @@ fn inspect_archive(args: &[String]) -> Result<String, String> {
|
|||||||
lookup_order_valid,
|
lookup_order_valid,
|
||||||
sample,
|
sample,
|
||||||
} => Ok(format!(
|
} => Ok(format!(
|
||||||
"{{\"kind\":\"NRes\",\"path\":{},\"entries\":{},\"lookup_order_valid\":{},\"sample\":[{}]}}",
|
"{{\"report_kind\":\"archive-inspection\",\"kind\":\"NRes\",\"path\":{},\"entries\":{},\"lookup_order_valid\":{},\"sample\":[{}]}}",
|
||||||
json_string(&file.display().to_string()),
|
json_string(&file.display().to_string()),
|
||||||
entries,
|
entries,
|
||||||
lookup_order_valid,
|
lookup_order_valid,
|
||||||
render_nres_entries(&sample)
|
render_nres_entries(&sample)
|
||||||
)),
|
)),
|
||||||
ArchiveInspection::Rsli { entries } => Ok(format!(
|
ArchiveInspection::Rsli { entries } => Ok(format!(
|
||||||
"{{\"kind\":\"RsLi\",\"path\":{},\"entries\":{}}}",
|
"{{\"report_kind\":\"archive-inspection\",\"kind\":\"RsLi\",\"path\":{},\"entries\":{}}}",
|
||||||
json_string(&file.display().to_string()),
|
json_string(&file.display().to_string()),
|
||||||
entries
|
entries
|
||||||
)),
|
)),
|
||||||
@@ -92,7 +92,7 @@ fn inspect_model(args: &[String]) -> Result<String, String> {
|
|||||||
let inspection = inspect_model_from_root(&query.root, &query.archive, &query.name)?;
|
let inspection = inspect_model_from_root(&query.root, &query.archive, &query.name)?;
|
||||||
|
|
||||||
Ok(format!(
|
Ok(format!(
|
||||||
"{{\"kind\":\"model\",\"archive\":{},\"name\":{},\"streams\":{},\"nodes\":{},\"slots\":{},\"positions\":{},\"indices\":{},\"batches\":{}}}",
|
"{{\"report_kind\":\"model-inspection\",\"kind\":\"model\",\"archive\":{},\"name\":{},\"streams\":{},\"nodes\":{},\"slots\":{},\"positions\":{},\"indices\":{},\"batches\":{}}}",
|
||||||
json_string(&query.archive),
|
json_string(&query.archive),
|
||||||
json_string(&query.name),
|
json_string(&query.name),
|
||||||
inspection.streams,
|
inspection.streams,
|
||||||
@@ -136,7 +136,7 @@ impl ViewerModelService {
|
|||||||
.count();
|
.count();
|
||||||
|
|
||||||
Ok(format!(
|
Ok(format!(
|
||||||
"{{\"kind\":\"model\",\"fixture\":{},\"service\":\"synthetic-model\",\"draw_commands\":{draw_commands}}}",
|
"{{\"report_kind\":\"model-inspection\",\"kind\":\"model\",\"fixture\":{},\"service\":\"synthetic-model-inspection\",\"draw_commands\":{draw_commands}}}",
|
||||||
json_string(fixture)
|
json_string(fixture)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -147,7 +147,7 @@ fn inspect_texture(args: &[String]) -> Result<String, String> {
|
|||||||
let inspection = inspect_texture_from_root(&query.root, &query.archive, &query.name)?;
|
let inspection = inspect_texture_from_root(&query.root, &query.archive, &query.name)?;
|
||||||
|
|
||||||
Ok(format!(
|
Ok(format!(
|
||||||
"{{\"kind\":\"texture\",\"archive\":{},\"name\":{},\"width\":{},\"height\":{},\"format\":{},\"mips\":{},\"pages\":{}}}",
|
"{{\"report_kind\":\"texture-inspection\",\"kind\":\"texture\",\"archive\":{},\"name\":{},\"width\":{},\"height\":{},\"format\":{},\"mips\":{},\"pages\":{}}}",
|
||||||
json_string(&query.archive),
|
json_string(&query.archive),
|
||||||
json_string(&query.name),
|
json_string(&query.name),
|
||||||
inspection.width,
|
inspection.width,
|
||||||
@@ -180,7 +180,7 @@ fn inspect_map(args: &[String]) -> Result<String, String> {
|
|||||||
fn render_map_inspection_json(path: &str, kind: &str, inspection: &MapInspection) -> String {
|
fn render_map_inspection_json(path: &str, kind: &str, inspection: &MapInspection) -> String {
|
||||||
match kind {
|
match kind {
|
||||||
"land-msh" => format!(
|
"land-msh" => format!(
|
||||||
"{{\"kind\":\"land-msh\",\"path\":{},\"streams\":{},\"positions\":{},\"faces\":{},\"slots\":{}}}",
|
"{{\"report_kind\":\"map-inspection\",\"kind\":\"land-msh\",\"path\":{},\"streams\":{},\"positions\":{},\"faces\":{},\"slots\":{}}}",
|
||||||
json_string(path),
|
json_string(path),
|
||||||
inspection.streams,
|
inspection.streams,
|
||||||
inspection.positions,
|
inspection.positions,
|
||||||
@@ -188,7 +188,7 @@ fn render_map_inspection_json(path: &str, kind: &str, inspection: &MapInspection
|
|||||||
inspection.slots
|
inspection.slots
|
||||||
),
|
),
|
||||||
"land-map" => format!(
|
"land-map" => format!(
|
||||||
"{{\"kind\":\"land-map\",\"path\":{},\"areals\":{},\"declared_areals\":{},\"grid_width\":{},\"grid_height\":{}}}",
|
"{{\"report_kind\":\"map-inspection\",\"kind\":\"land-map\",\"path\":{},\"areals\":{},\"declared_areals\":{},\"grid_width\":{},\"grid_height\":{}}}",
|
||||||
json_string(path),
|
json_string(path),
|
||||||
inspection.areals,
|
inspection.areals,
|
||||||
inspection.declared_areals,
|
inspection.declared_areals,
|
||||||
@@ -342,7 +342,7 @@ mod tests {
|
|||||||
fn model_fixture_uses_viewer_service_and_render_commands() -> Result<(), String> {
|
fn model_fixture_uses_viewer_service_and_render_commands() -> Result<(), String> {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
run(&strings(&["model", "--fixture", "synthetic/model-basic"]))?,
|
run(&strings(&["model", "--fixture", "synthetic/model-basic"]))?,
|
||||||
"{\"kind\":\"model\",\"fixture\":\"synthetic/model-basic\",\"service\":\"synthetic-model\",\"draw_commands\":1}"
|
"{\"report_kind\":\"model-inspection\",\"kind\":\"model\",\"fixture\":\"synthetic/model-basic\",\"service\":\"synthetic-model-inspection\",\"draw_commands\":1}"
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -389,6 +389,11 @@ pub trait RenderBackend {
|
|||||||
fn execute(&mut self, commands: &RenderCommandList) -> Result<FrameOutput, RenderError>;
|
fn execute(&mut self, commands: &RenderCommandList) -> Result<FrameOutput, RenderError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Marker trait for backends that execute draws against a live GPU.
|
||||||
|
///
|
||||||
|
/// Planning and capture-only backends must not implement this trait.
|
||||||
|
pub trait GpuRenderBackend: RenderBackend {}
|
||||||
|
|
||||||
/// Backend that validates commands and intentionally produces no pixels.
|
/// Backend that validates commands and intentionally produces no pixels.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct NullBackend;
|
pub struct NullBackend;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Acceptance coverage manifest.
|
# Acceptance coverage manifest.
|
||||||
# Format: <acceptance-id>\t<covered|partial|blocked|omitted>\t<evidence>
|
# Format: <acceptance-id>\t<covered|covered-planning|covered-stub|covered-gpu|partial|blocked|omitted>\t<evidence>
|
||||||
# Scope note: Stage 0 is closed for the macOS/codebase review scope.
|
# Scope note: Stage 0 is closed for the macOS/codebase review scope.
|
||||||
# Scope note: cross-platform native runtime and hosted CI evidence remain deferred.
|
# Scope note: cross-platform native runtime and hosted CI evidence remain deferred.
|
||||||
L0-COPYRIGHT-001 covered cargo test -p fparkan-corpus --offline report_json_contains_metrics_and_hashes_not_paths_or_payloads
|
L0-COPYRIGHT-001 covered cargo test -p fparkan-corpus --offline report_json_contains_metrics_and_hashes_not_paths_or_payloads
|
||||||
@@ -32,7 +32,7 @@ S0-PLAT-001 covered cargo test -p fparkan-platform-winit --offline window_port_r
|
|||||||
S0-PLAT-002 covered cargo clippy -p fparkan-platform -p fparkan-platform-winit --all-targets --all-features --locked -- -D warnings
|
S0-PLAT-002 covered cargo clippy -p fparkan-platform -p fparkan-platform-winit --all-targets --all-features --locked -- -D warnings
|
||||||
S0-PLAT-003 covered cargo test -p fparkan-platform-winit --offline smoke_window_plan_requires_native_handles_and_nonzero_extent smoke_window_plan_rejects_zero_extent
|
S0-PLAT-003 covered cargo test -p fparkan-platform-winit --offline smoke_window_plan_requires_native_handles_and_nonzero_extent smoke_window_plan_rejects_zero_extent
|
||||||
S0-PLAT-004 covered cargo test -p fparkan-platform-winit --offline smoke_window_app_requires_created_native_window smoke_window_app_rejects_synthetic_window_without_native_handles
|
S0-PLAT-004 covered cargo test -p fparkan-platform-winit --offline smoke_window_app_requires_created_native_window smoke_window_app_rejects_synthetic_window_without_native_handles
|
||||||
S0-VK-001 covered cargo test -p fparkan-render-vulkan --offline planning_backend_tracks_render_request_and_simulated_present
|
S0-VK-001 covered-planning cargo test -p fparkan-render-vulkan --offline planning_backend_tracks_render_request_and_simulated_present
|
||||||
S0-VK-002 covered cargo test -p fparkan-render-vulkan --offline device_scoring_is_deterministic_and_prefers_discrete_unified_queue
|
S0-VK-002 covered cargo test -p fparkan-render-vulkan --offline device_scoring_is_deterministic_and_prefers_discrete_unified_queue
|
||||||
S0-VK-003 covered cargo test -p fparkan-render-vulkan --offline portability_subset_is_reported_and_enabled_when_exposed
|
S0-VK-003 covered cargo test -p fparkan-render-vulkan --offline portability_subset_is_reported_and_enabled_when_exposed
|
||||||
S0-VK-004 covered cargo test -p fparkan-render-vulkan --offline rejects_missing_graphics_present_swapchain_and_format
|
S0-VK-004 covered cargo test -p fparkan-render-vulkan --offline rejects_missing_graphics_present_swapchain_and_format
|
||||||
@@ -52,8 +52,8 @@ S0-VK-017 covered cargo test -p fparkan-render-vulkan --offline swapchain_plan_j
|
|||||||
S0-VK-018 covered cargo test -p fparkan-render-vulkan --offline triangle_shader_manifest_hashes_are_stable checked_in_shader_manifest_matches_generated_report
|
S0-VK-018 covered cargo test -p fparkan-render-vulkan --offline triangle_shader_manifest_hashes_are_stable checked_in_shader_manifest_matches_generated_report
|
||||||
S0-VK-019 covered cargo test -p fparkan-render-vulkan --offline shader_manifest_report_json_is_stable
|
S0-VK-019 covered cargo test -p fparkan-render-vulkan --offline shader_manifest_report_json_is_stable
|
||||||
S0-VK-020 covered cargo test -p fparkan-render-vulkan --offline shader_manifest_rejects_invalid_spirv_containers
|
S0-VK-020 covered cargo test -p fparkan-render-vulkan --offline shader_manifest_rejects_invalid_spirv_containers
|
||||||
S0-VK-021 covered cargo test -p fparkan-render-vulkan --offline frame_submission_plan_json_is_stable
|
S0-VK-021 covered-planning cargo test -p fparkan-render-vulkan --offline frame_submission_plan_json_is_stable
|
||||||
S0-VK-022 covered cargo test -p fparkan-render-vulkan --offline planning_backend_tracks_render_request_and_simulated_present
|
S0-VK-022 covered-planning cargo test -p fparkan-render-vulkan --offline planning_backend_tracks_render_request_and_simulated_present
|
||||||
S0-VK-023 covered cargo test -p fparkan-vulkan-smoke --offline rejects_false_pass_without_full_evidence blocked_report_includes_shader_manifest_and_bootstrap_status
|
S0-VK-023 covered cargo test -p fparkan-vulkan-smoke --offline rejects_false_pass_without_full_evidence blocked_report_includes_shader_manifest_and_bootstrap_status
|
||||||
S0-VK-024 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_loader_probe formats_vulkan_api_version
|
S0-VK-024 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_loader_probe formats_vulkan_api_version
|
||||||
S0-VK-025 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_instance_probe parses_instance_probe_as_loader_probe
|
S0-VK-025 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_instance_probe parses_instance_probe_as_loader_probe
|
||||||
@@ -233,8 +233,8 @@ L3-P1-WEAR-001 covered cargo test -p fparkan-material --offline licensed_corpus_
|
|||||||
L3-P2-WEAR-001 covered cargo test -p fparkan-material --offline licensed_corpus_mat0_and_wear_parse
|
L3-P2-WEAR-001 covered cargo test -p fparkan-material --offline licensed_corpus_mat0_and_wear_parse
|
||||||
L3-P1-ASSET-001 covered cargo test -p fparkan-runtime --offline licensed_corpora_load_all_mission_foundations
|
L3-P1-ASSET-001 covered cargo test -p fparkan-runtime --offline licensed_corpora_load_all_mission_foundations
|
||||||
L3-P2-ASSET-001 covered cargo test -p fparkan-runtime --offline licensed_corpora_load_all_mission_foundations
|
L3-P2-ASSET-001 covered cargo test -p fparkan-runtime --offline licensed_corpora_load_all_mission_foundations
|
||||||
S2-PLANNING-CAPTURE-P1-001 covered cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
|
S2-PLANNING-CAPTURE-P1-001 covered-planning cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
|
||||||
S2-PLANNING-CAPTURE-P2-001 covered cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
|
S2-PLANNING-CAPTURE-P2-001 covered-planning cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
|
||||||
S3-WEAR-001 covered cargo test -p fparkan-material --offline wear_preserves_legacy_id_but_selects_by_index
|
S3-WEAR-001 covered cargo test -p fparkan-material --offline wear_preserves_legacy_id_but_selects_by_index
|
||||||
S3-WEAR-002 covered cargo test -p fparkan-material --offline wear_requires_declared_rows
|
S3-WEAR-002 covered cargo test -p fparkan-material --offline wear_requires_declared_rows
|
||||||
S3-WEAR-003 covered cargo test -p fparkan-material --offline wear_preserves_legacy_id_but_selects_by_index
|
S3-WEAR-003 covered cargo test -p fparkan-material --offline wear_preserves_legacy_id_but_selects_by_index
|
||||||
@@ -292,7 +292,7 @@ S2-PLANNING-RENDER-004 covered cargo test -p fparkan-render --offline command_or
|
|||||||
S2-PLANNING-RENDER-005 covered cargo test -p fparkan-render --offline command_capture_independent_of_snapshot_construction_order
|
S2-PLANNING-RENDER-005 covered cargo test -p fparkan-render --offline command_capture_independent_of_snapshot_construction_order
|
||||||
S2-PLANNING-RENDER-006 covered cargo test -p fparkan-render --offline invalid_range_returns_contextual_error
|
S2-PLANNING-RENDER-006 covered cargo test -p fparkan-render --offline invalid_range_returns_contextual_error
|
||||||
S2-PLANNING-RENDER-007 covered cargo test -p fparkan-render --offline capture_is_stable
|
S2-PLANNING-RENDER-007 covered cargo test -p fparkan-render --offline capture_is_stable
|
||||||
S2-PLANNING-RENDER-008 covered cargo test -p fparkan-render --offline recording_backend_stores_captures
|
S2-PLANNING-RENDER-008 covered-planning cargo test -p fparkan-render --offline recording_backend_stores_captures
|
||||||
S2-PLANNING-RENDER-009 covered cargo xtask policy
|
S2-PLANNING-RENDER-009 covered cargo xtask policy
|
||||||
S3-VK-MESH-UPLOAD-001 blocked awaits Stage 3 Vulkan asset renderer and GPU upload path
|
S3-VK-MESH-UPLOAD-001 blocked awaits Stage 3 Vulkan asset renderer and GPU upload path
|
||||||
S3-VK-TEXM-UPLOAD-001 blocked awaits Stage 3 Vulkan texture upload path
|
S3-VK-TEXM-UPLOAD-001 blocked awaits Stage 3 Vulkan texture upload path
|
||||||
@@ -441,7 +441,7 @@ L5-P1-MISSION-002 covered cargo test -p fparkan-runtime --offline licensed_corpo
|
|||||||
L5-P2-MISSION-002 covered cargo test -p fparkan-runtime --offline licensed_corpora_load_all_mission_foundations
|
L5-P2-MISSION-002 covered cargo test -p fparkan-runtime --offline licensed_corpora_load_all_mission_foundations
|
||||||
L5-P1-HEADLESS-001 covered cargo test -p fparkan-runtime --offline selected_is_and_is2_missions_execute_10000_deterministic_ticks
|
L5-P1-HEADLESS-001 covered cargo test -p fparkan-runtime --offline selected_is_and_is2_missions_execute_10000_deterministic_ticks
|
||||||
L5-P2-HEADLESS-001 covered cargo test -p fparkan-runtime --offline selected_is_and_is2_missions_execute_10000_deterministic_ticks
|
L5-P2-HEADLESS-001 covered cargo test -p fparkan-runtime --offline selected_is_and_is2_missions_execute_10000_deterministic_ticks
|
||||||
L5-P1-RENDER-001 covered cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
|
L5-P1-RENDER-001 covered-planning cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
|
||||||
L5-P2-RENDER-001 covered cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
|
L5-P2-RENDER-001 covered-planning cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
|
||||||
L3-DEVICE-001 omitted outside the current macOS-focused goal scope; RG40XX-capable device/profile evidence remains documented for the portable target scope
|
L3-DEVICE-001 omitted outside the current macOS-focused goal scope; RG40XX-capable device/profile evidence remains documented for the portable target scope
|
||||||
L5-RG40-001 omitted outside the current macOS-focused goal scope; RG40XX 640x480 on-device mission smoke/performance/memory evidence remains documented for the portable target scope
|
L5-RG40-001 omitted outside the current macOS-focused goal scope; RG40XX 640x480 on-device mission smoke/performance/memory evidence remains documented for the portable target scope
|
||||||
|
|||||||
|
+148
-7
@@ -2340,6 +2340,9 @@ struct CoverageEntry {
|
|||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
enum CoverageStatus {
|
enum CoverageStatus {
|
||||||
Covered,
|
Covered,
|
||||||
|
CoveredPlanning,
|
||||||
|
CoveredStub,
|
||||||
|
CoveredGpu,
|
||||||
Partial,
|
Partial,
|
||||||
Blocked,
|
Blocked,
|
||||||
Omitted,
|
Omitted,
|
||||||
@@ -2349,12 +2352,27 @@ impl CoverageStatus {
|
|||||||
fn parse(value: &str) -> Result<Self, String> {
|
fn parse(value: &str) -> Result<Self, String> {
|
||||||
match value {
|
match value {
|
||||||
"covered" => Ok(Self::Covered),
|
"covered" => Ok(Self::Covered),
|
||||||
|
"covered-planning" => Ok(Self::CoveredPlanning),
|
||||||
|
"covered-stub" => Ok(Self::CoveredStub),
|
||||||
|
"covered-gpu" => Ok(Self::CoveredGpu),
|
||||||
"partial" => Ok(Self::Partial),
|
"partial" => Ok(Self::Partial),
|
||||||
"blocked" => Ok(Self::Blocked),
|
"blocked" => Ok(Self::Blocked),
|
||||||
"omitted" => Ok(Self::Omitted),
|
"omitted" => Ok(Self::Omitted),
|
||||||
_ => Err(format!("unknown coverage status: {value}")),
|
_ => Err(format!("unknown coverage status: {value}")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Covered => "covered",
|
||||||
|
Self::CoveredPlanning => "covered-planning",
|
||||||
|
Self::CoveredStub => "covered-stub",
|
||||||
|
Self::CoveredGpu => "covered-gpu",
|
||||||
|
Self::Partial => "partial",
|
||||||
|
Self::Blocked => "blocked",
|
||||||
|
Self::Omitted => "omitted",
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
@@ -2366,22 +2384,34 @@ struct AcceptanceAudit {
|
|||||||
msrv: String,
|
msrv: String,
|
||||||
required_total: usize,
|
required_total: usize,
|
||||||
covered: Vec<String>,
|
covered: Vec<String>,
|
||||||
|
covered_planning: Vec<String>,
|
||||||
|
covered_stub: Vec<String>,
|
||||||
|
covered_gpu: Vec<String>,
|
||||||
partial: Vec<String>,
|
partial: Vec<String>,
|
||||||
blocked: Vec<String>,
|
blocked: Vec<String>,
|
||||||
omitted: Vec<String>,
|
omitted: Vec<String>,
|
||||||
missing: Vec<String>,
|
missing: Vec<String>,
|
||||||
|
invalid_coverage: Vec<String>,
|
||||||
unknown_coverage: Vec<String>,
|
unknown_coverage: Vec<String>,
|
||||||
coverage_evidence: BTreeMap<String, String>,
|
coverage_evidence: BTreeMap<String, String>,
|
||||||
by_stage: BTreeMap<String, usize>,
|
by_stage: BTreeMap<String, usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AcceptanceAudit {
|
impl AcceptanceAudit {
|
||||||
|
fn covered_total(&self) -> usize {
|
||||||
|
self.covered.len()
|
||||||
|
+ self.covered_planning.len()
|
||||||
|
+ self.covered_stub.len()
|
||||||
|
+ self.covered_gpu.len()
|
||||||
|
}
|
||||||
|
|
||||||
fn unverified(&self) -> Vec<String> {
|
fn unverified(&self) -> Vec<String> {
|
||||||
self.partial
|
self.partial
|
||||||
.iter()
|
.iter()
|
||||||
.chain(&self.blocked)
|
.chain(&self.blocked)
|
||||||
.chain(&self.omitted)
|
.chain(&self.omitted)
|
||||||
.chain(&self.missing)
|
.chain(&self.missing)
|
||||||
|
.chain(&self.invalid_coverage)
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@@ -2392,6 +2422,7 @@ impl AcceptanceAudit {
|
|||||||
.chain(&self.blocked)
|
.chain(&self.blocked)
|
||||||
.chain(&self.omitted)
|
.chain(&self.omitted)
|
||||||
.chain(&self.missing)
|
.chain(&self.missing)
|
||||||
|
.chain(&self.invalid_coverage)
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@@ -2469,6 +2500,9 @@ fn build_acceptance_audit(
|
|||||||
coverage: &BTreeMap<String, CoverageEntry>,
|
coverage: &BTreeMap<String, CoverageEntry>,
|
||||||
) -> AcceptanceAudit {
|
) -> AcceptanceAudit {
|
||||||
let mut covered = Vec::new();
|
let mut covered = Vec::new();
|
||||||
|
let mut covered_planning = Vec::new();
|
||||||
|
let mut covered_stub = Vec::new();
|
||||||
|
let mut covered_gpu = Vec::new();
|
||||||
let mut partial = Vec::new();
|
let mut partial = Vec::new();
|
||||||
let mut blocked = Vec::new();
|
let mut blocked = Vec::new();
|
||||||
let mut omitted = Vec::new();
|
let mut omitted = Vec::new();
|
||||||
@@ -2487,6 +2521,9 @@ fn build_acceptance_audit(
|
|||||||
*by_stage.entry(stage).or_insert(0) += 1;
|
*by_stage.entry(stage).or_insert(0) += 1;
|
||||||
match coverage.get(id).map(|entry| entry.status) {
|
match coverage.get(id).map(|entry| entry.status) {
|
||||||
Some(CoverageStatus::Covered) => covered.push(id.clone()),
|
Some(CoverageStatus::Covered) => covered.push(id.clone()),
|
||||||
|
Some(CoverageStatus::CoveredPlanning) => covered_planning.push(id.clone()),
|
||||||
|
Some(CoverageStatus::CoveredStub) => covered_stub.push(id.clone()),
|
||||||
|
Some(CoverageStatus::CoveredGpu) => covered_gpu.push(id.clone()),
|
||||||
Some(CoverageStatus::Partial) => partial.push(id.clone()),
|
Some(CoverageStatus::Partial) => partial.push(id.clone()),
|
||||||
Some(CoverageStatus::Blocked) => blocked.push(id.clone()),
|
Some(CoverageStatus::Blocked) => blocked.push(id.clone()),
|
||||||
Some(CoverageStatus::Omitted) => omitted.push(id.clone()),
|
Some(CoverageStatus::Omitted) => omitted.push(id.clone()),
|
||||||
@@ -2497,6 +2534,11 @@ fn build_acceptance_audit(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let invalid_coverage = coverage
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(id, entry)| coverage_semantic_failure(id, entry.status))
|
||||||
|
.collect();
|
||||||
|
|
||||||
let unknown_coverage = coverage
|
let unknown_coverage = coverage
|
||||||
.keys()
|
.keys()
|
||||||
.filter(|id| {
|
.filter(|id| {
|
||||||
@@ -2516,16 +2558,63 @@ fn build_acceptance_audit(
|
|||||||
msrv: WORKSPACE_MSRV.to_string(),
|
msrv: WORKSPACE_MSRV.to_string(),
|
||||||
required_total: required.len(),
|
required_total: required.len(),
|
||||||
covered,
|
covered,
|
||||||
|
covered_planning,
|
||||||
|
covered_stub,
|
||||||
|
covered_gpu,
|
||||||
partial,
|
partial,
|
||||||
blocked,
|
blocked,
|
||||||
omitted,
|
omitted,
|
||||||
missing,
|
missing,
|
||||||
|
invalid_coverage,
|
||||||
unknown_coverage,
|
unknown_coverage,
|
||||||
coverage_evidence,
|
coverage_evidence,
|
||||||
by_stage,
|
by_stage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn coverage_semantic_failure(id: &str, status: CoverageStatus) -> Option<String> {
|
||||||
|
if is_stage3_or_later(id)
|
||||||
|
&& matches!(
|
||||||
|
status,
|
||||||
|
CoverageStatus::CoveredPlanning | CoverageStatus::CoveredStub
|
||||||
|
)
|
||||||
|
&& has_gpu_delivery_token(id)
|
||||||
|
{
|
||||||
|
return Some(format!(
|
||||||
|
"{id}: {} cannot satisfy Stage 3+ GPU/pixel acceptance; use covered-gpu or leave the row non-green",
|
||||||
|
status.as_str()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(status, CoverageStatus::CoveredStub)
|
||||||
|
&& is_fx_lifecycle_compatibility_id(id)
|
||||||
|
&& !id.contains("STUB")
|
||||||
|
{
|
||||||
|
return Some(format!(
|
||||||
|
"{id}: covered-stub is reserved for explicit STUB-only FX lifecycle acceptance rows"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_stage3_or_later(id: &str) -> bool {
|
||||||
|
id.as_bytes().get(1).is_some_and(|stage| *stage >= b'3')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_gpu_delivery_token(id: &str) -> bool {
|
||||||
|
id.split('-').any(|token| {
|
||||||
|
matches!(
|
||||||
|
token,
|
||||||
|
"VK" | "GPU" | "DRAW" | "PIXEL" | "VALIDATION" | "RENDERED"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_fx_lifecycle_compatibility_id(id: &str) -> bool {
|
||||||
|
id.starts_with("S4-FX-") || id.starts_with("L4-P1-EFFECT-") || id.starts_with("L4-P2-EFFECT-")
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct AcceptanceAuditJson<'a> {
|
struct AcceptanceAuditJson<'a> {
|
||||||
schema_version: &'static str,
|
schema_version: &'static str,
|
||||||
@@ -2536,18 +2625,26 @@ struct AcceptanceAuditJson<'a> {
|
|||||||
msrv: &'a str,
|
msrv: &'a str,
|
||||||
required_total: usize,
|
required_total: usize,
|
||||||
covered_total: usize,
|
covered_total: usize,
|
||||||
|
covered_planning_total: usize,
|
||||||
|
covered_stub_total: usize,
|
||||||
|
covered_gpu_total: usize,
|
||||||
partial_total: usize,
|
partial_total: usize,
|
||||||
blocked_total: usize,
|
blocked_total: usize,
|
||||||
omitted_total: usize,
|
omitted_total: usize,
|
||||||
missing_total: usize,
|
missing_total: usize,
|
||||||
unverified_total: usize,
|
unverified_total: usize,
|
||||||
|
invalid_coverage_total: usize,
|
||||||
unknown_coverage_total: usize,
|
unknown_coverage_total: usize,
|
||||||
by_stage: &'a BTreeMap<String, usize>,
|
by_stage: &'a BTreeMap<String, usize>,
|
||||||
covered: &'a [String],
|
covered: &'a [String],
|
||||||
|
covered_planning: &'a [String],
|
||||||
|
covered_stub: &'a [String],
|
||||||
|
covered_gpu: &'a [String],
|
||||||
partial: &'a [String],
|
partial: &'a [String],
|
||||||
blocked: &'a [String],
|
blocked: &'a [String],
|
||||||
omitted: &'a [String],
|
omitted: &'a [String],
|
||||||
missing: &'a [String],
|
missing: &'a [String],
|
||||||
|
invalid_coverage: &'a [String],
|
||||||
unknown_coverage: &'a [String],
|
unknown_coverage: &'a [String],
|
||||||
coverage_evidence: &'a BTreeMap<String, String>,
|
coverage_evidence: &'a BTreeMap<String, String>,
|
||||||
}
|
}
|
||||||
@@ -2562,19 +2659,27 @@ fn render_audit_json(audit: &AcceptanceAudit) -> Result<String, String> {
|
|||||||
rust_toolchain: &audit.rust_toolchain,
|
rust_toolchain: &audit.rust_toolchain,
|
||||||
msrv: &audit.msrv,
|
msrv: &audit.msrv,
|
||||||
required_total: audit.required_total,
|
required_total: audit.required_total,
|
||||||
covered_total: audit.covered.len(),
|
covered_total: audit.covered_total(),
|
||||||
|
covered_planning_total: audit.covered_planning.len(),
|
||||||
|
covered_stub_total: audit.covered_stub.len(),
|
||||||
|
covered_gpu_total: audit.covered_gpu.len(),
|
||||||
partial_total: audit.partial.len(),
|
partial_total: audit.partial.len(),
|
||||||
blocked_total: audit.blocked.len(),
|
blocked_total: audit.blocked.len(),
|
||||||
omitted_total: audit.omitted.len(),
|
omitted_total: audit.omitted.len(),
|
||||||
missing_total: audit.missing.len(),
|
missing_total: audit.missing.len(),
|
||||||
unverified_total: unverified.len(),
|
unverified_total: unverified.len(),
|
||||||
|
invalid_coverage_total: audit.invalid_coverage.len(),
|
||||||
unknown_coverage_total: audit.unknown_coverage.len(),
|
unknown_coverage_total: audit.unknown_coverage.len(),
|
||||||
by_stage: &audit.by_stage,
|
by_stage: &audit.by_stage,
|
||||||
covered: &audit.covered,
|
covered: &audit.covered,
|
||||||
|
covered_planning: &audit.covered_planning,
|
||||||
|
covered_stub: &audit.covered_stub,
|
||||||
|
covered_gpu: &audit.covered_gpu,
|
||||||
partial: &audit.partial,
|
partial: &audit.partial,
|
||||||
blocked: &audit.blocked,
|
blocked: &audit.blocked,
|
||||||
omitted: &audit.omitted,
|
omitted: &audit.omitted,
|
||||||
missing: &audit.missing,
|
missing: &audit.missing,
|
||||||
|
invalid_coverage: &audit.invalid_coverage,
|
||||||
unknown_coverage: &audit.unknown_coverage,
|
unknown_coverage: &audit.unknown_coverage,
|
||||||
coverage_evidence: &audit.coverage_evidence,
|
coverage_evidence: &audit.coverage_evidence,
|
||||||
};
|
};
|
||||||
@@ -2936,7 +3041,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builds_acceptance_audit_counts() {
|
fn builds_acceptance_audit_counts() {
|
||||||
let required = ["S0-ARCH-001", "S0-ARCH-002", "L3-DEVICE-001", "L5-RG40-001"]
|
let required = ["S0-ARCH-001", "S0-ARCH-002", "L3-GPU-001", "L5-RG40-001"]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(str::to_string)
|
.map(str::to_string)
|
||||||
.collect::<BTreeSet<_>>();
|
.collect::<BTreeSet<_>>();
|
||||||
@@ -2949,10 +3054,10 @@ mod tests {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"L3-DEVICE-001".to_string(),
|
"L3-GPU-001".to_string(),
|
||||||
CoverageEntry {
|
CoverageEntry {
|
||||||
status: CoverageStatus::Omitted,
|
status: CoverageStatus::CoveredPlanning,
|
||||||
evidence: "outside macos scope".to_string(),
|
evidence: "planning-only evidence".to_string(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@@ -2976,14 +3081,46 @@ mod tests {
|
|||||||
let audit = build_acceptance_audit(&required, &coverage);
|
let audit = build_acceptance_audit(&required, &coverage);
|
||||||
|
|
||||||
assert_eq!(audit.covered, ["S0-ARCH-001"]);
|
assert_eq!(audit.covered, ["S0-ARCH-001"]);
|
||||||
|
assert_eq!(audit.covered_planning, ["L3-GPU-001"]);
|
||||||
assert_eq!(audit.blocked, ["L5-RG40-001"]);
|
assert_eq!(audit.blocked, ["L5-RG40-001"]);
|
||||||
assert_eq!(audit.omitted, ["L3-DEVICE-001"]);
|
|
||||||
assert_eq!(audit.missing, ["S0-ARCH-002"]);
|
assert_eq!(audit.missing, ["S0-ARCH-002"]);
|
||||||
assert_eq!(audit.unknown_coverage, ["S0-ARCH-099"]);
|
assert_eq!(audit.unknown_coverage, ["S0-ARCH-099"]);
|
||||||
assert_eq!(audit.by_stage.get("S0"), Some(&2));
|
assert_eq!(audit.by_stage.get("S0"), Some(&2));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
audit.strict_failures(),
|
audit.strict_failures(),
|
||||||
strings(&["L5-RG40-001", "L3-DEVICE-001", "S0-ARCH-002"])
|
vec![
|
||||||
|
"L5-RG40-001".to_string(),
|
||||||
|
"S0-ARCH-002".to_string(),
|
||||||
|
"L3-GPU-001: covered-planning cannot satisfy Stage 3+ GPU/pixel acceptance; use covered-gpu or leave the row non-green".to_string(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn covered_stub_requires_explicit_stub_fx_acceptance_row() {
|
||||||
|
let required = ["S4-FX-018"]
|
||||||
|
.into_iter()
|
||||||
|
.map(str::to_string)
|
||||||
|
.collect::<BTreeSet<_>>();
|
||||||
|
let coverage = [(
|
||||||
|
"S4-FX-018".to_string(),
|
||||||
|
CoverageEntry {
|
||||||
|
status: CoverageStatus::CoveredStub,
|
||||||
|
evidence: "reference stub output".to_string(),
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect::<BTreeMap<_, _>>();
|
||||||
|
|
||||||
|
let audit = build_acceptance_audit(&required, &coverage);
|
||||||
|
|
||||||
|
assert_eq!(audit.covered_stub, ["S4-FX-018"]);
|
||||||
|
assert_eq!(
|
||||||
|
audit.invalid_coverage,
|
||||||
|
vec![
|
||||||
|
"S4-FX-018: covered-stub is reserved for explicit STUB-only FX lifecycle acceptance rows"
|
||||||
|
.to_string()
|
||||||
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2997,10 +3134,14 @@ mod tests {
|
|||||||
msrv: WORKSPACE_MSRV.to_string(),
|
msrv: WORKSPACE_MSRV.to_string(),
|
||||||
required_total: 1,
|
required_total: 1,
|
||||||
covered: vec!["S0-ARCH-001".to_string()],
|
covered: vec!["S0-ARCH-001".to_string()],
|
||||||
|
covered_planning: Vec::new(),
|
||||||
|
covered_stub: Vec::new(),
|
||||||
|
covered_gpu: Vec::new(),
|
||||||
partial: Vec::new(),
|
partial: Vec::new(),
|
||||||
blocked: Vec::new(),
|
blocked: Vec::new(),
|
||||||
omitted: Vec::new(),
|
omitted: Vec::new(),
|
||||||
missing: Vec::new(),
|
missing: Vec::new(),
|
||||||
|
invalid_coverage: Vec::new(),
|
||||||
unknown_coverage: Vec::new(),
|
unknown_coverage: Vec::new(),
|
||||||
coverage_evidence: BTreeMap::new(),
|
coverage_evidence: BTreeMap::new(),
|
||||||
by_stage: BTreeMap::new(),
|
by_stage: BTreeMap::new(),
|
||||||
|
|||||||
Reference in New Issue
Block a user