Skip to content

propose: MCP filter frame — typed query language with one named carve-out#128

Merged
HumanBean17 merged 2 commits into
masterfrom
propose/mcp-filter-frame
May 14, 2026
Merged

propose: MCP filter frame — typed query language with one named carve-out#128
HumanBean17 merged 2 commits into
masterfrom
propose/mcp-filter-frame

Conversation

@HumanBean17
Copy link
Copy Markdown
Owner

Draft propose for issue #117 — locks the MCP filter frame.

Frame (locked)

The MCP V2 surface is a typed query language for the code graph. Filters and traversal targets are strict — every input field has one and only one mapping to a stored attribute, and inapplicable inputs fail loud. The search tool's query parameter is the single exception: it accepts opaque natural-language or code text and returns ranked results.

What's in the propose

  • §3.4 — 7 frame-edge decisions locked: wildcards rejected, describe(fqn=…) lossless alias for Symbols only, within-field OR / cross-field AND, negation predicates strict, empty-filter = pagination safety net, revisit-trigger N=3 in 6 months, transition-window fallback documented.
  • §3.5 — resolve named in the frame, designed in a separate propose. Two-decisions-in-one-thread anti-pattern avoided.
  • §4 — 18 UC re-walk across the strict-frame surface. No missing primitive surfaces; UC7 (identifier resolution) is the workflow most visibly degraded pre-resolve, but search covers it acceptably.
  • §6 — 3 PR migration (PR-FRAME-1/2/3). Migration step 1 (extra="forbid" + per-kind applicability validation) already shipped as lossless-permissive frame: tactical no-regret fix for #117 silent-drop bug class #122 — confirmed in master at mcp_v2.py:60, 83, 130, 525, 557, 678.
  • Appendix A — aligned-vocabulary audit: 17 fields × 4 columns. Three plausible cross-kind renames flagged for PR-FRAME-1 (source_layer/role, target_service/target_microservice, client_method/http_method). Most are deprecation-alias-friendly → V2.x incremental.

Builds on, does not replace

PR #89 V2 invariants are preserved: four primitives, closed EdgeType, rollup dot-keys read-only (decision #11), _coerce_filter lossless JSON-decoding. This propose does not relitigate them.

