Skip to content

Latest commit

 

History

History
763 lines (607 loc) · 37.3 KB

File metadata and controls

763 lines (607 loc) · 37.3 KB

TFTMAC Developer Record

CURRENT DEV ENGINEERING AUTHORITY — 2026-09-11. Read facts.md first, then project.md, then CHANGELOG.md before using this engineering map. Older material below remains historical evidence only when it conflicts with those current records.

Development baseline: current verified working configuration DEV-B8-WIN-01 on TFTMAC DEV 2.3.0 build 8 / StockShadow. Effective DEV runtime: 1920×1080 / 320 dpi / 60 Hz, 8 vCPU, 6144 MiB (6 GiB), host GPU/CoreAudio, OpenGL ES through ANGLE, ADB/console/controller 5041/5586/8556. Protected Control: separate immutable normal-play/LKG reference; historical 6-vCPU/5120-MiB Control values are not the DEV baseline. Active campaign model: results-first, one hypothesis at a time, integrating only verified net improvements and testing the next factor on the latest verified winner. Current winner: DEV-B8-WIN-01 removes syncMonolithicPipelinesToBlobCache while retaining multifile cache and disabled preferSubmitAtFBOBoundary. Primary objective: accumulate repeatable small and large net improvements in useful gameplay performance/system efficiency, one exposed setting at a time, until the combined DEV line can hold continuous useful 60 FPS without correctness, login, audio, memory, launch, or cleanup regression.

This is the engineering working file. It contains code ownership, measurement contracts, confirmed and rejected experiments, active hypotheses, and the next implementation gates. Facts that must not drift live in facts.md; project history and handoff live in project.md; exact full-run/A/B formulas and current findings live in benchmark.md.

1. Developer charter

We are not trying to prove that frame loss exists; the complete automatic run has already established it. Development must process all captured data, identify the first boundary that becomes late, change an owned boundary, and demonstrate a repeatable whole-run gain toward continuous 60 FPS without correctness, login, audio, memory, launch, or cleanup regression.

Rules:

  1. Preserve the working launcher/runtime/app before changing performance code.
  2. Change one attributable factor per candidate unless an explicitly named screening composite is being tested.
  3. Record requested, effective, and observed state separately.
  4. Use exact TFT SurfaceFlinger actual-present intervals as gameplay frame truth.
  5. Treat SRC, OUT, guest actual-present, and panel visibility as separate clocks.
  6. Averages never override 1% low, p95/p99, severe stalls, or the player's visible-stutter report.
  7. Do not claim Unreal, ANGLE, ASG, gfxstream, MoltenVK, Metal, or the final presenter caused a stall until that boundary is the first valid divergence.
  8. Do not modify Riot's signed package, shaders, credentials, or process.
  9. Retain negative results so they are not recycled as “new” ideas.
  10. A launch receipt proves setup, not performance.
  11. Before finalizing any plan or change, re-read facts.md and project.md; if newer evidence conflicts, validate it and reconcile those authority files before finalization.
  12. Promotion is based on verified repeatable net improvement, not mean FPS alone; p95/p99/worst-frame latency, jank, missed-vsync, CPU/RHI efficiency, memory behavior, stalls, responsiveness and stability all count. There is no fixed positive-gain floor: small clean gains are intentionally eligible so they can compound.
  13. A verified win becomes the next DEV-B8-WIN-## baseline even when the gain is small; an unverified/inconclusive/regressing candidate is logged, rolled back, and not integrated.
  14. Do not declare a selected managed change complete with accidental dirty Git state.
  15. OvernightLab telemetry is retained across minor configuration drift; comparability/promotion eligibility is separate from whether the data is worth keeping. Core client/RHI mismatch is data-only and cannot promote the current DEV line.
  16. OvernightLab normal control always starts from the latest verified DEV winner; historical LKG/global-sync and rejected candidates remain cataloged evidence, not automatic queue entries.

Build 8 process-observer invariant: invoke Android pidof as direct ADB arguments (adb ... shell pidof com.riotgames.league.teamfighttactics). Do not route this through an unquoted sh -c argument: live acceptance proved that form can discard the package argument, leave game_pid null, and suppress the periodic stack-receipt refresh even while layer-based frame logging continues.

“Write a driver” in this project means implementing an owned, measured adapter or scheduling/transport/cache change in TFTMAC, gfxstream/AEMU, ANGLE, or MoltenVK when the evidence names that owner. It does not mean overclocking the M4, modifying Riot's signed shaders, or adding an unmeasured kernel extension.

2. Runtime and code ownership map

