kobako 0.10.0-aarch64-linux → 0.11.0-aarch64-linux

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.
@@ -1,13 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kobako
4
- # A named grouping of Members for one Sandbox
5
- # ({docs/behavior.md B-07..B-11}[link:../../docs/behavior.md]).
4
+ # A named grouping of Members for one Sandbox.
6
5
  # Returned by +Sandbox#define+. Each instance owns a flat name→object
7
6
  # table of Members; member binding is validated against {NAME_PATTERN}.
8
7
  class Namespace
9
- # Ruby constant-name pattern shared by Namespace and Member names
10
- # ({docs/behavior.md B-07/B-08 Notes}[link:../../docs/behavior.md]).
8
+ # Ruby constant-name pattern shared by Namespace and Member names.
11
9
  NAME_PATTERN = /\A[A-Z]\w*\z/
12
10
 
13
11
  attr_reader :name
@@ -26,9 +24,8 @@ module Kobako
26
24
  # object that responds to the methods guest code will invoke. Returns
27
25
  # +self+ for chaining. Raises +ArgumentError+ when +member+ does not
28
26
  # match the constant pattern, when a Member of the same name is
29
- # already bound ({docs/behavior.md B-11}[link:../../docs/behavior.md]),
30
- # or when the owning Sandbox's first invocation has sealed Service
31
- # registration ({docs/behavior.md E-45}[link:../../docs/behavior.md]).
27
+ # already bound, or when the owning Sandbox's first invocation has
28
+ # sealed Service registration.
32
29
  def bind(member, object)
33
30
  raise ArgumentError, "cannot bind after first Sandbox invocation" if @sealed
34
31
 
@@ -39,10 +36,10 @@ module Kobako
39
36
  self
40
37
  end
41
38
 
42
- # Mark this Namespace as sealed ({docs/behavior.md B-33}[link:../../docs/behavior.md]).
43
- # Called by +Kobako::Catalog::Namespaces#seal!+ on the owning
44
- # Sandbox's first invocation; afterwards {#bind} raises
45
- # +ArgumentError+ (E-45). Idempotent; returns +self+.
39
+ # Mark this Namespace as sealed. Called by
40
+ # +Kobako::Catalog::Namespaces#seal!+ on the owning Sandbox's first
41
+ # invocation; afterwards {#bind} raises +ArgumentError+. Idempotent;
42
+ # returns +self+.
46
43
  def seal!
47
44
  @sealed = true
48
45
  self
@@ -7,8 +7,7 @@ module Kobako
7
7
  # Host-facing boundary for the OUTCOME_BUFFER produced by
8
8
  # +__kobako_eval+. Takes raw outcome bytes — a one-byte tag followed by
9
9
  # the msgpack-encoded body — and maps them to either the unwrapped
10
- # mruby return value or a raised three-layer
11
- # ({docs/behavior.md Error Scenarios}[link:../../docs/behavior.md]) exception.
10
+ # mruby return value or a raised three-layer exception.
12
11
  #
13
12
  # Self-contained: this module owns the wire framing (tag bytes,
14
13
  # body decoding), and the +Panic+ wire record lives at
@@ -17,11 +16,11 @@ module Kobako
17
16
  # nothing in +Transport+ participates.
18
17
  #
19
18
  # * tag 0x01, decode OK → return decoded value
20
- # * tag 0x01, decode fails → SandboxError (E-09)
21
- # * tag 0x02, origin="service" → ServiceError (E-13)
22
- # * tag 0x02, origin="sandbox"/missing → SandboxError (E-04..E-07)
23
- # * tag 0x02, decode fails → SandboxError (E-08)
24
- # * unknown tag → TrapError (E-03)
19
+ # * tag 0x01, decode fails → SandboxError
20
+ # * tag 0x02, origin="service" → ServiceError
21
+ # * tag 0x02, origin="sandbox"/missing → SandboxError
22
+ # * tag 0x02, decode fails → SandboxError
23
+ # * unknown tag → TrapError
25
24
  module Outcome
26
25
  # First byte of the OUTCOME_BUFFER for the success branch — body is
27
26
  # the bare msgpack encoding of the returned value
@@ -71,7 +70,7 @@ module Kobako
71
70
  [tag, body]
72
71
  end
73
72
 
74
- # Decode failure on the success tag is a SandboxError (E-09): the
73
+ # Decode failure on the success tag is a SandboxError: the
75
74
  # framing was fine, but the carried value is unrepresentable. The
76
75
  # specific codec fault is stashed in +details+ rather
77
76
  # than spliced into the message — callers cannot act on the inner
