v0.4.2: UX polish + 10 bug fixes (4 silent-accept, 2 LSP, 4 quality-of-life)#189
Merged
v0.4.2: UX polish + 10 bug fixes (4 silent-accept, 2 LSP, 4 quality-of-life)#189
Conversation
Surfacing existing-but-invisible data and fixing silent-accept in the
embed pipeline that the v0.4.1 Mythos pipeline would have flagged.
UI surfacing (data was always there, UI didn't show it):
- Artifact detail now lists documents that reference the artifact
via [[ID]] links, with line numbers per occurrence.
- Mermaid/AADL diagrams on artifact detail and schema-show pages now
wrap in .svg-viewer so they get the same zoom / fullscreen / popout
toolbar as graph and doc-linkage views.
Embed correctness:
- {{group:TYPE:FIELD}} two-arg form — the second arg was silently
discarded, causing every artifact to bucket into "unset" because
the first arg was read as the field name. Now scopes by type and
groups by field as the syntax suggests.
- {{query ...}} now honors fields= to customize table columns and
rejects colon-prefixed option syntax (:limit 10) with a helpful
error pointing to key=value form — previously silently dropped.
- Standalone {{artifact|links|table:...}} on its own line no longer
wraps in <p>, which produced invalid HTML nesting. Block-level
embeds emit directly.
Docs-check gate:
- rivet docs check now honors rivet.yaml's docs: list instead of
only scanning the top-level docs/ directory. Projects with
crates/*/docs or rivet/docs layouts are no longer silently missed.
Implements: REQ-004, REQ-008, REQ-010
Refs: FEAT-001
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two silent-accept bugs in the link cardinality validator that let
"required: true, cardinality: one-or-many" link-fields appear absent
while rivet validate stayed PASS.
Flow-style: `links: [{type: X, target: Y}]`
The rowan CST parser records flow sequences but does not emit nested
flow-mapping nodes, so extract_links walked an empty Sequence and
returned zero links. Added a serde_yaml fallback that re-parses the
value text when the CST yields no Sequence — flow and block styles
now produce byte-identical Link vectors.
Named-field form: schema `link-field.name: targets` + artifact
`targets: [SEC-AS-001]`
shorthand_links was declared on ArtifactTypeDef but never populated,
so the yaml_hir shorthand path never fired and `targets:` fell into
custom-fields instead of becoming a threatens-link. Schema::merge
now derives shorthand_links from each link-field automatically.
Both shapes were displayed correctly by `rivet get` (the parser saw
them for rendering) but the cardinality counter saw zero — the worst
kind of bug for safety tooling. Regression test pins the invariant
that flow-style and block-style yield identical Link vectors.
Fixes: REQ-004
Verifies: REQ-004
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ma-consistency check Two changes that close a silent-accept loop in the schema layer: 1. validate.rs — `unknown-link-type` Severity bumped from Warning to Error. An undeclared link-type means the schema's cardinality and target-type guarantees silently don't apply to those links; that's not an advisory, it's an integrity failure. De-duplicates per (artifact, link_type) so a single typo doesn't drown the report. 2. schema.rs — new `Schema::validate_consistency()` returns a list of schema-internal issues: - link-fields referencing undeclared link types - link-fields with unknown target artifact types - traceability rules with unknown from/target types This mirrors what `rivet schema validate` already reported but is now a library function callable from any load path, so a downstream project can fail-fast on a broken schema instead of validating artifacts against silently-broken rules. Two regression tests pin the invariants: undeclared link type emits exactly one Error diagnostic per (artifact, link-type) pair, and schema_consistency flags both dangling link-types and missing target types. Implements: REQ-010 Verifies: REQ-004, REQ-010 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ENTS.md template fix
Three-layered escape hatch so the ArtifactIdValidity gate can run as a
required CI check on projects that legitimately reference external IDs
(Jira, Polarion, hazard catalogs, upstream stakeholder docs).
1. rivet.yaml `docs-check.external-namespaces: [GNV, GNR, HZO, UC, ...]`
exempts every `<PREFIX>-NNN` matching one of those prefixes (case-
insensitive). Most discoverable form — namespace-level allow-list.
2. rivet.yaml `docs-check.ignore-patterns: [<regex>, ...]` for cases
where namespace matching isn't enough. Free-form regex escape hatch.
3. HTML-comment directives in any markdown:
`<!-- rivet-docs-check: ignore GNV-396 FOO-1 -->` skips the named
IDs anywhere in the doc.
`<!-- rivet-docs-check: ignore-line -->` skips every ID on the same
line as the directive.
Most surgical — keeps the exemption visible right at the citation.
Bundled AGENTS.md template now embeds an `ignore SC-1 REQ-001 FEAT-042`
directive so a fresh `rivet init && rivet docs check` doesn't fail on
its own example IDs.
Two regression tests cover both the config and directive paths. The
24 existing doc_check tests still pass — the new context fields are
additive, all in-tree call sites updated.
Implements: REQ-004
Refs: REQ-008
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ovenance
Three filter flags so provenance stamping no longer requires shell loops
like `rivet list | grep ... | xargs -I{} rivet stamp {} ...`. All
combinable with each other and with the existing `id "all"` form.
--type PATTERN
Glob (`SEC-*`) matches IDs by prefix; otherwise exact artifact-type
name (`requirement`). Combine with `id "all"` or a wider glob.
--changed-since REF
Restrict to artifacts whose source YAML was touched relative to the
given git ref — committed diff plus uncommitted modifications.
Falls back to "no matches" on git error so the flag never panics.
--missing-provenance
Skip artifacts that already carry a `provenance:` block. Idempotent
bulk stamping: rerun safely without overwriting human-reviewed
provenance.
Glob support uses an in-tree minimal `*` / `?` matcher (5 unit tests)
to avoid pulling in the `glob` crate for one tiny need.
Implements: REQ-007
Refs: REQ-008
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…require --yes for --force-regen Closes the documentation gaps the user flagged in Issue #5: - AUDIT: marker syntax for the ArtifactCounts invariant — explains when to use it (manual override of "N items" claims) and that the date is not parsed (advisory only). - conditional-rules: worked example showing when/then structure with `equals` condition and `required-fields` requirement. - rivet-managed BEGIN/END markers contract — content outside the markers is preserved across `rivet init --agents` regeneration; only use --force-regen if markers were lost. - rivet docs check escape hatches — three layered exemption mechanisms (config namespaces, ignore-patterns regex, HTML-comment directives) documented in one place. CLI safety: `--force-regen` now requires `--yes` (clap requires=). The destructive overwrite was previously one accidental flag away; now it needs both `--force-regen --yes` to fire. CLI clarity: error message for `rivet embed artifact:X` / `links:X` / `table:T:F` now explains why those embeds only render inside markdown documents, instead of the cryptic "handled inline" string. Saves users an hour of debugging. Refs: REQ-008, REQ-007 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…inline comments Issue #6 — two LSP-noise sources that train users to ignore the LSP. (a) LSP schema resolution The LSP previously called resolve_schemas_dir(cli) using cli.project, which is whatever directory the LSP process was launched from — often not the workspace root. So an LSP started from VS Code would look in `<cwd>/schemas/` and never find user schemas like `<workspace>/schemas/ulinc.yaml`. Result: every artifact-type defined in a project schema reported as "unknown artifact type" even though `rivet validate` accepted them. Now the LSP resolves the schemas directory from the workspace `project_dir` (derived from root_uri), with --schemas as the explicit override and the binary-relative location as a final fallback. (b) YAML inline-comment handling The CST mapping parser fell to the generic error branch on any line whose first non-whitespace token was a Comment, producing "expected mapping key, found Some(Comment)" diagnostics on every `.github/workflows/*.yml` line with a leading `# ...` comment. serde_yaml and python yaml.safe_load both parse the same input fine. parse_block_mapping now eats Comment tokens at the key position and continues, treating them as trivia. Trailing inline comments and nested-mapping leading comments were already handled. Three regression tests pin the YAML behaviour: - mapping_with_comment_only_line - mapping_with_indented_comment_line - mapping_with_inline_trailing_comment_on_value Implements: REQ-029, REQ-028 Verifies: REQ-029 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
⚠️ Performance Alert ⚠️
Possible performance regression was detected for benchmark 'Rivet Criterion Benchmarks'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.
| Benchmark suite | Current: 72a4c6a | Previous: 5e383ec | Ratio |
|---|---|---|---|
store_insert/10000 |
16909553 ns/iter (± 1538220) |
12020979 ns/iter (± 814719) |
1.41 |
link_graph_build/10000 |
35000806 ns/iter (± 2206460) |
26775109 ns/iter (± 1917654) |
1.31 |
validate/10000 |
14316911 ns/iter (± 853720) |
11485095 ns/iter (± 755817) |
1.25 |
This comment was automatically generated by workflow using github-action-benchmark.
…parity
Folds the items originally deferred to v0.4.3 back into v0.4.2 because
the customer needs them shipped together.
UI:
- Markdown headings now emit `id="..."` slugs so in-page TOC links and
external `#anchor` URLs actually navigate. New `slugify_heading`
strips embedded HTML (the inline embed resolver may have substituted
artifact cards), lowercases, and collapses non-alnum runs to single
hyphens. Two regression tests pin the slug shape and the heading id.
Docs:
- getting-started.md gains a "Variants in the dashboard" subsection
documenting the auto-discovery convention, the sidebar+dropdown UI,
and the `/variants` overview page. Closes the doc-reality drift the
user flagged ("how would I even see the variant").
- what-is-rivet.md section 4.5 mentions the dashboard variant selector
alongside the CLI workflow.
Playwright:
- New `diagram-viewer.spec.ts` codifies the architectural invariant:
every dashboard view rendering a diagram (graph, doc-linkage,
schema-linkage) wraps it in `.svg-viewer` with the same toolbar
(zoom-fit, fullscreen, popout). Fullscreen toggle verified.
- `artifacts.spec.ts` extended with: (a) artifact mermaid diagram
wrapped in svg-viewer, (b) "Referenced in Documents" reverse-index
block visible (skips when fixture has no references).
- `documents.spec.ts` extended with: rendered headings carry `id`
attributes — TOC navigation regression guard.
Implements: REQ-008
Refs: FEAT-001, REQ-007
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Background audit (run after the v0.4.2 batch) flagged 6 more sites
where invalid input was silently swallowed instead of surfaced. All
close before v0.4.2 ships.
P1 — visible silent skips that masked typos as "no data":
- {{coverage:typo-rule}} now errors with a list of known rule names
instead of rendering "No coverage rules defined" — previously a
typo'd rule was indistinguishable from a project genuinely without
rules.
- {{diagnostics:warnings}} (typo for `warning`) now errors with the
three valid severities. Previously the unknown severity matched the
`_ => true` arm and returned ALL diagnostics, hiding the typo.
- {{matrix:UnknownType:OtherType}} now errors before rendering. The
blank table that used to appear was indistinguishable from "rule
applies but nothing covered yet" — the user couldn't tell their
typo from a real coverage gap.
P2 — narrower-scope clarity wins:
- sexpr_eval `links-count` now distinguishes "second arg isn't a
symbol" from "operator literally empty" from "operator not in the
allowed set", with a hint listing the six valid operators.
- yaml_hir `extract_string_list` now falls back to serde_yaml when the
CST yields zero items from a non-empty FlowSequence — same defensive
pattern that fixed `extract_links` for flow-style mappings.
- yaml_hir top-level mapping walk now emits a Warning diagnostic when
an unknown key looks like a typo of a schema-defined section
(singular vs plural, fuzzy match). Legitimate metadata keys still
pass silently. Catches misspellings like `control-action:` (should
be `control-actions:`) that previously dropped every nested item.
Three new regression tests pin the P1 invariants: matrix rejects
unknown types, diagnostics rejects unknown severities, coverage
rejects unknown filter rules. Each verifies the error message names
the bad input.
Pattern: every fix here returns Err with a hint listing valid values
or known names — the same shape we adopted in the v0.4.2 main batch
for `{{group}}` and `{{query}}` parameter validation.
Implements: REQ-004, REQ-029
Verifies: REQ-004
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…heck UTF-8 boundary panic Surfaces SCRC "deterministic parsing / strict schemas" requirement: typo'd YAML keys in schema author files now error at load time instead of silently dropping. Annotates every schema-author struct with `#[serde(deny_unknown_fields)]`: - SchemaFile, SchemaMetadata, ArtifactTypeDef, MistakeGuide, FieldDef, LinkFieldDef, LinkTypeDef, TraceabilityRule, ConditionalRule, AlternateBacklink (new) — schema authoring - Link, Provenance — artifact-level The strict deserialization immediately surfaced two missing fields the bundled schemas were already using: - LinkFieldDef.description — explanatory text per link-field - TraceabilityRule.alternate_backlinks (new struct) — alternate backlink shapes used by safety-case schemas to express "supported-by OR decomposed-by OR has-sub-goal" without rule duplication Both added as `#[serde(default)]` Optional/Vec to preserve back-compat; 14 in-tree TraceabilityRule constructors updated to pass `vec![]`. Tangential bug found while landing this: - doc_check.rs:557 panicked on multi-byte boundary when slicing the 32-byte VersionConsistency context window if the cut landed inside a multi-byte char (e.g. an em-dash in a heading). Walks back to a char boundary first. Also clarified the resolve_str function in sexpr_eval.rs with a SAFETY-REVIEW-style comment explaining the intentional empty-string semantics for missing fields in filter queries (NOT silent-accept; it's the correct semantics for `(= asil "ASIL-D")` filters that should naturally exclude artifacts without an `asil` field). Hardened render_diagnostics severity match: the `_ => true` arm is now unreachable after the upstream validation pass landed earlier in this release; replaced with explicit `None` arm + `unreachable!()` for any other Some(value), so a contract bug fails loudly instead of silently. CHANGELOG.md gains a v0.4.2 entry covering all 18 silent-accept findings and the v0.4.3 SCRC roadmap. Implements: REQ-010, REQ-004 Verifies: REQ-010 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…wright coverage
New informational workflow (.github/workflows/rivet-delta.yml) that runs
on every PR touching artifacts/schemas/rivet.yaml/rivet-core/rivet-cli.
For each PR it:
1. Checks out base (merge-base) and head side-by-side.
2. Builds rivet-cli in release mode.
3. Runs `rivet diff --base ... --head ... --format json`.
4. Runs `rivet impact --since <base-sha> --depth 5 --format json`.
5. Runs `rivet export --format html --offline` for the head tree.
6. Generates a PR-comment markdown via scripts/diff-to-markdown.mjs.
7. Uploads the full delta-out/ (HTML dashboard + JSON) as a workflow
artifact retained for 14 days.
8. Posts or updates a single PR comment (found via the hidden marker
`<!-- rivet-delta-bot -->`) so the diff stays fresh across
subsequent pushes without stacking.
Security:
* All user-derived inputs (`pull_request.number`, `pull_request.base.sha`,
`run_id`, `repository`) are captured at job-scope env and referenced
from run: blocks via $VAR — follows GitHub's workflow-injection guide.
* Every diff/impact/export step is `continue-on-error: true`; the script
gracefully emits a warning comment if either JSON fails to load
instead of crashing the workflow.
* Never blocks merge — strictly informational.
Markdown format (scripts/diff-to-markdown.mjs):
* Hidden `<!-- rivet-delta-bot -->` marker for comment-update lookup.
* Counts table (added / removed / modified / impacted).
* Mermaid link-graph diagram, capped at 30 nodes with an `overflow`
sentinel node for the remainder; 3 classDef styles for
added/removed/modified.
* Collapsible `<details>` blocks per change class with 200-row cap
plus `… +N more` overflow.
* Workflow-artifact download link.
* All user-controlled strings escaped (pipe, backtick, *, _, [, ],
angle brackets) so hostile artifact IDs can't break out of the
comment structure.
Playwright regression suite (tests/playwright/rivet-delta.spec.ts):
* 6 tests pinning the "visible and usable" contract:
- shipping summary renders end-to-end (counts table visible,
"Modified" details expands, artifact link has correct href).
- Empty-diff path emits the no-change sentinel (no mermaid block).
- Malformed-JSON path produces a warning comment, not a crash.
- Mermaid source parses with the real bundled mermaid.js parser
(catches broken syntax before a reviewer sees a broken diagram).
- 30-node cap produces the `overflow` sentinel.
- Markdown metacharacters in artifact IDs (`*evil*`, `|pipe|`) are
escaped, not interpreted.
Refs: FEAT-001, REQ-008
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
📐 Rivet artifact deltaNo artifact changes in this PR. Code-only changes (renderer, CLI wiring, tests) don't touch the artifact graph. |
Three surfaces kept in sync for the v0.4.2 release tag: - workspace Cargo.toml - vscode-rivet/package.json - npm/package.json Per-platform npm packages (darwin-x64, linux-arm64, etc.) are generated with matching versions by the release-npm.yml workflow at publish time; no hand-editing needed. Trace: skip Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
Bundles the v0.4.2 UX polish discovered while dogfooding the dashboard with the six substantive issues reported by an external user (Delphi). Three categories:
Silent-accept bugs (highest-risk for safety tooling — looks green, isn't):
{{group:TYPE:FIELD}}: second arg was discarded → all artifacts bucketed as "unset"{{query (...) :limit 10}}: colon-prefixed options silently dropped → now rejected with hintWorkflow blockers:
rivet docs checknow respectsrivet.yaml docs:paths + adds external-namespace exemption mechanism so the gate can run on real projects with Jira/Polarion/hazard IDs# comments(was emitting "expected mapping key, found Comment" on every CI workflow file)rivet stampbatch filters:--type,--changed-since,--missing-provenance(no morexargsloops)UI surfacing (data already in core, just not shown):
Docs gaps closed:
AUDIT:marker syntax forArtifactCountsconditional-rules:worked example withwhen:/then:<!-- BEGIN/END rivet-managed -->contract forrivet init --agents--force-regennow requires--yes(destructive guard)Test plan
cargo test --workspace— all 36 test groups pass; ~700 rivet-core tests + integration testsrivet docs checksmoke test on this repo: PASS (41 files, 0 violations)rivet stamp 'SEC-*' --type threat-scenario --missing-provenanceon a project with mixed typesrivet serveand verify "Referenced in Documents" block appears on/artifacts/{id}pagesFollow-ups (deferred from this PR)
diagram-viewer.spec.tsfor B2/B3 + B5score/cybersecurityschema fixes (the user's downstream copies; this repo's bundled schemas are clean perrivet schema validate)🤖 Generated with Claude Code