45c3b96907f62399a6699db91ef6212585c61a24
1566 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
45c3b96907 |
feat(store): plugin store host module — signed catalogs, tiered trust, install jobs
The index is the verification gate: a catalog entry pins one exact version
plus that version's tarball integrity hash, so 'verified on every release'
is a property of the data rather than a promise about process. Nothing can
express 'track latest' for a catalogued plugin.
- store/index.rs signed index parse + ed25519 verify (ring), validate-and-drop
per entry, semver minHost/advisory ranges
- store/sources.rs built-in unom source (compiled-in URL + two key slots for
rotation) + operator sources in plugin-sources.json
- store/catalog.rs https fetch with size/timeout/redirect caps, signature before
parse, last-good disk cache (stale-but-usable when offline)
- store/jobs.rs single-flight install/uninstall: registry-integrity preflight
against the pin, spawn the runner CLI with live log capture,
post-install version check with rollback, provenance record,
runner restart (discovery is startup-only)
- store/manifest.rs install provenance; absence means CLI-installed
- mgmt/store.rs 12 routes under /api/v1/store, denied to the plugin token
(a plugin that can install plugins is an escalation primitive)
Also generalizes runner discovery and listInstalled from @punktfunk/plugin-*
to ANY scope's plugin-*: catalog entries must be scoped so the scope can map
to that entry's registry, so a third-party plugin necessarily arrives under
its own scope and would otherwise install but never run.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
96e19986bc |
feat(encode): RGB-direct padded-copy — unaligned modes (1080p) get the EFC path safely
apple / swift (push) Successful in 1m20s
apple / screenshots (push) Successful in 6m42s
windows-host / package (push) Successful in 9m24s
android / android (push) Failing after 18s
ci / web (push) Successful in 1m8s
ci / docs-site (push) Successful in 1m43s
arch / build-publish (push) Successful in 11m48s
decky / build-publish (push) Successful in 21s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 12s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 10s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 10s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 10s
ci / bench (push) Successful in 7m33s
deb / build-publish (push) Successful in 9m1s
deb / build-publish-host (push) Successful in 13m6s
ci / rust (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
Lifts 3aacec53's alignment gate into a mode select: an aligned mode keeps the true zero-copy direct import; an unaligned one (1080p!) now blits the visible frame into a per-slot ALIGNED BGRA staging image and duplicates the edge rows/columns into the 64x16 padding — transfer-only regions in one vkCmdCopyImage (1080p: visible + 8 row regions; width padding adds a second self-copy pass in GENERAL), no compute shader. The encode reads the staging image, never the capture buffer, so the EFC can never read past a producer allocation (the field GPU hang). Still one ~8 MB copy vs the CSC path's ~17 MB + dispatch + plane copies. Verdict line: active(padded-copy). The staging import drops the video profile entirely (TRANSFER_SRC only). CPU-payload paths made honest on the way (they were the smoke baseline AND the software-capture fallback): - rgb mode: the staging upload is padded CPU-side (edge duplication) so the aligned encode-src is fully defined; - CSC mode: the sampled image is now SOURCE-sized with a matching copy extent — the old aligned-size image + tightly-packed buffer sheared rows and left garbage rows at unaligned modes (black-bar artifacts; YMIN=16 in every smoke frame), which also masked as a 24 dB PSNR 'regression' against the (correct) padded output. On-glass (780M, host Mesa 26.0.4): all four smokes pass at 256x256 (direct) AND 250x250 (padded); padded-EFC frames decode perfectly uniform (YMIN==YMAX) at the exact 709-narrow values (79/148/60 for the first three fills); CSC-vs-padded PSNR 49.9 dB avg after the baseline fix. clippy clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
3aacec53d8 |
fix(encode): RGB-direct must not engage on unaligned modes — the EFC reads past the capture buffer (GPU hang)
apple / swift (push) Successful in 1m23s
apple / screenshots (push) Successful in 6m27s
windows-host / package (push) Successful in 9m29s
ci / web (push) Successful in 1m1s
ci / docs-site (push) Successful in 1m15s
ci / bench (push) Successful in 6m8s
android / android (push) Successful in 15m47s
arch / build-publish (push) Successful in 14m49s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 13s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 13s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 12s
decky / build-publish (push) Successful in 25s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 11s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 12s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 13s
deb / build-publish (push) Successful in 9m32s
ci / rust (push) Successful in 19m0s
deb / build-publish-host (push) Successful in 13m3s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 15m8s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 22m27s
docker / deploy-docs (push) Successful in 13s
Field report (commit
|
||
|
|
84e1e5aeb4 |
fix(web): restore the Dashboard status tiles' top padding
apple / swift (push) Successful in 1m30s
apple / screenshots (push) Successful in 6m28s
windows-host / package (push) Successful in 9m27s
ci / web (push) Successful in 1m10s
ci / docs-site (push) Successful in 1m11s
android / android (push) Successful in 13m1s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 11s
decky / build-publish (push) Successful in 20s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 13s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 37s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 11s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 22s
ci / bench (push) Successful in 6m9s
arch / build-publish (push) Successful in 15m32s
deb / build-publish (push) Successful in 9m10s
deb / build-publish-host (push) Successful in 10m45s
ci / rust (push) Successful in 24m42s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 17m6s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 17m24s
docker / deploy-docs (push) Successful in 12s
CardContent is shadcn's header-adjacent variant (`p-4 pt-0 sm:p-6 sm:pt-0`), but the four Live-status tiles use it with no CardHeader. tailwind-merge lets the call site's unprefixed `p-4` cancel the base `pt-0`, yet nothing cancels `sm:pt-0` — so the tiles lost their top padding at >=640px only, and the content sat against the top edge. Restores the top inset at the sm breakpoint and lets the content fill the stretched grid cell so it stays centred when a sibling tile is taller. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
1262fec2ae |
perf(zerocopy/vulkan): LN4 — global-priority VkBridge queue for the LINEAR/gamescope CSC
apple / swift (push) Successful in 1m22s
apple / screenshots (push) Successful in 6m27s
ci / web (push) Successful in 1m0s
ci / docs-site (push) Successful in 1m6s
decky / build-publish (push) Successful in 21s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 12s
ci / bench (push) Successful in 7m51s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 9s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 9s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 9s
deb / build-publish (push) Successful in 8m47s
arch / build-publish (push) Successful in 15m47s
android / android (push) Successful in 16m2s
deb / build-publish-host (push) Successful in 12m13s
ci / rust (push) Successful in 26m31s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 15m54s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 16m3s
docker / deploy-docs (push) Successful in 16s
The RGB→NV12 compute CSC shares the SMs with the game; request an
elevated global-priority queue (VK_KHR/EXT_global_priority) so the
driver can schedule it ahead. PUNKTFUNK_VK_QUEUE_PRIORITY =
off|high|realtime (default realtime), downgrading REALTIME→HIGH→none
on NOT_PERMITTED/INITIALIZATION_FAILED — a refused class never fails
the bridge. Mirrors PyroWave's
|
||
|
|
ae67315804 |
perf(encode/nvenc-linux): LN3 — pipelined-retrieve escalation replaces the depth-1 async foot-gun
apple / swift (push) Successful in 1m24s
apple / screenshots (push) Successful in 5m16s
windows-host / package (push) Successful in 10m11s
ci / web (push) Successful in 59s
ci / docs-site (push) Successful in 1m40s
ci / bench (push) Successful in 5m13s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 11s
decky / build-publish (push) Successful in 19s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 8s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 10s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 10s
android / android (push) Successful in 17m6s
arch / build-publish (push) Successful in 17m27s
deb / build-publish (push) Successful in 12m39s
deb / build-publish-host (push) Successful in 9m33s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Failing after 7m27s
ci / rust (push) Successful in 27m10s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 15m1s
docker / deploy-docs (push) Successful in 17s
PUNKTFUNK_NVENC_ASYNC gains a real tri-state: 1 = always (as before, now documented as ~+1 tick at depth-1), 0 = never (vetoes escalation), unset = ADAPTIVE — off until the session loop's cadence-overrun detector escalates. The host loop's adaptive-depth leaky bucket grows a second stage: once the capturer's depth is maxed (Linux portal is permanently depth-1), it asks the encoder for pipelined retrieve via the new Encoder::set_pipelined hook (asked exactly once; default impl declines, Windows untouched). nvenc_cuda engages at a safe point via a clean session rebuild WITHOUT the IO-stream binding: with input==output stream bound, later stream work waits on prior encode completions and would serialize a pipelined session — stream-ordered submit and two-thread retrieve are mutually exclusive. The ordered gate now also requires async_rt absence (belt-and-braces for the runtime switch). Re-open's first frame is the standard session IDR. On-hardware test: escalate mid-session → retrieve thread live, binding gone, all AUs deliver, first post-escalation AU is the IDR. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
256244430b |
feat(encode): Vulkan Video B1 — RGB-direct encode source via VCN EFC (PUNKTFUNK_VULKAN_RGB_DIRECT=1)
apple / swift (push) Successful in 1m25s
windows-host / package (push) Successful in 11m6s
apple / screenshots (push) Successful in 6m55s
ci / web (push) Successful in 1m8s
ci / docs-site (push) Successful in 1m4s
decky / build-publish (push) Successful in 20s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 11s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 10s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 15s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 10s
ci / rust (push) Failing after 10m50s
arch / build-publish (push) Successful in 14m36s
ci / bench (push) Successful in 6m3s
android / android (push) Successful in 15m19s
deb / build-publish-host (push) Successful in 9m39s
deb / build-publish (push) Successful in 10m24s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 16m6s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 15m53s
docker / deploy-docs (push) Successful in 18s
design/vulkan-rgb-direct-encode.md B1: when the probe passes AND
PUNKTFUNK_VULKAN_RGB_DIRECT=1 (default OFF until the B2 on-glass A/B),
the session opens with pictureFormat=B8G8R8A8 and the captured RGB frame
becomes the encode source — the VCN EFC front-end does the 709-narrow CSC
inline during encode. Deleted from the per-frame path: the compute CSC
dispatch, both NV12 plane copies, the semaphore hop and one queue submit
(dmabuf frames are ONE encode-queue submit; ~17 MB/frame of GPU traffic
gone). The DPB stays NV12; RFI/RC/quality-level machinery is untouched.
Shape:
- probe_rgb_direct now returns the chroma-siting bits to create the
session with (midpoint preferred, else cosited-even per axis); the open
verdict line gains "active" / "available(off; ...)" states.
- RgbProfileStack: the rgb-chained video profile rebuilt on the stack per
profiled-image creation after open (profile identity is by value) —
dmabuf imports become profiled VIDEO_ENCODE_SRC images (import cache
unchanged), the CPU staging image likewise (concurrent encode+compute).
- record_submit_rgb: steps 2–4 twin (dmabuf: single submit; CPU: staging
copy on the compute queue, semaphore-ordered); shared step-1/bookkeeping.
- begin_encode_cmd takes a SrcAcquire (CSC general / fresh-import FOREIGN
QFOT / cached visibility-only / staging TRANSFER_DST) so both paths
share the encode recording.
- RGB-direct frames skip the CSC per-slot resources entirely (make_frame
split into csc/common halves); cursor bitmaps warn once (EFC cannot
composite; gamescope — the flagship — embeds the cursor itself).
On-glass (780M RADV PHOENIX, host Mesa 26.0.4): all four smokes pass
(vulkan_smoke{,_av1,_rgb,_rgb_av1}); the EFC-encoded H265 stream decodes
clean and matches the CSC-encoded stream at 49.9 dB average PSNR (min
48.9) — within the design's ±1-code-value tolerance. (Raw-OBU ffmpeg
probing of the tiny AV1 dumps fails identically for BOTH paths —
pre-existing dump quirk, not a stream defect.) check+clippy+full unit
suite green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
589d48a975 |
fix(plugin-kit): SSE keepalive must outpace Bun's idle timeout (0.1.4)
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
decky / build-publish (push) Has been cancelled
deb / build-publish (push) Has been cancelled
deb / build-publish-host (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / web (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / bench (push) Has been cancelled
arch / build-publish (push) Has been cancelled
apple / swift (push) Has been cancelled
apple / screenshots (push) Has been cancelled
android / android (push) Has been cancelled
servePluginUi's Bun.serve leaves idleTimeout at Bun's 10s default, so the old 15s keepalive could never arrive — an idle status feed was closed before its first ping, which is exactly what a live host showed. Default is now 5s. Also adds the regression suite that should have caught it: the original test only covered a finite, self-driving stream. The new one exercises the production shape (PubSub-backed, published after the response opens) plus the keepalive — with a reader that does not re-enter read(), which is what made the first version of this test lie. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
424bab1c3a |
fix(plugin-kit): soften @unom/ui's card ring for the brand palette (0.1.3)
apple / swift (push) Successful in 1m20s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
decky / build-publish (push) Has been cancelled
deb / build-publish (push) Has been cancelled
deb / build-publish-host (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / web (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / bench (push) Has been cancelled
arch / build-publish (push) Has been cancelled
apple / screenshots (push) Has been cancelled
android / android (push) Successful in 14m52s
@unom/ui rings cards ring-2 ring-accent, sized for its own subtle accent; in this palette --accent is the brand violet, so every card shouted. The console already softens the same ring in its Card wrapper — plugin UIs now inherit that instead of each wrapping AnimatedCard themselves. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
5a27c02738 |
feat(encode/nvenc): LN1 phase-0 — slice-count + sub-frame-readback knobs and the slice-timing probe
apple / swift (push) Successful in 1m16s
apple / screenshots (push) Successful in 6m55s
windows-host / package (push) Successful in 11m18s
ci / web (push) Successful in 54s
ci / docs-site (push) Successful in 56s
ci / bench (push) Successful in 5m19s
android / android (push) Successful in 12m34s
decky / build-publish (push) Successful in 28s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 12s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 12s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 10s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 11s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 12s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 14s
arch / build-publish (push) Successful in 15m25s
deb / build-publish (push) Successful in 11m48s
deb / build-publish-host (push) Successful in 9m33s
ci / rust (push) Successful in 24m38s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 16m29s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 16m36s
docker / deploy-docs (push) Successful in 10s
PUNKTFUNK_NVENC_SLICES=N (2..=32, default off) splits H.264/HEVC frames into N slices (sliceMode 3); PUNKTFUNK_NVENC_SUBFRAME=1 (default off) arms enableSubFrameWrite + reportSliceOffsets on sync sessions only. Both experimental groundwork for sub-frame slice output (plan §7 LN1). nvenc_cuda_subframe_slice_probe (on-hardware, ignored) answers the LN1 go/no-go: spins lock_bitstream(doNotWait) against an in-flight frame and prints the (t_us, status, numSlices, bytes) timeline — incremental slice availability and its spacing, or all-at-completion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
d5a0f5012b |
fix(encode): RGB-direct probe — accept cosited-even chroma siting (what VCN EFC actually offers)
apple / swift (push) Successful in 1m17s
windows-host / package (push) Successful in 9m23s
apple / screenshots (push) Successful in 6m43s
ci / web (push) Successful in 1m8s
ci / docs-site (push) Successful in 1m8s
ci / bench (push) Successful in 6m28s
decky / build-publish (push) Successful in 21s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 12s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 13s
deb / build-publish (push) Successful in 9m33s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 9s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 10s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 9s
android / android (push) Successful in 17m10s
arch / build-publish (push) Successful in 17m21s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Failing after 7m30s
deb / build-publish-host (push) Successful in 12m39s
ci / rust (push) Successful in 26m58s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 15m26s
docker / deploy-docs (push) Successful in 30s
On-glass B0 result from the 780M (RADV PHOENIX, host Mesa 26.0.4): the probe returned no-709-narrow-midpoint because RADV advertises xChromaOffsets = COSITED_EVEN only — the VCN EFC does canonical H.26x left-cosited x-chroma, while the requirement was written to bit-match our 2x2-average (midpoint) shader. The delta is a half-pel chroma-x phase, imperceptible and unsignalled in our bitstream; EFC's siting is arguably the more correct one. Accept either siting bit per axis (model + range stay exact: 709 narrow); B1 will pass the preferred available bit. With this the 780M probes rgb_direct=available; both GPU smoke tests (H265 + AV1) pass on that box against host Mesa 26.0.4 — the first real-RADV validation of the poll fix, the quality-level control, and B0. (Container mesa alone can't run the H265 smoke: Fedora ships RADV with H264/H265 encode compiled out — AV1 only. Use the host ICD via VK_ICD_FILENAMES on Atomic boxes.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
d833cff470 |
fix(plugin-kit): resolve the --secondary text/surface collision in theme.css (0.1.2)
apple / swift (push) Successful in 1m19s
apple / screenshots (push) Successful in 6m34s
ci / web (push) Successful in 51s
ci / docs-site (push) Successful in 1m2s
ci / bench (push) Successful in 5m24s
deb / build-publish (push) Successful in 9m25s
decky / build-publish (push) Successful in 20s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 27s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 9s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 11s
deb / build-publish-host (push) Successful in 9m13s
android / android (push) Successful in 18m26s
arch / build-publish (push) Successful in 18m56s
ci / rust (push) Successful in 19m2s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 15m25s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 15m43s
docker / deploy-docs (push) Successful in 23s
@unom/ui reads --secondary as muted TEXT; this palette (like the console's) uses it as a dark SURFACE, so EmptyState captions, badge text and table headers rendered dark-on-dark. Tailwind derives both utilities from one token, so the text lane is re-pointed at --muted-foreground here — once, for every plugin, instead of in each plugin's stylesheet. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
34ec57cb52 |
test(encode/nvenc-linux): on-hardware assertion that stream-ordered submit arms
apple / swift (push) Successful in 1m20s
apple / screenshots (push) Successful in 6m19s
windows-host / package (push) Successful in 11m33s
ci / web (push) Successful in 55s
ci / docs-site (push) Successful in 1m2s
android / android (push) Successful in 12m27s
ci / bench (push) Successful in 5m21s
decky / build-publish (push) Successful in 1m56s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 11s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 10s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 10s
arch / build-publish (push) Successful in 16m24s
deb / build-publish (push) Successful in 9m21s
deb / build-publish-host (push) Successful in 9m24s
ci / rust (push) Successful in 19m1s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 23m11s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 22m26s
docker / deploy-docs (push) Successful in 24s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
cd36c46388 |
perf(encode/nvenc-linux): LN2 v1 — stream-ordered submit via NvEncSetIOCudaStreams
Bind the session's IO streams to the encode thread's high-priority copy stream: in sync-retrieve depth-1 use the per-frame input copy and cursor blend now enqueue with NO cuStreamSynchronize and encode_picture orders after them on the stream. Same stream both directions, so the encode's completion is inserted into the stream and later work (the next frame's copy into a reused ring slot) waits for it. Soundness gate: the fast path engages only when pending is empty (true depth-1 usage) — every prior encode was drained by a blocking poll, and the caller holds the frame payload across the matching poll (contract now documented on Encoder::submit; both host loops already comply). Pipelined callers and PUNKTFUNK_NVENC_ASYNC mode keep the blocking copies. True zero-copy input registration (registering the worker-owned IPC buffer directly) stays the LN2 v2 follow-up — it needs a contiguous worker-pool NV12 layout and a registration<->IPC-mapping lifetime tie. PUNKTFUNK_NVENC_STREAM_ORDERED=0 restores the old blocking behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
59b6d3796b |
perf(encode/nvenc-linux): LN0 — sampled submit/retrieve-lock split, sub-frame caps, zeroReorderDelay
Latency plan §7 LN0 (Linux/NVIDIA encode follow-on): - sampled PUNKTFUNK_PERF submit split (copy/blend/map/pic) in nvenc_cuda — the host loop's submit_us folds all four together; the D2D input copy is the LN2 zero-copy target and now measurable on its own - sampled blocking lock_bitstream timing on pf-nvenc-out — in two-thread mode the host loop's wait_us wraps a non-blocking poll, so the real encode wait was measured by no timer - caps probe + log SUPPORT_SUBFRAME_READBACK / SUPPORT_DYNAMIC_SLICE_MODE (LN1 sub-frame slice-output prerequisites, fleet visibility) - explicit zeroReorderDelay=1 in the shared low-latency config (P-only + no lookahead has no reordering anyway; pins the bit against preset or driver drift; shared with the Windows backend) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
78dba293a8 |
feat(encode): Vulkan Video B0 — vendored VK_VALVE_video_encode_rgb_conversion + RGB-direct probe telemetry
apple / swift (push) Successful in 1m16s
apple / screenshots (push) Successful in 6m16s
windows-host / package (push) Successful in 10m2s
ci / web (push) Successful in 1m13s
ci / docs-site (push) Successful in 1m18s
android / android (push) Successful in 13m46s
arch / build-publish (push) Successful in 12m58s
ci / bench (push) Successful in 7m23s
decky / build-publish (push) Successful in 38s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 21s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 14s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 17s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 16s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 14s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 12s
deb / build-publish (push) Successful in 9m35s
deb / build-publish-host (push) Successful in 9m43s
ci / rust (push) Successful in 28m29s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 21m33s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 21m42s
docker / deploy-docs (push) Successful in 25s
First phase of design/vulkan-rgb-direct-encode.md (punktfunk-planning): make the captured BGRx dmabuf the direct encode source with the VCN EFC front-end doing the 709-narrow CSC — deleting the per-frame compute CSC, both plane copies, the semaphore hop and one queue submit. B0 changes nothing about the encode path. It vendors the extension surface (vk_valve_rgb.rs — ash 0.38 predates it; same rationale and style as the vk_av1_encode module) and probes at open whether this host qualifies: extension present (Mesa >= 26.0 + EFC hardware) → feature bit → conversion caps cover the compute shader's exact math (709 / narrow / midpoint both axes) → encode-src format set offers B8G8R8A8 with DRM-modifier tiling. The verdict is one INFO line (rgb_direct=available | first missing requirement) — the field telemetry that decides where B1 can default on. Verified: cargo check + clippy clean + unit tests green (Linux box); the probe short-circuits to no-ext on non-RADV drivers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
cfdec2729d |
perf(encode): Vulkan Video — explicit VCN preset, persistent bitstream map, CSC split timing
apple / swift (push) Successful in 1m19s
apple / screenshots (push) Successful in 6m25s
windows-host / package (push) Successful in 9m18s
android / android (push) Has been cancelled
arch / build-publish (push) Has been cancelled
ci / web (push) Successful in 46s
ci / docs-site (push) Successful in 51s
ci / bench (push) Successful in 6m15s
decky / build-publish (push) Successful in 34s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 15s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 16s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 15s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 14s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 15s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m36s
deb / build-publish (push) Successful in 12m42s
deb / build-publish-host (push) Successful in 13m40s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 16m53s
ci / rust (push) Successful in 28m29s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 22m1s
docker / deploy-docs (push) Successful in 28s
Field follow-up to
|
||
|
|
6dc195f982 |
fix(encode): Vulkan Video poll() must block per the depth-1 pump contract
apple / swift (push) Successful in 1m20s
windows-host / package (push) Successful in 9m30s
apple / screenshots (push) Successful in 6m39s
ci / web (push) Successful in 50s
ci / docs-site (push) Successful in 1m2s
ci / bench (push) Successful in 8m45s
decky / build-publish (push) Successful in 20s
android / android (push) Successful in 20m36s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 44s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5m4s
ci / rust (push) Successful in 18m50s
deb / build-publish (push) Successful in 12m45s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 11s
arch / build-publish (push) Successful in 23m15s
deb / build-publish-host (push) Successful in 11m37s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 11m4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 15m29s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 13m4s
docker / deploy-docs (push) Successful in 12s
The session pump's depth-1 loop (capture → submit → poll) treats a poll()
None as "the backend holds the frame internally, re-poll next tick" —
true only of the libav AMF/QSV wrappers, whose codecs genuinely hold ~2
frames. The Vulkan Video backend probed its slot fence with
get_fence_status instead, so the AU of every frame — finished on the
ASIC in ~5 ms — sat unharvested until the tick AFTER the next frame was
submitted: encode_us read as one full frame period (~17 ms at 60 Hz vs
VAAPI's ~5.3 ms on the same VCN, the AMD field report) and every frame
shipped a frame period late — one frame of avoidable glass-to-glass
latency on the path that exists to beat libav VAAPI.
Wait the oldest in-flight slot's fence in poll() instead, matching the
sync NVENC backend's blocking lock_bitstream and the documented
Capturer::pipeline_depth contract ("capture → submit → poll-blocks").
Bounded by ENCODE_FENCE_TIMEOUT_NS like enqueue()'s backpressure wait,
for the same reason: poll runs on the thread the stall recovery runs on,
so a wedged GPU must surface as an error, not park it. None now only
means "nothing submitted". Covers H265 and AV1 (shared poll).
Verified: cargo check + DPB/RPS unit tests green (home-worker-5); the
GPU smoke tests fail at session open on that box's NVIDIA driver
identically on unmodified origin/main — pre-existing, needs the RADV
box for on-glass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
da259d5b79 |
feat(plugin-kit): browser-safe ./wire subpath for provider schemas (0.1.1)
apple / swift (push) Successful in 1m22s
apple / screenshots (push) Successful in 6m35s
ci / web (push) Successful in 1m13s
ci / docs-site (push) Successful in 1m14s
android / android (push) Successful in 17m3s
decky / build-publish (push) Successful in 18s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 11s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 9s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 8s
arch / build-publish (push) Successful in 16m33s
ci / bench (push) Successful in 14m48s
deb / build-publish (push) Successful in 14m48s
ci / rust (push) Successful in 22m36s
deb / build-publish-host (push) Successful in 18m16s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 18m30s
docker / deploy-docs (push) Successful in 23s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 28m25s
Plugin contracts share ProviderEntry/Artwork/LaunchSpec/PrepStep with their UIs; the kit root stays node-only (reconcile keeps the HostClient transport). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
4094f6208d |
fix(web): load the inlang plugin from node_modules, not a CDN
audit / bun-audit (push) Successful in 13s
ci / docs-site (push) Successful in 54s
ci / web (push) Successful in 56s
apple / swift (push) Successful in 1m19s
audit / cargo-audit (push) Successful in 3m6s
decky / build-publish (push) Successful in 19s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 55s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 10s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 11s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 11s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 10s
apple / screenshots (push) Successful in 6m41s
deb / build-publish (push) Successful in 10m14s
ci / bench (push) Successful in 10m59s
windows-host / package (push) Successful in 11m11s
deb / build-publish-host (push) Successful in 13m54s
android / android (push) Successful in 17m22s
arch / build-publish (push) Successful in 17m37s
ci / rust (push) Successful in 22m53s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 20m22s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 18m48s
docker / deploy-docs (push) Successful in 29s
`web/project.inlang/settings.json` pointed `modules` at https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js — inlang's stock `paraglide-js init` scaffolding, which nobody had a reason to keep. It made `bun run codegen` need the network at build time, so in a sandbox that has none (the Nix build; any air-gapped CI) the plugin import failed and paraglide compiled ZERO messages. That failure is silent by design: the inlang SDK logs a PluginImportError as a WARNING, paraglide still prints "Successfully compiled" and exits 0, vite bundles the empty message set, and the console only dies at request time inside renderToReadableStream because every `m.foo()` is undefined. Reported from a NixOS host running punktfunk-web-server. The plugin is a normal npm package, so depend on it like one: add @inlang/plugin-message-format as a devDependency and reference it by relative path. `loadProjectFromDirectory` (which both `paraglide-js compile` and the vite plugin use) imports non-`http` modules straight off disk, and the shipped dist/index.js is a self-contained bundle with no imports of its own, so it loads from the data: URL exactly as the CDN copy did. Compiles 268 messages offline, with no project.inlang/cache round-trip. Add tools/check-i18n.mjs, run at the end of `codegen`, so this can never ship silently again: it fails the build on a remote `modules` entry, a module that does not resolve, or a compiled message count below what messages/en.json defines. Verified it catches all three (remote URL, missing plugin, corrupt plugin that compiles to 0 messages) and passes a healthy build. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
0ed8ca90f2 |
fix(plugin-kit): regenerate bun.lock (duplicate package path after react devDep add)
android / android (push) Has been cancelled
apple / swift (push) Has been cancelled
apple / screenshots (push) Has been cancelled
arch / build-publish (push) Has been cancelled
ci / web (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / bench (push) Has been cancelled
deb / build-publish (push) Has been cancelled
deb / build-publish-host (push) Has been cancelled
decky / build-publish (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
8d72e1d27e |
feat(plugin-kit): @punktfunk/plugin-kit 0.1.0 — the Effect plugin framework
ci / rust (push) Has been cancelled
android / android (push) Has been cancelled
apple / swift (push) Has been cancelled
apple / screenshots (push) Has been cancelled
arch / build-publish (push) Has been cancelled
ci / web (push) Has been cancelled
ci / bench (push) Has been cancelled
ci / docs-site (push) Has been cancelled
deb / build-publish-host (push) Has been cancelled
deb / build-publish (push) Has been cancelled
decky / build-publish (push) Has been cancelled
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
windows-host / package (push) Has been cancelled
The ~80% of every plugin that was copy-pasted (rom-manager ↔ playnite), extracted as one Effect-v4 package: - runtime: definePluginKit — async-main boundary hiding a ManagedRuntime (two-effect-instances discipline), signal-driven interruption with a bounded shutdown grace - config: Schema-driven raw round-trip (defaults only in the Schema via withDecodingDefaultKey + encodingStrategy omit; file stays authored-shape), atomic writes, world-writable refusal, changes stream - cache-store: disposable derived state, corrupt→empty, write-through - reconcile: kit-owned provider wire schemas + typed client over the skew-safe untyped pf.request seam - sync-engine: generic poll/watch/debounce/single-flight-coalesce/ fingerprint-skip engine with a status PubSub (the SSE feed) - ui-server + sse: effect/unstable/httpapi behind servePluginUi with core-only env layers (validated by the phase-0 spikes); raw SSE route (httpapi has no event-stream media type) - cli: minimal command dispatcher reusing the plugin layer graph (deliberately not effect/unstable/cli — it needs platform packages) - react subpath: plugin router (path→hash→fallback deep-link restore + pf-ui:navigate bridge), ResultGate, sseAtom, resolvePluginBase - theme.css: the console's violet identity packaged for plugin UIs 18 bun tests incl. the two phase-0 spikes; publish workflow mirrors sdk-publish (tag plugin-kit-v*; 0.1.0 published manually). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c15c80718a |
chore(sdk): bump @punktfunk/host to 0.1.2
Manual publish (no sdk-v tag — the version was published directly so the plugin-kit and rewritten rom-manager can consume pluginStateDir/pluginIngestDir from the registry; the previously published 0.1.1 predates the security-tiers merge and lacks those exports). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
bb58fde369 |
feat(plugin-kit): scaffold @punktfunk/plugin-kit + phase-0 spikes
Two spikes validating the riskiest seams of the plugin-kit design before implementation: - HttpApi (effect/unstable/httpapi) served on Bun behind the SDK's servePluginUi using ONLY effect-core layers (Etag.layerWeak, Path.layer, HttpPlatform.layer + FileSystem.layerNoop) — no platform package. Auth, schema validation, and static fallthrough all verified end-to-end. - Browser client prefix strategy for the console proxy: both transformClient+prependUrl AND baseUrl preserve the /plugin-ui/<id> path prefix. Nested Schema.withDecodingDefaultKey defaults confirmed (Effect-valued defaults; encodingStrategy "omit" restores raw shape on encode). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
de7b54d4e0 |
fix(core): remaining 15 sweep lows — client, clipboard, C ABI (v10), FEC, GSO, GTK
ci / docs-site (push) Successful in 58s
ci / web (push) Successful in 1m11s
apple / swift (push) Successful in 1m20s
decky / build-publish (push) Successful in 29s
android / android (push) Has been cancelled
apple / screenshots (push) Has been cancelled
arch / build-publish (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / bench (push) Has been cancelled
deb / build-publish (push) Has been cancelled
deb / build-publish-host (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
flatpak / build-publish (push) Has been cancelled
release / apple (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
windows-host / package (push) Has been cancelled
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Has been cancelled
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Has been cancelled
windows / build (aarch64-pc-windows-msvc) (push) Has been cancelled
windows / build (x86_64-pc-windows-msvc) (push) Has been cancelled
Second and final batch from the 2026-07-20 core-sweep lows: client: - connect() timeout now sets `quit` before shutdown, so a handshake that completes after the deadline closes with QUIT_CLOSE_CODE instead of leaving the host lingering (virtual display up) for a reconnect that never comes. - probe_result: saturating_add on the wire-supplied wire_packets + send_dropped counters (debug-build overflow panic / release wrap). - the standing-latency bleed no longer sets flush_in_window: that flag is the ABR's SEVERE (×0.7) verdict, and the bleed fires only on provably loss-free windows the controller itself scores as fine. clipboard: - fetch_cancels pruned on every new fetch (was: one dead oneshot per paste for the session). - serve chunks gated on a parked waiter + capped at CLIP_FETCH_CAP with an Error event (was: unbounded silent accumulation under any req_id). - serve_inbound park bounded by FETCH_STALL_SECS + send.stopped() (was: an unanswered FetchRequest parked the task, waiter, and bi-stream forever; ~100 of them exhaust the connection's bidi budget). C ABI (ABI_VERSION 9 → 10, header regenerated, additive only): - new punktfunk_connection_clock_offset_now_ns — the LIVE re-synced offset (Swift/Kotlin latency math read the frozen connect-time value ~40ms wrong after a wall-clock step). - to_config: checked u64→usize narrowing of max_frame_bytes (32-bit armeabi truncated >4GiB to a plausible residue). - host_poll_input: no &mut held across the embedder callback (re-entry aliased it — UB under noalias); mid-drain callback clears now stick. - next_audio_pcm: DTX (empty) payloads skipped — decode synthesized 120ms of concealment per 5ms slot and grew the playout ring forever. - next_clipboard releases the parked payload on an empty poll (a one-off 50MiB paste stayed resident all session). - frames_dropped / wants_decode_latency write their documented 0/false defaults before the NULL-handle check. - gamepad constant docs match pick_gamepad() reality (DualSenseEdge/ SwitchPro landed; DualSense/DS4 honored on Windows UMDF too). FEC: - gf8 reconstruct/reconstruct_into reuse the (k,m) codec cache like encode_into (was: fresh 230×200 generator + decode inversion per lossy block on the pump thread). - vendored fec-rs: the 8 safe wrap_mul_slice shims assert equal lengths (x86 SIMD callees bound stores on input.len() — safe-code OOB write); ReconstructShard's safety contract gains the len()==get().len() clause and reconstruct_internal sizes raw slices from the slice. transport/GTK: - Linux GSO super-buffer capped at the real UDP payload ceiling (65487) not 65535 — seg sizes ≥1024 could EMSGSIZE and latch GSO off process-wide, blamed on the network. - GTK settings dialog no longer rewrites an unlisted-but-valid stored gamepad preference to "auto" on close. Already fixed on main (verified stale, skipped): the reassembler FEC ceiling, wants_decode_latency's third term, request_probe rollback + the generalized probe watchdog. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
76ac3cf867 |
fix(core): five sweep lows — seal-lane fallback, flush partial, codec echo, idle clamp, pair-name UTF-8
From the 2026-07-20 punktfunk-core quality sweep's adjudicated lows (~/punktfunk-sweeps/punktfunk-core-2026-07-20.json), each with a regression test: - session: the two-lane seal's dead-worker fallback dropped the frame's back half and returned Ok with half an access unit; the corpse lane was also never respawned. The send-failure arm now reclaims the tail (single-lane seals the WHOLE frame) and both failure arms drop the lane so the next large frame respawns it. A recv-side death now surfaces as an error instead of silent truncation. - reassemble: Reassembler::reset() left pending_partial parked, so a pre-flush stale partial survived Session::flush_backlog and was delivered as the first "frame" after a jump-to-live. - caps: resolve_codec echoed a non-conformant multi-bit preferred byte verbatim (downstream from_wire folds it to HEVC — possibly outside the shared set). It now isolates one bit of the intersection. - endpoint: stream_transport_idle only floored the value; an absurd operator-supplied idle timeout blew past QUIC's VarInt ms ceiling and panicked host startup through the expect. Clamped to 1s..1h. - pairing: PairRequest::encode cut the device name at a raw byte-64 boundary, splitting multi-byte UTF-8 (host showed U+FFFD forever); it now shares Hello's char-boundary truncate_to. The frozen-FEC-ceiling finding (reassemble.rs:109) was already fixed on main by the sweep's high-severity commit — skipped as stale. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
f4ec18d528 |
chore(core): fix build.rs + crate-doc drift left by the W7/W8 splits
- build.rs: drop the stale `rerun-if-changed=src/client.rs` (the file became client/ in W7; the path never fires). - lib.rs: the crate doc's module list named 6 of ~19 modules — add the missing ones (config/error/stats/input/reject/reanchor/render_scale/ audio/wol + the quic-gated control-plane group), without intra-doc links to feature-gated modules. - quic/mod.rs: the module doc still described the deleted `msgs` module; list the actual post-split module set. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
ce51a2ba74 |
refactor(core): decompose the client run_pump monolith into pump/ submodules
client/pump.rs was a single 1192-line async fn stacking six concerns.
It is now a 190-line orchestrator (same spawn order, same channel
wiring) over five focused modules:
- pump/handshake.rs — connect + Hello/Welcome/Start + skew handshake +
hole punch + Session construction (HandshakeOut)
- pump/input_task.rs — the gamepad snapshot/removal/arrival re-send
state machine + passthrough input forwarding
- pump/control_task.rs— the control-stream select loop (renegotiation,
probes, bitrate acks, clock re-sync, clip
metadata), bundled as ControlTask
- pump/datagram_task.rs — the datagram tag demux + rumble reorder gate
- pump/data.rs — the blocking data-plane pump (loss reports, ABR
+ capacity probe, jump-to-live detectors,
standing-latency bleed), bundled as DataPump
Every body moved verbatim (dedent + arg-struct destructures aliasing
the original binding names); no per-frame indirection added — the pump
loop, its locals, and the hot-path shape are byte-equivalent. The
Ctrl/DataPump arg structs exist only to stay under too_many_arguments.
196 lib tests pass; clippy clean on --features quic AND
--no-default-features (--all-targets); include/punktfunk_core.h
byte-identical; fmt clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
eacaaa5cd8 |
refactor(core): peel session.rs anti-replay, perf telemetry, and seal lane into submodules
session.rs (1203) sharpens down to the two hot-path state machines +
lifecycle (887): ReplayWindow + seq_of + their tests -> session/replay.rs;
the PUNKTFUNK_PERF trio PumpPerf/SealPerf/TimedCoder -> session/perf.rs;
the Phase-1.5 lane machinery SealLane/SealJob/seal_wire_slice/
TWO_LANE_MIN_PACKETS -> session/seal.rs. Facade pattern (session.rs stays
the parent file); pub use keeps session::{PumpPerf,SealPerf} stable and
lib.rs re-exports are untouched. Pure code motion + pub(super) bumps —
seal_frame_inner/poll_frame/poll_input bodies unchanged; the
wire-equivalence tests stay co-located with the seal path they pin.
196 lib tests pass, clippy --features quic --all-targets clean, fmt clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
e0a1edb9d4 |
refactor(core): co-locate the quic wire tests with their modules
quic/tests.rs (1813 lines, 43 tests) was the W7 split's leftover: the source moved into handshake/caps/control/clock/pairing/pake/datagram/ endpoint/clipstream/io but every test stayed in one monolithic file. Each test now lives in a #[cfg(test)] mod tests at the foot of the module it exercises, verbatim. The two CompositorPref/GamepadPref wire/name tests moved to config.rs (where those enums live), so they now also run under --no-default-features. The clip_loopback and ctrl_framing integration mods share connect_pair via a cfg(test)-only quic/test_util.rs. Test-only motion: 196 lib tests pass unchanged on macOS, clippy --features quic --all-targets clean, include/punktfunk_core.h byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a53369bf21 |
fix(ci): green main again — clock_sync callers, two clippy denials, an unused import
ci / web (push) Successful in 56s
ci / docs-site (push) Successful in 1m11s
apple / swift (push) Successful in 1m20s
decky / build-publish (push) Successful in 36s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 10s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 10s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 9s
ci / bench (push) Successful in 7m0s
flatpak / build-publish (push) Successful in 6m25s
deb / build-publish (push) Successful in 9m53s
docker / deploy-docs (push) Successful in 28s
release / apple (push) Successful in 9m25s
deb / build-publish-host (push) Successful in 10m0s
windows-host / package (push) Successful in 15m34s
apple / screenshots (push) Successful in 6m30s
arch / build-publish (push) Successful in 18m15s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 3m6s
android / android (push) Successful in 19m13s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 3m14s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 14m6s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 19m3s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 4m37s
ci / rust (push) Successful in 26m59s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 5m31s
`ci.yml`'s clippy gate has been failing on main since the pre-0.16.0 sweep landed, and because clippy stops at the first crate it can't compile, the visible error was only ever the first of four. `ci.yml` is not tag-triggered, so v0.16.0 cut and shipped over a red main; none of this reaches the release artifacts (the two E0308s are in a test binary and a dev tool, and the rest are lints) but the gate has been blind since. Fixed, in the order clippy surfaced them: - clients/probe failed to COMPILE (E0308, x2). `810d918d` moved `clock_sync` onto the resumable `io::MsgReader` but only updated the client pump, leaving the probe passing a bare `&mut RecvStream`. The probe now wraps the control stream in a `MsgReader` at `open_bi` and threads that everywhere — Welcome, the --remode and --bitrate watchers, and the speed-test result read — which is also what the refactor was for: those reads sit behind timeouts and `select!`, exactly where a straddling frame would desync the stream for the rest of the run. - pf-capture: `SPA_META_Cursor as u32` is a `u32 -> u32` no-op (`clippy::unnecessary_cast`). Line 1274 already passes the same constant uncast, so the type is not in question. - pf-inject: `noop as usize` on the SIGUSR1 wake handler added in `986402f7` trips `clippy::function_casts_as_integer`; goes via `*const ()` as the lint asks. Same value in the `usize`-typed `sa_sigaction` slot. - punktfunk-core: the `ctrl_framing` test module's `use super::*` is unused, which `-D warnings` promotes to an error. Verified with CI's own commands on a Linux box (this is all Linux-gated code, so a Mac cannot check it): `cargo clippy --workspace --all-targets --locked -- -D warnings` finishes clean, `cargo build --workspace --locked` succeeds, and `cargo test --workspace --locked` exits 0 with no failures — including punktfunk-core's 196-test suite, which covers the control-stream framing the probe change touches. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
3213c1b61c |
ci(flatpak): resolve over TCP so the flathub bootstrap stops failing on tag pushes
apple / swift (push) Successful in 1m22s
apple / screenshots (push) Successful in 6m43s
ci / web (push) Successful in 50s
ci / docs-site (push) Successful in 1m17s
ci / rust (push) Failing after 7m10s
ci / bench (push) Successful in 6m57s
decky / build-publish (push) Successful in 26s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 11s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 11s
arch / build-publish (push) Successful in 12m9s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 13s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 12s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 11s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 11s
deb / build-publish (push) Successful in 8m55s
android / android (push) Successful in 17m5s
deb / build-publish-host (push) Successful in 9m25s
docker / deploy-docs (push) Successful in 23s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 15m5s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 14m38s
flatpak / build-publish (push) Failing after 8m1s
The flathub remote-add has now burned its entire retry budget and failed the job on three consecutive tag builds — v0.15.0, the v0.15.0 re-point, and v0.16.0 — each one needing a manual re-run to land the bundle. The cause was already root-caused here on 2026-07-11 (see the Tooling step's comment): home-runner-1's Docker embedded resolver at 127.0.0.11 drops UDP lookups while the shared multi-org fleet is saturated. Nothing retransmits a dropped datagram, so the lookup simply times out. The fix then was to widen retry.sh to 10 attempts (~9 min), which comfortably outlasts a main push's ~8-workflow fan-out — but a TAG push starts 13 workflows at once, and that burst now outlives the whole budget. Retrying harder is chasing the symptom; the transport is the problem. `options use-vc` moves resolution to TCP, where the kernel retransmits and a query cannot be silently lost under load. Same resolver and search path — only the transport changes — so internal names still resolve exactly as before. Deliberately no additional nameservers: a public resolver in the list could answer an internal name (git.unom.io) with NXDOMAIN. retry.sh stays as the backstop for real upstream blips. Applied non-fatally, because Docker bind-mounts /etc/resolv.conf and may present it read-only: a DNS tuning that cannot be applied must not be the thing that fails a release build. If the write is refused we warn and stay on UDP, i.e. exactly today's behaviour. Scoped to the flatpak workflow, where the failure is actually evidenced, rather than applied fleet-wide on suspicion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
b3adfb3a56 |
ci(release): pin Xcode DerivedData so it stops filling the mac runner's disk
apple / swift (push) Successful in 1m23s
release / apple (push) Successful in 9m19s
ci / web (push) Successful in 52s
ci / docs-site (push) Successful in 59s
apple / screenshots (push) Successful in 6m31s
ci / rust (push) Failing after 6m18s
ci / bench (push) Successful in 5m7s
deb / build-publish (push) Successful in 8m58s
decky / build-publish (push) Successful in 30s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 21s
arch / build-publish (push) Failing after 16m42s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 11s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 46s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 15s
android / android (push) Successful in 18m40s
deb / build-publish-host (push) Successful in 9m25s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m5s
docker / deploy-docs (push) Successful in 25s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 19m38s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 19m36s
v0.16.0's Apple leg failed at the xcframework build with "No space left on device (os error 28)": the runner's boot volume was at 100% with 152 MB free. None of the four `xcodebuild archive` calls passed -derivedDataPath, so each one used the default ~/Library/Developer/Xcode/DerivedData/<name>-<hash> — and that hash is derived from the PROJECT'S ABSOLUTE PATH. act_runner rotates its workspace (~/.cache/act/<hash>/hostexecutor), so every rotation looked like a new project to Xcode and minted a fresh ~760 MB tree. Nothing ever collects those: they live outside the workspace, so act's own cleanup never sees them. 31 had accumulated in three days (17 -> 20 July), which with the 12 GB shared ModuleCache came to 32 GB — on a 228 GB volume already 95% full. Pin all four archives to one path. The tree is now REUSED rather than multiplied, which also keeps the module cache warm instead of rebuilding it per run. The new step additionally prunes anything week-stale left in the default root, covering both the legacy per-path trees and any other job that lands there. Cleared by hand on home-mac-mini-1 to unblock the release (152 MB -> 31 GB free); this is the change that stops it coming back. Note the same class of problem bit the Windows runner the same night from the other direction — its disk-cleanup task purges C:\t and deleted files out from under ISCC mid-pack — which is worth its own look and is NOT addressed here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
191c9a4e18 |
chore(release): bump workspace version to 0.16.0
audit / bun-audit (push) Successful in 18s
apple / swift (push) Successful in 1m34s
audit / cargo-audit (push) Successful in 2m10s
ci / web (push) Successful in 54s
ci / docs-site (push) Successful in 1m3s
apple / screenshots (push) Failing after 1m56s
ci / rust (push) Failing after 6m33s
ci / bench (push) Successful in 7m17s
android-screenshots / screenshots (push) Successful in 2m58s
decky / build-publish (push) Successful in 19s
release / apple (push) Successful in 11m22s
deb / build-publish (push) Successful in 11m14s
deb / build-publish-host (push) Successful in 11m17s
android / android (push) Successful in 13m10s
arch / build-publish (push) Successful in 14m6s
web-screenshots / screenshots (push) Successful in 2m57s
linux-client-screenshots / screenshots (push) Successful in 7m33s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 22m38s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 22m47s
flatpak / build-publish (push) Successful in 8m9s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 8m7s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 9m3s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 13s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 13s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 13s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 15s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 14s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 12s
docker / deploy-docs (push) Successful in 9s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 6m17s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 4m3s
windows-host / package (push) Successful in 12m35s
MINOR, not the 0.15.1 originally planned: the 24 commits since v0.15.0 carry 7 features, and they are not incidental — they change the plugin runner's privilege model. It stops holding the console's full-admin token (scoped plugin-token lane), the Windows runner drops from SYSTEM to LocalService, public-registry plugin installs are gated behind an explicit flag, and the systemd user unit is sandboxed. Operators have workflow-visible changes to absorb (a plugin genuinely needing the admin surface must now set PUNKTFUNK_MGMT_TOKEN; installing outside the @punktfunk scope needs --allow-public-registry). A patch label would understate all of that, and sdk-publish pushes this version straight to consumers. The other 12 fixes are largely the pf-encode/zerocopy/capture/inject quality sweep landing: teardown deadlocks, error-path leaks, a GL->CUDA copy race, an odd-height NV12 overrun, a cursor-meta OOB read, plus the two loss-recovery gaps 0.15.0 left open (Vulkan Video never got the LTR taint sweep; QSV's sweep skipped its modal single-swept-slot case). `WIRE_VERSION` stays 2 and the driver protocol stays v4 — pairings, clients and installed drivers keep working. The C ABI moves 8 -> 9 (PunktfunkFrame grows `received_ns`, so receipt is stamped at the session boundary rather than at the embedder's pull); the gitignored Apple xcframework needs a rebuild for that to reach the Apple clients. No OpenAPI path changes (45 before and after) — the new plugin-token lane is auth-layer only — so api/openapi.json moves info.version only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>v0.16.0 |
||
|
|
dd558be55b |
fix(core/client): fix the four ways a speed-test probe corrupts ABR and the report tick
ci / web (push) Successful in 1m3s
ci / docs-site (push) Successful in 1m2s
apple / swift (push) Successful in 1m19s
decky / build-publish (push) Successful in 53s
deb / build-publish (push) Successful in 12m22s
ci / bench (push) Successful in 6m13s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 44s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 6m32s
ci / rust (push) Failing after 9m2s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 11s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m22s
release / apple (push) Successful in 9m50s
windows-host / package (push) Failing after 13m7s
deb / build-publish-host (push) Successful in 13m1s
arch / build-publish (push) Failing after 14m11s
apple / screenshots (push) Failing after 3m37s
android / android (push) Successful in 14m56s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 6m8s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 8m32s
flatpak / build-publish (push) Failing after 8m13s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 6m2s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 6m33s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 7m44s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 20m32s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 20m13s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 9m0s
docker / deploy-docs (push) Successful in 26s
There is one `ProbeState` per session and no correlation id, and two independent requesters share it: the pump's startup link-capacity probe and the embedder's `NativeClient::request_probe` (the shipped "Test connection" in the Windows GUI and the Linux GTK app). The startup path had a busy check, a watchdog and a window rebase; the embedder path had none of them, and the two collide by default — both shipped speed tests call `request_probe` on the statement right after `connect()`, and the pump's probe fires 2 s later, inside that burst. Four defects, one cluster: - The pump overwrote the shared slot unconditionally. Mid-burst it drops `base_packets`/`base_bytes`, the pump re-snapshots them against the host's full-burst denominator, and the user's speed test reports roughly an order of magnitude low; if the result lands first instead, the reset wipes `done` and the embedder's poll loop never sees its own measurement. Now it defers and retries rather than stealing the slot. - An unanswered embedder probe never timed out. `probe_active` gates the entire report tick — LossReport, the ABR window feed, the standing-latency ladder and a pending ClockResync all live inside it. A host that ignores ProbeRequest is an anticipated configuration (the startup path was given a 6 s timeout for exactly that) so the embedder path could latch `active` forever and silently switch off every adaptation mechanism for the rest of the session. Now a watchdog covers a probe of either origin. - `request_probe` latched `active` before `try_send`, so a full or closed ctrl channel returned `Closed` to the caller while leaving the session wedged in the state above. It now rolls back, mirroring the startup path. - Only the startup path rebased the ABR window past the burst. Probe filler is counted into `bytes_received` for every accepted datagram but never reaches the decoder, and the tick is suppressed for the whole burst, so the first post-burst window read the burst rate as `actual_kbps`. That poisons `proven_kbps`, a monotone high-water mark that is never decayed, which disables the x1.5 evidence-gated climb guard for the session and authorizes a climb into a rate the decoder has never carried. The rebase now happens on the falling edge of any probe, and covers the loss/packet anchors too so the first post-burst LossReport isn't divided by a filler-inflated packet count. Also: `wants_decode_latency` advertised on two of the three terms the pump actually requires to arm ABR, omitting `resolved_bitrate_kbps > 0`, so against an old host that reports no rate an embedder fed decode latency to a controller that never runs. No wire or ABI change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
810d918d36 |
fix(core/quic): make the control-stream read cancel-safe
`io::read_msg` frames a message with two `quinn::RecvStream::read_exact` calls, and quinn documents `read_exact` as explicitly NOT cancel-safe: the bytes it has already taken out of the stream live only in the future's own buffer and nothing puts them back on drop. Both long-lived control loops drive that read from a `tokio::select!` arm — the client pump alongside `ctrl_rx.recv()` and the resync tick, the host alongside probe/reconfig/clip-offer channels — and neither uses `biased;`, so any sibling that becomes ready ends the iteration and drops a partially-progressed read. `clock_sync` has the same shape via `tokio::time::timeout`, which can fire mid-frame before the session even starts. A control frame only has to straddle two wakeups for this to bite: a ClipOffer carries up to 16 kinds x 128 bytes of MIME, ~2 KB, which exceeds one QUIC packet and is subject to the pacer; any frame whose second half is lost or reordered does it too. Losing the consumed length prefix misaligns the stream permanently — the next read takes two payload bytes as a length, so Reconfigured, ProbeResult, BitrateChanged, ClockEcho and ClipState all decode as garbage and are silently dropped, and a bogus length up to 64 KiB parks the read forever. Mode switches, adaptive bitrate, mid-stream clock resync and clipboard are dead for the rest of the session; only a reconnect recovers, and the log shows at most one `warn!`. Add `io::MsgReader`, which keeps the frame in progress in the reader rather than the future and reads via quinn's cancel-safe `read`, and switch the three cancelling sites to it (client control loop, host control loop, clock_sync). The sequential handshake/pairing callers keep the plain `read_msg`, whose doc comment now states the constraint. No wire bytes and no ABI change — only how the same length-prefixed frames are assembled. Tests: a frame split across two wakeups with the read cancelled in between must resume and leave the following frame correctly framed (confirmed to fail — it hangs on the desynced stream — against the old behavior), plus a zero-length frame round-trip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
7b2cdf5a7a |
fix(core/net): bind the data plane to the authenticated peer + stop adaptive FEC wedging large frames
Four defects from the punktfunk-core quality sweep, all in the data plane. transport/udp: the hole-punch adopted the source address of ANY datagram whose first 8 bytes matched PUNCH_MAGIC — a fixed public constant with no key, nonce or session id — and the authenticated QUIC peer was passed only as the no-punch fallback, so it was never used to validate. Hole-punch is the default bring-up path (it is skipped only for a fixed --data-port), and the data socket is an OS ephemeral, so spraying the ephemeral range during the 2500 ms punch wait let anyone steal the video plane: the legitimate client is then filtered out by the connect() and gets nothing, while QUIC stays healthy so no reconnect fires. With a spoofed source the same 8 bytes aim a full-rate stream at a third party. Take the authenticated peer IP and require the punch to match it — only the PORT is in question (that is what a NAT remaps and what the punch exists to discover); the client dials the same host IP as its QUIC connection, so a NAT presents one source IP for both planes. Also budget each read from the REMAINING window, so off-peer datagrams cannot stretch the wait past punch_timeout. transport/udp: the punch keepalive treated every send error as fatal and broke out of its loop permanently and silently. It holds a clone of the connected, non-blocking data socket — exactly the socket whose transient conditions this module defines and documents in is_transient_io. One ENOBUFS from a full wlan tx queue or an ENETUNREACH during an AP roam killed the only thing holding the NAT mapping open; the path recovers, video keeps flowing, and the stream dies later when the idle timer expires the mapping during a static scene. Route it through is_transient_io like every other send site in the file. packet: adaptive FEC moved fec_percent live (host bands it 1..=50 while Welcome advertises 10) but the receiver's per-block acceptance ceiling was computed once from the negotiated percentage and never re-derived. Once FEC ramped, every packet of a maximal block failed `total > max_total_shards`, the block never accumulated a shard, the frame aged out, and the resulting loss drove FEC higher still — large frames wedged at 100% loss exactly when FEC was meant to rescue the link. Fixed on both sides, because hosts and clients update independently: the sender clamps per-block parity to the ceiling the peer negotiated, and the receiver sizes that ceiling from the whole clamp range rather than a stale snapshot of it. No wire bytes and no C ABI signature change; WIRE_VERSION and ABI_VERSION are unchanged. Regression tests cover all three (the punch tests were confirmed to fail without the fix). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
15d51bc0ff |
Merge remote-tracking branch 'origin/main' into land/sweep-all
apple / swift (push) Successful in 1m13s
apple / screenshots (push) Successful in 6m28s
ci / web (push) Successful in 55s
ci / docs-site (push) Successful in 54s
ci / rust (push) Failing after 6m24s
decky / build-publish (push) Successful in 20s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 9s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 8s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 8s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 8s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 9s
ci / bench (push) Successful in 7m12s
docker / deploy-docs (push) Successful in 15s
deb / build-publish (push) Successful in 9m0s
deb / build-publish-host (push) Successful in 9m22s
arch / build-publish (push) Successful in 17m34s
android / android (push) Successful in 18m52s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 13m56s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 17m12s
windows-host / package (push) Failing after 14m42s
|
||
|
|
e9a4c4a601 |
feat(security): add a user-writable plugin ingest inbox for cross-account data
ci / web (push) Successful in 48s
ci / docs-site (push) Successful in 1m1s
apple / swift (push) Successful in 1m18s
decky / build-publish (push) Successful in 19s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 11s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 8s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 12s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 12s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 53s
ci / bench (push) Successful in 7m12s
apple / screenshots (push) Successful in 6m21s
deb / build-publish (push) Successful in 11m27s
deb / build-publish-host (push) Successful in 12m0s
arch / build-publish (push) Successful in 13m2s
android / android (push) Successful in 15m50s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 15m38s
ci / rust (push) Successful in 20m35s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 20m2s
docker / deploy-docs (push) Successful in 27s
windows-host / package (push) Successful in 15m19s
The LocalService runner can't traverse the interactive user's profile the way the old SYSTEM runner could — so a plugin can no longer read a file an app running as *you* produced (the acute case: the Playnite exporter's library JSON under %APPDATA%). Confirmed on-glass: as LocalService the glob finds nothing and the profile is un-traversable. Add the inverse of plugin-state: <config_dir>\ingest, granted BUILTIN\Users Modify by plugins enable (disable reverts to inherited Users:RX). An interactive-user app drops ingest\<plugin>\… and the de-privileged runner reads it there — the one Users-writable carve-out in the otherwise Users-read-only tree. SDK exports pluginIngestDir(name) to resolve it; on Linux the systemd --user runner owns the config dir so same-user producers write there with no grant. Accepted tradeoff: the inbox is writable by any local user (trusted-single- user model; it feeds only a LocalService runner). Consumers must treat ingest data as lower trust than their own state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
fdbfa37e43 |
fix(cli): silence host capture/DPI/GPU startup noise on management subcommands
A plain `punktfunk-host plugins add …` printed the host's startup banner and — on Windows — ran the win32u GPU-preference hook, whose DPI-awareness probe emits a scary `SetProcessDpiAwarenessContext … "access denied"` WARN. None of it is relevant to a package-manager command, and the WARN reads like a failure. Gate both behind is_management_cli(): plugins / openapi / library / detect-conflicts / driver / web / service-management verbs skip the banner and the DXGI hook. `service run` (the SCM-launched host) is explicitly NOT lightweight, so the hybrid-GPU ACCESS_LOST fix it depends on stays intact. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
73ec6ed9ef |
feat(security): give the de-privileged runner a writable plugin-state dir
The LocalService runner cannot write anywhere under %ProgramData%\punktfunk (the config dir is Users-read-only), so a state-writing plugin's saveCache / config-edit / first-run mkdir all fail EPERM — proven on-glass (rom-manager only looked fine because its state dir was pre-created by an admin run and a 0-title reconcile skipped the write). Add the one writable grant the model was missing, keeping the split crisp — code dirs RX+WA, secrets R, and now a dedicated state root RW: - plugins enable / build-scripting.ps1: create %ProgramData%\punktfunk plugin-state and grant LocalService (OI)(CI)(M); disable revokes. Users stay read-only, so another non-admin still can't tamper with a plugin's launch templates. - SDK: export pluginStateDir(name) -> <config_dir>/plugin-state/<name>. Same path on Linux (the systemd --user runner owns the config dir, writable with no grant), so plugins use one branch-free helper. Plugins must persist under pluginStateDir(), not straight under the config dir. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
5cd6e8f572 |
docs: reflect the plugin-runner security tiers
- plugins: the Windows runner task runs as LocalService now, and public-registry names need --allow-public-registry - automation + SDK README: connect()'s zero-config credential is the scoped plugin token; pairing administration and hook registration need an explicit PUNKTFUNK_MGMT_TOKEN opt-in Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
7b7231fdbe |
feat(security): gate public-registry plugin installs + sandbox the runner unit
Supply chain: resolvePackage() used to pass any punktfunk-plugin-* or foreign-scope name straight to bun add — a typo or a squatted look-alike on npmjs.org would install operator-privileged code. Only the @punktfunk scope (pinned to the Gitea registry by the bunfig scope map) resolves by default now; anything else throws with an explanation unless --allow-public-registry is passed, and even then installs print a loud warning. Removal never gates — uninstalling stays safe regardless of origin. systemd (user unit): free hardening for well-behaved plugins — NoNewPrivileges, PrivateTmp, ProtectSystem=strict with ReadWritePaths=%h (plugin state and download dirs under $HOME keep working), and RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6. Plugins writing outside $HOME, and distros that restrict unprivileged user namespaces for user units, are handled via a documented systemctl --user edit drop-in. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
7fe07d0fa5 |
feat(security): enforce the unit-file trust rule on Windows too
fileIsSafe() returned true unconditionally on win32 ('ACL check is a
follow-up'), leaving the best-effort directory DACL as the only guard on
what the runner imports and executes. The follow-up: before importing a
unit, read its SDDL (Get-Acl via the full-System32-path powershell) and
refuse loudly — exactly like the Unix mode-bits path — unless the owner
is SYSTEM/Administrators/TrustedInstaller (or the account the runner
itself runs as, mirroring Unix's 'your own file is fine') and no other
principal holds a write-capable allow ACE (write/append data, EA/attrs,
DELETE, WRITE_DAC, WRITE_OWNER, generic write/all).
The SDDL verdict is a pure exported function with platform-independent
tests; unknown ACE shapes and unreadable ACLs fail closed. Inherit-only
ACEs (templates for children) and deny ACEs don't trip it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
84c47cd0a7 |
feat(security): run the Windows plugin runner as LocalService, not SYSTEM
The PunktfunkScripting scheduled task ran operator-installed plugin code as SYSTEM with -RunLevel Highest — any plugin defect was a full compromise of the box. The principal is now NT AUTHORITY\LocalService (minimal privileges, no password to manage, exists at boot, loopback networking works), registered without RunLevel: - installer: New-ScheduledTaskPrincipal -UserId 'LocalService' - plugins enable: converges the principal idempotently (migrating tasks an older installer or a dev box registered as SYSTEM) BEFORE starting, then grants LocalService read — via icacls, full-System32-path — on exactly the two SYSTEM/Admins-DACL'd files the runner's connect() needs: the scoped plugin-token and the TLS-pin cert.pem. Never mgmt-token. plugins disable revokes the grants; plugins status now prints the task principal so the migration is verifiable. - build-scripting.ps1 mirrors the convergence + grants on dev deploys. The usage text also mentions the new --allow-public-registry gate that lands with the supply-chain commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
9b5ca0eff3 |
feat(security): scope the plugin runner to a capability-limited bearer token
The scripting runner used to hold the console's full-admin mgmt-token — a plugin defect could rewrite hooks.json (arbitrary command execution) or administer pairing. The host now mints a second persisted secret, plugin-token (PUNKTFUNK_PLUGIN_TOKEN), and require_auth grows a third lane for it: loopback-confined like the admin token, but plugin_may_access carves out /hooks (read AND write), everything under /pair, /native/pair, /native/pending, client unpair DELETEs, and other plugins' ui-credential. Everything a plugin legitimately does (status/library/events/sessions, its own UI lease) is untouched. The SDK's zero-config connect() now prefers PUNKTFUNK_PLUGIN_TOKEN / plugin-token over mgmt-token, so plugins pick the scoped credential up automatically; a script that genuinely needs the admin surface sets PUNKTFUNK_MGMT_TOKEN explicitly. Old hosts without a plugin-token fall back to mgmt-token unchanged. No OpenAPI change: the lane is auth-layer only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
ecec7cc062 |
feat(deploy/windows): always deploy the plugin/script runner
`punktfunk-host plugins add/remove/list` forward to the bun runner, which on
Windows is resolved relative to the running exe (<exe-dir>\bun\bun.exe +
<exe-dir>\scripting\runner-cli.js). Only the installer ever laid that payload
down, so on a deploy-host.ps1 dev box — where the service runs out of
target\release — both paths are absent and the CLI bails with "the plugin
runner isn't installed". deploy-all.ps1 was host + web console only.
Add build-scripting.ps1: it mirrors CI (bun install --frozen-lockfile
--ignore-scripts + bun build src/runner-cli.ts --target=bun, gated on the same
`attempt=` sentinel that proves the dynamic plugin import stayed a runtime
import), then lays the bundle + scripting-run.cmd + the shared bun next to every
host exe it finds — the built one and whatever the PunktfunkHost service runs —
so it is correct on a dev checkout or an installed {app}. It stops a running
PunktfunkScripting first (a live runner holds bun.exe open) and does not
silently enable the opt-in task (-EnableTask to do so).
deploy-all.ps1 is now host -> web console -> runner, always, so the host binary
and the runner bundle never drift apart.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
1e8b267d93 | Merge branch 'fix/vulkan-open-leak' into land/sweep-all | ||
|
|
dafab58943 | Merge branch 'fix/round1-highs' into land/sweep-all | ||
|
|
1dcba4dffa | Merge branch 'fix/encode-medium-tier' into land/sweep-all |