Boundary Owner Current implementation
macOS application lifecycle TFTMAC tftmac/App/TFTMACApplication.swift, AppCoordinator.swift
native window/fullscreen TFTMAC tftmac/App/MainWindowController.swift
performance settings UI TFTMAC tftmac/App/RuntimeSettingsWindowController.swift
Metal output and Mac input capture TFTMAC tftmac/Presentation/EmbeddedEmulatorView.swift
frame contracts/geometry TFTMAC FrameContract.swift, ViewportMapper.swift, TouchInput.swift
runtime/ADB/controller orchestration TFTMAC tftmac/Runtime/TFTMACRuntime.swift
profiles/configuration hashes TFTMAC tftmac/Runtime/RuntimeProfile.swift
AVD mutation/rollback TFTMAC AVDTransactionGuard.swift
exclusive runtime ownership TFTMAC RuntimeLease.swift
exact game-frame windows TFTMAC GameFrameTelemetry.swift
signal classification TFTMAC TelemetrySignalClassifier.swift
combat persistence/decision TFTMAC CombatBenchmarkStore.swift, CombatBenchmarkAnalysis.swift
logged-in-session emulator launch packaged host RuntimeHost/main.c
controller wire contract Android Emulator Vendor/AndroidEmulator/emulator_controller.proto, generated Swift
Unreal game workload Riot/TFT official package; observe only
GLES-to-Vulkan translation ANGLE emulator/runtime component
guest-to-host command transport gfxstream/ASG emulator/runtime component
Vulkan-to-Metal translation MoltenVK emulator/runtime component
GPU execution Apple Metal/M4 host OS/hardware
official delivery/auth Google Play/Riot official guest UI only

3. Current DEV winner and historical comparison candidates

Current DEV working winner — DEV-B8-WIN-01

app: /Applications/TFTMAC DEV.app / com.flashls1.tftmac.dev
runtime: advanced_diagnostics / TFTMAC_Diagnostic_StockShadow_R1
display: 1920x1080 @ 320 dpi / 60 Hz
effective guest: 8 vCPU / 6144 MiB
GPU/audio: host / CoreAudio
RHI: OpenGL ES through ANGLE
transport: virtio-gpu-asg
ASG: 1 MiB buffer / 16 KiB write step / 32 KiB ring / 800 us flush
ANGLE enabled: exposeNonConformant*:exposeES32ForTesting
ANGLE disabled: preferSubmitAtFBOBoundary
cache: multifile ON; syncMonolithicPipelinesToBlobCache REMOVED
TFT: 18.1-5423749 / versionCode 8423749

This is the baseline for the next optimization candidate. The sealed AVD file's 6/5120 values are restoration state, not the effective DEV launch.

Protected Control — historical comparison only

preset: control
display: 1920x1080 @ 320 dpi / 60 Hz
guest: 6 vCPU / 5120 MiB
TFT: High / 60 FPS / Performance Mode OFF
GPU/audio: host / CoreAudio
transport: virtio-gpu-asg
ASG: 1 MiB buffer / 16 KiB write step / 32 KiB ring / 800 us flush
ANGLE enabled: exposeNonConformantExtensionsAndVersions:exposeES32ForTesting
ANGLE disabled: preferSubmitAtFBOBoundary
MoltenVK: async submit / 64 active command buffers / fast math

Combat Latency A — historical rejected candidate

preset: combat_latency_a
all Control graphics, CPU, RAM, display, audio and transport values unchanged
LSSupportsGameMode: true
packaged host requests QOS_CLASS_USER_INTERACTIVE before execv
host records requested, set result, effective class and relative priority

Current direct receipt:

requested=user_interactive
set_result=0
pre_exec_effective=user_interactive
relative_priority=0
QEMU child-thread inheritance=NOT_CLAIMED_WITHOUT_COMBAT_EVIDENCE

The candidate configuration SHA-256 is 05039d1fd0987f46fc7da8de5f483d8c7ffaf8f39bd1eaecdd1aee11603bbb07. It passed launch/readiness, but the 2026-09-02 severe run delivered 26.446 weighted FPS, 2.770 FPS 1% low, 117.088 ms p95, and 21.037% severe intervals. The immediately restored Control run delivered 47.384 weighted FPS, 7.870 FPS 1% low, 34.002 ms p95, and 1.429% severe intervals. The workloads were not formally matched, so QoS alone is not assigned causality; the candidate is still rejected because it produced no usable normal-play benefit.

Separate Control and DEV launch products

Desktop TFTMAC.app
  -> /Applications/TFTMAC Control Launcher.app
  -> unchanged /Applications/TFTMAC.app
  -> com.flashls1.tftmac
  -> control / TFT_Ultra_Tablet / 5038 + 5582 + 8554

