Module: Kobako::Sandbox::OutcomeDecoder
- Defined in:
- lib/kobako/sandbox/outcome_decoder.rb
Overview
Pure-function decoder for the OUTCOME_BUFFER bytes returned by __kobako_run. Maps a tagged msgpack envelope to either the unwrapped mruby return value or a raised three-layer (SPEC.md “Error Scenarios”) exception.
* tag 0x01, decode OK → return Result.value
* tag 0x01, decode fails → SandboxError (E-09)
* tag 0x02, origin="service" → ServiceError (E-13)
* tag 0x02, origin="sandbox"/missing → SandboxError (E-04..E-07)
* tag 0x02, decode fails → SandboxError (E-08)
* unknown tag → TrapError (E-03)
Class Method Summary collapse
-
.build_panic_error(panic) ⇒ Object
Map a decoded Panic envelope into the corresponding three-layer Ruby exception.
- .decode(bytes) ⇒ Object
-
.decode_panic(body) ⇒ Object
Decode failure on a known Panic tag is a SandboxError (E-08).
-
.decode_result(body) ⇒ Object
Decode failure on a known Result tag is a SandboxError (E-09): the framing was fine, but the wrapped value is unrepresentable.
-
.panic_target_class(panic) ⇒ Object
SPEC “Error Classes”: when origin=“service” and the panic
classfield namesServiceError::Disconnected, surface that subclass so callers can rescue the disconnected path specifically (E-14). - .split_outcome_tag(bytes) ⇒ Object
-
.trap_for_tag(tag) ⇒ Object
TrapError for unknown or absent tag (SPEC.md ABI Signatures: len=0 and unknown-tag both walk the trap path).
- .wire_violation_error(message) ⇒ Object
Class Method Details
.build_panic_error(panic) ⇒ Object
Map a decoded Panic envelope into the corresponding three-layer Ruby exception. origin == “service” → ServiceError (with the ::Disconnected subclass selected when the panic carries the disconnected sentinel —SPEC “Error Classes”); everything else → SandboxError.
71 72 73 74 75 76 77 78 79 |
# File 'lib/kobako/sandbox/outcome_decoder.rb', line 71 def build_panic_error(panic) panic_target_class(panic).new( panic., origin: panic.origin, klass: panic.klass, backtrace_lines: panic.backtrace, details: panic.details ) end |
.decode(bytes) ⇒ Object
19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/kobako/sandbox/outcome_decoder.rb', line 19 def decode(bytes) tag, body = split_outcome_tag(bytes) case tag when Kobako::Wire::Envelope::OUTCOME_TAG_RESULT decode_result(body) when Kobako::Wire::Envelope::OUTCOME_TAG_PANIC decode_panic(body) else raise trap_for_tag(tag) end end |
.decode_panic(body) ⇒ Object
Decode failure on a known Panic tag is a SandboxError (E-08). Either path raises — on success the decoded Panic is mapped to its three- layer exception via build_panic_error and raised; on wire-decode failure the rescue path raises the wire-violation SandboxError. Symmetric with decode_result — both have signature “decode body and return value, or raise”.
59 60 61 62 63 |
# File 'lib/kobako/sandbox/outcome_decoder.rb', line 59 def decode_panic(body) raise build_panic_error(Kobako::Wire::Envelope.decode_panic(body)) rescue Kobako::Wire::Codec::Error => e raise wire_violation_error("panic envelope decode failed: #{e.}") end |
.decode_result(body) ⇒ Object
Decode failure on a known Result tag is a SandboxError (E-09): the framing was fine, but the wrapped value is unrepresentable.
47 48 49 50 51 |
# File 'lib/kobako/sandbox/outcome_decoder.rb', line 47 def decode_result(body) Kobako::Wire::Envelope.decode_result(body).value rescue Kobako::Wire::Codec::Error => e raise wire_violation_error("result envelope decode failed: #{e.}") end |
.panic_target_class(panic) ⇒ Object
SPEC “Error Classes”: when origin=“service” and the panic class field names ServiceError::Disconnected, surface that subclass so callers can rescue the disconnected path specifically (E-14).
85 86 87 88 89 |
# File 'lib/kobako/sandbox/outcome_decoder.rb', line 85 def panic_target_class(panic) return SandboxError unless panic.origin == Kobako::Wire::Envelope::Panic::ORIGIN_SERVICE panic.klass == "Kobako::ServiceError::Disconnected" ? ServiceError::Disconnected : ServiceError end |
.split_outcome_tag(bytes) ⇒ Object
40 41 42 43 |
# File 'lib/kobako/sandbox/outcome_decoder.rb', line 40 def split_outcome_tag(bytes) bytes = bytes.b [bytes.getbyte(0), bytes.byteslice(1, bytes.bytesize - 1)] end |
.trap_for_tag(tag) ⇒ Object
TrapError for unknown or absent tag (SPEC.md ABI Signatures: len=0 and unknown-tag both walk the trap path).
34 35 36 37 38 |
# File 'lib/kobako/sandbox/outcome_decoder.rb', line 34 def trap_for_tag(tag) return TrapError.new("guest exited without writing an outcome (len=0)") if tag.nil? TrapError.new(format("unknown outcome tag 0x%<tag>02x", tag: tag)) end |
.wire_violation_error(message) ⇒ Object
91 92 93 94 95 96 97 |
# File 'lib/kobako/sandbox/outcome_decoder.rb', line 91 def wire_violation_error() SandboxError.new( , origin: Kobako::Wire::Envelope::Panic::ORIGIN_SANDBOX, klass: "Kobako::WireError" ) end |