Repository navigation
Fix vlt scans re-parsing the lock per patch (#1570) - #1691
Conversation
Assisted-by: Claude Code:claude-opus-5-5
Hosted vlt scans split every vlt-lock.json node id (decode, semver and registry checks) once per patched package, three times over, and the artifact preflight parsed the whole lock again for each one. On a 1500-package lock with 30 patches that made vlt the slowest npm-family scan per package. The hosted lock now indexes its nodes once, by registry identity and by slot [1] name, and the preflight checks existing pins against the lock it already parsed. vlt/hosted and vlt/rescan get ~37% faster on the bench with the same results. Assisted-by: Claude Code:claude-opus-5-5
After splicing a patch into vlt-lock.json, the hosted rewrite re-reads the lock to confirm every instance carries the patched slots. It built the whole document as JSON for every patched package, which was a third of a 1500-package vlt scan. The check still parses every byte, so it refuses exactly what it did before, but it keeps only the nodes it is checking. vlt/hosted is now 47% and vlt/rescan 50% faster than main on the bench. Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
Its skipping parse is only sound on a lock the rewrite already read, so no other module should call it. Also stop copying each node's slot [1] into the index: the lookup key already is that name. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c4aa9f1. Configure here.
|
Labeled Ready for review (burn-down agent).
Generated by Claude Code |
|
Final review brief (head What it does: Hosted vlt scans re-split every Risk: low. Perf-only refactor of internal functions in Look here:
Verified: I read the full diff. Changes I made: none. Open questions: none. Auto-merge (squash) is armed, so approving sends this PR straight to the merge queue. Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1570
Summary
Hosted vlt scans did lock work once per patched package that only needs doing once per scan. This PR makes
vlt/hosted47% andvlt/rescan50% faster on the scan bench, with the same rewrite results.vlt/hostedvlt/rescan(
socket-patch-bench compare --runs 25 -f '^vlt/', interleaved pairs on one 4-vCPU runner, base =origin/main@aa69125.) The bench harness checks every run did the work the project calls for before keeping its timing, so the same lock edits are made on both sides.Root cause
For each npm override,
rewrite_dep(hosted rewrite) andpreflight_scope(artifact preflight) walked every node ofvlt-lock.json:partition_instances, the outside-registry check andhas_vendored_nodeeach calledsplit_dep_id(segment decode, semver and registry-identity checks) on every node id, i.e. up to 3 full walks per override in the rewrite plus 2 in the preflight.every_instance_pinnedre-parsed the whole lock text into aserde_json::Valueonce per override in the preflight (on the unchanged lock) and once per override in the rewrite's residual gate (on the spliced candidate). With the index in place, callgrind showed this gate alone at 35% of all instructions (27.8% parse + 7.8% dropping the tree).Fix
NodeIndex(built once inparse_hosted_lock): every node id is split once; registry nodes are indexed by(name, version)and git/file/remote nodes by slot [1].partition_instances,outside_instances(new, extracted),has_vendored_nodeand the lock-leveldiscarding_lock_codesread from it. Lock key order is kept (positions ascend), and ids that don't split are left out, exactly as before (they matched nothing).already_pinnedagainst the lock it already parsed (sniff_lockuses the sameserde_json::from_str) instead of parsing the text again.parse_nodes_ofparses the whole candidate with a serde visitor that keeps only the nodes being checked and skips (IgnoredAny) everything else. Broken JSON anywhere is still refused, and the lastnodes/ last duplicate key still win, as withValue. Skipping does not range-check numbers or pair\usurrogates in skipped values; the candidate is a locksniff_lockalready parsed whole, with only node lines re-rendered, so this can't change a verdict (documented on the function).Tests
the_node_index_matches_a_scan_of_every_node: on a mixed lock (both DepID eras, a foreign named registry, peer extras, git/remote/file/vendored/workspace nodes, an undecodable id), the index gives the same defaults, foreign, outside and vendored answers in the same order as the old per-node scan, for 4 identities.the_gate_parse_matches_a_full_value_parse: 23 documents (duplicatenodes, duplicate keys, escaped keys, non-objectnodesof every JSON type, broken JSON elsewhere in the document, trailing garbage, trailing comma, invalid escape, truncated, non-object top level, empty) give the same result as the oldValueparse./code-review high: no correctness findings. Taken: the gate is now private to the rewrite (its skipping parse is only sound on sniffed text) and the index no longer copies slot [1]. Not taken, with reason: avoiding the per-override line clone/join in the gate (the join is needed for the whole-document check that catches duplicatenodessections), reusing the index's split for the ledgerextraand allocation-free(name, version)lookups (one split / two small allocations per instance, not per node), and sharing oneHostedLockbetween preflight and rewrite (a wider API change acrosshosted::vlt::plan).residual_gate_refuses_when_the_parsed_node_is_not_the_spliced_line) pass unchanged.For a perf fix, the red→green evidence is the bench table above (main vs. this branch, same machine, interleaved).
Local runs
cargo fmt --all -- --check: okcargo clippy --workspace --all-features -- -D warnings: okcargo test --workspace --all-features: 234 suites ok. 10 tests in 4 targets fail only because this sandbox runs as root: theychmoda dir to0o555and expect a write or remove to fail (vlt_healunremovable hidden lock,copy_treesymlinked root, poetry/requirements wire-write failure,in_process_redirectwrite failures,repairunremovable lock). The other one,e2e_bun_lockb::binary_shared_bundled_record_hosted_pin_is_managed, fails the same way with this PR'spatch/redirect/reverted to main, so it is environmental too. None of these run vlt hosted code that this PR changes.e2e_redirect_vlt_build, vlt 1.2.0): not runnable here. Its harness fetches packages from npmjs with reqwest's webpki roots, which don't trust this sandbox's TLS proxy. CI's vlt leg covers it:e2e (ubuntu-latest, e2e_redirect_vlt_build, 1.2.0)passed onc4aa9f1.Checklist
NodeIndex,already_pinned,parse_nodes_of); bench -47% / -50%.No wrapper (
npm/,pypi/,gem/) changes are needed: this is internal to the core hosted rewriter.https://claude.ai/code/session_01FKVp3SxTz9Nyp97dCtuR2r
Generated by Claude Code