Desktop TFTMAC DEV.app
  -> /Applications/TFTMAC DEV.app
  -> com.flashls1.tftmac.dev
  -> advanced_diagnostics / TFTMAC_Diagnostic_StockShadow_R1 / 5041 + 5586 + 8556

DevLauncher/main.c is the minimal mode-selecting wrapper. It exports TFTMAC_RUNTIME_MODE=advanced_diagnostics and execs the separately packaged TFTMACDEVCore. scripts/build-dev-launcher.command builds/signs the isolated bundle and packages its generated DEV artwork. scripts/install-desktop-launchers.command verifies the protected Control hashes before and after installing DEV, the signed Control unlock wrapper, and the two Desktop symlinks. The PIN remains in Keychain and is sent to Control only through an interactive ADB shell stdin channel pinned to 5038/emulator-5582, never in process arguments. The shared global runtime lease is the collision guard.

The DEV AVD accepts the logged-in user's normal ADB key and reaches device without ADB_VENDOR_KEYS injection. R11/API 37 remains historical failed-first-frame evidence. The current physical stock-shadow clone passed three consecutive native-frame launches and is the only DEV baseline permitted for screening. It remains an engineering launcher and cannot replace Control.

4. Graphics pipeline and observability

Unreal OpenGL ES render/RHI (current dedicated engine-log receipt)
  -> ANGLE GLES-to-Vulkan translation
  -> guest Vulkan/ranchu
  -> gfxstream encoder + ASG guest transport
  -> host gfxstream decode/queues
  -> host Vulkan submit / MoltenVK translation
  -> Metal command buffer/GPU completion
  -> Android SurfaceFlinger actual-present
  -> EmulatorController completed RGBA image
  -> TFTMAC mailbox/Metal presenter
  -> macOS drawable completion

ANGLE is a verified current node in the DEV game route. The dedicated engine log selects OPENGL_ES_ANGLE; lower-stack Vulkan evidence describes ANGLE/gfxstream's backend rather than proving direct Unreal Vulkan. Direct Unreal Vulkan remains a rejected fast-pass candidate after compatibility failures.

What each signal can and cannot prove

Signal Can prove Cannot prove alone
TFT SurfaceFlinger actual-present timestamps player-facing guest frame cadence and stalls which upstream component caused lateness
SRC distinct-image rate completed images reaching TFTMAC Unreal simulation/render timing
hidden native-presenter receipt correctness/regression context only game-frame or emulator GPU ownership
QEMU CPU/RSS host emulator load/pressure direction exact worker or serialized wait owner
guest TFT PID/memory process lifetime and memory pressure GPU/transport stall owner
SurfaceFlinger HWC/GPU misses display-composition pressure ASG/MoltenVK root cause
logcat aggregate occurrence of known failure classes absence of all hidden stalls
Perfetto scheduler/GPU/process trace time-correlated execution and waits valid cross-host cause when clock RTT/observer gate fails
requested emulator/MoltenVK flags intended configuration effective internal behavior

The final presenter is a locked non-bottleneck for current work. Preserve its raw correctness receipt, but do not display, rank, or optimize it. It does not distinguish Unreal, ASG, gfxstream, or MoltenVK.

5. SQL and capture contract

benchmark.md is authoritative for legal time-domain joins, raw-interval and continuous-60 formulas, complete-timeline analysis, exact SQL, AI output shape, and promotion rules. The queries below are an operational index, not an alternate formula specification.

Session authority:

~/Library/Application Support/TFTMAC/Captures/<session-id>/
  TFTMAC_NATIVE_RUNTIME.sqlite

Persistent comparison authority:

~/Library/Application Support/TFTMAC/TFTMAC_LAB.sqlite

Required cadences

Cadence Measurements
1 second exact TFT FPS, 1% low, p50/p95/p99/max, jank, severe, missed-vsync equivalents, layer identity/history status
1 second source freshness/repetition/loss; native presenter submit/complete/reuse/errors/latency/GPU time
5 seconds QEMU CPU/RSS, TFT PID/activity, guest memory/swap, host memory/compression/swap/pageouts, thermal/power
30 seconds host/guest clock sync, renderer/feature receipts, SurfaceFlinger, display geometry/refresh, audio
event automatic graphics-run/process/layer/stack-receipt/incident events; optional benchmark/stutter/trace and package/ANR/OOM/crash/correctness events
boundary complete app/runtime/emulator/system-image/TFT/profile/input/audio identity

Privacy contract

Store no typed text, credential values, screenshots of login forms, raw frame payloads, tokens, cookies, PINs, CAPTCHA, MFA, or unrelated app data. Raw logcat and trace files stay local and require sanitization before any excerpt leaves the Mac.

