diff --git a/CHANGELOG.md b/CHANGELOG.md index 9007431..121ceb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ ## Unreleased +- 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` (including `Result`) 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`; 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`, 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/.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 ` (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. + - 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