○
Planned This feature is planned but not yet implemented.
bare phantom state outside declaring module must be rejected (ratified design)
Code
// Aspirational: bare phantom state referenced OUTSIDE its declaring module must
// be REJECTED (ratified design, OUTSTANDING_DESIGN_DECISIONS.md).
//
// Rule: bare `<secret>` / `<secret!>` / `<!secret>` is legal only INSIDE the
// declaring module (resolves to *this* module). Referenced from a DIFFERENT
// module it is ambiguous — the state's home cannot be inferred — and must be
// written qualified: `<app/lib/store:secret>`. The checker must reject the
// bare form with a clear error pointing the user at the qualified spelling.
//
// Today this is WRONG-GREEN: the bare `<secret>` on a user-module field
// canonicalizes to `<user>:secret` (the field's defining module) and silently
// compiles — it neither unifies with app/lib/store's secret nor errors. The
// fix (ratified design) makes bare-outside a hard error so the ambiguity is
// caught at the call site instead of producing a state that can never match.
~import std/io
~import app/lib/store
// BARE <secret> in a USER module — outside app/lib/store. Must be rejected.
~event use-secret { s: []const u8<secret> }
| used []const u8
~proc use-secret|zig {
return .{ .used = s };
}
~app/lib/store:make-secret(payload: "shh")
| secret s |> app/lib/store:reveal(s)
| plain p |> use-secret(p)
| used _ |> std/io:print.ln("ok")
Must fail at frontend compile:
Parsing or type-checking must reject the program.
Flows
flow ~make-secret click a branch to expand · @labels scroll to their anchor
make-secret (payload: "shh")
Imported Files
// A module that ISSUES a phantom-tagged scalar obligation, for the cross-module
// unification tests (330_087, 330_088, 330_089).
//
// `secret` is a compile-time taint tag: `make-secret` issues `<secret!>` (an
// obligation that the value must be `reveal`-ed before use); `reveal` consumes
// `<!secret>` and returns a plain value. This is the minimal taint-tracking
// vocabulary — a module that declares a phantom-state vocabulary carried on a
// builtin scalar (no home module of its own), which is exactly why the state
// must name its own module rather than being implied by the type.
const std = @import("std");
~pub event make-secret { payload: []const u8 }
| secret []const u8<secret!>
~proc make-secret|zig {
return .{ .secret = payload };
}
// Consume the secret obligation: discharges <secret!> -> a plain value.
~pub event reveal { s: []const u8<!secret> }
| plain []const u8
~proc reveal|zig {
return .{ .plain = s };
}
Test Configuration
Expected Error:
bare phantom state