fix(docs): make bridge-schema coverage rules discoverable (#895) - #903
fix(docs): make bridge-schema coverage rules discoverable (#895)#903avrabe wants to merge 1 commit into
Conversation
A user who saw `rivet coverage` report a bridge-schema rule fail (for example `constraint-has-requirement 0/11`) had no way to learn what link type and target types would satisfy it — `rivet docs schema/...` returned nothing for the bridge, and the coverage row itself named only the rule's counter. The workaround, guessing link types until the counter moves, silently produces false links in a safety artifact store. Two additive changes close that gap: - Register the seven embedded bridge schemas as `rivet docs` topics under a new `Bridges` category. Each topic serves the bridge YAML, so the rule's `source-type` / `required-link` / `target-types` / severity are reachable via `rivet docs schema/<bridge>` (the same shape non-bridge schemas already ship). Add `schema/bridges` as a short overview page. - In the `rivet coverage` text output, print a `<rule> needs: <link> <arrow> [<target-types>]` continuation line under every failing (non-100%, non-empty) row. Empty-scope rows and 100% rows are skipped — remediation isn't the question there. The line repeats the rule name so a plain `rivet coverage 2>&1 | grep <rule>` returns both the tally and the fix. A unit test in `docs::bridge_topic_tests` pins the topic set to `embedded::BRIDGE_SCHEMAS` so a new bridge cannot ship without a discoverable topic — the failure mode this issue exists to remove. Integration tests cover the list grouping, the topic body, and the coverage remediation line. Fixes: REQ-004 Refs: #895 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E9RwnfmhwjDB8wPhuq9Prd
📐 Rivet artifact deltaNo artifact changes in this PR. Code-only changes (renderer, CLI wiring, tests) don't touch the artifact graph. |
|
CI status on Grounds: this PR's diff touches Every other CI signal is either green or still in progress; I'll come back on those events. Watching until this PR is done. Generated by Claude Code |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Closes #895 — slice 1 (bridge-schema rule definitions are discoverable). Slice 2 (local-vs-external denominator distinction in coverage) is left for a follow-up PR, per the AC's explicit two-slice cut.
What changed
rivet docs schema/<bridge>for the seven built-in bridges. Registeredschema/eu-ai-act-aspice.bridge,schema/eu-ai-act-stpa.bridge,schema/iso-8800-stpa.bridge,schema/safety-case-eu-ai-act.bridge,schema/safety-case-stpa.bridge,schema/sotif-stpa.bridge, andschema/stpa-dev.bridgeasDocTopicentries served by the embedded bridge YAML — the same shape non-bridge schema topics already ship, so the rule'ssource-type/required-link/target-types/ severity are reachable viarivet docs.Bridgescategory inrivet docs --listgrouping the seven above plus aschema/bridgesoverview topic that names each bridge, itsextendslist, and how to read a failing coverage row.rivet coveragerows. For each row whose percentage is neither100.0%norn/a, the text output now prints a<rule> needs: <link> ← [<target-types>]continuation line (→for forward links,←for backlinks). The line repeats the rule name so a plainrivet coverage 2>&1 | grep <rule>returns both the tally and the fix — exactly the case the issue describes forconstraint-has-requirement. Empty-scope (0/0) and 100% rows are skipped; remediation isn't the question there. JSON output is unchanged.Sample against the rivet repo itself:
Acceptance criteria — slice 1
rivet docs schema/safety-case-stpa.bridgeandrivet docs schema/stpa-dev.bridge(plus the other five bridges) print the same shape asrivet docs schema/dev— per rule, name +source-type+required-link+target-types+ severity + description. The content is the raw bridge YAML, so every field the rule carries is exposed verbatim.rivet docs --listunder a newBridgesgroup, so a user chasing aconstraint-has-requirementfailure can walk from the topic list to a bridge without knowing the bridge filename in advance.schema/bridgesis the entry point that maps failing rule names back to their bridge.rivet coveragetext output renders each failing (non-100%) rule with itsrequired-link+target-typesinline (default-on, since the AC's regression test uses plainrivet coverage). Empty-scope and 100% rows are exempt.rivet coverage 2>&1 | grep constraint-has-requirementon the rivet repo now returns both the tally row and theconstraint-has-requirement needs: constraint-satisfies ← [requirement]line (see snippet above). Covered by an integration test.cargo test --workspacegreen (196rivet-cliintegration tests pass; workspace runs clean; a background workspace run is confirming the full slice).cargo fmt --all -- --checkandcargo clippy --all-targets -- -D warningsclean.rivet validatePASS on this repo (779 warnings, unchanged frommain).Out of scope (per the AC, filed separately)
--local-only, and the 3-state extension for cross-repo subjects. That's a coverage-semantics change, not a docs-discoverability one, and the AC explicitly cuts it into its own PR.unmodelled-rules: modelled-as: <sibling-rule>extension (REQ-320 territory, not this issue).Tests
docs::bridge_topic_tests::every_embedded_bridge_has_a_docs_topic— pins the topic set torivet_core::embedded::BRIDGE_SCHEMASso a new bridge cannot ship without a discoverable topic. This is the invariant that would have caught the original bug at CI time.docs::bridge_topic_tests::bridge_topic_slug_registry_matches_topics,bridge_topics_are_categorized_as_bridges,bridge_topic_content_carries_the_coverage_rule_shape— pin the category, slug pattern, and payload shape.docs_list_groups_bridges,docs_show_bridge_topic— integration tests that hit the real binary.coverage_text_prints_required_link_for_failing_rules— integration test on the rivet repo itself. Finds a failing row, asserts a<rule> needs:line follows it, and separately grep-pins therequirement-coveragecase as a specific regression anchor.🤖 Generated with Claude Code
https://claude.ai/code/session_01E9RwnfmhwjDB8wPhuq9Prd
Generated by Claude Code