Put the developer docs under docs/dev and index the folder for users first

docs/ had 26 developer documents flat beside the manual, and the two
audiences are very differently sized: most readers want the manual and
the gesture reference, a few want the register, the designs and the
measurements. The manual and gestures.md stay at the top; everything for
someone changing the code moves to docs/dev/, and the two documents that
name their own successors — the v0.1 milestone and the UI-refinement plan
— go to docs/dev/archive/ rather than being deleted, since both are still
cited. docs/README.md is the index, users first.

Every reference follows: code comments, Cargo manifests, the workflows,
the pre-commit hook, the bench and traceability tools (which locate the
repo root by docs/dev/requirements.md now), packaging, the Docker READMEs,
CLAUDE.md, CONTRIBUTING.md and the README. The matrix links one level
deeper and is regenerated. Links out of the moved documents into the tree
gain a level; a link checker over every Markdown file finds none broken.
This commit is contained in:
2026-09-20 16:20:15 +02:00
parent 08727cff5a
commit 6b1aac477d
137 changed files with 658 additions and 572 deletions
+8 -8
View File
@@ -1,7 +1,7 @@
//! Traceability gate and matrix generator.
//!
//! ```text
//! traces report # write docs/traceability.md
//! traces report # write docs/dev/traceability.md
//! traces json # machine-readable, to stdout
//! traces check # gate: non-zero exit on failure
//! traces gestures # write docs/gestures.md and the app's gesture table
@@ -67,7 +67,7 @@ fn main() -> Result<()> {
return run_gestures(&base, mode == "gestures-check");
}
let req_path = base.join("docs/requirements.md");
let req_path = base.join("docs/dev/requirements.md");
let markdown = std::fs::read_to_string(&req_path)
.with_context(|| format!("reading {}", req_path.display()))?;
let defined = parse_defined_requirements(&markdown);
@@ -106,7 +106,7 @@ fn main() -> Result<()> {
println!("\ntraceability gate: PASS");
}
_ => {
let out = base.join("docs/traceability.md");
let out = base.join("docs/dev/traceability.md");
let md = render(&files, &entries, &defined, &coverage);
std::fs::write(&out, md)?;
print_summary(&files, &entries, &defined, &coverage);
@@ -195,7 +195,7 @@ fn run_gestures(base: &Path, check: bool) -> Result<()> {
fn gate(files: &[PathBuf], defined: &DefinedRequirements, cov: &Coverage) -> Result<()> {
// A run that parsed nothing is misconfigured, not passing.
if defined.total() == 0 {
bail!("no requirements parsed from docs/requirements.md — misconfigured, not 0% coverage");
bail!("no requirements parsed from docs/dev/requirements.md — misconfigured, not 0% coverage");
}
if files.is_empty() {
bail!("no source files scanned — misconfigured, not 0% coverage");
@@ -325,7 +325,7 @@ fn render(
for (id, es) in &by_req {
let mut locs: Vec<String> = es
.iter()
.map(|e| format!("[`{}:{}`](../{}#L{})", e.file, e.line, e.file, e.line))
.map(|e| format!("[`{}:{}`](../../{}#L{})", e.file, e.line, e.file, e.line))
.collect();
locs.sort();
locs.dedup();
@@ -346,7 +346,7 @@ fn render(
let mut locs: Vec<String> = entries
.iter()
.filter(|e| e.requirements.contains(id))
.map(|e| format!("[`{}:{}`](../{}#L{})", e.file, e.line, e.file, e.line))
.map(|e| format!("[`{}:{}`](../../{}#L{})", e.file, e.line, e.file, e.line))
.collect();
locs.sort();
locs.dedup();
@@ -379,9 +379,9 @@ fn render(
/// The repo root, found by walking up from the executable's manifest dir.
fn repo_root() -> Result<PathBuf> {
let mut dir = Path::new(env!("CARGO_MANIFEST_DIR")).to_path_buf();
while !dir.join("docs/requirements.md").exists() {
while !dir.join("docs/dev/requirements.md").exists() {
if !dir.pop() {
bail!("could not locate repo root (no docs/requirements.md above the tool)");
bail!("could not locate repo root (no docs/dev/requirements.md above the tool)");
}
}
Ok(dir)