✓
Passing This code compiles and runs correctly.
Code
// Test: Cross-session handle discharge
// The core bridge scenario: create handle in run 1, discharge in run 2
//
// This is the Hollywood OS pattern - state persists across turns,
// human or AI can act on resources created in previous turns.
~import std/runtime
~import std/io
const std = @import("std");
const HandlePool = @import("root").koru_std.koru_interpreter.HandlePool;
// External pool - the bridge
var bridge_pool = HandlePool.init(std.heap.page_allocator);
// Events with obligations
~pub tor open { path: string } -> string<opened!>
~open -> "file_1"
~pub tor close { handle: string<!opened> }
~proc close|zig {
std.debug.print("close() called for handle\n", .{});
}
~std/runtime:register(scope: "files") {
open(10)
close(1)
}
// Session 1: Open a file (creates obligation). `open` is a bare return, so the
// value binds — there is no `| opened` branch to ask for, and asking for one
// was what killed this test from the day it was written.
const SESSION_1 = "open(path: \"test.txt\")";
// Session 2: Close the file (discharges obligation). `close` returns nothing,
// so there is no branch here either.
const SESSION_2 = "close(handle: \"file_1\")";
// Run session 1 — creates the handle on the shared pool.
~std/runtime:run(source: SESSION_1, scope: "files", budget: 100, handle_pool: &bridge_pool, auto_discharge: false)
| result r1 |> std/io:print.ln("PASS: session 1 opened — bridge holds {{ r1.handles:d }} handle(s)")
| unhandled-branch _ |> std/io:print.ln("FAIL: unhandled_branch")
| exhausted _ |> std/io:print.ln("FAIL: session 1 exhausted")
| parse-error _ |> std/io:print.ln("FAIL: session 1 parse_error")
| validation-error _ |> std/io:print.ln("FAIL: session 1 validation_error")
| shape-error _ |> std/io:print.ln("FAIL: session 1 shape_error")
| event-denied _ |> std/io:print.ln("FAIL: session 1 event_denied")
| dispatch-error _ |> std/io:print.ln("FAIL: session 1 dispatch_error")
| scope-not-found _ |> std/io:print.ln("FAIL: session 1 scope_not_found")
// Run session 2 — discharges the handle, same shared pool. Two flat runs
// (session.k's turn shape): a tor called as an arm body's last step is
// refused by KORU022's pipeline check, so the sessions are top-level.
~std/runtime:run(source: SESSION_2, scope: "files", budget: 100, handle_pool: &bridge_pool, auto_discharge: false)
| result r2 |> std/io:print.ln("PASS: session 2 closed — bridge holds {{ r2.handles:d }} handle(s)")
| unhandled-branch _ |> std/io:print.ln("FAIL: unhandled_branch")
| exhausted _ |> std/io:print.ln("FAIL: session 2 exhausted")
| parse-error _ |> std/io:print.ln("FAIL: session 2 parse_error")
| validation-error _ |> std/io:print.ln("FAIL: session 2 validation_error")
| shape-error _ |> std/io:print.ln("FAIL: session 2 shape_error")
| event-denied _ |> std/io:print.ln("FAIL: session 2 event_denied")
| dispatch-error _ |> std/io:print.ln("FAIL: session 2 dispatch_error")
| scope-not-found _ |> std/io:print.ln("FAIL: session 2 scope_not_found")
Actual
PASS: session 1 opened — bridge holds 1 handle(s)
close() called for handle
PASS: session 2 closed — bridge holds 0 handle(s)
Expected output
PASS: session 1 opened — bridge holds 1 handle(s)
close() called for handle
PASS: session 2 closed — bridge holds 0 handle(s)
Flows
flow ~register click a branch to expand · @labels scroll to their anchor
register (scope: "files", source: open(10)
close(1))
flow ~run click a branch to expand · @labels scroll to their anchor
run (source: SESSION_1, scope: "files", budget: 100, handle_pool: &bridge_pool, auto_discharge: false)
flow ~run click a branch to expand · @labels scroll to their anchor
run (source: SESSION_2, scope: "files", budget: 100, handle_pool: &bridge_pool, auto_discharge: false)
Test Configuration
MUST_RUN