@@ -86,7 +85,7 @@ module Kobako
86
85
  )
87
86
  end
88
87
 
89
- # Decode failure on the panic tag is a SandboxError (E-08). Either
88
+ # Decode failure on the panic tag is a SandboxError. Either
90
89
  # path raises — on success the decoded Panic is mapped to its three-
91
90
  # layer exception via +build_panic_error+ and raised; on wire-decode
92
91
  # failure the rescue path raises the wire-violation +SandboxError+.
@@ -130,13 +129,12 @@ module Kobako
130
129
  )
131
130
  end
132
131
 
133
- # {docs/behavior.md Error Scenarios}[link:../../docs/behavior.md]: map
134
- # the panic +class+ field to the matching Ruby exception subclass so
135
- # callers can rescue specific failure paths. +origin="service"+ →
132
+ # Map the panic +class+ field to the matching Ruby exception subclass
133
+ # so callers can rescue specific failure paths. +origin="service"+
136
134
  # +ServiceError+; +origin="sandbox"+ plus
137
135
  # +class="Kobako::BytecodeError"+ selects the +BytecodeError+
138
- # subclass (E-37 / E-38). Everything else falls back to the base
139
- # class for the origin.
136
+ # subclass. Everything else falls back to the base class for the
137
+ # origin.
140
138
  def panic_target_class(panic)
141
139
  case panic.origin
142
140
  when Panic::ORIGIN_SERVICE
data/lib/kobako/pool.rb CHANGED
@@ -5,32 +5,28 @@ require_relative "sandbox"
5
5
 
6
6
  module Kobako
7
7
  # Kobako::Pool — a bounded set of warm, identically set-up Sandboxes
8
- # handed out one exclusive holder at a time
9
- # ({docs/behavior.md B-46..B-48}[link:../../docs/behavior.md]).
8
+ # handed out one exclusive holder at a time.
10
9
  #
11
10
  # Construction forwards every +Kobako::Sandbox.new+ keyword verbatim
12
11
  # and holds the optional block as the per-Sandbox setup hook; a
13
12
  # checkout prefers an idle Sandbox and constructs a new one only when
14
- # none is idle and fewer than +slots+ exist (B-46). +#with+ blocks up
15
- # to +checkout_timeout+ seconds when every slot is held (E-46), applies
16
- # the +TrapError+ discard-and-recreate contract at checkin (B-47), and
13
+ # none is idle and fewer than +slots+ exist. +#with+ blocks up
14
+ # to +checkout_timeout+ seconds when every slot is held, applies
15
+ # the +TrapError+ discard-and-recreate contract at checkin, and
17
16
  # the Pool releases everything with its own reachability — there is no
18
- # teardown verb (B-48).
17
+ # teardown verb.
19
18
  class Pool
20
- # The +#with+ wait bound applied when +checkout_timeout+ is not given
21
- # ({docs/behavior.md B-46}[link:../../docs/behavior.md]).
19
+ # The +#with+ wait bound applied when +checkout_timeout+ is not given.
22
20
  DEFAULT_CHECKOUT_TIMEOUT_SECONDS = 5.0
23
21
 
24
- # Build a Pool of up to +slots+ Sandboxes
25
- # ({docs/behavior.md B-46}[link:../../docs/behavior.md]). +slots+ is
22
+ # Build a Pool of up to +slots+ Sandboxes. +slots+ is
26
23
  # a positive Integer; +checkout_timeout+ bounds the +#with+ wait in
27
24
  # seconds (+nil+ waits indefinitely); every other keyword is
28
25
  # forwarded verbatim to +Kobako::Sandbox.new+. The optional block
29
26
  # runs exactly once per constructed Sandbox — it is the setup window
30
27
  # for +#define+ / +#preload+ before that Sandbox's first checkout.
31
28
  # No Sandbox is constructed here. Raises +ArgumentError+ for an
32
- # invalid +slots+ / +checkout_timeout+
33
- # ({docs/behavior.md E-47}[link:../../docs/behavior.md]).
29
+ # invalid +slots+ / +checkout_timeout+.
34
30
  def initialize(slots:, checkout_timeout: DEFAULT_CHECKOUT_TIMEOUT_SECONDS, **sandbox_options, &setup)
35
31
  validate_slots!(slots)
36
32
  @slots = slots
@@ -44,11 +40,9 @@ module Kobako
44
40
  end
45
41
 
46
42
  # Yield one exclusively-held Sandbox to the block and return the
