feat(contracts): PKNT wire protocol + RAM .pkst assembler - #168
Merged
Conversation
This was referenced Jul 23, 2026
doodlewind
added a commit
that referenced
this pull request
Jul 23, 2026
…cklist The companion document for the PKNT wire (#168) and the Vita svc/video/ audio host (#169): why one ordered TCP connection, why the RAM ring is a byte-exact .pkst file image, the thread/ownership diagram, the GPU-idle present discipline, and the real-hardware verification checklist (Vita3K has no network stack, so the transport only proves itself on a device). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
doodlewind
force-pushed
the
feat/touch-goldens
branch
from
July 23, 2026 12:50
2f0e92b to
c4b94c1
Compare
doodlewind
force-pushed
the
feat/pknt-wire
branch
from
July 23, 2026 12:50
4ea9075 to
91330f1
Compare
doodlewind
added a commit
that referenced
this pull request
Jul 23, 2026
…cklist The companion document for the PKNT wire (#168) and the Vita svc/video/ audio host (#169): why one ordered TCP connection, why the RAM ring is a byte-exact .pkst file image, the thread/ownership diagram, the GPU-idle present discipline, and the real-hardware verification checklist (Vita3K has no network stack, so the transport only proves itself on a device). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
doodlewind
force-pushed
the
feat/touch-goldens
branch
from
July 23, 2026 12:55
c4b94c1 to
247d666
Compare
doodlewind
force-pushed
the
feat/pknt-wire
branch
from
July 23, 2026 12:55
91330f1 to
422b512
Compare
doodlewind
added a commit
that referenced
this pull request
Jul 23, 2026
…cklist The companion document for the PKNT wire (#168) and the Vita svc/video/ audio host (#169): why one ordered TCP connection, why the RAM ring is a byte-exact .pkst file image, the thread/ownership diagram, the GPU-idle present discipline, and the real-hardware verification checklist (Vita3K has no network stack, so the transport only proves itself on a device). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
doodlewind
force-pushed
the
feat/touch-goldens
branch
from
July 23, 2026 13:04
247d666 to
ab36340
Compare
doodlewind
force-pushed
the
feat/pknt-wire
branch
from
July 23, 2026 13:04
422b512 to
0be8712
Compare
doodlewind
added a commit
that referenced
this pull request
Jul 23, 2026
…cklist The companion document for the PKNT wire (#168) and the Vita svc/video/ audio host (#169): why one ordered TCP connection, why the RAM ring is a byte-exact .pkst file image, the thread/ownership diagram, the GPU-idle present discipline, and the real-hardware verification checklist (Vita3K has no network stack, so the transport only proves itself on a device). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
doodlewind
added a commit
that referenced
this pull request
Aug 3, 2026
…cklist The companion document for the PKNT wire (#168) and the Vita svc/video/ audio host (#169): why one ordered TCP connection, why the RAM ring is a byte-exact .pkst file image, the thread/ownership diagram, the GPU-idle present discipline, and the real-hardware verification checklist (Vita3K has no network stack, so the transport only proves itself on a device). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
doodlewind
force-pushed
the
feat/touch-goldens
branch
from
August 3, 2026 05:46
ab36340 to
c2a76ce
Compare
doodlewind
force-pushed
the
feat/pknt-wire
branch
from
August 3, 2026 05:46
0be8712 to
73ed7b8
Compare
doodlewind
force-pushed
the
feat/touch-goldens
branch
from
August 3, 2026 05:49
c2a76ce to
999a5f9
Compare
The svc mailbox (+side files +.pkst streams) only exists over PSPLINK's usbhostfs file share, which the Vita does not have. This defines the same semantics over one socket, contracts-first, hosts later: - spec.ts WIRE section: 'PKNT' framed TCP protocol (8-byte header: type, flags, u16 rsv, u32 len ≤ 256 KiB; unknown types skip by length), UDP 'PKDB' discovery beacon (ports 8621/8622), handshake, and message table — ping/pong, ctrl (one mailbox JSON line), file (proactive side-file push so synchronous loadImgFile hits a warm cache), streamOpen (verbatim 96-byte .pkst header block = full ring reset), videoSlot (bit0 = PackBits-RLE indices), audioChunk, streamMark (epoch/ended). ONE connection on purpose: TCP ordering is load-bearing (streamOpen before the announce line, file before the results line). No op-table changes; spec.rs regenerated. - engine/core/src/wire.rs: no_std bounds-checked parsers + fixed encoders (the stream.rs discipline — hostile lengths return None, never panic). - engine/core/src/stream_rx.rs: RamStream — a byte-exact .pkst FILE IMAGE in memory. Slots/chunks apply payload-first, latestSeq-after, preserving the torn-frame contract verbatim; the exact same stream.rs readers then run over buf(), so file-backed (PSP) and socket-backed (Vita) transports share one reader and one golden format. Tests (cargo test, 6 new): header/hello/beacon/payload round-trips with per-byte truncation fuzz; RAM image == an independent reference file writer, byte for byte (laps, marks); RLE slots decode via codec::packbits_decode and bad geometry never publishes a cursor; and the committed TS-written youtube-golden.pkst reconstructs byte-identically when re-fed as WIRE messages — the cross-language proof that the socket transport IS the file transport. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
doodlewind
force-pushed
the
feat/pknt-wire
branch
from
August 3, 2026 05:50
73ed7b8 to
c902e82
Compare
doodlewind
marked this pull request as ready for review
August 3, 2026 05:50
doodlewind
added a commit
that referenced
this pull request
Aug 3, 2026
The Vita host registered only ops 1–29: no svc channel, no video plane, no audio, no network stack. This implements the whole family (ops 30–38) over the PKNT wire protocol: - net.rs: sceNet init confined to one function (module load, 1 MiB static pool, sceNetCtlInit; failure is remembered and final — Vita3K has no network stack, so svcOpen stays false and emulator e2e never regresses); everything after rides std::net over the newlib shims. Supervisor thread (host.txt override → UDP beacon discovery → connect + handshake → rx loop: CTRL → line queue, FILE → 6 MiB LRU cache, SLOT/CHUNK/MARK → RamStream, PING → PONG) + tx thread draining an mpsc channel. On disconnect the ring is marked ended, 1 s backoff, rediscover. The 60 fps main thread never blocks: its ops pop queues and take short-held mutexes. - svc.rs (ops 30–33): PSP guest semantics verbatim — non-blocking svcOpen the app's connect pump retries, batched svcPoll, side files resolved from the proactive-push cache so the synchronous loadImgFile never waits on the network. - vid.rs (ops 34–37): the PSP vid.rs reader over RamStream::buf() — same epoch/lap/seq-validation logic, same stage-then-present split, minus the IO budget (reads are memcpys). present() commits in the GPU-idle window: Runtime::render now runs begin_frame → vid::present → render_over, and graphics grows update_texture_in_place (rewrites the existing vita2d texture's pixels — the register/recycle path would allocate + drain GXM once per presented frame at 24 fps). The GE race discipline, GXM edition. - audio.rs: the PSP design with sceAudioOut — BGM port at 44.1 kHz, SPSC ring (~743 ms), starvation sleeps, port opened AND released on the main thread (the channel-leak class of bug). Integer ×1/×2/×4 upsampler keeps PSP-profile 22.05 kHz streams playable. - stats.rs + debugStats (op 38): PSP shape + a net section (rxBytes/ txBytes/reconnects/slotsRx/fileEvicts); build.rs bakes the FNV-1a64 bundle hash for the stale-embed tripwire. Validated: full release VPK build (im-main) with the vita toolchain; Vita3K e2e cursor-main 5/5 byte-exact (new modules dormant without svcOpen). The wire/ring logic itself is covered by the engine/core tests (#168); transport verification is real-hardware only (Vita3K has no sceNet). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
doodlewind
added a commit
that referenced
this pull request
Aug 3, 2026
* feat(vita): svc mailbox + video plane + audio over WiFi TCP The Vita host registered only ops 1–29: no svc channel, no video plane, no audio, no network stack. This implements the whole family (ops 30–38) over the PKNT wire protocol: - net.rs: sceNet init confined to one function (module load, 1 MiB static pool, sceNetCtlInit; failure is remembered and final — Vita3K has no network stack, so svcOpen stays false and emulator e2e never regresses); everything after rides std::net over the newlib shims. Supervisor thread (host.txt override → UDP beacon discovery → connect + handshake → rx loop: CTRL → line queue, FILE → 6 MiB LRU cache, SLOT/CHUNK/MARK → RamStream, PING → PONG) + tx thread draining an mpsc channel. On disconnect the ring is marked ended, 1 s backoff, rediscover. The 60 fps main thread never blocks: its ops pop queues and take short-held mutexes. - svc.rs (ops 30–33): PSP guest semantics verbatim — non-blocking svcOpen the app's connect pump retries, batched svcPoll, side files resolved from the proactive-push cache so the synchronous loadImgFile never waits on the network. - vid.rs (ops 34–37): the PSP vid.rs reader over RamStream::buf() — same epoch/lap/seq-validation logic, same stage-then-present split, minus the IO budget (reads are memcpys). present() commits in the GPU-idle window: Runtime::render now runs begin_frame → vid::present → render_over, and graphics grows update_texture_in_place (rewrites the existing vita2d texture's pixels — the register/recycle path would allocate + drain GXM once per presented frame at 24 fps). The GE race discipline, GXM edition. - audio.rs: the PSP design with sceAudioOut — BGM port at 44.1 kHz, SPSC ring (~743 ms), starvation sleeps, port opened AND released on the main thread (the channel-leak class of bug). Integer ×1/×2/×4 upsampler keeps PSP-profile 22.05 kHz streams playable. - stats.rs + debugStats (op 38): PSP shape + a net section (rxBytes/ txBytes/reconnects/slotsRx/fileEvicts); build.rs bakes the FNV-1a64 bundle hash for the stale-embed tripwire. Validated: full release VPK build (im-main) with the vita toolchain; Vita3K e2e cursor-main 5/5 byte-exact (new modules dormant without svcOpen). The wire/ring logic itself is covered by the engine/core tests (#168); transport verification is real-hardware only (Vita3K has no sceNet). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(vita): a stale host.txt falls back to beacon discovery First hardware bring-up caught it immediately: the Mac's DHCP lease moved, the ux0:data/pocketjs/host.txt override pointed at a dead address, and because the override took precedence unconditionally the transport retried it forever — beacon discovery could never rescue the session. Connect failures now alternate the next discovery round onto the beacon listener, so a stale override degrades to broadcast discovery instead of wedging. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
doodlewind
added a commit
that referenced
this pull request
Aug 3, 2026
…cklist The companion document for the PKNT wire (#168) and the Vita svc/video/ audio host (#169): why one ordered TCP connection, why the RAM ring is a byte-exact .pkst file image, the thread/ownership diagram, the GPU-idle present discipline, and the real-hardware verification checklist (Vita3K has no network stack, so the transport only proves itself on a device). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
doodlewind
added a commit
that referenced
this pull request
Aug 3, 2026
…cklist (#170) The companion document for the PKNT wire (#168) and the Vita svc/video/ audio host (#169): why one ordered TCP connection, why the RAM ring is a byte-exact .pkst file image, the thread/ownership diagram, the GPU-idle present discipline, and the real-hardware verification checklist (Vita3K has no network stack, so the transport only proves itself on a device). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part 1/2 of the Vita networking series (stacked on #167; series goal: the svc mailbox + video plane over WiFi TCP for hosts without a shared filesystem).
What
Contracts (
contracts/spec/spec.ts, no op-table changes,spec.rsregenerated):WIRE_*: framed TCP protocol'PKNT'— 8-byte header (type·flags·rsv·len ≤ 256 KiB), forward-compatible skip-by-length; handshake (device sends app id, host acks version); UDP discovery beacon'PKDB'on 8621, TCP listener on 8622.ping/pong,ctrl(one mailbox JSON line),file(side files pushed before the ctrl line referencing them → synchronousloadImgFilehits a warm cache),streamOpen(verbatim 96-byte.pkstheader block = full ring reset),videoSlot(flag bit0 = PackBits-RLE indices),audioChunk,streamMark(epoch/ended).Core (
engine/core, both no_std):wire.rs: bounds-checked parsers + fixed-size encoders, stream.rs hardening discipline.stream_rx.rs:RamStream— a byte-exact.pkstfile image in RAM. payload-first/latestSeq-after preserved verbatim;stream.rsreaders (parse_header_block/slot_offset/…) run unchanged overbuf().Proof
6 new cargo tests, the load-bearing one: the committed TS-written
youtube-golden.pkstreconstructs byte-identically when its resident slots/chunks are re-fed as WIRE messages throughRamStream— socket transport ≡ file transport, cross-language. Plus: truncation fuzz on every parser, RAM-vs-independent-reference-writer equality, RLE decode, no cursor published on rejected payloads.bun tests/contract.tsgreen.Next in series:
hosts/vitasvc/vid/audio over this wire (net.rs + threads).🤖 Generated with Claude Code