You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Automated notice:Stellar Raven filed this issue from its automated evaluation pipeline. The issue includes evidence and a public source record. Please verify the live surface before you act.
Finding
searchConnectors in @cloudflare/codemode returns connector methods that share no real word with
the query. scoreField accepts a prefix match in both directions: field.tokens.some((c) => c.startsWith(token) || token.startsWith(c)).
With token.startsWith(c), a one- or two-character field token matches every query token that starts
with it. Such tokens include articles such as a and fragments from tokenize, such as s from city's and re from re-billed. Each match counts toward the coverage gate and the full-coverage bonus.
Evidence
Reproduction at main commit 16b6856070f6c711486011b8b9dd926c2eaae52b, with two unrelated connectors
(weather.getForecast and billing.refundInvoice):
Descriptions
Query
Result
Return a city's forecast. / Refund a re-billed invoice.
send slack message
weather.getForecast 27
same
read repository readme
billing.refundInvoice 55
Return the forecast for a city. / Refund an invoice billed twice.
add alarm
weather.getForecast 45
same
archive all tasks
weather.getForecast 27
Return the city forecast. / Refund duplicate invoice.
all four queries
no results
Return a city's forecast. / Refund a re-billed invoice.
city forecast, refund invoice
153, 481
The rule is unchanged in 0.4.2, 0.5.1, 0.5.2, and current main. No test file exists for connectors/search.ts at main.
Reproduce
Requires Node.js with TypeScript type stripping (tested on v24.13.0). No install is needed.
import{searchConnectors}from"./search.ts";constconnectors=(weather,billing)=>[{name: "weather",descriptors: {getForecast: {description: weather}}},{name: "billing",descriptors: {refundInvoice: {description: billing}}}];constcases=[["punctuation fragment","Return a city's forecast.","Refund a re-billed invoice.",["send slack message","read repository readme"]],["one-letter word","Return the forecast for a city.","Refund an invoice billed twice.",["add alarm","archive all tasks"]],["control: no 1-2 char tokens","Return the city forecast.","Refund duplicate invoice.",["send slack message","read repository readme","add alarm","archive all tasks"]],["sanity: intended queries","Return a city's forecast.","Refund a re-billed invoice.",["city forecast","refund invoice"]]];for(const[label,weather,billing,queries]ofcases){for(constqueryofqueries){const{ results }=searchConnectors(query,connectors(weather,billing));console.log(`${label} | ${JSON.stringify(query)} ->`,JSON.stringify(results.map((r)=>[r.path,r.score])));}}
Run node repro.mjs. Output:
punctuation fragment | "send slack message" -> [["weather.getForecast",27]]
punctuation fragment | "read repository readme" -> [["billing.refundInvoice",55]]
one-letter word | "add alarm" -> [["weather.getForecast",45]]
one-letter word | "archive all tasks" -> [["weather.getForecast",27]]
control: no 1-2 char tokens | "send slack message" -> []
control: no 1-2 char tokens | "read repository readme" -> []
control: no 1-2 char tokens | "add alarm" -> []
control: no 1-2 char tokens | "archive all tasks" -> []
sanity: intended queries | "city forecast" -> [["weather.getForecast",153]]
sanity: intended queries | "refund invoice" -> [["billing.refundInvoice",481]]
How the false matches score:
read repository readme: all three query tokens match the field token re. Coverage is 3/3, so
the score is 3 × 10 + 25 = 55.
add alarm: both query tokens match the field token a. Coverage is 2/2, which passes the
strict two-token gate, and the result gets the full-coverage bonus.
send slack message: send and slack match s. Coverage is 2/3, which passes the 0.6 gate.
(main, 2026-09-17). The same rule is at line 68 in tags @cloudflare/codemode@0.4.2 (062611d), 0.5.1 (f089c5b), and 0.5.2 (5f7ad7e).
2026-09-17T01:46Z local reproduction against the pinned main search.ts with Node v24.13.0 type stripping. Unrelated queries return weather.getForecast (27, 45, 27) or billing.refundInvoice (55). Controls without 1-2 character field tokens return no results. Intended queries still match (153, 481).
The published dist/index.js search regions of 0.4.2, 0.5.1, and 0.5.2 return the same false matches; the 0.5.1 and 0.5.2 regions are byte-identical.
Raven impact: src/catalog/vendor/search-scoring.ts:85 (adapted from 0.4.2) and the ungated replica at src/catalog/scoring.ts:474 carry the same rule. On one Raven routing control, the vendor gate matched 15 of 25 query tokens (coverage 0.6, the threshold). The reverse match actually→a supplied the deciding token; without it, coverage is 14/25 and the gate fails.
research/audits/2026-09-17-routing-audit/upstream-prefix-review.md records the commits, reproduction, ownership, and dedupe search.
research/audits/2026-09-17-routing-audit/scorer-followup-plan.md and porter-stem-experiment.md record the Raven-side ablations. Removing only the reverse prefix direction also removed query-side word forms such as forecasts→forecast.
Stop short field tokens and punctuation fragments from satisfying the coverage gate for unrelated query
words. Keep intended matches and regular query-side word forms. Raven measured that removing only token.startsWith(c) also drops matches such as forecasts → forecast. Add regression tests with the
unrelated queries, the controls, and the intended queries above.
Source Record
Raven recorded this finding as cs-001 (canonical-source, discovered 2026-09-17).
Include the finding ID and the resolving issue or pull request.
Include the deployed version or timestamp. Include the smallest live recheck.
Raven verifies the live surface before it sets the finding to fixed-upstream.
An issue closure or merged pull request does not prove the fix.
A separate reviewer repeats the live check before Raven retires the active finding.
Raven keeps a commit-pinned snapshot when one is available.
Note
Automated notice: Stellar Raven filed this issue from its automated evaluation pipeline. The issue includes evidence and a public source record. Please verify the live surface before you act.
Finding
searchConnectorsin@cloudflare/codemodereturns connector methods that share no real word withthe query.
scoreFieldaccepts a prefix match in both directions:field.tokens.some((c) => c.startsWith(token) || token.startsWith(c)).With
token.startsWith(c), a one- or two-character field token matches every query token that startswith it. Such tokens include articles such as
aand fragments fromtokenize, such assfromcity'sandrefromre-billed. Each match counts toward the coverage gate and the full-coverage bonus.Evidence
Reproduction at
maincommit16b6856070f6c711486011b8b9dd926c2eaae52b, with two unrelated connectors(
weather.getForecastandbilling.refundInvoice):Return a city's forecast./Refund a re-billed invoice.send slack messageweather.getForecast27read repository readmebilling.refundInvoice55Return the forecast for a city./Refund an invoice billed twice.add alarmweather.getForecast45archive all tasksweather.getForecast27Return the city forecast./Refund duplicate invoice.Return a city's forecast./Refund a re-billed invoice.city forecast,refund invoiceThe rule is unchanged in 0.4.2, 0.5.1, 0.5.2, and current
main. No test file exists forconnectors/search.tsatmain.Reproduce
Requires Node.js with TypeScript type stripping (tested on v24.13.0). No install is needed.
Download the file at the tested commit:
Create
repro.mjs:Run
node repro.mjs. Output:How the false matches score:
read repository readme: all three query tokens match the field tokenre. Coverage is 3/3, sothe score is 3 × 10 + 25 = 55.
add alarm: both query tokens match the field tokena. Coverage is 2/2, which passes thestrict two-token gate, and the result gets the full-coverage bonus.
send slack message:sendandslackmatchs. Coverage is 2/3, which passes the 0.6 gate.Additional recorded evidence:
agents/packages/codemode/src/connectors/search.ts
Lines 66 to 71 in 16b6856
Recommendation
Stop short field tokens and punctuation fragments from satisfying the coverage gate for unrelated query
words. Keep intended matches and regular query-side word forms. Raven measured that removing only
token.startsWith(c)also drops matches such asforecasts→forecast. Add regression tests with theunrelated queries, the controls, and the intended queries above.
Source Record
Raven recorded this finding as cs-001 (canonical-source, discovered 2026-09-17).
Public source record: improvements/canonical-source/cs-001-codemode-search-short-token-prefix.md
Immutable source snapshot: c6968e741239
Resolution Handoff
When you deploy a fix, link the resolving issue or pull request to the source record.
Then notify Raven through:
https://github.com/stellar-experimental/stellar-raven/issues/new?template=upstream-improvement-ready.yml&title=%5Bupstream-ready%5D%20cs-001%3A%20
Include the finding ID and the resolving issue or pull request.
Include the deployed version or timestamp. Include the smallest live recheck.
Raven verifies the live surface before it sets the finding to
fixed-upstream.An issue closure or merged pull request does not prove the fix.
A separate reviewer repeats the live check before Raven retires the active finding.
Raven keeps a commit-pinned snapshot when one is available.