Skip to content

Wave 2: five P1 cross-git fixes (REQ-063/064/068/075/076)#309

Merged
avrabe merged 5 commits into
mainfrom
feat/wave-2-p1-fixes
May 21, 2026
Merged

Wave 2: five P1 cross-git fixes (REQ-063/064/068/075/076)#309
avrabe merged 5 commits into
mainfrom
feat/wave-2-p1-fixes

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented May 21, 2026

Summary

Wave 2 of the cross-git investigation follow-ups (FEAT-135) — five P1
code fixes, each closing an F2-family finding (a silent failure under a
green rivet validate). Integrated from four parallel work units.

REQ Fix
REQ-063 rivet init --preset {do-178c,en-50128,iec-61508,iec-62304} no longer produces an unvalidatable project — the four safety-critical schemas are now embedded in the binary alongside the working five. (Two also carried an unparseable condition: field; brought in line with the en-50128 pattern.)
REQ-064 A derives-from-external link now satisfies a required derives-from link-field. The S4 finding was misdiagnosed as a parse failure; the link parses fine — the validator's cardinality check counted only exact matches. New link_satisfies_field helper.
REQ-068 rivet supplier pull refuses on sha256 drift (exit non-zero, names both hashes + supplier) instead of silently overwriting the cache; --accept-drift is the explicit auditor override.
REQ-075 Duplicate artifact IDs are detected at load time — a duplicate-artifact-id Error naming both source files — instead of Store::upsert silently keeping last-write-wins.
REQ-076 Orphan artifacts surface in rivet validate (orphan-artifact, Warning by default; --strict-orphans promotes to Error) — previously visible only in rivet stats.

Notable: REQ-075 immediately found a real bug

The new duplicate detection surfaced a genuine pre-existing collision in
rivet's own artifacts/: REQ-060 was declared twice (two unrelated
requirements). Resolved by renaming the v042 entry to REQ-077 (zero
inbound links, zero doc mentions — the safe one). Without this, rivet validate on the rivet repo itself would now FAIL.

Test plan

  • cargo build --workspace — clean.
  • cargo test --workspace0 failures across the full suite.
  • New regression tests: init_safety_critical_presets_produce_validating_projects, validate_accepts_derives_from_external_structured_target, supplier_pull_refuses_on_sha256_drift_without_accept_flag, validate_detects_duplicate_artifact_ids, validate_reports_orphans_as_warnings.
  • test_dogfood_validate + stats_json_counts_match_validate — still green.
  • cargo clippy --workspace --all-targets -- -D warnings — exit 0.

Implements: REQ-004, REQ-007, REQ-010
Verifies: REQ-063, REQ-064, REQ-068, REQ-075, REQ-076
Refs: FEAT-135

🤖 Generated with Claude Code

avrabe and others added 5 commits May 21, 2026 05:40
…REQ-063)

The do-178c/en-50128/iec-61508/iec-62304 presets named schemas that
were never embedded in the binary; rivet init relies entirely on the
include_str! embedded-schema registry and never writes schemas to disk,
so the next rivet validate failed. Embed all four schemas alongside the
working five. iec-61508 and iec-62304 also carried an unsupported
`condition:` field inside traceability-rules (no such parser feature
exists); replace it with the project-level-concern comment pattern that
en-50128 already uses, so the schemas parse and fresh projects validate.

Implements: REQ-007
Verifies: REQ-063
Refs: FEAT-135
…m link-field (REQ-064)

The cross-git investigation's S4 finding misdiagnosed this as "the
structured target is silently parsed as derives-from with no target".
Reproduction shows the link parses correctly — `rivet get` reports
`type: derives-from-external, target: ANCHOR-X`. The real bug is in
the validator's link-field cardinality check
(`validate.rs` phase 4): it counted only links whose type *exactly*
equalled the required link-field type. A `sw-req` carrying a
`derives-from-external` link to satisfy its required `derives-from`
link-field therefore counted 0 and failed with a spurious
`link 'derives-from' requires at least 1 target, found 0` Error.

Fix: new `link_satisfies_field(actual, required)` — a `<base>-external`
link is the cross-organizational variant of `<base>` (it terminates at
an `external-anchor` rather than an in-house artifact, but the
derivation still happened, it just crossed an org boundary), so it
satisfies a required `<base>` link-field. The cardinality count uses
it. The target-type check deliberately does NOT: a `derives-from-external`
link legitimately points at an `external-anchor`, which is not in the
base field's target-type list, and the existing exact-match filter
correctly skips it there.

Regression test: validate_accepts_derives_from_external_structured_target.
Verified: test_dogfood_validate still green; clippy -D warnings exit 0.

Implements: REQ-004
Verifies: REQ-064
Refs: FEAT-135
…drift to override (REQ-068)

`rivet supplier pull` was the only side of the federation handshake that
silently accepted changed supplier bytes — overwriting the cache and
exiting 0 with no DRIFT header — while `rivet validate` correctly refused
the same drift. A fetch was thus granting the supplier authority to revise
a delivered artifact with no audit trail.

Pull is now the authorisation point: it compares the new payload's sha256
against the prior recorded hash (the prior cache manifest's source-hash,
falling back to the anchor's stamped cited-source.sha256). On mismatch it
refuses — exit non-zero, naming the prior hash, the new hash, and the
supplier identity (org + contract) — and leaves the cache untouched. The
new --accept-drift flag is the explicit auditor authorisation path: it
overwrites the cache and re-stamps the anchor's cited-source. First pulls
and idempotent re-pulls of identical bytes are unaffected.

Implements: REQ-007
Verifies: REQ-068
Refs: FEAT-135
…75, REQ-076)

REQ-075: two artifacts declaring the same `id` collapsed silently —
`Store::upsert` is last-write-wins, so by the time `validate::validate`
runs only the survivor exists and the validator is structurally blind to
the collision. Extend the REQ-062 load-report channel: add a `LoadReport`
struct and `load_artifacts_with_report` that, alongside skipped files,
returns `DuplicateId` records detected at LOAD time where both copies are
still visible. `cmd_validate` loads every source, runs a project-wide
duplicate pass (`detect_duplicate_ids_for_validate`), and emits one Error
diagnostic per collision with `rule: duplicate-artifact-id` naming both
source files and the colliding ID. `load_artifacts`'s signature is
unchanged (rivet-core public API semver gate).

REQ-076: orphan artifacts (no inbound and no outbound links) were visible
to `rivet stats` but never to `rivet validate`. `cmd_validate` now reuses
`LinkGraph::orphans` — the exact computation behind `rivet stats` — and
emits one `rule: orphan-artifact` diagnostic per orphan. Severity is
Warning by default (a hard-error default would break Rivet's own dogfood,
which carries orphans) and is promoted to Error by a new `--strict-orphans`
flag, wired exactly like `--strict-cited-sources`.

`cmd_stats` now mirrors both rules into its diagnostic counts so `stats`
and `validate` stay consistent (`stats_json_counts_match_validate`). Both
new rules surface in the `--format json` `rule` field automatically.

Regression tests: `validate_detects_duplicate_artifact_ids` (two files
and twice-in-one-file) and `validate_reports_orphans_as_warnings`
(Warning default, Error under `--strict-orphans`).

Implements: REQ-004
Verifies: REQ-075, REQ-076
Refs: FEAT-135

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
REQ-075's new duplicate-artifact-id detection (in this same Wave-2
branch) immediately surfaced a genuine, pre-existing collision in
rivet's own artifacts/: `REQ-060` was declared twice —
  - artifacts/v040-verification.yaml:471 "Cross-platform binary support"
  - artifacts/v042-artifacts.yaml:393  "Every embed option must validate
                                        before the embed renders"
two unrelated requirements sharing one ID. Until now `Store::upsert`'s
last-write-wins silently kept only one and `rivet validate` reported
PASS — exactly the F2 silent-data-loss the cross-git investigation is
about. With REQ-075 shipped, `rivet validate` on the rivet repo itself
(pre-commit hook + CI) would FAIL on this collision.

Resolved by renaming the v042 entry to REQ-077 (the next free id). It
was the safe one to rename: zero inbound links anywhere in artifacts/,
zero mentions in docs/. The v040 REQ-060 keeps its id — its two inbound
links (v040-verification.yaml:125, :453) stay valid. The renamed
artifact's own outgoing links (verifies REQ-010, satisfies REQ-004) are
unchanged.

Also folds in `cargo fmt` of the cherry-pick-integrated cli_commands.rs
test block.

Implements: REQ-010
Refs: FEAT-135, REQ-075

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

📐 Rivet artifact delta

Change Count
Added 1
Removed 0
Modified 1
Downstream impacted (depth ≤ 5) 0

Graph

graph LR
  REQ_060["REQ-060"]:::modified
  REQ_077["REQ-077"]:::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
Loading
Added
  • REQ-077
Modified
ID Changes
REQ-060

📎 Full HTML dashboard attached as workflow artifact rivet-delta-pr-309download from the workflow run.

Posted by rivet-delta workflow. The graph shows only changed artifacts; open the HTML dashboard (above) for full context.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ 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: 4db7152 Previous: 0d98b7c Ratio
validate/10000 17999875 ns/iter (± 2513882) 13701860 ns/iter (± 1780687) 1.31

This comment was automatically generated by workflow using github-action-benchmark.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 21, 2026

Codecov Report

❌ Patch coverage is 21.56863% with 40 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
rivet-core/src/lib.rs 0.00% 40 Missing ⚠️

📢 Thoughts on this report? Let us know!

@avrabe avrabe merged commit ef5a855 into main May 21, 2026
17 of 39 checks passed
@avrabe avrabe deleted the feat/wave-2-p1-fixes branch May 21, 2026 04:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant