4 Commits
Author SHA1 Message Date
Valentin Popov 0c54142ad5 refactor: harden stage 2 graph and asset limits
Docs Deploy / Build and Deploy MkDocs (push) Successful in 36s
Test / Lint (push) Failing after 5m24s
Test / Test (push) Has been skipped
Test / Render parity (push) Has been skipped
2026-07-03 21:54:09 +04:00
Valentin Popov 44627cd532 fix: guard prepared asset id collisions 2026-07-03 21:49:42 +04:00
Valentin Popov f34c422b20 test: realign stage 2 acceptance coverage 2026-07-03 21:44:26 +04:00
Valentin Popov a89bd9af2a docs: clarify stage 0 acceptance scope 2026-07-03 21:28:18 +04:00
8 changed files with 1142 additions and 69 deletions
+39 -4
View File
@@ -255,7 +255,12 @@ fn prototype_inspect_json(
textures: report.texture_resolved_count,
lightmaps: report.lightmap_resolved_count,
is_success: report.is_success(),
failures: report.failures.iter().take(16).map(graph_failure_output).collect(),
failures: report
.failures
.iter()
.take(16)
.map(graph_failure_output)
.collect(),
})
}
@@ -366,9 +371,7 @@ fn serialize_json<T: Serialize>(value: &T) -> Result<String, String> {
serde_json::to_string(value).map_err(|err| err.to_string())
}
fn graph_failure_output(
failure: &fparkan_prototype::PrototypeGraphFailure,
) -> GraphFailureOutput {
fn graph_failure_output(failure: &fparkan_prototype::PrototypeGraphFailure) -> GraphFailureOutput {
GraphFailureOutput {
root_index: failure.root_index,
edge: prototype_graph_edge_label(failure.edge),
@@ -472,4 +475,36 @@ mod tests {
"{\"schema_version\":\"fparkan-prototype-inspect-v1\",\"key\":\"root\",\"roots\":1,\"node_count\":0,\"edge_count\":0,\"prototype_requests\":1,\"resolved\":1,\"unit_references\":0,\"unit_components\":0,\"direct_references\":1,\"wear_requests\":0,\"wear\":0,\"materials\":0,\"textures\":0,\"lightmaps\":0,\"is_success\":true,\"failures\":[]}"
);
}
#[test]
fn mission_graph_json_has_canonical_field_order() {
let json = serialize_json(&MissionGraphOutput {
schema_version: MISSION_GRAPH_SCHEMA,
mission: "MISSIONS/Autodemo.00/data.tma".to_string(),
objects: 2,
paths: 3,
clans: 4,
extras: 5,
roots: 6,
node_count: 7,
edge_count: 8,
direct_references: 9,
unit_references: 10,
unit_components: 11,
prototype_requests: 12,
wear_requests: 13,
wear: 14,
materials: 15,
textures: 16,
lightmaps: 17,
is_success: true,
failures: 0,
})
.expect("serialize");
assert_eq!(
json,
"{\"schema_version\":\"fparkan-mission-graph-v1\",\"mission\":\"MISSIONS/Autodemo.00/data.tma\",\"objects\":2,\"paths\":3,\"clans\":4,\"extras\":5,\"roots\":6,\"node_count\":7,\"edge_count\":8,\"direct_references\":9,\"unit_references\":10,\"unit_components\":11,\"prototype_requests\":12,\"wear_requests\":13,\"wear\":14,\"materials\":15,\"textures\":16,\"lightmaps\":17,\"is_success\":true,\"failures\":0}"
);
}
}
File diff suppressed because it is too large Load Diff
+2 -4
View File
@@ -128,6 +128,8 @@ pub struct PrototypeGraph {
pub prototype_requests: Vec<PrototypeKey>,
/// Mission object-local spans of effective prototype requests.
pub root_prototype_request_spans: Vec<std::ops::Range<usize>>,
/// Whether visual dependency expansion has already been applied.
pub visual_dependencies_expanded: bool,
/// Materialized prototype dependency graph nodes.
pub nodes: Vec<PrototypeGraphNode>,
/// Materialized prototype dependency graph edges.
@@ -187,8 +189,6 @@ pub enum PrototypeGraphNodeKind {
TextureResource,
/// TEXM lightmap dependency.
LightmapResource,
/// Effect dependency placeholder for later stages.
EffectResource,
/// Non-geometric prototype.
NonGeometric,
}
@@ -273,8 +273,6 @@ pub enum PrototypeGraphEdgeKind {
MaterialToTexture,
/// WEAR table to TEXM lightmap.
WearToLightmap,
/// MAT0 material to effect dependency.
MaterialToEffect,
}
/// Prototype graph edge record.
+56
View File
@@ -1114,6 +1114,50 @@ mod tests {
}
}
#[test]
#[ignore = "requires local testdata corpus"]
fn selected_is_and_is2_missions_preserve_runtime_object_drafts() {
for case in [
("IS", "MISSIONS/Autodemo.00/data.tma"),
("IS2", "MISSIONS/Autodemo.00/data.tma"),
] {
let root = local_testdata_root(case.0);
let vfs: Arc<dyn Vfs> = Arc::new(DirectoryVfs::new(root));
let mut engine = create(
EngineConfig {
mode: EngineMode::Headless,
},
EngineServices::new(vfs),
)
.expect("engine");
let loaded = load_mission(
&mut engine,
MissionRequest {
key: case.1.to_string(),
},
)
.expect("load mission");
let drafts = loaded_mission_object_drafts(&engine).expect("object drafts");
let assets = loaded_mission_assets(&engine).expect("mission assets");
assert_eq!(drafts.len(), loaded.object_count);
assert!(drafts.iter().any(|draft| !draft.visual_ids.is_empty()));
for (index, draft) in drafts.iter().enumerate() {
assert_eq!(
draft.original_id,
u32::try_from(index).ok().map(OriginalObjectId)
);
assert_eq!(draft.visual_ids, assets.visuals_for_object(index));
assert!(draft.position.iter().all(|component| component.is_finite()));
assert!(draft
.orientation_raw
.iter()
.all(|component| component.is_finite()));
assert!(draft.scale.iter().all(|component| component.is_finite()));
}
}
}
#[test]
#[ignore = "requires licensed corpus"]
fn licensed_corpora_load_all_mission_foundations() {
@@ -1326,6 +1370,18 @@ mod tests {
root
}
fn local_testdata_root(name: &str) -> PathBuf {
let root = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../testdata")
.join(name);
assert!(
root.is_dir(),
"local testdata root is missing: {}",
root.display()
);
root
}
#[derive(Clone, Copy)]
enum DenyRule {
Suffix(&'static str),
+5
View File
@@ -13,3 +13,8 @@ Result on 2026-06-23:
typed manifest parsing in `xtask`;
- `rpath`/offline mode is still useful for synthetic local checks;
- full online dependency resolution remains unavailable in the sandbox.
Scope labels:
- Stage 0 macOS/codebase: closed.
- Stage 0 cross-platform native runtime and hosted CI: deferred.
+36 -11
View File
@@ -1,5 +1,7 @@
# Acceptance coverage manifest.
# Format: <acceptance-id>\t<covered|partial|blocked|omitted>\t<evidence>
# Scope note: Stage 0 is closed for the macOS/codebase review scope.
# 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-P1-001 covered cargo test -p fparkan-corpus --offline licensed_part1_manifest_profile_and_counts_match_baseline
L0-P1-002 covered cargo test -p fparkan-corpus --offline licensed_part1_has_no_casefold_relative_path_collisions
@@ -64,6 +66,7 @@ S0-VK-031 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_wi
S0-VK-032 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_created_swapchain
S0-VK-033 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_created_logical_device
S0-VK-034 covered cargo test -p xtask --offline native_smoke_audit_accepts_complete_required_platform_pass native_smoke_audit_rejects_blocked_or_incomplete_reports
S0-VK-035 covered cargo test -p fparkan-render-vulkan --offline final_validation_snapshot_is_captured_after_surface_device_swapchain_drop
S0-LIMIT-001 covered cargo test -p fparkan-binary --offline rejects_count_stride_overflow
S0-LIMIT-002 covered cargo test -p fparkan-binary --offline rejects_oversized_declared_allocation_before_read
L1-P1-NRES-001 covered cargo test -p fparkan-nres --offline licensed_corpora_nres_roundtrip_gates
@@ -204,6 +207,20 @@ S2-GRAPH-003 covered cargo test -p fparkan-assets --offline repository_plan_dedu
S2-GRAPH-004 covered cargo test -p fparkan-prototype --offline graph_report_records_resolved_roots_and_failures
S2-GRAPH-005 covered cargo test -p fparkan-cli --offline prototype_graph_json_has_canonical_field_order
S2-GRAPH-006 covered cargo test -p fparkan-prototype --offline graph_report_records_resolved_roots_and_failures
S2-GRAPH-EDGE-001 covered cargo test -p fparkan-assets --offline graph_materializes_visual_dependency_nodes_and_edges
S2-GRAPH-PROV-001 covered cargo test -p fparkan-assets --offline graph_visual_dependency_edges_preserve_root_and_parent_provenance
S2-GRAPH-IDEMP-001 covered cargo test -p fparkan-assets --offline graph_visual_dependency_expansion_is_idempotent
S2-UNIT-EMPTY-001 covered cargo test -p fparkan-prototype --offline empty_unit_dat_resolves_as_zero_component_root
S2-ASSET-MODEL-001 covered cargo test -p fparkan-assets --offline prepare_single_visual_mission_assets_materialize_model_wear_material_and_texture_payloads
S2-ASSET-WEAR-001 covered cargo test -p fparkan-assets --offline prepare_single_visual_mission_assets_materialize_model_wear_material_and_texture_payloads
S2-ASSET-MATERIAL-001 covered cargo test -p fparkan-assets --offline prepare_single_visual_mission_assets_materialize_model_wear_material_and_texture_payloads
S2-ASSET-TEXM-001 covered cargo test -p fparkan-assets --offline prepare_single_visual_mission_assets_materialize_model_wear_material_and_texture_payloads
S2-ASSET-ID-001 covered cargo test -p fparkan-assets --offline forced_model_id_collision_is_rejected forced_wear_id_collision_is_rejected forced_material_id_collision_is_rejected forced_texture_id_collision_is_rejected
S2-ASSET-LIMIT-001 covered cargo test -p fparkan-assets --offline profiled_asset_preparation_reports_unique_asset_counts asset_preparation_limits_reject_texture_pixel_budget
S2-RUNTIME-DRAFT-001 covered local testdata/IS and testdata/IS2; cargo test -p fparkan-runtime --offline -- --ignored selected_is_and_is2_missions_preserve_runtime_object_drafts
S2-CLI-JSON-001 covered cargo test -p fparkan-cli --offline prototype_graph_json_has_canonical_field_order mission_graph_json_has_canonical_field_order
S2-LICENSED-MISSION-P1-001 covered local testdata/IS; cargo test -p fparkan-runtime --offline -- --ignored selected_is_and_is2_missions_preserve_runtime_object_drafts
S2-LICENSED-MISSION-P2-001 covered local testdata/IS2; cargo test -p fparkan-runtime --offline -- --ignored selected_is_and_is2_missions_preserve_runtime_object_drafts
S2-PROP-001 covered cargo test -p fparkan-prototype --offline generated_acyclic_prototype_graph_resolves_deterministically
S2-FUZZ-001 covered cargo test -p fparkan-prototype --offline arbitrary_unit_and_registry_bytes_are_bounded_and_panic_free
L3-P1-MSH-001 covered cargo test -p fparkan-msh --offline licensed_corpus_msh_assets_validate
@@ -216,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-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-P1-CAPTURE-001 covered cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
L3-P2-CAPTURE-001 covered cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
S2-PLANNING-CAPTURE-P1-001 covered 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
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-003 covered cargo test -p fparkan-material --offline wear_preserves_legacy_id_but_selects_by_index
@@ -268,15 +285,23 @@ S3-MAT-RESOLVE-002 covered cargo test -p fparkan-material --offline resolve_mate
S3-MAT-RESOLVE-003 covered cargo test -p fparkan-material --offline resolve_material_uses_first_entry_only_after_missing_default
S3-MAT-RESOLVE-004 covered cargo test -p fparkan-material --offline resolve_material_empty_texture_means_untextured
S3-MAT-RESOLVE-005 covered cargo test -p fparkan-material --offline resolve_material_without_lightmap_keeps_lightmap_absent
S3-RENDER-001 covered cargo test -p fparkan-render --offline one_snapshot_draw_produces_one_draw_command
S3-RENDER-002 covered cargo test -p fparkan-render --offline material_index_maps_through_resolved_material_slots
S3-RENDER-003 covered cargo test -p fparkan-render --offline node_transform_is_retained
S3-RENDER-004 covered cargo test -p fparkan-render --offline command_order_uses_phase_then_stable_key
S3-RENDER-005 covered cargo test -p fparkan-render --offline command_capture_independent_of_snapshot_construction_order
S3-RENDER-006 covered cargo test -p fparkan-render --offline invalid_range_returns_contextual_error
S3-RENDER-007 covered cargo test -p fparkan-render --offline capture_is_stable
S3-RENDER-008 covered cargo test -p fparkan-render --offline recording_backend_stores_captures
S3-RENDER-009 covered cargo xtask policy
S2-PLANNING-RENDER-001 covered cargo test -p fparkan-render --offline one_snapshot_draw_produces_one_draw_command
S2-PLANNING-RENDER-002 covered cargo test -p fparkan-render --offline material_index_maps_through_resolved_material_slots
S2-PLANNING-RENDER-003 covered cargo test -p fparkan-render --offline node_transform_is_retained
S2-PLANNING-RENDER-004 covered cargo test -p fparkan-render --offline command_order_uses_phase_then_stable_key
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-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-009 covered cargo xtask policy
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-DESCRIPTOR-001 blocked awaits Stage 3 descriptor set contract implementation
S3-VK-PIPELINE-001 blocked awaits Stage 3 graphics pipeline key and cache implementation
S3-VK-DRAW-MODEL-001 blocked awaits Stage 3 real Vulkan indexed model draw path
S3-VK-DRAW-TERRAIN-001 blocked awaits Stage 3 terrain Vulkan draw path
S3-VK-PIXEL-CAPTURE-001 blocked awaits Stage 3 fixed-camera pixel capture approval flow
S3-VK-VALIDATION-001 blocked awaits Stage 3 validation-clean GPU frame execution
S3-GL-001 omitted permanent macOS Desktop GL 3.3 adapter is not implemented; historical CGL probe is retained as external evidence only
S3-GL-002 omitted outside the current macOS-focused goal scope; GLES2 remains documented for portable/non-macOS targets
S3-GL-003 blocked legacy fparkan-render-gl adapter removed while Vulkan renderer path is being brought in as the stage-3 backend
1 # Acceptance coverage manifest.
2 # Format: <acceptance-id>\t<covered|partial|blocked|omitted>\t<evidence>
3 # Scope note: Stage 0 is closed for the macOS/codebase review scope.
4 # Scope note: cross-platform native runtime and hosted CI evidence remain deferred.
5 L0-COPYRIGHT-001
6 L0-P1-001
7 L0-P1-002
66 S0-VK-032
67 S0-VK-033
68 S0-VK-034
69 S0-VK-035
70 S0-LIMIT-001
71 S0-LIMIT-002
72 L1-P1-NRES-001
207 S2-GRAPH-004
208 S2-GRAPH-005
209 S2-GRAPH-006
210 S2-GRAPH-EDGE-001
211 S2-GRAPH-PROV-001
212 S2-GRAPH-IDEMP-001
213 S2-UNIT-EMPTY-001
214 S2-ASSET-MODEL-001
215 S2-ASSET-WEAR-001
216 S2-ASSET-MATERIAL-001
217 S2-ASSET-TEXM-001
218 S2-ASSET-ID-001
219 S2-ASSET-LIMIT-001
220 S2-RUNTIME-DRAFT-001
221 S2-CLI-JSON-001
222 S2-LICENSED-MISSION-P1-001
223 S2-LICENSED-MISSION-P2-001
224 S2-PROP-001
225 S2-FUZZ-001
226 L3-P1-MSH-001
233 L3-P2-WEAR-001
234 L3-P1-ASSET-001
235 L3-P2-ASSET-001
236 L3-P1-CAPTURE-001 S2-PLANNING-CAPTURE-P1-001
237 L3-P2-CAPTURE-001 S2-PLANNING-CAPTURE-P2-001
238 S3-WEAR-001
239 S3-WEAR-002
240 S3-WEAR-003
285 S3-MAT-RESOLVE-003
286 S3-MAT-RESOLVE-004
287 S3-MAT-RESOLVE-005
288 S3-RENDER-001 S2-PLANNING-RENDER-001
289 S3-RENDER-002 S2-PLANNING-RENDER-002
290 S3-RENDER-003 S2-PLANNING-RENDER-003
291 S3-RENDER-004 S2-PLANNING-RENDER-004
292 S3-RENDER-005 S2-PLANNING-RENDER-005
293 S3-RENDER-006 S2-PLANNING-RENDER-006
294 S3-RENDER-007 S2-PLANNING-RENDER-007
295 S3-RENDER-008 S2-PLANNING-RENDER-008
296 S3-RENDER-009 S2-PLANNING-RENDER-009
297 S3-VK-MESH-UPLOAD-001
298 S3-VK-TEXM-UPLOAD-001
299 S3-VK-DESCRIPTOR-001
300 S3-VK-PIPELINE-001
301 S3-VK-DRAW-MODEL-001
302 S3-VK-DRAW-TERRAIN-001
303 S3-VK-PIXEL-CAPTURE-001
304 S3-VK-VALIDATION-001
305 S3-GL-001
306 S3-GL-002
307 S3-GL-003
+34 -11
View File
@@ -64,6 +64,7 @@
`S0-VK-032`
`S0-VK-033`
`S0-VK-034`
`S0-VK-035`
`S0-LIMIT-001`
`S0-LIMIT-002`
`L1-P1-NRES-001`
@@ -191,6 +192,20 @@
`S2-GRAPH-004`
`S2-GRAPH-005`
`S2-GRAPH-006`
`S2-GRAPH-EDGE-001`
`S2-GRAPH-PROV-001`
`S2-GRAPH-IDEMP-001`
`S2-UNIT-EMPTY-001`
`S2-ASSET-MODEL-001`
`S2-ASSET-WEAR-001`
`S2-ASSET-MATERIAL-001`
`S2-ASSET-TEXM-001`
`S2-ASSET-ID-001`
`S2-ASSET-LIMIT-001`
`S2-RUNTIME-DRAFT-001`
`S2-CLI-JSON-001`
`S2-LICENSED-MISSION-P1-001`
`S2-LICENSED-MISSION-P2-001`
`S2-PROP-001`
`S2-FUZZ-001`
`L3-P1-MSH-001`
@@ -203,8 +218,8 @@
`L3-P2-WEAR-001`
`L3-P1-ASSET-001`
`L3-P2-ASSET-001`
`L3-P1-CAPTURE-001`
`L3-P2-CAPTURE-001`
`S2-PLANNING-CAPTURE-P1-001`
`S2-PLANNING-CAPTURE-P2-001`
`S3-WEAR-001`
`S3-WEAR-002`
`S3-WEAR-003`
@@ -255,15 +270,23 @@
`S3-MAT-RESOLVE-003`
`S3-MAT-RESOLVE-004`
`S3-MAT-RESOLVE-005`
`S3-RENDER-001`
`S3-RENDER-002`
`S3-RENDER-003`
`S3-RENDER-004`
`S3-RENDER-005`
`S3-RENDER-006`
`S3-RENDER-007`
`S3-RENDER-008`
`S3-RENDER-009`
`S2-PLANNING-RENDER-001`
`S2-PLANNING-RENDER-002`
`S2-PLANNING-RENDER-003`
`S2-PLANNING-RENDER-004`
`S2-PLANNING-RENDER-005`
`S2-PLANNING-RENDER-006`
`S2-PLANNING-RENDER-007`
`S2-PLANNING-RENDER-008`
`S2-PLANNING-RENDER-009`
`S3-VK-MESH-UPLOAD-001`
`S3-VK-TEXM-UPLOAD-001`
`S3-VK-DESCRIPTOR-001`
`S3-VK-PIPELINE-001`
`S3-VK-DRAW-MODEL-001`
`S3-VK-DRAW-TERRAIN-001`
`S3-VK-PIXEL-CAPTURE-001`
`S3-VK-VALIDATION-001`
`S3-GL-001`
`S3-GL-002`
`S3-GL-003`
+1
View File
@@ -64,5 +64,6 @@
`S0-VK-032`
`S0-VK-033`
`S0-VK-034`
`S0-VK-035`
`S0-LIMIT-001`
`S0-LIMIT-002`