47
- # block's value ({docs/behavior.md B-47}[link:../../docs/behavior.md]).
48
- # Blocks while every slot is held; raises +Kobako::PoolTimeoutError+
49
- # once the wait exceeds +checkout_timeout+
50
- # ({docs/behavior.md E-46}[link:../../docs/behavior.md]). The Sandbox
51
- # returns to the pool at block exit — unless the block raised
43
+ # block's value. Blocks while every slot is held; raises
44
+ # +Kobako::PoolTimeoutError+ once the wait exceeds +checkout_timeout+.
45
+ # The Sandbox returns to the pool at block exit — unless the block raised
52
46
  # +Kobako::TrapError+, in which case the unrecoverable Sandbox is
53
47
  # discarded and its slot refills by a fresh construction on next
54
48
  # demand.
@@ -68,12 +62,12 @@ module Kobako
68
62
  private
69
63
 
70
64
  # Acquire a Sandbox and hand it over in pre-invocation state — empty
71
- # output buffers and truncation predicates false (B-47).
65
+ # output buffers and truncation predicates false.
72
66
  def checkout
73
67
  acquire.tap(&:reset_invocation_state!)
74
68
  end
75
69
 
76
- # The idle-first claim loop (B-46): an idle Sandbox wins, unclaimed
70
+ # The idle-first claim loop: an idle Sandbox wins, unclaimed
77
71
  # capacity constructs, and a full pool waits for a checkin.
78
72
  def acquire
79
73
  timeout = @checkout_timeout
@@ -105,7 +99,7 @@ module Kobako
105
99
  end
106
100
 
107
101
  # Wait for a checkin or freed capacity; raises
108
- # +Kobako::PoolTimeoutError+ once +deadline+ has passed (E-46). Must
102
+ # +Kobako::PoolTimeoutError+ once +deadline+ has passed. Must
109
103
  # run while holding +@mutex+.
110
104
  def await_slot!(deadline)
111
105
  remaining = deadline && (deadline - monotonic_now)
@@ -119,7 +113,7 @@ module Kobako
119
113
 
120
114
  # Construct and set up one pooled Sandbox against the capacity
121
115
  # reserved by +claim_or_wait+. Construction and setup-block errors
122
- # propagate to the checkout caller unchanged (B-46); the reserved
116
+ # propagate to the checkout caller unchanged; the reserved
123
117
  # capacity is released so a later checkout can retry.
124
118
  def construct_slot
125
119
  done = false
@@ -154,7 +148,7 @@ module Kobako
154
148
  Process.clock_gettime(Process::CLOCK_MONOTONIC)
155
149
  end
156
150
 
157
- # E-47 pre-flight for +slots+ — no coercion, a positive Integer is
151
+ # Pre-flight for +slots+ — no coercion, a positive Integer is
158
152
  # the only accepted shape.
159
153
  def validate_slots!(slots)
160
154
  return if slots.is_a?(Integer) && slots.positive?
@@ -163,8 +157,8 @@ module Kobako
163
157
  end
164
158
 
165
159
  # Coerce +checkout_timeout+ into the Float seconds the wait loop
166
- # consumes, or +nil+ to wait indefinitely — the E-39 normalisation
167
- # idiom applied to E-47.
160
+ # consumes, or +nil+ to wait indefinitely — the same normalisation
161
+ # idiom +SandboxOptions+ applies to +timeout+.
168
162
  def normalize_checkout_timeout(checkout_timeout)
169
163
  return nil if checkout_timeout.nil?
170
164
  unless checkout_timeout.is_a?(Numeric)
@@ -13,21 +13,19 @@ require_relative "catalog"
13
13
 
14
14
  module Kobako
15
15
  # Kobako::Sandbox — the user-facing entry point for executing guest mruby
16
- # scripts inside a wasmtime-hosted Wasm module
17
- # ({docs/behavior.md B-01}[link:../../docs/behavior.md]).
16
+ # scripts inside a wasmtime-hosted Wasm module.
18
17
  #
19
18
  # The Sandbox owns the +Kobako::Runtime+, the per-Sandbox
