Checkpoint 4: harden native paths, authoring workflows and Player lifecycle
This commit is contained in:
@@ -57,6 +57,8 @@ Scene compiler переводит авторские данные в runtime и
|
||||
|
||||
Retained UI получает состояние и уведомления от AuthoringService; состояние виджетов не заменяет состояние документа. Стили/layout отделены от команд; ключевые действия доступны из интерфейса и через editor API. Импорт, компиляция и cook не блокируют event loop. Необходимые текстовый ввод, focus, clipboard, DPI и платформенные поведения проверяются на обеих ОС как часть UI, а не считаются автоматически решёнными SDL3.
|
||||
|
||||
**UI-референс не является источником истины.** Сгенерированные изображения задают визуальное направление: тёмные поверхности, плотность, типографику и иерархию. Состав функций, состояние документов и поведение определяют эти контракты, PLAN и проверенные пользовательские сценарии. Референс можно менять под рабочий функционал.
|
||||
|
||||
## 6. Runtime ECS, поведение и игровой цикл — принято
|
||||
|
||||
EnTT используется для компонентов и запросов за типизированным API Faset. Простое поведение и массовая система обращаются к одному состоянию. Собственная ECS не разрабатывается на первом этапе; выбор EnTT не обещает большей скорости или дешёвой замены backend. Системы объявляют фазу, чтение/запись компонентов и внешних ресурсов, зависимости и диагностическое имя.
|
||||
@@ -99,7 +101,7 @@ Development и release Player содержат runtime, выбранные иг
|
||||
|
||||
Первый путь доставки — самостоятельный каталог/архив игры и отдельно symbols. Windows и Linux собираются и проверяются собственными native workers. Clang/clang-cl не устраняют необходимость платформенных SDK/runtime; кросс-экспорт из Linux в Windows не считается готовой возможностью. Полностью побайтово воспроизводимый executable и стабильный ABI любых компиляторов не обещаются наличием build manifest.
|
||||
|
||||
Критерии [плана](../PLAN.md) включают цикл сцена → Inspector → MCP authoring edit → Undo → save → build → отдельный Player, повторный импорт GLB с сохранением overrides, lifecycle/handle tests и запуск на обеих ОС без Editor/Blender/MCP/SDK. Эти проверки предстоит реализовать и выполнить.
|
||||
Критерии [плана](../PLAN.md) включают цикл сцена → Inspector → MCP authoring edit → Undo → save → build → отдельный Player, повторный импорт GLB с сохранением overrides, lifecycle/handle tests и запуск на обеих ОС без Editor/Blender/MCP/SDK. Выполненные проверки и незакрытые условия перечислены в [журнале реализации](IMPLEMENTATION.md); наличие теста само по себе не означает прохождения на обеих ОС.
|
||||
|
||||
## История решений
|
||||
|
||||
|
||||
@@ -141,3 +141,68 @@ building its pinned software driver. A review also identified Windows Unicode pa
|
||||
boundaries that must be corrected before cross-platform acceptance. Clean offline
|
||||
build verification, final performance baselines and the final acceptance record
|
||||
remain open; no MVP tag has been created.
|
||||
|
||||
### Checks after checkpoint 3
|
||||
|
||||
- Public commit: `d834cfad67cd81d8c4998b90c16791361ca8c0f8`.
|
||||
- Linux and Windows headless CI plus strict manual passed in GitHub run
|
||||
[35295534027](https://github.com/emil28092005/Faset_Engine/actions/runs/35295534027).
|
||||
- A clean committed source snapshot built all native targets with external networking
|
||||
disabled; all 19 CPU tests passed. The recorded build/test phase took 174.03 s.
|
||||
[Offline evidence](validation/offline-linux-2026-09-18.json) distinguishes prepared
|
||||
system tools from source/dependency inputs. GPU/window checks remain separate.
|
||||
- The first full Windows graphics job compiled the whole Editor successfully, then
|
||||
failed creating a Vulkan instance with its CI software driver. Its CPU SceneView
|
||||
test also reported a texture-loading error. These are acceptance failures under
|
||||
investigation, not verified Windows graphics/export support.
|
||||
|
||||
## Checkpoint 4 — portability and acceptance hardening
|
||||
|
||||
Implemented after concrete regression findings:
|
||||
|
||||
- UTF-8 project, resource, plugin, CLI and subprocess boundaries. Windows native paths
|
||||
stay wide internally; Editor/Player/SchemaExporter normalize `wmain` arguments.
|
||||
File reads, hashes and atomic writes use extended native paths. All Faset Windows
|
||||
executables declare long-path support; CI enables the documented developer policy.
|
||||
- Normal Stop requests Player shutdown before bounded termination fallback. Real
|
||||
`onDestroy` execution was observed, and a dedicated Player fixture verifies that
|
||||
callback diagnostics also reach logs during shutdown. Custom component versions
|
||||
are checked against the linked gameplay schema, including data-only components.
|
||||
- POSIX subprocess cleanup keeps the exited leader's PID reserved while terminating
|
||||
its owned process group, then reaps it. A regression verifies that a descendant
|
||||
ignoring SIGTERM cannot survive normal leader exit or cancellation, without losing
|
||||
the leader's stdout tail or signaling a reused process-group ID.
|
||||
- Transparent sprites use stable layer/depth ordering without depth writes, avoiding
|
||||
invisible sprites hiding objects behind them. GPU regressions cover alpha layering,
|
||||
shader/capture paths longer than 300 characters, and window capture after resize.
|
||||
- Editor/launcher DPI scaling, logical-unit layout persistence and safe cancellation
|
||||
of unfinished drags on scale changes. Retained UI tests cover 1×/2× text rasterization,
|
||||
clipping, hit testing and text-input rectangles.
|
||||
- Manual import-removal review with exact IDs/names and explicit acceptance. Both the
|
||||
reviewed candidate and active generation are checked before publishing, so stale
|
||||
confirmation cannot apply a different import. The GUI regression exercises rejection,
|
||||
fresh review and successful acceptance through actual widget events.
|
||||
- Extended template workflow now saves through UI controls and opens a new Session,
|
||||
comparing IDs, nested origins, local additions and resolved values.
|
||||
- Blender verification now updates two instances in one live Editor/SceneView, preserves
|
||||
placement, tint, physics and opaque gameplay fields, and retains both visible meshes
|
||||
after a removal conflict. [Blender evidence](validation/blender-live-linux-2026-09-18.json).
|
||||
|
||||
Observed Linux integration: **32 passed, 1 skipped, 0 failed** in the 33-test suite.
|
||||
The skip is native Wayland programmatic restore, which the compositor declined;
|
||||
the same lifecycle scenario passed under XWayland. ASan/UBSan passed **17/17** tests.
|
||||
Strict MkDocs passed. [Recovery evidence](validation/editor-recovery-linux-2026-09-18.json)
|
||||
records actual Editor termination and failed save/import/build/Player scenarios.
|
||||
[Release baseline](validation/linux-release-2026-09-18/README.md) records the two
|
||||
relocated Unicode-path packages and 240-frame profiles with their scope and hashes.
|
||||
|
||||
Windows execution of these fixes remains a separate gate. The previous fast CPU run
|
||||
isolated a 264-character cooked path failure; the new native-path fixes must pass on
|
||||
Windows before that issue is considered closed there. Native OS IME composition and
|
||||
moving between physical monitors still have less coverage than deterministic widget
|
||||
and platform-boundary tests. No MVP tag has been created.
|
||||
|
||||
The final build-service review also reproduced a publication defect: an invalid
|
||||
custom-field default can pass the build stage's shallow schema check before the
|
||||
Editor rejects it. Full schema validation before publishing `last_build.json` is the
|
||||
next bounded correction; checkpoint 4 does not claim this gate is already complete.
|
||||
|
||||
@@ -28,6 +28,14 @@ MSVC-family builds use the dynamic CRT: `/MDd` in Debug, `/MD` otherwise. Physic
|
||||
Player, Editor and native plugins use compatible settings. Development and export
|
||||
have separate CMake directories, avoiding accidental Debug/Release mixing.
|
||||
|
||||
Windows developer machines use the **Enable Win32 long paths** policy
|
||||
(`LongPathsEnabled=1`). Faset executables carry `longPathAware` manifests. Engine
|
||||
stream/hash/atomic-file boundaries also use wide extended paths, while serialized
|
||||
project paths remain ordinary UTF-8. This does not change the independent path
|
||||
support of CMake, Ninja, the compiler or Slang. CI records/enables the same host
|
||||
profile; the build guide explains setup. A temporary path longer than 260 characters
|
||||
exposed the original SceneView failure and now has dedicated regression coverage.
|
||||
|
||||
## Graphics profiles
|
||||
|
||||
The baseline requires Vulkan 1.3 with dynamic rendering and synchronization2, a
|
||||
@@ -69,3 +77,9 @@ and graphics driver; they do not need this development toolchain.
|
||||
An offline build is recorded only after a clean build directory is configured and
|
||||
built with network access disabled. A warm incremental build or archive checksum
|
||||
verification alone is not that acceptance check.
|
||||
|
||||
Commit `d834cfad67cd81d8c4998b90c16791361ca8c0f8` passed this check on Linux: full
|
||||
native build and 19 CPU tests in a new user/network namespace with no external
|
||||
connectivity, using a `git archive` checkout and only prefetched inputs. See
|
||||
[`validation/offline-linux-2026-09-18.json`](validation/offline-linux-2026-09-18.json).
|
||||
Reproduce using `python3 tools/verify_offline_build.py --output .cache/offline-check`.
|
||||
|
||||
@@ -74,9 +74,17 @@ mesh datablocks remain shared. Repair deliberately duplicated material IDs in
|
||||
Blender's Custom Properties. Save the `.blend` again.
|
||||
|
||||
Removing an exported output produces an import conflict. Faset keeps the old
|
||||
generation active. Inspect the diagnostics and update affected references before
|
||||
explicitly importing with `allow_removed_outputs: true`. This accepts removal;
|
||||
it does not automatically remap references. A normal GLB without persistent custom
|
||||
generation active. In **Jobs**, choose **Review removals** to open **Conflicts**.
|
||||
Review the removed stable IDs and their last-good names; **Copy removed IDs** helps
|
||||
locate references. Update affected references, then use **Accept reviewed removal**.
|
||||
If source data or the active generation has changed since review, the acceptance
|
||||
fails safely; use **Reimport / review again** and inspect the new result.
|
||||
|
||||
The same explicit API action uses `allow_removed_outputs: true`, with
|
||||
`expected_generation` and `expected_active_generation` taken from the reviewed
|
||||
job's `result.generation` and `result.previous_generation`. Use the same source and
|
||||
settings. This accepts removal; it does not automatically remap references or delete
|
||||
scene components. A normal GLB without persistent custom
|
||||
IDs uses structural matching, which cannot guarantee identity after rename or
|
||||
restructuring.
|
||||
|
||||
@@ -118,3 +126,7 @@ For an end-to-end example, open `examples/projects/collect-3d`. Its exit arch in
|
||||
a `.blend`, reproducible Blender script and a published bundle. The repository's
|
||||
`tools/verify_blender_roundtrip.py` runs the actual Blender helper and Editor imports
|
||||
to check rename, geometry changes, removal conflicts and failure preservation.
|
||||
Pass `--ui-probe build/linux-debug/faset_blender_editor_probe` to also test two
|
||||
instances in one live editor session: both receive new geometry while preserving
|
||||
placement, tint, opaque gameplay fields and the authoring revision. This additional
|
||||
probe requires Vulkan and produces before/after captures.
|
||||
|
||||
@@ -80,9 +80,12 @@ and package execution tests; that is separate from physical GPU-driver testing.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Unknown component or schema version:** enable/register the missing runtime module
|
||||
and rebuild. The Editor preserves its data as opaque authoring fields, but export
|
||||
requires a matching runtime implementation.
|
||||
**Unknown component:** enable/register the missing runtime module and rebuild. A
|
||||
data-only custom component still needs a schema; it does not need callbacks.
|
||||
|
||||
**Schema version mismatch:** match the linked gameplay schema to the document or
|
||||
apply an explicit data migration, then rebuild. The Editor preserves future or
|
||||
missing component data as opaque fields; export requires a matching schema.
|
||||
|
||||
**Missing asset:** import the original source or Blender manifest again. Preserve its
|
||||
sidecar so the AssetId remains stable. A cache copied from another project is not a
|
||||
|
||||
@@ -23,8 +23,9 @@ resolution, validation activation, fixed ticks and timestep. A bounded run advan
|
||||
one synthetic fixed timestep per frame; it does not reproduce a real-time input
|
||||
session. Keep that distinction when comparing runs.
|
||||
|
||||
Startup starts at `main()` and ends at the first completed frame. OS process loading
|
||||
before `main()` is excluded. Frame wall times exclude writing the final profile and
|
||||
Startup starts at the Player application entry after platform argument normalization
|
||||
and ends at the first completed frame. OS process loading and Windows `wmain` UTF-8
|
||||
argument conversion are excluded. Frame wall times exclude writing the final profile and
|
||||
capture files. Simulation and scene-snapshot times are separate from the renderer
|
||||
call. Renderer CPU wall duration includes GPU waits and readback; it is **not CPU
|
||||
utilization**. GPU timestamps measure the submitted graphics work and can be null
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
# Editor workspace
|
||||
|
||||
The Editor follows the window's display scale. Text is rasterized at that scale;
|
||||
panel dimensions are saved in logical units so the layout remains usable when
|
||||
moving between displays. A scale change preserves focused text and cancels an
|
||||
unfinished numeric, divider or gizmo drag without committing an edit.
|
||||
|
||||
The Editor edits saved scene data and previews it in a Vulkan viewport. **Play**
|
||||
opens a separate Player process. Gameplay movement and spawned objects stay in that
|
||||
process; stopping it leaves the authoring scene unchanged.
|
||||
|
||||
@@ -67,6 +67,21 @@ Use an x64 Visual Studio Developer shell with the Windows SDK, MSVC runtime libr
|
||||
LLVM `clang-cl`, Ninja, CMake, and the Vulkan SDK available. Then use the
|
||||
`windows-debug` or `windows-release` presets.
|
||||
|
||||
Enable **Win32 long paths** on the Windows development machine before starting the
|
||||
build shell. Faset's executable manifest declares long-path support, and its direct
|
||||
file IO uses wide extended paths; external CMake/Ninja/compiler tools also need a
|
||||
compatible host policy for deeply nested build/cache directories. An administrator
|
||||
can enable the policy once in PowerShell:
|
||||
|
||||
```powershell
|
||||
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' `
|
||||
-Name LongPathsEnabled -Value 1 -PropertyType DWORD -Force
|
||||
```
|
||||
|
||||
Open a new build shell afterwards; Windows may require a restart for existing
|
||||
processes. See Microsoft's [long-path requirements](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation).
|
||||
Windows CI enables and records this developer profile explicitly.
|
||||
|
||||
```powershell
|
||||
py tools/fetch_slang.py
|
||||
cmake --preset windows-debug
|
||||
|
||||
@@ -4,7 +4,7 @@ Include `<faset/runtime/Runtime.hpp>` and use namespace `faset::runtime`. This i
|
||||
|
||||
## Register behavior
|
||||
|
||||
`void Runtime::registerBehavior(std::string componentType, Behavior behavior)` registers callbacks before scene loading. An empty or duplicate type, registration during a callback, and registration after entities have loaded are rejected.
|
||||
`void Runtime::registerBehavior(std::string componentType, Behavior behavior)` registers callbacks before scene loading. An empty or duplicate type and registration while entities are present or a callback is running are rejected. An empty or cleared world can register additional types.
|
||||
|
||||
`Behavior::Callback` is `std::function<void(Runtime&, EntityHandle, double)>`. Assign it to any of `onStart`, `fixedUpdate`, `update`, `lateUpdate`, and `onDestroy`. Unassigned members do nothing. `Behavior::onCollision` instead accepts `(Runtime&, EntityHandle, const CollisionEvent&)`.
|
||||
|
||||
@@ -63,6 +63,13 @@ Immediate validation errors throw. Deferred failures are recorded in diagnostics
|
||||
|
||||
`Runtime(RuntimeConfig = {})` constructs the controller. `load(const nlohmann::json&)` validates and prepares a scene, creates its entities, then calls initial callbacks. Invalid scene data leaves the preceding world intact. `clear()` destroys the current entities and invalidates their session handles.
|
||||
|
||||
Direct callers can include `<faset/runtime/schema.hpp>` and call
|
||||
`validate_scene_schemas(scene, gameplaySchema)` before `load`. The Player does this
|
||||
automatically: each custom TypeId/version must match its linked schema. Generic
|
||||
`Runtime` accepts opaque custom data with positive versions, including data-only
|
||||
components; built-ins use version 1. This helper verifies identity/version, without
|
||||
automatic migrations or authoring-style custom-field constraint validation.
|
||||
|
||||
`FrameStats advance(double elapsedSeconds, InputState = {})` advances fixed ticks, frame callbacks, interpolation, and late callbacks. `singleStep(InputState = {})` advances one fixed tick. `setPaused(bool)` clears accumulated time and resets presentation history; `paused()` reports this local state. Do not call load/clear/advance recursively from a callback.
|
||||
|
||||
`RuntimeConfig` defaults to `fixedDelta = 1.0 / 60.0`, `maxCatchUpTicks = 4`, `physicsSubsteps = 4`, and `gravity = {0, -9.81f, 0}`. `FrameStats` reports fixed ticks performed, dropped time, interpolation fraction, and total tick count.
|
||||
|
||||
@@ -42,7 +42,7 @@ Read the callback from top to bottom:
|
||||
4. `transform` gives a pose copy. Multiplying metres per second by seconds gives a displacement in metres.
|
||||
5. `setTransform` publishes the changed non-physical pose.
|
||||
|
||||
The `[](...) { ... }` expression is a C++ lambda: a function stored in `Behavior::update`. Empty brackets mean it captures no local variables. `registerBehavior` takes ownership of the callback object. Register before calling `load`; registration after a world has loaded is rejected.
|
||||
The `[](...) { ... }` expression is a C++ lambda: a function stored in `Behavior::update`. Empty brackets mean it captures no local variables. `registerBehavior` takes ownership of the callback object. Register before calling `load`; registration while entities exist or a callback is running is rejected.
|
||||
|
||||
The `schema()` function describes editable configuration. It does not create a runtime object. `tutorial.move_x` is the stable `TypeId`; `speed` is a stable `FieldId` within that type. Keep these IDs when changing a display label. Changing a field's meaning or units needs an explicit data migration, not just a new label.
|
||||
|
||||
@@ -56,7 +56,10 @@ The example scene is a complete, loadable document:
|
||||
|
||||
The sprite is visible because it has `faset.sprite`. It moves because it also has `tutorial.move_x`. The configuration field is `speed`; the type string must match the registration exactly. `rotation` uses radians, and the default coordinate system is Y-up.
|
||||
|
||||
After your project's schema is exported and loaded by the Editor, the type can be described through the same authoring schema used by the Inspector. The direct Player command above is useful before building an Editor workflow around your component.
|
||||
After **Build C++** succeeds in the Editor, choose **Add component** in the Inspector
|
||||
and select the registered type. Its schema supplies editable fields, defaults and
|
||||
constraints. The direct Player command above is useful for testing the same behavior
|
||||
independently of an editor session.
|
||||
|
||||
## Make a change and verify it
|
||||
|
||||
|
||||
@@ -23,6 +23,13 @@ A gameplay directory contains `Gameplay.hpp` and `Gameplay.cpp`. It provides two
|
||||
|
||||
The Player calls registration before loading a scene. The separate SchemaExporter calls `schema()` without creating a game world or running gameplay callbacks. The Editor reads the resulting declaration; it does not load the gameplay binary into the Editor process.
|
||||
|
||||
Every custom component in a played scene must have a matching TypeId and exact
|
||||
positive version in the linked gameplay `schema()`. The Player checks this before
|
||||
loading the world, including `--validate`. A data-only custom component still needs
|
||||
a schema, even when it registers no callbacks. Built-in TypeIds are reserved. The
|
||||
Editor preserves missing or future component data for recovery, but the Player
|
||||
rejects it until the corresponding module/schema is available or the data is migrated.
|
||||
|
||||
A scene object receives a behavior by containing a component whose `type` matches the string passed to `registerBehavior`. Registering a behavior does not attach it to every object. A component can contain data without having any callbacks.
|
||||
|
||||
## Data, poses, and state
|
||||
|
||||
@@ -10,6 +10,12 @@ Each ordinary callback receives `(Runtime& game, EntityHandle self, double delta
|
||||
|
||||
`onDestroy` runs while that object's handle and allowed component data are still valid. Clean up subscriptions or external C++ state there. After removal, `valid(oldHandle)` returns false. Removing a behavior component also runs that component's `onDestroy`. Clearing or replacing a scene runs destruction callbacks; a new scene uses a new session identity.
|
||||
|
||||
Normal Player shutdown and the Editor's **Stop** request also run destruction callbacks.
|
||||
Stop gives the Player a bounded grace period to finish. An unresponsive native callback
|
||||
can force the Editor to terminate the process; no application can guarantee cleanup
|
||||
callbacks after forced termination or a crash. Such fallback is reported in Console.
|
||||
Exceptions caught from callbacks, including shutdown callbacks, appear in Player logs.
|
||||
|
||||
Registering a callback does not make captured pointers safe. A lambda that stores a reference to a stack variable in `registerGameplay` will outlive that variable. The [timed-despawn example](examples.md#spawn-and-destroy-on-safe-boundaries) uses shared ownership for captured state and removes each object's entry on destruction.
|
||||
|
||||
## One fixed tick
|
||||
@@ -58,4 +64,4 @@ The Player reads this optional object from the scene document. The settings are
|
||||
}
|
||||
```
|
||||
|
||||
This is an excerpt, not a complete scene. The tutorial scenes contain complete examples. `fixed_delta` is seconds, gravity is metres per second squared, and substeps are solver subdivisions inside one fixed tick. These do not create additional gameplay callbacks. Invalid configuration is rejected before the Player starts. Editing these JSON settings is implemented; an Editor settings panel should only be relied on where the current UI exposes it.
|
||||
This is an excerpt, not a complete scene. The tutorial scenes contain complete examples. `fixed_delta` is seconds, gravity is metres per second squared, and substeps are solver subdivisions inside one fixed tick. These do not create additional gameplay callbacks. Invalid configuration is rejected before the Player starts. The Editor's **Simulation** dialog edits these scene settings through normal Undo transactions; **Project settings** edits the project's name, dimension and start scene separately.
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Validation evidence
|
||||
|
||||
These files preserve bounded checks and their inputs. Each record states its source revision or working-tree limitation; a passing record does not certify later commits or every supported platform.
|
||||
|
||||
- [Linux offline build](offline-linux-2026-09-18.json): a fresh build from committed `d834cfad67cd81d8c4998b90c16791361ca8c0f8`, prefetched dependency inputs, and a network namespace without external connectivity. CPU tests ran; graphics execution is separate.
|
||||
- [Linux Release export and rendering](linux-release-2026-09-18/README.md): two relocated playable games, Unicode paths, imported Blender geometry, raw frame profiles and exact package hashes. This measurement used an evolving working tree around `5ac4db4`, not a clean checkout of the current commit.
|
||||
- [Live Blender reimport](blender-live-linux-2026-09-18.json): actual Blender 4.5.3 exports and two live Editor instances, preserving authoring/gameplay/physics while refreshing geometry.
|
||||
- [Editor recovery](editor-recovery-linux-2026-09-18.json): killed Editor, explicit journal recovery, failed save/import/build and failed Player startup with last-good preservation.
|
||||
- [Native window boundaries](native-window-linux-2026-09-18.json): XWayland lifecycle, isolated Unicode clipboard, SDL text-input rectangles and the explicit native Wayland restore limitation.
|
||||
- [Linux native window and input boundaries](native-window-linux-2026-09-18.json): XWayland resize/minimize/restore and SDL text-input-area checks; isolated Xvfb Unicode clipboard roundtrip with restoration. Native Wayland restore remains unconfirmed; real OS IME composition was not tested.
|
||||
|
||||
The Linux records do not establish Windows correctness, physical Windows GPU performance, native Wayland restore support, or editor responsiveness under large workloads. Windows CI artifacts record their own commit and software Vulkan results. A skipped compositor operation is not a completed acceptance check.
|
||||
|
||||
Performance budgets below are proposals for P1 regression tracking, not completed release requirements. Repeat measurements on a controlled reference host and add representative content before treating them as engine-wide targets.
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"blender": "Blender 4.5.3 LTS",
|
||||
"asset_id": "54c039e4-c19f-4365-a9f8-a38416ec6e3f",
|
||||
"initial_generation": "499f254ce440ecb86118f2f6803f21013e763d35cfdba1c4356be7a457eec718",
|
||||
"renamed_generation": "963e996b59ba11c2f9dd9eba51b89e7ae3f3dce6f177e4adaf5682479cb204a8",
|
||||
"stable_output_ids": true,
|
||||
"removed_output_conflict": true,
|
||||
"failed_import_keeps_generation": true,
|
||||
"authoring_preserved": true,
|
||||
"live_editor": {
|
||||
"conflict_keeps_visible_generation": true,
|
||||
"instances": 2,
|
||||
"live_geometry_updated": true,
|
||||
"opaque_gameplay_preserved": true,
|
||||
"physics_fields_preserved": true,
|
||||
"placement_and_tint_preserved": true,
|
||||
"status": "passed",
|
||||
"validation_enabled": true,
|
||||
"validation_errors": 0
|
||||
},
|
||||
"source_context": "Shared Linux checkpoint 4 working tree around 5ac4db4; not a clean-commit result",
|
||||
"reproduce": "python3 tools/verify_blender_roundtrip.py --blender PATH --editor build/linux-debug/faset_editor --ui-probe build/linux-debug/faset_blender_editor_probe --output NEW_DIRECTORY"
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"format": "faset.editor-recovery-verification",
|
||||
"version": 1,
|
||||
"status": "passed",
|
||||
"checks": [
|
||||
"acknowledged unsaved edit survives killed Editor and explicit recovery",
|
||||
"failed save preserves live authoring and last saved file",
|
||||
"failed Player process is reported without changing authoring data",
|
||||
"Undo repairs the scene, then Play and Stop leave authoring unchanged",
|
||||
"failed C++ build keeps prior schema and reports stale status",
|
||||
"fixed C++ rebuild restores current schema status",
|
||||
"failed import preserves authoring"
|
||||
],
|
||||
"logs": [
|
||||
"build completed",
|
||||
"Gameplay schema loaded",
|
||||
"Play started in a separate Player process",
|
||||
"Player failed: unsupported component version\n",
|
||||
"Player exited with code 1",
|
||||
"build completed",
|
||||
"Gameplay schema loaded",
|
||||
"Play started in a separate Player process",
|
||||
"New round: collect the three gold cubes, then reach the green exit. E resets.\n{\"device\":\"NVIDIA GeForce RTX 2080 Ti\",\"dimension\":2,\"frames\":382,\"ticks\":103,\"validation_errors\":0}\n",
|
||||
"Play stopped; authoring scene unchanged",
|
||||
"build failed: Process exited with code 1; see job log; previous gameplay metadata remains available and is marked stale",
|
||||
"build completed",
|
||||
"Gameplay schema loaded",
|
||||
"Asset import failed: Cannot read: /home/emil/Desktop/Faset_Engine/.cache/recovery-checkpoint3-v3/project/Assets/missing.glb\n"
|
||||
],
|
||||
"engine_revision": "d834cfad67cd81d8c4998b90c16791361ca8c0f8",
|
||||
"execution_context": "Linux development desktop; Editor and source from the clean offline checkout; disposable sample project",
|
||||
"scope": "Crash recovery and last-good preservation. Graceful OnDestroy is verified separately by the later Player shutdown regression."
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
# Linux Release export baseline — 2026-09-18
|
||||
|
||||
Both checked-in playable projects passed real Editor export, standalone CPU validation and 120 offscreen frames after relocation. Their disposable source-project paths were hidden during launch; no `--scene` or `--assets` override was supplied. Copied project and executable paths contain `Faset Café 世界`. The 3D export includes the Blender exit-arch asset.
|
||||
|
||||
This is a measurement of the shared working tree around `5ac4db438dae5ee28e5619e62cf8d6647beecd52` plus in-progress checkpoint 4 changes. It is **not an exact clean-commit result**. The two Release generations are `48ec8546-3750-463f-9c4c-f76c3b933256` (2D) and `17281e17-9f4f-44f0-8821-6e0071e9a45b` (3D). [Evidence](evidence.json) retains project input hashes and build fingerprints; [2D](collect-2d-manifest.json) and [3D](collect-3d-manifest.json) manifests retain the exact executable, cooked data and shader hashes.
|
||||
|
||||
The same relocated executables then recorded 240 frames each, sequentially, without physics debug drawing or player input. Hardware: Ryzen 7 1700, 32 GiB RAM, RTX 2080 Ti 11 GiB, NVIDIA 595.84; Ubuntu 26.04, kernel 7.0.0-31. Build: Clang 21.1.8, Release `-O3 -DNDEBUG`, Vulkan 1.3, 1280×720, actual Khronos validation enabled. Both runs had zero validation errors. The desktop remained active; this was not an isolated benchmark machine.
|
||||
|
||||
Raw [2D](collect-2d-profile-240.json) and [3D](collect-3d-profile-240.json) profiles include every completed frame, including the first, with nearest-rank percentiles. Times below are p50 / p95 milliseconds:
|
||||
|
||||
- 2D: total measured frame 2.234 / 2.684; renderer call 1.865 / 2.221; GPU 0.565 / 0.579; readback 0.510 / 0.633; simulation 0.201 / 0.258; snapshot 0.170 / 0.215.
|
||||
- 3D: total measured frame 2.299 / 2.732; renderer call 1.884 / 2.180; GPU 0.588 / 0.600; readback 0.469 / 0.608; simulation 0.213 / 0.300; snapshot 0.181 / 0.257.
|
||||
|
||||
Live Vulkan allocations stayed at 15,750,288 bytes (2D) and 15,787,008 bytes (3D), about 15.02 and 15.06 MiB. Counts were 11 / 31 draws, 66 / 576 packed vertices per frame, and one fallback texture. A packed mesh can be drawn again for its shadow pass. These memory totals include aligned explicit allocations and exclude driver internals. First-frame startup from `main()` was 265.5 / 260.8 ms; OS loader time is excluded.
|
||||
|
||||
`render_call` includes GPU waits and synchronous readback; it is not CPU utilization. GPU timestamps cover submitted rendering. Frame timings exclude profile bookkeeping and final file writes. Synthetic 1/60-second simulation ticks run as fast as the offscreen loop allows. The resulting numbers are not display FPS or a real-time gameplay pacing test. Small sample scenes, one GPU, 240 frames and a static camera cannot establish scalability, a memory-leak guarantee, or broad performance claims. The imported 3D material also emits the recorded warning about unsupported material features in its manifest.
|
||||
|
||||
Proposed P1 budgets for these exact scenes on this reference-class Linux host, at the same resolution and validation/readback settings:
|
||||
|
||||
- Measured frame p95 ≤ 4 ms; GPU p95 ≤ 1 ms; readback p95 ≤ 1 ms.
|
||||
- Simulation and snapshot p95 ≤ 0.5 ms each.
|
||||
- Explicit live Vulkan memory ≤ 20 MiB, with no growth after warmup over a future 3,000-frame resource-lifecycle run.
|
||||
- Startup from `main()` ≤ 500 ms for these tiny packages.
|
||||
|
||||
These initial thresholds leave headroom above the observed values. They are **proposed**, not enforced acceptance criteria. P1 should retain cold-start results separately, run repeated sessions, measure editor input latency and larger content, and collect independent Windows hardware baselines before adopting release gates.
|
||||
|
||||
Reproduce export validation from the repository with `python tools/verify_playable_exports.py --editor build/linux-debug/faset_editor --output <new-empty-directory>`. Run each retained standalone Player with `--headless --frames 240 --profile <output.json>` to repeat the longer measurement. A new run builds current sources and produces new immutable generations; use the stored hashes to distinguish it from this record.
|
||||
|
||||
Captured 120-frame outputs:
|
||||
|
||||

|
||||
|
||||

|
||||
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"asset_generations": {},
|
||||
"build_fingerprint": "5b1996b0fe44eeaa01ee1fd581f9f063f8c84147128e896541d27207dbab9aaa",
|
||||
"configuration": "Release",
|
||||
"executable": "faset_player",
|
||||
"files": [
|
||||
{
|
||||
"path": "scene.fscene",
|
||||
"sha256": "811242b85ede88c6d7920eeda5b7f6ae189db4d9e17d568cdfd230f27ce629b6",
|
||||
"size": 6496
|
||||
},
|
||||
{
|
||||
"path": "faset_player",
|
||||
"sha256": "ef12daa3a1e71ef9e9d933cfa0347249de86b5e8da3536e709a3899a731e4333",
|
||||
"size": 5809704
|
||||
},
|
||||
{
|
||||
"path": "shaders/vertexMain.spv",
|
||||
"sha256": "1ad2631c35d654f48166321ae43d4165043e1b919b14f1dc61caf97b1ada0898",
|
||||
"size": 1224
|
||||
},
|
||||
{
|
||||
"path": "shaders/fragmentMain.spv",
|
||||
"sha256": "f5c4f289917ecab5d00d543c053aac1d10e6cca311fd172daf06d315160a3505",
|
||||
"size": 7436
|
||||
},
|
||||
{
|
||||
"path": "shaders/shadowMain.spv",
|
||||
"sha256": "7643b4d688492b5ee923b9606f0b0e70343ca05fa67673838206119a6f86d8d8",
|
||||
"size": 784
|
||||
},
|
||||
{
|
||||
"path": "shaders/vertexMain.reflection.json",
|
||||
"sha256": "c584f3b957ebf194a292451362a98590f85ff3cfbfd8f917b1c1265039381777",
|
||||
"size": 2639
|
||||
},
|
||||
{
|
||||
"path": "shaders/fragmentMain.reflection.json",
|
||||
"sha256": "72ebf8d32452830650416dc4717d89a4324e97ece7028dfb97c66803c8dce71f",
|
||||
"size": 2649
|
||||
},
|
||||
{
|
||||
"path": "shaders/shadowMain.reflection.json",
|
||||
"sha256": "e3fd0889cd2f569d410f5d7558a4091d9f57f247a1dcf1788462f67525340819",
|
||||
"size": 2645
|
||||
},
|
||||
{
|
||||
"path": "Notices/sdl3/LICENSE.txt",
|
||||
"sha256": "97f35b302b361680ec1e891e95d2d52097bb95abff361434916d99dc1305f127",
|
||||
"size": 884
|
||||
},
|
||||
{
|
||||
"path": "Notices/entt/LICENSE",
|
||||
"sha256": "0785027ce472d7c61f05fba664a1d3ba6639c1593ced351ad9e4bed868765d99",
|
||||
"size": 1097
|
||||
},
|
||||
{
|
||||
"path": "Notices/box2d/LICENSE",
|
||||
"sha256": "68a3e676d7e94093b102d5cba0d4e04af812040d6f230c3db67a6664574e43d2",
|
||||
"size": 1067
|
||||
},
|
||||
{
|
||||
"path": "Notices/box3d/LICENSE",
|
||||
"sha256": "da5e31a26bf3cfd5ba5c96d6823e480128c81e76c107ef9d3ee5d94789184b90",
|
||||
"size": 1067
|
||||
},
|
||||
{
|
||||
"path": "Notices/json/LICENSE.MIT",
|
||||
"sha256": "46a65cffd1ea955132d95a8dd921640714a8d6b537d2e4e482d31145ae95b603",
|
||||
"size": 1076
|
||||
},
|
||||
{
|
||||
"path": "Notices/stb/LICENSE",
|
||||
"sha256": "bebfe904b14301657e4e5d655c811d51fd31b97c455b9cc2d8600d6bac6cff63",
|
||||
"size": 2510
|
||||
},
|
||||
{
|
||||
"path": "Notices/dependencies.json",
|
||||
"sha256": "a54639ad2d9ad13c2e5f1ec90d6775f5dfc493656789b78c7e44debe2a378fdc",
|
||||
"size": 2206
|
||||
},
|
||||
{
|
||||
"path": "Notices/Faset-NOTICE.txt",
|
||||
"sha256": "30c2e7e80f5153b31ab57675e07246aef9165965d64e36022b426a26449ece3f",
|
||||
"size": 204
|
||||
},
|
||||
{
|
||||
"path": "README.txt",
|
||||
"sha256": "4dc2f0271c69fe39017ff96aa2dfa00b625bec1401d924dc396193ce71c09f3e",
|
||||
"size": 225
|
||||
}
|
||||
],
|
||||
"format": "faset.export",
|
||||
"generation": "48ec8546-3750-463f-9c4c-f76c3b933256",
|
||||
"platform": "linux",
|
||||
"prerequisites": [
|
||||
"Linux x86_64",
|
||||
"Vulkan 1.3 driver",
|
||||
"Compatible glibc and libstdc++ runtime"
|
||||
],
|
||||
"renderer_profile": {
|
||||
"api": "Vulkan 1.3",
|
||||
"materials": [
|
||||
"base-color factor and texture",
|
||||
"metallic and roughness factors"
|
||||
],
|
||||
"required_features": [
|
||||
"dynamicRendering",
|
||||
"synchronization2"
|
||||
],
|
||||
"shadow_map": {
|
||||
"resolution": 1024,
|
||||
"world_extent": 40
|
||||
},
|
||||
"texture_sampling": "linear clamp, one mip level",
|
||||
"unsupported_material_features": [
|
||||
"normal maps",
|
||||
"metallic-roughness maps",
|
||||
"emissive and occlusion maps",
|
||||
"alpha mode selection",
|
||||
"unlit mode",
|
||||
"per-material face culling"
|
||||
]
|
||||
},
|
||||
"scene_hash": "05ab2c3e5b152ab25867976c47635961f440f41d8cd0408732eb2d8d5b7800a8",
|
||||
"simulation": {
|
||||
"fixed_delta": 0.016666666666666666,
|
||||
"gravity": [
|
||||
0,
|
||||
-9.81,
|
||||
0
|
||||
],
|
||||
"max_catch_up_ticks": 4,
|
||||
"physics_substeps": 4
|
||||
},
|
||||
"units": {
|
||||
"angle": "radian",
|
||||
"coordinates": "right-handed Y-up",
|
||||
"distance": "metre"
|
||||
},
|
||||
"validation_log": "{\"dimension\":2,\"validated\":true}\n",
|
||||
"version": 1
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,170 @@
|
||||
{
|
||||
"asset_generations": {
|
||||
"5832763b-3ed0-44d6-9088-0b524f196a91": "4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2"
|
||||
},
|
||||
"build_fingerprint": "5a516f5c4bded8f8e3f027b3dd2812a34b7f40b37e281c21ce87d7586fff88e4",
|
||||
"configuration": "Release",
|
||||
"executable": "faset_player",
|
||||
"files": [
|
||||
{
|
||||
"path": "scene.fscene",
|
||||
"sha256": "a7ac2dcd93dc9dce2d8ce860aa5dd838af2604dd7b40d5b50581d1a72bd5bf23",
|
||||
"size": 9218
|
||||
},
|
||||
{
|
||||
"path": "faset_player",
|
||||
"sha256": "a68c39af919d5c04db4985f36e3da4573f9a4c13862bc599cd85724ac6da22dc",
|
||||
"size": 5814720
|
||||
},
|
||||
{
|
||||
"path": "shaders/vertexMain.spv",
|
||||
"sha256": "1ad2631c35d654f48166321ae43d4165043e1b919b14f1dc61caf97b1ada0898",
|
||||
"size": 1224
|
||||
},
|
||||
{
|
||||
"path": "shaders/fragmentMain.spv",
|
||||
"sha256": "f5c4f289917ecab5d00d543c053aac1d10e6cca311fd172daf06d315160a3505",
|
||||
"size": 7436
|
||||
},
|
||||
{
|
||||
"path": "shaders/shadowMain.spv",
|
||||
"sha256": "7643b4d688492b5ee923b9606f0b0e70343ca05fa67673838206119a6f86d8d8",
|
||||
"size": 784
|
||||
},
|
||||
{
|
||||
"path": "shaders/vertexMain.reflection.json",
|
||||
"sha256": "c584f3b957ebf194a292451362a98590f85ff3cfbfd8f917b1c1265039381777",
|
||||
"size": 2639
|
||||
},
|
||||
{
|
||||
"path": "shaders/fragmentMain.reflection.json",
|
||||
"sha256": "72ebf8d32452830650416dc4717d89a4324e97ece7028dfb97c66803c8dce71f",
|
||||
"size": 2649
|
||||
},
|
||||
{
|
||||
"path": "shaders/shadowMain.reflection.json",
|
||||
"sha256": "e3fd0889cd2f569d410f5d7558a4091d9f57f247a1dcf1788462f67525340819",
|
||||
"size": 2645
|
||||
},
|
||||
{
|
||||
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2/meshes/mesh-fc069a07a87e0f831fd92efdbc4efa1f-0.fmesh",
|
||||
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
|
||||
"size": 928
|
||||
},
|
||||
{
|
||||
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2/meshes/mesh-0961e2a3f92977836a3aa80cab09277e-0.fmesh",
|
||||
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
|
||||
"size": 928
|
||||
},
|
||||
{
|
||||
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2/meshes/mesh-93b5b3e52cb6bb120fefb80e2d8e222b-0.fmesh",
|
||||
"sha256": "3875c16ea628d4126373ebfe07816621fbad3961596a2fcd112f1eec0e378071",
|
||||
"size": 928
|
||||
},
|
||||
{
|
||||
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2/manifest.json",
|
||||
"sha256": "ee3f68794c6dc44ab492b1ba4640aa74e4de79a5ec10aed8dcdd45a03afc508e",
|
||||
"size": 4532
|
||||
},
|
||||
{
|
||||
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/current.json",
|
||||
"sha256": "b0732959808ce61ef5a3223fba2d9ad8c17a3ea7873d4a81c00aadee6c51032e",
|
||||
"size": 134
|
||||
},
|
||||
{
|
||||
"path": "Notices/sdl3/LICENSE.txt",
|
||||
"sha256": "97f35b302b361680ec1e891e95d2d52097bb95abff361434916d99dc1305f127",
|
||||
"size": 884
|
||||
},
|
||||
{
|
||||
"path": "Notices/entt/LICENSE",
|
||||
"sha256": "0785027ce472d7c61f05fba664a1d3ba6639c1593ced351ad9e4bed868765d99",
|
||||
"size": 1097
|
||||
},
|
||||
{
|
||||
"path": "Notices/box2d/LICENSE",
|
||||
"sha256": "68a3e676d7e94093b102d5cba0d4e04af812040d6f230c3db67a6664574e43d2",
|
||||
"size": 1067
|
||||
},
|
||||
{
|
||||
"path": "Notices/box3d/LICENSE",
|
||||
"sha256": "da5e31a26bf3cfd5ba5c96d6823e480128c81e76c107ef9d3ee5d94789184b90",
|
||||
"size": 1067
|
||||
},
|
||||
{
|
||||
"path": "Notices/json/LICENSE.MIT",
|
||||
"sha256": "46a65cffd1ea955132d95a8dd921640714a8d6b537d2e4e482d31145ae95b603",
|
||||
"size": 1076
|
||||
},
|
||||
{
|
||||
"path": "Notices/stb/LICENSE",
|
||||
"sha256": "bebfe904b14301657e4e5d655c811d51fd31b97c455b9cc2d8600d6bac6cff63",
|
||||
"size": 2510
|
||||
},
|
||||
{
|
||||
"path": "Notices/dependencies.json",
|
||||
"sha256": "a54639ad2d9ad13c2e5f1ec90d6775f5dfc493656789b78c7e44debe2a378fdc",
|
||||
"size": 2206
|
||||
},
|
||||
{
|
||||
"path": "Notices/Faset-NOTICE.txt",
|
||||
"sha256": "30c2e7e80f5153b31ab57675e07246aef9165965d64e36022b426a26449ece3f",
|
||||
"size": 204
|
||||
},
|
||||
{
|
||||
"path": "README.txt",
|
||||
"sha256": "4dc2f0271c69fe39017ff96aa2dfa00b625bec1401d924dc396193ce71c09f3e",
|
||||
"size": 225
|
||||
}
|
||||
],
|
||||
"format": "faset.export",
|
||||
"generation": "17281e17-9f4f-44f0-8821-6e0071e9a45b",
|
||||
"platform": "linux",
|
||||
"prerequisites": [
|
||||
"Linux x86_64",
|
||||
"Vulkan 1.3 driver",
|
||||
"Compatible glibc and libstdc++ runtime"
|
||||
],
|
||||
"renderer_profile": {
|
||||
"api": "Vulkan 1.3",
|
||||
"materials": [
|
||||
"base-color factor and texture",
|
||||
"metallic and roughness factors"
|
||||
],
|
||||
"required_features": [
|
||||
"dynamicRendering",
|
||||
"synchronization2"
|
||||
],
|
||||
"shadow_map": {
|
||||
"resolution": 1024,
|
||||
"world_extent": 40
|
||||
},
|
||||
"texture_sampling": "linear clamp, one mip level",
|
||||
"unsupported_material_features": [
|
||||
"normal maps",
|
||||
"metallic-roughness maps",
|
||||
"emissive and occlusion maps",
|
||||
"alpha mode selection",
|
||||
"unlit mode",
|
||||
"per-material face culling"
|
||||
]
|
||||
},
|
||||
"scene_hash": "6510f994ee01af5823614911fcdeff0fd433846d937ff1a65d5bf5fb08e45e8f",
|
||||
"simulation": {
|
||||
"fixed_delta": 0.016666666666666666,
|
||||
"gravity": [
|
||||
0,
|
||||
-9.81,
|
||||
0
|
||||
],
|
||||
"max_catch_up_ticks": 4,
|
||||
"physics_substeps": 4
|
||||
},
|
||||
"units": {
|
||||
"angle": "radian",
|
||||
"coordinates": "right-handed Y-up",
|
||||
"distance": "metre"
|
||||
},
|
||||
"validation_log": "warning: material material-bb63b094febbf90bb7049c9bcf7587bc has features beyond the initial base-color/PBR renderer\n{\"dimension\":3,\"validated\":true}\n",
|
||||
"version": 1
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,312 @@
|
||||
{
|
||||
"format": "faset.validation-evidence",
|
||||
"version": 1,
|
||||
"status": "passed",
|
||||
"scope": "Linux relocated Release game export and offscreen small-scene measurement",
|
||||
"source_checkout": {
|
||||
"reference_commit": "5ac4db438dae5ee28e5619e62cf8d6647beecd52",
|
||||
"clean_commit_match": false,
|
||||
"description": "Shared working tree around 5ac4db4 plus in-progress checkpoint 4 work; builds were not made from a frozen clean commit. Exact exported binary/shader hashes are retained in each manifest."
|
||||
},
|
||||
"export_started_utc": "2026-09-18T01:46:06.267995+00:00",
|
||||
"export_finished_utc": "2026-09-18T01:49:50.149934+00:00",
|
||||
"host": {
|
||||
"os": "Ubuntu 26.04 LTS",
|
||||
"kernel": "7.0.0-31-generic x86_64",
|
||||
"cpu": "AMD Ryzen 7 1700 Eight-Core Processor (8 cores,16 threads)",
|
||||
"system_memory_bytes": 33571037184,
|
||||
"gpu": "NVIDIA GeForce RTX 2080 Ti",
|
||||
"gpu_memory_mib": 11264,
|
||||
"nvidia_driver": "595.84"
|
||||
},
|
||||
"configuration": {
|
||||
"build": "Release",
|
||||
"compiler": "Clang 21.1.8",
|
||||
"cxx_flags": "-O3 -DNDEBUG",
|
||||
"cmake": "4.2.3",
|
||||
"api": "Vulkan 1.3",
|
||||
"resolution": [
|
||||
1280,
|
||||
720
|
||||
],
|
||||
"presentation": "offscreen",
|
||||
"validation_enabled": true,
|
||||
"physics_debug": false,
|
||||
"frames_per_final_profile": 240,
|
||||
"fixed_delta_seconds": 0.016666666666666666,
|
||||
"simulation": "synthetic fixed timestep, no player input",
|
||||
"sampling": "nearest rank, all completed frames, cold first frame retained"
|
||||
},
|
||||
"verification": {
|
||||
"tool": "tools/verify_playable_exports.py",
|
||||
"project_copies_and_relocated_binaries_include": "Faset Café 世界",
|
||||
"steps": [
|
||||
"Copy exact checked-in sample project inputs",
|
||||
"Real Editor import of 3D Blender arch bundle",
|
||||
"Real Editor Release export",
|
||||
"Verify every package file size and SHA256",
|
||||
"Copy generation outside engine/source trees",
|
||||
"Hide disposable source-project paths",
|
||||
"Launch Player from unrelated empty cwd without scene/assets arguments",
|
||||
"CPU --validate then 120-frame offscreen capture and profile",
|
||||
"Additional 240-frame no-debug profile of each same relocated executable"
|
||||
],
|
||||
"validation_errors": 0
|
||||
},
|
||||
"projects": [
|
||||
{
|
||||
"name": "collect-2d",
|
||||
"dimension": 2,
|
||||
"generation": "48ec8546-3750-463f-9c4c-f76c3b933256",
|
||||
"build_fingerprint": "5b1996b0fe44eeaa01ee1fd581f9f063f8c84147128e896541d27207dbab9aaa",
|
||||
"scene_hash": "05ab2c3e5b152ab25867976c47635961f440f41d8cd0408732eb2d8d5b7800a8",
|
||||
"asset_generations": {},
|
||||
"source_inputs": [
|
||||
{
|
||||
"path": ".gitignore",
|
||||
"sha256": "53aa4d7124d4c8d93b8d7c4cb470b6c82b844e019a660d6243ffeadc50602de1"
|
||||
},
|
||||
{
|
||||
"path": "README.md",
|
||||
"sha256": "d6c35206b10ee28efd5cc02da77a3ce9b6e1f8ce085793150bbf2f23bd925d65"
|
||||
},
|
||||
{
|
||||
"path": "Scenes/main.scene.json",
|
||||
"sha256": "be48a6d21385e717b6c8ebf9a3b4322eebbeff6bb067428e089ab5214be79854"
|
||||
},
|
||||
{
|
||||
"path": "Scripts/Gameplay.cpp",
|
||||
"sha256": "6b581b24da613e1915819de0a0f0ea820dd3333efa62c4b479a9ea7ffdbc6bcc"
|
||||
},
|
||||
{
|
||||
"path": "Scripts/Gameplay.hpp",
|
||||
"sha256": "4121587182ed4f74901b1c0757c53daadbf309af1d6bb5dd87fef142130ccbbe"
|
||||
},
|
||||
{
|
||||
"path": "project.faset.json",
|
||||
"sha256": "36e2acd32210f5489372a2331346a3294ead2395f0713e3e5fd2da4e83263689"
|
||||
}
|
||||
],
|
||||
"package_file_count": 17,
|
||||
"source_project_paths_unavailable": true,
|
||||
"standalone_validation": "passed",
|
||||
"standalone_render_frames": 120,
|
||||
"capture": {
|
||||
"width": 1280,
|
||||
"height": 720,
|
||||
"sampled_colors": 7,
|
||||
"sha256": "f9d74067d87c1ebf30c6db372a26d93b7285791c8cb0307a24af5adb23bf201a"
|
||||
},
|
||||
"final_profile": "collect-2d-profile-240.json",
|
||||
"profile_recorded_at_utc": "2026-09-18T01:51:24.599491+00:00",
|
||||
"gpu_allocated_bytes": {
|
||||
"min": 15750288,
|
||||
"max": 15750288
|
||||
},
|
||||
"draw_calls": [
|
||||
11
|
||||
],
|
||||
"vertices": [
|
||||
66
|
||||
],
|
||||
"texture_count": [
|
||||
1
|
||||
],
|
||||
"summary_ms": {
|
||||
"gpu": {
|
||||
"max": 0.58912,
|
||||
"min": 0.563616,
|
||||
"p50": 0.564832,
|
||||
"p95": 0.57856,
|
||||
"samples": 240
|
||||
},
|
||||
"render_call": {
|
||||
"max": 5.705444,
|
||||
"min": 1.581003,
|
||||
"p50": 1.865269,
|
||||
"p95": 2.22086,
|
||||
"samples": 240
|
||||
},
|
||||
"renderer_cpu": {
|
||||
"max": 5.701056,
|
||||
"min": 1.578639,
|
||||
"p50": 1.861723,
|
||||
"p95": 2.216031,
|
||||
"samples": 240
|
||||
},
|
||||
"renderer_readback_cpu": {
|
||||
"max": 2.763424,
|
||||
"min": 0.432917,
|
||||
"p50": 0.509912,
|
||||
"p95": 0.632894,
|
||||
"samples": 240
|
||||
},
|
||||
"simulation": {
|
||||
"max": 0.513789,
|
||||
"min": 0.144743,
|
||||
"p50": 0.200708,
|
||||
"p95": 0.258247,
|
||||
"samples": 240
|
||||
},
|
||||
"snapshot": {
|
||||
"max": 0.25444,
|
||||
"min": 0.127029,
|
||||
"p50": 0.170341,
|
||||
"p95": 0.214946,
|
||||
"samples": 240
|
||||
},
|
||||
"wall": {
|
||||
"max": 6.089358,
|
||||
"min": 1.879436,
|
||||
"p50": 2.233955,
|
||||
"p95": 2.684014,
|
||||
"samples": 240
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "collect-3d",
|
||||
"dimension": 3,
|
||||
"generation": "17281e17-9f4f-44f0-8821-6e0071e9a45b",
|
||||
"build_fingerprint": "5a516f5c4bded8f8e3f027b3dd2812a34b7f40b37e281c21ce87d7586fff88e4",
|
||||
"scene_hash": "6510f994ee01af5823614911fcdeff0fd433846d937ff1a65d5bf5fb08e45e8f",
|
||||
"asset_generations": {
|
||||
"5832763b-3ed0-44d6-9088-0b524f196a91": "4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2"
|
||||
},
|
||||
"source_inputs": [
|
||||
{
|
||||
"path": ".gitignore",
|
||||
"sha256": "53aa4d7124d4c8d93b8d7c4cb470b6c82b844e019a660d6243ffeadc50602de1"
|
||||
},
|
||||
{
|
||||
"path": "Assets/exit-arch/create.py",
|
||||
"sha256": "9c7291124fb1498a3f992ef74afc39cd98f9cc3e2ff4687c633bece85d580905"
|
||||
},
|
||||
{
|
||||
"path": "Assets/exit-arch/manifest.json",
|
||||
"sha256": "7a13347adc89761fb02ebeab3c58ba87f319cd62f53ec87a3bb61bcd066ffa55"
|
||||
},
|
||||
{
|
||||
"path": "Assets/exit-arch/manifest.json.faset-import.json",
|
||||
"sha256": "ef4eef28a18a0cc40a40df75db34c97faa5d783b891265f862633f3aec514afc"
|
||||
},
|
||||
{
|
||||
"path": "Assets/exit-arch/payload/ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3.glb",
|
||||
"sha256": "ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3"
|
||||
},
|
||||
{
|
||||
"path": "Assets/exit-arch/source.blend",
|
||||
"sha256": "ff2676bec97ab778e531e87a185ad716049ea3b05b4a4f0027a6345737735035"
|
||||
},
|
||||
{
|
||||
"path": "README.md",
|
||||
"sha256": "2df5ca4df47ab5d3d05d41508201296d4ad5ec876245f19f061767ade6a30e8f"
|
||||
},
|
||||
{
|
||||
"path": "Scenes/main.scene.json",
|
||||
"sha256": "61b65baf79e52f07ac386a7f98acf985a1b09e88770cdde37ef461dc94b9dcd7"
|
||||
},
|
||||
{
|
||||
"path": "Scripts/Extensions/Beacon.hpp",
|
||||
"sha256": "c60d56161eead16f541835053ad32ac3333383d83015709c060b7d45e0af5a97"
|
||||
},
|
||||
{
|
||||
"path": "Scripts/Gameplay.cpp",
|
||||
"sha256": "5d419786a6861d7f14ed4eca54634694d8cd43be5dbbd60a2c6790db665c3a6a"
|
||||
},
|
||||
{
|
||||
"path": "Scripts/Gameplay.hpp",
|
||||
"sha256": "4121587182ed4f74901b1c0757c53daadbf309af1d6bb5dd87fef142130ccbbe"
|
||||
},
|
||||
{
|
||||
"path": "project.faset.json",
|
||||
"sha256": "43d273b1054ec9069369073f54cc1fc7efb3d6b699dcd342c552a2dc2ef852ef"
|
||||
}
|
||||
],
|
||||
"package_file_count": 22,
|
||||
"source_project_paths_unavailable": true,
|
||||
"standalone_validation": "passed",
|
||||
"standalone_render_frames": 120,
|
||||
"capture": {
|
||||
"width": 1280,
|
||||
"height": 720,
|
||||
"sampled_colors": 42,
|
||||
"sha256": "914060401de93d08b33bf09a1e210859e491a0060c331e5e2044f517356f4980"
|
||||
},
|
||||
"final_profile": "collect-3d-profile-240.json",
|
||||
"profile_recorded_at_utc": "2026-09-18T01:51:25.501500+00:00",
|
||||
"gpu_allocated_bytes": {
|
||||
"min": 15787008,
|
||||
"max": 15787008
|
||||
},
|
||||
"draw_calls": [
|
||||
31
|
||||
],
|
||||
"vertices": [
|
||||
576
|
||||
],
|
||||
"texture_count": [
|
||||
1
|
||||
],
|
||||
"summary_ms": {
|
||||
"gpu": {
|
||||
"max": 0.624064,
|
||||
"min": 0.58432,
|
||||
"p50": 0.58752,
|
||||
"p95": 0.600448,
|
||||
"samples": 240
|
||||
},
|
||||
"render_call": {
|
||||
"max": 4.807059,
|
||||
"min": 1.644403,
|
||||
"p50": 1.884165,
|
||||
"p95": 2.179593,
|
||||
"samples": 240
|
||||
},
|
||||
"renderer_cpu": {
|
||||
"max": 4.803463,
|
||||
"min": 1.626759,
|
||||
"p50": 1.880197,
|
||||
"p95": 2.174082,
|
||||
"samples": 240
|
||||
},
|
||||
"renderer_readback_cpu": {
|
||||
"max": 2.729419,
|
||||
"min": 0.398812,
|
||||
"p50": 0.468945,
|
||||
"p95": 0.608337,
|
||||
"samples": 240
|
||||
},
|
||||
"simulation": {
|
||||
"max": 0.441703,
|
||||
"min": 0.185701,
|
||||
"p50": 0.213223,
|
||||
"p95": 0.300146,
|
||||
"samples": 240
|
||||
},
|
||||
"snapshot": {
|
||||
"max": 0.740007,
|
||||
"min": 0.162066,
|
||||
"p50": 0.181302,
|
||||
"p95": 0.257285,
|
||||
"samples": 240
|
||||
},
|
||||
"wall": {
|
||||
"max": 5.902556,
|
||||
"min": 2.040269,
|
||||
"p50": 2.298847,
|
||||
"p95": 2.732225,
|
||||
"samples": 240
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"evidence_sha256": {
|
||||
"collect-2d-profile-240.json": "0141cb2ad6d31394b542d575dce3409fef82ff2e77fe91eb4a7183811471e36f",
|
||||
"collect-3d-profile-240.json": "bedf3a68df03c1af42bdb4d3b416d930c6e92fa6e99033c63ea9b17ae977c8c6",
|
||||
"collect-2d-manifest.json": "83a0c8a58dae07376c0db58ca58b115d9ecedb245bcba88bdcd5429796ba5be9",
|
||||
"collect-3d-manifest.json": "6374a6af5618a6c613b09978b2bf42300b1565808ded21bf9c2b82444027f252",
|
||||
"collect-2d.png": "c380583f2fd8bc09c5b0e1c6e755c35c3d64b5385ed66177b04d1bbdb532b236",
|
||||
"collect-3d.png": "98941a2004c3345da336294fa0e1b9e363922fc581c7a8612652ecbb0d764c07"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"format": "faset.native-window-validation",
|
||||
"version": 1,
|
||||
"date": "2026-09-18",
|
||||
"platform": "Linux, KDE Wayland session and isolated Xvfb",
|
||||
"source_checkout": "Working tree around5ac4db4 plus checkpoint4 changes; not an exact clean-commit result",
|
||||
"fixture": "tests/render_window_tests.cpp",
|
||||
"cases": [
|
||||
{
|
||||
"surface": "XWayland in the active desktop",
|
||||
"result": "passed",
|
||||
"scope": [
|
||||
"resize convergence",
|
||||
"fresh readback while minimized",
|
||||
"native minimize/restore events",
|
||||
"live SDL display-scale getter",
|
||||
"native SDL text input start/stop",
|
||||
"drawable-pixel input-area conversion checked through SDL_GetTextInputArea"
|
||||
],
|
||||
"clipboard": "Skipped because the existing clipboard advertised non-text payload; no replacement attempted.",
|
||||
"log": "driver=x11 stage=created\nstage=resized width=360 height=300 resize_events=2\nclipboard=skipped_to_preserve_non_text_payload\ntext_input_area=coordinate_conversion_passed\nstage=minimized fresh_frames=12 minimize_events=1 focus_lost_events=1\nstage=restored restored_events=1 activation_required=0 frames=56 validation_enabled=1 validation_errors=0\n"
|
||||
},
|
||||
{
|
||||
"surface": "Private Xvfb server, SDL X11 driver",
|
||||
"result": "clipboard and input-area checks passed; lifecycle skipped",
|
||||
"scope": [
|
||||
"Unicode clipboard roundtrip through Renderer/SDL",
|
||||
"saved plain-text clipboard restored without logging contents",
|
||||
"native SDL text-input activation and rectangle conversion"
|
||||
],
|
||||
"limit": "No window manager; minimize request unconfirmed, so this is not minimize/restore acceptance.",
|
||||
"log": "driver=x11 stage=created\nstage=resized width=360 height=300 resize_events=2\nclipboard=unicode_roundtrip_passed\ntext_input_area=coordinate_conversion_passed\nSKIP: window system declined the minimize request\n"
|
||||
},
|
||||
{
|
||||
"surface": "Native Wayland in the active desktop",
|
||||
"result": "partial; restore acceptance unresolved",
|
||||
"scope": [
|
||||
"resize convergence",
|
||||
"12 fresh readbacks while SDL reported minimized"
|
||||
],
|
||||
"limit": "Compositor did not confirm restore/activation. SDL Wayland may synthesize its minimized flag because xdg-shell has no minimized-state acknowledgement; physical minimization is not independently established."
|
||||
}
|
||||
],
|
||||
"limits": [
|
||||
"No real OS IME composition session was performed.",
|
||||
"Synthetic text events in other tests do not substitute for real IME acceptance.",
|
||||
"Windows native clipboard/window behavior requires its own run.",
|
||||
"No clipboard contents were retained in logs or artifacts."
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"format": "faset.offline-build",
|
||||
"version": 1,
|
||||
"revision": "d834cfad67cd81d8c4998b90c16791361ca8c0f8",
|
||||
"recorded_at_utc": "2026-09-18T01:33:07.301477+00:00",
|
||||
"seconds": 174.03467636999994,
|
||||
"returncode": 0,
|
||||
"network": "fresh user/network namespace; external connection must fail",
|
||||
"source": "git archive of committed HEAD; no existing build directory",
|
||||
"inputs": "prefetched archives + Slang; system compiler, SDK and development libraries",
|
||||
"tests": "full native build, CPU CTests; GPU/window execution verified separately"
|
||||
}
|
||||
Reference in New Issue
Block a user