Useful SQL

-- Exact session and frozen configuration
SELECT * FROM sessions;
SELECT receipt_key, receipt_value, confidence
FROM runtime_receipts ORDER BY id;

-- Actual TFT frame truth
SELECT started_monotonic_ns, status, unavailable_reason,
       effective_fps, one_percent_low_fps,
       p50_interval_ms, p95_interval_ms, p99_interval_ms,
       maximum_interval_ms, jank_count, severe_count,
       missed_vsync_equivalents
FROM game_frame_windows
ORDER BY started_monotonic_ns;

-- Separate upstream freshness from final presentation
SELECT * FROM stream_freshness_windows ORDER BY started_monotonic_ns;
SELECT * FROM host_presentation_windows ORDER BY started_monotonic_ns;

-- User/benchmark boundaries
SELECT kind, observed_utc, monotonic_ns, payload_json
FROM events
WHERE kind IN ('MATCH_ENTRY','COMBAT_START','VISIBLE_STUTTER','MATCH_END',
               'COMBAT_BENCHMARK_STARTED','COMBAT_BENCHMARK_ENDED')
ORDER BY monotonic_ns;

-- Fault counts without exposing raw log lines
SELECT * FROM logcat_aggregates
WHERE anr_count + fatal_count + memory_kill_count + input_timeout_count
    + angle_warning_count + vulkan_warning_count + audio_error_count > 0;

SELECT * FROM pipeline_log_aggregates
WHERE gfxstream_warning_count + asg_stall_count + vulkan_error_count
    + moltenvk_warning_count + shader_error_count + fence_timeout_count > 0;

-- Durable combat evidence
SELECT benchmark_id, session_id, preset_id, configuration_sha256,
       duration_seconds, surface_availability, clock_coverage,
       p95_clock_rtt_ms, correctness_passed, weighted_fps,
       one_percent_low_fps, p95_interval_ms, p99_interval_ms,
       max_interval_ms, jank_rate, severe_rate,
       observer_overhead_invalid, valid, invalid_reason
FROM combat_benchmarks;

SELECT * FROM combat_incidents ORDER BY observed_monotonic_ns;
SELECT * FROM combat_comparisons ORDER BY rowid;

6. Full-run and bounded A/B validity and decisions

Full match

  • Markers are optional user annotations. Automatic graphics_runs are the primary full-session record and remain valid without any marker.
  • Full runs process every frame and every resource/pipeline sample and are required before normal-play promotion.
  • No semantic phase markers are required. Fixed intervals and rolling windows expose every sustained under-60 period directly.
  • A bad clock gate leaves direct guest-frame results valid but makes cross-host ownership UNKNOWN.
  • A full candidate run without a compatible Control is a baseline, not an A/B decision.

Valid run

  • at least 300 seconds of representative continuous gameplay;
  • automatic end at 480 seconds;
  • at least 95% exact TFT SurfaceView coverage;
  • at least 95% clock coverage;
  • stable semantic layer identity;
  • untruncated frame history;
  • same current TFT package and comparison configuration;
  • correctness passed;
  • clock RTT at most 10 ms for any cross-host ordering claim.

Dynamic SurfaceFlinger tokens differ after every process launch. Control matching must compare the stable semantic identity—package, activity, SurfaceView/BLAST role—not the ephemeral token prefix/suffix.

Trace policy

  • one 20-second/32-MiB trace at benchmark start;
  • up to two 15-second/32-MiB incident traces;
  • automatic trigger requires two adjacent bad one-second windows;
  • bad window: 1% low below 30 FPS, p99 at least 50 ms, or severe stalls;
  • 120-second cooldown; no concurrent traces;
  • SHA-256 seal and normalize with pinned trace_processor_shell v58.2;
  • if trace overhead changes frame metrics by more than 5%, performance remains useful but causal conclusions become OBSERVER_OVERHEAD_INVALID.

Decision engine

Decision Rule
HOME_RUN standout broad win: 1% low +20%, jank and severe each -30% relative, and either weighted FPS +10% or p95 interval -15%, without a material veto
PROMISING any valid directional gain in weighted FPS, 1% low, both p95/p99 tails, or smoothness rates when no material regression/correctness veto fires; no +5% positive floor
REJECT correctness/usability failure or material regression: weighted FPS -5%, 1% low -10%, p95/p99 interval +10% worse, or an equivalent operational veto
INCONCLUSIVE invalid/mismatched workload, coverage, clock, observer, or valid evidence with no directional signal

Any HOME_RUN/PROMISING result needs a five-minute cold confirmation before becoming the next DEV winner. Rollback is select the latest verified winner and restart. A failed active candidate records the rejection/failure and restores that winner automatically.

Relative decisions select the better implementation; they do not lower the goal. Small verified wins are intentionally retained and compounded. Report TARGET_NOT_MET until a complete automatic run holds at least 60 useful FPS throughout with no missed-vsync equivalents or severe stalls.

7. Retained results

Historical campaign winners

Candidate Result Decision
ASG vs pipe 40.1 FPS / 34.85 ms p95 vs 29.6 / 49.75 at same stage keep ASG
67% effects/LOD 45.20 / 38.50 / 33.80 FPS at Trial 1-2/1-5/1-8 historical winner
ASG write step 16 KiB 41.3–43.0 / 34.1–35.1 at 1-5/1-8; paired 4 KiB 38.0 / 32.8 keep 16 KiB
ANGLE preferSubmitAtFBOBoundary disabled 46.90 / 36.10 / 29.60 first pass retained in current stack; old run alone was provisional

These were collected on the historical M1 Max/userdebug campaign. Do not use the numbers as M4 native Build 7 measurements.

Home Run A rejection

Metric Value
Duration 480.646 s
Weighted FPS 56.665
1% low 17.698 FPS
p50 / p95 / p99 16.703 / 21.760 / 34.335 ms
Maximum 517.488 ms
Jank / severe rate 4.554% / 0.290%
Incident 1% lows 1.932 and 4.629 FPS
Validity invalid for comparison/cause: clock RTT too high; observer overhead invalid
Usability user rejected as worst-ever experience

The configuration combined Riot Performance Mode Beta with NativeTextureDecompression and NoDelayCloseColorBuffer; formal evidence cannot allocate blame among those factors. Operationally, the complete preset is barred and should not be decomposed unless new evidence gives a specific reason.

Build 7 Combat Latency A marked full run

Metric Value
Duration 1,895.054 s / 31m35.054s
Exact actual-present intervals 93,724
Weighted FPS 49.449
1% low 16.300 FPS
p50 / p95 / p99 16.965 / 33.822 / 48.746 ms
Maximum 1,254.162 ms
Jank / severe rate 19.110% / 0.610%
Over-60-budget intervals 58,925 / 62.871%
One-second windows below 60 FPS 1,599 of 1,693 / 94.448%
Total budget overrun / longest miss run 357,921.976 ms / 325 intervals
Exact-layer coverage/history 100% measured overlap / no truncation
Final Metal output 59.968 FPS mean; zero drawable/command errors; 3.267 ms max GPU time
Repeated-source presentations 23,231
Clock 97.494% in-range bracket; 86.757 ms p95 RTT
Decision full-run candidate baseline; no matched Control; cross-host cause UNKNOWN

This is direct proof that the current run does not hold 60 FPS and that final OUT cadence masks repeated upstream frames. It does not prove whether Combat Latency A improved or regressed against Control. Complete formulas, the entire timeline, resources, and claim limits are retained in benchmark.md.

8. Negative-result ledger

Do not repeat these without a changed mechanism and explicit new evidence:

Candidate Retained reason
pipe transport materially slower than ASG
MoltenVK 128 strong first run failed cold/sustained reproduction; worse tails
MoltenVK 256 incomplete and included 133 ms frame
synchronous MoltenVK submit about -10.3% in retained input test
guest submit thread regression
shader prewarm / submit+prewarm failed promotion
upstream ASG screen failed promotion
50% scale no complete advantage over 67% profile
isolated/extreme effects or LOD neutral/incomplete/regressive tails
ASG 2/4 ms flush inconsistent or worse tail/reproduction
ASG 8/32 KiB steps failed screen; 32 KiB long frame
ASG 64/128 KiB rings no reproducible gain
ASG 512 KiB buffer two startup failures, Failed to unbox VkPipeline
VirtioGpuNativeSync regression
VirtioGpuNext neutral
descriptor batching disabled regression; keep batching
forced half-rate skeletal animation worse tails
r.OneFrameThreadLag=0 -21.9%
disabled async composition slower, no proven latency gain
explicit native swapchain no-op/not promoted
MSAA2 black 3D pass
material quality 1 neutral/noisier
active-consumer host patch 11.2 FPS / 334 ms p95 lobby regression
native GLES 3.0/3.1 crash/capability failure
direct TFT Vulkan did not solve verified problem
extra RAM / eighth vCPU did not solve verified problem
audio disabled neutral/slower; sound required
Riot Performance Mode Beta direct user rejection and terrible incident tails

9. Research council and model evidence

Specialist work was performed across Unreal, ANGLE, gfxstream/ASG, MoltenVK, Metal, and transferable Fortnite/Unreal behavior. ZoeMC v0.2 ranked 10,000 modeled architecture worlds. Its priors were subjective, so its output is a hypothesis queue—not a measured performance result.

One major branch was resolved empirically: authenticated raw gRPC can deliver a correct 1920×1080 image and native input. That removes zero-copy/MMAP as a prerequisite. The council's remaining useful output is the strict ownership map, the requirement for fencing before MMAP, and the ordering of frame correlation before deeper transport/translation patches.

Fortnite/Unreal sources may inform shader/pipeline-cache behavior, trace categories, device-profile reasoning, and render-thread/RHI hypotheses. They do not establish which path the current signed TFT build chose or authorize shader replacement.

10. Active hypotheses and code gates

H1 — Combat Latency A / host scheduling

Mechanism: the emulator launch thread may enter QEMU with a latency-oriented QoS class, reducing scheduling delay in critical host work.

Implemented: RuntimeHost/main.c, profile/receipt/rollback in native Swift, Game Mode eligibility, unit tests.

Evidence now held: historical candidate evidence plus the latest automatic Build 8 run with exact actual-present, source, correctness-context presenter, and stack receipts.

Status: DEFERRED / NOT CURRENT ACTION. The preset is observed but not promoted. Do not spend the next development cycle on another broad scheduling comparison while the internal path remains uninstrumented.

Accept: HOME_RUN/PROMISING plus cold confirmation. Reject: no gain, worse tails, or any correctness/login/audio/cleanup issue. Critical unknown: QEMU worker inheritance and worker-specific scheduling.

H2 — advanced causal work-ID instrumentation

Mechanism: an allocation-free, source-instrumented work-ID ring carries owned transport work through guest Vulkan encode, ASG/gfxstream receipt, decoder, host Vulkan submit, MoltenVK enqueue, Metal completion, and Android buffer release. It names the earliest owned divergent site or reports the exact unowned/missing boundary as UNKNOWN.

Implementation contract:

capacity sized from measured submit rate for five seconds of prehistory
no allocation on render/decoder hot paths
transport work ID + generation + overwrite/loss counter
guest submit timestamp and ASG write/flush state
host receipt/decode/queue timestamp
Vulkan submit, MoltenVK enqueue, and Metal completion timestamp
QSRI/color-buffer release timestamp
queue depth at each owned handoff
static source-site ID mapped to commit/blob/function/line in a sealed manifest

Status: FULLY IMPLEMENTED AND LIVE-ACCEPTED (2026-09-03). The timeline-semaphore submit sideband (VK_KHR_timeline_semaphore passing {0, frame + 1} across two signal semaphores) marshals intact across goldfish ASG into the host. Gfxstream decodes this in OP_vkQueueSubmitAsyncGOOGLE (Sites 1001 instant, 1002 begin/end), and MoltenVK intercepts vkQueueSubmit (Sites 2002 entry, 2003 begin/end, 2004 Metal commit, 2005 GPU completion callback).

Live acceptance run causal-hook-timeline-20260903-r6 recorded 99,480 events across 15 active threads, producing 10,796 fully correlated frames through all 6 sites with 0 losses, 0 overwrites, and 100% SHA-256 integrity. Host stage measurements:

  • Host Vulkan Submit (Site 1002): mean 0.014 ms, p95 0.029 ms, p99 0.064 ms
  • MoltenVK Translation & Enqueue (Site 2003): mean 0.106 ms, p95 0.199 ms, p99 0.253 ms
  • Metal GPU Execution (Site 2005): mean 0.683 ms, p95 1.338 ms, p99 1.911 ms
  • Total Host Pipeline (Site 1001 -> 2005): mean 0.792 ms, p50 0.692 ms, p95 1.489 ms, max 4.005 ms.

First Divergent Bottleneck Isolation: The entire host graphics stack consumes <5% of the 16.667 ms budget for 60 FPS. The bottleneck causing gameplay frame drops and tails is located upstream of host decode: in guest Unreal simulation / Vulkan command recording and ASG transport serialization.

Gate: the 42-minute Build 8 automatic run established an unresolved internal causal gap below the SurfaceFlinger authority. Implement only in the isolated modern emu-main-dev manifest pinned at 2692acc620f6563b21995540656674faeb536cdc, never by replacing normal-play Build 8. Clock mapping, source/binary manifest, and overwrite counts are mandatory. Do not log shaders, frame contents, or credentials.

Outcome: identify the first valid owned divergent boundary. If lateness begins before host receipt, report UNREAL_OR_GUEST_UPSTREAM_UNKNOWN unless a diagnostic guest hook provides evidence. ANGLE is second-line only if a TFT receipt proves it is active.