20
- # +Kobako::Catalog::Handles+ ({docs/behavior.md B-19}[link:../../docs/behavior.md]),
21
- # the per-instance +Kobako::Catalog::Namespaces+ (which receives the
22
- # +Catalog::Handles+ by injection so guest→host dispatch and host→guest
23
- # auto-wrap share one allocator), and the dispatch +Proc+ /
24
- # +yield_to_guest+ lambda installed on the Runtime via
25
- # +Runtime#on_dispatch=+ ({docs/behavior.md B-12}[link:../../docs/behavior.md]).
26
- # The underlying wasmtime Engine and compiled Module are cached at process
27
- # scope by the native ext and never surface to Ruby — constructing many
28
- # Sandboxes amortises both costs automatically.
19
+ # +Kobako::Catalog::Handles+, the per-instance
20
+ # +Kobako::Catalog::Namespaces+ (which receives the +Catalog::Handles+ by
21
+ # injection so guest→host dispatch and host→guest auto-wrap share one
22
+ # allocator), and the dispatch +Proc+ / +yield_to_guest+ lambda installed
23
+ # on the Runtime via +Runtime#on_dispatch=+. The underlying wasmtime Engine
24
+ # and compiled Module are cached at process scope by the native ext and
25
+ # never surface to Ruby constructing many Sandboxes amortises both costs
26
+ # automatically.
29
27
  #
30
- # Output capture policy ({docs/behavior.md B-04}[link:../../docs/behavior.md]): the
28
+ # Output capture policy: the
31
29
  # per-channel cap (+stdout_limit+ / +stderr_limit+) is enforced inside the
32
30
  # WASI pipe — the host buffer stops growing at the cap, subsequent guest
33
31
  # writes on that channel fail or are dropped, and +#run+ still returns
@@ -46,9 +44,8 @@ module Kobako
46
44
 
47
45
  # Returns the bytes the guest wrote to stdout during the most recent
48
46
  # invocation as a UTF-8 String, clipped at +stdout_limit+. Empty before
49
- # any invocation. {docs/behavior.md B-04}[link:../../docs/behavior.md] the byte
50
- # content never contains a truncation sentinel; use +#stdout_truncated?+ to
51
- # observe overflow.
47
+ # any invocation; the byte content never contains a truncation sentinel,
48
+ # so use +#stdout_truncated?+ to observe overflow.
52
49
  def stdout
53
50
  @stdout_capture.bytes
54
51
  end
@@ -61,9 +58,8 @@ module Kobako
61
58
  end
62
59
 
63
60
  # Returns +true+ iff stdout capture during the most recent invocation
64
- # exceeded +stdout_limit+ ({docs/behavior.md B-04}[link:../../docs/behavior.md]). Resets
65
- # to +false+ at the start of the next invocation
66
- # ({docs/behavior.md B-03}[link:../../docs/behavior.md]).
61
+ # exceeded +stdout_limit+. Resets to +false+ at the start of the next
62
+ # invocation.
67
63
  def stdout_truncated?
68
64
  @stdout_capture.truncated?
69
65
  end
@@ -75,8 +71,7 @@ module Kobako
75
71
  end
76
72
 
77
73
  # Returns the +Kobako::Usage+ value object for the most recent
78
- # invocation ({docs/behavior.md B-35}[link:../../docs/behavior.md]).
79
- # Carries +wall_time+ (Float seconds the guest export call spent
74
+ # invocation. Carries +wall_time+ (Float seconds the guest export call spent
80
75
  # inside wasmtime) and +memory_peak+ (Integer bytes, high-water of
81
76
  # the per-invocation +memory.grow+ delta past the entry-time
82
77
  # baseline). Returns +Kobako::Usage::EMPTY+ before any invocation;
@@ -109,9 +104,8 @@ module Kobako
109
104
  reset_invocation_state!
110
105
  end
111
106
 
112
- # Declare or retrieve the Namespace named +name+ on this Sandbox
113
- # ({docs/behavior.md B-07, B-09, B-10}[link:../../docs/behavior.md]). +name+ must be a
114
- # Symbol or String in constant form. Returns the
107
+ # Declare or retrieve the Namespace named +name+ on this Sandbox. +name+
108
+ # must be a Symbol or String in constant form. Returns the
115
109
  # +Kobako::Namespace+.
116
110
  #
117
111
  # Raises +ArgumentError+ when called after the first invocation, or
@@ -120,20 +114,18 @@ module Kobako
120
114
  @services.define(name)
121
115
  end
122
116
 
123
- # Register a snippet on this Sandbox in one of two forms
124
- # ({docs/behavior.md B-32}[link:../../docs/behavior.md]):
117
+ # Register a snippet on this Sandbox in one of two forms:
125
118
  #
126
119
  # * +preload(code: source, name: Name)+ — +source+ is mruby source
127
120
  # as a +String+ and +Name+ matches +/\A[A-Z]\w*\z/+. The +name+
128
121
  # becomes the snippet's +(snippet:Name)+ backtrace filename and
129
- # is the dedupe key for E-33.
122
+ # is the dedupe key that rejects a duplicate +code:+ snippet.
130
123
  # * +preload(binary: bytes)+ — +bytes+ is precompiled RITE
131
124
  # bytecode as a +String+. The canonical name, when present,
132
125
  # lives in the bytecode's embedded +debug_info+ and is resolved
133
126
  # by the guest at load time; the host treats the bytes as
134
- # opaque. Structural failures
135
- # ({docs/behavior.md E-37 / E-38}[link:../../docs/behavior.md])
136
- # surface as +Kobako::BytecodeError+ on the first invocation.
127
+ # opaque. Structural failures surface as +Kobako::BytecodeError+
128
+ # on the first invocation.
137
129
  #
138
130
  # Subsequent invocations (+#eval+ or +#run+) replay every registered
139
131
  # snippet — in insertion order — against the fresh +mrb_state+
@@ -145,11 +137,9 @@ module Kobako
145
137
  # supplied, when both forms are mixed (e.g., +code:+ and +binary:+
146
138
  # together, or +binary:+ paired with +name:+), when +code+ / +bytes+
147
139
  # is not a +String+, when +name+ does not match the constant
148
- # pattern ({docs/behavior.md E-34}[link:../../docs/behavior.md]),
149
- # when +name+ duplicates an already-registered +code:+ form snippet
150
- # ({docs/behavior.md E-33}[link:../../docs/behavior.md]), or when
151
- # called after the first invocation
152
- # ({docs/behavior.md E-35, B-33}[link:../../docs/behavior.md]).
140
+ # pattern, when +name+ duplicates an already-registered +code:+ form
141
+ # snippet, or when called after the first invocation has sealed the
142
+ # snippet table.
153
143
  def preload(code: nil, name: nil, binary: nil)
154
144
  raise ArgumentError, "cannot preload after first Sandbox invocation" if @services.sealed?
155
145
 
@@ -157,17 +147,16 @@ module Kobako
157
147
  self
158
148
  end
159
149
 
160
- # Dispatch into a preloaded entrypoint constant
161
- # ({docs/behavior.md B-31}[link:../../docs/behavior.md]). Delegates host
150
+ # Dispatch into a preloaded entrypoint constant. Delegates host
162
151
  # pre-flight and wire encoding to +Kobako::Transport::Run+ /
163
152
  # +Kobako::Transport::Run#encode+: a non-Symbol/String +target+ raises
164
- # +TypeError+ (E-24), while a +target+ failing the constant pattern
165
- # (E-25), a forged +Kobako::Handle+ in +args+ / +kwargs+ (E-29), or a
166
- # non-Symbol +kwargs+ key (E-30) raise +ArgumentError+. The guest
167
- # resolves +target+ as a top-level constant, calls +#call+ on it with
168
- # +args+ / +kwargs+, and returns the deserialized result. The first
169
- # invocation seals the Service registry and snippet table (B-07 /
170
- # B-33). Runtime errors follow the same three-class taxonomy as +#eval+.
153
+ # +TypeError+, while a +target+ failing the constant pattern, a forged
154
+ # +Kobako::Handle+ in +args+ / +kwargs+, or a non-Symbol +kwargs+ key
155
+ # raise +ArgumentError+. The guest resolves +target+ as a top-level
156
+ # constant, calls +#call+ on it with +args+ / +kwargs+, and returns the
157
+ # deserialized result. The first invocation seals the Service registry
158
+ # and snippet table. Runtime errors follow the same three-class
159
+ # taxonomy as +#eval+.
171
160
  def run(target, *args, **kwargs)
172
161
  run_envelope = Transport::Run.new(entrypoint: target, args: args, kwargs: kwargs)
173
162
  invoke!(:run) do
@@ -175,29 +164,27 @@ module Kobako
175
164
  end
176
165
  end
177
166
 
178
- # Execute a guest mruby source string in a fresh +mrb_state+
179
- # ({docs/behavior.md B-02 / B-03 / B-06}[link:../../docs/behavior.md]). +code+ is the
180
- # mruby source as a UTF-8 String. Returns the deserialized last
167
+ # Execute a guest mruby source string in a fresh +mrb_state+. +code+ is
168
+ # the mruby source as a UTF-8 String. Returns the deserialized last
181
169
  # expression of the source.
182
170
  #
183
171
  # Source delivery uses the WASI stdin three-frame protocol
184
172
  # ({docs/wire-codec.md Invocation channels}[link:../../docs/wire-codec.md]):
185
173
  # Frame 1 carries the msgpack-encoded preamble (Namespace / Member
