Umbrella from the inconsistency audit, claim-vs-code lens. Headline instance filed separately: #952 (sql read-only claim + --qualification-mode scope).
Note rivet docs check passes (64 files, 0 violations) — none of these gaps are machine-gated, which is itself the pattern.
Verification status: agent-reported with claim file:line + code file:line + an empirical check for each. I re-ran the sql and --qualification-mode ones myself (#952); the rest are recorded as reported.
1. link-types: source-types / target-types are documented as restrictions and never enforced
schemas/common.yaml:102-106 — the header defining the construct for all 30 shipped schemas: "source-types — (optional) restrict which artifact types may originate / target-types — (optional) restrict which artifact types may be targeted."
rivet-core/src/schema.rs:306-308 declares the fields; no validation path reads them. The only non-render reader is validate.rs:1254-1256, a suppression heuristic for prose-mention-without-typed-link — it uses the restriction to decide when not to warn. The sole enforced restriction is the artifact-type-level link-fields[].target-types (validate.rs:925-926). There is no source-type check anywhere.
Empirical: stpa.yaml:314-318 declares prevents with source-types: [system-constraint, controller-constraint], target-types: [hazard, sub-hazard]. A uca emitting prevents → L-001 (a loss) violates both, and validate returns PASS with zero diagnostics — while the coverage rule still reports the hazard as "needs an incoming prevents link". The illegal link is simultaneously unflagged and uncounted.
Highest-consequence item in this list: a schema author declaring source-types believes the graph is constrained.
2. export --format html — three documented flags silently ignored, config.js never generated
main.rs:742,746,750 document --homepage "written to config.js", --version-label, --versions. They arrive as _homepage, _version_label, _versions_json — underscore-prefixed unused params at main.rs:12114-12116. cmd_export_zola doesn't take them at all.
docs.rs:1807 — "Runtime customization is done entirely through config.js"; :1813 shows a file tree with config.js, requirements.html, matrix.html…; :1804 says "CSS is embedded inline with no external dependencies"; :1951 describes an externalCss mechanism. RIVET_EXPORT, config.js, externalCss and all seven documented CSS classes appear only in docs.rs.
Empirical: export with all three flags produces no config.js and no file containing the URL or label; index.html has zero <style> tags and links href="_assets/styles.css". Real layout is artifacts/index.html, matrix/index.html, etc.
3. Document scanning is non-recursive; the prose says recursive, and skips are silent
docs.rs:920-921 — - docs # loads docs/*.md recursively. document.rs:406 is std::fs::read_dir(dir) — one level. The module's own test comment at :2590 concedes it.
docs/ holds 60 .md but only 21 at top level; 4 frontmattered documents under docs/research/, docs/design/, docs/historical/ are invisible to the link graph, dropped with no warning — contradicting the "Loud-by-default doc scanning" design at docs.rs:625, since a file never enumerated cannot be declined. Knock-on: the exclude: "generated/**" example at :623 can never match.
4. init --vendor-schemas "immune to release-to-release rule drift" — false for bridges
main.rs:303 / docs.rs:790 make that claim. embedded.rs:249 discover_bridges() iterates the compiled-in list and falls back to embedded_bridge() when the on-disk file is absent, so a bridge added in a later release fires on a project vendored before it existed.
Empirical: with common/dev/stpa vendored and no stpa-dev.bridge.yaml, schema rules shows constraint-has-requirement active and rivet schema sources prints stpa-dev.bridge … embedded (compiled into rivet — changes on upgrade; vendor under schemas/ to pin) — the binary contradicting its own help text in one run.
5. ai-generated-needs-review can never fire on a valid store
schemas/common.yaml:430 — "AI-generated artifacts with active/approved status must have a reviewer." The rule body uses when: {field: status, equals: active}, but active is not among the nine values in the status enum (common.yaml:58-67), which is gated at Error severity. Condition::Equals is single-valued, so approved — also named in the description — never matches either.
Empirical: an AI-authored requirement with status: approved and no reviewer produces no such diagnostic (a sibling conditional rule does fire, proving the machinery works); with status: active it errors on the enum.
The shipped review gate on AI-authored artifacts emits zero warnings on every valid store — in a repo whose tool-confidence story leans on AI provenance. check_conditional_consistency (schema.rs:929-981) never cross-checks a when.equals value against the field's allowed-values, so nothing reports the dead rule.
6. AGENTS.md documents the release plan as baseline; the field is release
AGENTS.md:188-198 — "rivet's release plan lives in the baseline field … Scope a release = rivet list --filter '(= baseline "vX.Y.Z-track")'". The model field is release (model.rs:322), with --release, --set-release and a rivet release subcommand. sexpr_eval.rs:581-586 falls unknown bare names through to fields.get(...), so the query returns empty rather than erroring.
Empirical: --filter '(= baseline "v0.35.0-track")' → 0 artifacts; --release v0.35.0 → 12.
Second gap in the same file: AGENTS.md:7-10 says hand-authored content "lives below [the markers] … they survive regeneration" — but this section is at lines 186-205, inside the marker pair (END at :220). managed_section.rs:121 replaces the whole region, so rivet init --agents destroys it.
7. Smaller
docs.rs:2736-2738 — "At schema load time … the schema is rejected with a diagnostic." It's a validate-time Warning (schema.rs:936), reached from validation not load, and requirements_overlap only fires on identical requirements. Three overstatements in one sentence.
docs.rs:1085 — "Orphan detection: Artifacts never referenced in any document are flagged." links.rs:216-221 is "no incoming or outgoing links"; documents are not consulted.
main.rs:1522-1525 — "schemas for every --format json output (validate, stats, coverage, list)". Five ship (incl. query); ~52 --format json sites exist; diff, matrix, audit, commits, impact have none.
docs.rs:2106,2108,2240 — "The 15-Tool Catalog" / "fifteen tools". rivet mcp --list-tools → 16; the table omits rivet_bundle. CLI_DOC in the same binary says "the 16-tool catalog".
README.md:89 — rivet init --preset dev # scaffold rivet.yaml + schemas/ + artifacts/. main.rs:4355 guards the only create_dir_all(&schemas_dir) behind if vendor_schemas. A fresh init produces no schemas/.
Explicitly not filed
Stale counts with no behavioural consequence (schema type-count tables, "33 Playwright spec files", "28 Kani harnesses", README.md:152's "v0.5.0 series"), and normative statements whose adjacent comments already disclose non-enforcement (DSGVO at common.yaml:228-230, the SIL/DAL parentheticals). Worth a tidy pass, not a bug.
Umbrella from the inconsistency audit, claim-vs-code lens. Headline instance filed separately: #952 (
sqlread-only claim +--qualification-modescope).Note
rivet docs checkpasses (64 files, 0 violations) — none of these gaps are machine-gated, which is itself the pattern.Verification status: agent-reported with claim file:line + code file:line + an empirical check for each. I re-ran the
sqland--qualification-modeones myself (#952); the rest are recorded as reported.1.
link-types:source-types/target-typesare documented as restrictions and never enforcedschemas/common.yaml:102-106— the header defining the construct for all 30 shipped schemas: "source-types— (optional) restrict which artifact types may originate /target-types— (optional) restrict which artifact types may be targeted."rivet-core/src/schema.rs:306-308declares the fields; no validation path reads them. The only non-render reader isvalidate.rs:1254-1256, a suppression heuristic forprose-mention-without-typed-link— it uses the restriction to decide when not to warn. The sole enforced restriction is the artifact-type-levellink-fields[].target-types(validate.rs:925-926). There is no source-type check anywhere.Empirical:
stpa.yaml:314-318declarespreventswithsource-types: [system-constraint, controller-constraint],target-types: [hazard, sub-hazard]. Aucaemittingprevents → L-001(aloss) violates both, and validate returns PASS with zero diagnostics — while the coverage rule still reports the hazard as "needs an incomingpreventslink". The illegal link is simultaneously unflagged and uncounted.Highest-consequence item in this list: a schema author declaring
source-typesbelieves the graph is constrained.2.
export --format html— three documented flags silently ignored,config.jsnever generatedmain.rs:742,746,750document--homepage"written to config.js",--version-label,--versions. They arrive as_homepage,_version_label,_versions_json— underscore-prefixed unused params atmain.rs:12114-12116.cmd_export_zoladoesn't take them at all.docs.rs:1807— "Runtime customization is done entirely throughconfig.js";:1813shows a file tree withconfig.js,requirements.html,matrix.html…;:1804says "CSS is embedded inline with no external dependencies";:1951describes anexternalCssmechanism.RIVET_EXPORT,config.js,externalCssand all seven documented CSS classes appear only in docs.rs.Empirical: export with all three flags produces no
config.jsand no file containing the URL or label;index.htmlhas zero<style>tags and linkshref="_assets/styles.css". Real layout isartifacts/index.html,matrix/index.html, etc.3. Document scanning is non-recursive; the prose says recursive, and skips are silent
docs.rs:920-921—- docs # loads docs/*.md recursively.document.rs:406isstd::fs::read_dir(dir)— one level. The module's own test comment at:2590concedes it.docs/holds 60.mdbut only 21 at top level; 4 frontmattered documents underdocs/research/,docs/design/,docs/historical/are invisible to the link graph, dropped with no warning — contradicting the "Loud-by-default doc scanning" design atdocs.rs:625, since a file never enumerated cannot be declined. Knock-on: theexclude: "generated/**"example at:623can never match.4.
init --vendor-schemas"immune to release-to-release rule drift" — false for bridgesmain.rs:303/docs.rs:790make that claim.embedded.rs:249discover_bridges()iterates the compiled-in list and falls back toembedded_bridge()when the on-disk file is absent, so a bridge added in a later release fires on a project vendored before it existed.Empirical: with
common/dev/stpavendored and nostpa-dev.bridge.yaml,schema rulesshowsconstraint-has-requirementactive andrivet schema sourcesprintsstpa-dev.bridge … embedded (compiled into rivet — changes on upgrade; vendor under schemas/ to pin)— the binary contradicting its own help text in one run.5.
ai-generated-needs-reviewcan never fire on a valid storeschemas/common.yaml:430— "AI-generated artifacts with active/approved status must have a reviewer." The rule body useswhen: {field: status, equals: active}, butactiveis not among the nine values in thestatusenum (common.yaml:58-67), which is gated at Error severity.Condition::Equalsis single-valued, soapproved— also named in the description — never matches either.Empirical: an AI-authored requirement with
status: approvedand no reviewer produces no such diagnostic (a sibling conditional rule does fire, proving the machinery works); withstatus: activeit errors on the enum.The shipped review gate on AI-authored artifacts emits zero warnings on every valid store — in a repo whose tool-confidence story leans on AI provenance.
check_conditional_consistency(schema.rs:929-981) never cross-checks awhen.equalsvalue against the field'sallowed-values, so nothing reports the dead rule.6.
AGENTS.mddocuments the release plan asbaseline; the field isreleaseAGENTS.md:188-198— "rivet's release plan lives in thebaselinefield … Scope a release =rivet list --filter '(= baseline "vX.Y.Z-track")'". The model field isrelease(model.rs:322), with--release,--set-releaseand arivet releasesubcommand.sexpr_eval.rs:581-586falls unknown bare names through tofields.get(...), so the query returns empty rather than erroring.Empirical:
--filter '(= baseline "v0.35.0-track")'→ 0 artifacts;--release v0.35.0→ 12.Second gap in the same file:
AGENTS.md:7-10says hand-authored content "lives below [the markers] … they survive regeneration" — but this section is at lines 186-205, inside the marker pair (END at:220).managed_section.rs:121replaces the whole region, sorivet init --agentsdestroys it.7. Smaller
docs.rs:2736-2738— "At schema load time … the schema is rejected with a diagnostic." It's a validate-time Warning (schema.rs:936), reached from validation not load, andrequirements_overlaponly fires on identical requirements. Three overstatements in one sentence.docs.rs:1085— "Orphan detection: Artifacts never referenced in any document are flagged."links.rs:216-221is "no incoming or outgoing links"; documents are not consulted.main.rs:1522-1525— "schemas for every--format jsonoutput (validate, stats, coverage, list)". Five ship (incl.query); ~52--format jsonsites exist;diff,matrix,audit,commits,impacthave none.docs.rs:2106,2108,2240— "The 15-Tool Catalog" / "fifteen tools".rivet mcp --list-tools→ 16; the table omitsrivet_bundle.CLI_DOCin the same binary says "the 16-tool catalog".README.md:89—rivet init --preset dev # scaffold rivet.yaml + schemas/ + artifacts/.main.rs:4355guards the onlycreate_dir_all(&schemas_dir)behindif vendor_schemas. A fresh init produces noschemas/.Explicitly not filed
Stale counts with no behavioural consequence (schema type-count tables, "33 Playwright spec files", "28 Kani harnesses",
README.md:152's "v0.5.0 series"), and normative statements whose adjacent comments already disclose non-enforcement (DSGVO atcommon.yaml:228-230, the SIL/DAL parentheticals). Worth a tidy pass, not a bug.