feat: client-side AADL diagram rendering via spar WASM#5
Merged
Conversation
Replace the server-side /api/render-aadl endpoint (which shelled out
to the spar CLI) with browser-side rendering using the jco-transpiled
spar WASM component.
- Add /wasm/{*path} route to serve jco-transpiled JS + WASM assets
- Add /source-raw/{*path} route for raw file access (files + dir listings)
- Rewrite AADL_JS to load spar WASM module with a virtual WASI
filesystem adapter, call renderer.render() client-side
- Add diagram caption bar with AADL badge, root name, component count
- Add zoom controls (+/-/reset) and mouse wheel zoom + drag pan
- Remove server-side SparAnalyzeOutput, find_aadl_files, build_instance_graph
- Exclude /wasm/ and /source-raw/ from HTMX redirect middleware
- Fix double-render by removing DOMContentLoaded listener
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add comprehensive AADL integration section to getting-started.md covering setup, architecture artifacts, diagram embedding, dashboard views, and client-side WASM rendering flow - Update build-wasm.sh to use --instantiation async for jco transpilation - Update WASM README with async instantiation instructions - Fix MSRV reference (1.85 -> 1.89) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
avrabe
added a commit
that referenced
this pull request
Apr 22, 2026
…f-life) (#189) * fix(embed,docs,ui): v0.4.2 UX polish + 4 embed bugs 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> * fix(validate): count flow-style and named-field links for cardinality 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> * fix(schema,validate): treat undeclared link types as ERROR + add schema-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> * feat(docs-check): external-namespace exemption + skip directives + AGENTS.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> * feat(stamp): batch filter flags --type, --changed-since, --missing-provenance 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> * docs: cover AUDIT marker, conditional-rules, rivet-managed contract; 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> * fix(lsp,yaml): LSP resolves workspace schemas; YAML parser tolerates 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> * feat(ui,docs,e2e): TOC anchors + variant dashboard docs + Playwright 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> * fix(embed,sexpr,yaml): close 6 silent-accept findings from project audit 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> * fix(schema,parse): deny_unknown_fields on schema structs + fix docs-check 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> * feat(ci): rivet-delta PR workflow with graphical artifact diff + Playwright 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> * chore: bump workspace + VSCode + npm to 0.4.2 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> --------- 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
/api/render-aadl(shelled out to spar CLI) with browser-side rendering using the jco-transpiled spar WASM component/wasm/and/source-raw/routes for serving WASM assets and raw file content--instantiation asyncjco transpilationTest plan
cargo check --allpassescargo clippy --all-targetscleanrivet serverenders AADL diagrams in architecture.md documents🤖 Generated with Claude Code