You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two distinct but related rivet issues observed while analyzing the spar project (pulseengine/spar). Both block users from resolving schema-drift / link-cardinality errors without an ecosystem-wide fix.
1. extends: on a schema replaces existing type definitions instead of merging
Observed
Project-local schema under schemas/ declaring an artifact type whose name matches a type already declared in a parent schema replaces the parent's definition. All fields from the parent schema vanish.
Reproducer
Spar already ships schemas/sysml2.yaml which extends common but only adds new types (sysml-requirement, sysml-component, …) — this works fine.
Adding schemas/spar-extensions.yaml that tries to add a single field to feature:
Then registering it in rivet.yaml under project.schemas.
Effect:
$ rivet schema show feature
Type: feature
Description: Spar extension of the common 'feature' type with test-evidence fields
Fields:
method string optional
# Gone: phase, acceptance-criteria, baseline
# Gone: satisfies, implements link-fields
The built-in common fields and link-fields are lost. rivet validate errors jumped from 625 → 646 (the original drift errors remained, plus new ones as previously-declared fields became undeclared).
Expected
extends: [common] combined with redeclaring a type should merge — that is, keep the parent's fields + link-fields and union with the new declaration (project-local fields take precedence on conflict). The sysml2 schema's use of extends: to add entirely new types works; the merge case is the missing mode.
Why it matters
Without merge-on-extends, any project that has authoring conventions not covered by the built-in schemas (e.g., feature.method, requirement.mitigates, requirement.traces-to, design-decision.interfaces — see #2 below) has three equally unpleasant options:
Migrate every artifact to drop the undeclared fields (lose semantic content).
Live with INFO: field X is not defined in schema for type Y noise forever.
Fork rivet's schemas.
Spar took option 2 (981 INFOs in rivet validate) because 1 and 3 both have outsized costs.
2. stpa-yaml source format doesn't expand shorthand into the link graph
Observed
Artifacts authored in the shorthand form declared by the stpa schema's link-field names — e.g.:
are not resolved into entries of the artifact's links: list during parsing. The schema declares these link-fields correctly:
$ rivet schema show uca
Link fields:
controller issued-by -> [controller] required exactly-one
hazards leads-to-hazard -> [hazard, sub-hazard] required one-or-many
but validation fails with:
ERROR: [UCA-4] link 'issued-by' requires exactly 1 target, found 0
ERROR: [UCA-4] link 'leads-to-hazard' requires at least 1 target, found 0
Meanwhile rivet validate reports 0 broken cross-refs — confirming the targets do resolve to existing artifacts; they just aren't counted as links of their declared type.
Scale (in spar)
625 link-cardinality ERRORs (217 artifacts, most with 2-3 missing links each) across:
When a source-format: stpa-yaml file contains a field whose name matches a declared link-field of the artifact's type, rivet should synthesize a canonical links: entry: { type: <declared-link-type>, target: <field-value> }. This would:
Make rivet list --format json report accurate links counts (currently zero for these artifacts, giving a false "172 orphaned artifacts" signal when nothing is actually orphaned).
Eliminate the 625 cardinality ERRORs in projects that use the idiomatic STPA shorthand.
Remove the 981 "field not defined" INFOs for names that are in fact declared link-field shorthands.
The generic-yaml format wouldn't need this — it'd be specific to stpa-yaml since stpa is where the shorthand convention lives.
Alternative
If the shorthand isn't the intended authoring model, that's worth documenting and providing a migration tool. Every STPA-adjacent project I've seen (including the spar STPA analysis and the built-in rivet examples) writes the shorthand.
Full analysis filed as memory notes during spar's April 2026 issue-batch PR (pulseengine/spar#130 — unrelated fixes, mentions rivet drift in its "Not in this PR" section).
Suggested priority
#1 (merge-on-extends) is the more impactful fix: it unblocks any downstream project from silencing drift INFOs locally without upstream changes.
#2 (stpa-yaml shorthand expansion) could even be worked around downstream once #1 is resolved — if schemas can be locally extended to re-declare the link-fields in a way the validator honors.
Two distinct but related rivet issues observed while analyzing the spar project (
pulseengine/spar). Both block users from resolving schema-drift / link-cardinality errors without an ecosystem-wide fix.1.
extends:on a schema replaces existing type definitions instead of mergingObserved
Project-local schema under
schemas/declaring an artifact type whose name matches a type already declared in a parent schema replaces the parent's definition. All fields from the parent schema vanish.Reproducer
Spar already ships
schemas/sysml2.yamlwhich extendscommonbut only adds new types (sysml-requirement,sysml-component, …) — this works fine.Adding
schemas/spar-extensions.yamlthat tries to add a single field tofeature:Then registering it in
rivet.yamlunderproject.schemas.Effect:
The built-in common fields and link-fields are lost.
rivet validateerrors jumped from 625 → 646 (the original drift errors remained, plus new ones as previously-declared fields became undeclared).Expected
extends: [common]combined with redeclaring a type should merge — that is, keep the parent's fields + link-fields and union with the new declaration (project-local fields take precedence on conflict). The sysml2 schema's use ofextends:to add entirely new types works; the merge case is the missing mode.Why it matters
Without merge-on-extends, any project that has authoring conventions not covered by the built-in schemas (e.g.,
feature.method,requirement.mitigates,requirement.traces-to,design-decision.interfaces— see #2 below) has three equally unpleasant options:INFO: field X is not defined in schema for type Ynoise forever.Spar took option 2 (981 INFOs in
rivet validate) because 1 and 3 both have outsized costs.2.
stpa-yamlsource format doesn't expand shorthand into the link graphObserved
Artifacts authored in the shorthand form declared by the stpa schema's link-field names — e.g.:
are not resolved into entries of the artifact's
links:list during parsing. The schema declares these link-fields correctly:but validation fails with:
Meanwhile
rivet validatereports 0 broken cross-refs — confirming the targets do resolve to existing artifacts; they just aren't counted as links of their declared type.Scale (in spar)
issued-by/leads-to-hazardconstrains-controller/inverts-uca/preventsleads-to-hazardleads-to-losspreventsissued-by/acts-onExpected
When a
source-format: stpa-yamlfile contains a field whose name matches a declared link-field of the artifact's type, rivet should synthesize a canonicallinks:entry:{ type: <declared-link-type>, target: <field-value> }. This would:rivet list --format jsonreport accuratelinkscounts (currently zero for these artifacts, giving a false "172 orphaned artifacts" signal when nothing is actually orphaned).The
generic-yamlformat wouldn't need this — it'd be specific tostpa-yamlsince stpa is where the shorthand convention lives.Alternative
If the shorthand isn't the intended authoring model, that's worth documenting and providing a migration tool. Every STPA-adjacent project I've seen (including the spar STPA analysis and the built-in rivet examples) writes the shorthand.
Concrete evidence
Spar repository: https://github.com/pulseengine/spar
Full analysis filed as memory notes during spar's April 2026 issue-batch PR (pulseengine/spar#130 — unrelated fixes, mentions rivet drift in its "Not in this PR" section).
Suggested priority
#1 (merge-on-extends) is the more impactful fix: it unblocks any downstream project from silencing drift INFOs locally without upstream changes.
#2 (stpa-yaml shorthand expansion) could even be worked around downstream once #1 is resolved — if schemas can be locally extended to re-declare the link-fields in a way the validator honors.
🤖 Generated with Claude Code