1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! The prose a builtin publishes to the model must not name kernel internals.
//!
//! `params_from_clap` copies a clap **argument**'s `///` doc into
//! `ParamSchema.description`, and the kernel ships that to the model through
//! `Kernel::tool_schemas()` — so those lines are published prose, governed at
//! full weight by `docs/style.md`. The leak is easy to reintroduce because the
//! doc comment sits in a Rust file next to code that legitimately discusses
//! clap, and nothing about writing it looks like writing documentation.
//!
//! This walks the real registry rather than grepping the source, so a leak is
//! caught wherever the text comes from: a doc comment, a hand-written
//! `ToolSchema::param` call, or a builtin that composes its schema at runtime.
//!
//! `docs/style.md`, "Do not leak the kernel" is the rule; the "Known debt"
//! section records the sweep that motivated this test.
//!
//! Coverage depends on features: the registry only holds what the build
//! enabled, so a default run does not walk `timeout`, `tokens`, or `ps`. Run
//! `cargo test -p kaish-kernel --features full --test published_prose_tests`
//! to cover every capability-gated builtin. Both were green when this landed.
//! (`--all-features` does not build — a `schemars` bound in `kaish-types`
//! fails independently of this test.)
// Test-fixture code: unwrap/expect on known-good setup is the idiom here.
#![allow(clippy::unwrap_used, clippy::expect_used)]
use kaish_kernel::{Kernel, KernelConfig};
/// Substrings that only ever appear when Rust or clap mechanism has escaped
/// into published text. Each was a real leak found while clearing the style
/// guide's punch list, so this list is evidence, not speculation.
const MECHANISM_MARKERS: &[&str] = &[
"to_argv",
"consumes=",
"args.named",
"args.positional",
"ArgAction",
"ParamSchema",
"ToolArgs",
"clap",
"Sink —",
"Sink -",
"module docs",
];
/// Every published param description, as `(tool, param, text)`. Walks
/// subcommand trees too — a leaf's params are published exactly like a root's.
fn published_descriptions() -> Vec<(String, String, String)> {
fn walk(
prefix: &str,
schema: &kaish_kernel::tools::ToolSchema,
out: &mut Vec<(String, String, String)>,
) {
let name = if prefix.is_empty() {
schema.name.clone()
} else {
format!("{prefix} {}", schema.name)
};
for param in &schema.params {
out.push((name.clone(), param.name.clone(), param.description.clone()));
}
for sub in &schema.subcommands {
walk(&name, sub, out);
}
}
let kernel = Kernel::new(KernelConfig::isolated()).expect("isolated kernel");
let mut out = Vec::new();
for schema in kernel.tool_schemas() {
walk("", &schema, &mut out);
}
out
}
#[test]
fn published_param_descriptions_name_no_kernel_internals() {
let mut leaks: Vec<String> = Vec::new();
for (tool, param, description) in published_descriptions() {
for marker in MECHANISM_MARKERS {
if description.contains(marker) {
leaks.push(format!(
"{tool} --{param}: contains {marker:?} — {description}"
));
}
}
}
assert!(
leaks.is_empty(),
"these param descriptions ship kernel mechanism to the model. Move the \
mechanism to a `//` comment and leave the `///` describing what the \
reader must predict (docs/style.md, \"Do not leak the kernel\"):\n {}",
leaks.join("\n ")
);
}
/// A published description that is empty tells the model nothing about a flag
/// it can still pass. Catching this is cheap and it is the same class of
/// omission as a leak: the reader cannot predict behavior from what shipped.
#[test]
fn every_published_param_carries_a_description() {
let missing: Vec<String> = published_descriptions()
.into_iter()
.filter(|(_, _, description)| description.trim().is_empty())
.map(|(tool, param, _)| format!("{tool} --{param}"))
.collect();
assert!(
missing.is_empty(),
"these params publish an empty description — give the clap field a `///` \
line describing what it does:\n {}",
missing.join("\n ")
);
}