mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-08-28 05:25:25 +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> * fix(group)!: honour --exact-only, drop inert --allow-stale, report every matching stage Addresses the review findings on #3020, all of which are the same defect the PR itself is about: group-sync surface that describes behaviour the pipeline does not have. `exactOnly` was inert in exactly the way `skipEmbeddings` was — declared on `SyncOptions`, threaded through the CLI and the MCP tool, and read by nothing — and strictly worse, because the stage it promised to suppress DOES run and DOES write `matchType:'wildcard'` links into contracts.json and the bridge, which `group impact` and cross-repo `trace` then traverse. It is now honoured rather than deleted: unlike the never-built BM25/embedding stages, the stage it names exists, so the flag describes a real choice. The substituted result is `{ matched: [], remaining: unmatched }`, not an empty result — `wildcard.remaining` IS `SyncResult.unmatched`, so skipping the stage has to leave its input unmatched rather than dropping it from the count an operator reads. `allowStale` had no such stage to gate: `syncGroup` emits no stale warning at any point (the `checkStaleness` call lives in `groupStatus`, a different path), so it is removed under the same rationale as `skipEmbeddings`. `group sync` now prints every matching stage instead of `exact` alone. The old block printed a `Matching cascade:` header and counted only exact links while the next line reported `result.crossLinks.length` — which also includes `manifest` and `wildcard` — so for any group with those the two numbers disagreed with nothing on screen explaining why. Counting is an exhaustive `Record<MatchType, number>`, so a new MatchType fails the build here instead of going silently uncounted, and reads through `?? 0` so a legacy registry carrying a removed matchType prints an honest count rather than `NaN`. Also: the MCP `group_sync` description no longer omits the wildcard stage that always runs, `exactOnly`'s description no longer refers to a "cascade", and bench/cross-repo-trace/verify.mjs no longer generates the removed threshold keys into a fresh group.yaml. Tests: `sync-exact-only.test.ts` pins both directions of the gate (mutation-verified: removing the gate, or returning `remaining: []`, both go red). `group-tools.test.ts` pins that the MCP schema dropped `skipEmbeddings` and kept `exactOnly`. `group-cli.test.ts` pins that both removed flags are rejected, with `--exact-only` as an accepted-flag control. `config-parser.test.ts` now pins that legacy keys are PRESERVED (measured, not assumed) rather than only that parsing does not throw. The type narrowing's fallout in test files is cleared: `tsc -p tsconfig.test.json` is 987 errors at head against 987 measured on origin/main, with the two error sets identical — zero net, zero new, zero masked. Verification: `tsc --noEmit` exit 0; prettier clean; eslint 0 errors (2 warnings, both pre-existing on base); 69 test files / 1169 tests green across test/unit/group, test/integration/group, tools, cli-i18n and cli-index-help. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(group): reject malformed and retired group_sync parameters (U1) `GroupService.groupSync` read `exactOnly` off an untyped MCP payload with `Boolean(params.exactOnly)`. While the flag was inert that coercion was harmless; now that it gates the wildcard matching stage, the string "false" -- a routine shape for an LLM caller emitting JSON -- is truthy, so a caller that asked to KEEP wildcard matching got it suppressed and a registry with fewer cross-links persisted to disk. The opposite of the request, written down. Validate instead of coercing, at the service boundary: the MCP SDK does not enforce a tool's advertised inputSchema and `callTool` is reachable directly, so this method is the real gate. The validator mirrors `validateImpactMode`'s `{ value } | { error }` shape -- the established idiom for this boundary, and the one groupSync's other guards already return through. Also refuse `skipEmbeddings` and `allowStale` by name. The CLI rejects them outright because commander errors on an unknown option; the MCP path accepted and silently dropped them, so an agent working from a cached tool schema was never told. Removing them took away discoverability, not acceptance. Both guards run before the group is read off disk, so a rejected call performs no work. Every test asserts the sync did NOT run -- an error string alone cannot distinguish "refused" from "refused but synced anyway". The tool description gains the validation note AFTER the registryOutcome paragraph: `tools.test.ts` slices that description by ordinal position of the 'preserved' / 'superseded' / 'no-prior-registry' literals, so appending past all three leaves those slices intact (verified, 44/44). tsc clean; 1039/1039 group unit tests pass. * fix(group): record the matching stages a sync was told to skip (U2) An `--exact-only` sync wrote a contracts.json and bridge with fewer cross-links and nothing recorded that the wildcard stage had been suppressed by request. `group_impact` and cross-repo `trace` read that registry as authoritative, so a narrowed graph was indistinguishable from a complete one -- and because `group_sync` is MCP-exposed, one agent call durably narrowed the shared answer for every later reader with no signal at all. Add `suppressedMatchStages` to ContractRegistry and SyncResult, following the `unreadableRepos` tri-state end to end: absent means a registry written before the field existed, `[]` is the measurement "this run suppressed nothing", and a populated list names the stages. The writer always emits it, because omitting the empty case is what made "measured, none" unreachable for `unreadableRepos`. Two properties that are easy to get backwards, and are why the split matters: - SyncResult carries the marker on EVERY outcome. The sync genuinely did skip the stage whatever happened to the file afterwards, and the CLI summary (U3) renders from this rather than re-deriving it from the caller's options. - The PERSISTED registry stamps it only on the `written` outcome. The preserve path re-writes `{ ...prior }`, so a carried-forward registry keeps the marker of the sync that actually produced its contracts instead of being relabelled with this run's request. That holds by construction: the registry literal carrying the field is only reachable on the written path. `loadContractRegistryResilient` gains an explicit line, because it rebuilds the envelope field by field with no spread of the parsed root -- a new on-disk field is silently dropped unless named there. Its reader is `recordedMatchStages`, not the existing `recordedRepoList`: that one validates `string[]`, which is right for repo names and one notch too weak here. This repo has already retired MatchType members ('bm25', 'embedding'), so a stale value on disk is a real shape, and dropping non-members keeps an unknown stage name from reaching a caller typed as a live one. Surfaced on `group_contracts` and on `group_sync`'s own return -- deliberately kept separate from the truncated/truncationReason/riskEpistemic triple. That triple reports limits a run hit by accident, whose remedy is to fix the repo; a suppressed stage was asked for, and its remedy is to re-sync without the flag. Conflating them would tell an agent to retry something that returns identically. tsc clean; 1043/1043 group unit tests pass. * fix(group): name a skipped matching stage as skipped, and pin it (U3, U4) Two facts were printing as the same line. `wildcard: 0 cross-links` meant both "the stage ran and matched nothing" and "the stage never ran because you passed --exact-only" -- the same conflation this summary block was introduced to remove one line up, reintroduced by the flag that made the block necessary. Render a suppressed stage as `skipped (--exact-only)`, driven by the sync's own `suppressedMatchStages` rather than by `opts.exactOnly`. The renderer reports what the sync did, not what the caller asked for, so it stays correct on the outcomes where the run ended without writing a registry -- which is where the summary is least legible and a re-derivation from the options would have been wrong. Also drops the `?? 0` fallback and the comment justifying it. The comment claimed a legacy registry could carry a retired matchType into this loop. It cannot: `syncGroup` returns a freshly computed `crossLinks` array on every outcome, and even on the preserve path the prior links go to disk while the fresh array is returned. The code was harmless; the stated reason was false, and a comment that explains an unreachable path is worse than no comment. U4 pins both halves through the CLI. A manifest fixture is sufficient: the stage counts must sum to the total on the `Wrote contracts.json (…)` line, and the skipped rendering does not need a stage to have matched anything, because --exact-only records the suppression whatever the fixture holds. That is why this coverage did not need indexed gRPC/Thrift fixture repos. Verified by mutation, not assertion: removing the skipped-rendering branch turns `names a stage it was told to skip as skipped` red and leaves the other 22 green. A control case pins the opposite direction -- the same group without the flag still reports the stage as zero -- so `skipped` cannot be printed unconditionally and pass. U3 and U4 land together: the test has no value without the renderer, so one commit keeps a revert clean. Both depend on U2, which introduced the field they read. tsc clean; 1066/1066 across the group unit and CLI integration suites. * fix(group): make every description of --exact-only match what it does (U5) Two descriptions this branch wrote or touched still misstated behavior. The MCP `exactOnly` description carries "Manifest links still apply." The CLI help and both locale strings, rewritten in the same commit, omit it -- so the surface most operators read understated what still runs. Manifest cross-links are computed before the gate and are genuinely unaffected by the flag, so the caveat is the accurate half and the CLI now says it too. The `group_sync` tool description opened with "extract HTTP contracts". That clause was carried forward byte-identical while only the trailing cross-linking half was rewritten, and it is wrong: the detect config has six non-HTTP extraction toggles, and this branch's own new test fixture is Thrift. `help-i18n.ts` is deliberately untouched. It maps an option to its translation key and that key already exists; only the commander string and the two locale values carry text, so a text-only change does not reach it. The tool-description edit sits ahead of the registryOutcome paragraph, leaving the relative order of the 'preserved' / 'superseded' / 'no-prior-registry' literals intact -- `tools.test.ts` slices that description by their positions. tsc clean; 64/64 across the locale-parity, help-registration, tool-schema and group-tool suites. * fix(group)!: remove max_candidates_per_step and shared_libs (U6) Both keys were declared, defaulted, written into every generated group.yaml, and read by nothing -- the same three-station dead surface this PR removed for bm25_threshold, embedding_threshold and detect.embedding_fallback. Every other DetectConfig field gates a real extractor in sync.ts; shared_libs gates nothing, because 'lib' contracts come only from the operator-declared manifest extractor. MatchingConfig reaches matching.ts solely through buildNoisyContractFilter, which reads exclude_links_paths and exclude_links_param_only_paths and nothing else. Existing group.yaml files keep loading and keep their keys. parseGroupConfig spreads the raw block over its defaults, so a key the schema no longer knows about survives into the returned config -- which matters because `group add` and `group remove` round-trip the operator's file through loadGroupConfig -> yaml.dump -> write, so anything the parser dropped would be deleted from their checked-in file. The legacy-config test now pins both keys in the same cast form as its three siblings, and the fixture carries shared_libs so that assertion is not vacuous. Two stations that are easy to miss and are swept here: - gitnexus/bench/cross-repo-trace/verify.mjs GENERATES a fresh group.yaml. It is not a preserve-path fixture, so "leave YAML fixtures alone" does not cover it; the repo has two generators and both are updated. It is a .mjs file outside tsconfig's include, so no type gate would have caught it. - config-parser.test.ts asserted the removed default at runtime, which vitest DOES run. That assertion is gone from the defaults case (the key no longer has a default) and re-formed as a preserve assertion in the legacy case. Verification gate, corrected: "zero net new errors against origin/main" would have measured the whole branch delta and been red through no fault of this commit. Measured instead against the branch tip immediately before it -- tsc -p tsconfig.test.json --noEmit reports 989 before and 989 after. Twenty-four typed-literal sites across ten test files, none of them CI-gated, plus the two runtime sites above which are. Note the deliberate side effect: removing a key from the defaults also stops the group add round-trip from re-adding it to a file that never carried it. Nothing in src reads either key, so no behavior changes. BREAKING CHANGE: `matching.max_candidates_per_step` and `detect.shared_libs` are no longer part of the group.yaml schema and are no longer written into generated templates. Existing files carrying them continue to parse and retain them. src tsc clean; 1189/1189 across the group unit, group integration, locale-parity, help-registration and tool-schema suites. * docs(group): map PR #3020 review findings to the commits that close them Retitles the ledger to hold one section per reviewed PR and adds #3020's ten findings. Two things are stated rather than claimed away: `abda0d041` closes three findings because they are one code block plus the test that pins it, and the suppressed-stage marker is a coupled set because the renderer consumes the field the earlier commit introduces. Also records what is NOT closed here -- the PR description's false claim about `max_candidates_per_step` lives outside this branch. * refactor(group): apply simplify-pass findings Four cleanup agents (reuse, simplification, efficiency, altitude) over this run's diff. Efficiency was clean. The rest found five things worth fixing, two of which were real gaps rather than style. `recordedMatchStages` filtered unknown values instead of rejecting the list. That inverted the tri-state on the one field built to prevent exactly this conflation: a stale `['bm25']` -- the scenario its own comment cites as the motivation -- survived as `[]`, which on this field MEANS "measured, nothing was suppressed". A confident clean answer manufactured from a value we could not read. Now all-or-nothing, matching `recordedRepoList`. `gitnexus group contracts` showed nothing after an exact-only sync. The human renderer destructures a fixed field list and gates its incompleteness warning on `truncated`, so the marker reached the MCP payload and the JSON output but not the listing an operator actually reads. It now warns, separately from the `truncated` warning, because the remedies differ: one says fix the repo, this one says re-run without the flag. `verbose` was still coerced with `Boolean()` in the same call whose tool description this branch changed to promise "PARAMETERS ARE VALIDATED". Validated now, and added to the tool schema -- it was read by the backend and advertised nowhere. Reuse: the thrift wildcard-matchable pair existed twice, near-verbatim, in `sync-exact-only` and `registry-suppressed-stages`. Both now call a shared `makeWildcardPair` fixture, so the shape `runWildcardMatch` fires on is defined once. Simplification: dropped a `Set` built per sync over a list that only ever holds zero or one entries; iterating `Object.keys(STAGE_COUNTS) as MatchType[]` also keeps the exhaustiveness the `Record` was built for, which `Object.entries` had discarded. Deliberately not done, with reasons: a schema-driven unknown-parameter layer at the MCP chokepoint (five parameters are read by backends and declared in no schema, so a strict layer rejects working calls today, and it cannot produce the "was removed" message finding 3 is about); folding the marker into `GROUP_IMPACT_TRUNCATION_REASONS` (reverses a recorded plan decision and the bridge scope is an open question for the maintainer); a per-stage suppression cause `Record` (no second suppressor exists -- speculative); collapsing the six `detect` extractor branches into a table (a real generalization, but a refactor outside this diff); and converging an untouched pre-existing CLI test onto the new manifest helper (it captures a value the helper does not return, so the change risks more than the duplication costs). tsc clean; eslint 0 errors (1 pre-existing warning); 1085/1085. * docs(group): remove REVIEW-FINDINGS-MAP.md Removes the findings-to-commits ledger from the source tree. Note for anyone reading this in history: the file was introduced on main by #3012 and carried that PR's findings map; this branch had appended a #3020 section. Deleting it drops both. #3012's content is recoverable with `git show 2c0fb7753:gitnexus/src/core/group/REVIEW-FINDINGS-MAP.md`. * fix(group): stop cross-repo impact and trace claiming a narrowed graph is complete Closes the half of the suppressed-stage finding that was deferred. The reviewers were right that deferring it was the weak point: the motivating harm was named as `group_impact` and cross-repo `trace` traversing a graph missing real edges, and those were exactly the surfaces left uncovered. The deferral rested on an assumption that does not hold. "It is already blind to this, so we do not make it worse" is false: `--exact-only` was inert before this PR, so the number of narrowed registries in the world goes from zero to nonzero exactly when this lands. The blindness was harmless only while narrowing was impossible. And silence there is not neutral -- `cross-impact.ts` documents `truncated: false` as an affirmative completeness claim, so those tools were about to start asserting a complete answer over a knowingly short graph. `suppressedMatchStages` now rides the bridge the same way `unreadableRepos` does: persisted in meta.json (no BRIDGE_SCHEMA_VERSION bump -- meta fields have this precedent), read back all-or-nothing, and carried across the preserve path through `refreshPreservedBridgeMeta`'s diagnostics so a preserved bridge keeps the marker of the sync that actually built it. `crossRepoCompleteness` folds it in, which is what makes this one change reach all three surfaces -- that function is by design the ONE computation behind the truncation triple. Precedence is explicit: an unreadable or unaccounted repo outranks a suppressed stage, because it is the more serious structural gap and its remedy has to be the one reported. `'suppressed-stage'` is a new member of the truncation-reason union rather than a reuse of `'incomplete-sync'`. The earlier decision not to touch that union was about not conflating remedies -- telling an agent to repair a repo that read fine, for a narrowing it requested. A distinct member preserves that reasoning while letting the answer stop claiming completeness, which is what reusing the existing member would have destroyed. The union's guard test did its job: adding a member failed the check that every reason is explained on the agent-facing surface, so the impact tool description now names this one and its distinct remedy (re-run WITHOUT the flag; nothing failed to read). `group status` and its CLI renderer surface it too, on the populated case only -- absent is a registry predating the field and empty is the ordinary clean sync; neither earns a line. Deliberately still not done, and why: a repo-wide unknown-parameter layer for every MCP tool. Five parameters are read by backends and declared in no schema (`subgroupExact`, `unmatchedOnly`, `showClusters`, `showProcesses`, and `verbose` until this branch declared it), and three tools dispatch with no schema entry at all, so a strict layer rejects working calls until each is reconciled. That reconciliation is the work; the layer is the cheap part. It also cannot produce the "was removed and is no longer accepted" message the retired-parameter guard exists to give. tsc clean; eslint 0 errors (2 pre-existing warnings); 1159/1159 across the group unit, group integration and tool-schema suites. * fix(group): make the suppressed-stage signal actually reach its readers Applies the mechanical findings from the code review of the previous commit. That commit claimed cross-repo impact and trace stop reporting a narrowed graph as complete. Trace did; impact did not, and two operator-facing messages said something false. Four reviewers plus the cross-model pass converged on the same two defects, and the untested seams were exactly where they were. `runGroupImpact` recomputed the truncation reason and hardcoded its fallback, so it could never emit 'suppressed-stage' -- the value the previous commit added to the union and documented in the tool description. Every narrowed-but-readable bridge was reported as 'incomplete-sync', telling the caller to repair a repo that read fine. It now propagates the bridge's own reason, as cross-trace.ts already did. The preserve path stamped this run's request onto an older bridge. When no repo can be read the database and registry are kept from an earlier sync, so meta.json has to keep describing that sync; instead `{ ...existing, ...diagnostics }` overwrote its marker, leaving contracts.json, meta.json and bridge.lbug describing three different runs. Currently masked by unreadable-repo precedence, one loosened condition from a live wrong verdict. `group contracts` printed "the last sync did not record which repos it could read" after any exact-only sync: truncated was set with both repo lists empty, so the message fell through to the wrong branch. It is now gated on the reason, not the flag. `group impact` likewise blamed the local walk for a floor the flag caused. The tri-state reader is now defined once, in the leaf module whose own comment says it exists so this exact duplication cannot recur -- it had been copied into bridge-db.ts within one commit of that comment being true. Both agent-facing descriptions now name the field. The previous commit added it to three payloads and documented it on none. Tests cover what shipped green: the preserve path for both artifacts (verified by mutation -- reintroducing the stamp turns exactly one test red), and the reason's REACHABILITY. The existing guard only asserted each reason is described, which is why a documented-but-unemittable value passed it. Also corrects a comment that said the marker is deliberately not folded into the truncation triple. True when written; false one commit later. tsc clean; eslint 0 errors; 1163/1163 across the group unit, group integration and tool-schema suites. * fix(group): drop verbose from the MCP surface, fail a superseded bridge closed Two maintainer-directed findings from the review. verbose is removed from the group_sync MCP schema and from GroupService, and kept on the CLI. The parameter never did what either description claimed: the gates emit workspace-dependency discovery stats and one aggregate manifest line, not "each cross-link". Worse, they emit them through the server's logger, which an MCP caller cannot read at all -- so advertising it introduced precisely the kind of knob this PR exists to delete, in the PR that deletes them. SyncOptions keeps the field and the CLI keeps --verbose, because a CLI user really can see that output; its help now says "Show additional sync diagnostics", which is what it shows. It was added to the MCP schema earlier in this same PR, so there is no published compatibility burden in taking it back out. A caller that still sends it is ignored rather than refused: it was never a documented parameter, and the retired-name guard is reserved for ones this tool actually withdrew. The second fixes a split-brain the completeness work made materially worse. When contracts.json commits and the bridge write then fails, the previous database stays in place describing an EARLIER sync. Until now it kept vouching for itself, so group_impact could traverse the superseded graph and call its answer complete while group_contracts reported the advanced registry -- two public surfaces making contradictory epistemic claims out of one sync. That was tolerable when the disagreement was about counts. It is not, now that suppressed-stage makes completeness a correctness property. markBridgeProvenanceUnknown withdraws the claim without touching the database: bridgeMetaMatchesFile already gives provenanceUnknown highest precedence and refuses to vouch for the pair, so cross-repo answers downgrade to a floor until a sync succeeds. Deliberately not a re-stamp -- the metadata still describes the database it was written for, and saying otherwise recreates the mis-pairing the preserve path avoids. Deliberately not a delete -- the old graph is still worth having as a floor, it just stops being called complete. Best-effort, because it runs inside a failure handler and must not replace a reported bridge failure with an unrelated one; the warning now states which of the two happened. Shared registry+bridge generation identity is the architectural fix and is deliberately NOT attempted here. This is the PR-sized containment. Verified by mutation, both directions: neutering the withdrawal turns the new test red, and a control pins that a healthy sync does not withdraw provenance -- otherwise every successful run would report its own answers as a floor. tsc clean; eslint 0 errors; 1185/1185. * refactor(group): apply simplify-pass findings Four cleanup agents over the last five commits. Efficiency was clean and traced why: the containment helper is failure-path only, the reason ternary sits after the fan-out loop, and the tri-state readers run once per artifact read. The strongest finding was one the diff itself proved. `refreshPreservedBridgeMeta` enforced the never-persisted rule for `repoListsUnreadable` and `pairedWithDatabase` with two deletes in its own body, under a comment noting it was the only code that read metadata and wrote it back. That held exactly as long as there was one such caller. `markBridgeProvenanceUnknown` made it two, and inherited nothing. The strip now lives in `writeBridgeMeta`, so every writer gets it and no future one can forget; `pairedWithDatabase` is the dangerous one, because persisted it tells every later reader the pair was verified when nothing verified it. `group impact` still printed "fan-out stopped early" whenever `truncatedRepos` was non-empty — but the bridge's incomplete repos are unioned into that list even when zero crossings were attempted, so a structural gap was reported as a runtime one, with the only working remedy omitted. That is the same false-cause shape the contract listing was re-gated for one commit ago, left live one command over because the new reason was bolted in front of the old branch rather than replacing the thing it branched on. Now keyed on the reason. The `?? 'incomplete-sync'` arm in cross-impact was unreachable: reaching it needs `truncated` true with all three of its inputs false, which `truncated = runtimeTruncated || bridge.truncated` forbids. Flattened. Also: a `recordedMatchStages` insert had split `crossRepoCompleteness` from its own JSDoc; one new test was a strict subset of another; and the bridge-failure warning interleaved concatenation with a mid-chain ternary. The new invariant assertion was caught being VACUOUS by mutation before it shipped — seeded with a valid repo list, `readBridgeMeta` never sets the reader-only field, so it passed with or without the strip. The fixture now seeds an unreadable list, and both it and the pre-existing assertion go red when the strip is removed. Deliberately skipped, with reasons: a shared `firstTruncated` fold over `TruncationFields` (the right altitude, but it changes cross-trace's return assembly and that surface separately documents a 'timeout' rung it cannot emit — a behavior change, not a cleanup); a reason-keyed `explainFloor` helper across all four CLI renderers (real, but a four-site refactor); narrowing the persisted stage vocabulary to a `SuppressibleStage` alias (would be undone by the very extension the field was modelled as a list to allow); moving `verbose` to `logger.debug` and deleting `SyncOptions.verbose` (the maintainer explicitly directed keeping both); and merging the two tri-state readers behind a predicate (they are adjacent in one file now, so a tightening applies to both by inspection — the duplication the comment warned about was cross-FILE). tsc clean; eslint 0 errors; 1164/1164. * fix(group): address gitnexus-check findings Seven bot comments across two review rounds; five distinct after dedup. Four were valid and are fixed, two were already resolved by later commits the bot had not seen. The validator could throw from its own error path. `JSON.stringify` is the right renderer there — it is what distinguishes the string "false" from the boolean, which is the entire point of the message — but it throws on a BigInt and on a cyclic object. So a validator promising a structured `{ error }` instead rejected, and `callTool` is reachable directly, so neither input is hypothetical. Guarded, keeping the distinction and falling back for the shapes that cannot serialize. An unreadable suppression record read as "nothing was suppressed". `recordedMatchStages` is all-or-nothing by design, so garbage collapses to `undefined` — and the consumer treated `undefined` as an empty measurement, throwing that safety away and reporting a registry it could not parse as complete. Present-but-unreadable now forces the floor, while absent stays legitimate: a registry written before the field existed has no opinion and should not be dragged to a floor for it. Two test-side findings, both real and both invisible to CI because `tsconfig.json` is src-only. Three `mock.calls[0][1]` accesses did not type-check against a zero-arg mock, and four assertions read `truncationReason` / `riskEpistemic` straight off `CrossRepoCompleteness`, which is a discriminated union carrying them on one arm. Also removed a `StoredContract` import that went dead when those fixtures moved to `makeWildcardPair`. Worth recording: U6 set a test-config gate at 989 errors and later commits walked it to 994 without anyone re-measuring — the bot caught three of the five. Now 987, below the original baseline. Already fixed, not by this commit: the preserve-path stamp the bot flagged against |
||
|---|---|---|
| .. | ||
| call-routing | ||
| cfg | ||
| group | ||
| import-resolvers | ||
| ingestion | ||
| integrations | ||
| lbug | ||
| mcp | ||
| model | ||
| scope-resolution | ||
| storage | ||
| taint | ||
| workers | ||
| ai-context-unknown-risk-policy.test.ts | ||
| ai-context.test.ts | ||
| analysis-features.test.ts | ||
| analyze-api.test.ts | ||
| analyze-community-skills-gate.test.ts | ||
| analyze-config.test.ts | ||
| analyze-embedding-endpoint-flags.test.ts | ||
| analyze-embeddings-limit.test.ts | ||
| analyze-finalize-failure-exits.test.ts | ||
| analyze-gitnexusrc.test.ts | ||
| analyze-heap-respawn.test.ts | ||
| analyze-http-endpoint-error.test.ts | ||
| analyze-job.test.ts | ||
| analyze-launch-collapse.test.ts | ||
| analyze-lbug-checkpoint-threshold.test.ts | ||
| analyze-local-embedding-error.test.ts | ||
| analyze-no-stats-bridge.test.ts | ||
| analyze-pagesize-error.test.ts | ||
| analyze-respawn-progress-terminal.test.ts | ||
| analyze-self-commit-bridge.test.ts | ||
| analyze-undeclared-pair-error.test.ts | ||
| analyze-wal-error.test.ts | ||
| analyze-wipe-error.test.ts | ||
| analyze-worker-core.test.ts | ||
| analyze-worker-ipc.test.ts | ||
| analyze-worker-pool-size.test.ts | ||
| analyze-worker-timeout.test.ts | ||
| analyzer-identity-is-inside.test.ts | ||
| analyzer-identity-linked-dev-dependency.test.ts | ||
| analyzer-identity-path-normalization.test.ts | ||
| analyzer-identity-symlink.test.ts | ||
| analyzer-identity.test.ts | ||
| api-analyze-token.test.ts | ||
| api-analyze-upload.test.ts | ||
| api-file-route.test.ts | ||
| api-graph-streaming.test.ts | ||
| api-query-readonly-wiring.test.ts | ||
| api-readonly-wiring.test.ts | ||
| assert-publish-grammar-coverage.test.ts | ||
| ast-utils.test.ts | ||
| basicblock-callee-ids-schema.test.ts | ||
| binding-accumulator.test.ts | ||
| blade-template-routes.test.ts | ||
| bm25-search.test.ts | ||
| build-tree-sitter-grammars-probe.test.ts | ||
| c-static-linkage-side-channel.test.ts | ||
| call-attribution-issue-1166.test.ts | ||
| call-extraction.test.ts | ||
| call-form.test.ts | ||
| call-processor-routes.test.ts | ||
| call-summary-schema-version.test.ts | ||
| callable-id-lockstep.test.ts | ||
| calltool-dispatch-id-bridge.test.ts | ||
| calltool-dispatch.test.ts | ||
| canonicalize-path-long-path-prefix.test.ts | ||
| cfg-callee-ids-of-block.test.ts | ||
| cfg-callees-of-block.test.ts | ||
| cfg-site-position.test.ts | ||
| checkpoint-busy-2599.test.ts | ||
| chunker.test.ts | ||
| cjk-segmentation.test.ts | ||
| cli-commands.test.ts | ||
| cli-entry.test.ts | ||
| cli-i18n.test.ts | ||
| cli-impact-disambiguation.test.ts | ||
| cli-impact-pdg-format.test.ts | ||
| cli-index-help.test.ts | ||
| cli-message.test.ts | ||
| clone-safety-cloneable.test.ts | ||
| clone-safety-payloads.test.ts | ||
| clone-safety.test.ts | ||
| cobol-copy-expander.test.ts | ||
| cobol-preprocessor.test.ts | ||
| cohesion-consistency.test.ts | ||
| community-processor.test.ts | ||
| compatible-stdio-transport.test.ts | ||
| conn-lock.test.ts | ||
| constant-resolver.test.ts | ||
| convex-dispatch-metadata.test.ts | ||
| convex-metadata-persistence-contract.test.ts | ||
| convex-metadata.test.ts | ||
| cors.test.ts | ||
| cpp-captures-budget.test.ts | ||
| cpp-ue-preprocessor.test.ts | ||
| cross-file-routes.test.ts | ||
| cross-platform-shard.test.ts | ||
| csharp-namespace-extraction.test.ts | ||
| csv-escaping.test.ts | ||
| cursor-hook.test.ts | ||
| cypher-escape.test.ts | ||
| dart-import-resolver.test.ts | ||
| dart-type-extractor.test.ts | ||
| data-route-table-routes.test.ts | ||
| deferred-resolution-profile.test.ts | ||
| definition-properties.test.ts | ||
| detect-changes-eol.test.ts | ||
| detect-changes-hunk-scale.test.ts | ||
| detect-changes-local-id-stability.test.ts | ||
| detect-changes-worktree.test.ts | ||
| dispatch-guard-routes.test.ts | ||
| django-root-discovery.test.ts | ||
| django-route-extraction.test.ts | ||
| dockerfile-runtime-asset-parity.test.ts | ||
| doctor-format.test.ts | ||
| drop-fts-index-error-classification.test.ts | ||
| embedder.test.ts | ||
| embedding-checkpoint.test.ts | ||
| embedding-chunking.test.ts | ||
| embedding-config.test.ts | ||
| embedding-count.test.ts | ||
| embedding-dims-guard.test.ts | ||
| embedding-dims.test.ts | ||
| embedding-install-arg-delivery.test.ts | ||
| embedding-pipeline.test.ts | ||
| embedding-runtime-install.test.ts | ||
| embedding-runtime-resolution.test.ts | ||
| embedding-runtime-support.test.ts | ||
| embeddings-install-command.test.ts | ||
| engineering-skills-contract.test.ts | ||
| ensure-initialized-reinit-watermark.test.ts | ||
| entry-point-scoring.test.ts | ||
| env.test.ts | ||
| esm-extension-resolution.test.ts | ||
| eval-formatters.test.ts | ||
| eval-server-auth.test.ts | ||
| eval-server-bind-restriction.test.ts | ||
| eval-server-tool-allowlist.test.ts | ||
| evidence-provenance-helper.test.ts | ||
| exact-search.test.ts | ||
| expo-routes.test.ts | ||
| extension-load-error.test.ts | ||
| extract-element-type-from-string.test.ts | ||
| extract-generic-type-args.test.ts | ||
| fastapi-router-bindings.test.ts | ||
| fetch-reason-parsing.test.ts | ||
| fetch-site-capture.test.ts | ||
| field-extraction.test.ts | ||
| filesystem-walker-order.test.ts | ||
| format-elapsed.test.ts | ||
| framework-detection.test.ts | ||
| fts-degraded-warning.test.ts | ||
| fts-indexes.test.ts | ||
| fts-rss-verdict.test.ts | ||
| fts-schema.test.ts | ||
| git-clone.test.ts | ||
| git-utils.test.ts | ||
| git.test.ts | ||
| gitnexus-home-roots.test.ts | ||
| grammar-update-monitor.test.ts | ||
| graph-collapse-wiring.test.ts | ||
| graph.test.ts | ||
| group-service-not-found.test.ts | ||
| has-method.test.ts | ||
| hf-env.test.ts | ||
| hook-db-lock-probe.test.ts | ||
| hooks.test.ts | ||
| http-client-safe-url.test.ts | ||
| http-embedder.test.ts | ||
| http-embedding-body-retry.test.ts | ||
| hybrid-search.test.ts | ||
| ignore-build-output.test.ts | ||
| ignore-service.test.ts | ||
| impact-batching-grouping.test.ts | ||
| impact-confidence.test.ts | ||
| impact-pagination.test.ts | ||
| impact-pdg-ascent-note.test.ts | ||
| impact-pdg-blast-radius-metrics.test.ts | ||
| impact-pdg-compose-dedup.test.ts | ||
| impact-pdg-id-bridge-gate.test.ts | ||
| impact-pdg-id-vs-name-metrics.test.ts | ||
| impact-pdg-metric-math.test.ts | ||
| impact-pdg-real-code-metrics.test.ts | ||
| import-cycles.test.ts | ||
| import-resolver-factory.test.ts | ||
| incremental-dirty-recovery.test.ts | ||
| incremental-escalation-gate.test.ts | ||
| incremental-file-hash.test.ts | ||
| incremental-fts-drop-ordering.test.ts | ||
| incremental-index-extension-dml-gate.test.ts | ||
| incremental-orchestration.test.ts | ||
| incremental-parse-cache.test.ts | ||
| incremental-shadow-candidates.test.ts | ||
| incremental-subgraph-extract.test.ts | ||
| incremental-vector-extension-ordering.test.ts | ||
| index-freshness-graph-collapse.test.ts | ||
| index-lock.test.ts | ||
| index-repo-command.test.ts | ||
| ingestion-utils.test.ts | ||
| install-duckdb-extension.test.ts | ||
| java-call-arity.test.ts | ||
| java-description-extractor.test.ts | ||
| java-module-resolution.test.ts | ||
| java-route-const-pipeline-e2e.test.ts | ||
| java-route-const-resolver.test.ts | ||
| java-spring-route-ingestion.test.ts | ||
| jcl-parser.test.ts | ||
| jvm-package-siblings.test.ts | ||
| kotlin-description-extractor.test.ts | ||
| kotlin-module-resolution.test.ts | ||
| kotlin-scope-captures.test.ts | ||
| kotlin-static-marker.test.ts | ||
| language-availability-skip.test.ts | ||
| language-skip.test.ts | ||
| laravel-route-extraction.test.ts | ||
| lazy-action.test.ts | ||
| lbug-adapter-wal-schema.test.ts | ||
| lbug-checkpoint-lifecycle.test.ts | ||
| lbug-checkpoint.test.ts | ||
| lbug-config-pagesize.test.ts | ||
| lbug-config-wal.test.ts | ||
| lbug-delete-all-error.test.ts | ||
| lbug-embedding-hashes.test.ts | ||
| lbug-extension-loader.test.ts | ||
| lbug-missing-staging-csv.test.ts | ||
| lbug-native-check.test.ts | ||
| lbug-native-safe-path.test.ts | ||
| lbug-pool-fts-load.test.ts | ||
| lbug-pool-pinning.test.ts | ||
| lbug-query-result-utils.test.ts | ||
| lbug-readonly-error.test.ts | ||
| lbug-wipe-db-files.test.ts | ||
| leading-doc-comment.test.ts | ||
| leading-doc-description-all-languages.test.ts | ||
| line-base-conversion.test.ts | ||
| list-status-branch.test.ts | ||
| local-backend-embedding-dims-warn.test.ts | ||
| local-backend-lazy-vector.test.ts | ||
| local-backend-maxbuffer.test.ts | ||
| local-backend-semantic-warn.test.ts | ||
| local-cli-subprocess.test.ts | ||
| local-symbol-pruner.test.ts | ||
| logger.test.ts | ||
| max-file-size.test.ts | ||
| mcp-http-transport.test.ts | ||
| mcp-output-budget.test.ts | ||
| mcp-read-only.test.ts | ||
| mcp-repository-policy.test.ts | ||
| mcp-stdout-sentinel.test.ts | ||
| mcp-wal-feedback.test.ts | ||
| method-extraction.test.ts | ||
| method-props.test.ts | ||
| middleware-public-origin.test.ts | ||
| middleware-trust-proxy.test.ts | ||
| mro-processor.test.ts | ||
| native-check-probe.test.ts | ||
| nest-decorator-routes.test.ts | ||
| node-module-compat.test.ts | ||
| node-workspace-packages.test.ts | ||
| node-workspace-scope.test.ts | ||
| noise-filter.test.ts | ||
| onnxruntime-common-resolver.test.ts | ||
| onnxruntime-node-resolver.test.ts | ||
| parse-diff-hunks.test.ts | ||
| parse-impl-heap-guard-pipeline.test.ts | ||
| parse-impl-heap-guard.test.ts | ||
| parse-impl-warm-cache-parsedfile-coverage.test.ts | ||
| parse-impl-worker-lazy-cache.test.ts | ||
| parse-impl-worker-startup-gating.test.ts | ||
| parsedfile-store.test.ts | ||
| parser-loader-abi.test.ts | ||
| parser-loader-skip-optional.test.ts | ||
| parser-loader.test.ts | ||
| parsing-worker-fallback.test.ts | ||
| pdg-bridge-id-match.test.ts | ||
| pdg-callee-id-capture.test.ts | ||
| pdg-impact-engine.test.ts | ||
| pdg-mode-flip.test.ts | ||
| phase-timer.test.ts | ||
| php-namespace-extraction.test.ts | ||
| php-template-scope.test.ts | ||
| pipeline-exports.test.ts | ||
| pipeline-runner.test.ts | ||
| platform-capabilities.test.ts | ||
| pool-freshness-invalidation.test.ts | ||
| pool-wal-recovery.test.ts | ||
| prebuild-coverage.test.ts | ||
| preprocess-source-parity.test.ts | ||
| private-ip.test.ts | ||
| process-processor.test.ts | ||
| processes-phase-sink-wiring.test.ts | ||
| publish.test.ts | ||
| python-const-resolver.test.ts | ||
| python-decorator-arg-capture.test.ts | ||
| query-batch.test.ts | ||
| query-degraded-signal.test.ts | ||
| query-determinism-guard.test.ts | ||
| query-fts-parameterization.test.ts | ||
| query-params.test.ts | ||
| query-text-unbounded-guard.test.ts | ||
| range-binding-parse-timeout.test.ts | ||
| rate-limit.test.ts | ||
| receiver-chain-codec.test.ts | ||
| receiver-extraction.test.ts | ||
| receiver-twin-list-drift.test.ts | ||
| rel-csv-split.test.ts | ||
| rel-pair-routing.test.ts | ||
| remove-command.test.ts | ||
| rename-edit-report.test.ts | ||
| render-blueprint.test.ts | ||
| repo-manager-ensure-ignore-readonly.test.ts | ||
| repo-manager-finalize-invariant.test.ts | ||
| repo-manager-reconcile.test.ts | ||
| repo-manager-registry-atomic-write.test.ts | ||
| repo-manager-registry-strict-read.test.ts | ||
| repo-manager-rm-failure.test.ts | ||
| repo-manager-transient-error.test.ts | ||
| repo-manager.test.ts | ||
| resolve-enclosing-owner.test.ts | ||
| resolve-invocation.test.ts | ||
| resolve-route-handler-symbols.test.ts | ||
| resources.test.ts | ||
| result-merge.test.ts | ||
| review-agent-workflow.test.ts | ||
| route-process-linking.test.ts | ||
| route-tool-detection.test.ts | ||
| run-analyze-adopt-failure.test.ts | ||
| run-analyze-fts-repair.test.ts | ||
| run-analyze.test.ts | ||
| runner-exec-tail.test.ts | ||
| safe-parse.test.ts | ||
| schema-fingerprint.test.ts | ||
| schema-pair-coverage.test.ts | ||
| schema.test.ts | ||
| scope-index-store.test.ts | ||
| security.test.ts | ||
| semantic-chunk-search.test.ts | ||
| server-api-repo-resolution.test.ts | ||
| server-cors-stack.test.ts | ||
| server-sse-payload.test.ts | ||
| server-validation.test.ts | ||
| server.test.ts | ||
| setup-antigravity.test.ts | ||
| setup-codex.test.ts | ||
| setup-jsonc.test.ts | ||
| setup-selection.test.ts | ||
| setup.test.ts | ||
| shape-check.test.ts | ||
| shard-arg.test.ts | ||
| shard-balance.test.ts | ||
| shared-type-extractors.test.ts | ||
| shipped-skills-sync.test.ts | ||
| shutdown-helpers.test.ts | ||
| sibling-clone-drift.test.ts | ||
| sidecar-recovery.test.ts | ||
| skill-evolution-workflow.test.ts | ||
| skill-gen.test.ts | ||
| skills-steering.test.ts | ||
| skip-git-cli.test.ts | ||
| source-control-bytes.test.ts | ||
| spring-annotation-arguments.test.ts | ||
| spring-aop.test.ts | ||
| spring-auto-configuration.test.ts | ||
| spring-bean-extractor.test.ts | ||
| spring-bean-schema.test.ts | ||
| spring-config-bindings.test.ts | ||
| spring-interface-inheritance.test.ts | ||
| spring-non-http-handlers.test.ts | ||
| spring-route-extractor-parity.test.ts | ||
| staleness.test.ts | ||
| stdout-silence.test.ts | ||
| stream-graph-emit-config.test.ts | ||
| stream-graph-emit-force-ordering.test.ts | ||
| stream-pdg-emit-config.test.ts | ||
| stream-query-driver-guard.test.ts | ||
| structure-processor.test.ts | ||
| suffix-index-ambiguity.test.ts | ||
| swift-conditional-directive-preprocess.test.ts | ||
| symbol-table.test.ts | ||
| sync-plugin-manifests.test.ts | ||
| temp-dir-pool-cleanup.test.ts | ||
| text-generator.test.ts | ||
| tool-direct-cli.test.ts | ||
| tool-process-linking.test.ts | ||
| tool-staleness.test.ts | ||
| tools.test.ts | ||
| topological-sort.test.ts | ||
| trace-bfs.test.ts | ||
| trace-cli.test.ts | ||
| tree-sitter-queries.test.ts | ||
| ts-js-function-node-type-lists.test.ts | ||
| ts-receiver-chain-capture.test.ts | ||
| tsconfig-index.test.ts | ||
| type-env.test.ts | ||
| uninstall.test.ts | ||
| upload-filter-ignore-drift.test.ts | ||
| upload-ingest.test.ts | ||
| upload-sweep.test.ts | ||
| utils.test.ts | ||
| variable-extraction.test.ts | ||
| vendored-grammars.test.ts | ||
| vue-sfc-extractor.test.ts | ||
| wal-checkpoint-driver-reentrancy.test.ts | ||
| wal-checkpoint-driver.test.ts | ||
| web-ui-serving.test.ts | ||
| wiki-db-pin.test.ts | ||
| wiki-flags.test.ts | ||
| wiki-graph-queries-list-binding.test.ts | ||
| wiki-grouping-batch.test.ts | ||
| wiki-llm-client.test.ts | ||
| wiki-mermaid-sanitizer.test.ts | ||
| windows-long-path-prefix.test.ts | ||
| worker-pool-cumulative-timeout.test.ts | ||
| worker-pool-error-stack.test.ts | ||
| worker-pool-options.test.ts | ||
| worker-pool-ready-timeout-env.test.ts | ||
| worker-pool-resilience.test.ts | ||
| worker-pool-resource-limits.test.ts | ||
| worker-pool-slot-generation.test.ts | ||
| worker-pool-stall-credit.test.ts | ||
| worker-pool-startup-stderr.test.ts | ||
| worker-pool-stdout-forward.test.ts | ||
| worker-pool-timeout-retire.test.ts | ||
| worker-pool-transferlist.test.ts | ||
| worker-pool-windows-quarantine.test.ts | ||