H3 — adaptive ASG transport

Mechanism: fixed batching may either wake too often or hold a frame/release command too long. Adapt around frame boundaries and queue occupancy rather than blindly increasing buffers.

Candidate behavior:

  • flush immediately for frame boundary/release-image work;
  • batch while occupancy and latency are healthy;
  • wake consumer early as occupancy rises;
  • stop batching when guest waits for space;
  • prevent one context from monopolizing decode;
  • record occupancy, wait duration, wake reason, batch size, and loss.

Do not do: enlarge every ring/buffer. Larger prior values did not improve and 512 KiB write buffer failed startup.

Gate: frame-ID ring must first show lateness at ASG/host receipt.

H4 — gfxstream decoder/submission thread scheduling

Mechanism: critical decoder/render/submission workers may be delayed or serialized on the M4 host even when total CPU capacity exists.

Needed evidence: per-thread name/ID, runnable delay, wakeup-to-run latency, queue depth, lock/wait owner, and correlation to bad game-frame windows.

Candidate: apply explicit latency QoS to the identified critical worker only, not every QEMU thread. Keep I/O/background work lower. Verify effective class on the actual thread.

Gate: valid scheduler trace/frame ring shows the worker is the first late boundary. Reject if CPU contention, thermals, audio, input, or tails regress.

H5 — persistent MoltenVK pipeline cache

Mechanism: repeated SPIR-V-to-MSL/pipeline-state work may cause first-use or combat-effect stalls. Reusing equivalent pipelines could remove them.

Cache key must include: TFT package/build, shader/pipeline hash, MoltenVK build, M4 GPU identity, effective graphics configuration, and cache schema.

Instrumentation: pipeline lookup/create duration, hit/miss, translation time, Metal pipeline creation time, compile thread, warm/cold state, and invalidation.

Safety: no Riot shader modification; cache only owned translation products. Fail closed on version/hash mismatch. Bound disk size and support complete invalidations.

Gate: frame-ID/trace evidence places first lateness after host receipt and around pipeline creation. Blind prewarming remains rejected.

H6 — frame submission and pacing

Mechanism: too many/few frames in flight, release signaling, swapchain image count, queue bubbles, or commit cadence can produce poor tails without saturating the GPU.

Variables: present mode, swapchain images, frames in flight, fence polling vs callbacks, deferred commands, release-image signaling, command-buffer commit cadence, and host mailbox depth.

Evidence: queue depth, submit-to-complete, complete-to-present, repeated source, drawable errors, actual-present intervals.

Gate: isolate one factor; never reintroduce synchronous submit or 128/256 buffers without a new mechanism.

H7 — Vulkan/ANGLE capability and Unreal device selection

Mechanism: the official game may select a conservative or incompatible device profile based on exposed Vulkan/GLES/GPU/texture/surface capabilities.

Method: compare effective reported capabilities and live code path; implement only features that pass representative shader/render tests. Never lie that an unsupported feature exists.

Evidence needed: active TFT package/version, Vk/GLES identity/extensions, selected surface formats/present modes, shader/renderer warnings, and visual correctness.

Historical PBE DeviceProfiles are reference evidence only. Do not mount an old overlay into the current signed production client.

H8 — internal render resolution

Mechanism: fewer rendered pixels can help a truly GPU-fill-bound scene while TFTMAC still outputs fullscreen 1920×1080.

Current caution: live TFT SurfaceView has often been 1280×720 inside the 1920×1080 guest, and a historical 2560×1440/1600×900 A/B barely changed FPS. Lowering resolution may therefore reduce quality without fixing CPU/RHI/ transport stalls.

Gate: prove Metal/game GPU saturation or pixel-dependent scaling first. Test 100/83/75% one factor at a time, record exact SurfaceView buffer size, and reject quality loss without tail gain.

H9 — MMAP/shared-memory frame delivery

Mechanism: remove the final raw gRPC copy or reduce frame age/host CPU.

Preconditions: producer readiness/fencing, stable stride/format/color, bounded ownership, no overwrite while Metal reads, tear/corruption detector, sequence/age measurement, and clean rollback to raw gRPC.

Gate: isolated A/B shows material CPU/frame-age gain with zero integrity or input regression. Raw gRPC remains production control otherwise.

H10 — startup phase latency

User observation: native startup felt slow. No valid phase budget has yet been measured.

Instrumentation: record duration for lease/preflight, ADB server, host/QEMU launch, controller discovery, Android boot, power gate, secure unlock wait, package receipt, logger health, TFT process start, and first ready frame.