186
174
  # registry snapshot), Frame 2 carries the user source UTF-8 bytes, and
187
- # Frame 3 carries the snippet table registered via +#preload+ (B-32).
175
+ # Frame 3 carries the snippet table registered via +#preload+.
188
176
  # Each frame is prefixed by a 4-byte big-endian u32 length; Frame 3 is
189
177
  # mandatory-presence — an empty snippet table sends an empty msgpack
190
178
  # array, never an absent frame.
191
179
  #
192
- # The first invocation seals the Service registry and snippet table
193
- # ({docs/behavior.md B-07 / B-33}[link:../../docs/behavior.md]); subsequent
194
- # +#define+ / +#preload+ calls raise +ArgumentError+.
180
+ # The first invocation seals the Service registry and snippet table;
181
+ # subsequent +#define+ / +#preload+ calls raise +ArgumentError+.
195
182
  #
196
183
  # Raises +Kobako::TrapError+ on a Wasm trap or wire-violation fallback;
197
184
  # +Kobako::SandboxError+ when the guest ran to completion but failed
198
185
  # (including when +code+ is +nil+ or not a String, or when a preloaded
199
- # snippet's replay raises E-36);
200
- # +Kobako::ServiceError+ on an unrescued Service capability failure.
186
+ # snippet's replay raises); +Kobako::ServiceError+ on an unrescued
187
+ # Service capability failure.
201
188
  def eval(code)
202
189
  raise SandboxError, "code must be a String, got #{code.class}" unless code.is_a?(String)
203
190
 
@@ -207,15 +194,11 @@ module Kobako
207
194
  end
208
195
 
209
196
  # Reset all per-invocation observable state to its pre-invocation
210
- # sentinels — both per-channel captures
211
- # ({docs/behavior.md B-05}[link:../../docs/behavior.md]) and the
212
- # per-last-invocation usage record
213
- # ({docs/behavior.md B-35}[link:../../docs/behavior.md]). Shared by
214
- # +#initialize+ (first-time setup) and +#begin_invocation!+
215
- # (between-invocation reset) so both paths agree on what
216
- # "pre-invocation state" means; +Kobako::Pool+ calls it at checkout
217
- # so a pooled Sandbox hands over empty output buffers
218
- # ({docs/behavior.md B-47}[link:../../docs/behavior.md]).
197
+ # sentinels — both per-channel captures and the per-last-invocation
198
+ # usage record. Shared by +#initialize+ (first-time setup) and
199
+ # +#begin_invocation!+ (between-invocation reset) so both paths agree on
200
+ # what "pre-invocation state" means; +Kobako::Pool+ calls it at checkout
201
+ # so a pooled Sandbox hands over empty output buffers.
219
202
  def reset_invocation_state!
220
203
  @stdout_capture = Capture::EMPTY
221
204
  @stderr_capture = Capture::EMPTY
@@ -224,14 +207,13 @@ module Kobako
224
207
 
225
208
  private
226
209
 
227
- # Configure the +Runtime+'s host↔guest dispatch wiring
228
- # ({docs/behavior.md B-12}[link:../../docs/behavior.md]). Builds a
210
+ # Configure the +Runtime+'s host↔guest dispatch wiring. Builds a
229
211
  # lambda that re-enters the guest via
230
- # +Runtime#yield_to_active_invocation+ (B-24) and a dispatch +Proc+
231
- # that routes guest→host calls through the stateless
232
- # +Transport::Dispatcher+, capturing +@services+ / +@handler+ in the
233
- # closure. Both are registered on the +Runtime+ once at construction
234
- # time so the wasm ext callback can fire without further setup.
212
+ # +Runtime#yield_to_active_invocation+ and a dispatch +Proc+ that routes
213
+ # guest→host calls through the stateless +Transport::Dispatcher+,
214
+ # capturing +@services+ / +@handler+ in the closure. Both are registered
215
+ # on the +Runtime+ once at construction time so the wasm ext callback can
216
+ # fire without further setup.
235
217
  def install_dispatch_proc!
236
218
  yield_to_guest = ->(args_bytes) { @runtime.yield_to_active_invocation(args_bytes) }
237
219
  @runtime.on_dispatch = lambda do |request_bytes|
@@ -239,14 +221,13 @@ module Kobako
239
221
  end
240
222
  end
241
223
 
