Scanner rules without an API key
rvl scan now does something useful before you have a key.
The rules ship in two tiers. The commercial artifact is unchanged, byte for byte. Alongside it there is a second artifact holding the vocabulary lanes, the parts of the ruleset that describe what a construct in your code is rather than whether it is a problem: server and client kinds, emission shapes, configuration keys. That tier carries CDLA-Permissive-2.0 in its envelope and is served unauthenticated.
The CLI syncs the OSS tier into its own store, and when you do have a key the commercial tier layers over it rather than replacing it. rvl cache status reports both.
Judgment lanes, judgments, default bounds, blocking intent and sentinels are structurally absent from the OSS artifact rather than filtered out of it, but exist in the commercial set.
What changes if you already have a key
Nothing about what your scans report. The one behavior change is the exit contract: rvl scan now exits 1 only when neither tier can be loaded, where before it exited 1 when the commercial tier was unavailable. A scan that used to refuse to run in that state now runs against vocabulary rules and tells you which tier it used.
Retired knowledge stops outranking current knowledge
Incident pages, risk citations and the data-lake export now show current knowledge instead of facts the pipeline had already retired.
The pipeline has marked facts, patterns and procedures as superseded since re-extraction and CAST re-observation were introduced, but some read paths kept returning retired rows.
The filter is now applied on almost all read paths. Four deliberately still see retired rows, because of legitimate need, and each says so in the code now. A check runs on every commit so a new read path cannot quietly reintroduce the problem.
Similar findings stop being merged into each other
Two defects meant the knowledge graph was comparing CAST findings on the wrong text and then merging them without keeping what each one was evidence for.
Every signal embedded its rendered template rather than its payload. Ranking was never affected, because a constant prefix shifts every pair alike. What was affected was every absolute threshold calibrated against the squeezed range, including the one governing merges.
Twin-merge then discarded provenance. Only 0.5 to 2.6% of near-duplicate pairs share a source, so a merge at that threshold was collapsing findings drawn from different incidents and attributing the survivor to just one of them. Merges now union provenance, so a combined finding still points at every incident that produced it.
Separately, we fixed a bug where CAST extraction didn’t carry a risk control. Only 107 of 61,870 CAST facts carried a control code, because the model was correctly abstaining from selection.
Findings go to the service you declared
A scan can no longer file its findings into a service you did not name.
A scan carried two independent service-naming channels and nothing cross-checked them. When services declared in a flag and via config disagree, the submission created a catalog entry under the declared name and filed its risks into the other service’s register.
Both halves are fixed. The CLI derives finding attribution from the declared service, falling back to the config project when --service is absent. The server rejects an incoherent submission with a 400 that names the offending findings, lists every foreign service and carries the service it believes you meant, and the check runs before the catalog upsert so a rejected submission doesn’t submit flawed data.
Fixes
- You can create risks past
R-999. An org that reached its thousandth risk code could not create another one at all; codes now grow without a ceiling. find_similar_incidentsover MCP returns results instead ofUPSTREAM_ERROR. The error was swallowed, so hybrid search had quietly been running two of its three legs.- The grouped Teams and Services posture view loads instead of hanging on a skeleton when a registry team has no mapped risks.
- Reindexing the corpus re-runs knowledge extraction instead of flooding the dead-letter queue. The re-emit had been writing to the wrong input stream.
- SendGrid status is read from Twilio’s Statuspage feed.
status.sendgrid.comwas deactivated around 2026-08-12 and had been failing crawls for several days. - Crawler bronze writes dedupe per page and stop deleting content when the metadata write fails. One page with 28 links wrote the same object 28 times in six seconds.
- Uploaded documents go through the same chunker as the incident corpus, so search over your uploads behaves like search over everything else.
goindexstops reporting adefer f(&tok, &err)helper as a swallowed error. That is the idiom the named-result check already accepted, one indirection away.- A scan carrying the skill’s
provenancestring submits instead of failing with a 400, and the engine document no longer rides along as an unmapped extra finding set. - Trial enforcement counts documents against a column that exists, and owner-email lookup failures surface instead of being reported as a missing owner.
- A polynomial backtracking case in the TypeScript indexer’s trailing-slash trim is rewritten to the anchored form. Behavior is unchanged.
Improvements
- The Scan Coverage page distinguishes a repo that assigns ownership per component from one nobody has claimed, with a badge naming the owning teams and a link to their registers.
rvl feedbackis rate limited to 5 a minute per user, with size caps on the body and attached diagnostics. Oversize returns 413, throttled returns 429 withRetry-After.- Continuous distillation runs in production, and no longer re-clusters facts it already fused or compares every pair to find neighbours.
- The rvl documentation is reorganized around a scanning guide: install, the no-key tier, reading output, exit codes, hooks, suppression, and what does and does not leave your machine.
- The production spec-signing key is pinned in the CLI alongside the development key, so caches signed by either keep verifying.
- Both cache fetchers time out after 30 seconds. They had none, so a black-holed network hung instead of degrading.
Breaking
rvl scanexits1only when no rule tier can be loaded, rather than when the commercial tier specifically is unavailable. With the OSS tier reachable without a key, a scan that would previously have refused to run now runs against vocabulary rules.0,2and3are unchanged.- A scan whose findings reference a service other than the one it declares is rejected with a 400
service_scope_mismatch, closing a path that filed risks into another real service’s register. Nothing changes if you omit--service, the common path. Upgrade torvl1.1.0 first, since it derives attribution from the declared service. If you do hit it, resubmit the same scan directory; the findings are unchanged and still on disk.