Skip to content

Rivet 0.12.0

Latest

Choose a tag to compare

@github-actions github-actions released this 19 Oct 06:47
· 12 commits to main since this release
  • Make cross-platform verification first-class. raco rivet matrix <report.json>... [--json] folds the per-platform acceptance --json
    reports for one commit into a single machine-readable verdict: a required
    kind/platform cell is proven only by a passing suite on that platform,
    missing platforms are never silently green, and the exit code is green only
    when every required cell is proven — so an agent editing on one OS can
    still be judged by the other platforms' evidence. docs/product-acceptance.md
    now defines the guaranteed / conditional / platform-specific capability
    classification, and the maintainer contract states that the local
    operating system does not reduce the required verification scope.

  • Ship the Windows runtime source list as a machine-consumable property
    sheet. platform/windows/rivet-runtime-sources.props is now the single
    author of the host library's <ClCompile> set — rivet-host.vcxproj
    imports it, and hosts that still compile Rivet sources directly (the
    transitional path until #238 ships prebuilt static libraries) import the
    same file instead of hand-copying entries that rot: adding a runtime
    translation unit previously broke every downstream Windows host at link
    time (the podlens valid_utf8 LNK2001). A guard test keeps the props in
    step with runtime/CMakeLists.txt, and platform/windows/README.md
    documents both consumption contracts.

  • Fix generated C++ bounded-wait RPCs so each promise yields exactly one
    future, reused for both the timeout wait and the result read. Void RPCs now
    also fulfill their promise after decoding a successful response; previously
    non-Void calls threw future_already_retrieved and Void calls always timed
    out even when the backend had completed.

  • Add executable product acceptance contracts. raco rivet acceptance --json validates rivet-acceptance.rktd, rejects missing kind/platform
    coverage, launches each current-platform suite as an executable plus argv
    without a shell, enforces bounded time and output, and fails on nonzero exits
    or missing evidence. inspect --json, generated projects, agent guidance,
    and the native UI extension contract now expose the same definition of done,
    so a build-only or unrun platform can no longer be described as accepted.

  • Set the Windows title-bar icon from the embedded exe resource. WinUI shows a generic placeholder in the title bar unless the window is handed an icon explicitly, so every shipped host ran with a foreign default glyph while taskbar and shortcuts showed the real brand icon — the icon was compiled into the exe (resource ID 1 since #283) but nothing ever loaded it. The host template now loads it with LoadIconW and hands it to AppWindow.SetIcon at construction; projects without a windows-icon declaration keep the placeholder. Existing products carry the same lines in their own MainWindow constructor (podlens landed it first).

  • Add the release gate. raco rivet generate --check regenerates every client file in memory and fails when the tree differs — the writer and the gate share one regeneration, so a hand-edited version stamp or a forgotten regeneration (four shipped-repo incidents in one week) cannot merge. raco rivet doctor --release validates in one command and one exit code: generated freshness, the committed schema baseline, hand-written host sources calling fetch-update-manifest/select-update/download-update/fetch-sibling-asset only with keywords the installed rivet accepts (read via procedure-keywords from the live functions, closing the payback #:redirections class), and every rivet.git#... pin being non-empty and consistent with the installed release (the autarx empty-ref incident). The update API keyword contract is a documented, test-guarded stable surface, and docs/ci.md warns about the empty URL# footgun.

  • Own the Linux runtime layout discovery and ship the GTK main-thread bridge. rivet::linux_runtime::discover_layout() locates runtime/*.boot plus res/core.zo beside the executable (an explicit-root overload serves tests), layout_error_hint() is the remediation message hosts display, and the host template consumes the library instead of carrying a private copy — the staged-versus-packaged layout is Rivet's contract, so the code that knows it lives with it. The template also ships rpc_bridge.hpp: unpack flattens a generated Result<T> (including Result<void>) into a value-or-error decided on the reader thread, and post_to_main runs the closure on the GTK main loop, freeing it there. A new GTK host starts with the correct pattern instead of rediscovering thread affinity the hard way.

  • Single-source user-visible strings. raco rivet i18n verifies the parity contract of shared/i18n/{zh,en}.json (flat string-to-string maps with identical key sets; violations name the file and key) and regenerates the embedded host tables (GeneratedI18n.hpp on Windows and Linux, GeneratedI18n.swift on macOS). The shipped loaders consult the active language, then the other language, then the key, identically across hosts, so a key can never exist in one host's fallback and not another's. The release gate fails when the parity contract breaks or the embedded tables drift from the shared source; projects without a shared/i18n source skip the check.

  • Generate bounded-wait RPC companions for the Windows and Linux C++ clients. Every RPC gains name_within(arguments, std::chrono::milliseconds): the completion resolves a promise, the call waits up to the timeout, and a miss cancels the pending request through the existing request table — so long-lived polling UIs stop spawning a detached thread per tick. Void RPCs return bool; other results return std::optional<T>; backend errors still throw from the final get. The naming collision check treats _within as a generated companion, and the fix removes a latent generator defect the new Void fixture exposed: the Void async completion handler assigned into Result<void>, which has no value member and made every generated header with a Void RPC uncompilable.

  • Add macos-localizations packaging support. A (macos-localizations "zh-Hans" "en") declaration (BCP 47 identifiers, validated at project load) emits CFBundleLocalizations in Info.plist and stages marker Contents/Resources/<lang>.lproj/InfoPlist.strings files before sign-macos! runs, so AppKit renders the system-provided chrome (About/Quit menus, standard alerts) in the user's language instead of the development region's — replacing per-app plutil injection plus manual re-signing. Projects without the declaration build byte-identical bundles to before.

  • Add raco rivet measure for host apps. measure size lists every dist/ artifact with its byte count and, with --budget <file> (glob rules, first match wins), exits nonzero when any artifact exceeds its budget so a bundle-size regression fails the build instead of shipping. measure startup runs the launch-survival smoke over the packaged artifact and reports the elapsed window. Per-RPC latency deliberately stays with the integration --benchmark mode, which measures the real embedded runtime end to end; docs/benchmarks.md documents the budget format and that boundary.

  • Add the updater scaffolding to rivet/distribution. A runtime binds the
    updater config, destination directory, settings bridge, and injectable
    transport hooks; updater-runtime-check! fetches, selects, and drives the
    download while a phase box (idle/checking/available/downloading/ downloaded/error with percent, message, and downloaded path) feeds the
    product's update-state event. The family silent-check throttle stamp is
    now owned here: a stamp is written only when a check settles — an answer
    or a definitive failure — and silent-check-due? reads it through the
    product's settings adapter, ending the three hand-rolled timestamp
    semantics where one offline launch could silence four hours.
    The sticky 0-99 rollout bucket resolves through the same adapter
    (resolve-rollout-bucket!): drawn once from OS entropy, recovered on later
    runs, redrawn on corrupt stored values, degrading to an unpersisted draw when
    the store cannot write.

  • Let one update feed carry multiple installables per platform. Artifacts
    gain an optional component discriminator (app, cli, or tool) that
    participates in the manifest's duplicate-identity rule, writers emit the
    legacy shape when no component is set, and updater-config selects by
    component; a config without one keeps matching component-less entries
    only. raco rivet release --update-payload <installer>:<glob>[:<component>]
    (repeatable) expands project-relative globs into component-tagged feed
    entries, so products shipping an app and a CLI — or a portable tar.gz
    instead of the zip — stop splitting into two feeds. The
    updater-config struct gains the component field as its last argument.

  • Add fetch-sibling-asset to rivet/distribution and the
    raco rivet sign-manifest subcommand. The sibling helper checks the HTTP
    status before saving, enforces the declared Content-Length against the
    byte limit, verifies an optional expected SHA-256, and streams under the
    same connect and idle deadlines as the manifest fetch — replacing the
    private per-product sidecar downloads that silently accepted 404 pages.
    The subcommand builds a manifest from explicitly named artifacts, signs
    it with the distribution signer, verifies the written bytes with the
    public half before publishing (deleting the output on failure), and
    optionally emits .sha256 sidecars next to each artifact, so products
    keep only their asset-naming conventions.

  • Extend the family boundary to Commerce: online payment orchestration and
    credential delivery remain optional product/service concerns and never
    become Rivet dependencies.

  • Bound the updater's network legs. fetch-update-manifest runs its
    blocking connect inside a custodian-owned worker with configurable
    connect and idle deadlines, and download-update enforces a stall
    deadline (no bytes for N seconds) plus an optional total cap on the copy
    loop, so a black-holed peer raises a retryable error instead of parking
    the backend serve thread forever.

  • Add the Kotlin device-session client for Android companions. The RVD1
    records, the HMAC authentication proof and six-digit pairing-code
    transcripts, and the client state machine with its credential-persistence
    gate live beside the existing RVT1 runtime, pinned by the shared
    device-session-golden fixture now shipped into the Kotlin test resources.
    A blocking runner drives the state machine over any byte stream with
    injectable clocks, enforces the post-TLS deadline, surfaces pairing codes
    without auto-confirming them, and accepts the desktop user's decision from
    another thread. Discovery binds the canonical advertisement codec behind
    a driver interface so applications supply their own NSD stack while the
    browser keeps the canonical-only, bounded, vanished-result semantics.
    TLS transport and product integration remain platform work.

  • Document the product-level Permit composition boundary: Rivet remains a
    framework with general secure storage and update integrity, not a built-in
    entitlement, trial, activation, payment, or account system.

  • Give the installers a commercial first-run experience. The macOS DMG
    switches to the branded drag-to-install layout when the project declares
    dmg-background: the volume stages the bundle next to an /Applications
    symlink, a read/write image is attached, Finder is scripted to size the
    660x400 window, set the background, and place both icons, and the styled
    volume converts back to the compressed image. The Windows MSI now authors
    the stock install-dir wizard sequence (welcome, license agreement,
    install directory, progress, exit) through the UI extension, with a
    launch-app checkbox on the finish page driven by the Util extension's
    WixShellExec; the license page shows the configured windows-license
    RTF or renders the repository license text automatically, and optional
    windows-installer-bitmaps replace the wizard artwork. The deb ships
    executable postinst/postrm scripts that refresh the desktop database.
    All behavior is opt-in per project key; projects without the keys build
    byte-identical installers to before.

  • Recreate the Windows package destination before copying release payloads, so
    build/package/release retries over a dirty dist/ tree are idempotent and
    cannot retain stale files or fail with copy-file: destination exists.

  • Add leaf-loadable distribution identity helpers for the canonical manifest
    platform, architecture, installer-extension, and UTC RFC 3339 vocabulary.
    Release tooling and the managed updater now consume the same implementation
    instead of maintaining private mappings.

  • Add the Windows device-gateway transport. A CNG-persisted P-256
    self-signed identity (rotatable by deletion), an SChannel TLS server over
    any accepted socket with the rivet-device/1 ALPN requirement, the
    fail-closed rivet-device._tcp advertisement through DNS-SD, and a
    bounded single-connection listener come together in
    rivet::windows::DeviceSessionService, which feeds accepted sockets to
    the portable rivet::DeviceSessionHost. X.509 SubjectPublicKeyInfo
    extraction joined the portable runtime so companion pins are
    byte-identical across platforms.

  • Add the portable C++ device-session host driver. Over any
    rivet::Transport, rivet::DeviceSessionHost runs the RVD1 preface for
    one accepted desktop connection, enforces the post-TLS deadline, surfaces
    pairing codes without auto-approving, accepts the desktop user's
    confirm/reject decision from another thread with transport writes
    serialized against the run loop, waits on the pairing-window clock, and
    hands the accepted stream to an application handler only after
    acceptance. Deterministic pipe, clock, and multi-thread tests pin the
    reconnect, pairing, rejection, timeout, cancellation, and malformed-preface
    behavior; the Windows and Linux gateways become thin transports over it.

  • Add the portable C++ device-session preface for the Windows and Linux
    gateways. rivet/device_session.hpp implements the RVD1 v1 records, the
    HMAC authentication proof and six-digit pairing-code transcripts, and the
    server-side state machine: reconnect authentication with an
    indistinguishable unknown-device challenge and constant-time proof
    comparison, dual-confirmation pairing over injected window/attempt and
    secure-storage boundaries, canonical scope enforcement, stable reject
    codes, and the post-TLS deadline. The shared
    device-session-golden.txt vectors plus deterministic codec, transcript,
    and state-machine tests pin the contract; TLS transport, listeners, and
    discovery remain platform work.

  • Move the test suite under the rivet collection (rivet/tests/). A
    top-level tests/ directory inside a multi-collection package publishes a
    generic tests collection that cannot coexist with any other package
    doing the same, which the package catalog reports as a conflict. The suite
    now follows the family layout used by the other Rivet libraries, and
    raco test rivet/tests/ is the documented entry point.

  • Keep the package build farm green on hosts without desktop conveniences.
    Console executables are now resolved from the running installation's bin
    directory before PATH, so the build, launch-smoke, and AppImage process
    tests run on build farms that invoke bin/racket by a relative path.
    Digest- and signing-dependent tests skip with a notice where the pinned
    libcrypto factory is unavailable, the manifest composer skips without an
    Ed25519 provider instead of raising, and CI-wiring checks tolerate packaged
    copies that omit dot-directories.

  • Add the framework-only Apple session client for iOS companions.
    RivetDeviceAppleSessionClient connects one explicitly selected endpoint
    through a pinned reconnect or an explicit provisional-pairing TLS context,
    drives the RVD1 session client state machine, surfaces the pairing code
    without auto-confirming it, persists each new credential through an injected
    secure-storage boundary before accepting RVT1, enforces the post-TLS
    deadline, and closes without a pairing fallback when authentication is
    rejected. Connection, session-client, persistence, and deadline boundaries
    are injectable for deterministic reconnect, pairing, persistence-failure,
    timeout, cancellation, and malformed-preface tests; connection policy,
    background lifecycle, and permission strings stay product-owned.

  • Add the framework-only Apple Bonjour browser for iOS companions. Browsing is
    explicitly started and stopped, accepts only the canonical bounded Rivet TXT
    record, bounds candidates and pending events, reports add/change/remove
    lifecycle events, and clears candidates on failure or cancellation.
    Discovery remains unauthenticated and never opens a connection; local-network
    usage strings and Bonjour declarations stay owned by the consuming
    application.

  • Connect accepted macOS device transports to a fresh RivetDeviceSessionServer
    through RivetDeviceAppleSessionHost. The host enforces post-TLS deadlines,
    reports pairing codes without auto-approval, switches to RVT1 only after
    authenticated acceptance, and performs idempotent disconnect cleanup.

  • Repair generated-project package smoke tests after the schema compatibility
    gate became automatic. Workflows that intentionally replace the scaffold
    backend now explicitly regenerate and verify their reviewed schema baseline
    before build/package checks, preserving the gate instead of bypassing it.

  • Add the first Apple companion-session security layers. Service-scoped,
    device-local Keychain storage now persists pairing credentials on macOS and
    iOS, while RivetDeviceSession supplies the bounded RVD1 preface codec,
    HMAC reconnect authentication, dual-confirmation pairing state machines, and
    a credential-persistence gate. Language-neutral golden vectors and
    deterministic malformed-input, ordering, timeout, and authentication tests
    pin the contract before Network.framework integration.

  • Add RivetDeviceAppleTransport for the next Apple companion layer. It
    configures Network.framework for TLS 1.2+, forward-secret AEAD suites, and
    the rivet-device/1 ALPN,
    authenticates either an exact server SPKI SHA-256 pin or an explicit
    provisional-pairing identity, extracts canonical SPKI DER from X.509, bounds
    connection setup to 30 seconds, and preserves the one-way RVD1 to RVT1
    stream transition without exposing a listener or discovery service.

  • Add the disabled-by-default macOS device listener and per-install P-256 TLS
    identity lifecycle. Private keys and their self-signed certificates stay in
    the application Keychain namespace; explicit rotation invalidates the public
    pin. Listener admission is capped before transport/session allocation, and
    disable, failure, and termination close every accepted connection. Product
    enablement remains a separate future step.

  • Add privacy-bounded Bonjour advertising to the macOS device listener. The
    _rivet-device._tcp service exists only while the listener is ready, carries
    a deterministic 128-byte-bounded TXT record with the session version, a
    per-listener ephemeral identifier, and the pairing-window bit, and is removed
    before shutdown. No API names, account/device identifiers, filenames, or user
    content enter discovery; iOS browsing and product UI remain separate work.