Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
5 changes: 3 additions & 2 deletions docs/what-is-rivet.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,9 @@ server-side-validated before it lands.
- **Polarion / ReqIF fidelity audit.**
[docs/design/polarion-reqif-fidelity.md](design/polarion-reqif-fidelity.md).
- **Roadmap.** [docs/roadmap.md](roadmap.md).
- **Audit report.** [docs/audit-report.md](audit-report.md) — state
of doc-vs-reality after PR #171's audit.
- **Audit report.** [docs/historical/audit-report.md](historical/audit-report.md)
— archived doc-vs-reality snapshot (2026-03-09). Superseded by
[docs/research/2026-05-19-docs-audit.md](research/2026-05-19-docs-audit.md).

---

Expand Down
32 changes: 29 additions & 3 deletions rivet-core/src/doc_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,15 @@

impl DocFile {
pub fn new(rel_path: PathBuf, content: String) -> Self {
// `plans/` and `design/` are forward-looking; `historical/` is
// frozen archive (REQ-073/074). All three legitimately reference
// subcommands / artifact counts / IDs that have since changed,
// so they opt out of the existence-based invariants.
let is_design_doc = content.contains("rivet-docs-check: design-doc-aspirational-ok")
|| rel_path
.components()
.any(|c| c.as_os_str() == "plans" || c.as_os_str() == "design");
|| rel_path.components().any(|c| {
let s = c.as_os_str();
s == "plans" || s == "design" || s == "historical"
});
Self {
rel_path,
content,
Expand Down Expand Up @@ -1169,10 +1174,10 @@
// that is actually part of a longer hex run.
if let Some((head, tail)) = id.rsplit_once('-') {
if tail.len() >= 4
&& tail.chars().all(|c| c.is_ascii_hexdigit())

Check warning on line 1177 in rivet-core/src/doc_check.rs

View workflow job for this annotation

GitHub Actions / Mutation Testing (rivet-core)

Missed mutant

replace && with || in is_non_artifact_id
&& tail.chars().any(|c| c.is_ascii_alphabetic())

Check warning on line 1178 in rivet-core/src/doc_check.rs

View workflow job for this annotation

GitHub Actions / Mutation Testing (rivet-core)

Missed mutant

replace && with || in is_non_artifact_id
// at least one letter ==> not a pure decimal id
&& head.chars().all(|c| c.is_ascii_uppercase() || c == '-')

Check warning on line 1180 in rivet-core/src/doc_check.rs

View workflow job for this annotation

GitHub Actions / Mutation Testing (rivet-core)

Missed mutant

replace == with != in is_non_artifact_id
{
return true;
}
Expand Down Expand Up @@ -1223,13 +1228,13 @@

impl DocInvariant for MigrationConflict {
fn name(&self) -> &'static str {
"MigrationConflict"

Check warning on line 1231 in rivet-core/src/doc_check.rs

View workflow job for this annotation

GitHub Actions / Mutation Testing (rivet-core)

Missed mutant

replace <impl DocInvariant for MigrationConflict>::name -> &'static str with "xyzzy"

Check warning on line 1231 in rivet-core/src/doc_check.rs

View workflow job for this annotation

GitHub Actions / Mutation Testing (rivet-core)

Missed mutant

replace <impl DocInvariant for MigrationConflict>::name -> &'static str with ""
}

fn check(&self, ctx: &DocCheckContext<'_>) -> Vec<Violation> {
let mut out = Vec::new();
let root = ctx.project_root.join("artifacts");
if !root.is_dir() {

Check warning on line 1237 in rivet-core/src/doc_check.rs

View workflow job for this annotation

GitHub Actions / Mutation Testing (rivet-core)

Missed mutant

delete ! in <impl DocInvariant for MigrationConflict>::check
return out;
}
let mut files = Vec::new();
Expand All @@ -1256,7 +1261,7 @@
if let Some(k) = kind {
out.push(Violation {
file: rel.clone(),
line: idx + 1,

Check warning on line 1264 in rivet-core/src/doc_check.rs

View workflow job for this annotation

GitHub Actions / Mutation Testing (rivet-core)

Missed mutant

replace + with * in <impl DocInvariant for MigrationConflict>::check

Check warning on line 1264 in rivet-core/src/doc_check.rs

View workflow job for this annotation

GitHub Actions / Mutation Testing (rivet-core)

Missed mutant

replace + with - in <impl DocInvariant for MigrationConflict>::check
invariant: "MigrationConflict".to_string(),
claim: format!("artifact YAML contains migration conflict marker ({k})"),
reality: "run `rivet schema migrate --status` for context, then \
Expand All @@ -1282,7 +1287,7 @@
} else if p
.extension()
.and_then(|e| e.to_str())
.is_some_and(|e| e == "yaml" || e == "yml")

Check warning on line 1290 in rivet-core/src/doc_check.rs

View workflow job for this annotation

GitHub Actions / Mutation Testing (rivet-core)

Missed mutant

replace == with != in collect_artifact_yaml_files

Check warning on line 1290 in rivet-core/src/doc_check.rs

View workflow job for this annotation

GitHub Actions / Mutation Testing (rivet-core)

Missed mutant

replace || with && in collect_artifact_yaml_files
{
out.push(p);
}
Expand Down Expand Up @@ -1586,6 +1591,27 @@
assert_eq!(v[0].file, PathBuf::from("README.md"));
}

/// REQ-073/074: a file under `docs/historical/` is a frozen archive
/// snapshot and opts out of the existence-based invariants — same as
/// `plans/` and `design/` — without needing the explicit marker.
///
/// rivet: verifies REQ-074
#[test]
fn historical_dir_is_design_doc_without_marker() {
assert!(
doc("docs/historical/old-plan.md", "Run `rivet discover`.").is_design_doc,
"docs/historical/ must be exempt from existence invariants"
);
assert!(
doc("docs/plans/p.md", "x").is_design_doc,
"docs/plans/ exemption must still hold"
);
assert!(
!doc("docs/getting-started.md", "x").is_design_doc,
"a normal reference doc must NOT be auto-exempt"
);
}

#[test]
fn subcommand_references_skip_design_doc() {
let content = "<!-- rivet-docs-check: design-doc-aspirational-ok -->\n\
Expand Down
Loading