tech.tresbien/drupal-code-query
name:tech.tresbien/drupal-code-query
Drupal core API changes, contrib usage, upgrade readiness, patch verdicts, code search, SQL.
- transport:
- remote
- credential class:
- self-provisionable
Owner verification
Not yet verified. Verifying proves you control this server and is free, permanently — it never changes a published score.
Start verification →Tools
- check_patchesshallow
Does each composer patch still apply to the release the site installed, and is its fix already in that release? Send composer_json + composer_lock (plus patch_files for local patches) after composer update and every extra.patches entry is checked at its installed version in one call; do not download releases or run patch --dry-run yourself. - Send a package's patches in the order composer.json declares them, and keep them together: they are judged in that order because a patch manager applies them in it, so a later patch is applied to what the earlier ones left. Reordering them changes the verdicts. - items: up to 50 of {project, version, patch, title}, when you would rather name them yourself. project is the drupal.org machine name (webform) or composer name (drupal/webform), drupal or core for Drupal core; version is the composer version (1.13.0, 2.0.0-beta4, 11.4.5); patch is the diff text or its URL on www.drupal.org/files/issues or a git.drupalcode.org merge request .patch/.diff. - Per item: tag (the release tag matched, or unknown_version), applies_at (the -p level at which git apply passes, null when none), fuzzy (applied only with reduced context and whitespace ignored, as GNU patch fuzz does: review it), hunks_failed (file, line, reason), reverse_applies (the patched lines are already in the tag), mr (merge-request state when the patch is an MR URL), merged_in_version, suggested. - suggested is the verdict: shipped (fix is in the release: drop the patch), still-needed (applies cleanly: keep it), needs-reroll (neither: call reroll_patch with that item, it returns the re-rolled diff), unknown (tag or patch unresolved; see error). - next_step names the follow-up calls and the row count the report owes; counts is the verdict tally to check that table against. An item that could not be judged comes back suggested unknown with the reason in error: report it as unclear, never leave the row out. - files_shipped on a result names the patch's files the release already carries when only some of them do: the patch is partly upstream and what is left is a re-roll, not a drop. A failed hunk carries moved_to when the release keeps that file under another path. - next_step names the follow-up calls and the row count the report owes; counts is the verdict tally to check that table against. An item that could not be judged comes back suggested unknown with the reason in error: report it as unclear, never leave the row out. - hunks_shipped and files_shipped name the parts of a patch the release already carries when only some of it does: a partly-merged patch, so what is left is a re-roll rather than a drop. A failed hunk carries moved_to when the release keeps that file under another path. - next_step names the follow-up call when any item needs a re-roll. Each verdict is the result of running git apply against the release the site installed, so it replaces a hand dry-run rather than pointing at one. - core_references: what the code the patch adds references in core, checked at target_core (defaults to the lock's core): flagged lists removed or moved classes and calls whose argument count no longer fits the target signature (parent::__construct is checked against the constructor the core parent class actually declares, walking core's extends chain), each with file, line, change_record and replacement; deprecated is a short side list; checked counts references the catalog knows. Scope: added lines, direct references only (extends, implements, trait use, new, static calls, parent::__construct). A patch that does not apply carries a note instead. - Verdicts come from git apply --check against the tag's tree; a still-needed patch can still be wrong at runtime.
- describe_datasetshallow
Learn the dataset before writing SQL for query_dataset; call with no arguments first. Returns text. Prefer a typed tool when one answers the question. - No arguments: every view with one line, the join map, the four invariants (dev-branch isolation, no SUM(usage), *_seq compares, adoption polarity), the gotchas behind empty results (fqn forms, placeholders, machine names), the recipe index. - view=<name>, or views=[…] for several in one call: columns with types and descriptions, an example filter that returns rows, the joins that reach the view. - recipe=<id>: a ready-to-run statement for a common question (who uses a symbol, deprecated symbols per project, a change record's adoption, symbols deprecated between minors, one project's deprecated uses, change records between minors); substitute the placeholders and run it with query_dataset.
- get_change_recordshallow
Return one core change record in full: title, flavour, target version, machine-checkable tracks, linked issues, linked core symbols, and contrib adoption counts. To find records use list_change_records or what_changed's change_record_nids; for one symbol's detail use lookup_core_symbol. - Flavour: coming-break (API going away), coming-new-API (API added), landed-but-still-relevant (shipped), policy-only (no code target, no adoption). - Adoption counts contrib development branches only. legacy = still calls the going-away side (not adopted); migrated = moved. - Returns counts across every affected project plus a ranked head, outstanding first. For one project use project_upgrade_report rather than raising top_projects. - symbols: the core API the record is about, role from (going away) or to (replacement); use the fqn with lookup_core_symbol. Empty means the catalog links no symbol, which is common.
- list_change_recordsshallow
List the core change records (the human write-ups) targeting a range of core versions, tagged by flavour and ranked, with counts. For the symbol-level diff use what_changed; for one record in full use get_change_record. - Bounds inclusive; forms 11.2, 11.2.x, 11.2.0, 11, 11.x; a bare major covers every minor of it. - Flavours: coming-break (an API going away), coming-new-API (one being added), landed-but-still-relevant (already shipped). policy-only records target no version and never appear here. - project narrows to one maintainer's view: each record then carries how many of that project's development branches are still on the legacy side. - Returns the count of every record in range plus a ranked head; each entry carries its nid for get_change_record.
- list_class_relationsshallow
List the contrib classes that extend, implement or use a core class, interface or trait, one row per edge with file and line, paged: "who subclasses FormBase". Call-site counts: list_symbol_users; the symbol's status: lookup_core_symbol. - target with or without the leading backslash; unknown → refused, pointing at lookup_core_symbol (a fragment lists candidates). rel_kind narrows to one of extends, implements, uses_trait; project to one machine name. - Development branches only. edge_count = every edge, project_count = projects, count = edges after the per_project cap (default 3 per project per page, so "top projects" reads off one page; project_edges on each row is the full count; per_project=50 with project= lists one project in full). - Rows by project installs, project, source_fqn: project, branch, installs, source_fqn, rel_kind, file, line, project_edges. limit ≤ 100; next_offset absent on the last page.
- list_projectsshallow
List drupal.org projects after filters, largest install base first, paged: "top modules without an 11.4 branch", "themes over 10k installs without security coverage". One project: project_profile; its pending records: project_upgrade_report. - Filters combine: type, min_installs, security (covered, not-covered, revoked), core_minor (+ missing), era (d8plus, pre_d8); all apply to count and rows. - core_minor reads the composer constraint of the NEWEST RELEASE on each development branch (drupal.org metadata, composer/semver; a minor counts when any patch of it satisfies); an unreleased tip change is not seen. missing=true keeps projects with no branch declaring it — the upgrade gap list. - Row: machine_name, title, type, installs, security, status, dev_branches (branch, installs, core_minors, era), latest_release. count = projects; next_offset absent on the last page.
- list_symbol_usersshallow
List every contrib project using one core symbol or any symbol in a class of symbols, one row per project, paged — and the matched symbols themselves. lookup_core_symbol answers one symbol with a head of 30. - Pass fqn, or filters: kind, status (deprecated, scheduled_removal, removed), subsystem, removal_in (13.0), deprecated_in (11.4). "Top modules still calling a method going away in 13.0" = kind=method, status=scheduled_removal, removal_in=13.0. Filters take public symbols only. - Development branches only, evidence rollup as of evidence_built_at. count = projects; symbol_count = matched symbols, listed in symbols_matched (≤ matched, most-used first, with stamps, projects_using, change_record_nids). - Rows by installs, occurrences, name: project, title, installs, branch, branches, symbol_count, occurrences, symbols (heaviest first, each fqn, kind, removal_in, occurrences, files, change_record_nids → get_change_record). next_offset absent on the last page.
- lookup_core_symbolshallow
Answer "is this core symbol safe to use, and who still uses it" for one symbol; a name that resolves to nothing returns the catalog names containing it instead. Every user in pages: list_symbol_users. Changed between versions: what_changed. Code text: search_code. - fqn forms: namespaced with or without the leading backslash, a bare function or constant name, a prefixed pseudo-symbol (fn:check_markup, core:hook:preprocess_page, core:library:claro/drupal.shortcut), or a fragment (fromRoute, EntityInterface). - Resolved: symbol with status flags: removed (gone), scheduled_removal (@deprecated names the version, still present), deprecated, internal, placeholder (catalog row no scanner located); audience contrib | test_support | test | theme. usage: contrib development branches only, evidence rollup as of evidence_built_at; projects and branches counts plus top_projects (≤ 30) by install base. change_records: records that touched the symbol, with nid for get_change_record. - Not resolved (found false): count = catalog names containing the fragment (case-insensitive, public symbols; kind narrows), candidates a head of ≤ candidates with fqn, kind, subsystem, stamps, projects_using, change_record_nids; names starting with the fragment first, then by projects_using. Call again with one fqn.
- project_profileshallow
Answer "what is this contrib project, how big is it, which core versions does it support, what moves with it" for one drupal.org project. Pending change records: project_upgrade_report; core symbols it calls: list_symbol_users. - project: title, type, status, security, installs. installs_by_version: install base per contrib version. - dev_branches: each scanned development branch with installs, core_constraint (composer constraint of the newest release on that line, from drupal.org — not the unreleased tip), core_minors it admits (a minor counts when any patch satisfies), latest commit date, era. latest_core_minor = newest admitted. - releases (newest first, ≤ releases, with core_compatibility and security), release_count, supported_branches. missing_sections names what the bundle could not fill. - related (summary): requires / required_by counts + top 3, co_installed top 3 or a note, delta_12m per release line ("*" = total). - include=["related"]: related becomes the full report: requires (every dependency, via info_yml or composer, core modules left out), required_by paged by installs (count, next_offset; dependents / dependents_offset), co_installed (rho, rank, method residual_spearman) or a note. - include=["trend"]: trend = months (oldest first), series per release_line aligned with months (null = no count, "*" = total), lines with installs_now, share, delta_3m / delta_12m / delta_36m, peak, first_seen / last_seen. drupal.org month-end installs. - Unknown project: error. An included section refuses when the bundle predates its view.
- project_upgrade_reportshallow
Answer "is this contrib project ready for a target core version, and what work is left". For one record's detail use get_change_record; for a symbol's users use list_symbol_users. - A record applies when it targets the target version or earlier and a development branch of the project matched one of its tracks. - Verdict per record: outstanding (a branch still calls the going-away side), in_progress (some branches moved), adopted (all moved). - Returns counts by verdict, then a ranked head of outstanding records with file and line evidence from the project's own code. - Each entry carries how many other projects are outstanding on the same record (wait for upstream or not) and its nid for get_change_record. - removed_symbols: core symbols removed by the target, or scheduled for removal at or before it, that the project's development branches still reference, with occurrences, files and the replacement when the catalog names one. These need no change record, so they hold the breakage a record-only view misses: a class moved to another module, a service dropped. removed_symbol_count is the whole set; the head is newest removal first, then by occurrences; test and test-support symbols are left out.
- query_datasetshallow
Run read-only DuckDB SELECTs over the dataset behind the other tools, for a question none of them asks. Call describe_dataset first (it lists the 29 views, their columns, joins and recipes); prefer a typed tool when one fits. - statements=[…] runs up to 5 in one call, one result or error each — explore in one round trip. - Result: columns, rows as arrays, ≤ max_rows (≤ 500, default 100) and ≤ 16 KB; truncated → aggregate, filter, LIMIT/OFFSET. Single SELECT (or SHOW, DESCRIBE, FROM-first), no semicolon, 15 s limit, nothing outside the bundle. - Dev-branch isolation: JOIN contrib_branch AND filter kind = 'dev_branch' AND project <> 'drupal' before counting projects (change_record_adoption, symbol_usage, core_symbol_evidence carry release tags too; core_symbol_evidence is the full rollup, symbol_usage its string-scan subset). - Adoption polarity: legacy = still on the old API (NOT adopted); migrated = adopted. Versions are text: compare *_seq integers (major*1000+minor). Never SUM(usage) across branch rows. - Errors name the views, the columns of the views you used, or the join map; an empty result over a backslash-less fqn carries a hint. - The same views are downloadable as parquet under https://api.tresbien.tech/data/docs; its cookbook targets api.duckdb plus prelude views this mirror does not carry, so take recipes from describe_dataset.
- reroll_patchshallow
Re-roll one composer patch that check_patches reported needs-reroll: a 3-way merge of the patch onto the installed release, returned as a new diff. Call check_patches first for the whole list; call this per patch that came back needs-reroll. - Input: project, version, patch (text or URL), title. One patch per call. A hand-made patch without index lines is merged from the newest tag it applies to (reroll.base). - reroll.verified true means the service already ran the check a caller would run by hand; reroll.verified_by names it (the command, the -p level, the tag). Write reroll.patch to the patch file and move on: no git apply --check, no patch --dry-run, no pristine copy of the release to diff against. composer install is the test. - A conflicts result is not the end: send the same project, version and patch again with resolutions, one per region of reroll.conflicts[].hunks ({file, region, choice: release|patch} or {file, region, text}), and the service re-merges with your decisions and apply-checks the diff. What comes back is the finished patch file: write it and run composer install. Deciding regions this way replaces reading the release files, editing the patch by hand and dry-running it. - reroll.status: clean (every file merged and the diff apply-checked against the release, reroll.verified true: write reroll.patch as the new patch file, no re-test needed; an empty reroll.patch with reroll.note means the release already carries the change and suggested is shipped), conflicts (reroll.patch holds the hunks that merged cleanly, apply-checked when reroll.verified is true; each file in reroll.conflicts carries hunks with the three sides of every region: release = what the release has, base = what the patch was written against, patch = what the patch wants, plus release_line and release_context, the release file's numbered lines around the region. Write the missing hunks from those and append them to reroll.patch; no download, file read or dry-run needed), unavailable (no index lines and no recent tag takes the patch; re-roll by hand from hunks_failed). - reroll.patch paths are relative to the repository root: contrib patches apply at -p1, core patches carry core/ and apply at -p2 from web/core. patch_truncated means the diff was cut to the result budget; POST /v1/patch/check on api.tresbien.tech with reroll: true returns it whole. - A patch that still applies (applies_at set) or is already in the release (shipped) returns its verdict with reroll null. - core_references: as on check_patches, read from the re-rolled diff when the merge was clean: removed or moved core classes and calls whose argument count no longer fits the target signature, at target_core.
- scan_composershallow
Which of a site's drupal/* packages need a new release for a target core, and which have none? Send composer.lock (and composer.json) once instead of one query per package; the answer is the release scan for every package plus extra.patches as check_patches items. Constraints are read by composer's own semver library. - composer_lock: the file, or the slim form {"packages":[{"name","version"}]} for drupal/* only. composer_json adds constraints and extra.patches. target_core: 11.4 or 11.4.5; empty scans against the installed core (target_is_installed), i.e. what can be updated without a core upgrade. - rows, ranked problems first: no_release (no published release supports the target; latest_any and dev_branch say what exists), update (a compatible release the site does not have: latest, latest_core), unknown (not a drupal.org project in the bundle; the note says where its releases are), current (installed_supports and nothing newer needed; such a row carries package, installed and installed_supports only). counts covers every package even when rows are cut. - candidates on every row that is not current: the newest three releases with version, core constraint, date and supports_target. That is what choosing a version needs; project_profile adds installs and branches, not more releases. - patches: one item per extra.patches entry with the installed version filled in; pass them to check_patches after composer update (local paths need the file text). - patches:true answers with plan instead: every patch judged against the release its package would install for target_core, so the join needs no second call. plan.counts is the verdict tally, plan.package_counts the scan tallies, plan.no_release the packages that block the target, plan.patches one row per patch needing a decision (needs-reroll, unknown, shipped), and plan.still_needed the number that apply and are still required. The scan rows themselves are not in a plan; call again without patches for them. A patch whose package has no release for the target is unknown with the reason in note; a row's project for reroll_patch is its package without the drupal/ prefix. - A plan never carries a re-rolled diff: plan.next_step names reroll_patch, one call per patch, when any patch no longer applies. - bundle_date is when the release data was published; a release after it is invisible here, so confirm a no_release with composer show or drupal.org before acting.
- search_codeshallow
Search the source of every indexed contrib project, plus core, for a code pattern: which files, or with by_repo which projects. Who-uses-a-core-symbol counts: list_symbol_users or lookup_core_symbol. - query is a regex; set literal for exact text with ( [ ] . $ : or a space, and put r: f: lang: case: sym: b: terms in filters. repos takes machine names. The index runs RE2: no lookaround, no backreferences. - .module, .install, .theme, .engine, .profile, .inc count as PHP (lang:php reaches them; sym: resolves inside them); no language filter is applied for you. - Returns total_matches and total_files plus a head of files (repo, path, matching lines), limit ≤ 50. by_repo: (repo, file_count) rows from a pull of ≤ 1000 files, total_files the ceiling, truncated when cut. A parse error returns the index's own message.
- subsystem_couplingshallow
Answer "what else tends to fail when a merge request touches this core subsystem" from CI history over ~9,000 core MRs; with issue_nid, "which subsystems does this issue touch and what co-fails with them". No arguments: the directory of subsystem names (shared by core_symbol.subsystem and list_symbol_users subsystem=). - subsystem resolves a name (Views, case-insensitive) or a bucket (module:views, core_lib:Entity); unknown → refused with the nearest names. - Edge: touched_bucket → failing_bucket (+ subsystem), lift, co_fail_count, touched_count, failed_count, total_mrs; lift = P(fail | touched) − P(fail | any MR). Self edges left out. - Floors min_lift (0.05) and min_co_fail (3) drop noise; count = edges above them, edges ≤ limit (≤ 50) by lift. When nothing clears the floors the strongest edges are listed with a note. - issue_nid: touched_subsystems first; a note explains an issue with no MR file data.
- what_changedshallow
Answer "what changed in the core API between two core versions": symbols added, deprecated, removed, as ranked groups with counts. One symbol: lookup_core_symbol. Human write-ups: list_change_records. Every row of one bucket: flat=true with bucket, paged; every row of the whole diff: the result's bulk block (attach + sql for the published catalog, rows to disk not context). - Bounds inclusive; forms 11.2, 11.2.x, 11.2.0, 11, 11.x; same version twice = one minor; upgrading 11.2 → 11.4 means from=11.3. Buckets are independent. - Grouped (default): a head entry is a symbol group (grouped_by: change_record | name_prefix | singleton); head counts groups (≤ 5), count symbols, group_count groups; members ≤ 3 per group, highest usage first; group fields appear only when every member agrees. Rank: max_projects_using desc, then member_count magnitude, tier, count, key (ranked_by). head_covers_all_callers false → narrow with kind / min_projects_using or page with offset. - Flat (flat=true, bucket=added, deprecated, removed): rows by projects_using then fqn: fqn, kind, subsystem, stamp, projects_using, removal_in, removal_kind, replacement when the catalog names one, change_record_nids. count = public symbols in the bucket after filters; limit ≤ 100, next_offset absent on the last page. - Filters apply to every count. internal_excluded and test_theme_excluded are counted apart and left out; unplaceable_symbols have no minor in their stamp. - Usage = contrib development branches only, evidence rollup as of usage_evidence_built_at; 0 = no caller observed. - change_record_nids → get_change_record. removal_kind observed = gone, scheduled = promised and still present (say "scheduled for removal in 13.0").
Embed this server’s score
Tool count and median score across every tool in this server’s corpus — honest in a way a single cherry-picked tool’s badge wouldn’t be.
[](https://vouch.tools/servers/d68e7689-3a2e-4660-bb0a-a1d4b0d1cbd4)