✓
Passing This code compiles and runs correctly.
Code
// PIN: after `commit(tx)` discharges the <transaction!> obligation, binding `tx`
// is stale — its phantom state was consumed. Using `tx` in a subsequent call
// (rollback) is use-after-discharge. This is the database analogue of
// 330_007_use_after_disposal: a binding used after its obligation is discharged.
//
// Grounding:
// - legal flow: 330_027/input.kz:4-9 (commit OR rollback, then disconnect)
// - commit consuming <!tx>: ./db.kz:40 (~pub event commit { tx: *Transaction<!transaction> })
// - use-after pattern: 330_007/input.kz:3 (close then use-file with same binding)
import app/db
app/db:connect(url: "postgres://localhost/test"): c |> app/db:query(conn: c, sql: "SELECT * FROM users"): tx |> app/db:commit(tx) |> app/db:rollback(tx) |> app/db:disconnect(conn: c)
Must contain:
Use-after-dischargeError Verification
Actual Compiler Output
error[KORU030]: Use-after-discharge: binding 'tx' was already discharged and cannot be used
--> phantom_semantic_check:13:0
❌ Compiler coordination error: Phantom semantic validation failed
error: CompilerCoordinationFailed
???:?:?: 0x10061f9d3 in _backend.RuntimeEmitter.emit (???)
???:?:?: 0x100620b63 in _backend.main (???)Flows
flow ~connect click a branch to expand · @labels scroll to their anchor
connect (url: "postgres://localhost/test")
Imported Files
// Library module: db (copy of 330_027/db.kz)
// Database operations with layered cleanup obligations
//
// Pattern: connect → query → (commit OR rollback) → disconnect
//
// Grounding: 330_027_db_transaction_pattern/db.kz verbatim
const std = @import("std");
const Connection = struct {
id: i32,
};
const Transaction = struct {
conn: *Connection,
};
~pub event connect { url: []const u8 } -> *Connection<connected!>
~proc connect|zig {
std.debug.print("Connecting to: {s}\n", .{url});
const allocator = std.heap.page_allocator;
const c = allocator.create(Connection) catch unreachable;
c.* = Connection{ .id = 1 };
return c;
}
~pub event query { conn: *Connection<connected>, sql: []const u8 } -> *Transaction<transaction!>
~proc query|zig {
std.debug.print("Query: {s}\n", .{sql});
const allocator = std.heap.page_allocator;
const t = allocator.create(Transaction) catch unreachable;
t.* = Transaction{ .conn = conn };
return t;
}
~pub event commit { tx: *Transaction<!transaction> }
~proc commit|zig {
std.debug.print("Committing transaction\n", .{});
}
~pub event rollback { tx: *Transaction<!transaction> }
~proc rollback|zig {
std.debug.print("Rolling back transaction\n", .{});
}
~pub event disconnect { conn: *Connection<!connected> }
~proc disconnect|zig {
std.debug.print("Disconnecting\n", .{});
}
Test Configuration
MUST_FAIL