Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions adapters/antigravity/cli/scripts/stash.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8251,7 +8251,7 @@ async function acquireLock(lockPath) {
}

// src/internal/search.ts
var ROUTING_PROFILE_VERSION = 3;
var ROUTING_PROFILE_VERSION = 4;
var FIELD_WEIGHTS = {
name: 6,
alias: 6,
Expand Down Expand Up @@ -8351,6 +8351,7 @@ function scoreRecord(prepared, totalRecords, frequenciesByDocument, queryTerms)
let score = 0;
const matchedTerms = /* @__PURE__ */ new Set();
const matchedKinds = /* @__PURE__ */ new Set();
const descriptionMatchedTerms = /* @__PURE__ */ new Set();
const reasons = [];
const seenReason = /* @__PURE__ */ new Set();
for (const field of prepared.fields) {
Expand All @@ -8368,6 +8369,9 @@ function scoreRecord(prepared, totalRecords, frequenciesByDocument, queryTerms)
score += termIdf * (weightedTf * 2.2 / (weightedTf + 1.2));
matchedTerms.add(term);
matchedKinds.add(field.kind);
if (field.kind === "description") {
descriptionMatchedTerms.add(term);
}
if (field.kind !== "group") {
const reasonKey = `${field.kind}:${term}`;
if (!seenReason.has(reasonKey)) {
Expand All @@ -8378,7 +8382,13 @@ function scoreRecord(prepared, totalRecords, frequenciesByDocument, queryTerms)
}
}
score *= negativePenalty(prepared.record, queryTerms);
return { score, matchedTerms, matchedKinds, reasons };
return {
score,
matchedTerms,
matchedKinds,
descriptionMatchedTerms,
reasons
};
}
function normalizedTerms(value) {
const normalized = normalizeText(value);
Expand Down Expand Up @@ -8444,7 +8454,7 @@ function classifyCandidate(prepared, totalRecords, frequenciesByDocument, query,
reasons: phrase.reason ? [phrase.reason, ...scored.reasons].slice(0, 8) : scored.reasons.slice(0, 8)
};
}
const denseDescriptionEvidence = scored.matchedTerms.size >= 3 && scored.matchedKinds.size === 1 && scored.matchedKinds.has("description");
const denseDescriptionEvidence = scored.descriptionMatchedTerms.size >= 3;
const materialEvidence = scored.matchedTerms.size >= 2 && scored.matchedKinds.size >= 2 && highPriorityMatch(scored.matchedKinds) || denseDescriptionEvidence || queryTerms.length === 1 && highPriorityMatch(scored.matchedKinds) && !(scored.matchedKinds.size === 1 && scored.matchedKinds.has("description"));
const evidenceAdjustedThreshold = denseDescriptionEvidence ? materialScoreThreshold * 0.58 : scored.matchedTerms.size >= 2 && scored.matchedKinds.size >= 2 && highPriorityMatch(scored.matchedKinds) ? materialScoreThreshold * 0.75 : materialScoreThreshold;
if (materialEvidence && scored.score >= evidenceAdjustedThreshold) {
Expand Down
16 changes: 13 additions & 3 deletions adapters/antigravity/ide/skills/stash/scripts/stash.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8251,7 +8251,7 @@ async function acquireLock(lockPath) {
}

// src/internal/search.ts
var ROUTING_PROFILE_VERSION = 3;
var ROUTING_PROFILE_VERSION = 4;
var FIELD_WEIGHTS = {
name: 6,
alias: 6,
Expand Down Expand Up @@ -8351,6 +8351,7 @@ function scoreRecord(prepared, totalRecords, frequenciesByDocument, queryTerms)
let score = 0;
const matchedTerms = /* @__PURE__ */ new Set();
const matchedKinds = /* @__PURE__ */ new Set();
const descriptionMatchedTerms = /* @__PURE__ */ new Set();
const reasons = [];
const seenReason = /* @__PURE__ */ new Set();
for (const field of prepared.fields) {
Expand All @@ -8368,6 +8369,9 @@ function scoreRecord(prepared, totalRecords, frequenciesByDocument, queryTerms)
score += termIdf * (weightedTf * 2.2 / (weightedTf + 1.2));
matchedTerms.add(term);
matchedKinds.add(field.kind);
if (field.kind === "description") {
descriptionMatchedTerms.add(term);
}
if (field.kind !== "group") {
const reasonKey = `${field.kind}:${term}`;
if (!seenReason.has(reasonKey)) {
Expand All @@ -8378,7 +8382,13 @@ function scoreRecord(prepared, totalRecords, frequenciesByDocument, queryTerms)
}
}
score *= negativePenalty(prepared.record, queryTerms);
return { score, matchedTerms, matchedKinds, reasons };
return {
score,
matchedTerms,
matchedKinds,
descriptionMatchedTerms,
reasons
};
}
function normalizedTerms(value) {
const normalized = normalizeText(value);
Expand Down Expand Up @@ -8444,7 +8454,7 @@ function classifyCandidate(prepared, totalRecords, frequenciesByDocument, query,
reasons: phrase.reason ? [phrase.reason, ...scored.reasons].slice(0, 8) : scored.reasons.slice(0, 8)
};
}
const denseDescriptionEvidence = scored.matchedTerms.size >= 3 && scored.matchedKinds.size === 1 && scored.matchedKinds.has("description");
const denseDescriptionEvidence = scored.descriptionMatchedTerms.size >= 3;
const materialEvidence = scored.matchedTerms.size >= 2 && scored.matchedKinds.size >= 2 && highPriorityMatch(scored.matchedKinds) || denseDescriptionEvidence || queryTerms.length === 1 && highPriorityMatch(scored.matchedKinds) && !(scored.matchedKinds.size === 1 && scored.matchedKinds.has("description"));
const evidenceAdjustedThreshold = denseDescriptionEvidence ? materialScoreThreshold * 0.58 : scored.matchedTerms.size >= 2 && scored.matchedKinds.size >= 2 && highPriorityMatch(scored.matchedKinds) ? materialScoreThreshold * 0.75 : materialScoreThreshold;
if (materialEvidence && scored.score >= evidenceAdjustedThreshold) {
Expand Down
16 changes: 13 additions & 3 deletions adapters/claude-code/skills/stash/scripts/stash.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8251,7 +8251,7 @@ async function acquireLock(lockPath) {
}

// src/internal/search.ts
var ROUTING_PROFILE_VERSION = 3;
var ROUTING_PROFILE_VERSION = 4;
var FIELD_WEIGHTS = {
name: 6,
alias: 6,
Expand Down Expand Up @@ -8351,6 +8351,7 @@ function scoreRecord(prepared, totalRecords, frequenciesByDocument, queryTerms)
let score = 0;
const matchedTerms = /* @__PURE__ */ new Set();
const matchedKinds = /* @__PURE__ */ new Set();
const descriptionMatchedTerms = /* @__PURE__ */ new Set();
const reasons = [];
const seenReason = /* @__PURE__ */ new Set();
for (const field of prepared.fields) {
Expand All @@ -8368,6 +8369,9 @@ function scoreRecord(prepared, totalRecords, frequenciesByDocument, queryTerms)
score += termIdf * (weightedTf * 2.2 / (weightedTf + 1.2));
matchedTerms.add(term);
matchedKinds.add(field.kind);
if (field.kind === "description") {
descriptionMatchedTerms.add(term);
}
if (field.kind !== "group") {
const reasonKey = `${field.kind}:${term}`;
if (!seenReason.has(reasonKey)) {
Expand All @@ -8378,7 +8382,13 @@ function scoreRecord(prepared, totalRecords, frequenciesByDocument, queryTerms)
}
}
score *= negativePenalty(prepared.record, queryTerms);
return { score, matchedTerms, matchedKinds, reasons };
return {
score,
matchedTerms,
matchedKinds,
descriptionMatchedTerms,
reasons
};
}
function normalizedTerms(value) {
const normalized = normalizeText(value);
Expand Down Expand Up @@ -8444,7 +8454,7 @@ function classifyCandidate(prepared, totalRecords, frequenciesByDocument, query,
reasons: phrase.reason ? [phrase.reason, ...scored.reasons].slice(0, 8) : scored.reasons.slice(0, 8)
};
}
const denseDescriptionEvidence = scored.matchedTerms.size >= 3 && scored.matchedKinds.size === 1 && scored.matchedKinds.has("description");
const denseDescriptionEvidence = scored.descriptionMatchedTerms.size >= 3;
const materialEvidence = scored.matchedTerms.size >= 2 && scored.matchedKinds.size >= 2 && highPriorityMatch(scored.matchedKinds) || denseDescriptionEvidence || queryTerms.length === 1 && highPriorityMatch(scored.matchedKinds) && !(scored.matchedKinds.size === 1 && scored.matchedKinds.has("description"));
const evidenceAdjustedThreshold = denseDescriptionEvidence ? materialScoreThreshold * 0.58 : scored.matchedTerms.size >= 2 && scored.matchedKinds.size >= 2 && highPriorityMatch(scored.matchedKinds) ? materialScoreThreshold * 0.75 : materialScoreThreshold;
if (materialEvidence && scored.score >= evidenceAdjustedThreshold) {
Expand Down
16 changes: 13 additions & 3 deletions adapters/codex/skills/stash/scripts/stash.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8251,7 +8251,7 @@ async function acquireLock(lockPath) {
}

// src/internal/search.ts
var ROUTING_PROFILE_VERSION = 3;
var ROUTING_PROFILE_VERSION = 4;
var FIELD_WEIGHTS = {
name: 6,
alias: 6,
Expand Down Expand Up @@ -8351,6 +8351,7 @@ function scoreRecord(prepared, totalRecords, frequenciesByDocument, queryTerms)
let score = 0;
const matchedTerms = /* @__PURE__ */ new Set();
const matchedKinds = /* @__PURE__ */ new Set();
const descriptionMatchedTerms = /* @__PURE__ */ new Set();
const reasons = [];
const seenReason = /* @__PURE__ */ new Set();
for (const field of prepared.fields) {
Expand All @@ -8368,6 +8369,9 @@ function scoreRecord(prepared, totalRecords, frequenciesByDocument, queryTerms)
score += termIdf * (weightedTf * 2.2 / (weightedTf + 1.2));
matchedTerms.add(term);
matchedKinds.add(field.kind);
if (field.kind === "description") {
descriptionMatchedTerms.add(term);
}
if (field.kind !== "group") {
const reasonKey = `${field.kind}:${term}`;
if (!seenReason.has(reasonKey)) {
Expand All @@ -8378,7 +8382,13 @@ function scoreRecord(prepared, totalRecords, frequenciesByDocument, queryTerms)
}
}
score *= negativePenalty(prepared.record, queryTerms);
return { score, matchedTerms, matchedKinds, reasons };
return {
score,
matchedTerms,
matchedKinds,
descriptionMatchedTerms,
reasons
};
}
function normalizedTerms(value) {
const normalized = normalizeText(value);
Expand Down Expand Up @@ -8444,7 +8454,7 @@ function classifyCandidate(prepared, totalRecords, frequenciesByDocument, query,
reasons: phrase.reason ? [phrase.reason, ...scored.reasons].slice(0, 8) : scored.reasons.slice(0, 8)
};
}
const denseDescriptionEvidence = scored.matchedTerms.size >= 3 && scored.matchedKinds.size === 1 && scored.matchedKinds.has("description");
const denseDescriptionEvidence = scored.descriptionMatchedTerms.size >= 3;
const materialEvidence = scored.matchedTerms.size >= 2 && scored.matchedKinds.size >= 2 && highPriorityMatch(scored.matchedKinds) || denseDescriptionEvidence || queryTerms.length === 1 && highPriorityMatch(scored.matchedKinds) && !(scored.matchedKinds.size === 1 && scored.matchedKinds.has("description"));
const evidenceAdjustedThreshold = denseDescriptionEvidence ? materialScoreThreshold * 0.58 : scored.matchedTerms.size >= 2 && scored.matchedKinds.size >= 2 && highPriorityMatch(scored.matchedKinds) ? materialScoreThreshold * 0.75 : materialScoreThreshold;
if (materialEvidence && scored.score >= evidenceAdjustedThreshold) {
Expand Down
4 changes: 3 additions & 1 deletion benchmarks/routing-golden.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
{"id":"broad-generic-term","kind":"search","query":"design","expectedRelevant":["design-game-encounters","design-system"]}
{"id":"short-ui-term-respects-boundaries","kind":"search","query":"ui","expectedRelevant":["design-system","ui-craft"]}
{"id":"short-go-term-abstains","kind":"search","query":"go","expectedRelevant":[]}
{"id":"dense-description-three-term-material","kind":"search","query":"generate voice audio","expectedRelevant":["elevenlabs-tts"]}
{"id":"dense-description-three-term-material","kind":"search","query":"generate voice audio","expectedRelevant":["elevenlabs-tts"],"expectedPossible":["media-options-guide","narration-workflows","recording-cleanup","waveform-previews"]}
{"id":"dense-description-overlap-is-monotonic","kind":"search","query":"synthesize timbre cadence","expectedRelevant":["cadence-synthesizer","timbre-synthesizer"],"expectedPossible":["discouraged-synthesizer","synthesis-previews"]}
{"id":"dense-description-overlap-no-match","kind":"search","query":"synthesize quantum fragrance","expectedRelevant":[]}
{"id":"typo-fallback","kind":"search","query":"security-audi","expectedRelevant":["security-audit"]}
{"id":"negative-example-demotion","kind":"search","query":"database migration review","expectedRelevant":["api-contract-review","database-migration-review"],"expectedFirst":"database-migration-review"}
{"id":"source-id-discovers-all","kind":"search","query":"mengto","expectedRelevant":["create-brand-world","design-game-encounters"]}
Expand Down
6 changes: 3 additions & 3 deletions docs/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ It never invokes natural-language reranking.

## Discovery

Current routing profile: `3`.
Current routing profile: `4`.

Discovery uses BM25F-style scoring with initial weights:

Expand All @@ -40,8 +40,8 @@ A score alone cannot make a result relevant. The evidence gate also requires:

- whole-term phrase evidence in name/alias; or
- multiple query terms across multiple fields with a high-priority field; or
- at least three query terms in a description, above the dense-description
threshold; or
- at least three distinct query terms in a description, above the
dense-description threshold, even when another field also matches; or
- a single specific term in name, alias, intent, or tag.

Single-term description-only and group-only generic matches remain `possible`.
Expand Down
64 changes: 4 additions & 60 deletions scripts/check-branding.mjs
Original file line number Diff line number Diff line change
@@ -1,68 +1,12 @@
import { readdir, readFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { scanBranding } from "./lib/branding.mjs";

const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const brandSeparator = String.raw`(?:[-_]|\s)+`;
const forbiddenBrand = new RegExp(
["agent", "skills", "stash"].join(brandSeparator),
"iu",
);
const ignoredDirectories = new Set([
"coverage",
"dist",
"node_modules",
]);
const files = [];
const violations = new Set();
const { violations } = await scanBranding(root);

function shouldIgnoreDirectory(name) {
return ignoredDirectories.has(name) || name.startsWith(".stash-cache");
}

function relativePath(filePath) {
return path.relative(root, filePath).split(path.sep).join("/");
}

async function walk(directory) {
for (const entry of await readdir(directory, { withFileTypes: true })) {
if (
entry.name === ".git" ||
(entry.isDirectory() && shouldIgnoreDirectory(entry.name))
) {
continue;
}
const entryPath = path.join(directory, entry.name);
if (entry.isFile() && entry.name.endsWith(".tgz")) {
continue;
}
const relative = relativePath(entryPath);
if (forbiddenBrand.test(relative)) {
violations.add(`${relative} (path)`);
}
if (entry.isDirectory()) {
await walk(entryPath);
} else if (entry.isFile()) {
files.push(entryPath);
}
}
}

await walk(root);

for (const file of files) {
const content = await readFile(file);
if (content.includes(0)) {
continue;
}
if (forbiddenBrand.test(content.toString("utf8"))) {
violations.add(relativePath(file));
}
}

if (violations.size > 0) {
const sortedViolations = [...violations].sort();
if (violations.length > 0) {
throw new Error(
`Legacy three-part brand remains in: ${sortedViolations.join(", ")}`,
`Legacy three-part brand remains in: ${violations.join(", ")}`,
);
}
76 changes: 76 additions & 0 deletions scripts/lib/branding.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { readdir, readFile } from "node:fs/promises";
import path from "node:path";

const brandParts = ["agent", "skills", "stash"];
const contentSeparator = String.raw`(?:[-_]|\s)+`;
const pathSeparator = String.raw`(?:[-_/\\]|\s)+`;
const forbiddenContentBrand = new RegExp(
brandParts.join(contentSeparator),
"iu",
);
const forbiddenPathBrand = new RegExp(
brandParts.join(pathSeparator),
"iu",
);
const ignoredDirectories = new Set([
"coverage",
"dist",
"node_modules",
]);

function shouldIgnoreDirectory(name) {
return ignoredDirectories.has(name) || name.startsWith(".stash-cache");
}

export async function scanBranding(root) {
// The checkout root belongs to the environment, so scan descendants only.
const resolvedRoot = path.resolve(root);
const files = [];
const violations = new Set();

function relativePath(filePath) {
return path.relative(resolvedRoot, filePath).split(path.sep).join("/");
}

async function walk(directory) {
for (const entry of await readdir(directory, { withFileTypes: true })) {
if (
entry.name === ".git" ||
(entry.isDirectory() && shouldIgnoreDirectory(entry.name))
) {
continue;
}
const entryPath = path.join(directory, entry.name);
if (entry.isFile() && entry.name.endsWith(".tgz")) {
continue;
}
const relative = relativePath(entryPath);
if (forbiddenPathBrand.test(relative)) {
violations.add(`${relative} (path)`);
}
// Check the link path above without traversing or reading its target.
if (entry.isSymbolicLink()) {
continue;
}
if (entry.isDirectory()) {
await walk(entryPath);
} else if (entry.isFile()) {
files.push(entryPath);
}
}
}

await walk(resolvedRoot);

for (const file of files) {
const content = await readFile(file);
if (content.includes(0)) {
continue;
}
if (forbiddenContentBrand.test(content.toString("utf8"))) {
violations.add(relativePath(file));
}
}

return { violations: [...violations].sort() };
}
Loading