handoff: VSync/event-wedge fixes + iterate 2.A–2.BC research notes
Source changes (dormant parity infra, retained from iterate 2.AI/2.AO): - xenia-kernel/exports.rs: nt_create_event manual_reset polarity + related event wiring - xenia-gpu/mmio_region.rs: D1MODE_VBLANK_VLINE_STATUS hardcode parity Also lands the audit-runs/ analysis notes (.md/.txt/.json digests) for the iterate 2.x VSync/0x10e8/0x1004 wedge investigation. Raw trace dumps (.jsonl/.gz/.csv/.stdout) and agent worktrees (.claude/) are gitignored as regenerable local artifacts — see memory + HANDOFF for the running findings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
# Cold-vs-cold result — Phase C+12 (2026-05-14)
|
||||
|
||||
| canary_tid | ours_tid | matched | first_divergence | event-kind at divergence |
|
||||
|---|---|---|---|---|
|
||||
| 6 | 1 | **103862** | 103862 | `kernel.return NtCreateFile game:\dat\files.tbl`: canary=STATUS_OBJECT_NAME_NOT_FOUND / ours=STATUS_SUCCESS (synth-empty stub) |
|
||||
| 4 | 11 | 9 | — | no divergence in 9 events |
|
||||
| 7 | 2 | 29 | — | no divergence in 29 events |
|
||||
| 12 | 7 | 2 | 2 | KeWaitForSingleObject — pre-existing, not regressed |
|
||||
| 14 | 9 | 39 | 39 | XAudio init — pre-existing, not regressed |
|
||||
| 15 | 10 | 15 | — | no divergence in 15 events |
|
||||
|
||||
Main matched-prefix advance: **+1458 events** (102,404 → 103,862).
|
||||
|
||||
New cold digest baseline (stable mode):
|
||||
`ad4f74ee324fdedb0bfdd4cc4c6468e9` (UNCHANGED from C+11.1 — the
|
||||
Phase C+12 fix is a pure kernel-export observation change that
|
||||
doesn't shift any of the stable counters in the digest).
|
||||
|
||||
Phase B `image_loaded_sha256`:
|
||||
`ea8d160e9369328a5b922258a92113efb8d7ce3e1a5c12cc521e375985c91c18`
|
||||
(unchanged).
|
||||
@@ -0,0 +1,131 @@
|
||||
# Phase A diff report
|
||||
|
||||
**This report is the output of Phase A's diff harness. Divergences
|
||||
shown here are INPUT for Phase B (first-divergence localization),
|
||||
not findings of Phase A.** Phase A's job is to make the harness
|
||||
itself correct, not to analyze what it surfaces.
|
||||
|
||||
## Summary
|
||||
|
||||
| canary_tid | ours_tid | matched | canary_total | ours_total | first_divergence_at |
|
||||
|---|---|---|---|---|---|
|
||||
| 4 | 11 | 9 | 20000 | 9 | — |
|
||||
| 6 | 1 | 103862 | 250000 | 108471 | 103862 |
|
||||
| 7 | 2 | 29 | 29 | 30 | — |
|
||||
| 12 | 7 | 2 | 10532 | 3 | 2 |
|
||||
| 14 | 9 | 39 | 20000 | 75 | 39 |
|
||||
| 15 | 10 | 15 | 20000 | 15 | — |
|
||||
|
||||
## canary_tid=4 → ours_tid=11
|
||||
|
||||
No divergence within the 9 compared events (canary has 20000, ours has 9).
|
||||
|
||||
## canary_tid=6 → ours_tid=1
|
||||
|
||||
First divergence at `tid_event_idx=103862`: payload.return_value: canary=18446744072635809844 ours=0
|
||||
|
||||
**Pre-context (last 5 matching events):**
|
||||
```
|
||||
canary: [103857] import.call RtlInitAnsiString
|
||||
ours: [103857] import.call RtlInitAnsiString
|
||||
canary: [103858] kernel.call RtlInitAnsiString
|
||||
ours: [103858] kernel.call RtlInitAnsiString
|
||||
canary: [103859] kernel.return RtlInitAnsiString
|
||||
ours: [103859] kernel.return RtlInitAnsiString
|
||||
canary: [103860] import.call NtCreateFile
|
||||
ours: [103860] import.call NtCreateFile
|
||||
canary: [103861] kernel.call NtCreateFile
|
||||
ours: [103861] kernel.call NtCreateFile
|
||||
```
|
||||
|
||||
**Divergent event:**
|
||||
```
|
||||
canary: [103862] kernel.return NtCreateFile
|
||||
ours: [103862] kernel.return NtCreateFile
|
||||
```
|
||||
|
||||
**Next event after the divergence (if any):**
|
||||
```
|
||||
canary: [103863] import.call RtlNtStatusToDosError
|
||||
ours: [103863] import.call RtlEnterCriticalSection
|
||||
```
|
||||
|
||||
**Raw events (JSON):**
|
||||
```json
|
||||
{"deterministic": true, "engine": "canary", "guest_cycle": 0, "host_ns": 805501600, "kind": "kernel.return", "payload": {"name": "NtCreateFile", "return_value": 18446744072635809844, "side_effects": [], "status": "0xc0000034"}, "schema_version": 1, "tid": 6, "tid_event_idx": 103862}
|
||||
{"deterministic": true, "engine": "ours", "guest_cycle": 5470532, "host_ns": 463681670, "kind": "kernel.return", "payload": {"name": "NtCreateFile", "return_value": 0, "side_effects": [], "status": "0x00000000"}, "schema_version": 1, "tid": 1, "tid_event_idx": 103862}
|
||||
```
|
||||
|
||||
## canary_tid=7 → ours_tid=2
|
||||
|
||||
No divergence within the 29 compared events (canary has 29, ours has 30).
|
||||
|
||||
## canary_tid=12 → ours_tid=7
|
||||
|
||||
First divergence at `tid_event_idx=2`: payload.return_value: canary=258 ours=0
|
||||
|
||||
**Pre-context (last 5 matching events):**
|
||||
```
|
||||
canary: [0] import.call KeWaitForSingleObject
|
||||
ours: [0] import.call KeWaitForSingleObject
|
||||
canary: [1] kernel.call KeWaitForSingleObject
|
||||
ours: [1] kernel.call KeWaitForSingleObject
|
||||
```
|
||||
|
||||
**Divergent event:**
|
||||
```
|
||||
canary: [2] kernel.return KeWaitForSingleObject
|
||||
ours: [2] kernel.return KeWaitForSingleObject
|
||||
```
|
||||
|
||||
**Next event after the divergence (if any):**
|
||||
```
|
||||
canary: [3] import.call RtlEnterCriticalSection
|
||||
ours: <end of stream>
|
||||
```
|
||||
|
||||
**Raw events (JSON):**
|
||||
```json
|
||||
{"deterministic": true, "engine": "canary", "guest_cycle": 0, "host_ns": 935048400, "kind": "kernel.return", "payload": {"name": "KeWaitForSingleObject", "return_value": 258, "side_effects": [], "status": "0x00000102"}, "schema_version": 1, "tid": 12, "tid_event_idx": 2}
|
||||
{"deterministic": true, "engine": "ours", "guest_cycle": 30, "host_ns": 479443976, "kind": "kernel.return", "payload": {"name": "KeWaitForSingleObject", "return_value": 0, "side_effects": [], "status": "0x00000000"}, "schema_version": 1, "tid": 7, "tid_event_idx": 2}
|
||||
```
|
||||
|
||||
## canary_tid=14 → ours_tid=9
|
||||
|
||||
First divergence at `tid_event_idx=39`: payload.ord: canary=503 ours=293
|
||||
|
||||
**Pre-context (last 5 matching events):**
|
||||
```
|
||||
canary: [34] kernel.call KeReleaseSpinLockFromRaisedIrql
|
||||
ours: [34] kernel.call KeReleaseSpinLockFromRaisedIrql
|
||||
canary: [35] kernel.return KeReleaseSpinLockFromRaisedIrql
|
||||
ours: [35] kernel.return KeReleaseSpinLockFromRaisedIrql
|
||||
canary: [36] import.call KfLowerIrql
|
||||
ours: [36] import.call KfLowerIrql
|
||||
canary: [37] kernel.call KfLowerIrql
|
||||
ours: [37] kernel.call KfLowerIrql
|
||||
canary: [38] kernel.return KfLowerIrql
|
||||
ours: [38] kernel.return KfLowerIrql
|
||||
```
|
||||
|
||||
**Divergent event:**
|
||||
```
|
||||
canary: [39] import.call XAudioGetVoiceCategoryVolumeChangeMask
|
||||
ours: [39] import.call RtlEnterCriticalSection
|
||||
```
|
||||
|
||||
**Next event after the divergence (if any):**
|
||||
```
|
||||
canary: [40] kernel.call XAudioGetVoiceCategoryVolumeChangeMask
|
||||
ours: [40] kernel.call RtlEnterCriticalSection
|
||||
```
|
||||
|
||||
**Raw events (JSON):**
|
||||
```json
|
||||
{"deterministic": true, "engine": "canary", "guest_cycle": 0, "host_ns": 1106484200, "kind": "import.call", "payload": {"module": "xboxkrnl.exe", "name": "XAudioGetVoiceCategoryVolumeChangeMask", "ord": 503}, "schema_version": 1, "tid": 14, "tid_event_idx": 39}
|
||||
{"deterministic": true, "engine": "ours", "guest_cycle": 417, "host_ns": 1658972624, "kind": "import.call", "payload": {"module": "xboxkrnl.exe", "name": "RtlEnterCriticalSection", "ord": 293}, "schema_version": 1, "tid": 9, "tid_event_idx": 39}
|
||||
```
|
||||
|
||||
## canary_tid=15 → ours_tid=10
|
||||
|
||||
No divergence within the 15 compared events (canary has 20000, ours has 15).
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"instructions": 50000002,
|
||||
"imports": 40447,
|
||||
"unimpl": 0,
|
||||
"draws": 0,
|
||||
"swaps": 1,
|
||||
"unique_render_targets": 0,
|
||||
"shader_blobs_live": 0,
|
||||
"texture_cache_entries": 0
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"instructions": 50000002,
|
||||
"imports": 40447,
|
||||
"unimpl": 0,
|
||||
"draws": 0,
|
||||
"swaps": 1,
|
||||
"unique_render_targets": 0,
|
||||
"shader_blobs_live": 0,
|
||||
"texture_cache_entries": 0
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"instructions": 50000002,
|
||||
"imports": 40447,
|
||||
"unimpl": 0,
|
||||
"draws": 0,
|
||||
"swaps": 1,
|
||||
"unique_render_targets": 0,
|
||||
"shader_blobs_live": 0,
|
||||
"texture_cache_entries": 0
|
||||
}
|
||||
3498
audit-runs/phase-c12-NtQueryFullAttributesFile/fix.diff
Normal file
3498
audit-runs/phase-c12-NtQueryFullAttributesFile/fix.diff
Normal file
File diff suppressed because it is too large
Load Diff
179
audit-runs/phase-c12-NtQueryFullAttributesFile/investigation.md
Normal file
179
audit-runs/phase-c12-NtQueryFullAttributesFile/investigation.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# Phase C+12 — investigation (canary's NtQueryFullAttributesFile)
|
||||
|
||||
## Canary's verified behavior
|
||||
|
||||
### Entry point
|
||||
`NtQueryFullAttributesFile_entry` lives in
|
||||
`xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc:474-513`. It
|
||||
takes `(X_OBJECT_ATTRIBUTES*, X_FILE_NETWORK_OPEN_INFORMATION*)` and:
|
||||
|
||||
1. Translates the ANSI object name to a guest VFS path
|
||||
(`util::TranslateAnsiPath`).
|
||||
2. Calls `kernel_state()->file_system()->ResolvePath(target_path)`.
|
||||
3. On hit, populates the OUT struct from `entry->{create,access,
|
||||
write}_timestamp()` + `entry->allocation_size()` + `entry->size()`
|
||||
+ `entry->attributes()`. Returns `X_STATUS_SUCCESS`.
|
||||
4. On miss, returns `X_STATUS_NO_SUCH_FILE` (NOT
|
||||
`OBJECT_NAME_NOT_FOUND`).
|
||||
|
||||
`xboxkrnl_io.cc:498-512`:
|
||||
|
||||
```cpp
|
||||
auto entry = kernel_state()->file_system()->ResolvePath(target_path);
|
||||
if (entry) {
|
||||
file_info->creation_time = entry->create_timestamp();
|
||||
file_info->last_access_time= entry->access_timestamp();
|
||||
file_info->last_write_time = entry->write_timestamp();
|
||||
file_info->change_time = entry->write_timestamp(); // <-- same as write
|
||||
file_info->allocation_size = entry->allocation_size();
|
||||
file_info->end_of_file = entry->size();
|
||||
file_info->attributes = entry->attributes();
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
```
|
||||
|
||||
### Resolution mechanism
|
||||
|
||||
`VirtualFileSystem::ResolvePath`
|
||||
(`xenia-canary/src/xenia/vfs/virtual_file_system.cc:129-158`) walks
|
||||
the in-memory `Entry` tree. It does NOT re-stat the host FS. The
|
||||
tree is populated:
|
||||
|
||||
* **Eagerly at mount time** by
|
||||
`HostPathDevice::Initialize` →
|
||||
`HostPathDevice::PopulateEntry`
|
||||
(`xenia-canary/src/xenia/vfs/devices/host_path_device.cc:31-75`)
|
||||
which recursively walks the host directory and builds
|
||||
`HostPathEntry` instances via `HostPathEntry::Create`.
|
||||
* **Per-create** by `Entry::CreateEntry` /
|
||||
`HostPathEntry::CreateEntryInternal`
|
||||
(`xenia-canary/src/xenia/vfs/entry.cc:88` /
|
||||
`host_path_entry.cc:78-98`), called from
|
||||
`VirtualFileSystem::OpenFile` → `CreatePath`
|
||||
(`virtual_file_system.cc:160-187`) on successful NtCreateFile create.
|
||||
|
||||
### Struct layout
|
||||
|
||||
`X_FILE_NETWORK_OPEN_INFORMATION` in
|
||||
`xenia-canary/src/xenia/kernel/info/file.h:117-127`:
|
||||
|
||||
```cpp
|
||||
struct X_FILE_NETWORK_OPEN_INFORMATION { // 56 bytes
|
||||
be<uint64_t> creation_time;
|
||||
be<uint64_t> last_access_time;
|
||||
be<uint64_t> last_write_time;
|
||||
be<uint64_t> change_time;
|
||||
be<uint64_t> allocation_size;
|
||||
be<uint64_t> end_of_file;
|
||||
be<uint32_t> attributes;
|
||||
be<uint32_t> pad;
|
||||
};
|
||||
```
|
||||
|
||||
All multibyte fields are `be<>`, i.e. byte-swapped on write to guest
|
||||
memory (Xbox 360 is big-endian).
|
||||
|
||||
### Attribute / size derivation
|
||||
|
||||
`HostPathEntry::Create`
|
||||
(`xenia-canary/src/xenia/vfs/devices/host_path_entry.cc:32-54`):
|
||||
|
||||
* `attributes_ = kFileAttributeDirectory (0x10)` if host is a dir.
|
||||
* `attributes_ = kFileAttributeNormal (0x80)` for regular files.
|
||||
`kFileAttributeReadOnly (0x01)` is OR'd in iff
|
||||
`device->is_read_only()`. `cache:` mounts are read-WRITE
|
||||
(`xenia_main.cc:641-651`), so the bit is NOT set.
|
||||
* `size_ = file_info.total_size`.
|
||||
* `allocation_size_ = round_up(total_size, device->bytes_per_sector())`.
|
||||
The base `Device` ctor defaults `bytes_per_sector_ = 512`
|
||||
(`xenia-canary/src/xenia/vfs/device.h`); host-path devices don't
|
||||
override.
|
||||
|
||||
### Timestamp format
|
||||
|
||||
Windows FILETIME — 100-ns ticks since 1601-01-01 UTC. On the Windows
|
||||
debug build, canary derives these via
|
||||
`COMBINE_TIME(WIN32_FILE_ATTRIBUTE_DATA::ftCreationTime)`
|
||||
(`filesystem_win.cc:226-228`), which is already FILETIME-format.
|
||||
|
||||
### Why ours diverged at idx 102404
|
||||
|
||||
ours's `nt_query_full_attributes_file` previously consulted
|
||||
`std::fs::metadata` directly. On TRUE cold-vs-cold (both engines'
|
||||
cache wiped), the host file `cache/d4ea4615/e/46ee8ca` doesn't
|
||||
exist → ours returned `STATUS_NO_SUCH_FILE`. So why does canary
|
||||
return SUCCESS?
|
||||
|
||||
The original Phase C+11.1 protocol wiped `~/.local/share/Xenia/cache`
|
||||
but the Windows-debug canary running under wine actually stores its
|
||||
cache under
|
||||
`xenia-canary/build-cross/bin/Windows/Debug/cache/` (canary's
|
||||
storage root resolves to `GetUserFolder()` when no `portable.txt`
|
||||
is present, but the build-cross binary writes there anyway — verified
|
||||
by `Storage root: Z:\home\fabi\RE - Project Sylpheed\xenia-canary\
|
||||
build-cross\bin\Windows\Debug` in the canary stdout). So the
|
||||
"cold-vs-cold" baseline at C+11.1 was actually
|
||||
ours-cold-vs-canary-warm: canary's binary-dir cache survived the
|
||||
wipe and the pre-existing `46ee8ca` file (May 12 timestamp) made
|
||||
canary's mount-time scan populate the in-memory tree.
|
||||
|
||||
A TRUE cold-vs-cold (Phase C+12 protocol, see `re-validation.md`)
|
||||
that ALSO wipes the binary-dir cache shows canary ALSO returns
|
||||
NO_SUCH_FILE for `cache:\d4ea4615\e\46ee8ca` at idx 102404 — and
|
||||
the divergence at 102404 dissolves.
|
||||
|
||||
But the underlying gap remains: canary maintains an in-memory entry
|
||||
tree that ours did not, and any boot where canary has a populated
|
||||
host cache (Sylpheed's normal warm/persistent operation) would see
|
||||
canary succeed where ours misses. Fixing this is in scope per the
|
||||
user directive.
|
||||
|
||||
## Architecture decision
|
||||
|
||||
Architecture **B** (in-memory entry tree mirroring canary):
|
||||
|
||||
* Add `cache_entries: HashMap<String, CacheEntryMeta>` to `KernelState`.
|
||||
* Eager mount-time scan via `populate_cache_entries_from_host`
|
||||
(mirrors canary's `HostPathDevice::PopulateEntry`).
|
||||
* Per-create registration via `register_cache_entry` (mirrors canary's
|
||||
`Entry::CreateEntry`).
|
||||
* `nt_query_full_attributes_file` consults the tree first;
|
||||
defensive host-FS fallback only fires when the tree missed but
|
||||
the file is on disk (refreshes tree as a side effect).
|
||||
|
||||
Architecture A alone (just stat host FS) would technically work for
|
||||
the specific 102404 case after the corrected cold-vs-cold protocol,
|
||||
but would diverge from canary on any sequence where the in-memory
|
||||
tree's freshness matters (e.g. an entry created earlier this same
|
||||
boot whose host write hasn't flushed yet — rare but possible if a
|
||||
future game pre-allocates entries before the corresponding write).
|
||||
Architecture B keeps semantic parity with canary regardless of the
|
||||
host-FS flush timing.
|
||||
|
||||
## Cold-vs-cold protocol correction
|
||||
|
||||
The C+11.1 protocol wiped `~/.local/share/Xenia/cache`. The Phase
|
||||
C+12 protocol additionally wipes
|
||||
`xenia-canary/build-cross/bin/Windows/Debug/cache/`
|
||||
(plus `cache0/`, `cache1/`) because that's where the Windows-debug
|
||||
canary actually writes its cache under wine. Backup is preserved at
|
||||
`/tmp/canary-binary-cache-backup.tar.gz` (4.7 MB, 23 files) and a
|
||||
copy lives in this audit-run dir as
|
||||
`canary-binary-cache-pre-wipe.tar.gz`.
|
||||
|
||||
## File:line citations
|
||||
|
||||
| canary source | line(s) | what |
|
||||
|---|---|---|
|
||||
| `xboxkrnl_io.cc` | 474-513 | `NtQueryFullAttributesFile_entry` body |
|
||||
| `xboxkrnl_io.cc` | 504 | `change_time = write_timestamp()` |
|
||||
| `xboxkrnl_io.cc` | 512 | `return X_STATUS_NO_SUCH_FILE` |
|
||||
| `info/file.h` | 117-127 | `X_FILE_NETWORK_OPEN_INFORMATION` layout |
|
||||
| `vfs/entry.h` | 67-95 | `kFileAttribute*` consts + accessors |
|
||||
| `vfs/entry.cc` | 88-104 | `Entry::CreateEntry` |
|
||||
| `vfs/virtual_file_system.cc` | 129-158 | `ResolvePath` |
|
||||
| `vfs/devices/host_path_device.cc` | 31-75 | `Initialize` + `PopulateEntry` |
|
||||
| `vfs/devices/host_path_entry.cc` | 32-54 | `HostPathEntry::Create` (attrs + size) |
|
||||
| `base/filesystem_win.cc` | 208-230 | `GetInfo` (FILETIME timestamps) |
|
||||
| `app/xenia_main.cc` | 641-651 | `cache:` mount registration |
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"build_id": "ours-phaseB",
|
||||
"cvars": {
|
||||
"phase_b_dump_section_content": false,
|
||||
"phase_b_snapshot_and_exit": true,
|
||||
"phase_b_snapshot_dir": "/tmp/phase-b-c12"
|
||||
},
|
||||
"deterministic_skip": [
|
||||
"host_ns_at_snapshot",
|
||||
"wall_clock_iso8601",
|
||||
"build_id",
|
||||
"iso_path",
|
||||
"cvars.phase_b_snapshot_dir"
|
||||
],
|
||||
"engine": "ours",
|
||||
"host_ns_at_snapshot": 0,
|
||||
"image_loaded_sha256": "ea8d160e9369328a5b922258a92113efb8d7ce3e1a5c12cc521e375985c91c18",
|
||||
"iso_path": "",
|
||||
"schema_version": 1,
|
||||
"wall_clock_iso8601": "epoch:0",
|
||||
"xex_entry_point": "0x824ab748",
|
||||
"xex_header_sha256": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"xex_image_base": "0x82000000",
|
||||
"xex_image_size": 9568256
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
{
|
||||
"cr": [
|
||||
"0x0",
|
||||
"0x0",
|
||||
"0x0",
|
||||
"0x0",
|
||||
"0x0",
|
||||
"0x0",
|
||||
"0x0",
|
||||
"0x0"
|
||||
],
|
||||
"ctr": "0x0000000000000000",
|
||||
"deterministic_skip": [
|
||||
"hw_id"
|
||||
],
|
||||
"engine": "ours",
|
||||
"fpr": [
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000"
|
||||
],
|
||||
"fpscr": "0x00000000",
|
||||
"gpr": [
|
||||
"0x0000000000000000",
|
||||
"0x00000000700fff00",
|
||||
"0x0000000020000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x000000007fff0000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000",
|
||||
"0x0000000000000000"
|
||||
],
|
||||
"hw_id": 0,
|
||||
"lr": "0x00000000bcbcbcbc",
|
||||
"msr": "0x0000000000009030",
|
||||
"pc": "0x824ab748",
|
||||
"pcr_base": "0x7fff0000",
|
||||
"schema_version": 1,
|
||||
"stack_base": "0x00000000",
|
||||
"stack_limit": "0x00000000",
|
||||
"thread_id": 1,
|
||||
"tls_base": "0x00000000",
|
||||
"vr": [
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000"
|
||||
],
|
||||
"vrsave": "0xffffffff",
|
||||
"vscr": "00000000000000000000000000010000",
|
||||
"xer": {
|
||||
"ca": 0,
|
||||
"ov": 0,
|
||||
"so": 0,
|
||||
"tbc": 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"deterministic_skip": [
|
||||
"raw_handle_id",
|
||||
"exports_registered_count"
|
||||
],
|
||||
"engine": "ours",
|
||||
"exports_registered_count": 199,
|
||||
"exports_registered_sample": [
|
||||
"xam.xex!NetDll_WSACleanup",
|
||||
"xam.xex!NetDll_WSAStartup",
|
||||
"xam.xex!XGetAVPack",
|
||||
"xam.xex!XGetGameRegion",
|
||||
"xam.xex!XGetLanguage",
|
||||
"xam.xex!XGetVideoMode",
|
||||
"xam.xex!XMsgInProcessCall",
|
||||
"xam.xex!XMsgStartIORequest",
|
||||
"xam.xex!XMsgStartIORequestEx",
|
||||
"xam.xex!XNotifyGetNext",
|
||||
"xam.xex!XNotifyPositionUI",
|
||||
"xam.xex!XamAlloc",
|
||||
"xam.xex!XamContentClose",
|
||||
"xam.xex!XamContentCreate",
|
||||
"xam.xex!XamContentCreateEnumerator",
|
||||
"xam.xex!XamContentDelete",
|
||||
"xam.xex!XamContentGetCreator",
|
||||
"xam.xex!XamContentGetDeviceData",
|
||||
"xam.xex!XamContentGetDeviceName",
|
||||
"xam.xex!XamContentGetDeviceState",
|
||||
"xam.xex!XamContentSetThumbnail",
|
||||
"xam.xex!XamEnableInactivityProcessing",
|
||||
"xam.xex!XamEnumerate",
|
||||
"xam.xex!XamFree",
|
||||
"xam.xex!XamGetExecutionId",
|
||||
"xam.xex!XamGetSystemVersion",
|
||||
"xam.xex!XamInputGetCapabilities",
|
||||
"xam.xex!XamInputGetKeystrokeEx",
|
||||
"xam.xex!XamInputGetState",
|
||||
"xam.xex!XamInputSetState",
|
||||
"xam.xex!XamLoaderLaunchTitle",
|
||||
"xam.xex!XamLoaderTerminateTitle"
|
||||
],
|
||||
"exports_registered_sha256": "bca7668a2a76ce1d1cc4dba8a862a2f16ec6ee3b2aab8a71d8d8bc0ccc89a097",
|
||||
"handle_name_table": [],
|
||||
"notification_listeners": [],
|
||||
"objects": [
|
||||
{
|
||||
"details": {
|
||||
"entry_pc": "0x824ab748",
|
||||
"exit_code": null,
|
||||
"hw_id": 0,
|
||||
"is_entry_thread": true,
|
||||
"thread_id": 1
|
||||
},
|
||||
"handle_semantic_id": "9879c5053fedb1d0",
|
||||
"name": null,
|
||||
"raw_handle_id": "0x00001000",
|
||||
"type": "Thread",
|
||||
"type_code": 5
|
||||
}
|
||||
],
|
||||
"schema_version": 1
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"engine": "ours",
|
||||
"files": {
|
||||
"config.json": "f56c3d4f8e36876c5161c3a1d2196b1666e1a98ed0a16484a152dace7735e0a9",
|
||||
"cpu_state.json": "4e6df54ca1939d08854f3a52b49ed2c5ee0823d63cdecad8a7395203dac5443a",
|
||||
"kernel.json": "2db219d4ca8b0313e53be379b8fcf90ab13b99116e6fac5601f6bdefd1aa6900",
|
||||
"memory.json": "b96ae4daebfbdd314e574492c1e162f532fa4f89ff5c0d7c6c29743797089cf1",
|
||||
"vfs.json": "97bb2bda57266d8e0dd1da13309eab5ece43130ef378a0b682917d299e9dc4e1"
|
||||
},
|
||||
"schema_version": 1
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"committed_pages_total": 2594,
|
||||
"deterministic_skip": [
|
||||
"host_base_pointer"
|
||||
],
|
||||
"engine": "ours",
|
||||
"guest_address_space_bytes": 4294967296,
|
||||
"heaps": [
|
||||
{
|
||||
"base": "0x00000000",
|
||||
"name": "v00000000",
|
||||
"page_size": 4096,
|
||||
"page_state_histogram": {
|
||||
"committed": 0
|
||||
},
|
||||
"size": "0x40000000"
|
||||
},
|
||||
{
|
||||
"base": "0x40000000",
|
||||
"name": "v40000000",
|
||||
"page_size": 4096,
|
||||
"page_state_histogram": {
|
||||
"committed": 266
|
||||
},
|
||||
"size": "0x40000000"
|
||||
},
|
||||
{
|
||||
"base": "0x80000000",
|
||||
"name": "v80000000",
|
||||
"page_size": 4096,
|
||||
"page_state_histogram": {
|
||||
"committed": 2336
|
||||
},
|
||||
"size": "0x40000000"
|
||||
},
|
||||
{
|
||||
"base": "0x90000000",
|
||||
"name": "v90000000",
|
||||
"page_size": 4096,
|
||||
"page_state_histogram": {
|
||||
"committed": 0
|
||||
},
|
||||
"size": "0x40000000"
|
||||
}
|
||||
],
|
||||
"page_size": 4096,
|
||||
"regions": [
|
||||
{
|
||||
"byte_count": 1048576,
|
||||
"end": "0x70100000",
|
||||
"protect": 0,
|
||||
"section_kind": null,
|
||||
"sha256": "30e14955ebf1352266dc2ff8067e68104607e750abb9d3b36582b8af909fcb58",
|
||||
"start": "0x70000000"
|
||||
},
|
||||
{
|
||||
"byte_count": 4096,
|
||||
"end": "0x7ffe1000",
|
||||
"protect": 0,
|
||||
"section_kind": null,
|
||||
"sha256": "ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7",
|
||||
"start": "0x7ffe0000"
|
||||
},
|
||||
{
|
||||
"byte_count": 4096,
|
||||
"end": "0x7fff1000",
|
||||
"protect": 0,
|
||||
"section_kind": null,
|
||||
"sha256": "e35cddaf9c210aed7505ec4cf1c599f58ac2b7ec25b0885db1ee49aba2db519a",
|
||||
"start": "0x7fff0000"
|
||||
},
|
||||
{
|
||||
"byte_count": 9568256,
|
||||
"end": "0x82920000",
|
||||
"protect": 0,
|
||||
"section_kind": null,
|
||||
"sha256": "ea8d160e9369328a5b922258a92113efb8d7ce3e1a5c12cc521e375985c91c18",
|
||||
"start": "0x82000000"
|
||||
}
|
||||
],
|
||||
"regions_walked": [],
|
||||
"schema_version": 1,
|
||||
"section_contents": null
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"cache_root_listing": [],
|
||||
"deterministic_skip": [
|
||||
"host_path_realpath"
|
||||
],
|
||||
"engine": "ours",
|
||||
"mounted_devices_observed_count": 1,
|
||||
"resolve_path_probes": [
|
||||
{
|
||||
"is_directory": true,
|
||||
"path": "\\Device\\Cdrom0",
|
||||
"resolved": true,
|
||||
"size": null
|
||||
},
|
||||
{
|
||||
"is_directory": true,
|
||||
"path": "\\Device\\Cdrom0\\dat",
|
||||
"resolved": true,
|
||||
"size": 4096
|
||||
},
|
||||
{
|
||||
"is_directory": null,
|
||||
"path": "\\Device\\Cdrom0\\dat\\movie",
|
||||
"resolved": false,
|
||||
"size": null
|
||||
},
|
||||
{
|
||||
"is_directory": null,
|
||||
"path": "\\Device\\Cdrom0\\dat\\movie\\opening.bik",
|
||||
"resolved": false,
|
||||
"size": null
|
||||
},
|
||||
{
|
||||
"is_directory": false,
|
||||
"path": "\\Device\\Cdrom0\\default.xex",
|
||||
"resolved": true,
|
||||
"size": 3497984
|
||||
},
|
||||
{
|
||||
"is_directory": null,
|
||||
"path": "\\Device\\HardDisk0\\Partition1",
|
||||
"resolved": false,
|
||||
"size": null
|
||||
},
|
||||
{
|
||||
"is_directory": true,
|
||||
"path": "cache:\\",
|
||||
"resolved": true,
|
||||
"size": null
|
||||
},
|
||||
{
|
||||
"is_directory": null,
|
||||
"path": "cache:\\nonexistent_probe",
|
||||
"resolved": false,
|
||||
"size": null
|
||||
},
|
||||
{
|
||||
"is_directory": true,
|
||||
"path": "game:\\dat",
|
||||
"resolved": true,
|
||||
"size": 4096
|
||||
},
|
||||
{
|
||||
"is_directory": false,
|
||||
"path": "game:\\default.xex",
|
||||
"resolved": true,
|
||||
"size": 3497984
|
||||
}
|
||||
],
|
||||
"schema_version": 1
|
||||
}
|
||||
101
audit-runs/phase-c12-NtQueryFullAttributesFile/re-validation.md
Normal file
101
audit-runs/phase-c12-NtQueryFullAttributesFile/re-validation.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# Phase C+12 re-validation (cold-vs-cold)
|
||||
|
||||
## Cache-wipe protocol (CORRECTED from C+11.1)
|
||||
|
||||
The Phase C+11.1 protocol wiped `~/.local/share/Xenia/cache`, but
|
||||
the Windows-debug canary running under wine actually stores its
|
||||
cache at `xenia-canary/build-cross/bin/Windows/Debug/cache/` (the
|
||||
binary directory; verified by canary's `Storage root: Z:\...\build-
|
||||
cross\bin\Windows\Debug` startup log). C+12's effective wipe targets
|
||||
the binary directory.
|
||||
|
||||
Step-by-step (the protocol used here):
|
||||
|
||||
1. Backup canary's binary-dir cache:
|
||||
`tar -czf /tmp/canary-binary-cache-backup.tar.gz -C
|
||||
xenia-canary/build-cross/bin/Windows/Debug cache`
|
||||
(4.7 MB, 23 files). Copy to
|
||||
`audit-runs/phase-c12-NtQueryFullAttributesFile/
|
||||
canary-binary-cache-pre-wipe.tar.gz`.
|
||||
2. Wipe both engines' caches:
|
||||
* `find xenia-canary/build-cross/bin/Windows/Debug/cache -mindepth 1 -delete`
|
||||
* `find xenia-canary/build-cross/bin/Windows/Debug/cache0 -mindepth 1 -delete`
|
||||
* `find xenia-canary/build-cross/bin/Windows/Debug/cache1 -mindepth 1 -delete`
|
||||
* `find ~/.local/share/xenia-rs/cache -mindepth 1 -delete`
|
||||
3. Cold ours run:
|
||||
`./xenia-rs/target/release/xrs-c12 exec --phase-a-event-log
|
||||
/tmp/ours-cold-c12-v2.jsonl -n 50000000 "<ISO>"`
|
||||
(~3 s wallclock).
|
||||
4. Cold canary run (background, killed after 5M+ canary events):
|
||||
`cd xenia-canary/build-cross/bin/Windows/Debug &&
|
||||
/usr/bin/wine ./xc-c12.exe --mute=true
|
||||
--phase_a_event_log_path=canary-cold-c12-v2.jsonl "<ISO>"`
|
||||
Killed via `wineserver -k` after ~120 s wallclock once the jsonl
|
||||
reached ~6 M lines (250 k tid=6 events buffered).
|
||||
5. Truncate canary jsonl per-tid (cap tid=6 at 250 k, other tids at
|
||||
20 k) to keep the diff tractable. Truncated file is 119 MB / 533 k
|
||||
lines (kept) — the differ runs on this.
|
||||
6. Diff:
|
||||
`python3 xenia-rs/tools/diff-events/diff_events.py
|
||||
--canary <truncated> --ours /tmp/ours-cold-c12-v2.jsonl
|
||||
--out /tmp/diff-c12-cold-v2.md`.
|
||||
7. Restore canary's binary-dir cache from backup so future runs
|
||||
keep the oracle intact.
|
||||
|
||||
## Canonical post-C+12 cold-vs-cold matched-prefix table
|
||||
|
||||
| canary_tid | ours_tid | matched | canary_total | ours_total | first_divergence_at | notes |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 6 | 1 | **103862** | 250000 | 108471 | 103862 | **main chain — +1458 events vs C+11.1**. New divergence: NtCreateFile `game:\dat\files.tbl` returns canary=STATUS_OBJECT_NAME_NOT_FOUND (0xC0000034) / ours=STATUS_SUCCESS (synth-empty stub for missing disc files; AUDIT-006 fallback). |
|
||||
| 4 | 11 | 9 | 20000 | 9 | — | sister — no divergence within the 9 ours events |
|
||||
| 7 | 2 | 29 | 29 | 30 | — | sister — no divergence within the 29 canary events |
|
||||
| 12 | 7 | 2 | 10532 | 3 | 2 | sister — pre-existing KeWaitForSingleObject return (TIMEOUT/SUCCESS); NOT regressed |
|
||||
| 14 | 9 | 39 | 20000 | 75 | 39 | sister — pre-existing XAudio init divergence; NOT regressed |
|
||||
| 15 | 10 | 15 | 20000 | 15 | — | sister — no divergence within the 15 ours events |
|
||||
|
||||
## Gate matrix
|
||||
|
||||
| gate | result | notes |
|
||||
|---|---|---|
|
||||
| Build (cargo build --release) | PASS | 1 unrelated `dead_code` warning, no errors |
|
||||
| Kernel tests (172 → 177) | PASS | 5 new C+12 tests, all pass |
|
||||
| Full workspace tests | PASS | 702 tests pass (sum of all crates) |
|
||||
| Determinism — 3× cold stable-digest | PASS | `ad4f74ee324fdedb0bfdd4cc4c6468e9` (all 3) — IDENTICAL to C+11.1 baseline |
|
||||
| `--stable-digest` digest unchanged | PASS | C+12 fix is observation-only on the stable counters |
|
||||
| Phase B `image_loaded_sha256` | PASS | `ea8d160e9369328a5b922258a92113efb8d7ce3e1a5c12cc521e375985c91c18` unchanged |
|
||||
| Cold-vs-cold matched prefix | PASS | **102404 → 103862 (+1458)** on main chain |
|
||||
| Sister-chain regression check | PASS | All 5 sister chains unchanged |
|
||||
|
||||
## Source data
|
||||
|
||||
| file | size | notes |
|
||||
|---|---|---|
|
||||
| `canary-cold.jsonl` | 1.4 GB | full canary cold run, 6.0 M lines (post-kill) |
|
||||
| `canary-cold-tid6-250k.jsonl` | 119 MB | per-tid truncated for diff (tid 6: 250 k, others: 20 k cap) |
|
||||
| `ours-cold.jsonl` | 28 MB | ours cold run, 121 k tid=1 events |
|
||||
| `diff-cold-vs-cold.md` | 8 KB | the `diff_events.py` output |
|
||||
| `canary-binary-cache-pre-wipe.tar.gz` | 4.7 MB | canary's 23-file oracle preserved before wipe (binary-dir!) |
|
||||
| `digest-cold-stable-{1,2,3}.json` | <1 KB each | 3 determinism runs, identical hash |
|
||||
| `phase-b-snap/ours/` | ~5 MB | Phase B 5-file snapshot with `image_loaded_sha256` |
|
||||
|
||||
## Notes
|
||||
|
||||
* The +1458-event advance lands at a new tid=6 divergence:
|
||||
`NtCreateFile game:\dat\files.tbl` returns SUCCESS in ours because
|
||||
the disc dump doesn't ship this file but ours's `open_vfs_file`
|
||||
fallback synthesizes a 0-byte file (see `exports.rs:1399-1422`),
|
||||
while canary returns `STATUS_OBJECT_NAME_NOT_FOUND` since it has
|
||||
no equivalent stub. This is a long-standing intentional fallback
|
||||
(rationale: "synthesize empty file lets the game's existence
|
||||
probe succeed for files the rip lacks") that now becomes the
|
||||
next divergence target.
|
||||
* The synth-empty fallback was originally introduced to prevent
|
||||
`XamShowDirtyDiscErrorUI` on missing disc files — removing it
|
||||
outright might regress past audits. Phase C+13 should investigate
|
||||
whether Sylpheed actually needs the file or whether the dirty-disc
|
||||
path is now correctly gated by other logic.
|
||||
* Stable digest unchanged confirms the C+12 fix is a **pure observation
|
||||
change**: the in-memory entry tree and the `nt_query_full_attributes_
|
||||
file` rewrite affect only the kernel's response on `cache:` lookup
|
||||
probes, not the per-instruction execution path observed by the
|
||||
digest. The 1458-event advance is the kernel-export-side effect.
|
||||
Reference in New Issue
Block a user