Sequencing

  1. Review & lock this propose.
  2. Open propose: design \resolve` tool` as a follow-up (named in §3.5 / decision feat: B2b HTTP_CALLS + ASYNC_CALLS extractor (PR-D1) #12).
  3. Lock rollup decomposition affordance: describe surfaces composed edges that neighbors can't directly traverse #118 (rollup decomposition) — frame here strongly suggests option A (read-only) with propose: hints field as machine-readable road signs on MCP V2 outputs #120 hints as the teaching surface for the 2-call pattern.
  4. Revisit PR propose: hints field as machine-readable road signs on MCP V2 outputs #120 (paused — see pause comment) with full information.

Open questions deferred to review

  • Appendix A audit decisions (3 rename calls) — locked in PR-FRAME-1, not here.
  • resolve design — its own propose.

Status

Draft. Status header in the file is draft. Will move to under review when this PR opens, locked after consistency pass on review comments.

…-out

Drafts propose/MCP-FILTER-FRAME-PROPOSE.md for issue #117. Locks the
strict frame, the 7 frame-edge questions surfaced during grilling,
`resolve` as a named-but-deferred primitive, and a 3-PR migration shape
(step 1 already shipped as #122). Appendix A is the aligned-vocabulary
audit handed to PR-FRAME-1.

Builds on PR #89 V2 decisions (four primitives, closed EdgeType, rollup
dot-keys read-only, _coerce_filter lossless JSON-decoding). Does not
relitigate them.
@HumanBean17 HumanBean17 marked this pull request as ready for review May 14, 2026 19:13
@HumanBean17
Copy link
Copy Markdown
Owner Author

Review (propose only)

Overall: the frame is sound, the carve-out boundary is well reasoned, and the migration is correctly sequenced with step 1 already shipped. A few items worth flagging before locking.

Code reference accuracy

The six mcp_v2.py enforcement references check out against current master (extra="forbid", _NODEFILTER_APPLICABLE_FIELDS, _nodefilter_applicability_error, search_v2 / find_v2 / neighbors_v2 call sites).

Substantive notes

  1. _coerce_filter line reference — The propose cites mcp_v2.py:79–98 for _coerce_filter. In current master, that span is not where _coerce_filter lives (79 is still inside NodeFilter). Worth correcting so line-anchored evidence stays trustworthy.

  2. §3.4.2 (describe(fqn=…)) — scope — The decision locks FQN as a lossless alias for Symbols only. Today describe is (id, kind); there is no fqn parameter yet. Clarify whether this is purely a frame statement (“FQN is a valid identifier shape for Symbols”) or an explicit PR-FRAME-2 deliverable (add fqn to the tool schema). That avoids ambiguity between “locked in prose” and “shipped in code.”

  3. §3.4.3 (within-field OR) — Forward-looking is fine; worth one sentence noting what the schema exercises today: mainly symbol_kinds and exclude_roles as the multi-value / negation surfaces, so the decision is grounded in shipped shapes.

  4. §4 UC table — In the diff the 18-row table was truncated; worth a quick pass in the rendered file that every row is complete and pipes render cleanly in Markdown.

  5. Appendix A (source_layer / role)_NODEFILTER_APPLICABLE_FIELDS already keeps them disjoint (role symbol-only, source_layer client-only). The audit is vocabulary / concept alignment, not a current applicability bug.

  6. Appendix A (client_methodhttp_method) — Agree this is the strongest cross-kind alignment candidate. If PR-FRAME-1 does it, call out that both route and client would then list the same field name under applicability — straightforward but worth an explicit “both kinds share this predicate” note so PR-FRAME-2 tests stay obvious.

  7. §6 PR-FRAME-3 “telemetry hooks” — The repo does not imply an observability stack. Either narrow the word (e.g. stderr counters, opt-in logging, local counters) or say “design at PR-FRAME-3 time” so readers do not expect full product telemetry.

Minor

  • §7 “Decisions taken” is a useful index for review threads.
  • References block at the end is helpful for reviewers.

Verdict: Ready to move from draft toward lock after tightening #2 and #7; the rest are suggestions or doc fixes.

Accepted:
- Fix _coerce_filter line reference (79-98 -> 161-180).
- Clarify §3.4.2 describe(fqn=...) as PR-FRAME-2 deliverable, not frame-only.
- Ground §3.4.3 in shipped multi-value surfaces (symbol_kinds, exclude_roles).
- Reframe Appendix A as vocabulary/concept alignment, not applicability bug.
- Add 'both kinds list http_method' note to client_method audit row.
- Narrow PR-FRAME-3 'telemetry hooks' to local counters / stderr; no
  observability stack assumed.

Additional revision per user constraint (breaking changes allowed, no users):
- Drop deprecation-alias scaffolding from PR-FRAME-1; rename in place.
- Drop transition-window framing (§3.4.7 renamed to identifier-resolution
  fallback; not user-facing).
- Strike V2.x/V3.0 ceremony from principle #8 and decision #14.
- Drop alias-friendly risk row; update remaining risk rows accordingly.
@HumanBean17
Copy link
Copy Markdown
Owner Author

Thanks. Revision pushed at 68f4b39. Accepted notes + one push-back below.

Accepted

  1. _coerce_filter line reference — fixed. Verified in master: _coerce_filter lives at mcp_v2.py:161–180, not 79–98 (line 79 is still inside NodeFilter). References block updated.

  2. §3.4.2 scope — sharpened. describe(fqn=…) is no longer phrased as a "lossless alias" (migration-flavored language). Decision now reads: PR-FRAME-2 adds fqn as a second accepted identifier shape for describe, accepted only when kind="symbol". This is an additive change to the tool schema, not a frame-only statement.

  3. §3.4.3 grounding — done. Added: "Today the schema exercises this with symbol_kinds (multi-value OR) and exclude_roles (multi-value negation); the decision generalizes their semantics to any multi-value field added later."

  4. Appendix A reframing — done. Header now reads: "Vocabulary audit across the 17 NodeFilter fields — concept alignment, not applicability bugs. Today _NODEFILTER_APPLICABLE_FIELDS already keeps fields disjoint per kind; this audit asks whether two same-concept fields under different names should share a name across kinds."

  5. client_methodhttp_method note — added. Row now reads: "…Post-rename, _NODEFILTER_APPLICABLE_FIELDS lists http_method under both route and client; PR-FRAME-2 tests cover both kinds with the same predicate name."

  6. PR-FRAME-3 narrowing — done. "Telemetry hooks" is gone. PR-FRAME-3 now reads: "Lightweight local counters + tool-description updates. Local counter for revisit-trigger tracking — a stderr counter or a small local file recording fail-loud events per workflow shape. Not product telemetry; no observability stack."

Verified — point 4

UC table renders cleanly in the file. The truncation you saw is the GitHub diff view collapsing wide tables; the rendered file has all 18 rows with complete pipes.

Beyond the review — soft-migration framing dropped

The review didn't flag this, but it's worth surfacing: the original draft carried deprecation-alias scaffolding in PR-FRAME-1, transition-window framing in §3.4.7, and V2.x-vs-V3.0 ceremony in principle #8 and decision #14. With no users (confirmed by the author), all of that is over-engineering — there's no migration cost to amortize. Dropped:

  • PR-FRAME-1 — "Aligned-vocabulary audit + renames with deprecation aliases" → "Vocabulary renames: rename misaligned vocabulary in place — no deprecation aliases, no users to migrate. Update _NODEFILTER_APPLICABLE_FIELDS, NodeFilter, all call-site references, and tests in one commit."
  • §3.4.7 — "Transition-window gap" → "Identifier-resolution fallback (pre-resolve)" with explicit note: "Not a user-facing transition — the AMA agent is the only consumer."
  • Principle add brownfield route overrides and codebase route composition (PR-A3) #8 — "V2.x for additive + deprecation-alias-friendly; V3.0 only if a rename has no alias path" → "No users, no version ceremony. Breaking changes are allowed; renames ship in place."
  • Decision chore: refresh AGENTS.md and .cursor/rules to current Tier 1B state #14 — same simplification.
  • Appendix A summary — "deprecation-alias-friendly, so V2.x incremental""With no users, renames ship in place; no alias scaffolding."
  • Risk row — "Aligned-vocabulary audit surfaces a rename that has no clean deprecation alias" → dropped entirely.

Net effect: the propose is shorter and sharper. PR-FRAME-1 in particular shrinks substantially.

Ready to lock?

After your re-read of 68f4b39, if no further changes I'll flip Status from draft to under reviewlocked and proceed to the resolve propose and #118.

@HumanBean17 HumanBean17 merged commit 117c966 into master May 14, 2026
1 check passed
@HumanBean17 HumanBean17 deleted the propose/mcp-filter-frame branch May 23, 2026 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants