// mooncassette/format_lock —— 生成 FORMAT.lock:0.10.0 的格式快照。
//
// 这是「格式冻结」机制的执行端:用当前写入端构造一组覆盖格式各个角落的
// 见证 cassette,把它们的规范文本、缩进文本与摘要打印到标准输出。CI 会把
// 这份输出与仓库里的 FORMAT.lock 逐字节比对,于是任何解析 / 序列化行为的
// 改动都会立刻现形。
//
// 生成方式(在仓库根目录):
// moon run examples/format_lock --target js
//
// 程序直接写出 FORMAT.lock(经由 `x/fs`,逐字节写 UTF-8、`\n` 行尾),
// 而不是打印到标准输出再由 shell 重定向 —— shell 的编码与行尾策略在
// Windows / Linux 上并不一致,会让「同一份源码」产出两份字节不同的快照。
//
// 格式是被承诺过的契约:改动它必须显式重新生成本文件,并在评审里说明缘由
// 以及对读端兼容性的影响。
///|
/// 见证样例使用的固定 generator。
///
/// 刻意不用 `@core.generator_id`:否则每发一版都会改动本文件,把「格式变了」
/// 与「版本号变了」搅在一起。版本号与 generator 的一致性由 CI 的版本校验
/// 步骤单独负责。
let witness_generator : String = "mooncassette/format-lock"
///|
fn meta_of(name : String, recorded_at? : String) -> @core.CassetteMeta {
{ name, generator: witness_generator, recorded_at }
}
///|
fn json_obj(entries : Array[(String, Json)]) -> Json {
let map : Map[String, Json] = Map([])
for entry in entries {
map.set(entry.0, entry.1)
}
Json::object(map)
}
///|
fn json_arr(items : Array[Json]) -> Json {
Json::array(items)
}
///|
fn json_str(text : String) -> Json {
Json::string(text)
}
///|
/// 构造一个「看起来像整数」的 JSON 数字,避免写出 `42.0` 这类噪声。
fn json_int(value : Int) -> Json {
Json::number(value.to_double(), repr=value.to_string())
}
// ---------------------------------------------------------------------------
// 见证样例
// ---------------------------------------------------------------------------
///|
/// 见证 1:版本 1 的非流式形状(0.3.0 及更早的写法)。
///
/// 覆盖:缺省的 `usage` / `stream` 被省略、旧版本声明原样写出(不擅自升版)。
fn witness_v1() -> @core.Cassette {
let request : @core.Request = {
provider: "openai",
model: "gpt-4o",
body: json_obj([
(
"messages",
json_arr([
json_obj([("role", json_str("user")), ("content", json_str("ping"))]),
]),
),
]),
}
let response : @core.Response = {
status: 200,
body: json_obj([
(
"choices",
json_arr([
json_obj([
(
"message",
json_obj([
("role", json_str("assistant")),
("content", json_str("pong")),
]),
),
]),
]),
),
]),
usage: None,
stream: None,
}
{
version: 1,
meta: meta_of("witness-v1"),
interactions: [{ request, response }],
}
}
///|
/// 见证 2:版本 2 + `usage` + `recorded_at`。
///
/// 覆盖:`usage` 对象、整数写法(不出现 `12.0`)、可选的 `recorded_at`。
fn witness_usage() -> @core.Cassette {
let request : @core.Request = {
provider: "anthropic",
model: "claude-3-5-sonnet",
body: json_obj([
("max_tokens", json_int(64)),
(
"messages",
json_arr([
json_obj([("role", json_str("user")), ("content", json_str("你好"))]),
]),
),
]),
}
let response : @core.Response = {
status: 200,
body: json_obj([
(
"content",
json_arr([
json_obj([
("type", json_str("text")),
("text", json_str("你好!我是月兔助手。")),
]),
]),
),
]),
usage: Some(@core.Usage::new(11, 7)),
stream: None,
}
{
version: 2,
meta: meta_of("witness-usage", recorded_at="2026-01-01T00:00:00Z"),
interactions: [{ request, response }],
}
}
///|
/// 见证 3:流式响应(版本 2 引入的 `stream` 帧序列)。
///
/// 覆盖:带 / 不带 `event` 的帧、`[DONE]` 哨兵、被转义后嵌入的帧文本。
fn witness_stream() -> @core.Cassette {
let request : @core.Request = {
provider: "openai",
model: "gpt-4o",
body: json_obj([
("stream", Json::boolean(true)),
(
"messages",
json_arr([
json_obj([
("role", json_str("user")),
("content", json_str("stream please")),
]),
]),
),
]),
}
let frames : Array[@core.StreamFrame] = [
@core.StreamFrame::new(
"{\"choices\":[{\"delta\":{\"content\":\"hi\"},\"index\":0}]}",
event="message",
),
@core.StreamFrame::new("[DONE]"),
]
let response : @core.Response = {
status: 200,
body: json_obj([("choices", json_arr([]))]),
usage: Some(@core.Usage::new(3, 2)),
stream: Some(frames),
}
{
version: 2,
meta: meta_of("witness-stream"),
interactions: [{ request, response }],
}
}
///|
/// 见证 4:二进制载荷信封。
///
/// 覆盖:`payload` + `content_encoding` 的规范形状,含需要补齐填充的字节
/// (`café` 为 5 字节)与空字节串。
fn witness_envelope() -> @core.Cassette {
let padded = @payload.pack_bytes(@utf8.encode("café"))
let empty = @payload.pack_bytes(Bytes::new(0))
let request : @core.Request = {
provider: "openai",
model: "gpt-4o",
body: json_obj([("input", padded)]),
}
let response : @core.Response = {
status: 200,
body: json_obj([("output", empty)]),
usage: None,
stream: None,
}
{
version: 2,
meta: meta_of("witness-envelope"),
interactions: [{ request, response }],
}
}
///|
/// 见证 5:文本转义与数字写法。
///
/// 覆盖:引号、反斜杠、换行、制表、控制字符、非 ASCII、补充平面字符(emoji)、
/// BOM,以及浮点 / 负整数 / 零 / 千级整数。
fn witness_escapes() -> @core.Cassette {
let tricky = "q:\" bs:\\ nl:\n tab:\t ctrl:\u{01} 中文 😀 \u{FEFF}bom"
let request : @core.Request = {
provider: "openai",
model: "gpt-4o",
body: json_obj([("text", json_str(tricky))]),
}
let response : @core.Response = {
status: 200,
body: json_obj([
("text", json_str(tricky)),
("float", Json::number(3.5)),
("negative", json_int(-7)),
("zero", json_int(0)),
("thousand", json_int(1000)),
]),
usage: None,
stream: None,
}
{
version: 2,
meta: meta_of("witness-escapes"),
interactions: [{ request, response }],
}
}
// ---------------------------------------------------------------------------
// 输出
// ---------------------------------------------------------------------------
///|
fn header_lines() -> Array[String] {
[
"# mooncassette — FORMAT.lock",
"#",
"# 这是 mooncassette 的格式快照(0.10.0 起冻结),由当前写入端生成。CI 会重新",
"# 生成并与本文件逐字节比对,因此任何解析 / 序列化行为的改动都会在这里现形。",
"#",
"# 生成方式(在仓库根目录):",
"# moon run examples/format_lock --target js",
"#",
"# 格式是被承诺过的契约:改它必须显式重新生成本文件,并在评审里说明缘由",
"# 以及对读端兼容性的影响。",
"#",
"# 见证样例刻意使用固定 generator(" +
witness_generator +
"),使本文件只随格式变化,",
"# 不随发布版本号变化。",
"",
"## constants",
"format_tag=" + @codec.format_tag,
"cassette_format_version=" + @core.cassette_format_version.to_string(),
"stream_format_version=" + @core.stream_format_version.to_string(),
"content_encoding=" + @payload.encoding_base64,
"payload_key=" + @payload.payload_key,
"content_encoding_key=" + @payload.content_encoding_key,
"min_payload_bytes=" + @payload.min_payload_bytes.to_string(),
"min_payload_chars=" + @payload.min_payload_chars.to_string(),
"fingerprint_algorithm=" + @fingerprint.algorithm,
]
}
///|
/// 见证样例清单。集中在一处,便于审阅「快照到底覆盖了什么」。
fn witnesses() -> Array[(String, @core.Cassette)] {
[
("v1-nonstream", witness_v1()),
("v2-usage-recorded", witness_usage()),
("v2-stream", witness_stream()),
("v2-envelope", witness_envelope()),
("v2-escapes", witness_escapes()),
]
}
///|
/// 自校验:某种文本必须能原样解回同一个 cassette。
///
/// 生成器自己先证明「写出去的东西读得回来」,这份快照才有资格被当作契约。
fn check_text(
name : String,
label : String,
text : String,
cassette : @core.Cassette,
) -> Bool {
try {
let restored = @codec.decode(text)
if restored == cassette {
true
} else {
println(
"format_lock: 见证 " +
name +
" 的 " +
label +
" 文本往返后不等价",
)
println(" before: " + @codec.encode(cassette, indent=0))
println(" after : " + @codec.encode(restored, indent=0))
false
}
} catch {
error => {
println(
"format_lock: 见证 " +
name +
" 的 " +
label +
" 文本解码报错:" +
error.to_string(),
)
false
}
}
}
///|
/// 自校验:规范文本与缩进文本都必须能原样解回同一个 cassette。
fn check_roundtrip(name : String, cassette : @core.Cassette) -> Unit {
let canonical = @codec.encode(cassette, indent=0)
let pretty = @codec.encode(cassette, indent=2)
let canonical_ok = check_text(name, "canonical", canonical, cassette)
let pretty_ok = check_text(name, "pretty", pretty, cassette)
if !canonical_ok || !pretty_ok {
panic()
}
}
///|
/// 生成 FORMAT.lock 的完整文本。
///
/// 每行都以 `\n` 结尾(不依赖平台行尾),因此这份文件在任何系统上都逐字节
/// 一致。
fn lock_text() -> String {
let lines : Array[String] = header_lines()
for entry in witnesses() {
let name = entry.0
let cassette = entry.1
check_roundtrip(name, cassette)
lines.push("")
lines.push("## witness: " + name)
for item in cassette.interactions {
lines.push("fingerprint=" + @fingerprint.fingerprint(item.request))
lines.push("integrity=" + @fingerprint.integrity_digest(item))
}
lines.push("--- canonical ---")
lines.push(@codec.encode(cassette, indent=0))
lines.push("--- pretty ---")
lines.push(@codec.encode(cassette, indent=2))
}
let mut text : String = ""
for line in lines {
text = text + line + "\n"
}
text
}
///|
/// 写出 FORMAT.lock(路径相对当前工作目录,请在仓库根目录运行)。
fn main {
let text = lock_text()
@fs.write_string_to_file("FORMAT.lock", text) catch {
@fs.IOError(message) => {
println("format_lock: 写 FORMAT.lock 失败:" + message)
panic()
}
}
println(
"format_lock: 已写出 FORMAT.lock,共 " +
witnesses().length().to_string() +
" 个见证样例",
)
}