Repository navigation
Description
Priority: P2
Area: Graphify context adapter
Repository / target branch: wavect/semaprax / wavect/v090
Reviewed commit: 5428b0805fa3cf35859c843a53e30c3252ef378c
Review date: 6 October 2026
Failure and impact
Graphify accepts the context request's in field but ignores it when collecting search results and references. A request scoped to allowed returns source items from allowed-sibling and elsewhere as well. Unrelated results can consume the item limit, reduce useful context, and make source selection disagree with the user's requested area.
This is a request-scope correctness defect, not evidence of a filesystem permission escape: the provider already has project-read access. The host independently filters the configured provider scope, which may cover the whole project; it does not currently enforce the narrower scope of this individual request.
Exact source and cause
contract/payload/context.rs:19–49: search and references explicitly admit an optional project-relativeinpath.context/broker.rs:439–443: the broker forwardsreq.withinaspayload.in.graphify/adapter.py:858–877: search scores every graph node and truncates globally without readingin.graphify/adapter.py:896–928: references likewise collects and limits all matching call-site edges without applying it.context/broker.rs:269–278: result normalization filterssrc.scope(), notreq.within, so a normally unscoped Graphify provider does not get this repaired downstream.
Executed reproduction
Load the unchanged production Graph, Index, and request handlers. Use three real temporary files, each defining helper, with corresponding valid graph nodes:
allowed/a.py
allowed-sibling/b.py
elsewhere/c.py
Inject only Index.ensure to return this already validated deterministic graph, then call the real search handler:
{"query": "helper", "in": "allowed", "max_items": 20}Observed status: complete with these returned paths:
["allowed-sibling/b.py", "allowed/a.py", "elsewhere/c.py"]Expected item paths: only allowed/a.py. Search, ranking, source reads, item creation, and envelope fitting all use production code. This is an adapter component reproduction; an actual Graphify extractor or full host workflow was not executed. The equivalent omission in references is source-confirmed and needs its own regression within this ticket. See repros/context/repro_graphify_scope.py and evidence/graphify-scope-evidence.json.
Focused fix
Apply component-aware project-relative scope matching before ranking and max_items truncation. For in: "allowed", admit the exact file path when applicable and descendants allowed/..., but not allowed-sibling/.... Scope references by the returned call-site path while preserving legitimate target resolution outside the scoped directory; restricting targets to the same directory could incorrectly remove calls to external definitions.
Add broker-side filtering by the request scope as a defensive consistency check for all external providers. Keep the configured provider scope too; both constraints must hold. A post-limit filter alone is insufficient because out-of-scope candidates could already have displaced useful in-scope items. Maintain truthful coverage and Graphify's existing non-exhaustive reference/absence semantics.
Acceptance criteria
- Scoped search returns only items at or under the requested path, with deterministic ranking among that filtered set.
- Scoped references filters call sites before truncation and still resolves targets defined elsewhere.
- Sibling-prefix paths such as
allowed-siblingdo not matchallowed. - A high-ranking out-of-scope item cannot consume the entire result limit and starve an in-scope result.
- An exact file scope, directory scope, no scope, and an empty in-scope result behave consistently.
- The broker prevents a provider returning out-of-scope items from admitting them into the final context packet.
- Coverage remains honest; no empty result is upgraded into proof of absence.
Existing issue boundary and implementation handoff
The context/Graphify implementation predecessors include #423, #446, and #421. No retrieved issue describes this missing per-request filter. Read AGENTS.md, the context contract, and the existing Graft scope behavior as a consistency reference. Extend Graphify's current Python fixtures and the existing broker tests; avoid a new context provider API.
Activity
harness: qualified cost evidence, budget-fitted Graft envelopes, scop…
wsdt commentedon Oct 6, 2026
Fixed in 83044ff (pushed to main). Graphify ignored
in; a component-aware scope_of() now filters search nodes before ranking and the item limit and reference call sites before truncation (invalidin→ SPX-HPG006), and the broker applies the request's within on every provider, forfeiting exhaustiveness on any drop. Evidence: 4 new RequestScope Python tests (all failed on the old adapter), graphify suite 77 OK, and context dv14_a_provider_item_outside_the_request_scope_is_never_admitted.