feat(validate): --structural gates on integrity only, via Diagnostic::is_structural() (REQ-161, #408)#418
Merged
Merged
Conversation
…:is_structural() (REQ-161, #408) From #408 (and the recurring #353/#355 ask): `rivet validate`'s PASS/FAIL lumps structural integrity (a broken graph) together with coverage/lint findings, so a bulk status-flip can't tell "did I break the graph?" from "the project is still incomplete". spar/sigil both hand-rolled a `0 broken cross-refs` gate for exactly this. Add `Diagnostic::is_structural()` — an explicit allowlist of the structural rule ids (broken-link, duplicate-artifact-id, artifact-parse-error, link-target-type, cardinality, known-type, unknown-link-type, doc-broken-ref, yaml-type-coercion, conditional-rule-consistency, coverage-rule-consistency). Everything else is coverage/lint, including the three borderline rules required-field / unknown-field / status-allowed-values (an incomplete/extra/typo'd field doesn't break the graph) and all schema-defined coverage/status-gate rules. `rivet validate --structural` retains only structural diagnostics before counting/display, so the shown set, counts, and PASS/FAIL exit reflect structural-only. No rename of `validate_structural*` (its name is unrelated to this gate) — the classification lives on Diagnostic (#408 option b). Verified: rivet repo `validate --structural` PASSes with 0 shown (its 206 warnings are all coverage/lint); a broken-link fixture FAILs --structural; a coverage-only fixture PASSes. Unit test enumerates every built-in rule's class; CLI test covers the gate. clippy --all-targets + fmt clean; docs check PASS. Implements: REQ-161
📐 Rivet artifact delta
Graphgraph LR
REQ_161["REQ-161"]:::added
classDef added fill:#d4edda,stroke:#28a745,color:#155724
classDef removed fill:#f8d7da,stroke:#dc3545,color:#721c24
classDef modified fill:#fff3cd,stroke:#ffc107,color:#856404
classDef overflow fill:#e2e3e5,stroke:#6c757d,color:#495057,stroke-dasharray: 3 3
Added
Posted by |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements #408. You delegated the 3 borderline classifications — I went with my recommendation (all coverage/lint), documented inline.
Why
rivet validate's PASS/FAIL lumps structural integrity (a broken graph) with coverage/lint (incomplete/non-compliant). A bulk status-flip or edit can't tell "did I break the graph?" from "still incomplete". spar and sigil both hand-rolled a0 broken cross-refsgate for exactly this (#353/#355).What
Diagnostic::is_structural()— explicit allowlist:artifact-parse-error,duplicate-artifact-id,known-type,unknown-link-type,link-target-type,cardinality,broken-link,doc-broken-ref,yaml-type-coercion,conditional-rule-consistency,coverage-rule-consistency. Everything else (including all schema-defined coverage/status-gate rules) is coverage/lint.required-field,unknown-field,status-allowed-values→ coverage/lint (an incomplete/extra/typo'd field doesn't break the graph). Easy to flip later if you disagree — they're one line in the allowlist.rivet validate --structuralretains only structural diagnostics before counting/display, so shown set + counts + PASS/FAIL all reflect structural-only.validate_structural*(option b) — the classification is aDiagnosticmethod, decoupled from that misnamed function.Verify
validate --structural→ PASS, 0 shown (its 207 warnings are all coverage/lint).--structuralFAILs and shows it; coverage-only fixture →--structuralPASSes.is_structural_classifies_every_builtin_rule(enumerates every built-in rule) +validate_structural_gates_on_structural_onlyCLI test.--all-targets+ fmt clean; docs check PASS.--helpdocuments the flag.Deferred
Per-rule
allow:config (net-new infra) and anyvalidate_structural*rename.Implements: REQ-161
🤖 Generated with Claude Code