Code rule: optimize only the measured slow owned phase. Never move logging after launch, bypass ADB authorization, skip the power/package/controller gates, or weaken AVD rollback merely to report a smaller startup number.

11. Fastest next development sequence

  1. Preserve Build 8 capture 2026-08-31T22-30-26.086Z-8df607d7-a34a-4e2a-b00d-739aa3143200 by ID, size, hash, and normalized metrics only; keep the raw database private.
  2. Keep stock Build 8 as normal-play authority and keep the final Mac presenter out of displayed/ranked causal views.
  3. Complete the already-started H2 work-ID/source-site integration only in the isolated modern emu-main-dev source runtime, with parity, clock, loss, stream-seal, and observer-overhead gates.
  4. Have the diagnostic run identify the first owned divergent boundary or name the exact missing/unowned boundary as UNKNOWN.
  5. Use that evidence to choose exactly one owned performance change from H3, H4, H5, or H6.
  6. Screen that one change with a bounded A/B when useful, then require a complete automatic full run and direct player/correctness acceptance before promotion.

The current run has already shown that Build 8 boundary joins are insufficient for internal attribution. The work-ID ring is the shortest path to writing the correct deeper code instead of another blind emulator flag.

12. Login reliability track

Keep login reliability separate from graphics performance:

  • record exact Riot activity and WebView version;
  • primary click remains Android touch;
  • show_ime_with_hard_keyboard=0 is the known recovered state;
  • if MobileFREWebViewActivity hits an input-dispatch ANR, restart only Riot's process and reopen the official Splash activity;
  • do not restart a healthy emulator or destroy the current AVD/session;
  • never inspect or persist credential values;
  • count ANR/input timeouts in SQL and invalidate any affected correctness run.

The repository contains older credential-automation helpers from historical work. They conflict with the current strict manual-auth boundary and must not be used as product behavior or benchmark prerequisites.

13. Build, test, release, and rollback

Authoritative commands:

scripts/test-native-app.command
scripts/build-native-app.command
scripts/verify-tftmac.command
scripts/verify-installed-runtime.command
scripts/summarize-native-session.command

Toolchain:

Xcode: /Applications/Xcode-26.6.0.app
Swift: 6.3.3
target: arm64 macOS
app: /Applications/TFTMAC.app
runtime: /Volumes/MAC MINI M4/TFTMAC/Runtime

Verification claims must be scoped:

  • unit tests prove parsers, configuration, comparison logic, and local contracts;
  • source verification proves the unsigned Release build and the current 54-test native suite;
  • installed-runtime verification proves current local hashes/runtime/signing; the 2026-09-02 post-repair check passed for both installed launchers;
  • launch receipts prove runtime readiness, not combat gain;
  • SQL combat comparison proves measured change, not internal cause when clock or observer gates fail;
  • user acceptance proves playability/experience, not the first software boundary.

Build 6 rollback was preserved at:

/Applications/TFTMAC.app.build6-backup-20260830-2150

Do not replace or restart the currently running app during live user gameplay. Apply restart-bound changes only after the user is out of a game and the current session can seal and restore its AVD transaction.

14. Current gaps to close

  • RESOLVED (2026-09-03): Causal work-ID tracing and lineage proven across all 6 host graphics boundaries (causal-hook-timeline-20260903-r6). Host graphics stack is <5% of 16.67 ms frame budget.
  • RESOLVED (2026-09-03): MoltenVK Global Persistent Pipeline Cache (moltenvk_pso.cache) and guest AOT compilation (scripts/prewarm-tft-gameplay.command) eliminating shader compile hitches.
  • RESOLVED (2026-09-04): 32-minute live match telemetry forensics (55.80 avg FPS, 58.6% locked at 60 FPS) and memory pressure audit (guest memory healthy at 1.7 GB free; host memory proved at risk if VM RAM increased).
  • RESOLVED (2026-09-04): 8-vCPU DEV routing (RuntimeModeAuthority.swift), cloth physics disabled (p.ClothPhysics=0), dynamic resolution enabled (r.DynamicRes.OperationMode=1), and PSO precompile pool tuned (r.pso.PrecompileThreadPoolSize=2).
  • RESOLVED (2026-09-04): Clean Quickboot snapshot shutdown implemented in stop() via am force-stop to avoid UNSUPPORTED_VK_APP.
  • Next live match verification with user on Desktop TFTMAC DEV.app under 8-vCPU profile.
  • Recurrent Riot WebView/IME reliability across future updates.
  • Public signing/notarization if distribution beyond this Mac becomes a goal.

The current engineering posture is: preserve the proven app, reject generic averages and recycled settings, and write the next code at the first boundary that the synchronized full-run data actually shows is late.