Skip to content

fix(modify): insert new base fields after trailing block mappings, not inside#600

Merged
avrabe merged 1 commit into
mainfrom
fix/set-field-insert-before-block
Jun 26, 2026
Merged

fix(modify): insert new base fields after trailing block mappings, not inside#600
avrabe merged 1 commit into
mainfrom
fix/set-field-insert-before-block

Conversation

@avrabe

@avrabe avrabe commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

P0 — write-path corruption in released v0.21.0

rivet modify --set-release (and any set_field that inserts a new base field) corrupts an artifact whose last field is a block mapping — most importantly provenance:, which every AI-stamped artifact has. The new key is spliced between provenance: and its children:

    provenance:
    release: v0.22.0        # ← invalid YAML: splits the block
      created-by: ai-assisted
      model: claude-opus-4-8

→ the file fails to parse → the artifact (and its file-mates) vanish on reload. Same class as #573, this time in the #516 release-field setter shipped in v0.21.0.

Root cause

find_insert_position treats provenance: as a base field but measured its extent with block_scalar_end, which only skips block scalars (|/>), not nested block mappings. So "after the last base field" landed right after the provenance: line — inside its block.

Fix

Add field_block_end, which consumes a field's full on-disk extent including nested block-mapping children, and use it in find_insert_position. The inserted field now lands after the whole block.

How it surfaced

Dogfooding: I ran a real rivet modify --set-release v0.22.0 on rivet's own provenance-stamped requirements.yaml while planning v0.22 — and it corrupted the file. Exactly the friction the methodology is meant to catch.

Verification

  • New regression test set_field_inserts_after_trailing_provenance_block: was RED (parse failure), now GREEN — output parses, release set, provenance block intact.
  • All 33 yaml_edit tests pass; fmt + clippy clean.

Fixes #573-adjacent corruption in the release-field setter. Recommend a v0.21.1 patch since --set-release on any provenance-stamped artifact corrupts it.

🤖 Generated with Claude Code

…t inside

`rivet modify --set-release` (and any `set_field` inserting a NEW base field)
corrupted the artifact when its last field was a block MAPPING — e.g.
`provenance:` with `created-by`/`model` children, which every AI-stamped
artifact has. `find_insert_position` treated `provenance:` as a base field but
used `block_scalar_end` to find its extent, which only skips block *scalars*
(`|`/`>`), not nested mappings. The new key was spliced BETWEEN `provenance:`
and its children:

    provenance:
    release: v0.22.0        # <- invalid: splits the block
      created-by: ai-assisted

making the file unparseable so the artifact vanished on reload (a #573-class
write-path corruption, in the #516 release-field setter).

Fix: add `field_block_end`, which consumes a field's full extent including
nested block-mapping children, and use it in `find_insert_position`. The new
field now lands AFTER the whole block.

Surfaced by dogfooding the release field while planning v0.22 (a real
`--set-release` on rivet's own provenance-stamped requirements.yaml corrupted
it). Regression test added; affects released v0.21.0 → warrants a v0.21.1 patch.

Fixes: REQ-004
Verifies: REQ-004
@github-actions

Copy link
Copy Markdown

📐 Rivet artifact delta

No artifact changes in this PR. Code-only changes (renderer, CLI wiring, tests) don't touch the artifact graph.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

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: d784881 Previous: 11db466 Ratio
store_lookup/1000 24987 ns/iter (± 39) 19362 ns/iter (± 110) 1.29
validate/10000 1119785830 ns/iter (± 33988932) 914370645 ns/iter (± 5183624) 1.22
diff/1000 726155 ns/iter (± 9442) 590833 ns/iter (± 3936) 1.23
query/100 1301 ns/iter (± 23) 837 ns/iter (± 4) 1.55
query/1000 15243 ns/iter (± 170) 11489 ns/iter (± 47) 1.33

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

@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.82609% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
rivet-core/src/yaml_edit.rs 97.82% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@avrabe

avrabe commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Merging past the single Kani Proofs failure — exit 143 (SIGTERM during the Kani build, the #567/#590 resource kill; no proof runs). Diff is rivet-core/src/yaml_edit.rs only (does not touch proofs.rs). All other gates pass; 33 yaml_edit tests green incl. the new regression, fmt + clippy clean. Empty required-contexts.

@avrabe avrabe merged commit f489a91 into main Jun 26, 2026
28 of 29 checks passed
@avrabe avrabe deleted the fix/set-field-insert-before-block branch June 26, 2026 17:33
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.

friction: modify --set-field corrupts flow-style fields: {...} maps (file becomes unparseable, artifacts silently vanish)

1 participant