kobako 0.26.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0c1c827c03774c7feb9dcb7ff38a4e070203a94abff75c0f76c37f95368ac46
4
- data.tar.gz: 696243ed20eb3354c2f8f545be8a52844a84a5cde353d6a177acba4d5378d017
3
+ metadata.gz: 44a30ef91d42472a6c2e293837d896a58f2bd9e0e91b922ea8d670cc5247282b
4
+ data.tar.gz: 9c401384a1e616408c825873db91437c4600651102160635fa99ef2e89cdbe03
5
5
  SHA512:
6
- metadata.gz: b0628a560a80d649b8b8a40731d688253466b574cd88456fc69900815bb18444a50958364b8a8d8c99ef19244ad0c90ca7730cbde07d41d90a304a035377a23f
7
- data.tar.gz: 8e2ca842efc9529f06840463db63e85823de7dbaac7b91613f6bf198a96e3b012cb36c589ca64d9603a11add54574458d4116e801694c3d0f27cbb99c2403ca4
6
+ metadata.gz: f1be03c26db0531498c857f534e0a8b0ee8f5242bef0f84fdc20f3a906e2ed04ef4896677cea484da200cc5363410867da2fbc1993f0f9c66bce4b6f213c44e2
7
+ data.tar.gz: cd6abe2b568419cce5a4bc31098dd69ff87bd6c6e3d865c25352697b744c895bcefdbbc7bc1d769a4fa5104f2ea12d26741d674589e952014642b01980c577d6
@@ -1 +1 @@
1
- {".":"0.26.0","wasm/kobako-core":"0.16.0","wasm/kobako-mruby":"0.16.0","wasm/kobako-io":"0.16.0","wasm/kobako-json":"0.16.0","wasm/kobako-regexp":"0.16.0","wasm/kobako-baker":"0.16.0","crates/kobako-transport":"0.16.0","crates/kobako-codec":"0.16.0","crates/kobako-runtime":"0.16.0","crates/kobako-wasmtime":"0.16.0","crates/kobako":"0.16.0"}
1
+ {".":"0.27.0","wasm/kobako-core":"0.17.0","wasm/kobako-mruby":"0.17.0","wasm/kobako-io":"0.17.0","wasm/kobako-json":"0.17.0","wasm/kobako-regexp":"0.17.0","wasm/kobako-baker":"0.17.0","crates/kobako-transport":"0.17.0","crates/kobako-codec":"0.17.0","crates/kobako-runtime":"0.17.0","crates/kobako-wasmtime":"0.17.0","crates/kobako":"0.17.0"}
data/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.27.0](https://github.com/elct9620/kobako/compare/v0.26.0...v0.27.0) (2026-09-20)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * **guest:** a pattern's allocator is undefined from the moment the capability installs rather than from its first wrap, so allocating one is refused for the missing allocator throughout an invocation, where before the first statement could still reach an uninitialized carrier.
9
+ * **mruby:** `kobako_mruby::dispatch` takes `Option<Proc>` where it took a `Value` that could be nil. A gem passes the block its method read off its own frame; `None` says there is none.
10
+ * **json:** a JSON failure whose error class the guest replaced reaches the Host App as a guest exception rather than as a trap.
11
+ * **json:** JSON.parse refuses a second positional argument. Options passed as a positional Hash, the shape MRI also refuses, must be written as keywords.
12
+ * **mruby:** an object bearing a capability reference's class name without being one is refused as a value the wire cannot carry, where it previously crossed as a reference to whatever identifier it held.
13
+ * **mruby:** an object whose class carries a list's or a map's name without being one is refused rather than read as that container, both as the invocation's own answer and as a dispatch argument.
14
+ * **guest:** `Kobako::raise_transport_error`, `raise_service_error` and `reraise` are gone. A flow of its own builds `Kobako::transport_error` or `service_error` and hands the result back as `Err`, which beni raises at the guest call site.
15
+
16
+ ### Features
17
+
18
+ * **gate:** hold a crate README's install snippet to its manifest ([31f6926](https://github.com/elct9620/kobako/commit/31f692602de6e1a2d9e5f84872164e83c4008e50))
19
+ * **guest:** rebuild the guest crates on beni 0.17 ([b397701](https://github.com/elct9620/kobako/commit/b397701231c7d8718503d24f73b175676d0d1be3))
20
+ * **guest:** rebuild the guest crates on beni 0.18 ([ae232eb](https://github.com/elct9620/kobako/commit/ae232ebbf708419ff0672172fbf8627363fb02da))
21
+
22
+
23
+ ### Bug Fixes
24
+
25
+ * **json:** read a parse's options from the keywords it declares ([6f0c83c](https://github.com/elct9620/kobako/commit/6f0c83cc0b6ae0fe0f327ad0b514d46a6f3432c0))
26
+ * **json:** report a replaced error class instead of ending the invocation ([5a75e42](https://github.com/elct9620/kobako/commit/5a75e42ba7990eb31d8487dd3979cca3c4a3d29b))
27
+ * **mruby:** prove a container's layout by its tag, not its class name ([5ee8c59](https://github.com/elct9620/kobako/commit/5ee8c59db90cee27f356028ff466860afe89e06e))
28
+ * **mruby:** read a reference's identity from the class the bridge registered ([0f24102](https://github.com/elct9620/kobako/commit/0f24102b75f771548cbc39256690e59d6df1f9e4))
29
+
30
+
31
+ ### Code Refactoring
32
+
33
+ * **mruby:** carry a dispatch's block as the block it is ([01d8831](https://github.com/elct9620/kobako/commit/01d8831dff173e80c10d965af8615acb4de2498b))
34
+
3
35
  ## [0.26.0](https://github.com/elct9620/kobako/compare/v0.25.0...v0.26.0) (2026-09-15)
4
36
 
5
37
 
data/Cargo.lock CHANGED
@@ -858,7 +858,7 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
858
858
 
859
859
  [[package]]
860
860
  name = "kobako"
861
- version = "0.26.0"
861
+ version = "0.27.0"
862
862
  dependencies = [
863
863
  "kobako-runtime",
864
864
  "kobako-transport",
@@ -869,18 +869,18 @@ dependencies = [
869
869
 
870
870
  [[package]]
871
871
  name = "kobako-runtime"
872
- version = "0.16.0"
872
+ version = "0.17.0"
873
873
  dependencies = [
874
874
  "kobako-transport",
875
875
  ]
876
876
 
877
877
  [[package]]
878
878
  name = "kobako-transport"
879
- version = "0.16.0"
879
+ version = "0.17.0"
880
880
 
881
881
  [[package]]
882
882
  name = "kobako-wasmtime"
883
- version = "0.16.0"
883
+ version = "0.17.0"
884
884
  dependencies = [
885
885
  "kobako-runtime",
886
886
  "kobako-transport",
data/README.md CHANGED
@@ -24,11 +24,14 @@ The host (`wasmtime`) runs a precompiled `kobako.wasm` guest containing mruby an
24
24
 
25
25
  ## Requirements
26
26
 
27
- - **Ruby ≥ 3.3.0**
28
- - **Rust / Cargo** at install time — the native extension compiles from source via `rb_sys`
29
- - **Linux** or **macOS** — Windows is not supported
27
+ | What | Which versions | When you need it |
28
+ |---|---|---|
29
+ | Ruby | ≥ 3.3.0 | always |
30
+ | Platform | Linux or macOS | always — Windows is not supported |
31
+ | Rust / Cargo | current stable | only where no prebuilt gem matches your platform; otherwise the native extension installs ready-built |
32
+ | WASI toolchain | vendored by the build | only when building the gem from a source checkout — see [Development](#development) |
30
33
 
31
- The precompiled `kobako.wasm` Guest Binary ships inside the gem, so end users do **not** need a WASI toolchain. (The toolchain is only required if you build the gem from a source checkout — see [Development](#development).)
34
+ The precompiled `kobako.wasm` Guest Binary ships inside the gem, so end users do **not** need a WASI toolchain.
32
35
 
33
36
  ## Installation
34
37
 
@@ -63,9 +66,16 @@ The gem bundles its Guest Binary; a Rust host loads one explicitly — see [Fron
63
66
 
64
67
  ## Frontends & Guest Binaries
65
68
 
66
- Embedding kobako is two independent choices: the **host frontend** you build against, and the **Guest Binary** it runs. They compose freely — any frontend loads any Guest Binary, so a Ruby host can run a JSON-enabled guest and a Rust host can run the pure default.
69
+ Embedding kobako is two independent choices: the **host frontend** you build against, and the **Guest Binary** it runs.
67
70
 
68
- How far down those choices go — and which ones a given starting point quietly makes for you — is laid out in [`docs/architecture.md`](docs/architecture.md).
71
+ ```text
72
+ host frontend Guest Binary
73
+ Ruby gem ──┐ ┌── kobako.wasm (pure)
74
+ Rust SDK ──┼──┼── kobako+regexp.wasm
75
+ your own ──┘ └── kobako+json.wasm · your own
76
+ ```
77
+
78
+ They compose freely — any frontend loads any Guest Binary, so a Ruby host can run a JSON-enabled guest and a Rust host can run the pure default. How far down those choices go — and which ones a given starting point quietly makes for you — is laid out in [`docs/architecture.md`](docs/architecture.md).
69
79
 
70
80
  ### Host frontends
71
81
 
@@ -149,6 +159,16 @@ Build the crate as a `cdylib` for `wasm32-wasip1`, then bake the canonical boot
149
159
 
150
160
  ## Usage
151
161
 
162
+ Each section below stands on its own; this is the order they build in.
163
+
164
+ | If you want to | Read |
165
+ |---|---|
166
+ | let guest code call into your host | [Services](#services), [Per-Invocation Bindings](#per-invocation-bindings), [Service Blocks](#service-blocks) |
167
+ | see what a run produced or why it failed | [Output Capture](#output-capture), [Error Handling](#error-handling), [Invocation Lifecycle](#invocation-lifecycle) |
168
+ | bound what a run may consume | [Resource Limits](#resource-limits), [Concurrency](#concurrency), [Pooling](#pooling) |
169
+ | hand host objects across the boundary | [Handle Management](#handle-management) |
170
+ | ship guest code with the Sandbox | [Snippets & Entrypoints](#snippets--entrypoints), [Extensions](#extensions) |
171
+
152
172
  ### Services
153
173
 
154
174
  `bind` any Ruby object as a Service at a constant-path name; the guest reaches it as a `MyService::KV` (or top-level `File`) proxy and invokes the public methods its own class defines through the Transport wire. See [`SV-006`](docs/spec/behavior/services.md) and [`SV-007`](docs/spec/behavior/services.md).
@@ -256,7 +276,14 @@ Beyond the four caps, `profile:` requests the Sandbox's isolation posture on the
256
276
 
257
277
  ### Concurrency
258
278
 
259
- A Sandbox keeps no state from any run, so concurrent Threads may invoke distinct Sandboxes or share a single one; each invocation owns its Handles, captures, and usage either way ([`RT-001`](docs/spec/behavior/runtime.md), [`RT-002`](docs/spec/behavior/runtime.md)). One Thread still runs one invocation at a time. Sharing a Sandbox adds a single obligation: an object bound once at setup is reached by every Thread and must itself be thread-safe, while an object supplied per invocation — `ctx.bind`, or an Extension `provider:` — carries no such requirement.
279
+ A Sandbox keeps no state from any run, so concurrent Threads may invoke distinct Sandboxes or share a single one; each invocation owns its Handles, captures, and usage either way ([`RT-001`](docs/spec/behavior/runtime.md), [`RT-002`](docs/spec/behavior/runtime.md)). One Thread still runs one invocation at a time. Sharing a Sandbox adds a single obligation.
280
+
281
+ | What you bind | Who reaches it | What it owes |
282
+ |---|---|---|
283
+ | Bound once at setup | every Thread sharing the Sandbox | it must itself be thread-safe |
284
+ | Supplied per invocation — `ctx.bind`, or an Extension `provider:` | that invocation alone | nothing |
285
+
286
+ #### Choosing a GVL mode
260
287
 
261
288
  By default an invocation holds Ruby's GVL for its whole span, so guest execution across Threads serializes. `gvl: :release` drops the GVL for the guest span and re-acquires it for each guest→host dispatch, running guest code in parallel across Threads ([`RT-024`](docs/spec/behavior/runtime.md), [`RT-026`](docs/spec/behavior/runtime.md)).
262
289
 
@@ -321,8 +348,6 @@ For workloads that must be isolated from each other (one Sandbox per tenant, per
321
348
 
322
349
  For hosts that serve many short invocations, `Kobako::Pool` keeps a bounded set of warm, identically set-up Sandboxes and hands each one to a single exclusive holder at a time ([`PL-003`](docs/spec/behavior/pool.md), [`PL-011`](docs/spec/behavior/pool.md)). Construction forwards every `Sandbox.new` keyword verbatim; the optional block is the per-Sandbox setup window and runs exactly once per constructed Sandbox.
323
350
 
324
- `Kobako::Pool` is experimental today and is best treated as a convenience for warm, pre-configured reuse rather than a throughput optimisation. The build bakes the shared boot state into the artifact ([`mruby.md`](docs/spec/behavior/mruby.md)) and every dynamic script still compiles and runs per invocation, so all a pool actually saves is the host-side `Sandbox.new` — now under 3 µs, an order of magnitude below the invocation that follows it. For the workload kobako is built for — many small, short-lived Sandboxes running dynamic scripts — that is not a gain worth the coupling. What a Pool buys is warm setup and exclusive checkout, not isolation: a Sandbox holds no state from any run, so Threads sharing one are equally safe (see [Concurrency](#concurrency)).
325
-
326
351
  ```ruby
327
352
  pool = Kobako::Pool.new(slots: 4) do |sandbox|
328
353
  sandbox.bind("KV::Lookup", ->(key) { redis.get(key) })
@@ -331,6 +356,8 @@ end
331
356
  pool.with { |sandbox| sandbox.eval(%(KV::Lookup.call("user_42"))).value }
332
357
  ```
333
358
 
359
+ #### Options and lifetime
360
+
334
361
  | Option | Meaning | Default |
335
362
  |--------|---------|---------|
336
363
  | `slots:` | Upper bound on constructed Sandboxes | required |
@@ -338,6 +365,14 @@ pool.with { |sandbox| sandbox.eval(%(KV::Lookup.call("user_42"))).value }
338
365
 
339
366
  Sandboxes construct lazily on first demand. `#with` yields a Sandbox and returns the block's value; at block exit the Sandbox returns to the pool, except a block that raises `Kobako::TrapError` discards its Sandbox and the slot refills by a fresh construction on next demand. A checkout that waits past `checkout_timeout` raises `Kobako::PoolTimeoutError`. There is no teardown verb — a Pool releases everything with its own reachability.
340
367
 
368
+ #### What a Pool buys
369
+
370
+ | It gives you | It does not give you |
371
+ |---|---|
372
+ | warm, pre-configured Sandboxes and exclusive checkout | isolation — a Sandbox holds no state from any run, so Threads sharing one are equally safe (see [Concurrency](#concurrency)) |
373
+
374
+ `Kobako::Pool` is experimental today and is best treated as a convenience for warm, pre-configured reuse rather than a throughput optimisation. The build bakes the shared boot state into the artifact ([`mruby.md`](docs/spec/behavior/mruby.md)) and every dynamic script still compiles and runs per invocation, so all a pool actually saves is the host-side `Sandbox.new` — now about 3 µs, an order of magnitude below the invocation that follows it. For the workload kobako is built for — many small, short-lived Sandboxes running dynamic scripts — that is not a gain worth the coupling.
375
+
341
376
  ### Service Blocks
342
377
 
343
378
  A Service method can accept a guest-supplied block via `&blk` and `yield` into it. The block body runs inside the Wasm guest; `break` / `next` / exceptions follow normal Ruby semantics, scoped to the single dispatch. See [`T-085`](docs/spec/behavior/transport-yield.md) and [`T-089`](docs/spec/behavior/transport-yield.md).
@@ -367,6 +402,8 @@ sandbox.eval('Factory::Make.call("Bob")').value # => #<Greeter @name="Bob
367
402
 
368
403
  A `break` value from a guest block is the one exception: it unwinds back to the guest Service call rather than to host code, so a Handle in it stays a Handle — restoring would just re-wrap the same object into a new id on the return trip.
369
404
 
405
+ #### One Handle per dispatch
406
+
370
407
  Each dispatch that hands back a non-wire-representable object allocates a *new* Handle — kobako never deduplicates by object identity ([`T-007`](docs/spec/behavior/transport-dispatch.md), [`T-009`](docs/spec/behavior/transport-dispatch.md)). This is most visible with fluent / builder APIs. An `ActiveRecord::Relation` chain `spawn`s a fresh relation at each step, so every hop is an independent dispatch that binds its own Handle:
371
408
 
372
409
  ```
@@ -417,6 +454,8 @@ A target no snippet defined raises `Kobako::UndefinedEntrypointError`, whose `#a
417
454
  return the Execution, then discard the instance
418
455
  ```
419
456
 
457
+ #### Choosing a payload form
458
+
420
459
  `#preload` accepts two payload forms:
421
460
 
422
461
  | Form | Signature | Snippet name source | Validation timing |
@@ -481,11 +520,22 @@ sandbox.bind("Cfg::Settings", ThemeReader.new) # not: bind("Cfg::Settings", App
481
520
  sandbox.eval('Cfg::Settings.color').value # => "#3366ff" — every other method raises NoMethodError
482
521
  ```
483
522
 
523
+ #### Gating an object's own surface
524
+
484
525
  When a purpose-built wrapper is more than you need, an object can gate its own surface in
485
526
  place: a private `respond_to_guest?(name)` answers, per method, whether the guest may call
486
527
  it. Returning `false` for every name makes the object opaque — a credential the guest
487
528
  forwards to another Service but never reads — while permitting a named subset exposes exactly those.
488
529
 
530
+ ```ruby
531
+ class Credential
532
+ def initialize(token) = @token = token
533
+ def to_s = @token
534
+
535
+ private def respond_to_guest?(_name) = false # forwardable, never readable
536
+ end
537
+ ```
538
+
489
539
  Guest code can name any `MyService::KV` path, but a forged name only resolves to
490
540
  something you bound — the real authorization gate is this host-side allowlist. Give each
491
541
  trust context its own Sandbox, and see [`docs/security-model.md`](docs/security-model.md) for the rest
@@ -499,17 +549,25 @@ Order-of-magnitude figures on macOS arm64, Ruby 3.4.7, YJIT off. Absolute values
499
549
  | Phase | Cost |
500
550
  |--------------------------------------------------------------|-----------------------|
501
551
  | First `Sandbox.new` ever for a Guest Binary (Module JIT, then disk-cached) | ~500 ms once per machine |
502
- | First `Sandbox.new` in a fresh process (`.cwasm` cache warm) | ~1.3 ms one-time |
552
+ | First `Sandbox.new` in a fresh process (`.cwasm` cache warm) | ~3 ms one-time |
503
553
  | Subsequent `Sandbox.new` (caches warm) | ~3 µs |
504
- | Warm `#eval` with one Service call on a reused Sandbox | ~71 µs |
505
- | Warm `#run(:Entrypoint, ...)` dispatch | ~81 µs |
506
- | Service call amortized inside one invocation | ~5.7 µs |
507
- | Snippet replay per invocation | ~7.5 µs each |
554
+ | Warm `#eval` with one Service call on a reused Sandbox | ~70 µs |
555
+ | Warm `#run(:Entrypoint, ...)` dispatch | ~79 µs |
556
+ | Service call amortized inside one invocation | ~5.8 µs |
557
+ | Snippet replay per invocation | ~7.0 µs each |
508
558
  | Per additional idle Sandbox (RSS) | ~1 KB |
509
559
 
510
- The Cranelift JIT runs once per machine and gem version — the compiled artifact persists in a `.cwasm` disk cache, so later processes deserialize in milliseconds. An idle Sandbox holds no wasm instance (the canonical boot state is baked into the artifact and instantiated per invocation), which is why a thousand idle tenants cost ~33 MB total. Under the default `gvl: :hold`, wasm work is GVL-serialized: aggregate throughput stays around 16k `#eval`/s regardless of Thread count, though Ruby-side `#eval` setup still overlaps. Opting a Sandbox into `gvl: :release` lifts that ceiling for compute-bound scripts (see [Concurrency](#concurrency)). A +10% regression on any SPEC-mandated benchmark blocks release.
560
+ The Cranelift JIT runs once per machine and gem version — the compiled artifact persists in a `.cwasm` disk cache, so later processes deserialize in milliseconds. An idle Sandbox holds no wasm instance (the canonical boot state is baked into the artifact and instantiated per invocation), which is why a thousand idle tenants cost ~34 MB total. A +10% regression on any SPEC-mandated benchmark blocks release.
561
+
562
+ #### What moves the ceiling
511
563
 
512
- Regexp is an opt-in capability gem, excluded from the default binary and the gated set; its throughput is tracked in a separate non-gated characterization (`#11` in [`benchmark/README.md`](benchmark/README.md)). There `=~` (~5 µs/match) costs about 4.5× `match?` (~1.1 µs), because `=~` eagerly builds the `MatchData` and match globals — prefer `match?` for boolean tests.
564
+ | Choice | What it changes |
565
+ |---|---|
566
+ | `gvl: :hold` (default) | wasm work is GVL-serialized: aggregate throughput stays around 16k `#eval`/s regardless of Thread count, though Ruby-side `#eval` setup still overlaps |
567
+ | `gvl: :release` | lifts that ceiling for compute-bound scripts (see [Concurrency](#concurrency)) |
568
+ | `match?` over `=~` | `=~` (~5 µs/match) costs about 5× `match?` (~1.0 µs), because it eagerly builds the `MatchData` and match globals — prefer `match?` for boolean tests |
569
+
570
+ Regexp is an opt-in capability gem, excluded from the default binary and the gated set; its throughput is tracked in a separate non-gated characterization (`#11` in [`benchmark/README.md`](benchmark/README.md)).
513
571
 
514
572
  ```bash
515
573
  bundle exec rake bench # every gated regression benchmark (~5-8 min)
@@ -530,7 +588,12 @@ Building from source requires a WASI-capable Rust toolchain in addition to the s
530
588
 
531
589
  Bug reports and pull requests are welcome at <https://github.com/elct9620/kobako>. Please open an issue before starting on non-trivial changes so we can align on scope.
532
590
 
533
- Releases are automated with release-please across two tracks — the gem and the linked guest-crate group. The version rules, commit conventions, and how to cut each release live in [`docs/releasing.md`](docs/releasing.md).
591
+ Releases are automated with release-please across two tracks; the version rules, commit conventions, and how to cut each release live in [`docs/releasing.md`](docs/releasing.md).
592
+
593
+ | Track | What it ships | Tag |
594
+ |---|---|---|
595
+ | Gem | the Ruby gem, with the bundled `kobako.wasm` | `v*` |
596
+ | Crates | the linked guest-crate group | `<component>-v*` |
534
597
 
535
598
  ## License
536
599
 
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.17.0](https://github.com/elct9620/kobako/compare/kobako-runtime-v0.16.0...kobako-runtime-v0.17.0) (2026-09-20)
4
+
5
+
6
+ ### Miscellaneous Chores
7
+
8
+ * **kobako-runtime:** Synchronize kobako crates versions
9
+
3
10
  ## [0.16.0](https://github.com/elct9620/kobako/compare/kobako-runtime-v0.15.0...kobako-runtime-v0.16.0) (2026-09-15)
4
11
 
5
12
 
@@ -13,7 +13,7 @@
13
13
 
14
14
  [package]
15
15
  name = "kobako-runtime"
16
- version = "0.16.0"
16
+ version = "0.17.0"
17
17
  edition = "2021"
18
18
  description = "Engine-neutral host runtime contract for embedding kobako Wasm guests."
19
19
  license = "Apache-2.0"
@@ -27,4 +27,4 @@ categories = ["wasm", "virtualization"]
27
27
  # in-tree builds (and the Ruby gem, which ships both crates) resolving
28
28
  # locally.
29
29
  [dependencies]
30
- kobako-transport = { version = "0.16.0", path = "../kobako-transport" }
30
+ kobako-transport = { version = "0.17.0", path = "../kobako-transport" }
@@ -6,17 +6,14 @@ sandbox for running untrusted mruby scripts.
6
6
 
7
7
  A kobako host drives a Guest Binary through a wasm engine; this crate
8
8
  is the surface where the two meet, free of any engine or frontend
9
- type, so the engine stays swappable:
10
-
11
- - `runtime` — the `Runtime` trait: one guest invocation on a fresh
12
- instance in, its observable `Snapshot` out
13
- - `snapshot` — the per-invocation observables: `Completion` (outcome
14
- or trap), the two output `Capture`s, and resource `Usage`, uniform
15
- across success and trap
16
- - `error` — the neutral failure channels: `Trap` (engine fault) and
17
- `SetupError` (the invocation never started)
18
- - `dispatch` / `yielder` — the `DispatchHandler` and `Yielder` traits
19
- a frontend supplies for guest→host dispatch and block-yield re-entry
9
+ type, so the engine stays swappable.
10
+
11
+ | Module | What it declares |
12
+ |---|---|
13
+ | `runtime` | the `Runtime` trait: one guest invocation on a fresh instance in, its observable `Snapshot` out |
14
+ | `snapshot` | the per-invocation observables — `Completion` (outcome or trap), the two output `Capture`s, and resource `Usage`, uniform across success and trap |
15
+ | `error` | the neutral failure channels: `Trap` (engine fault) and `SetupError` (the invocation never started) |
16
+ | `dispatch` / `yielder` | the `DispatchHandler` and `Yielder` traits a frontend supplies for guest→host dispatch and block-yield re-entry |
20
17
 
21
18
  Engine implementations (such as `kobako-wasmtime`) implement
22
19
  `Runtime`; host frontends (such as the kobako Ruby gem's native ext)
@@ -26,7 +23,7 @@ map the neutral types onto their own language surface.
26
23
 
27
24
  ```toml
28
25
  [dependencies]
29
- kobako-runtime = "0.16.0" # x-release-please-version
26
+ kobako-runtime = "0.17.0" # x-release-please-version
30
27
  ```
31
28
 
32
29
  ## License
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.17.0](https://github.com/elct9620/kobako/compare/kobako-transport-v0.16.0...kobako-transport-v0.17.0) (2026-09-20)
4
+
5
+
6
+ ### Miscellaneous Chores
7
+
8
+ * **kobako-transport:** Synchronize kobako crates versions
9
+
3
10
  ## [0.16.0](https://github.com/elct9620/kobako/compare/kobako-transport-v0.15.0...kobako-transport-v0.16.0) (2026-09-15)
4
11
 
5
12
 
@@ -12,7 +12,7 @@
12
12
 
13
13
  [package]
14
14
  name = "kobako-transport"
15
- version = "0.16.0"
15
+ version = "0.17.0"
16
16
  edition = "2021"
17
17
  description = "The kobako core envelope — the fixed host↔guest wire frame every assembly shares."
18
18
  license = "Apache-2.0"
@@ -5,27 +5,34 @@ an in-process Wasm sandbox for running untrusted mruby scripts.
5
5
 
6
6
  kobako is assembled from three parts chosen independently: a host, a
7
7
  payload codec, and a guest. That works only because two things are the
8
- same in every assembly. This crate is both of them, and nothing else:
9
-
10
- - `envelope` — the **core envelope**, the outer frame each message rides
11
- in: `Call` / `Reply` / `YieldReply` for a dispatch round-trip,
12
- `Outcome` / `Panic` for how an invocation ended, `Run` / `Preamble` /
13
- `Snippets` for what an invocation is handed, and the `ErrorRecord` a
14
- guest failure carries
15
- - `abi` — the values a host and a guest must already agree on to
16
- exchange a byte: the version, the packed `(ptr, len)` return layout,
17
- the invocation-channel frame prefix, and the message size cap
18
-
19
- The envelope reads a message's routing fields and its ok-versus-fault
20
- tag without decoding a payload byte; everything the resolved method
21
- consumes rides through as an opaque `payload` this layer never reads.
22
- A decoded envelope borrows the buffer it came from, so that payload
23
- reaches its reader as a view rather than a copy.
24
-
25
- This crate depends on no other, and every kobako tier depends on it:
26
- `kobako-runtime` and `kobako-wasmtime` on the host, `kobako-core` and
27
- `kobako-mruby` in the guest, and any third-party engine, codec, or
28
- guest that composes against them.
8
+ same in every assembly. This crate is both of them, and nothing else.
9
+
10
+ | Module | What it fixes |
11
+ |---|---|
12
+ | `envelope` | the **core envelope**, the outer frame each message rides in: `Call` / `Reply` / `YieldReply` for a dispatch round-trip, `Outcome` / `Panic` for how an invocation ended, `Run` / `Preamble` / `Snippets` for what an invocation is handed, and the `ErrorRecord` a guest failure carries |
13
+ | `abi` | the values a host and a guest must already agree on to exchange a byte: the version, the packed `(ptr, len)` return layout, the invocation-channel frame prefix, and the message size cap |
14
+
15
+ ## What the envelope does not read
16
+
17
+ The envelope reads a message's routing fields and its ok-versus-fault tag
18
+ without decoding a payload byte. Everything the resolved method consumes
19
+ rides through opaque, and a decoded envelope borrows the buffer it came
20
+ from, so that payload reaches its reader as a view rather than a copy.
21
+
22
+ ```text
23
+ Call { method, payload }
24
+ └── opaque here; read by whoever owns the schema
25
+ ```
26
+
27
+ ## Where it sits
28
+
29
+ This crate depends on no other, and every kobako tier depends on it —
30
+ including any third-party engine, codec, or guest composing against them.
31
+
32
+ ```text
33
+ host kobako-runtime · kobako-wasmtime ──┐
34
+ guest kobako-core · kobako-mruby ────────┴──> kobako-transport
35
+ ```
29
36
 
30
37
  The byte layout is specified in
31
38
  [`docs/wire/envelope.md`](https://github.com/elct9620/kobako/blob/main/docs/wire/envelope.md);
@@ -35,7 +42,7 @@ the golden vectors in this crate are derived from that document.
35
42
 
36
43
  ```toml
37
44
  [dependencies]
38
- kobako-transport = "0.16.0" # x-release-please-version
45
+ kobako-transport = "0.17.0" # x-release-please-version
39
46
  ```
40
47
 
41
48
  ## License
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.17.0](https://github.com/elct9620/kobako/compare/kobako-wasmtime-v0.16.0...kobako-wasmtime-v0.17.0) (2026-09-20)
4
+
5
+
6
+ ### Miscellaneous Chores
7
+
8
+ * **kobako-wasmtime:** Synchronize kobako crates versions
9
+
3
10
  ## [0.16.0](https://github.com/elct9620/kobako/compare/kobako-wasmtime-v0.15.0...kobako-wasmtime-v0.16.0) (2026-09-15)
4
11
 
5
12
 
@@ -15,7 +15,7 @@
15
15
 
16
16
  [package]
17
17
  name = "kobako-wasmtime"
18
- version = "0.16.0"
18
+ version = "0.17.0"
19
19
  edition = "2021"
20
20
  description = "wasmtime implementation of the kobako host runtime contract."
21
21
  license = "Apache-2.0"
@@ -28,10 +28,10 @@ categories = ["wasm", "virtualization"]
28
28
  # The engine-neutral contract this crate implements. The version pin
29
29
  # rides the linked release group; the path keeps in-tree builds (and
30
30
  # the Ruby gem, which ships both crates) resolving locally.
31
- kobako-runtime = { version = "0.16.0", path = "../kobako-runtime" }
31
+ kobako-runtime = { version = "0.17.0", path = "../kobako-runtime" }
32
32
  # The fixed tier: the core envelope this driver shuttles and the ABI
33
33
  # values it drives the exports against.
34
- kobako-transport = { version = "0.16.0", path = "../kobako-transport" }
34
+ kobako-transport = { version = "0.17.0", path = "../kobako-transport" }
35
35
  # wasmtime — host-side embedder for kobako.wasm. We disable default-features
36
36
  # and opt back in only what kobako needs: a Cranelift-backed runtime that can
37
37
  # compile a pre-built wasm32-wasip1 module on the host triple, plus the `wat`
@@ -6,16 +6,14 @@ The [wasmtime](https://wasmtime.dev) implementation of the
6
6
 
7
7
  `Driver` implements the contract's `Runtime` trait over wasmtime and
8
8
  owns every engine-bound mechanic, so frontends see only the neutral
9
- contract surface:
9
+ contract surface.
10
10
 
11
- - process-wide Engine and compiled-Module caches with an on-disk AOT
12
- (`.cwasm`) artifact cache keyed by Guest Binary content
13
- - a pre-linked `InstancePre` per guest path; every invocation runs on
14
- a fresh instance and discards its Store afterwards
15
- - the epoch-based wall-clock timeout and the per-invocation
16
- linear-memory cap
17
- - ambient denial: frozen WASI clocks and a constant RNG, so a guest
18
- observes no real time and no real entropy
11
+ | Mechanic | What the driver holds |
12
+ |---|---|
13
+ | Compilation | process-wide Engine and compiled-Module caches, with an on-disk AOT (`.cwasm`) artifact cache keyed by Guest Binary content |
14
+ | Instantiation | a pre-linked `InstancePre` per guest path; every invocation runs on a fresh instance and discards its Store afterwards |
15
+ | Bounds | the epoch-based wall-clock timeout and the per-invocation linear-memory cap |
16
+ | Ambient denial | frozen WASI clocks and a constant RNG, so a guest observes no real time and no real entropy |
19
17
 
20
18
  The kobako Ruby gem's native ext is the first frontend; a Rust host
21
19
  SDK consumes the same surface.
@@ -24,7 +22,7 @@ SDK consumes the same surface.
24
22
 
25
23
  ```toml
26
24
  [dependencies]
27
- kobako-wasmtime = "0.16.0" # x-release-please-version
25
+ kobako-wasmtime = "0.17.0" # x-release-please-version
28
26
  ```
29
27
 
30
28
  ## License
data/data/kobako.wasm CHANGED
Binary file
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "kobako"
3
- version = "0.26.0"
3
+ version = "0.27.0"
4
4
  edition = "2021"
5
5
  authors = ["Aotokitsuruya <contact@aotoki.me>"]
6
6
  license = "Apache-2.0"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kobako
4
- VERSION = "0.26.0"
4
+ VERSION = "0.27.0"
5
5
  end
data/rust-toolchain.toml CHANGED
@@ -3,9 +3,13 @@
3
3
  # vendored wasi-sdk 33's libc.a supplies that symbol, so the two move together.
4
4
  # Bump this in lockstep with the wasi-sdk toolchain beni vendors
5
5
  # (`rake beni:build`, wired in the Rakefile's Beni::Tasks block).
6
+ # The floor is 1.98: rustc strips an Apple binary with its own Mach-O writer,
7
+ # and only from that release does the stripped string pool keep the alignment
8
+ # dyld requires from macOS 26 onward — below it, `strip = true` in the release
9
+ # profile yields an ext no dlopen accepts.
6
10
  # This file is the single source of the channel; the CI workflows read it.
7
11
  [toolchain]
8
- channel = "1.96.0"
12
+ channel = "1.98.0"
9
13
  components = ["clippy", "rustfmt"]
10
14
  targets = ["wasm32-wasip1"]
11
15
  profile = "minimal"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kobako
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.26.0
4
+ version: 0.27.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aotokitsuruya