Native app spike (D238): SwiftUI + Metal vs web canvas in WebKit, macOS #217
Open
opened 2026-10-15 07:07:54 +00:00 by kayg
·
32 comments
No Branch/Tag specified
main
j470b-server-mesh-rejoin
mesh-compat-382
j444b-d381-key-wins-flood
j461b-macos-utun-reader-thread
j475b-remove-host-motion
fix-reconnect-new-link
j481-d380
dev
j479-mesh-soak
fix/j476-host-facts
j475-motion-pill-split
j470-mac-node-join
root-upgrade-d376
j474-review-merge
latency-targets-120hz
nightly-suite-shards
gotatun-pin-j469
macos-utun-reader-thread
fix-flood-echo-stall
wip/j416
motion-fast-ease-out
mesh-addhost-j259
takeover-close-terminals-d368
kbd-instant-followups
fix-trust-key-double-click
nightly-suite-partial-report
appwin-icons-j207
rusqlite-slice1
swipe-content-first-d374
mesh-mtu-381
addhost-instant-open
glass-contrast-d365-mock
glass-contrast-d365
signout-followups-442
fix-startup-toast-red
research-gotatun-matrix-j317
themes-sync-j304
fix-load-flakes
fix-nix-zig-patch
fix-compute01-browser-baseline
ratchet-size-baseline-419
predict-auto-d130
revoke-coverage-d367
nightly-suite-queue-timeout
nightly-browser-suite
fix-rustsec-2026-0459
fonts-ioskeley-obel
log-retention-d375
fix-kbd-no-anim-427
fix-dev-red-specs-2
takeover-proof-305-j205
wip/j410-server-pump
ui-consistency-d372
fix-osc52-clipboard
libghostty-vt-1.0
forget-retired-host-d369
j404-merge-426
fix-setup-lock-race
fix-touch-select-426
revoke-access-report-ui
fix-predictive-echo-specs
fix-selinux-agent-exec
wip/j395-checkpoint2
wip/j395
j391-review-scratch
ui-consistency-j195-deferred-rebased
fix-rustc-paths-421
decisions-wording-341
fix-install-suite-red
fix-dev-rtt-specs
fix-pending-removal-align
fix-privileged-skip
fix-install-suite-404
review-j368
mesh-dns-j254
revoke-access-report-d356b
revoke-privilege-round5
fix-removal-confirm
review-j360
gotatun-rotation-367
deps-refresh-340
review-j354
review-J351
review-j350
addhost-takeover-d359
revoke-report-items-347
revoke-end-sessions-d362
review-j348
size-mesh-ssh-346
size-trim-337
revoke-access-diff-d356
j259-pre-rebase-b06c5a6
j305-ended-at-start-spec
addhost-sudo-consent
fix-layout-real-specs-411
fix-shell-open-411
fix-console-hosts-373
fix-shell-exit
fuzz-host-name-353
fix-host-details-410
macos-filter-j197
research-gotatun-tricks
revoke-p3-j216l
stale-state-pill
revoke-followups-j216k
revoke-progress-j216e
backup/macos01-20261106/lume/j197
backup/macos01-20261106/lume/appwin-icons-j207-stash0
backup/macos01-20261106/claude/stash-0
backup/macos01-20261106/claude/stash-1
backup/macos01-20261106/claude/J80-macos-s1
backup/macos01-20261106/claude/J80
backup/macos01-20261106/claude/J80-slice1-20261102
backup/macos01-20261106/claude/J16b-appwin-on-dev
backup/macos01-20261106/claude/appwin-launch-idle-146
backup/macos01-20261106/claude/J80-s1-run
wip/j259
trust-285-p3c
runtime-lock-j216f
mesh-ssh-p3-j175
tun-proof-p3b
trust-285-p3
terminal-polish-j271
tun-proof-p3
ssh-install-flakes-j216i
fuzz-fixes-j264
trust-285-a
trust-285-b
restart-oversized-fixture-j198
backup/macos01-20261106/lume/appwin-icons-j207
restart-bound-j216h
up-preflight-p3-j198
backup/macos01-20261106/lume/j251
up-preflight-j198
wip/up-preflight-j198-j245-p2
wip/up-preflight-j198-j245-p1
agent-fsync-offloop-j196
wip/up-preflight-j198-j245
settings-offscreen-j231
wip/up-preflight-j198-j226-inspection
wip/j103f
themes-j206
wip/up-preflight-j198-j226
flakes-j216c
backup/macos01-20261106/claude/j197
flakes-j216b
backup/macos01-20261106/claude/j197-red
wip/up-preflight-j198-review
flakes-j216
backup/macos01-20261106/claude/appwin-icons-j207
engineering-j208b
appwin-mock-j209
toast-stack-j165
engineering-j208
decisions-d351
decisions-d350
decisions-d349
appearance-presets-mock-j129
decisions-d348
docs-audit-spec
doc-coverage-baseline-raise
decisions-d347
decisions-d346b
decisions-d346
j88h-profile
ui-consistency-j195-deferred
ui-consistency-j195
engineering-practices-j194
preferred-login-ui-j166
signin-pools-263-j174
macos-node-265-s1
decisions-d345
decisions-d344
proxy-cgroup-j164
verify-quick-fuzz-329
proxy-start-io-j168
timing-flakes-j163
up-263-s1
mcp-events-j147
verify-quick-fuzz-j158
proxy-p3-j159
agent-resource-j157-detect
wip/j103d-final
remote-cancel-hang-j155
proxy-traefik-281-j62d
j149-verify-quick
proxy-traefik-281-j62b
j150-drop-unnamed
wip/j79d-red-r4
wip/j103d-d332
rootless-toast-j142
wip/j103d-head
wip/j103d
j125c-mcp
macos-build-j136
backup/macos01-20261106/claude/j136
wip/j79d-red-cli
wip/j79d-red-server
j121-link-liveness
j118c-tracer-failures
wip/j79c-head
release-desktop-j131
j124c-signed-macos
wip/j79c-red-p3
wip/j79c-red-p23
wip/j79c-red-p22
merge-j128-check
perf-deferred-j128
sidebar-toggle-260
j127-shortcut-changed-dot
j125-mcp
j118-tracer-failures
j126-account-summary
settings-sections-mock-j92
j120-pinch-lock
sidebar-292
backup/macos01-20261106/claude/j120
taste-2026-11-03
row-actions-242-215
backup/macos01-20261106/claude/stash-0-untracked
backup/macos01-20261106/claude/J80-265-s1-run
backup/macos01-20261106/claude/J80-macos-s1-20261102
j112-canvas-commands
ui-no-overshoot-scroll
fix-recovery-restart
backup/macos01-20261106/claude/stash-1-untracked
taste-2026-11-02
size-baseline-ratchet
machine-cards-structure-j108
j109-boot-copy-mockups
fix-dev-red
wip/up-263-s1
j95b-settings-rows
proxy-traefik-281
j95-option-rows
docs-human-j91
docs-keys-palette
fix-flood-1013-270-j38d
mesh-ssh-s1
mesh-ssh-s0
addhost-d291-tunnel
test-stability-load
mesh-relay-220
repro-296
shim-thp-off-24
mesh-pins-258-v2
mesh-dns
signin-d311-merged
docs-pages
ui-size-283
fix-ui-batch-specs
wip/j12b-edge-update
gate-on-arm
fix-rename-sync-293
trust-285-j60b
fix-focus-ring-clip
integ-ui-1101
edge-update-v2
signin-d311
taste-2026-11-01
layout-per-tab-250
ui-approved-splitopt-224
ui-approved-splitopt-224-on-dev
icon-text-centre-282
ui-approved-189-212-216
research-reverse-proxy
transfer-budget-320
review-mesh-pins-258-r2
sidebar-pill-259
review-mesh-relay-220
wip/j12-edge-update-v2
nix-package
status-crash-loop-237
fix-dev-test-failures
fix-fixture-socket-path
wip/mesh-relay-220-pre-dev-advance-rebase
fix-canvas-side-clip
research-head-to-head
frosted-real-256
review-mesh-pins-258
wip/mesh-relay-220-pre-final-rebase
review-layout-per-tab-250-r2
broad-suite-triage
nix-devshell
review-status-crash-loop-237-r3
wip/nix-devshell-pre-p3
taste-frosted-real
wip/code-serve-demo-2026-10-30
wip/code-serve-glass-2026-10-30
wip/code-serve-clusters-2026-10-30
wip/code-merge-release94-dev-2026-10-30
wip/rproxy-delta-scratch-2026-10-30
wip/stale-note-257-staged-2026-10-30
wip/d241-size-staged-2026-10-30
review-broad-suite-207
wip/mesh-pins-258-pre-split
wip/mesh-relay-220-pre-rebase
mesh-measure-220
plan-211-update
review-edge-autoupdate-r3
perf24-reconnect
review-stale-note-r2
release-prod-live
d241-shell-marker
review-mesh-pins-server-258
review-revocation-r3
review-setup-token-r2
review-sync-journal-r3
wip/review-mesh-pins-258-prune-review-1995fee46
frosted-scroll-256
sync-journal-r3
revocation-per-account-wip
review-tokio-asyncfd-0386
review-sync-p3s
wip/stash-8by64-stash0-2026-10-30
mesh-drag-r2
setup-token-data-wip
release-9-4
auth-busy-1013
mesh-view-overlap
sync-p3s
review-auth-busy-wake
review-readd-r8-wip
mesh-drag-bounds
audit-auth-93
app-windows-stream-start
review-authority-cap-r3
app-windows-r7-measure
readd-minimal-r6
readd-minimal-r5
app-windows-r7-soak
readd-minimal-r4
app-windows-r7
app-windows-r6
readd-minimal-r3
readd-minimal-r2
readd-minimal
merge-release8-dev
review-busy-page-liveness-r2
review-busy-page-liveness
mesh-view-trim
review-authority-read-retry-r2
review-remove-uninstall-r2
release-retry-reattach
release-retry
review-remove-uninstall
review-authority-read-retry
app-windows-ship
mesh-autoswitch-p2
mesh-ssh
mesh-relay
mesh-macos-node
screen-and-control
session-labels
review-real-logins-r5
review-real-logins-r4
review-real-logins-r3
shim-memory-r2
review-real-logins-r2
shim-memory
shadow-addhost-instant
shadow-real-logins
shadow-same-session-flood
shadow-prod-perf-fix
hosts-from-server
app-windows-real
app-windows-transport
release-prod-6w
mesh-policy-verify
quiet-close-toast
dev-merge-r4
review-mesh-agent-transport
review-app-windows-transport
settings-roundtrip
review-release-pipeline-r4
mesh-agent-transport
ended-strip-fix
review-audit-ca-update-d244
settings-rows
phone-width
signout-clear
fix-restart-tests
dev-merge-rp
signer-hardening
review-audit-ca-update
terminal-fidelity
review-audit-ca-update-wip
mesh-integrate
review-mesh-agent-transport-515d3712
review-mesh-dataplane-feec1988
mesh-dataplane
signout
research-canvas-node
wip/review-renderer-cost
wip/review-terminal-fidelity
padlock-glyph
review-release-pipeline-2e95b689
phone-polish
sidebar-polish
inbox-generic
review-mesh-dataplane-378d4055
prod-batch
ui-inbox
ui-ca-unlock
ui-machine-sections
review-mesh-dataplane-a5f744fb
tls-session-prod
session-bounds-prod
fix-dead-session
session-bounds
tls-session
palette-polish
shortcuts-d222
research-appmeta
phone-gutter
ui-centre-button
wip/ui-centre-button
wip/tls-session
review-addhost-breakit
ui-platform
renderer-cost
remote-agents
mesh-api
ssh-bootstrap
prod-hotfix2
prod-fixes
review-remote-agents
review-mesh-dataplane
session-life
research-browser
review-mesh-api
research-capture
review-mesh-api-round3
review-mesh-api-round1
gate-stability
review-gate-stability
review-relay-direct
review-mesh-api-findings
proto-sessions
font-picker
proto-addhost
proto-windows
mesh-core
latency-gate
research-bsd
research-discovery
keytray-mods
mock-core
ui-tweaks
fix-motion-sel
fix-motion
integrate2
fix-robust
t-web
t-server
vt-ghostty
fix-snap-echo
t-web-auth
review-vt2
t-agent
lane-protocol
lane-shim
lane-auth
s1-base
s1-contracts
s1-workspace
No results found.
No labels
launch-qa
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
kayg/infraternal#217
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Owner-authorized throwaway measurement prototype on branch native-spike under research/native-spike. Compare 10/25/50 live terminals using the existing Rust VT core through a batched C ABI and the production tracer in WKWebView mock mode. Three repeats on the owner MacBook; raw receipts attached here. No foundational choice or product changes. Parent: D238 (no parent issue supplied).
Start: branch native-spike; base
498ebd34f3(origin/dev merge base). Read CLAUDE.md, DECISIONS D14/D88/D188/D238/D259, ARCHITECTURE, PROCESS and TASTE. No parent issue was supplied; #217 was created as requested. MacBook lock held by mac-hardware, started 2026-10-15T08:56:58+02:00; battery AC 100%. Mock finding: apps/tracer/src/canvas/mock/sessions.ts: one live terminal, other windows static previews. Will report this as a comparability limitation, not N live web terminals. No product code changes.Preparation finding: existing scripts/build-vt supports Linux targets only. research/native-spike/prepare_vt.py reuses its pinned archive/checksum and recipe, adding aarch64-macos plus a research-only ASCII grid export into a distinct cache. No engine or binding generator selected. Swift sources pass xcrun swiftc -typecheck with the installed macOS SDK. Available xctrace templates include Animation Hitches and Metal System Trace, but no named WebKit timeline template. Native instrumentation uses CADisplayLink plus drawable presentedTime; web uses rAF and a grid-change proxy, explicitly not input-to-photon. Mac preflight held and released the shared lock without opening app windows. Build-host VT tests/build queued through build-slot, now compiling.
Completed core boundary:
5cedb7b76, pushed to native-spike. Isolated research staticlib, no added dependencies and no product changes. Same pinned VT source as the shim; research adapter adds macOS and ASCII grid export. One bulk feed/read call for all N terminals, 80x24 cells each; history cap 17 MiB/terminal (850 MiB cap at N=50, lazy allocation). cargo fmt --check and clippy --all-targets -- -D warnings pass; real VT integration check passes. Initial test failure was an incorrect one-based cursor expectation and was corrected. Cross-build and tracer build remain in the host slot queue.Completed tests:
84c535180, pushed. Two real pinned-engine tests pass: independent focused input/bounded output, and partitioned control sequences with output canaries. fmt and clippy -D warnings pass. Completed recorder:396ac0d1e, pushed. Two real-PTY captures have identical manifests. Shell 52 B; source flood 1,048,576 B becomes 1,064,463 B after PTY newline expansion; redraw 1,463 B. Manifest/raw recordings: $HOME/.cache/codex-scratch/native-spike/evidence/streams/. These are deterministic command-generated captures, not a recorded human session.Finding: apps/tracer/test/mock-server.ts appendEchoOutput silently returns once echoOutputLength exceeds MAX_MOCK_OUTPUT (1 MiB), and the PTY flood alone is 1,064,463 B. The research-only bundler raises that existing reservoir to 8 MiB; product sources stay unchanged. Web replay now checks output_sequence increments for every chunk. This is an explicit backend-fixture difference. Other comparisons remain limited: web mock one live terminal plus N-1 previews; product layout/chrome/glyph sizes differ from the native grid. No N-live-web or renderer-only conclusion will be drawn. Build and Mac queues still occupied; no user action needed.
Functional N=50 smoke: xcodebuild Release succeeded; both modes delivered all 1,064,463 flood bytes and recorded 200 input samples without harness errors. Native had 0 dropped submissions. These are smoke receipts, not the three-repeat result. All 8 started app/server/service/capture PIDs are gone (each ps_exit=1 in cleanup.json).
OS window capture failed: "could not create image from window" in both modes. No permission or system setting was changed. Will capture only our own Metal canvas / WKWebView content in separate runs, label the difference, and omit capture from timing repeats.
Display finding: the Mac has two active 120 Hz screens; NSWindow default placement chose the main display. Measured repeats will explicitly use the built-in screen and record its display ID, current rendering geometry, visibility and physical display metadata. The external-display smoke is excluded from results.
smoke-external.tar.gz
Completed and pushed atomic steps:
579585bc9accounting;4ef8695cdnative renderer;097502404web host/replay;384951f97app entry/build;6128fcb75runner/analysis;c6e09f6b5methodology. Optional tracing now uses --no-prompt (f6077f56e); installed developer mode was already enabled. No system setting changed.Built-in-panel N=50 functional capture pair: xcodebuild Release passes; 50 native live engines versus 50 web windows (1 live). Both complete the entire 1,064,463-byte flood and 200 input samples without harness errors. All 6 app/server/service PIDs are gone, each ps_exit=1. The windows report visible=true, onscreen=true, occluded=false, built-in display ID 1. The physical panel is 3456x2234 Retina on M2 Max (32 GiB, 12 CPU cores); its current scaled workspace is 1168x755 points at backing scale 2. Both app content views are 1168x697 points. No display setting changed.
Images below are separate capture runs, excluded from timing repeats: native Metal canvas readback (SwiftUI chrome omitted), and WKWebView own-content snapshot (tracer chrome included). Full OS window capture was unavailable. These are functional receipts, not a visual-quality verdict. Geometry differs: native 80x24 cells in a 5-column grid; initial live web terminal 71x66 cells, product horizontal layout and other mock views retained. Per-phase web geometry is recorded.
cleanup.json
Three alternating-mode repeats at N=10 are now running without capture or tracing. Next N=25, then N=50, releasing the Mac lock between counts.
Measurement correction before accepting input results: native synthetic input was injected inside CADisplayLink tick, bypassing the wait for the next frame. Web input was also tied to rAF. These are phase-locked best-case samples, not general arrival latency. Added a receipt validation first; it fails on measured-10/native-10-r1.json with: "AssertionError: input arrived inside rendering; independent arrival receipt missing" (input-validation-before.log).
Changing both generators to independent 20 Hz timers with deterministic 13-step phase jitter. Native will record input-dispatch-to-callback waiting as well as dispatch-to-presentation; web will track each echoed byte through processed output sequence before the following rAF. Existing old-method runs will be preserved and excluded; all N=10/25/50 three-repeat sets will be rerun with the corrected method. This is a prototype measurement fix, no product changes.
Repository iterate result: fmt PASS; VT native fmt PASS; CLI plugin compile-out PASS; clippy PASS; cargo-deny PASS; workspace test FAIL. Failure is in unchanged product test crates/infraternal-agent/src/remote_server_path_tests.rs:909, remote_client::server_path::tests::component_down_activates_the_warm_fallback_without_a_new_connection: "component down opened another fallback connection despite a healthy parked proof", left 3, right 2. 96 passed, 1 failed, 14 ignored in that crate. Host load when inspected: 11.76 14.47 15.72. Full log: evidence/build-host.log. Product tree is unchanged by this branch. Running the isolated test and still requiring a green final fast gate; no waiver is claimed for this test.
678f6b8aapushed: corrected input measurement and receipt validation. Strict zero-leeway timer, background byte inbox, actual dispatch spacing, 200 input samples, fixed receipt drain. Presentation scalar copied immediately so logging cannot retain drawables; intervals derive from unique positive hardware times, with zero/duplicate counts retained. Corrected N=10 trial passes and all 3 final native N=10/N=25 repeats pass validation. Earlier phase-locked/coalesced samples are excluded.Further reuse finding corrects the earlier broad mock limitation: main.ts proto=product mounts canvas/product.ts with N real clients from sessions/live.ts. Only the stock test server is limited to one attached terminal per socket. Preparing a research build that keeps the actual product renderer/window operations, overrides client pooling to 1 stream/socket (max 64), and broadcasts the existing mock output route to every attached session. No product files are edited. This will measure N live web states; the stock clusters-preview runs remain secondary and excluded. Socket count and per-client replay completion will be recorded. Frontend build is waiting for a host slot; native N=50 repeats are running meanwhile.
The unchanged warm-fallback test passes in isolation using the already built workspace test executable (1 passed, 110 filtered out). A bare-package cargo rerun selected a different feature graph and ran 0 matching tests, so that is not counted as validation. Full fast remains required; no waiver.
4a88e06edpushed: CPU timebase fix. Old exporter failed getrusage self-check (0.000165072 vs 0.006868000..0.006889000). Device mach_timebase_info=125/3; corrected exporter passes (0.003581417 inside 0.003576000..0.003586000). Native raw counters are preserved with explicit cpu-correction.json; only CPU analysis scales by 125/3, not frame/input/memory.24a311433pushed: actual live product canvas fixture. Research-only overrides: 1 stream/socket, max64 sockets; 8 MiB/session mock reservoir; existing replay route broadcasts to all sessions; 2-second minimum client/server liveness grace, ping traffic retained. Default RTT+50 ms led to client close4000, then mock close1002 invalid attach during N=10 flood. This is a fixture limitation/control, not a product fix or proof of shipping transport behavior. Identity-only local assets skip gzip/Brotli creation; minified loaded code uses the normal build script, all loads precede sampling.Controlled live web N=10 and N=50 runs: no harness errors, full recording processed by all N clients, 200 input samples. N=50 capture run is excluded from timing. New images will wait for all 50 clients to be ready. Native corrected-method N=10/25/50 each have 3 valid repeats. Final live web N=10 three-repeat set is now running; N=25 and N=50 follow. Full fast is still waiting for a host build slot.
fa93e0988andd66f521b5pushed: all-live replay validation and calibrated-method documentation. All 9 native repeats passed; first 3 all-live web N=10 repeats passed (10/10 clients received 1,064,463 bytes, 200/200 input receipts). Web N=25 is running. Native hardware presentation intervals have p50 8.333 ms; p99 is usually 16.667 ms, so these are not perfect 120 Hz runs. Final CPU analysis converts old native Mach counters by measured 125/3; frame and input timestamps are unaffected. Full fast is queued behind the host-wide build slots; no waiver.Primary measurement complete: all 18 uninstrumented runs passed receipt validation (3 repeats × 10/25/50 × native/web). Code head
d66f521b5, pushed; no product files changed. These are prototype observations, not a foundational recommendation. Full repository fast gate and static-size comparison remain queued.Method: M2 Max Mac14,6, 32 GiB, macOS 27.0.1 (26A434), Xcode 27.0 (27A266a), AC 100%. Built-in physical panel 3456×2234, advertised maximum 120 Hz; existing scaled workspace 1168×755 points, backing scale 2. Content 1168×697 points. Native canvas loses 160 points to its sidebar; web uses the full content area. No display/system settings changed. Each isolated process runs 40 seconds: idle 4, pan 6, zoom 6, flood 6, snap 3, redraw 3, typing/drain 12. Native was collected before web rather than randomized; load averages accompany every 1-second accounting sample. No deliberate load was generated.
Identical command-generated real-PTY recordings feed every independent state: shell 52 B; source 1 MiB flood expands to 1,064,463 B with PTY CRLF; redraw 1,463 B. SHA256 manifests attached. Every final web run verifies all N connected clients and every session's replay sequence, and all 200 focused-input receipts; native validates complete delivery and 200 presentation receipts. Strict independent native input timer, independent jittered web timer; raw dispatch spacing passes validation. Earlier frame-locked/coalesced input and static-preview web measurements are excluded.
Native frame time is the interval between unique positive CAMetalDrawable presentation timestamps, driven by CADisplayLink requesting 120 Hz. Zero/duplicate timestamp counts and callback timing remain raw. No native submission drops, but p99 16.667 ms means missed 120 Hz deadlines. Web frame time is rAF cadence, integer-ms precision in this environment; it is not hardware presentation. The web's roughly 60 Hz ceiling was observed without changing experimental settings.
Input definitions differ: native synthetic dispatch → drawable presentation containing local VT echo; web synthetic dispatch → confirmed mock echo processed by the real client → following rAF. Neither measures physical keyboard to photon, remote latency, or D259 reconnect. Each percentile uses 200 samples/repeat. Native's 8.333 ms frame median therefore does not imply an 8.333 ms input delay.
All ranges are min–max across three repeats, not pooled percentiles. Times are ms; pairs are p50 / p99.
Sampled peak whole-process-tree memory, MiB. Per-terminal divides by N and includes fixed overhead. ×50 is arithmetic, not a separate 50-terminal observation except at N=50.
Native frame boundary includes VT work and bulk output copy; it is not pure call overhead.
Interpretation and limits: native is ASCII-only 80×24 with no style/shaping, fixed 5-column scene, minimal SwiftUI chrome, all grids copied and all glyph instances rebuilt every frame including off-screen. Web is the real tracer product canvas, 71×66 cells in these runs, real fonts/chrome/visibility suspension, and its normal 10,000-row history rather than native's 17 MiB cap. Both have N live terminal states, but this is not a renderer-only or feature-equivalent comparison. Native's idle loop is deliberately continuous, not an event-driven product estimate.
Mock accommodation: one stream/socket, up to 64 sockets rather than product pooling (28 streams/socket, 12 sockets); 8 MiB/session replay reservoir; replay route broadcasts identical chunks to every session. Both fixture watchdogs have a 2-second minimum grace; the normal RTT+50 ms grace reconnected during flooding in this altered fixture. Ping remains enabled. This is not evidence of shipping pooling/reconnect behavior. No product source was edited.
Memory/CPU method: 1 Hz proc_pid_rusage samples, sum main app + explicitly owned WebKit content/GPU/network services; test server excluded. CPU 100%=one core; sparse idle samples (2–3 deltas) and phase boundaries limit precision. Peaks exclude post-run JSON teardown. RSS and phys_footprint are process-ledger totals, not unique physical RAM or pure engine allocation; shared/GPU charges may overlap, and framework/recording overhead is included. The very different fixed overhead makes ×50 extrapolations from N=10 misleading; N=50 is measured directly. CPU was checked against getrusage; Mach timebase is 125/3. Original native tick counters remain unchanged with explicit correction files; newer web exports seconds directly. Raw CPU calibration before/after is attached.
The C ABI crosses once/frame with byte buffers and copies N×7,680 output bytes (384,000 at N=50). The boundary table includes parsing and grid copying; the dependent empty-call loop only isolates a mean scalar-call cost, not a latency percentile or binding-generator comparison. No generator or replacement engine was selected. Native flood boundary p99 rises to 2.642–4.477 ms at 50 terminals; this is a material part of an 8.333 ms frame budget even though the empty call itself is tiny.
Raw repeat data, process ownership/cleanup receipts, stream manifests, source hashes, validation, and full per-phase distributions:
primary-raw.tar.gz
results.csv
Final N=50 snapshots: both capture runs validated on built-in display_id=1, 1168×697-point content, visible/onscreen/unoccluded; capture runs are excluded from timing repeats. Web records snapshot_live_terminals=50 after all clients attach. Native image is an own-Metal-canvas readback (no SwiftUI sidebar/pill); web is WKWebView.takeSnapshot (product content, no OS titlebar). OS window capture was unavailable, and no permissions/settings were changed. These replace the earlier exploratory screenshots.
87fae716pushed: documented a further exact scene limitation confirmed by the snapshot and apps/tracer/src/canvas/product.ts:179–181. The default product creates a second Settings view with seven nonterminal panels. At overview its five terminal columns show only their top windows; all 50 real clients still process and verify replay. Native displays all 50 grids. Thus extra product UI and different visible glyph work are part of the measured result; do not read it as an isolated rendering-technology comparison. No claim about the decision follows from this prototype alone.Correction to primary results: do not treat the attached tables as validated built-in-panel measurements yet. Final image dimensions (native 4426×2692, web 5004×2692) disagree with the requested 1168×697-point content at scale 2. main.swift recorded targetScreen rather than window.screen and captured content size only before activation. This cannot prove the actual display/geometry after activation. The stricter validator now rejects these receipts (display-validation-before.log: actual display receipt missing or external).
Adding actual runtime screen ID, whole-window containment, current bounds per phase, and a post-activation frame application before native measurement starts. Will rerun primary measurements and replace the tables if this can be verified. Earlier data remains raw secondary evidence, not a built-in-panel claim. No system settings or owner windows are changed.
Runtime guard confirmed the issue: actual display_id=4 (external), 2502×1346-point content, surface 4684×2692, despite requesting the built-in panel. The 2-second guarded run stopped with no measurements; its app/server PIDs are gone. This supersedes earlier startup metadata. Testing an own fixed floating utility panel, with active/key-window checks and per-second actual display/containment/geometry receipts. No owner settings or windows are changed.
Mac lock is now mac-hardware, started 2026-10-15T11:39:01+02:00; waiting to compile/run the corrected window. Full fast started on
2d55db290; a final-head run will still be needed after the display fix commits. Current research-only changes are uncommitted until Xcode and runtime validation pass.ab5203515and3a408914apushed: actual display proof and its documentation. Both N=50 capture runs pass the stricter validator: display_id=1, builtin=true, contained=true, active=true, key=true, visible=true and unoccluded throughout. Content is 1168×697 points; native surface and PNG agree at 2016×1394, web at 2336×1394. A fixed floating utility panel avoids the automatic tiling that moved the normal window. No system/owner window settings changed.Fresh primary measurements now alternate native/web inside each repeat. N=10 is underway. The earlier tables and earlier images remain excluded from the built-in-panel claim; these are the accepted replacement images. Raw capture receipts and the failing regular-window evidence are attached. Capture runs are excluded from timing repeats.
verified-capture-raw.tar.gz
Further rejected run: verified-10/web-10-r2 ended at 25.996 s when display configuration changed. Before: external 2560×1440-point screen + built-in 1168×755. At rejection: only built-in 1728×1117 remains; app content stayed 1168×697 but the screen origin changed. builtin remained true, while containment against the startup screen failed. Do not attribute this rejection to utility-panel tiling. No settings were changed by this job.
Adding an explicit per-second display-configuration signature and repeating under the current built-in-only configuration. Previous partial set is preserved; it will not be pooled with new viewport/configuration runs.
Instrumentation finding: xctrace takes app focus during recording (native trace receipt app_active=false, key_window=false at finish). These samples cannot stand in for focused primary runs. Immediate graceful-stop trial left an unexportable native document: trace returncode -9 after bounded wait, export_returncode 10, Document Missing Template Error. Trial source retained outside checkout as immediate-interrupt-attempt.py; the uncommitted optimization was rejected and the earlier bounded save path restored. Failed traces remain separate from all primary statistics.
Own viewport is now fixed at 1168×697 points across desktop scaled modes; per-second display signature rejects any hotplug/geometry change within a run. Fresh uninstrumented/focused N=10 runs are queued behind tracing cleanup. No further profiling experiments will delay the primary matrix; timeline limitations will be stated explicitly.
Measurement blocked by focus interruptions: four consecutive focused attempts were rejected (15.072 s, near startup, about 30 s, 1.908 s). The last diagnostic records a non-test foreground process PID 83754 while our app is visible, contained on built-in display 1, and display configuration is unchanged. The job will not interact with that application or force focus during measurement.
Needed from owner/orchestrator: uninterrupted foreground use of the built-in panel for 40 seconds per run (18 app runs total, in short lock-held phases). Pausing app launches while that condition is unavailable; build-host final gate and cleanup continue. No primary table will be published from these rejected attempts. Normal app launch now uses LaunchServices and the app-published UI PID, so launcher CPU/memory is excluded. Diagnostic process metadata reads no other window content.
Completed and pushed:
0082a9c64(fixed viewport/display signature/fail-fast drift),d85dbdce6(bounded selected-repeat retry),7be368535(normal signed-app launch, actual UI PID, source/binary hashes and bounded cleanup),4eb22fffc(reproduction documentation). Xcode Release build and ad hoc signing pass. Real-process identity check: UI differs from launcher; UI is sampled, launcher is excluded; all owned PID cleanup checks return ps_exit=1.The read-only IOHIDSystem inactivity counter confirms ongoing input (0.191, 0.5, 0.2 seconds at checks). A job wrapper now waits for 60 seconds of inactivity before acquiring the Mac lock; it holds no lock while waiting and reads no input contents. No test windows are open during that wait. Final-head gate will run sequentially in the same build slot after the milestone gate and baseline build. Product diff against base
498ebd34f3remains empty.Milestone fast static x86_64 finding (gate start
2d55db290, current research head4eb22fffc):PT_INTERP: absent; size: 22277392 bytes; cap: 22204304 bytes; delta: +73088 bytes
binary exceeds the 22204304-byte size budget: 22277392 bytes
Binary is stripped static PIE; SHA256 e179f2d1254d374190e9766dc08ac1d0d4a4f291429e0e7b299d71502be0c8c0. Product diff vs merge base
498ebd34f3is empty. This is cap overage, not yet a branch-vs-base growth measurement. Baseline comparison is pending; no attribution or waiver is claimed. The first fast run continues through the second architecture. Its failure will prevent the original success-only comparison path, so a follow-up slot will run final-head fast plus baseline comparison and any TS checks skipped by the Rust failure.Mac primary matrix: all 18 runs have now passed the strict validator (3 repeats each at 10/25/50, both apps). Consolidating tables and receipts. No decisions or budgets were changed.
Accepted primary results — supersedes every earlier timing/memory table on this issue.
All 18 receipts pass the final validator: 3 repeats × N=10/25/50 × native/web. Head
4eb22fffc6, pushed. All nine phase source manifests match branch sources and one signed executable hash. No foundational recommendation is made.Machine/method: physical M2 Max Mac14,6, 32 GiB, macOS 27.0.1 (26A434), Xcode 27.0 (27A266a), AC 100%. Built-in 3456×2234 panel, maximum 120 Hz; existing scaled workspace 1168×755 points, backing scale 2. Fixed content 1168×697 points: native Metal surface 2016×1394 pixels after its 160-point sidebar; web 2336×1394. No display, power or experimental WebKit preferences changed. Actual display=1, containment, visibility, active/key state and unchanged display configuration are sampled at 1 Hz and validated. Each phase starts after ≥60 s input inactivity (observed 64.47–806.80 s), with the shared lock released between pairs. Native then web within each repeat; order is not randomized. Observed one-minute load 2.91–6.75 on 12 logical CPUs; no artificial CPU load.
Each fresh process runs 40 s: idle 0–4, pan 4–10, zoom 10–16, flood 16–22, snap 22–25, redraw 25–28, typing/drain 28–40. Real-PTY command-generated recordings: 52 B shell-style transcript, 1,064,463 B flood (1 MiB source expanded by PTY CRLF), 1,463 B cursor-control redraw. The recordings are deterministic, not a human interactive session. Both modes deliver identical replay bytes to every independent live VT state. The flood is paced over six seconds, max 8192 B/callback; a remainder can drain after the boundary. This is a controlled replay rate, not maximum unthrottled throughput. Redraw is up to 30/s; 200 focused ASCII inputs at 20 Hz have deterministic phase jitter, verified dispatch spacing and complete receipts.
Native frame figures are intervals between unique positive CAMetalDrawable presentation timestamps, driven by CADisplayLink requesting 120 Hz. Web figures are rAF callback cadence, coarsened to integer milliseconds here, rather than hardware presentation. The default WKWebView delivered roughly 60 rAF/s; this does not establish its unrestricted engine limit. Native input is strict background dispatch → drawable presentation containing local VT echo. Web input is JS timer dispatch → confirmed mock echo processed by the real client → an additional rAF. Web excludes time before JS dispatch and adds the following-frame wait; neither is physical keyboard-to-photon. Do not rank physical input latency from these different proxies.
All ranges are min–max across three repeats, not pooled percentiles. Times are ms; pairs are p50 / p99.
Sampled peak whole-process-tree memory, MiB. Per-terminal divides by N and includes fixed overhead. ×50 is arithmetic, not a separate 50-terminal observation except at N=50.
Native frame boundary includes VT work and bulk output copy; it is not pure call overhead.
Memory/CPU: requested 1 Hz proc_pid_rusage sampling, realized median spacing 1.086–1.169 s across runs. Reported memory is sampled peak before post-run JSON teardown. RSS and phys_footprint are sums of the actual app and its explicitly owned WebKit content/GPU/network services; launcher, test server and sampler are excluded. These are ledger totals, not unique physical RAM or pure engine allocations; shared/GPU charges can overlap. Per-terminal division includes fixed framework/harness costs, so ×50 from small N overestimates the directly measured N=50 result. CPU 100%=one core; idle has only 2–3 usable deltas and flood 4–5. Mach timebase 125/3 is applied and checked against getrusage for each pair. All primary files export seconds directly; legacy corrected data is excluded.
Scene/fixture limits: native is a minimal 80×24 ASCII grid, no styles/shaping, product services or rich window frames; it copies every grid and rebuilds all glyph instances even off-screen. Web uses the real product canvas, 43×30 cells, real fonts/styles/chrome, five vertically scrolling columns and seven default Settings panels, with existing off-screen/frozen drawing suspension. All N VT states continue parsing; the sequence advances after the real write callback. Overview/camera/focus operations and visible glyph work differ. Native retains its last zoom during flood; web centers its live terminal. This is a whole-prototype comparison, not isolated rendering technology or a complete Rust client-core comparison.
Web uses the normal repository minifier with INFRATERNAL_CLUSTERS_PREVIEW=1 and ?mock=1&proto=product&fixture=none, a research control probe, and identity assets loaded before sampling (gzip/Brotli sidecars skipped only for the local server). Stock test-server limitations require 1 stream/socket, max 64 sockets rather than product pooling (28/socket, 12 sockets), an 8 MiB/session reservoir and a 2-second minimum watchdog grace on both fixture ends. Replay arrives through a client HTTP control upload then the normal WebSocket output path; that client-side driver work is included. Typed input uses only the focused client and normal mock echo. No product source is edited.
The full boundary timer includes pinned native VT processing and N×7680 B grid export (384,000 B/frame at N=50). The empty 100,000-call dependent scalar loop is only a mean control; no buffer-only ABI distribution or binding generator was measured. At N=50, full flood boundary p99 is 1.314–1.355 ms within the nominal 8.333 ms period; it is materially larger than the scalar crossing itself.
Not measured/validated: physical input-to-photon, a usable focused WebKit Inspector timeline, unrestricted high-refresh WebKit preferences, simultaneous motion plus flood, cold-start/transfer budgets (D188), reconnect budgets (D259), iPhone performance or the rest of the D238 Rust client core. Separate Animation Hitches attempts lost focus and/or failed export with Document Missing Template Error; none enter this table. Failed/partial runs, geometry mistakes, focus interruptions and transfer-overlap runs remain excluded. No decision follows beyond these observed workloads.
Accepted raw receipts, source/artifact hashes, manifests, all per-repeat/per-phase distributions and CSV:
accepted-primary-raw.tar.gz
accepted-results.csv
accepted-summary.json
N=50 own-content images are in the accepted capture comment above: native Metal-only image excludes SwiftUI chrome; WKWebView snapshot excludes OS titlebar. Capture runs are separate from these timings. Primary cleanup proof lists 91 app/service/launcher/controller PIDs, all absent in final ps checks. Gate status remains blocked by the static x86_64 cap overage; final-head and baseline comparison are pending. This is not a claim that the repository gate is green.
Mac cleanup and measurement audit: all 91 primary app/service/launcher/controller PIDs are absent. Final audit lists all 395 recorded job PIDs with individual ps checks, all absent; the cleanup controller PID 76967 is separately absent. No job-local executable remains active, and the Mac lock was released. Removed only this job's derived build, static library, bundled runtime/site, sampler and trace artifacts. Source/raw receipts remain under the job directory and in the attached Linux evidence archive.
Artifact hashes before removal match the primary manifests (app SHA256 6e63a0c2d93901a8069b31c855bd0947f66d8d6435e07e1d48d1c51e1544ac86; core 48ecd6f1c02206f7a330ad578ba1e728622661acb205262547898ace137a951c). Native pan/zoom/flood audits have zero submission drops and zero missing/duplicate hardware timestamps across all nine primary native runs. These are functional/resource checks, not a visual-quality judgment.
mac-cleanup-and-diagnostics.tar.gz
Measurement collection and Mac cleanup are complete; accepted primary results and receipts are posted above. Final-head validation and the baseline static-size comparison have been queued through build-slot since 11:16:22 UTC (over 22 minutes as of 11:39 UTC). No second heavy command is running for this job. Earlier milestone gate failed only its static-build row: x86_64 stripped size 22,277,392 B against a 22,204,304 B cap (+73,088 B); branch-vs-base growth remains unmeasured until this queued comparison completes. Product paths are unchanged from base
498ebd34f3. Head4eb22fffc6is pushed.Final-head gate/baseline size comparison remains queued since 11:16:22 UTC; checked 2026-10-15T12:02:09.130680+00:00. Wrapper PID 2246770 is alive, no gate output yet. Current slot ownership:
Measurement results and Mac cleanup are already posted. Continuing to wait; no other jobs or limits changed.
Final-head gate and baseline static-size comparison are still waiting for build-slot (queued 11:16:22 UTC; checked 2026-10-15T12:45:59.867312+00:00). Wrapper PID 2246770 remains alive in the native-spike worktree. Neither final-verify-fast.log nor the baseline comparison exists yet. Current slots:
Continuing to wait. Accepted measurement collection and Mac cleanup are complete, posted above; no new benchmark or heavy process was started.
Final validation remains blocked on the shared build-slot queue after about two hours (queued 11:16:22 UTC, checked 2026-10-15T13:16:04.849246+00:00). Wrapper PID 2246770 remains alive; no final gate output yet. Current slots:
Continuing to wait. No extra heavy command, VM use or Mac activity. Accepted results/cleanup are complete. Baseline size delta remains unmeasured; earlier cap failure remains open.
Final-head gate is now running through build-slot (observed active by 13:18:44 UTC after roughly two hours queued). Verified gate HEAD
4eb22fffc6. fmt, CLI compile-out and clippy progressed into workspace tests. Baseline size comparison remains sequenced after this gate in the same wrapper.Final-head scripts/verify fast exited 1 at
4eb22fffc6. Rust summary: fmt PASS; VT native fmt PASS; CLI plugin compile-out PASS; clippy PASS; test FAIL (101); cargo-deny PASS; static builds FAIL (1). The test row reports 422 passed, 1 failed, 46 ignored in infraternal-server: auth::tests::socket_tests::fresh_delete::review_mesh_delete_requires_fresh_passkey_tap, at crates/infraternal-server/src/auth/tests.rs:1740:17, "server closed websocket unexpectedly: None". This is not an explicit timeout receipt; no #118 exception is claimed. The earlier milestone full Rust tests passed. A single exact control is now compiling on detached base498ebd34f3(the one-unit-test exception; same job target). Static cap failure remains; separate TypeScript checks and baseline size comparison are still running/pending in the same build-slot wrapper. No product files differ from base.Final gate controls: separate ts_verify_fast exited 0 (the full fast command skipped TS after Rust failed). Original final-head server test executable rerun with the exact fresh-delete test: 1 passed, 0 failed, 468 filtered. Detached baseline single-package default-feature control: 0 passed, 1 failed, 263 filtered; failure at fresh_delete.rs:131 (expected successful call 83), unlike the full-head unexpected socket close at auth/tests.rs:1740. These feature sets/contexts differ, so this is not an equivalent failing-baseline proof or a #118 waiver. Full fast remains FAILED.
Both shipping static caps fail on final head: x86_64 22,277,392 B / cap 22,204,304 B (+73,088 B); aarch64 19,705,112 B / cap 19,638,744 B (+66,368 B). These are cap overages, not measured branch growth. The required same-recipe x86_64 baseline build is now running under the existing build slot. No product code or cap changed.
Measurement collection finished; repository gate remains blocked. Final pushed head:
4eb22fffc6on native-spike, base498ebd34f3. Clean checkout; all 24 changed paths are under research/native-spike/. No product code, cap, dependency or foundational decision changed. No deploy.The accepted primary results comment above is the result: 18 validated runs, 3 repeats for each app at N=10/25/50, with tables, method/noise, differences, screenshots and raw receipts. At N=50 native presentation p50/p99 is 8.333/8.338 ms; web rAF pan p50/p99 is 16/24–25 ms (zoom 17/25–26, flood 17/21–23). These are different presentation proxies and unequal minimal/full-product scenes, not an isolated renderer or physical input comparison. A usable WebKit Inspector timeline and physical input-to-photon were not validated. No recommendation on D238.
Required stripped static x86_64 comparison, identical release recipe: head 22,277,392 B; merge base 22,277,392 B; delta 0 B. Hashes differ; this is equal size, not byte identity. Both are stripped static PIE. The x86 cap is already exceeded on the base by 73,088 B. Final-head aarch64 also exceeds its cap by 66,368 B (19,705,112 B against 19,638,744 B); no aarch64 baseline measurement is claimed.
Final-head scripts/verify fast exit 1, verbatim summary:
The test row failed on auth::tests::socket_tests::fresh_delete::review_mesh_delete_requires_fresh_passkey_tap, with "server closed websocket unexpectedly: None" at auth/tests.rs:1740. Original head executable passes that exact test in isolation (1 passed, 468 filtered); detached baseline default-feature single-package control fails a different assertion at fresh_delete.rs:131 (1 failed, 263 filtered). These contexts differ; neither proves the same failure nor justifies a #118 timeout exception. The earlier milestone Rust test row passed. This final failed gate is not waived.
Because fast skips TS after Rust failure, ts_verify_fast ran separately in the same build slot and exited 0. Its test summaries, verbatim:
Cleanup: the prior attached Mac audit lists 395 recorded job PIDs individually absent, plus the separately absent final cleanup controller, and the shared Mac lock released. Host debug/release targets, saved binaries, staging bundles, downloaded runtime copy and detached baseline checkout are now removed; build wrapper PID 2246770 is absent. Evidence and small reproduction helpers remain outside the checkout. Author checklist and scope/cleanup receipts are in this final archive; screenshots remain for owner review, with no author visual-quality judgment.
The orchestrator needs to reconcile the development-line size-cap failure and investigate the server test before integration. This research-only lane does not change those product paths. Issue remains open.
Final raw gate/control/build logs, size comparison, author review and cleanup receipts:
final-validation-and-size.tar.gz
final-verify-fast.log
static-size-comparison.json
Accepted measurement receipts: accepted-primary-raw.tar.gz, accepted-results.csv.
kayg referenced this issue2026-10-28 17:53:56 +00:00