mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-05 02:43:32 +00:00
fix(group)!: remove the matching cascade that was advertised but never built
`gitnexus group create` wrote `matching.bm25_threshold` and `matching.embedding_threshold` into every generated group.yaml, and no matcher ever read either one. That was not the whole of it — an entire feature surface described a BM25/embedding cascade that does not exist: - `matching.bm25_threshold` / `matching.embedding_threshold` — parsed, persisted, unread - `detect.embedding_fallback` — defaulted and templated, unread - `MatchType` declared `'bm25' | 'embedding'`; both variants unreachable - `SyncOptions.skipEmbeddings` — declared in sync.ts and never read - `gitnexus group sync --skip-embeddings` — accepted, threaded through GroupService, ignored - CLI help in en and zh-CN promised "Exact + BM25 only (no embedding fallback)" - the MCP `group_sync` schema exposed `skipEmbeddings`, described as "Exact + BM25 only (Demo PR: same as default exact path)" `sync.ts` imports exactly `buildProviderIndex`, `runExactMatch` and `runWildcardMatch`, and the printed cascade has one stage. An operator whose links do not match reaches for those thresholds first, and turning either knob changes nothing — config that silently does nothing is how people conclude a feature is broken. Evidence that the cascade should be deleted rather than implemented, from a real backend/frontend pair: of 165 consumer contracts, 149 link exactly and 16 do not. Nine of the sixteen are third-party APIs (Google OAuth, Apple public keys, PostHog, image annotation) with no in-group provider by construction — similarity matching cannot recover them, it can only invent false links. Two are verb mismatches: the frontend calls `POST /links` and `GET /links/check-exists` while the backend declares `GET /links` and eleven other `/links/*` routes but neither of those, so a fuzzy path match would link a POST consumer to a GET provider. The rest are path-extraction artifacts. Roughly none of the sixteen would be correctly recovered, and several would be actively mis-linked. BREAKING CHANGE: `gitnexus group sync --skip-embeddings` and the MCP `group_sync` `skipEmbeddings` parameter are removed. Both were accepted and ignored, so no behavior changes — but a script passing the flag now fails with `unknown option` instead of being silently misled. Existing group.yaml files keep loading: the removed keys are simply no longer part of the schema, and a regression test pins that a legacy config carrying all three still parses. Closes #3006 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
aac7515d2a
commit
90425a4554
11 changed files with 27 additions and 21 deletions
|
|
@ -149,7 +149,6 @@ export function registerGroupCommands(program: Command): void {
|
|||
group
|
||||
.command('sync <name>')
|
||||
.description('Sync Contract Registry — extract contracts and build cross-links')
|
||||
.option('--skip-embeddings', 'Exact + BM25 only (no embedding fallback)')
|
||||
.option('--exact-only', 'Exact match only')
|
||||
.option('--allow-stale', 'Skip stale index warnings')
|
||||
.option('--verbose', 'Show each cross-link detail')
|
||||
|
|
@ -168,7 +167,6 @@ export function registerGroupCommands(program: Command): void {
|
|||
groupDir,
|
||||
allowStale: Boolean(opts.allowStale),
|
||||
verbose: Boolean(opts.verbose),
|
||||
skipEmbeddings: Boolean(opts.skipEmbeddings),
|
||||
exactOnly: Boolean(opts.exactOnly),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -155,7 +155,6 @@ const OPTION_DESCRIPTION_KEYS = {
|
|||
'embeddings install|--cuda': 'help.option.embeddings.install.cuda',
|
||||
'embeddings install|--force': 'help.option.embeddings.install.force',
|
||||
'group create|--force': 'help.option.group.create.force',
|
||||
'group sync|--skip-embeddings': 'help.option.group.sync.skipEmbeddings',
|
||||
'group sync|--exact-only': 'help.option.group.sync.exactOnly',
|
||||
'group sync|--allow-stale': 'help.option.group.sync.allowStale',
|
||||
'group sync|--verbose': 'help.option.group.sync.verbose',
|
||||
|
|
|
|||
|
|
@ -293,7 +293,6 @@ export const en = {
|
|||
'help.option.embeddings.install.force':
|
||||
'Install into the runtime prefix even when the stack already resolves',
|
||||
'help.option.group.create.force': 'Overwrite existing group',
|
||||
'help.option.group.sync.skipEmbeddings': 'Exact + BM25 only (no embedding fallback)',
|
||||
'help.option.group.sync.exactOnly': 'Exact match only',
|
||||
'help.option.group.sync.allowStale': 'Skip stale index warnings',
|
||||
'help.option.group.sync.verbose': 'Show each cross-link detail',
|
||||
|
|
|
|||
|
|
@ -273,7 +273,6 @@ export const zhCN = {
|
|||
'同时下载 CUDA GPU 二进制文件(运行 onnxruntime-node 的 NuGet postinstall;代理后请设置 GLOBAL_AGENT_HTTPS_PROXY)',
|
||||
'help.option.embeddings.install.force': '即使嵌入组件已可解析,也强制安装到运行时目录',
|
||||
'help.option.group.create.force': '覆盖现有仓库组',
|
||||
'help.option.group.sync.skipEmbeddings': '仅使用 exact + BM25(不使用嵌入回退)',
|
||||
'help.option.group.sync.exactOnly': '仅精确匹配',
|
||||
'help.option.group.sync.allowStale': '跳过过期索引警告',
|
||||
'help.option.group.sync.verbose': '显示每条跨仓库链接详情',
|
||||
|
|
|
|||
|
|
@ -30,14 +30,11 @@ const DEFAULT_DETECT = {
|
|||
thrift: true,
|
||||
topics: true,
|
||||
shared_libs: true,
|
||||
embedding_fallback: true,
|
||||
includes: false,
|
||||
workspace_deps: false,
|
||||
};
|
||||
|
||||
const DEFAULT_MATCHING = {
|
||||
bm25_threshold: 0.7,
|
||||
embedding_threshold: 0.65,
|
||||
max_candidates_per_step: 3,
|
||||
exclude_links_paths: [] as string[],
|
||||
exclude_links_param_only_paths: false,
|
||||
|
|
|
|||
|
|
@ -350,7 +350,6 @@ export class GroupService {
|
|||
const result = await syncGroup(config, {
|
||||
groupDir,
|
||||
exactOnly: Boolean(params.exactOnly),
|
||||
skipEmbeddings: Boolean(params.skipEmbeddings),
|
||||
allowStale: Boolean(params.allowStale),
|
||||
verbose: Boolean(params.verbose),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -94,11 +94,8 @@ detect:
|
|||
grpc: true
|
||||
topics: true
|
||||
shared_libs: true
|
||||
embedding_fallback: true
|
||||
|
||||
matching:
|
||||
bm25_threshold: 0.7
|
||||
embedding_threshold: 0.65
|
||||
max_candidates_per_step: 3
|
||||
# exclude_links_paths: [/ping, /health, /healthcheck]
|
||||
# exclude_links_param_only_paths: false
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,5 +1,5 @@
|
|||
export type ContractType = 'http' | 'grpc' | 'thrift' | 'topic' | 'lib' | 'custom' | 'include';
|
||||
export type MatchType = 'exact' | 'manifest' | 'wildcard' | 'bm25' | 'embedding';
|
||||
export type MatchType = 'exact' | 'manifest' | 'wildcard';
|
||||
export type ContractRole = 'provider' | 'consumer';
|
||||
|
||||
export interface GroupConfig {
|
||||
|
|
@ -27,14 +27,11 @@ export interface DetectConfig {
|
|||
thrift: boolean;
|
||||
topics: boolean;
|
||||
shared_libs: boolean;
|
||||
embedding_fallback: boolean;
|
||||
includes: boolean;
|
||||
workspace_deps: boolean;
|
||||
}
|
||||
|
||||
export interface MatchingConfig {
|
||||
bm25_threshold: number;
|
||||
embedding_threshold: number;
|
||||
max_candidates_per_step: number;
|
||||
/**
|
||||
* HTTP paths to exclude from cross-link matching. Contracts at these paths
|
||||
|
|
|
|||
|
|
@ -859,10 +859,6 @@ WHEN TO USE: After changing group.yaml or re-indexing member repos.`,
|
|||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', description: 'Group name' },
|
||||
skipEmbeddings: {
|
||||
type: 'boolean',
|
||||
description: 'Exact + BM25 only (Demo PR: same as default exact path)',
|
||||
},
|
||||
exactOnly: { type: 'boolean', description: 'Exact match only in cascade' },
|
||||
},
|
||||
required: ['name'],
|
||||
|
|
|
|||
|
|
@ -59,11 +59,36 @@ repos:
|
|||
expect(config.links).toEqual([]);
|
||||
expect(config.packages).toEqual({});
|
||||
expect(config.detect.http).toBe(true);
|
||||
expect(config.matching.bm25_threshold).toBe(0.7);
|
||||
expect(config.matching.max_candidates_per_step).toBe(3);
|
||||
expect(config.matching.exclude_links_paths).toEqual([]);
|
||||
expect(config.matching.exclude_links_param_only_paths).toBe(false);
|
||||
});
|
||||
|
||||
it('still parses a legacy config carrying the removed matching knobs', () => {
|
||||
// `bm25_threshold`, `embedding_threshold` and `detect.embedding_fallback`
|
||||
// were written into every generated group.yaml but read by no matcher, so
|
||||
// they are gone from the schema and the template. Every group.yaml already
|
||||
// on disk still has them, and must keep loading without complaint.
|
||||
const legacy = `
|
||||
version: 1
|
||||
name: test
|
||||
repos:
|
||||
app: my-app
|
||||
detect:
|
||||
http: true
|
||||
embedding_fallback: true
|
||||
matching:
|
||||
bm25_threshold: 0.7
|
||||
embedding_threshold: 0.65
|
||||
max_candidates_per_step: 3
|
||||
`;
|
||||
const config = parseGroupConfig(legacy);
|
||||
expect(config.name).toBe('test');
|
||||
expect(config.repos).toEqual({ app: 'my-app' });
|
||||
expect(config.detect.http).toBe(true);
|
||||
expect(config.matching.max_candidates_per_step).toBe(3);
|
||||
});
|
||||
|
||||
it('defaults thrift detection to true', () => {
|
||||
const minimal = `
|
||||
version: 1
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue