tools-manual: render a tool's manual from its own clap::Command tree, cargo metadata, the tier registry, and operator-authored rows (sections, examples) into one deterministic markdown export; `check` diffs the export and re-runs every example as a bounded probe, so a manual cannot describe a flag that does not exist, an example that does not run, or a count that drifted (sprint 4.49, ADR 0045).
| Tier | tools |
| Role | tooling |
| Path | crates/tools/manual |
| Edition | 2021 |
| Targets | tools-manual, tools_manual, cli, golden, probe, wiring |
| Public items | 65 across 10 modules |
| Tests | 37 |
What it is for
tools-manual — the manual is rendered from the command tree, and its examples are probes (sprint 4.49; ADR 0045: documents are renderings).
Three inputs, all real: the tool's own clap::Command tree (introspect), cargo metadata and the tier registry (model::ToolMeta), and operator-authored rows — sections and example runs (model::ManualSources). One pure renderer (render::render_manual) turns them into markdown in the ratified nine-section skeleton (skeleton::ManualSkeleton::ratified), byte for byte the same for the same inputs. A required operator section with no row renders as a missing_slot line; nothing is ever invented to fill a heading. probe re-runs examples as bounded subprocesses; check compares a fresh render with the export in the tree.
Reading rows and walking cargo output are the binary's concern.
Capabilities
ExportOutcome
The export check (sprint 4.49 AC5): a fresh render against the file in the
| Item |
|---|
pub enum ExportOutcome |
fn check_export(rendered : & str, on_disk : Option <& str>) -> ExportOutcome |
cli (other)
The tools-manual command tree, exposed from the library so the manual of
| Item |
|---|
fn tools_manual_command() -> clap::Command |
Cmd
The tools-manual command tree, exposed from the library so the manual of
| Item |
|---|
pub enum Cmd |
ExampleCmd
The tools-manual command tree, exposed from the library so the manual of
| Item |
|---|
pub enum ExampleCmd |
ManualCli
The tools-manual command tree, exposed from the library so the manual of
| Item |
|---|
pub struct ManualCli |
introspect (other)
clap::Command → CommandDoc: the command specification, read from the
| Item |
|---|
pub const MAX_COMMAND_DEPTH: usize |
pub const MAX_COMMAND_WIDTH: usize |
fn introspect(cmd : & Command) -> Result <CommandDoc, IntrospectError> |
ArgDoc
clap::Command → CommandDoc: the command specification, read from the
| Item |
|---|
pub struct ArgDoc |
CommandDoc
clap::Command → CommandDoc: the command specification, read from the
| Item |
|---|
pub struct CommandDoc |
IntrospectError
clap::Command → CommandDoc: the command specification, read from the
| Item |
|---|
pub enum IntrospectError |
meta (other)
What cargo and the layer registry say about a tool (sprint 4.49 U4).
| Item |
|---|
fn tier_for(layers_toml : & str, package : & str) -> Option <String> |
fn tool_meta(meta : & WorkspaceMeta, layers_toml : & str, package : & str,) -> Result <ToolMeta, MetaError> |
MetaError
What cargo and the layer registry say about a tool (sprint 4.49 U4).
| Item |
|---|
pub enum MetaError |
PackageMeta
What cargo and the layer registry say about a tool (sprint 4.49 U4).
| Item |
|---|
pub struct PackageMeta |
WorkspaceMeta
What cargo and the layer registry say about a tool (sprint 4.49 U4).
| Item |
|---|
pub struct WorkspaceMeta |
WorkspaceMeta :: fn from_cargo_json(json : & str) -> Result <Self, MetaError> |
WorkspaceMeta :: fn package(& self, name : & str) -> Result <& PackageMeta, MetaError> |
WorkspaceMeta :: fn bin_artifacts(& self, profile : & str) -> Vec <(String, PathBuf)> |
Example
The operator-authored half of a manual: what no program can derive.
| Item |
|---|
pub struct Example |
ManualSources
The operator-authored half of a manual: what no program can derive.
| Item |
|---|
pub struct ManualSources |
OperatorSection
The operator-authored half of a manual: what no program can derive.
| Item |
|---|
pub struct OperatorSection |
ToolMeta
The operator-authored half of a manual: what no program can derive.
| Item |
|---|
pub struct ToolMeta |
paths (other)
Where a tool's export and rows live (sprint 4.49 U4), and the one place a
| Item |
|---|
pub const MAX_TOOL_NAME_BYTES: usize |
pub const MANUALS_DIR: & str |
pub const ROWS_DIR: & str |
PathRefusal
Where a tool's export and rows live (sprint 4.49 U4), and the one place a
| Item |
|---|
pub enum PathRefusal |
fn validate_tool_name(name : & str) -> Result <& str, PathRefusal> |
fn export_path(repo_root : & Path, tool : & str) -> Result <PathBuf, PathRefusal> |
fn rows_path(repo_root : & Path, tool : & str) -> Result <PathBuf, PathRefusal> |
probe (other)
Examples are probes (sprint 4.49 AC4). An example row is the record of a
| Item |
|---|
pub const SCRATCH_TOKEN: & str |
pub const NORMALIZE_RULE_VERSION: u32 |
pub const PREVIEW_BYTES: usize |
pub const EXECUTION_ENVELOPE: & (& str, & str) |
fn normalize_output(bytes : & u8, scratch : & Path) -> Vec <u8> |
fn recording_decision(first : & RunCapture, second : & RunCapture) -> Result <(), RecordingRefusal> |
async fn run_example(example : & Example, allowlist : & ArtifactAllowlist, scratch : & Path, limits : ProbeLimits,) -> ExampleOutcome |
async fn record_example(id : & str, argv : & & str, allowlist : & ArtifactAllowlist, scratch : & Path, limits : ProbeLimits, recorded_by : & str,) -> Result <Example, RecordingRefusal> |
AllowlistError
Examples are probes (sprint 4.49 AC4). An example row is the record of a
| Item |
|---|
pub enum AllowlistError |
ArtifactAllowlist
Examples are probes (sprint 4.49 AC4). An example row is the record of a
| Item |
|---|
pub struct ArtifactAllowlist |
ArtifactAllowlist :: fn from_bins <I, S>(target_dir : & Path, bins : I) -> Result <Self, AllowlistError> where I : IntoIterator <Item =(S, PathBuf)>, S : Into <String>, |
ArtifactAllowlist :: fn resolve_bin(& self, name : & str) -> Result <PathBuf, AllowlistError> |
ExampleOutcome
Examples are probes (sprint 4.49 AC4). An example row is the record of a
| Item |
|---|
pub enum ExampleOutcome |
ProbeLimits
Examples are probes (sprint 4.49 AC4). An example row is the record of a
| Item |
|---|
pub struct ProbeLimits |
ProbeLimits :: fn default() -> Self |
RecordingRefusal
Examples are probes (sprint 4.49 AC4). An example row is the record of a
| Item |
|---|
pub enum RecordingRefusal |
RunCapture
Examples are probes (sprint 4.49 AC4). An example row is the record of a
| Item |
|---|
pub struct RunCapture |
render (other)
One deterministic renderer: CommandDoc + ManualSources + ManualSkeleton
| Item |
|---|
pub const CELL_RULE_VERSION: u32 |
fn first_differing_slot(a : & str, b : & str) -> Option <String> |
fn is_level2_heading(line : & str) -> bool |
fn cell(s : & str) -> String |
RenderRefusal
One deterministic renderer: CommandDoc + ManualSources + ManualSkeleton
| Item |
|---|
pub enum RenderRefusal |
fn render_manual(doc : & CommandDoc, sources : & ManualSources, skeleton : & ManualSkeleton,) -> Result <String, RenderRefusal> |
rows (other)
The interim row store (sprint 4.49 U4): one TSV per tool under
| Item |
|---|
pub const ROWS_ESCAPE_VERSION: u32 |
fn escape_cell(s : & str) -> String |
fn parse_rows(tsv : & str) -> Result <ManualRows, RowsError> |
ManualRows
The interim row store (sprint 4.49 U4): one TSV per tool under
| Item |
|---|
pub struct ManualRows |
fn render_rows(rows : & ManualRows) -> String |
RowsError
The interim row store (sprint 4.49 U4): one TSV per tool under
| Item |
|---|
pub enum RowsError |
fn unescape_cell(s : & str, line : usize) -> Result <String, RowsError> |
ManualSkeleton
The Manual skeleton as ratified in sprint 4.49's round 1 (AC3). Its row in
| Item |
|---|
pub struct ManualSkeleton |
ManualSkeleton :: fn ratified() -> Self |
ManualSkeleton :: fn section_names(& self) -> Vec <& 'static str> |
SkeletonSection
The Manual skeleton as ratified in sprint 4.49's round 1 (AC3). Its row in
| Item |
|---|
pub struct SkeletonSection |
How to use it
No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.
Module structure
tools_manual
checkcliintrospectmetamodelpathsproberenderrowsskeleton
flowchart TD n_tools_manual["tools_manual"] n_tools_manual --> n_check["check"] n_tools_manual --> n_cli["cli"] n_tools_manual --> n_introspect["introspect"] n_tools_manual --> n_meta["meta"] n_tools_manual --> n_model["model"] n_tools_manual --> n_paths["paths"] n_tools_manual --> n_probe["probe"] n_tools_manual --> n_render["render"] n_tools_manual --> n_rows["rows"] n_tools_manual --> n_skeleton["skeleton"]
Public surface
`check`
| Item | What it is |
|---|---|
pub enum ExportOutcome | Outcome of comparing a fresh render with the export on disk. |
fn check_export(rendered : & str, on_disk : Option <& str>) -> ExportOutcome | Compare rendered with the export's bytes (None when the file does not exist) |
`cli`
| Item | What it is |
|---|---|
pub struct ManualCli | Render a tool's manual from its own command tree and operator rows; check the export and re-run its examples. |
pub enum Cmd | Top-level subcommands. |
pub enum ExampleCmd | Example row actions. |
fn tools_manual_command() -> clap::Command | The command tree as declared |
`introspect`
| Item | What it is |
|---|---|
pub const MAX_COMMAND_DEPTH: usize | Maximum nesting of subcommands, root inclusive. |
pub const MAX_COMMAND_WIDTH: usize | Maximum visible arguments (positional + options) on any one command. |
pub struct ArgDoc | One argument as the manual describes it. |
pub struct CommandDoc | One command node, with its visible subcommands in definition order. |
pub enum IntrospectError | Why a tree was refused. |
fn introspect(cmd : & Command) -> Result <CommandDoc, IntrospectError> | Read a command tree as DECLARED |
`meta`
| Item | What it is |
|---|---|
pub struct PackageMeta | One workspace package as the manual needs it. |
pub struct WorkspaceMeta | The workspace as cargo reports it. |
pub enum MetaError | Why metadata or the registry could not answer. |
WorkspaceMeta :: fn from_cargo_json(json : & str) -> Result <Self, MetaError> | Parse cargo metadata --format-version 1 output |
WorkspaceMeta :: fn package(& self, name : & str) -> Result <& PackageMeta, MetaError> | The named package |
WorkspaceMeta :: fn bin_artifacts(& self, profile : & str) -> Vec <(String, PathBuf)> | (bin name, artifact path) pairs for every [bin] in the workspace, under <target_directory>/<profile>/. |
fn tier_for(layers_toml : & str, package : & str) -> Option <String> | The tier layers.toml registers package under, read from its crate_layer lines. |
fn tool_meta(meta : & WorkspaceMeta, layers_toml : & str, package : & str,) -> Result <ToolMeta, MetaError> | Assemble the manual's ToolMeta for one package |
`model`
| Item | What it is |
|---|---|
pub struct ToolMeta | What cargo metadata and the tier registry say about the tool. |
pub struct OperatorSection | One operator-written section body, keyed by the skeleton section it fills. |
pub struct Example | One recorded example run |
pub struct ManualSources | Everything the renderer needs besides the command tree. |
`paths`
| Item | What it is |
|---|---|
pub const MAX_TOOL_NAME_BYTES: usize | Longest tool name accepted. |
pub const MANUALS_DIR: & str | Exports: docs/manuals/<tool>.md. |
pub const ROWS_DIR: & str | Interim rows: docs/reference/manual-sections/<tool>.tsv. |
pub enum PathRefusal | Why a name or path was refused. |
fn validate_tool_name(name : & str) -> Result <& str, PathRefusal> | Validate a tool name |
fn export_path(repo_root : & Path, tool : & str) -> Result <PathBuf, PathRefusal> | <root>/docs/manuals/<tool>.md, proven under <root> |
fn rows_path(repo_root : & Path, tool : & str) -> Result <PathBuf, PathRefusal> | <root>/docs/reference/manual-sections/<tool>.tsv, proven under <root> |
`probe`
| Item | What it is |
|---|---|
pub const SCRATCH_TOKEN: & str | The token the scratch working directory is rewritten to before hashing. |
pub const NORMALIZE_RULE_VERSION: u32 | Version of normalize_output; bump when its rules change. |
pub const PREVIEW_BYTES: usize | Bytes of normalized output shown when a hash differs. |
pub const EXECUTION_ENVELOPE: & (& str, & str) | The declared execution envelope: every run gets exactly these variables. |
pub struct ProbeLimits | Wall-clock and output caps for one example run. |
ProbeLimits :: fn default() -> Self | — |
pub enum AllowlistError | Why a name or artifact is not runnable. |
pub struct ArtifactAllowlist | Binary name → canonical artifact path, every path proven under the target directory at construction. |
ArtifactAllowlist :: fn from_bins <I, S>(target_dir : & Path, bins : I) -> Result <Self, AllowlistError> where I : IntoIterator <Item =(S, PathBuf)>, S : Into <String>, | Build from (bin name, artifact path) pairs (cargo's reported targets); a path that resolves outside target_dir refuses the whole list |
ArtifactAllowlist :: fn resolve_bin(& self, name : & str) -> Result <PathBuf, AllowlistError> | Resolve a binary NAME to its artifact |
fn normalize_output(bytes : & u8, scratch : & Path) -> Vec <u8> | Exactly two rules (NORMALIZE_RULE_VERSION): CRLF → LF, and the scratch directory's path (as bytes, so a non-UTF-8 path still matches) → SCRATCH_TOKEN |
pub struct RunCapture | What one run produced, after normalization and hashing. |
pub enum RecordingRefusal | Why a recording was refused. |
fn recording_decision(first : & RunCapture, second : & RunCapture) -> Result <(), RecordingRefusal> | The double-run rule: two captures must agree on every field |
pub enum ExampleOutcome | Outcome of re-running one example. |
async fn run_example(example : & Example, allowlist : & ArtifactAllowlist, scratch : & Path, limits : ProbeLimits,) -> ExampleOutcome | Re-run one example under the envelope and compare it with its recording. |
async fn record_example(id : & str, argv : & & str, allowlist : & ArtifactAllowlist, scratch : & Path, limits : ProbeLimits, recorded_by : & str,) -> Result <Example, RecordingRefusal> | Run an example twice and, when the runs agree, return the row to record |
`render`
| Item | What it is |
|---|---|
pub const CELL_RULE_VERSION: u32 | Version of the cell-escaping rule; bump when cell changes. |
pub enum RenderRefusal | Why a render was refused |
fn render_manual(doc : & CommandDoc, sources : & ManualSources, skeleton : & ManualSkeleton,) -> Result <String, RenderRefusal> | Render the manual |
fn first_differing_slot(a : & str, b : & str) -> Option <String> | Name the first level-2 section whose text differs between two renderings, or None when the texts are equal |
fn is_level2_heading(line : & str) -> bool | CommonMark ATX level-2 heading: up to three leading spaces, ##, then a space, a tab, or the end of the line |
fn cell(s : & str) -> String | The one cell-escaping rule (CELL_RULE_VERSION): `\ |
`rows`
| Item | What it is |
|---|---|
pub const ROWS_ESCAPE_VERSION: u32 | Version of the cell-escaping grammar; bump when it changes. |
pub struct ManualRows | The rows one tool's TSV holds. |
pub enum RowsError | Why a TSV was refused. |
fn escape_cell(s : & str) -> String | Escape one cell. |
fn unescape_cell(s : & str, line : usize) -> Result <String, RowsError> | Unescape one cell |
fn parse_rows(tsv : & str) -> Result <ManualRows, RowsError> | Parse a tool's TSV |
fn render_rows(rows : & ManualRows) -> String | Render rows in canonical order, with the grammar comment on top. |
`skeleton`
| Item | What it is |
|---|---|
pub struct SkeletonSection | One skeleton section. |
pub struct ManualSkeleton | The ordered section set of the Manual document kind. |
ManualSkeleton :: fn ratified() -> Self | The Manual kind as ratified in the sprint 4.49 round-1 redline: options added as the derived section for flags; refusals and see also are operator rows. |
ManualSkeleton :: fn section_names(& self) -> Vec <& 'static str> | Section names in order, for the containment check. |
Re-exports. Exported here, defined elsewhere.
| Export | Defined in |
|---|---|
{Example,ManualSources,OperatorSection,ToolMeta} | model::{Example,ManualSources,OperatorSection,ToolMeta} |
{ManualSkeleton,SkeletonSection} | skeleton::{ManualSkeleton,SkeletonSection} |
{cell,first_differing_slot,is_level2_heading,render_manual,RenderRefusal,CELL_RULE_VERSION,} | render::{cell,first_differing_slot,is_level2_heading,render_manual,RenderRefusal,CELL_RULE_VERSION,} |
{check_export,ExportOutcome} | check::{check_export,ExportOutcome} |
{introspect,ArgDoc,CommandDoc,IntrospectError,MAX_COMMAND_DEPTH,MAX_COMMAND_WIDTH,} | introspect::{introspect,ArgDoc,CommandDoc,IntrospectError,MAX_COMMAND_DEPTH,MAX_COMMAND_WIDTH,} |
Boundary
Reaches into foundation.
Shares tier tools with 84 other crates: tools-advisory-reach, tools-archive-guard, tools-artifact-scaffold, tools-ask-ai-core, tools-ask-ais, tools-ask-gemini, tools-book, tools-book-report, … (84 total).
_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._
Where it sits
| Tier (ontology) | tools |
| Architectural role (taxonomy) | tooling |
| Location | crates/tools/manual |
| Vocabulary in force (lexicon) | current |
Tier flow. Which tiers this crate's own edges cross.
flowchart LR n_tools["tools"] --> n_foundation["foundation"]
Dependencies
Runtime, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `foundation-audit-log` | foundation | no | always |
| `foundation-bounded-io` | foundation | no | always |
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
chrono | ^0.4 | serde | no | always |
clap | ^4 | derive, env, string | no | always |
serde | ^1 | derive, derive | no | always |
serde_json | ^1 | — | no | always |
thiserror | ^2 | — | no | always |
tokio | ^1 | full | no | always |
Development, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `tools-cli-conformance` | tools | no | always |
Build. None.
Depended on by. Nothing in this workspace.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR SELF["tools-manual"] SELF -->|development| n_tools_cli_conformance["tools-cli-conformance"] SELF -->|runtime| n_foundation_audit_log["foundation-audit-log"] SELF -->|runtime| n_foundation_bounded_io["foundation-bounded-io"] classDef self fill:#1f883d,stroke:#1f883d,color:#fff; class SELF self;
Feature flags
No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.
Targets
| Kind | Name | Source |
|---|---|---|
| bin | tools-manual | `src/main.rs` |
| lib | tools_manual | `src/lib.rs` |
| test | cli | `tests/cli.rs` |
| test | golden | `tests/golden.rs` |
| test | probe | `tests/probe.rs` |
| test | wiring | `tests/wiring.rs` |
Error model
| Error type | Named by |
|---|---|
AllowlistError | declared, no public signature returns it |
IntrospectError | introspect |
MetaError | tool_meta |
RowsError | parse_rows, unescape_cell |
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | yes |
| async runtime | yes |
| database access | none detected |
| network I/O | none detected |
| unsafe code | none detected |
| environment variables | none detected |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.
Related capabilities
No workspace crate depends on this one.
Verification
| Kind | Count |
|---|---|
| Unit tests | 1 |
| Integration tests | 36 |
| Examples | 0 |
| Doctests | 0 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
check | 2 | 0 | 0 |
cli | 4 | 0 | 0 |
introspect | 6 | 0 | 0 |
meta | 5 | 0 | 0 |
model | 4 | 0 | 0 |
paths | 7 | 0 | 0 |
probe | 14 | 0 | 0 |
render | 6 | 0 | 0 |
rows | 7 | 0 | 0 |
skeleton | 2 | 0 | 0 |
What the tests establish, by name:
missing_required_rows_refuse_write_and_count_as_findings—tests/cli.rsrecord_render_write_check_then_hand_edit_fails—tests/cli.rsunknown_tool_and_bad_name_are_refused—tests/cli.rsa_flag_renders_no_possible_values—tests/golden.rsabsent_optional_operator_section_renders_no_rows—tests/golden.rsabsent_required_operator_section_renders_missing_slot_line—tests/golden.rscommand_wider_than_max_width_is_refused_by_name—tests/golden.rsfirst_differing_slot_names_the_preamble_and_ignores_fenced_headings—tests/golden.rsglobal_declared_on_a_subcommand_is_listed_under_that_subcommand—tests/golden.rsgolden_render_matches_fixture_byte_for_byte—tests/golden.rshidden_subcommand_is_dropped_with_its_children—tests/golden.rslast_and_variadic_positionals_render_as_clap_accepts_them—tests/golden.rslevel_two_headings_are_the_skeleton_in_order—tests/golden.rsmutated_help_changes_bytes_and_names_the_options_slot—tests/golden.rsoperator_body_with_a_level_two_heading_is_refused—tests/golden.rspipes_and_newlines_in_help_are_escaped_into_one_table_cell—tests/golden.rsreordered_root_arguments_change_bytes_and_name_the_options_slot—tests/golden.rsshuffled_rows_render_identical_bytes—tests/golden.rssubcommands_render_in_definition_order—tests/golden.rstree_deeper_than_max_depth_is_refused_by_name—tests/golden.rsallowlist_resolves_a_named_bin_and_refuses_the_rest—tests/probe.rscheck_export_names_absence_match_and_drift—tests/probe.rsheading_in_long_about_or_description_is_refused—tests/probe.rslevel_two_heading_predicate_follows_commonmark_atx—tests/probe.rsnon_zero_expectation_is_refused_before_spawn—tests/probe.rsnormalize_applies_exactly_the_two_rules—tests/probe.rsrecorded_help_example_matches_on_rerun—tests/probe.rsrecording_decision_refuses_two_runs_that_disagree—tests/probe.rsunlisted_binary_and_non_zero_recording_are_refused—tests/probe.rswrong_hash_and_wrong_exit_are_named_failures—tests/probe.rs- _… 7 more_
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 64 | 65 |
Public modules with a //! block | 10 | 10 |
pie showData
title Public items with rustdoc
"Documented" : 64
"No rustdoc detected" : 1
Metrics
| Metric | Value |
|---|---|
| Rust source files | 12 |
| Source lines | 2082 |
| Code lines | 1606 |
| Public API items | 65 |
| Public modules | 10 |
| Tests | 37 |
| Examples | 0 |
| Cargo features | 0 |
| Direct runtime dependencies | 8 |
| Workspace reverse dependencies | 0 |
pie showData
title Public API by kind
"constant" : 11
"enum" : 11
"function" : 20
"method" : 8
"struct" : 15
pie showData
title Rust source composition
"Code" : 1606
"Blank or comment" : 476
Generation
Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.