feat(modify): --where <s-expr> for query-driven bulk modify (REQ-141)#380
Merged
Conversation
…353) Bringing a real project's statuses in line with shipped code (bulk draft->implemented) had no first-class tool — only a shell loop of per-ID `rivet modify` calls, which #353 reported silently no-op'ing under redirection (a suspected reload/rewrite race between rapid-succession subprocesses). Add `rivet modify --where '<s-expr>' --set-*`: select every artifact matching the same s-expression filter `rivet query` uses and apply the change in a SINGLE in-process pass — load once, validate every target up front (all-or-nothing), then write each affected file once. No subprocess re-spawn, so it cannot race the way the shell loop could. - `--where` is mutually exclusive with a positional <ID> (clap-enforced). - `--dry-run` previews the match set, writes nothing. - An empty match set is a loud no-op ("no artifacts match the --where filter") so an agent never reads silence as success. - Reuses the existing `sexpr_eval` engine — no new filter dialect. Verified end-to-end on a scratch project (dry-run byte-identical, bulk apply flips only matches, empty-match no-op, ID+--where rejected). New `modify_where.rs` integration test (4 cases); clippy --all-targets + fmt clean; `rivet validate` PASS. Implements: REQ-141, REQ-007 Refs: REQ-141 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
📐 Rivet artifact delta
Graphgraph LR
REQ_141["REQ-141"]:::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
Added
Posted by |
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: f29cd39 | Previous: ab298f5 | Ratio |
|---|---|---|---|
store_lookup/100 |
2222 ns/iter (± 73) |
1664 ns/iter (± 4) |
1.34 |
store_lookup/1000 |
25996 ns/iter (± 128) |
19453 ns/iter (± 50) |
1.34 |
traceability_matrix/1000 |
61475 ns/iter (± 166) |
41005 ns/iter (± 99) |
1.50 |
query/100 |
749 ns/iter (± 1) |
612 ns/iter (± 3) |
1.22 |
query/1000 |
7376 ns/iter (± 33) |
5134 ns/iter (± 100) |
1.44 |
This comment was automatically generated by workflow using github-action-benchmark.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This was referenced Jun 2, 2026
avrabe
added a commit
that referenced
this pull request
Jun 2, 2026
…#382) The `modify --where` after_help examples I added in #380 used an invalid filter shorthand — `(type "requirement")` / `(status "draft")` — where the head symbol must be an operator, not the field name. Run verbatim they error with "unknown form 'type'/'status'". Corrected to the canonical `(= field "value")` form, both examples now run clean: rivet modify --where '(= status "draft")' --set-status implemented rivet modify --where '(and (= type "requirement") (= status "draft"))' … Verified both examples execute (dry-run) without a parse error. The broader discoverability gap (the parse error shows no example of the common field-equality form) is tracked in #381. Implements: REQ-141 Refs: REQ-007 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 2, 2026
avrabe
added a commit
that referenced
this pull request
Jun 2, 2026
…ke (#389) (#390) `graph_type_filter_renders_when_under_budget` fetched `/graph?types=requirement` with the default 5s read timeout. That endpoint does a BFS + layout over the dogfood corpus (~742 nodes / 1477 edges), which on a loaded CI runner can brush past 5s; `fetch_with_timeout` parses a timed-out/empty response's status as 0, so the timeout surfaced as `status == 0` and failed the `== 200` assertion. Same chronic flake the focus-graph tests already fixed with a 15s budget — this one test was missed. It falsely failed CI on #380, #387, and #388. Switch it to `fetch_with_timeout(..., 15s)`, matching the other graph endpoints. The test asserts on the response shape (SVG or budget message), not a hard latency bound, so the wider timeout is safe. Verified locally: passes 3/3 runs. Trace: skip Closes: #389 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
avrabe
added a commit
that referenced
this pull request
Jun 2, 2026
…REQ-151, #353) (#399) #353 feature ask: every invocation can emit WARN-level log lines before a command's real output (e.g. "could not load externals: …"), noise for scripted/agent consumption — especially with `--format json`. There was `-v/--verbose` to raise the log level but no way to lower it below the default `warn`. Add a global `-q/--quiet` (mutually exclusive with `--verbose`) that sets the log filter to `error`: the WARN preamble is suppressed while the command's own stdout and hard-error reporting stay intact. Pairs with `--format json` for clean machine-consumable output. Verified: on a project with a misconfigured external, default emits `[WARN rivet] could not load externals: …` but `--quiet` emits nothing on stderr and stdout still lists the artifact; a hard config error is still reported under `--quiet`. New `cli_commands::quiet_suppresses_warn_preamble` test; clippy --all-targets + fmt clean; rivet validate + docs check PASS. Also records (verified this iteration, no code needed): #353 part 3 (the "tight modify loop silently no-op'd" race) does NOT reproduce on current main — 90/90 rapid sequential `modify`s succeeded and persisted across 3 trials; superseded anyway by `modify --where` (#380). Implements: REQ-151 Refs: REQ-007 Co-authored-by: Claude Opus 4.8 (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.
What
Bringing a real project's requirement statuses in line with shipped code (the bulk
draft→implementedtask in #353) had no first-class tool — only a shell loop of per-IDrivet modifycalls, which the reporter found silently no-op'd under redirection (a suspected reload/rewrite race between rapid-succession subprocesses).rivet modify --where '<s-expr>' --set-*selects every artifact matching the same s-expression filterrivet queryuses and applies the change in a single in-process pass — load once, validate every target up front (all-or-nothing), then write each affected file once. No subprocess re-spawn, so it cannot race the way the shell loop could.--whereis mutually exclusive with a positional<ID>(clap-enforced).--dry-runpreviews the match set, writes nothing.no artifacts match the --where filter) — silence is never read as success.sexpr_evalengine — no new filter dialect (design on existing patterns).Verification
End-to-end on a scratch project: dry-run leaves files byte-identical; bulk apply flips only the matches (non-matches untouched) and prints
modified N artifacts; empty match → loud no-op;ID + --whererejected. Newrivet-cli/tests/modify_where.rs(4 cases, all green); clippy--all-targets+ fmt clean;rivet validate→ PASS.Triage context (#353)
This closes the bulk
--set-status/--wherefeature ask and addresses Part 3 (the racy shell loop) at its root — by removing the need for the loop entirely. Earlier parts of #353 were already handled: Part 1 (silent file-skip) by REQ-062, Part 4 (WARN noise) by #379/REQ-139. The remaining open item is the cross-command parse inconsistency filed as REQ-140 (maintainer design call).Implements: REQ-141
🤖 Generated with Claude Code