mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-21 00:21:30 +00:00
docs(grpc-guide): drop hard line wraps, rely on editor soft wrap
Made-with: Cursor
This commit is contained in:
parent
47bca13485
commit
8aedc21c25
1 changed files with 65 additions and 233 deletions
|
|
@ -2,69 +2,30 @@
|
|||
|
||||
## When to use this guide
|
||||
|
||||
This guide is for teams whose product lives in **several separate Git
|
||||
repositories** — one per service — and whose services talk to each other
|
||||
over **gRPC** (possibly alongside HTTP and message topics). GitNexus
|
||||
indexes each repo independently, then a *group* stitches the per-repo
|
||||
indexes into a single cross-repo view that the `impact`, `query`, and
|
||||
`context` tools can traverse. If your services live in one monorepo,
|
||||
much of this still applies — set each service as a member of a group
|
||||
and use the `service` prefix to scope queries — but the walkthrough
|
||||
assumes the harder multi-repo case.
|
||||
This guide is for teams whose product lives in **several separate Git repositories** — one per service — and whose services talk to each other over **gRPC** (possibly alongside HTTP and message topics). GitNexus indexes each repo independently, then a _group_ stitches the per-repo indexes into a single cross-repo view that the `impact`, `query`, and `context` tools can traverse. If your services live in one monorepo, much of this still applies — set each service as a member of a group and use the `service` prefix to scope queries — but the walkthrough assumes the harder multi-repo case.
|
||||
|
||||
## Mental model
|
||||
|
||||
- Each repository has its own `.gitnexus/` index (a LadybugDB graph of
|
||||
symbols, relationships, processes). `gitnexus analyze` in each repo
|
||||
produces that index completely independently.
|
||||
- A **group** is a higher-level construct stored at
|
||||
`~/.gitnexus/groups/<group>/` that references the per-repo indexes by
|
||||
their registry name.
|
||||
- Sync-time extractors walk each member repo and emit **contracts** —
|
||||
provider or consumer records keyed by a canonical `contractId`
|
||||
(`grpc::auth.AuthService/Login`, `http::GET::/orders`, etc.).
|
||||
- The sync step matches providers and consumers that share a
|
||||
`contractId` and writes **cross-links** to
|
||||
`<groupDir>/contracts.json`. Those cross-links are what lets
|
||||
`impact({repo: "@<group>", target: "X"})` hop from one repo into
|
||||
another.
|
||||
- Contracts come from three places: automatic contract extractors
|
||||
(`grpc-extractor`, `http-route-extractor`, `topic-extractor`), a
|
||||
manifest escape hatch (`config.links` in `group.yaml`), and — for
|
||||
same-name symbol matches where no contract is declared — the
|
||||
exact-match matching cascade in
|
||||
[`matching.ts`](../../gitnexus/src/core/group/matching.ts).
|
||||
- Each repo stays editable and re-indexable on its own. Re-run
|
||||
`gitnexus analyze` in a repo when it changes, then `gitnexus group
|
||||
sync <group>` to refresh `contracts.json`. `gitnexus group status`
|
||||
reports which members are stale.
|
||||
- Each repository has its own `.gitnexus/` index (a LadybugDB graph of symbols, relationships, processes). `gitnexus analyze` in each repo produces that index completely independently.
|
||||
- A **group** is a higher-level construct stored at `~/.gitnexus/groups/<group>/` that references the per-repo indexes by their registry name.
|
||||
- Sync-time extractors walk each member repo and emit **contracts** — provider or consumer records keyed by a canonical `contractId` (`grpc::auth.AuthService/Login`, `http::GET::/orders`, etc.).
|
||||
- The sync step matches providers and consumers that share a `contractId` and writes **cross-links** to `<groupDir>/contracts.json`. Those cross-links are what lets `impact({repo: "@<group>", target: "X"})` hop from one repo into another.
|
||||
- Contracts come from three places: automatic contract extractors (`grpc-extractor`, `http-route-extractor`, `topic-extractor`), a manifest escape hatch (`config.links` in `group.yaml`), and — for same-name symbol matches where no contract is declared — the exact-match matching cascade in [`matching.ts`](../../gitnexus/src/core/group/matching.ts).
|
||||
- Each repo stays editable and re-indexable on its own. Re-run `gitnexus analyze` in a repo when it changes, then `gitnexus group sync <group>` to refresh `contracts.json`. `gitnexus group status` reports which members are stale.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- GitNexus installed and runnable as `gitnexus` or `npx gitnexus` (see
|
||||
the root [README.md](../../README.md)).
|
||||
- Each service repository checked out locally. No requirement that they
|
||||
share a parent directory — the group references them by registry
|
||||
name.
|
||||
- Write access to `~/.gitnexus/` (the default gitnexus home; see
|
||||
`getDefaultGitnexusDir` in
|
||||
[`storage.ts`](../../gitnexus/src/core/group/storage.ts)).
|
||||
- GitNexus installed and runnable as `gitnexus` or `npx gitnexus` (see the root [README.md](../../README.md)).
|
||||
- Each service repository checked out locally. No requirement that they share a parent directory — the group references them by registry name.
|
||||
- Write access to `~/.gitnexus/` (the default gitnexus home; see `getDefaultGitnexusDir` in [`storage.ts`](../../gitnexus/src/core/group/storage.ts)).
|
||||
|
||||
## Step-by-step walkthrough
|
||||
|
||||
The example uses three services — a TypeScript API gateway, a Go
|
||||
orders service, and a Python inventory service — with gRPC between
|
||||
them. The gateway is an `orders` consumer; the orders service is both
|
||||
an `orders` provider and an `inventory` consumer; the inventory
|
||||
service is an `inventory` provider.
|
||||
The example uses three services — a TypeScript API gateway, a Go orders service, and a Python inventory service — with gRPC between them. The gateway is an `orders` consumer; the orders service is both an `orders` provider and an `inventory` consumer; the inventory service is an `inventory` provider.
|
||||
|
||||
### 1. Index each repository
|
||||
|
||||
Run `analyze` from inside each service repo (or pass the path). The
|
||||
CLI surface lives in
|
||||
[`gitnexus/src/cli/analyze.ts`](../../gitnexus/src/cli/analyze.ts) and
|
||||
is wired in
|
||||
[`gitnexus/src/cli/index.ts`](../../gitnexus/src/cli/index.ts).
|
||||
Run `analyze` from inside each service repo (or pass the path). The CLI surface lives in [`gitnexus/src/cli/analyze.ts`](../../gitnexus/src/cli/analyze.ts) and is wired in [`gitnexus/src/cli/index.ts`](../../gitnexus/src/cli/index.ts).
|
||||
|
||||
```bash
|
||||
cd ~/code/gateway && npx gitnexus analyze
|
||||
|
|
@ -75,22 +36,15 @@ cd ~/code/inventory && npx gitnexus analyze
|
|||
Useful flags:
|
||||
|
||||
- `--force` — reindex even if up to date.
|
||||
- `--embeddings` — generate embedding vectors (needed only if you want
|
||||
semantic search; the exact-match cross-repo cascade does **not**
|
||||
need them).
|
||||
- `--name <alias>` — register the repo under a specific alias when two
|
||||
repos share a basename (e.g. two `api/` folders).
|
||||
- `--embeddings` — generate embedding vectors (needed only if you want semantic search; the exact-match cross-repo cascade does **not** need them).
|
||||
- `--name <alias>` — register the repo under a specific alias when two repos share a basename (e.g. two `api/` folders).
|
||||
- `--skip-git` — index a checkout that isn't a git repo.
|
||||
|
||||
Each run writes a `.gitnexus/` folder in the repo and registers the
|
||||
repo in `~/.gitnexus/registry.json`. Confirm with `npx gitnexus list`.
|
||||
Each run writes a `.gitnexus/` folder in the repo and registers the repo in `~/.gitnexus/registry.json`. Confirm with `npx gitnexus list`.
|
||||
|
||||
### 2. Author `group.yaml`
|
||||
|
||||
Create the group directory and edit the config. Either use the CLI
|
||||
scaffolder or write the file directly — both produce the same shape
|
||||
consumed by
|
||||
[`config-parser.ts`](../../gitnexus/src/core/group/config-parser.ts).
|
||||
Create the group directory and edit the config. Either use the CLI scaffolder or write the file directly — both produce the same shape consumed by [`config-parser.ts`](../../gitnexus/src/core/group/config-parser.ts).
|
||||
|
||||
```bash
|
||||
npx gitnexus group create payments-platform
|
||||
|
|
@ -130,26 +84,14 @@ matching:
|
|||
max_candidates_per_step: 3
|
||||
```
|
||||
|
||||
Field notes (schema in
|
||||
[`types.ts`](../../gitnexus/src/core/group/types.ts)):
|
||||
Field notes (schema in [`types.ts`](../../gitnexus/src/core/group/types.ts)):
|
||||
|
||||
- `version` — must be `1`. The parser rejects anything else.
|
||||
- `name` — required; used for the group directory name and all CLI /
|
||||
MCP calls.
|
||||
- `repos` — a mapping from **group path** (a logical name you choose;
|
||||
can be a hierarchy like `backend/orders`) to **registry name** (the
|
||||
name shown by `npx gitnexus list`). Both sides appear throughout the
|
||||
tooling: contract rows use the group path; `@<group>/<groupPath>`
|
||||
routes tools to a single member.
|
||||
- `links` — optional manifest escape hatch, one entry per explicit
|
||||
cross-repo contract. Validated by the parser: `from` and `to` must
|
||||
be known repo paths, `type` must be one of `http | grpc | topic | lib
|
||||
| custom`, and `role` must be `provider | consumer`.
|
||||
- `detect` — toggles per extractor family. Defaults (set in
|
||||
`config-parser.ts`) turn `http`, `grpc`, `topics`, and `shared_libs`
|
||||
on; disable the ones you don't use to speed up sync.
|
||||
- `matching` — thresholds for the matching cascade. The exact match is
|
||||
always run; other strategies depend on indexer state.
|
||||
- `name` — required; used for the group directory name and all CLI / MCP calls.
|
||||
- `repos` — a mapping from **group path** (a logical name you choose; can be a hierarchy like `backend/orders`) to **registry name** (the name shown by `npx gitnexus list`). Both sides appear throughout the tooling: contract rows use the group path; `@<group>/<groupPath>` routes tools to a single member.
|
||||
- `links` — optional manifest escape hatch, one entry per explicit cross-repo contract. Validated by the parser: `from` and `to` must be known repo paths, `type` must be one of `http | grpc | topic | lib | custom`, and `role` must be `provider | consumer`.
|
||||
- `detect` — toggles per extractor family. Defaults (set in `config-parser.ts`) turn `http`, `grpc`, `topics`, and `shared_libs` on; disable the ones you don't use to speed up sync.
|
||||
- `matching` — thresholds for the matching cascade. The exact match is always run; other strategies depend on indexer state.
|
||||
|
||||
### 3. Sync the group
|
||||
|
||||
|
|
@ -157,34 +99,26 @@ Field notes (schema in
|
|||
npx gitnexus group sync payments-platform --verbose
|
||||
```
|
||||
|
||||
What this does (see
|
||||
[`sync.ts`](../../gitnexus/src/core/group/sync.ts)):
|
||||
What this does (see [`sync.ts`](../../gitnexus/src/core/group/sync.ts)):
|
||||
|
||||
1. Opens each member's per-repo LadybugDB.
|
||||
2. Runs the HTTP, gRPC, and topic extractors against the source files.
|
||||
3. Applies manifest `links` through
|
||||
[`manifest-extractor.ts`](../../gitnexus/src/core/group/extractors/manifest-extractor.ts).
|
||||
4. Runs the exact-match cascade, joining providers and consumers that
|
||||
share a normalized `contractId`.
|
||||
3. Applies manifest `links` through [`manifest-extractor.ts`](../../gitnexus/src/core/group/extractors/manifest-extractor.ts).
|
||||
4. Runs the exact-match cascade, joining providers and consumers that share a normalized `contractId`.
|
||||
5. Writes `contracts.json` in the group directory.
|
||||
|
||||
Flags:
|
||||
|
||||
- `--exact-only` — stop after the exact cascade; skip BM25 and
|
||||
embedding fallback.
|
||||
- `--skip-embeddings` — run exact plus BM25 but not embedding-based
|
||||
matching.
|
||||
- `--exact-only` — stop after the exact cascade; skip BM25 and embedding fallback.
|
||||
- `--skip-embeddings` — run exact plus BM25 but not embedding-based matching.
|
||||
- `--allow-stale` — don't warn if a member's index is stale.
|
||||
- `--json` — machine-readable output.
|
||||
|
||||
The same operation is available over MCP as
|
||||
`group_sync({ name: "payments-platform" })` — see
|
||||
[`tools.ts`](../../gitnexus/src/mcp/tools.ts).
|
||||
The same operation is available over MCP as `group_sync({ name: "payments-platform" })` — see [`tools.ts`](../../gitnexus/src/mcp/tools.ts).
|
||||
|
||||
### 4. Inspect the registry
|
||||
|
||||
Use `gitnexus group contracts` for the CLI view or read the
|
||||
`gitnexus://group/<name>/contracts` MCP resource for the same data.
|
||||
Use `gitnexus group contracts` for the CLI view or read the `gitnexus://group/<name>/contracts` MCP resource for the same data.
|
||||
|
||||
```bash
|
||||
npx gitnexus group contracts payments-platform --type grpc --json
|
||||
|
|
@ -227,19 +161,11 @@ A shortened response:
|
|||
}
|
||||
```
|
||||
|
||||
Staleness of the underlying indexes shows up in
|
||||
`npx gitnexus group status payments-platform` or the
|
||||
`gitnexus://group/<name>/status` resource.
|
||||
Staleness of the underlying indexes shows up in `npx gitnexus group status payments-platform` or the `gitnexus://group/<name>/status` resource.
|
||||
|
||||
### 5. Run cross-repo impact with `@<group>` routing
|
||||
|
||||
From any shell (you do **not** have to `cd` into a member repo), the
|
||||
normal `impact` / `query` / `context` tools accept `repo: "@<group>"`
|
||||
to fan out across all members, or `repo: "@<group>/<memberPath>"` to
|
||||
target one member. Routing is implemented in
|
||||
[`resolve-at-member.ts`](../../gitnexus/src/core/group/resolve-at-member.ts)
|
||||
and described in
|
||||
[`tools.ts`](../../gitnexus/src/mcp/tools.ts).
|
||||
From any shell (you do **not** have to `cd` into a member repo), the normal `impact` / `query` / `context` tools accept `repo: "@<group>"` to fan out across all members, or `repo: "@<group>/<memberPath>"` to target one member. Routing is implemented in [`resolve-at-member.ts`](../../gitnexus/src/core/group/resolve-at-member.ts) and described in [`tools.ts`](../../gitnexus/src/mcp/tools.ts).
|
||||
|
||||
Example MCP calls:
|
||||
|
||||
|
|
@ -266,29 +192,14 @@ npx gitnexus group impact payments-platform \
|
|||
--repo orders --target PlaceOrder --direction upstream --cross-depth 2
|
||||
```
|
||||
|
||||
Phase 1 walks within the anchor member; Phase 2 hops across the
|
||||
Contract Bridge wherever a cross-link endpoint matches an impacted
|
||||
symbol. See
|
||||
[`cross-impact.ts`](../../gitnexus/src/core/group/cross-impact.ts) for
|
||||
the bridge query.
|
||||
Phase 1 walks within the anchor member; Phase 2 hops across the Contract Bridge wherever a cross-link endpoint matches an impacted symbol. See [`cross-impact.ts`](../../gitnexus/src/core/group/cross-impact.ts) for the bridge query.
|
||||
|
||||
## How gRPC extraction works
|
||||
|
||||
`GrpcExtractor`
|
||||
([`grpc-extractor.ts`](../../gitnexus/src/core/group/extractors/grpc-extractor.ts))
|
||||
runs two passes per member repo:
|
||||
`GrpcExtractor` ([`grpc-extractor.ts`](../../gitnexus/src/core/group/extractors/grpc-extractor.ts)) runs two passes per member repo:
|
||||
|
||||
1. **Proto map.** Every `**/*.proto` file is parsed to enumerate
|
||||
`service Foo { rpc Bar(...) }` blocks and (transitively) resolve
|
||||
the package name. Each RPC method becomes a provider contract with
|
||||
`contractId = grpc::<package>.<Service>/<Method>` and
|
||||
`confidence = 0.85`. Parsing uses the vendored `tree-sitter-proto`
|
||||
grammar when available and falls back to a length-preserving
|
||||
manual parser (`extractServiceBlocks`) otherwise, so `.proto`
|
||||
extraction works on platforms where the grammar fails to build.
|
||||
2. **Source scan.** Every source file whose extension matches
|
||||
[`GRPC_SCAN_GLOB`](../../gitnexus/src/core/group/extractors/grpc-patterns/index.ts)
|
||||
is parsed by its language plugin:
|
||||
1. **Proto map.** Every `**/*.proto` file is parsed to enumerate `service Foo { rpc Bar(...) }` blocks and (transitively) resolve the package name. Each RPC method becomes a provider contract with `contractId = grpc::<package>.<Service>/<Method>` and `confidence = 0.85`. Parsing uses the vendored `tree-sitter-proto` grammar when available and falls back to a length-preserving manual parser (`extractServiceBlocks`) otherwise, so `.proto` extraction works on platforms where the grammar fails to build.
|
||||
2. **Source scan.** Every source file whose extension matches [`GRPC_SCAN_GLOB`](../../gitnexus/src/core/group/extractors/grpc-patterns/index.ts) is parsed by its language plugin:
|
||||
|
||||
| Language | Provider signal | Consumer signal |
|
||||
|----------|-----------------|-----------------|
|
||||
|
|
@ -297,54 +208,28 @@ runs two passes per member repo:
|
|||
| Python ([`python.ts`](../../gitnexus/src/core/group/extractors/grpc-patterns/python.ts)) | `add_XxxServicer_to_server(...)` (bare or `_pb2_grpc.` attribute form) | `XxxStub(channel)` (ignores `Mock`/`Test`/`Fake`/`Stub`) |
|
||||
| Node / TS ([`node.ts`](../../gitnexus/src/core/group/extractors/grpc-patterns/node.ts)) | NestJS `@GrpcMethod('Service','Method')` | `@GrpcClient` field typed `XxxServiceClient`, `client.getService<X>('Service')`, `new XxxServiceClient(...)`, `new foo.bar.XxxService(...)` in files that call `loadPackageDefinition` |
|
||||
|
||||
For each source-scan detection the extractor looks up the short
|
||||
service name in the proto map and picks:
|
||||
For each source-scan detection the extractor looks up the short service name in the proto map and picks:
|
||||
|
||||
- `grpc::<package>.<Service>/<Method>` when a method is named and the
|
||||
service resolves against the proto map,
|
||||
- `grpc::<package>.<Service>/*` (wildcard) when only the service is
|
||||
known, or
|
||||
- `grpc::<package>.<Service>/<Method>` when a method is named and the service resolves against the proto map,
|
||||
- `grpc::<package>.<Service>/*` (wildcard) when only the service is known, or
|
||||
- `grpc::<ServiceName>/*` when no `.proto` is available at all.
|
||||
|
||||
Provider detections land at confidence 0.8 (with proto) or 0.65
|
||||
(without); consumers at 0.75 or 0.55. NestJS `@GrpcMethod` is fixed at
|
||||
0.8 because the decorator is self-describing.
|
||||
Provider detections land at confidence 0.8 (with proto) or 0.65 (without); consumers at 0.75 or 0.55. NestJS `@GrpcMethod` is fixed at 0.8 because the decorator is self-describing.
|
||||
|
||||
### Matching
|
||||
|
||||
`matching.ts` lowercases the package/service segment before comparing
|
||||
contract ids, so bindings that capitalize names differently
|
||||
(`auth.AuthService` vs `auth.authservice`) still match. Method names
|
||||
are compared case-sensitively because gRPC's wire path is
|
||||
case-sensitive. Service-only wildcards (`grpc::pkg.Svc/*`) match any
|
||||
method on the same service during cross-linking.
|
||||
`matching.ts` lowercases the package/service segment before comparing contract ids, so bindings that capitalize names differently (`auth.AuthService` vs `auth.authservice`) still match. Method names are compared case-sensitively because gRPC's wire path is case-sensitive. Service-only wildcards (`grpc::pkg.Svc/*`) match any method on the same service during cross-linking.
|
||||
|
||||
### Known limitations
|
||||
|
||||
- **Ambiguous proto resolution.** If a short service name exists in
|
||||
more than one `.proto` file and the source-scan hit can't be
|
||||
narrowed down by shared directory segments (`resolveProtoConflict`
|
||||
refuses to guess), the extractor skips contract emission and logs a
|
||||
warning.
|
||||
- **Proto packages must be resolvable locally.** Transitive imports
|
||||
that point outside the repo produce an empty package segment, which
|
||||
means the contract id collapses to `grpc::<Service>/<Method>`.
|
||||
Cross-repo matches still work as long as both sides agree on the
|
||||
empty package.
|
||||
- **Rewrite rules are not implemented.** If the provider repo writes
|
||||
`grpc::orders.OrderService/PlaceOrder` and the consumer repo writes
|
||||
`grpc::orderspb.OrderService/PlaceOrder`, they won't cross-link
|
||||
automatically. Use `config.links` to declare the correspondence
|
||||
(see below).
|
||||
- **One sync = one snapshot.** Contracts are extracted against the
|
||||
indexed snapshot of each repo. Re-index first, then re-sync; the
|
||||
`status` command and resource surface staleness.
|
||||
- **Ambiguous proto resolution.** If a short service name exists in more than one `.proto` file and the source-scan hit can't be narrowed down by shared directory segments (`resolveProtoConflict` refuses to guess), the extractor skips contract emission and logs a warning.
|
||||
- **Proto packages must be resolvable locally.** Transitive imports that point outside the repo produce an empty package segment, which means the contract id collapses to `grpc::<Service>/<Method>`. Cross-repo matches still work as long as both sides agree on the empty package.
|
||||
- **Rewrite rules are not implemented.** If the provider repo writes `grpc::orders.OrderService/PlaceOrder` and the consumer repo writes `grpc::orderspb.OrderService/PlaceOrder`, they won't cross-link automatically. Use `config.links` to declare the correspondence (see below).
|
||||
- **One sync = one snapshot.** Contracts are extracted against the indexed snapshot of each repo. Re-index first, then re-sync; the `status` command and resource surface staleness.
|
||||
|
||||
## When automatic extraction isn't enough
|
||||
|
||||
The escape hatch is the `links` list in `group.yaml`, handled by
|
||||
[`ManifestExtractor`](../../gitnexus/src/core/group/extractors/manifest-extractor.ts).
|
||||
Each entry is a **one-directional** provider/consumer declaration:
|
||||
The escape hatch is the `links` list in `group.yaml`, handled by [`ManifestExtractor`](../../gitnexus/src/core/group/extractors/manifest-extractor.ts). Each entry is a **one-directional** provider/consumer declaration:
|
||||
|
||||
```yaml
|
||||
version: 1
|
||||
|
|
@ -379,85 +264,32 @@ links:
|
|||
role: consumer
|
||||
```
|
||||
|
||||
What the manifest extractor does (see
|
||||
[`manifest-extractor.ts`](../../gitnexus/src/core/group/extractors/manifest-extractor.ts)):
|
||||
What the manifest extractor does (see [`manifest-extractor.ts`](../../gitnexus/src/core/group/extractors/manifest-extractor.ts)):
|
||||
|
||||
1. Builds a canonical `contractId` with `buildContractId` — the same
|
||||
canonicalization used by the automatic extractors, so manifest
|
||||
links cross-match automatic contracts on the other side.
|
||||
2. Tries to resolve each side to a real graph symbol (the `Route` node
|
||||
for HTTP, a `Function|Method` / `Class|Interface` for gRPC, a
|
||||
`Package|Module` for `lib`).
|
||||
3. If resolution fails, falls back to a deterministic synthetic uid
|
||||
(`manifest::<repo>::<contractId>`) so both sides still line up in
|
||||
cross-impact — name-only links still work when the symbol isn't in
|
||||
the graph.
|
||||
4. Emits both a provider and a consumer `StoredContract` (confidence
|
||||
`1.0`, `source: "manifest"`) and a `CrossLink` with
|
||||
`matchType: "manifest"`.
|
||||
1. Builds a canonical `contractId` with `buildContractId` — the same canonicalization used by the automatic extractors, so manifest links cross-match automatic contracts on the other side.
|
||||
2. Tries to resolve each side to a real graph symbol (the `Route` node for HTTP, a `Function|Method` / `Class|Interface` for gRPC, a `Package|Module` for `lib`).
|
||||
3. If resolution fails, falls back to a deterministic synthetic uid (`manifest::<repo>::<contractId>`) so both sides still line up in cross-impact — name-only links still work when the symbol isn't in the graph.
|
||||
4. Emits both a provider and a consumer `StoredContract` (confidence `1.0`, `source: "manifest"`) and a `CrossLink` with `matchType: "manifest"`.
|
||||
|
||||
Use `links` for exactly the cases the extractor can't infer: different
|
||||
package names across repos (see #701), hand-rolled transports, cases
|
||||
where the provider repo isn't checked out locally but you still want a
|
||||
record, or any contract whose provider and consumer simply don't
|
||||
share a surface the extractors know how to pattern-match.
|
||||
Use `links` for exactly the cases the extractor can't infer: different package names across repos (see #701), hand-rolled transports, cases where the provider repo isn't checked out locally but you still want a record, or any contract whose provider and consumer simply don't share a surface the extractors know how to pattern-match.
|
||||
|
||||
History: the manifest extractor used to be silently skipped by the
|
||||
sync pipeline; that was fixed in
|
||||
[#827](https://github.com/abhigyanpatwari/GitNexus/pull/827) (tracking
|
||||
issue #826). If you ever see `config.links` with zero cross-links in
|
||||
`contracts.json`, make sure you're on a build that includes that fix,
|
||||
then re-run `group sync`.
|
||||
History: the manifest extractor used to be silently skipped by the sync pipeline; that was fixed in [#827](https://github.com/abhigyanpatwari/GitNexus/pull/827) (tracking issue #826). If you ever see `config.links` with zero cross-links in `contracts.json`, make sure you're on a build that includes that fix, then re-run `group sync`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
1. **`contracts.json` is empty after a sync.** Either no member repo
|
||||
contained a recognizable gRPC pattern, or the extractors are
|
||||
disabled in `detect`. Confirm `detect.grpc: true` and re-run with
|
||||
`--verbose`.
|
||||
2. **A known provider/consumer pair doesn't cross-link.** Most common
|
||||
cause: the package segment differs. Check the raw contract ids
|
||||
with `gitnexus group contracts <name> --unmatched` — if you see
|
||||
two same-method contracts with different package prefixes, add a
|
||||
manifest `links:` entry to bridge them (no automatic rewrite
|
||||
rules yet).
|
||||
3. **`matchType: "manifest"` is missing entirely.** The extractor
|
||||
needs `config.links` to be non-empty and the sync pipeline to
|
||||
actually call it — verify you're on a post-#827 build. Empty
|
||||
contract rows for manifest links usually mean `resolveSymbol`
|
||||
couldn't find a graph match; the synthetic uid still lets
|
||||
cross-impact work, it just won't carry a file path.
|
||||
4. **Ambiguous proto warnings.** Look for
|
||||
`[grpc-extractor] Ambiguous proto resolution` in the sync logs;
|
||||
that means a service name exists in multiple `.proto` files under
|
||||
the same repo and the path-distance heuristic couldn't pick a
|
||||
winner. Resolve by renaming the service or declaring the intended
|
||||
pairing in `config.links`.
|
||||
5. **Cross-impact says "stale".** Both sides need a fresh per-repo
|
||||
index *and* a fresh group sync. Order matters: `gitnexus analyze`
|
||||
in each changed repo, then `gitnexus group sync <name>`. Use
|
||||
`gitnexus group status <name>` to see which side is behind.
|
||||
1. **`contracts.json` is empty after a sync.** Either no member repo contained a recognizable gRPC pattern, or the extractors are disabled in `detect`. Confirm `detect.grpc: true` and re-run with `--verbose`.
|
||||
2. **A known provider/consumer pair doesn't cross-link.** Most common cause: the package segment differs. Check the raw contract ids with `gitnexus group contracts <name> --unmatched` — if you see two same-method contracts with different package prefixes, add a manifest `links:` entry to bridge them (no automatic rewrite rules yet).
|
||||
3. **`matchType: "manifest"` is missing entirely.** The extractor needs `config.links` to be non-empty and the sync pipeline to actually call it — verify you're on a post-#827 build. Empty contract rows for manifest links usually mean `resolveSymbol` couldn't find a graph match; the synthetic uid still lets cross-impact work, it just won't carry a file path.
|
||||
4. **Ambiguous proto warnings.** Look for `[grpc-extractor] Ambiguous proto resolution` in the sync logs; that means a service name exists in multiple `.proto` files under the same repo and the path-distance heuristic couldn't pick a winner. Resolve by renaming the service or declaring the intended pairing in `config.links`.
|
||||
5. **Cross-impact says "stale".** Both sides need a fresh per-repo index _and_ a fresh group sync. Order matters: `gitnexus analyze` in each changed repo, then `gitnexus group sync <name>`. Use `gitnexus group status <name>` to see which side is behind.
|
||||
|
||||
## Related docs and references
|
||||
|
||||
- [AGENTS.md](../../AGENTS.md) — authoritative list of MCP tools and
|
||||
resources, including group-mode routing and the `gitnexus://group/…`
|
||||
resources.
|
||||
- [ARCHITECTURE.md](../../ARCHITECTURE.md) — overall data flow and the
|
||||
call-resolution DAG that the per-repo indexer uses.
|
||||
- [`gitnexus/src/core/group/`](../../gitnexus/src/core/group/) —
|
||||
`service.ts`, `sync.ts`, `config-parser.ts`, `matching.ts`.
|
||||
- [`gitnexus/src/core/group/extractors/grpc-extractor.ts`](../../gitnexus/src/core/group/extractors/grpc-extractor.ts)
|
||||
and [`grpc-patterns/`](../../gitnexus/src/core/group/extractors/grpc-patterns/)
|
||||
— gRPC detection.
|
||||
- [`gitnexus/src/core/group/extractors/manifest-extractor.ts`](../../gitnexus/src/core/group/extractors/manifest-extractor.ts)
|
||||
— the `config.links` escape hatch.
|
||||
- [`gitnexus/src/mcp/tools.ts`](../../gitnexus/src/mcp/tools.ts) —
|
||||
MCP tool schemas (`group_list`, `group_sync`, plus `@<group>`
|
||||
routing on `impact` / `query` / `context`).
|
||||
- [`gitnexus/src/cli/group.ts`](../../gitnexus/src/cli/group.ts) —
|
||||
CLI command definitions and flags.
|
||||
- Upstream issues:
|
||||
[#701](https://github.com/abhigyanpatwari/GitNexus/issues/701),
|
||||
[#826](https://github.com/abhigyanpatwari/GitNexus/issues/826),
|
||||
[#906](https://github.com/abhigyanpatwari/GitNexus/issues/906).
|
||||
- [AGENTS.md](../../AGENTS.md) — authoritative list of MCP tools and resources, including group-mode routing and the `gitnexus://group/…` resources.
|
||||
- [ARCHITECTURE.md](../../ARCHITECTURE.md) — overall data flow and the call-resolution DAG that the per-repo indexer uses.
|
||||
- [`gitnexus/src/core/group/`](../../gitnexus/src/core/group/) — `service.ts`, `sync.ts`, `config-parser.ts`, `matching.ts`.
|
||||
- [`gitnexus/src/core/group/extractors/grpc-extractor.ts`](../../gitnexus/src/core/group/extractors/grpc-extractor.ts) and [`grpc-patterns/`](../../gitnexus/src/core/group/extractors/grpc-patterns/) — gRPC detection.
|
||||
- [`gitnexus/src/core/group/extractors/manifest-extractor.ts`](../../gitnexus/src/core/group/extractors/manifest-extractor.ts) — the `config.links` escape hatch.
|
||||
- [`gitnexus/src/mcp/tools.ts`](../../gitnexus/src/mcp/tools.ts) — MCP tool schemas (`group_list`, `group_sync`, plus `@<group>` routing on `impact` / `query` / `context`).
|
||||
- [`gitnexus/src/cli/group.ts`](../../gitnexus/src/cli/group.ts) — CLI command definitions and flags.
|
||||
- Upstream issues: [#701](https://github.com/abhigyanpatwari/GitNexus/issues/701), [#826](https://github.com/abhigyanpatwari/GitNexus/issues/826), [#906](https://github.com/abhigyanpatwari/GitNexus/issues/906).
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue