Repository navigation
Releases
Releases · yiesko/Adsum
v0.50.0-rc3
Immutable
release. Only release title and notes can be modified.
Added
- Discord RPC OAuth, optional and experimental. Add optional browser sign-in, the
adsum oauthcommands, optional refresh tokens,GET_USER,GET_GUILDS, limits, and timeouts. - OAuth setup in the installer.
install.shcan write the OAuth redirect and secret settings for the user service. - Cross-client state snapshots. With
--state-file, Adsum can createarrpc-state-Nlinks in client runtime folders and useADSUM_STATE_PREFIXto choose the file prefix. - Compatibility detection. Adsum now recognizes games started by Box64, FEX, QEMU, Wine/Proton, and Steam reaper, including Wine games on macOS, plus Minecraft and compatible loaders on Linux.
- Pre-release tags. Alpha, beta, and release-candidate tags are now published as GitHub pre-releases with notes from this changelog. Stable tags still need a numbered changelog section.
Changed
- Lower memory use at startup. The bundled game database is stored in a smaller form, so the measured startup peak fell from about 57 MB to about 28 MB in local testing.
- More exact game matching. Game arguments keep their original boundaries, including empty arguments, so programs opened through a wrapper are matched by the real game.
- Clearer IPC overload response. When the queue is full, publishing now reports
5000 Activity queue is full; retry laterinstead of appearing successful.
A rejected publication still does not gain ownership. - Pre-release binary versions. Build tags are stamped into the workspace, so the binary reports the exact tag version. The self-updater still uses GitHub's stable release only.
Fixed
- Cleaner shutdown. The scanner is stopped before its threads are joined, so shutdown does not wait beyond the shared time limit for stuck workers.
- State aliases. Existing aliases now follow only trusted paths, and a missing alias is not recreated from an old snapshot.
- OAuth expiry. The first command that finds the expired session now reports
InvalidAccessToken, notNotAuthenticated. - Non-Linux builds. Windows, macOS, and other non-Linux targets now compile.
Security
- OAuth tokens. Responses contain identity and scopes, never the access token. Logs and debug output do not show it.
- OAuth settings. Refresh and restore require
ADSUM_OAUTH_CLIENT_SECRET; without it, the client secret error is returned instead of a misleading invalid-argument error. - Paths and IPC. Paths reached through a symlink are checked across the full path, not only the last directory.
- Windows IPC pipe. The named pipe now has an explicit access policy instead of receiving default permissions.
v0.40.0
Immutable
release. Only release title and notes can be modified.
Performance
- Incremental process table (Linux): a per-pid classification cache
(crates/adsum-detect/src/cache/procs.rs) replaces the full re-read of
every process each tick. A tick now enumerates/procfor liveness,
sweeps the dead, revalidates cached hits (one cmdline read per detected
game; the matcher re-runs if the argv fingerprint drifts) and classifies
only new pids. Cached misses are not re-read; a miss that becomes a hit
surfaces as an EXEC event or a watcher-loss flush.- Steady state: zero cmdline reads, automaton walks and allocations.
On the bundled database shape (1062 processes): 5.05 → 0.38 ms/tick
(−92%), 3152 → 3 allocs/tick, 40.3 KB → 54 B/tick of churn. - Every watcher loss channel (
cn_procgaps, backlog sheds, socket
overruns, watcher death/resubscribe) forces one full-read tick; bundle
swaps invalidate through an epoch in the generationArc. - Watcher disabled/dead, other OSes and one-shot diagnostics keep the
classic full sweep, byte-for-byte.
- Steady state: zero cmdline reads, automaton walks and allocations.
- Zero-allocation
/procenumeration: rawgetdents64into a reused,
aligned arena replacesstd::fs::read_dir. ~3 allocations per entry →
0 (~29 MB/h of churn removed at 1000 processes), which also keeps the
glibc arenas and the RSS floor low. - Allocation-free snapshot lane:
ScannedEntry.id/.nameand
ProcessDetectedEvent::Removednow useAppId/Arc<str>, and the scan
loop's snapshotVecis reused across ticks. Per tick: zero
allocations; the daemon pump'sScannedGameconstruction is two
refcount bumps instead of two deep copies. - Aux-table arena: the four
SortedIndextables (steam/epic/name/
nodot) pack keys into one contiguous per-generation arena. Miss-heavy
lookups are 13–39% faster and per-key malloc headers are gone. Build
order, first-wins ties and lookups are unchanged (pinned by tests). - Steam install-tail matching:
match_install_tail_intobinary-searches
a precomputed sorted tail index (rebuilt ondirsmutation) instead of
walking every install prefix per probe, so large libraries no longer
multiply each sweep or EXEC storm. Longest-wins and ambiguity refusal
are preserved; a parity oracle test compares it with the old linear
walk.refresh_if_stalenow fingerprints over the map in place. - Borrow pass: five places that copied where a borrow suffices:
matching: the command-line AppId fallback no longer wraps the borrowed
&strin a freshAppIdper process per tick.cache/appid: oneAppIdshared by refcount instead of two copies.runtime: first-sighting inserts are refcount bumps, notto_string().types/cmd:ActivityCmd.cmdisCow<'static, str>, so synthesized
commands borrow their verb (wire format unchanged).bridge/handoff:is_process_aliveformats/proc/<pid>into a stack
buffer.
- Hoisted locks and buffers: the exclusions
RwLockis read once per
tick/event instead of per process; the dead-pid sweep,is_suspended
andread_cwd_intoreuse caller-owned sets and buffers. - Windows/macOS: the snapshot enumerator folds
\→/at fill time so
match_process'sCowstaysBorrowed;sysinfoslots are refilled in
place and gaincompact_slots;process_start_msrefreshes with
ProcessRefreshKind::nothing()instead ofeverything(). - Minor:
Exclusions.executablesis anFxHashSet; the persist gate
swaps its dirty flag withAcqRel(wasSeqCst);broadcast_raw
answers both encoding questions in one pass.
Changed
- File organization: one concern per module. The near-twin module
pairs are gone —scan.rs(classification) is nowmatching/with
the pipeline inmod.rsand its rule families innormalize(the one
name-folding rule),paths(what it means for a declared name to name
a path),args(borrowed command-line token scans) andtiers(the
aux match tiers + shared hit tail); the tick orchestration moved from
scanner.rstosweep.rs;database.rs(bundle swaps) became
generations.rs, leavingdb.rsas the single wire-model module.
runtime.rssplit intoruntime/{mod,workers,lanes,cadence,loops}—
start()reads as lifecycle and the two 150+ line thread closures are
named bodies (run_scan_loop,run_refresh_loop). The reuse-buffer
family moved to a top-levelscratch.rswith a new
EnumerateScratchgroup (pid list, getdents arena, liveness/work
lists) so the enumeration state no longer rides inside the per-pid
reader scratch, and the two per-pid caches grouped undercache/
(appid+procs) with their shared trust model documented once.
os_matchesmoved besideOsNameintypes.rs;first_sightings/
apply_ignore_listmoved beside the lanes that consume them. Public
paths that embedders use are preserved (adsum_detect::proc_start,
runtime::ScanGuard/idle_wait, thematching::re-exports); the
test tree mirrors the source (tests/unit/matching/,
tests/unit/cache/,tests/unit/platform/). No behavior change: the
full suite passes untouched, rustdoc is warning-free. - Platform backends behind one seam: the OS-specific code that was
scattered as#[cfg]islands inside shared files (six reader pairs in
scan.rs, two enumerations inscanner.rs, the netlink wiring in
runtime.rs, four arena-release arms inserver.rs) now lives under
crates/adsum-detect/src/platform/—linux/(/procreaders,
getdents64enumerator, netlink dispatch/watcher),snapshot/(the
sysinfobackend for every non-Linux target),macos/(the.app
bundle-interior shape — deliberately ungated: the tier is data-driven
and must run, and be tested, everywhere),windows/(documented
empty: nothing Windows-only is left in the crate), plus unified
memory.rs(arena release) andproc_start.rs(public path
adsum_detect::proc_startunchanged). The seam is a static-method
ProcessEnumeratortrait (traits/enumerator.rs:begin_tick+
read_one), so the tick orchestration — BOTH the full sweep and the
incremental cache — is now 100% cfg-free and runs on every target;
the incremental mode is gated only bycache_mode_live(watcher
enabled AND live), which today can only hold on Linux. No behavior
change: the full test suite passes untouched, and theparse_proc_pid
suite moved with its function. - Watcher opt-in under systemd: the user-unit guide now shows a drop-in
that resets the namespace-creating sandbox directives socn_proccan
deliver, with the filesystem and device isolation loss stated explicitly.
The default unit keeps its sandbox and polling.
Added
- SteamAppId tier on Windows and macOS:
read_steam_app_idwas a
Nonestub off Linux, leaving the 57% of database entries with no
declared executables without their authoritative tier on those
platforms. sysinfo 0.39 reads the environ block on both (PEB through
the process handle on Windows, the sysctl arg/env route on macOS); the
reader uses aSystemscoped to the call — the shared snapshot never
accumulates environ copies — and the existing per-pid memo
(Present/Absent/Stale+ invalidation sequence) keeps it to one
read per process lifetime. Permission-gated processes memoize
Absent, exactly like an unreadable/proc/<pid>/environ. - Steam and Heroic discovery off Linux: fallback Steam roots now
include the registry'sSteamPath(HKCU\Software\Valve\Steamvia
reg query— dependency-free; discovery runs at startup plus every
120th tick) and theProgram Files (x86)/Program Filesdefaults on
Windows, and~/Library/Application Support/Steamon macOS; Heroic's
cached library is found under%APPDATA%\heroic(Windows) and
~/Library/Application Support/heroic(macOS). The
ADSUM_STEAM_ROOT/ADSUM_HEROIC_ROOToverrides stay exclusive.
Without these, the Steam-library and-epicapptiers were silently
dead off Linux ($HOME/XDG shapes do not exist on Windows). DetectablesBundlecarries a monotonicepoch(stamped inside the
generationArc, so a reader can never pair it with a foreign
bundle): the cache-invalidation signal for refreshes and override
edits, costing one full-read tick per swap.watch()takes aninvalidateflag it sets on every loss channel it
can observe from inside (sequence gap, shed,ENOBUFS); the retry
loop sets it on both edges of the watch.
Fixed
- Proc-events watcher: a non-initial user or PID namespace now turns
the watcher off with one warning instead of retrying a self-test the
kernel can never satisfy.watcher_liveis set only after the self-test
parses an event and cleared on every exit. A refusal is recognized both
as a nonzeroNLMSG_ERRORand as aPROC_EVENT_NONEack with an error
in the event body, and retries back off from 5 seconds to a 5-minute cap
instead of waiting a fixed 5 minutes. A watch that proved delivery resets
that backoff, so a late failure retries soon instead of inheriting a stale
cap. - Proc-events listener leak: every exit after a successful subscription
now sendsPROC_CN_MCAST_IGNOREbefore closing the netlink socket. The
kernel decrements its global listener count only on that message, so a
stopped watcher, a failed self-test or a lost receiver no longer leaves
the count positive. A leaked count let sandboxed sockets receive events
they were never granted. - PID namespace gate: the watcher also reads
NSpidfrom
/proc/self/statusand stays off when it sees several values, which
means a nested PID namespace. A procfs mounted inside that namespace
collapses the line to one value, so the self-test remains the final word. - Steam demos whose executable is not in the database (VEIN Demo is the
motivating case) are now detected when the process runs under the AppId's
own install dir (steamapps/common/<installdir>/). T...
v0.39.0
Immutable
release. Only release title and notes can be modified.
Breaking
- Renamed the project from rsRPC to Adsum. The binary is now
adsum, the
systemd service isadsum.service, environment variables use the
ADSUM_*prefix, and config/cache moved to~/.config/adsumand
~/.cache/adsum. Existing 0.38.1 installations need a one-time manual
migration: the old updater only looks forrsrpc-cli-*assets and
cannot update across the rename.
Added
- Heroic/Epic sandbox-id detection: Proton games launched by Heroic carry
-epicsandboxid=<id>on the command line, and the service sandbox hides
the environ — so the cmdline is the only distributor id a service can
see. GTA V Enhanced is the motivating case. - Epic
-epicappfallback: older Legendary releases (before 0.20.25) omit
the sandbox id and pass only the app name. Heroic's cached
store_cache/legendary_library.jsonmaps it to the sameepic
namespace the database stores; the sandbox id remains the first choice.
The config root can be overridden exclusively withADSUM_HEROIC_ROOT.
Fixed
- IPC
SET_ACTIVITYpublications with a missing or zero PID are now
rejected before any state change, instead of leaving an orphan
presence downstream. - An absent
activityfield in an activity update is now rejected
instead of being treated as a clear; only an explicit null clears the
presence.
Security
- Bumped
rustls-webpkito 0.103.16 andwebpki-rootsto 1.0.10 in all
three lockfiles; RUSTSEC-2026-0382 (distrusted intermediates accepted)
and RUSTSEC-2026-0381 (distrusted emSign roots bundled) are fixed in
those versions. Both crates are reached only throughureq/rustls,
the HTTPS client.
What's Changed
- Activity: a missing activity field is not a request to clear by @yiesko in #30
- Detect: the Epic sandbox id names the game when the environment is hidden by @yiesko in #31
- Detect: the Epic app name identifies the game when the sandbox id is missing by @yiesko in #32
Full Changelog: v0.38.1...v0.39.0
v0.38.1
Immutable
release. Only release title and notes can be modified.
Security
- Bumped
rustlsto 0.23.46 in all three workspaces; RUSTSEC-2026-0346,
-0347, -0348 and -0349 were published on 2026-10-14 and are fixed in
0.23.46 and later. The crate is reached only throughureq, the HTTPS
client, and the gate went red on a push that had not touched it.
v0.38.0 - 91db30a03ae3993807a31f097fb764bf2a919610
Immutable
release. Only release title and notes can be modified.
Added
- Detection traceability: every first sighting logs which matcher won
(automaton,cwd-joined,proton-automaton,steam-app-id,
steam-library,exe-stem,folder) plus process age in ms at
classification; every clear carries its reason (sdk-clear,
abrupt-close,process-vanished,scan-absent,yielded); SDK takeovers and
generic resumes name both sides of the slot. Snapshots gain additive
detectionSource/detectLatencyMsfields per card ("sdk"for
client-published cards, absent on old ones). Tracing only, on
lifecycle transitions — no hot-path cost, no retained state. Guide:
docs/detection-traceability.md.
Security
- Bumped
rustlsto 0.23.45 in thefuzzandtools/updater
workspaces (RUSTSEC-2026-0285, TLS 1.3 handshake); the main lock was
already clean. All three locks are now audited in CI. - The bridge now validates the WebSocket
Originheader like the game
transport already did: absentOrigin(native clients) and Discord's
own pages pass, anything else is closed at connect before READY unless
listed in--bridge-allowed-origins/RSRPC_BRIDGE_ALLOWED_ORIGINS.
A malicious page can no longer read local activities or send bridge
commands throughws://127.0.0.1:1337; frames pipelined past the
close are dropped as unregistered. Client ids are now unique
process-wide across both bridge servers (per-server counters could
alias registrations), and messages from unregistered ids never reach
control handling. - The installer is fail-closed: a missing signature manifest or a
missingminisignbinary aborts the install instead of continuing on
SHA256 alone (explicit--binaryfiles stay exempt). The systemd unit
ships as a signed release asset covered bySHA256SUMS.txtand is
verified the same way before anything is installed from it. - Presence snapshots are owner-only: the temp file is created with an
explicit0600mode on Unix (the rename carries it to the final
path), so app ids, pids and ports stay private under a permissive
umask. Every write uses its own temp, created exclusively without
following symlinks, so a planted link is refused and concurrent
daemons sharing a slot still write apart. Slot selection stays
best-effort — concurrent daemons share slots, last writer wins —
and stale crash temps are swept under the same staleness rule.
Performance
- The per-tick, per-publish and per-connection allocations left behind by
the earlier memory fix (#2) are gone, under one rule: one owned
materialization at the boundary, zero deep copies after it (61 commits,
59 files, +6394/-1349). Same games detected, same order, same log lines. - Ids (
AppId,SocketId) areArc<str>newtypes withDeref<str>, so
cloning one is a refcount bump: every path that copied a client id,
socket id or app id now shares it. - Payloads that reach more than one consumer cross as
Bytes/Utf8Bytes/Arc<T>and are encoded once; the MessagePack
derivation is lazy and shared instead of rebuilt per consumer. - Scratch buffers (
ExecScratch,MatchScratch, the/procstat and
environ paths) are owned by the loop and reused across ticks, which is
where roughly 400 allocations every 5 s per process came from. The scan
tick classifies every process on the machine, so this is the path that
decides the resident set, not a hot path in the usual sense. - Collections that outlive their build are
Box<[T]>and shrunk;
transient ones deliberately are not. Entries carry packed[u32;2]
index pairs, and the automaton is built in a single pass with exact
reservations. - Structural caps on the fetched database, measured rather than guessed:
the bundled snapshot is 24,299 entries, and the maxima within an entry are
16 executables, 8 aliases, 30 Steam SKUs and 204-character names. Every
cap sits an order of magnitude above that. A body decoding past one is
rejected asDatabaseTooLarge,
distinct from a parse failure, and the caller keeps the database it
already holds. The 64 MiB body limit bounded the bytes; it never
bounded what they decode into — one entry with tens of thousands of
executables is a megabyte of JSON becoming one automaton pattern and
one index pair each. - The census now reports the resident high-water mark beside the current
RSS and the live/free heap split from the allocator, so a growth can be
told from a floor that held while the peak climbed. Both were verified
against the kernel before being written: thekBunit in
/proc/self/statusis really KiB, confirmed by comparing resident pages
againstVmRSS. - Two deliberate deviations. The
SET_ACTIVITYecho emitsdata
keys in declaration order instead of theBTreeMap's alphabetical
order (the echo contract already allows key-order variance and every
test compares parsed values), and the IPC close-clear nonce now carries
the value the client sent instead of its JSON text — that one is a
fix, see below.
Changed
- Folded
rsrpc-stateintorsrpc-bridge(12 crates down to 11): the
snapshot slots had exactly one consumer, so the crate boundary only
added hops.rsrpc-telemetrystays separate: four crates share it,
and folding it into the bridge would point their dependencies the
wrong way.BindPaths=/tmpin the unit stays as is: tightening was
investigated, but BindPaths takes no globs, the sockets only exist at
runtime, and the fan-out symlinks need the host path writable. - Regression nets now pin the memory bounds: replay-cache pruning and
broadcast fan-out never exceedMAX_CACHED_ACTIVITIES, and the
flood-guard table stays within its cap. - Shared package metadata and dependency pins now live in the workspace
root ([workspace.package]+[workspace.dependencies]): edition,
MSRV, license, repository, authors and 15 dependency versions change
once instead of per crate.Cargo.lockis byte-identical, and per-crate
versions are untouched.authorsnames the historical author and the
current maintainer (spikehd,yieskoW).tokio-utilstays pinned
per crate on purpose: inheritance cannot overridedefault-features. - CI now runs the test suite on Windows and macOS as well as Linux,
audits all three lockfiles, and validates non-Rust artifacts
(node --checkon the plugin,systemd-analyze verifyon the unit,
typecheck of the fuzz workspace). A new fuzz workflow smoke-checks
targets on PRs and runs the engine nightly (10 minutes per target:
ipc_frame,activity_full,trim_db,db_parse), with corpus
caching between runs. Newipc_framefuzz target drives the IPC
reader (handle_streamwith a mock facilitator and a split
byte-duplex), asserting every response byte belongs to a complete
frame (708k runs clean locally). - All GitHub Actions references are pinned to commit SHAs (tags kept as
comments), closing the mutable-tag supply-chain window on the release
pipeline especially. - Unix IPC pumps are capped at 16 concurrent peers like Windows (which
keeps 32): connection floods past the cap drop peers at accept instead
of parking blocking threads without bound, leaving room in the
32-thread blocking pool for unrelated work. - Split the two biggest modules internally, same crates and same
behavior:crates/rsrpc-detect/src/server.rsis now foundation plus
runtime(threads, shutdown, join),database(bundle ownership and
swaps),scanner(enumeration and classification),steam
(library roots) alongside the existingbundle/db/refresh/scan
modules;crates/rsrpc-bridge/src/bridge.rsis now construction plus pumps
alongsideconsumer(fan-out and pruning),router(activity
decisions),replay(cache and ghost-reap pid resolution),snapshot
(persistence) andcontrol(SET_USER/RESET_USER).Sharedfields
are crate-visible for the new units; wire protocols unchanged. One
breaking change for library callers:rsrpc_proc_events::watchnow
takes a shutdown flag (watch(events, stop)), so the watcher thread
joins on directed shutdown instead of blocking on netlink. - CodeQL now scans the workspace as one job with the v4 action inputs, and
re-scans whenever any workflow changes rather than only its own. - Dependabot maintains the three cargo workspaces and the pinned actions;
CI declares the least permissions each workflow needs, and the runners
are pinned by image label instead of floating onubuntu-latest. - The three workspaces share one grouped
cargoentry in CI instead of
three near-duplicates.
Fixed
- Hostile timestamps saturate instead of overflowing:
normalize_timestamp
usessaturating_mul, so extreme inputs floor ati64::MINin both
debug and release builds. - Payload builders (
empty_cached,generic_payload) returnNoneon
encode failure instead of shipping empty frames: callers log, count a
dropped broadcast and skip. The hand-written clear JSON is gone — clears
serialize from the same struct as everything else — and the emergency
error frames escape the command name instead of interpolating it raw. - The flood-guard key builds once per call instead of twice (an
AppId
key would allocate identically, since callers hold&str). - Scanner threads now belong to the daemon lifecycle:
ProcessServer
gained directedshutdown()+join()(plusrsrpc-*thread names),
every long sleep became an interruptible park, the netlink watcher
honors a stop flag (including its self-test), andDaemon::run_until
shuts down, joins and drops the scanner on success and bind failures.
Future abandonment (dropping the future viaselect!/timeout/abort)
signals shutdown through a cancellation guard instead, so threads exit
on their own within ab...
v0.36.1 - 676fedc1fb9dba2f0465e5d19c3e17bbdd071c43
Immutable
release. Only release title and notes can be modified.
Commits in v0.36.1 (v0.36.0..HEAD)
- docs: credit SpikeHD as the original rsRPC author (a4de519)
- chore: rename repository urls to yiesko/discord-rich-presence (437b3d0)
- fix(cli): stop --rollback from re-execing into a swap loop (e9b4d85)
- feat(cli): wire --state-file and RSRPC_STATE_FILE into the bridge (15b06d8)
- fix(unit): drop dead RSRPC_LOGS_ENABLED and allow the self-update swap (7c2d5ae)
- docs: rewrite the README, split guides into docs/, add screenshots (e2422ea)
- docs: changelog the rollback, state-file and unit fixes (6e68663)
- docs: release 0.36.1 changelog (15944cd)
- style(cli): wrap the release api url for rustfmt (b64fee6)
- chore: release v0.36.1 (676fedc)
Full Changelog: v0.36.0...v0.36.1
v0.36.0 - 203d0dab72f6ef5023421fc64dd847ca2dce1864
Immutable
release. Only release title and notes can be modified.
Commits in v0.36.0 (HEAD)
- feat(ws): rsrpc-ws skeleton with config, error and message types (6d9d4f4)
- feat(ws): async server with bounded queues, keepalive and shutdown (6d06911)
- feat(types): rsrpc-types with Arc ids, cmd and user modules (20ee90f)
- feat(protocol): rsrpc-protocol with typed errors and Arc-shared payloads (89f6942)
- feat(types): Box conversions and TimeoutValue accessor (9ce7aaa)
- refactor(lib): re-export types/protocol with Arc payloads and typed errors (ee9fd86)
- feat(transport-ws): game WS transport over rsrpc-ws without map lock contention (1d18abd)
- feat(transport-ipc): async IPC transport with JoinSet lifecycle (ab7248b)
- feat(state): rsrpc-state snapshot slots with caller version (65cfd1e)
- refactor(protocol): canonical query_params shared by transports (a90d444)
- feat(bridge): async activity bridge with dirty-gated snapshots (31b1cac)
- feat(telemetry): rsrpc-telemetry gauges, RSS and census rendering (f61e859)
- feat(proc-events): rsrpc-proc-events watcher with shared gauge sink (fff1fc0)
- feat(steam): rsrpc-steam VDF provider with hermetic tests (69eadde)
- feat(detect): rsrpc-detect database module with bundled snapshot (95ff1f1)
- feat(detect): process scanner split with lock-free generation swaps (d9c1c63)
- feat(core): rsrpc-core daemon wiring with run_until shutdown (4643436)
- feat(cli): thin async CLI over Daemon with tokio signal handling (30aafd6)
- refactor!: remove legacy lib, wire workspace lints and CI paths (43262b4)
- fix(core): move database into scanner instead of cloning and retaining it (8e5139c)
- perf: drop chrono, lazy fallback, inlines, reused IPC frame buffers (ba2daea)
- perf: snapshot slots without deep clone, borrow args map (9e65707)
- perf: carry is_clear on payloads instead of re-parsing (bcbb3b8)
- perf: FxHashMap on u64-keyed hot maps with bench proof (b173331)
- perf: refcounted text payloads, slim subscriber, tuned runtime (8a70ee8)
- fix(ipc): clear presence on protocol-violation close (6bc8dfb)
- fix(bridge): reap dead-pid ghosts from replay on null scan (2d42c76)
- fix(transports): clear every published pid on disconnect, bounded history (4ca6ba9)
- docs: fix private intra-doc link from public cache_entry_pid (9496c98)
- docs: point Unreleased entries at workspace paths, document modularization (ffa2039)
- fix(bridge): resolve replay-cache owner from body pid first (75b8db2)
- fix(bridge): register consumers under resolved protocol (7a8dff6)
- fix: close four reviewer-found correctness gaps (c683bbd)
- fix(detect,steam): guard empty exclusion fetch, decode mount UTF-8 (58b3777)
- fix(ipc): socket-link ownership, reliable presence clears (22ed44b)
- fix(ws,ipc): reap JoinSets, enforce idle on its own deadline (429ba03)
- fix(ipc): unblock connection pumps on unix shutdown (fc4bd06)
- fix: process parity and review nits (9ead738)
- refactor(bridge): split handle_set_activity into focused helpers (127e867)
- refactor(ipc): split handle_stream per-packet arms (2c55e02)
- refactor(bridge): single user-mutex section in handle_bridge_control (599563c)
- refactor(cli): split async_main into focused helpers (1cc2d9e)
- feat: wire resource census hourly and session-boundary emission (9dee156)
- fix: restore cross-platform builds and lint gates (9b9cfd5)
- fix(detect): share one detection generation across server clones (04cd02f)
- fix(ipc): probe errs toward alive after a successful connect (638bd3e)
- fix(transport-ws): bound reply waits so a stalled client cannot freeze the pump (7b603d9)
- fix(ipc): route clean-close clear through the retrying clear path (f6ab963)
- fix(proc-events): count only delivered events as forwarded (8610bea)
- docs(ipc): document the Windows shutdown drain limitation (3a3f7e2)
- docs(readme): make the library examples compile (01a9317)
- fix(bridge): return the unix liveness probe directly (04e627a)
- fix(proc-events): gate netlink-only items to Linux (cff8fa0)
- fix(detect): serialize detection-bundle writers under one lock (58e94e2)
- fix(transport-ws): record publications even when the reply fails (0b4e7ed)
- docs(readme): align the runtime description with current behavior (e2c5591)
- chore(core): drop the unused tokio-util dependency (31e7e49)
- docs(core): correct the scanner channel-bound comment (14cb146)
- docs(detect): finish the ac_probe rustdoc sentence (1679600)
- refactor(steam): remove unused test seams (948230c)
- refactor(protocol)!: decouple the HTTP error from the client (b0369b2)
- docs(readme): drop removed-behavior bullets, complete bench paths (e554719)
- perf(publish): fingerprint first, drop floods before building (cee0efd)
- fix(protocol): stamp application id before fingerprinting (b257006)
- docs(readme): drop the unsupported RSRPC_STATE_FILE bullet (9003659)
- fix(transport-ws): clear evicted pids instead of leaking them (28a111a)
- fix(transport-ws): refuse disallowed origins at connect (bbbc3f8)
- docs(protocol): scope the dependency claim to workspace-internal (34f93a9)
- docs: cover undocumented functions touched by the PR (e430d02)
- fix(transport-ws): retain evicted clears when enqueue fails (0e0f0bd)
- fix(detect,bridge,core): per-slot clears, scan shutdown exit, ignored EXEC hits (a402725)
- fix(detect): allow dead exec_hit_ignored off Linux (cd6e958)
- docs: document every function touched by the PR diff (8454abc)
- fix(transport-ws,ws): cap publications at tracking bound; validate bind bounds (3618b0d)
- fix(detect,bridge): review follow-ups; validators after swap, watcher-gated backoff, single-lock removal (8dd860b)
- fix(ws): bound over-limit rejection backlog; register tasks for shutdown (8cafbb3)
- fix(core): map each connector flag to its command class (142b16f)
- chore(msrv): raise minimum toolchain to 1.95 (4ff4b8a)
- docs(ws): restore slow-consumer doc displaced by bind test (491d71b)
- chore(ci): pin toolchain action to immutable SHA (bb82013)
- fix(ws,transport-ws): reject zero keepalive at bind; drain residue on shutdown (b989297)
- fix(detect): reject empty exe names; unpark scan on watcher failure (7f64ef4)
- fix(ws): cancel handshakes on shutdown; reject zero keepalive at bind (265a9cc)
- fix(bridge): fallible pid_t narrowing; deterministic barrier test (af26859)
- fix(steam): hermetic cache seam for refresh tests (def2702)
- fix(ws): reject zero idle_timeout at bind (d349efe)
- fix(ipc): malformed activity disturbs no presence (414cd58)
- fix(ipc): bind falls through candidate dirs (1529a25)
- docs: precedence wording; symbol citation over line number (fbccb1c)
- fix(bridge): count pruned consumers in raw broadcasts (5253767)
- fix(ipc): drop closes live sockets; cancel before abort (5feba05)
- fix(telemetry,proc-events): bounded watcher backlog with CAS reservation (1fba9bd)
- fix(transport-ws): ordered pending-clear queue with per-clear deadlines (dfb6949)
- fix(detect): normalized match-all guard; unpark dead-code allowance (5157fb3)
- fix(ipc): error reply on malformed activity; disturb no presence (9259930)
- fix(bridge): deterministic raw-broadcast counting test (8c867fc)
- fix(bridge): prune consumer protocol entries with dead consumers (0271714)
- fix(ipc): back off on repeated accept errors (4a77f49)
- fix(bridge): prune consumer protocol entries with dead consumers (741fab2)
- fix(ws,ipc): back off on persistent accept errors (309e764)
- fix(detect,bench): poison-tolerant sweep; pinned flood-drop timestamp (476d289)
- docs: mutable daemon in staged API example (4f8ebe7)
- fix(core): hermetic override paths via explicit environment source (7bb631e)
- fix(ws): server Drop; hub close timeout; zero idle validation (d1ef8da)
- fix(transport-ws): per-clear deadlines; ordered staging; retry worker (cdae401)
- fix(detect): normalized match-all guard; unpark allowance (1f5e6d5)
- fix(ipc): malformed error reply; candidate-dir fallback; minimal tokio-util (1503ef6)
- fix(core,protocol,cli): scan interval validation; WsExhausted wording; misc (86ec39f)
- ci: fix msrv toolchain input; drop Node audit; pin ubuntu 22.04 (22bfa68)
- Merge staging: full workspace modularization + ghost-presence and memory fixes (e12182a)
- fix(detect): deferred post-swap trim and allocator telemetry (97185db)
- perf(detect): reuse per-tick buffers in scan and match paths (78a59d2)
- perf(detect): single-pass automaton build with sized vectors (b7f9d08)
- chore(deps): trim tokio-util to default features (0840f49)
- fix(detect,ws): non-Linux builds and review feedback (d6cab8c)
- test(detect): capacity-gated backing assert; check normalized
/(62fe758) - fix(detect): gate native_at helper to linux test path (29f0f6e)
- style(detect): rustfmt native_at closure onto one line (eec9d73)
- perf(detect): retain high-water Exec slots across smaller sweeps (61aa308)
- Merge PR #2: Fix hourly memory ratchet + per-tick churn (54a85cd)
- docs: release 0.36.0 changelog (21fceba)
- chore: release v0.36.0 (203d0da)
What's Changed
- Full workspace modularization + ghost-presence and memory fixes by @yiesko in #1
- Fix hourly memory ratchet + per-tick churn (measured, no behavior change) by @yiesko in #2
New Contributors
Full Changelog: https://github.com/yiesko/discord-rich-presence/commits/v0.36.0