feat: render shared operator surface - #57
Conversation
ReviewIncremental · 1 open
SummaryWhat these patches actually doRender pipeline lives in the binary's test tree, not in the build. Golden-file semantics with an accept switch. Version coupling is now enforced. Test coverage moved rather than shrunk. Content changes in the rendered documentsBoth documents pick up a generated Two behavioral notes on the generated table: the One paragraph was dropped from Boundary and packaging
The templates live under Files
Open
History
|
| fn render_template(relative: &str, context: &Value) -> String { | ||
| let source = crate_file(relative); | ||
| let environment = ctl_core::surface::environment() | ||
| .unwrap_or_else(|error| panic!("operator environment: {error}")); | ||
| environment | ||
| .template_from_named_str(relative, &source) | ||
| .unwrap_or_else(|error| panic!("parse {relative}: {error}")) | ||
| .render(context) | ||
| .unwrap_or_else(|error| panic!("render {relative}: {error}")) | ||
| } |
There was a problem hiding this comment.
Trailing-newline mismatch: render() output is byte-compared against the committed file, but MiniJinja strips the template's final newline by default (keep_trailing_newline is false) while skills/qctl/SKILL.md and src/instructions.md end with a newline. Both new tests fail on a clean checkout, and regenerating with UPDATE_OPERATOR_DOCS=1 writes a src/instructions.md without a trailing newline, breaking instructions_prints_the_installed_contract_exactly (tests/cli.rs:526-529); normalize the trailing newline before comparing or writing, or enable keep_trailing_newline on the environment.
| fn render_template(relative: &str, context: &Value) -> String { | |
| let source = crate_file(relative); | |
| let environment = ctl_core::surface::environment() | |
| .unwrap_or_else(|error| panic!("operator environment: {error}")); | |
| environment | |
| .template_from_named_str(relative, &source) | |
| .unwrap_or_else(|error| panic!("parse {relative}: {error}")) | |
| .render(context) | |
| .unwrap_or_else(|error| panic!("render {relative}: {error}")) | |
| } | |
| .render(context) | |
| .map(|rendered| format!("{}\n", rendered.trim_end_matches('\n'))) | |
| .unwrap_or_else(|error| panic!("render {relative}: {error}")) |
Why
Qctl still copied mounted invocation/no-
--policy across its skill and installed instructions, and its only operator-doc test checked one version line. Command prose could drift from Clap without failing CI.What
surfaceonly in test builds..ctl/operator/.--policy, and visible command inventories from the real Clap graph.-f/--filecontract.Evidence
mise run verify: all unit, integration, doc, operator-render, rustfmt, and denied-warning Clippy checks pass.mise run build: optimized release binary compiles without the test-only Surface/MiniJinja feature.cargo package --allow-dirty --locked: packaged crate compiles from its tarball.cargo tree --edges normal -i minijinja: the release dependency graph contains no MiniJinja.