* fix(analyze): degrade FTS search instead of aborting analyze on index-build failure
createSearchFTSIndexes re-tokenizes every stored row on every analyze run
(full or incremental). A native LadybugDB tokenizer error on a single
pre-existing row (e.g. "Failed calling LOWER: Invalid UTF-8") previously
propagated uncaught out of run-analyze.ts's main FTS phase, discarding an
otherwise-successful run's graph/embeddings work every time analyze ran
thereafter.
Add buildSearchIndexesOrDegrade(), which catches build/verify failures and
lets analyze finish with keyword search degraded for that run instead —
mirroring the existing sibling degrade path for a missing FTS extension.
The dedicated --repair-fts path is untouched and still fails loudly.
Fixes#2544, #2546.
* fix(analyze): keep capabilities.fts/ftsSkipped honest when index build degrades
ftsSkipped and capabilities.fts.status were keyed only on ftsAvailable
(extension loaded), which the new degrade path leaves true even when the
index build itself failed. Track that outcome in ftsReady and use it for
both, and update run-analyze-fts-repair.test.ts's coverage of this path
from asserting the old throw to asserting the new degrade contract
(ftsSkipped, log message, meta.json capabilities.fts.status).
* docs(plans): add provider-hook value-refs plan (#2437)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(plans): deepen #2437 plan to USES + property-dispatch design
Design revised after prior-art research (Kythe ref vs ref/call, Joern
METHOD_REF, Feldthaus field-based call graphs, CodeQL impliedReceiverStep):
registration sites emit reference-class USES, invocation is recovered by a
field-based property-dispatch pass synthesizing CALLS at member-call sites.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(scope-resolution): model provider-hook value references (#2437)
Functions referenced as object-literal property values (provider hooks like
emitScopeCaptures: emitCppScopeCaptures) previously produced no edge at all,
so impact/context reported a false-safe 0 upstream dependents.
Two coordinated halves, per prior art (Kythe ref vs ref/call, Joern
METHOD_REF, Feldthaus ICSE'13 field-based call graphs, CodeQL
impliedReceiverStep):
- Registration -> USES: new ReferenceKind 'value-ref'; TS/JS queries capture
pair values and shorthand properties (with @reference.property-key);
emitted as a reference-class USES edge, reason 'scope-resolution:
value-ref'. Resolution is callable-gated so plain values emit nothing.
- Dispatch -> CALLS: new shared pass emitPropertyDispatchCalls synthesizes
CALLS (reason 'property-dispatch', confidence 0.7, per-key fan-out cap 32
calibrated on this repo's 16-provider hook tables) from member-call sites
to every function registered under the same property key.
Deviation from plan: the pass owns value-ref resolution entirely via the
post-finalize findCallableBindingInScope walker — the shared registries only
see pre-finalize local bindings, so imported hooks (the c-cpp.ts case) were
unresolvable through lookupForSite; Reference.propertyKey passthrough
dropped as unnecessary.
SCHEMA_BUMP 13 -> 14: ParsedFile gains value-ref sites + propertyKey.
Verified end-to-end: impact(emitCppScopeCaptures, upstream) now reports 8
impacted / HIGH with extractParsedFile (true dispatch caller) at d=1 via
property-dispatch and the c-cpp.ts registration via USES.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(scope-resolution): cover value-ref registration and property dispatch (#2437)
Integration: same-file/cross-file/aliased/shorthand registrations emit USES;
non-callable and destructuring values emit nothing; dispatch sites gain
property-dispatch CALLS (incl. JS twins and per-language partitioning);
fan-out-capped keys are dropped entirely; factory-call values unchanged.
Unit: capture-shape pins for @reference.value-ref + @reference.property-key.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(scope-resolution): surface dropped property-dispatch keys in stats (#2437)
Review finding: skippedKeys was returned but discarded — a hook table
larger than the fan-out cap silently reopened the #2437 gap for those
keys. Log dropped keys and fold value-ref USES + dispatch CALLS into
referenceEdgesEmitted.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(plans): add callable reference-flow implementation plan
* fix(scope-resolution): close property-dispatch review gaps
* feat(scope-resolution): add callable flow facts
* feat(scope-resolution): resolve callable value flow
* feat(scope-resolution): resolve callable references across providers
* fix: harden callable reference flow resolution
* fix(scope-resolution): preserve callable binding semantics
* docs(plans): add pr-2522-review-fixes plan
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(storage): bump INCREMENTAL_SCHEMA_VERSION for callable-value-flow edges
Callable-value-flow CALLS/USES edges (#2437) can connect two files whose
content did not change, but the incremental write set only covers changed
files — a top-up against a pre-v7 index would silently omit the new edges
for every unchanged file pair, indefinitely. Force the one-time full
re-analyze (review finding 1, #2522).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(storage): sanitize callable-flow sites per-site at load, log drops
The load-time validator rejected the WHOLE ParsedFile when one site was
malformed or over-bound, with no logging — and C++ legitimately emits
empty-string parameterTypes entries ('' = unknown, the
ReferenceSite.argumentTypes convention) for cv-only/ERROR-recovered types,
so real repos fell into a permanent, silent warm-cache-miss reparse loop
through the #1983-sensitive main-thread path (review finding 7, #2522).
Now: '' entries are valid in type arrays; a malformed/over-bound site drops
only itself (counted, warned once per load); only non-array garbage —
evidence the serialization itself is untrustworthy — rejects the file.
Deviation from plan §6 wording: validator-side tolerance replaces emit-side
clamps — smaller diff, same asymmetry closed at the single chokepoint.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(scope-resolution): keep declarations in the union for reassigned callable cells
The binding-lookup suppression for fact-constrained cells was wholesale:
reassigning a declared function through its own name (greet = other;
greet()) deferred the call to the solver, which then refused the lexical
lookup that resolves the declaration — an unresolvable RHS yielded zero
CALLS for a call that resolved pre-flow (review finding 8, #2522).
Suppression now applies only to cells bound by FORMAL facts — its actual
purpose (a parameter whose grammar emits no declaration binding must not
adopt a same-named outer function). Copy/alias/store/load destinations keep
their declaration as an inclusion seed (Andersen-style union).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(scope-resolution): count forfeited deferred sites in the budget-bailout warning
On work-budget exhaustion the deferred invoke sites end the run with zero
CALLS — free-call fallback and reference emission already skipped them —
but the warning said 'ordinary graph emission remains untouched', which is
false for exactly those sites. The warning context now carries the
unresolved deferred-site count and the comment states the real cost
(review finding: budget-bailout honesty, #2522).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(scope-resolution): surface dropped property-dispatch keys in stats and warn payload
The over-cap warning carried only a count; the dropped key NAMES were
discarded and RunScopeResolutionStats had no field, so the PR-body claim
'includes them in resolver statistics' was unimplemented (review finding,
#2522; reviewer ask on the fan-out cap). The warn payload now names up to
20 dropped keys and the stats carry propertyDispatchSkippedKeys.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(scope-resolution): drop producer-less ownerQualifiedName from formal sites
No capture emitter anywhere produces @callable-flow.owner-qualified-name —
the solver branch consuming it was unreachable in production, yet the field
was typed, parsed, validated, and unit-tested with hand-built input (review
finding 16, #2522; YAGNI). Re-add with a real producer if C++ qualified
member declarators ever need it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(scope-resolution): drop dead callable-flow knobs
CallableFlowPassingMode 'callable-object' had no producer and no consumer
distinguishing it, and CallableFlowCaptureOptions.extractCallArguments had
no language providing it (unlike its live sibling extractCallCallee) —
review finding 17, #2522 (YAGNI). The invocation-kind 'callable-object'
is a different, live concept and stays.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(ingestion): bind subscripted callable cells to the container, not the index
terminalIdentifier iterates children in reverse, so tbl[i] = handler seeded
the INDEX variable's cell (polluting a same-named formal) and tbl[i](7)
looked up the callee under i in a different scope — no join, no CALLS edge
for the classic function-pointer-array dispatch (review finding 12, #2522).
Subscript nodes now recurse into their container field only, in both
bindingIdentifier and terminalIdentifier, across the fielded grammars
(C/C++/JS/TS/Python/Go/Java).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(ingestion): make cross-function file-scope callable bindings resolvable
Two stacked gaps killed the canonical C callback-registration pattern
(fp assigned in init(), called in run()) — the exact #2437 false-safe this
PR exists to fix (review finding H1, #2522):
1. isVisibleValueBinding only consulted assignment regions and formals, so
a call in a function OTHER than the assigning one emitted no invoke
fact. A declared callable-typed binding is now a value binding wherever
its declaration is visible (visibleCallableSignature).
2. The C scope query had no @declaration.variable pattern for function-
pointer declarators — void (*fp)(int); created no scope-tree binding,
so the seed (init) and invoke (run) cells canonicalized to different
keys and never joined. Both bare and initialized forms now bind.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(c): detect variadic parameters via the named variadic_parameter node
tree-sitter-c materializes '...' as a named variadic_parameter node; the
anonymous-token checks never matched, so variadic function-pointer
signatures were emitted with a wrong fixed arity and no '...' sentinel
(review finding, #2522). C++ is unaffected ('...' stays an anonymous token
there); the token checks remain for such grammars.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(ingestion): emit invoke facts for field-stored callable member calls
The C ops-vtable pattern (o->run = handler; o->run(1)) captured the store
but never the call — the member path in emitCallFacts bailed for languages
without protocol methods, and the value-binding index recorded the member
store under the OBJECT's name ('o'), not the member's ('run') (review
finding 11/M3, #2522). Member destinations now also record their terminal
member name, and a member call whose name-cell has a visible store emits an
indirect invoke — gated on the store so plain accessor calls (map.get)
stay inert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cpp): disambiguate (obj->*ptr)() ERROR recovery by token order
tree-sitter-cpp groups the recovered '->*' two ways depending on
error-recovery cost (identifier lengths): [identifier, ERROR '->*m'] or
[ERROR 'obj->*', identifier]. The recovery assumed the first shape, so the
second silently swapped receiver/member and dropped the call site — the
committed test passed only by name luck (review finding H2, #2522). The
identifier's position relative to '->*' inside the ERROR now decides roles.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cpp): class members are never file-local in hasFileLocalCallableLinkage
The name-keyed file-local set is populated from every static declaration,
so an in-class 'static void make();' (external linkage — in-class static
means no-instance) and any member sharing a name with a static free
function were over-marked, refusing legitimate cross-file
declaration/definition joins (review finding 13/M2, #2522). Method and
Constructor defs now bypass the name-set, per the hook's own linkage-only
contract.
Deviation from plan step 13: the regression is a unit-level contract pin
rather than an end-to-end join test — C++ merges out-of-line member
definitions onto the member node by qualified identity, so the graph shape
cannot discriminate the join refusal for members.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cpp): classify parameter passing mode from the declarator chain only
A whole-subtree scan for reference_declarator inverted copy vs alias:
void reg(void (*cb)(int& out)) marked the by-value pointer cb as
'reference' because of the NESTED parameter's int&, making the solver
back-propagate formal targets into every caller's argument cell — alias
semantics for a copy (review finding 14/M5, #2522). The chain walk never
descends into nested parameter lists; a reference anywhere ON the chain
(int& x, void (*&cb)(int)) still aliases.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(ruby): bare identifiers are calls, not callable references
Ruby parses a receiver-less zero-arg method call identically to a variable
read, so 'action = process' — which CALLS process and stores its return —
seeded action with the callable and minted a wrong CALLS edge from any
dispatch through it, confirmed end-to-end (review finding 15/HIGH, #2522).
New provider knob bareNamesAreCalls: a bare name that is not a provably
local value binding and not an explicit reference form (method(:x),
lambda/proc) emits no flow fact, on both the assignment and argument paths.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(go): pair multi-value := positionally instead of cross-wiring
The shared field fallback took the FIRST LHS identifier and the LAST RHS
identifier of Go's expression_list pair, cross-wiring 'a, b := f, g' and
synthesizing a garbage comma-joined qualified name — the real relationships
were silently dropped (review finding 16, #2522). extractAssignment may now
return multiple pairs; Go pairs list entries positionally and emits nothing
for a length mismatch (multi-return call RHS).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(java): drop get/test from callableProtocolMethods
'get' and 'test' collide with ubiquitous non-functional-interface APIs
(Map/List/Optional/Future.get), so every ordinary container access emitted
a spurious callable-object invoke fact — high-volume misleading graph facts
with a cross-wiring risk on receiver-name reuse (review finding 17, #2522).
Supplier.get/Predicate.test dispatch is deliberately traded away until the
check can gate on the receiver's declared type.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(rust): pin the qualified-name no-degrade guard as a hard invariant
Rust's scoped_identifier callable-reference capture over-includes unit enum
variants and associated constants (Shape::Square seeds as if callable);
they stay edge-free only because resolveSeedCandidates refuses to degrade
an unresolved qualified name to a simple-name lookup (review finding 18,
#2522). Capture-side type filtering would false-negative on tuple-variant
constructors, so the guard IS the contract: documented as a hard invariant
(Go's mis-shaped multi-value forms also rely on it) and pinned end-to-end.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(php): remove nonexistent optional_parameter node type
tree-sitter-php has no 'optional_parameter' — defaults ride on
simple_parameter — so the entry was dead weight the #1920 literal gate
does not cover for capture-option Sets (review finding 19, #2522).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cobol): detect procedure pointers on fixed-format sources
Two stacked defects made the feature a no-op on classic sequence-numbered
fixed format (review finding 20/H3, #2522):
1. parseDataItemClauses' USAGE alternation knew POINTER but not
PROCEDURE-POINTER/FUNCTION-POINTER, so the dataItems filter was dead.
2. The raw-line fallback scanned UNCLEANED text, where the sequence number
satisfied the leading digits and the LEVEL NUMBER got captured as the
pointer name. It now scans preprocessed lines and requires a letter-
initial name (COBOL data names must contain a letter).
161 COBOL preprocessor/copy-expander tests stay green; free-format matrix
case unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cobol): skip comment lines in SET seed/copy scans
A commented-out SET (indicator-column '*'/'/' or free-format '*>')
produced a live seed and a false CALLS edge from dead code (review
finding 21/M1, #2522). The scan now skips indicator-column comment lines
and strips inline '*>' tails before matching.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(architecture): document callable-flow-only mode and skipped-key reporting
The Callable-value flow section omitted scopeResolutionEdgeMode:
'callable-flow-only' — a real emit-pipeline branch that suppresses all
ordinary emission for standalone providers (review finding 22, #2522) —
and predated the skipped-key names/stats surfacing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(scope-resolution): correct value-ref resolution attribution and stale pdg-gating comments
The value-ref contract comment claimed MethodRegistry resolution — the
mechanism is the post-finalize findCallableBindingInScope walker owned by
emitPropertyDispatchCalls (resolveReferenceSites skips these sites). Three
'only under --pdg' calleeIdSink comments were falsified by the #2437 gating
change (callee-id-sink.ts's header was updated; these copies were missed).
Review finding 23, #2522.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(ingestion): direct unit coverage for synthesizeCallableFlowCaptures
The 1,100-line shared synthesizer had no test naming it — only downstream
consumers were covered (review finding 24, #2522). Pins seed/invoke/
formal/argument emission, subscript container binding, store-gated member
invokes, produced-value guards, and the bareNamesAreCalls knob over a
minimal options object so assertions target the synthesizer's own
semantics.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(resolvers): deepen shallow-language coverage; fix Kotlin/Swift reassignment gaps it exposed
Adds the COBOL SET x TO y copy-branch scenario and conditional-assignment
scenarios for Kotlin, C#, Swift, and Dart (10 languages previously had one
generic case each — review finding 25, #2522). The new scenarios exposed
two real capture gaps, fixed here:
- tree-sitter-kotlin's 'assignment' node is fieldless, so nested
reassignments (chosen = ::target inside a block) produced no flow facts;
Kotlin's extractAssignment now decomposes it positionally.
- tree-sitter-swift fields its assignment as target:/result:, neither in
the shared fallback's field lists; both added.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(infra): literal-validation gate for callable-capture option Sets
The #1920 gate validates query literals and exported configs but not the
module-private *_CALLABLE_CAPTURE_OPTIONS Sets consumed by the shared
synthesizer — a typo'd node type silently captures nothing (PHP shipped a
dead 'optional_parameter'; review finding 26, #2522). Every <key>NodeTypes
Set literal is now validated against its language's grammar; name-carrying
sets (callableProtocolMethods, memberPointerOperators) are deliberately
outside the contract.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(storage): centralize corrupt-fixture casts into makeStoreEntry
The callable-flow store tests scattered 'as unknown as' double-casts per
fixture (review finding 27, #2522; standing no-as-any rule). One typed
helper now owns the single controlled escape hatch for building malformed
serialization-boundary payloads.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore(bench): refresh capture fingerprints after review fixes
python-scope: the committed baseline (8d5c3699) never matched this
branch's code — CI's benchmarks arm was red on the PR head (review
finding 2/HIGH, #2522); regenerated (a99e69ab), scaling 1.04 in budget.
scope-capture: ruby/cpp/swift/java/kotlin drifted from the review-fix
commits (bare-name suppression, passing modes + ->* recovery, assignment
fields, protocol narrowing, positional assignment); all 14 languages
re-verified PASS with ratios <= 1.18 against the 1.5 budget.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore(docs): untrack docs/plans working documents
docs/ is gitignored (local working docs); the plan files were force-added
past the ignore. Untracked from the index only — they stay on disk.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(golden): regenerate captures goldens after callable-flow review fixes
The per-language digest guards (csharp/go/php/python/ruby/rust/swift)
locked the pre-fix capture output; the review-fix series intentionally
changed it — store-gated member invokes, subscript container binding,
Ruby bare-name suppression, Swift assignment fields, positional pairing.
Regenerated with UPDATE_GOLDEN=1; clean verification run 59/59; all other
parity/golden guards (pipeline-graph, spring-route, python parity) pass
untouched at 33/33.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(ingestion): prototypes are callees, not callable value cells
The cross-function visibility fix indexed EVERY signature-bearing
declaration as a value binding — including plain function/method
prototypes (void f(int);). Every call to a declared function then became
an indirect invoke, and with emitCanonicalInvokeReference (C/C++) minted a
free-call reference that resolved through the registry, bypassing the
precise passes' two-phase/ambiguity/subobject suppression — eight phantom
CALLS edges in the cpp resolver suite on CI.
Only declarations whose binding identifier sits under a pointer/
parenthesized declarator (callable-typed variables like void (*fp)(int);)
create value cells now. cpp resolver suite 331/331; callable-value-flow +
C/C++ suites 181/181 (the cross-function fp regression still passes); cpp
fingerprint rebaselined, both bench gates PASS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(wiki): allow explicit HTTP LLM hosts
Keep wiki LLM HTTP endpoints fail-closed by default while adding a narrow exact-host opt-in for LAN/self-hosted models.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(wiki): simplify insecure LLM flag name
Rename the wiki HTTP opt-in flag to --allow-insecure-connection per review feedback.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(wiki): simplify insecure connection env
Rename the wiki HTTP allowlist environment variable and align validation errors with the CLI flag naming.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
The busiest Windows platform shard reached 14m57s against the 15 minute
watchdog on the rc.19 green run and has timed out once since. CI now
sets GITNEXUS_CROSS_PLATFORM_TIMEOUT_MINUTES=20 (the job timeout stays
25), the stale comfortably-under comment reflects reality, and the
runner always logs status, signal, spawn code and elapsed time so the
next status-null death is diagnosable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The RC path bumped only gitnexus/package.json, so every v1.6.10-rc tag
through rc.28 shipped the four plugin manifest surfaces frozen at 1.6.9
and failed its own unit suite. The npm version lifecycle script now
runs a fail-closed sync whenever npm version executes, in CI or on a
maintainer's laptop; publish.yml verifies the result and stages the
surfaces into the detached release commit, and the stable path refuses
to publish a tag whose manifests drifted. The sync is textual so a
release commit carries a one-line change per surface instead of
reformatting churn.
Design follows the proposal by @100yenadmin in #2445, moved onto the
standard npm version hook.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The skip-git ignore test asserted the error payload while relying on
exit 0; since the output() guard an error payload also exits 1, so the
test now captures the payload from the exec failure and pins both.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The zero-symbol File fallback from #2455 writes File embedding rows,
but the filePath-scoped delete sweeps joined through EMBEDDABLE_LABELS
only. Docs repos accumulated duplicate rows on re-analyze and deleted
files left orphans. Free for code repos: no File rows exist to match.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Moves the #2469 guard from cypherCommand into output() so all seven
tool commands that print backend results share the exit semantics.
Adds query and context regression cases.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An fs failure while resetting a chunk generation now warns and
continues like the neighboring durable-store paths instead of failing
the analyze. Workers recreate the directory on write.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Composed with the read-only and repository policies in the CallTool
handler: read-only assert, then budget resolution, then scoped dispatch
with the transport arg stripped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The C#, Java and Go flag-off digests shift with the canonical community
projection from #2478 stacked on the walker sort from #2482. Regenerated
via vitest -u; mini-repo pipeline golden was already correct.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Merged with the read-only policy: both filters compose in server.ts.
Review hardening: assertResourceUri compares the opaque host case
insensitively (GITNEXUS://GROUP bypass) and gains the fail-closed
fallback for unparseable URIs; the backend proxy now also intercepts
queryClusters/queryProcesses/queryClusterDetail/queryProcessDetail;
scrubGroupDescription is shared from read-only-policy.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
crossDepth and subgroup are inert outside @group routing, but rejecting
them keeps the scrubbed schema and the dispatch contract in agreement.
Also documents that resource content scrubbing is cosmetic.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds the missing #2481 Rust regression test (importer before definer),
fails closed when a PHP namespace suffix matches directories under
different roots, and points the baselines note at #2481/#2482.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>