242
- # Per-invocation prologue ({docs/behavior.md B-03 / B-07 /
243
- # B-33}[link:../../docs/behavior.md]). Seals the Service / snippet
244
- # registries on first call (idempotent) and zeros the per-invocation
245
- # capability state — capture buffers, truncation predicates, and the
224
+ # Per-invocation prologue. Seals the Service / snippet registries on
225
+ # first call (idempotent) and zeros the per-invocation capability
226
+ # state capture buffers, truncation predicates, and the
246
227
  # +Catalog::Handles+ counter — before the guest runs. The
247
- # +Catalog::Handles+ itself is held as +@handler+ and never exposed beyond
248
- # this class: SPEC.md Terminology pins it as "Not exposed to the
249
- # Host App" (B-19 / B-20 / E-29).
228
+ # +Catalog::Handles+ itself is held as +@handler+ and never exposed
229
+ # beyond this class: SPEC.md Terminology pins it as "Not exposed to the
230
+ # Host App".
250
231
  def begin_invocation!
251
232
  @services.seal!
252
233
  @handler.reset!
@@ -254,8 +235,7 @@ module Kobako
254
235
  end
255
236
 
256
237
  # Read the per-last-invocation +wall_time+ and +memory_peak+ from
257
- # the ext and wrap them as a +Kobako::Usage+ value object
258
- # ({docs/behavior.md B-35}[link:../../docs/behavior.md]). Runs in
238
+ # the ext and wrap them as a +Kobako::Usage+ value object. Runs in
259
239
  # the +invoke!+ +ensure+ block so the usage record is populated on
260
240
  # every outcome — value return, +Kobako::TrapError+ (including
261
241
  # +TimeoutError+ / +MemoryLimitError+), +Kobako::SandboxError+,
@@ -273,8 +253,7 @@ module Kobako
273
253
  end
274
254
 
275
255
  # Pick the +TrapError+ subclass to re-raise based on +err+'s actual
276
- # class. Cap-trap subclasses
277
- # ({docs/behavior.md E-19 / E-20}[link:../../docs/behavior.md])
256
+ # class. Cap-trap subclasses (+TimeoutError+ / +MemoryLimitError+)
278
257
  # preserve their named identity; everything else collapses to the
279
258
  # base +Kobako::TrapError+. The ext already raises the right subclass
280
259
  # directly, so this is a pure re-attribution that lets +#invoke!+
@@ -298,9 +277,8 @@ module Kobako
298
277
  # +Capture+ and feeds +#return_bytes+ to +Outcome.decode+; usage is
299
278
  # populated by the +ensure+ readout ({#read_usage!}) on every outcome.
300
279
  # The rescue chain is the single trap-translation boundary —
301
- # configured-cap paths
302
- # ({docs/behavior.md E-19 / E-20}[link:../../docs/behavior.md])
303
- # surface as named TrapError subclasses; everything else surfaces as
280
+ # configured-cap paths surface as named TrapError subclasses
281
+ # (+TimeoutError+ / +MemoryLimitError+); everything else surfaces as
304
282
  # the base +TrapError+.
305
283
  def invoke!(verb)
306
284
  begin_invocation!
@@ -309,7 +287,7 @@ module Kobako
309
287
  @stderr_capture = snapshot.stderr
310
288
  # A Capability Handle in the result is decoded as a Kobako::Handle
311
289
  # token; restore it to the host object the guest referenced before
312
- # handing the value to the Host App (B-37). @handler still holds this
290
+ # handing the value to the Host App. @handler still holds this
313
291
  # invocation's table — reset only happens at the next #begin_invocation!.
314
292
  Codec::Utils.deep_restore(Outcome.decode(snapshot.return_bytes), @handler)
315
293
  rescue Kobako::TrapError => e
@@ -2,8 +2,7 @@
2
2
 
3
3
  module Kobako
4
4
  # Kobako::SandboxOptions — immutable Value Object holding the four
5
- # per-Sandbox configuration caps ({docs/behavior.md B-01,
6
- # E-20}[link:../../docs/behavior.md]). Built on the +class X <
5
+ # per-Sandbox configuration caps. Built on the +class X <
7
6
  # Data.define(...)+ subclass form (the Steep-friendly shape — see
8
7
  # +lib/kobako/outcome/panic.rb+).
9
8
  #
@@ -13,18 +12,15 @@ module Kobako
13
12
  # +super+. Anything that survives +SandboxOptions.new+ is a wire-ready
14
13
  # cap bundle the +Kobako::Runtime+ constructor consumes as-is.
15
14
  class SandboxOptions < Data.define(:timeout, :memory_limit, :stdout_limit, :stderr_limit)
16
- # Default wall-clock timeout for a single invocation: 60 seconds
17
- # ({docs/behavior.md B-01}[link:../../docs/behavior.md]).
15
+ # Default wall-clock timeout for a single invocation: 60 seconds.
18
16
  DEFAULT_TIMEOUT_SECONDS = 60.0
19
17
 
20
18
  # Default cap on the per-invocation guest linear-memory delta:
21
- # 1 MiB ({docs/behavior.md B-01}[link:../../docs/behavior.md]).
22
- # The mruby image's initial allocation and prior invocations'
23
- # watermark sit outside this budget — see B-01 Notes.
19
+ # 1 MiB. The mruby image's initial allocation and prior invocations'
20
+ # watermark sit outside this budget.
24
21
  DEFAULT_MEMORY_LIMIT = 1 << 20
25
22
 
26
- # Default per-channel capture ceiling: 1 MiB
27
- # ({docs/behavior.md B-01}[link:../../docs/behavior.md]).
23
+ # Default per-channel capture ceiling: 1 MiB.
28
24
  DEFAULT_OUTPUT_LIMIT = 1 << 20
29
25
 
30
26
  def initialize(timeout: DEFAULT_TIMEOUT_SECONDS,
@@ -16,8 +16,7 @@ module Kobako
16
16
  # Host App.
17
17
  class Snapshot
18
18
  # Wrap the stdout capture pair (+stdout_bytes+, +stdout_truncated+)
19
- # as a +Kobako::Capture+ value object. {docs/behavior.md
20
- # B-04}[link:../../docs/behavior.md] — the byte content never carries
19
+ # as a +Kobako::Capture+ value object. The byte content never carries
21
20
  # a truncation sentinel; +#truncated?+ is the only way to observe
22
21
  # that the cap was hit.
23
22
  def stdout
@@ -31,8 +30,7 @@ module Kobako
31
30
  end
32
31
 
33
32
  # Wrap the per-last-invocation usage pair (+wall_time+,
34
- # +memory_peak+) as a +Kobako::Usage+ value object
35
- # ({docs/behavior.md B-35}[link:../../docs/behavior.md]).
33
+ # +memory_peak+) as a +Kobako::Usage+ value object.
36
34
  def usage
37
35
  Usage.new(wall_time: wall_time, memory_peak: memory_peak)
38
36
  end
@@ -3,8 +3,7 @@
3
3
  module Kobako
4
4
  module Snippet
5
5
  # Kobako::Snippet::Binary — value object representing a single
6
- # +#preload(binary:)+ entry held by +Kobako::Catalog::Snippets+
7
- # ({docs/behavior.md B-32}[link:../../../docs/behavior.md]).
6
+ # +#preload(binary:)+ entry held by +Kobako::Catalog::Snippets+.
8
7
  #
9
8
  # The +body+ is RITE bytecode (as emitted by +mrbc+) carried as an
10
9
  # +ASCII_8BIT+ String so msgpack-ruby encodes it as +bin+ family on
@@ -12,7 +11,6 @@ module Kobako
12
11
  # The host treats the bytes as opaque — the snippet's canonical
13
12
  # name, when present, lives in the bytecode's embedded +debug_info+
14
13
  # and is resolved by the guest at load time; structural validation
15
- # ({docs/behavior.md E-37 / E-38}[link:../../../docs/behavior.md])
16
14
  # is deferred to the first invocation's guest replay.
17
15
  #
18
16
  # The class is a +Data.define+ subclass — frozen and value-equal.
@@ -3,8 +3,7 @@
3
3
  module Kobako
4
4
  module Snippet
5
5
  # Kobako::Snippet::Source — value object representing a single
6
- # +#preload(code:, name:)+ entry held by +Kobako::Catalog::Snippets+
7
- # ({docs/behavior.md B-32}[link:../../../docs/behavior.md]).
6
+ # +#preload(code:, name:)+ entry held by +Kobako::Catalog::Snippets+.
8
7
  #
9
8
  # +name+ is the canonical +Symbol+ identity baked into the loaded
10
9
  # IREP's +debug_info+; backtrace frames originating in this snippet
@@ -5,8 +5,7 @@ require_relative "snippet/source"
5
5
 
6
6
  module Kobako
7
7
  # Kobako::Snippet — value-object family for preloaded snippet entries
8
- # held by +Kobako::Catalog::Snippets+
9
- # ({docs/behavior.md B-32 / B-33}[link:../../docs/behavior.md]).
8
+ # held by +Kobako::Catalog::Snippets+.
10
9
  #
11
10
  # +Source+ represents a single +#preload(code:, name:)+ entry; +Binary+
12
11
  # represents a single +#preload(binary:)+ entry. Both are plain value