Skip to content

Use Org Metadata Catalog for find-missing-artifact org lookups - W-23971749 #664

Description

@peternhale

Summary

Canonical work item: W-23971749

Migrate org-related findMissingArtifact lookups in packages/apex-lsp-vscode-extension to the production Org Metadata Catalog exposed by @salesforce/vscode-services.

The immediate goal is to stop the Apex language-server client from owning duplicate org discovery, Tooling queries, and remote Apex source storage where the released catalog can provide those responsibilities. The migration must preserve the existing parser-owned candidate selection, missing-artifact wire protocol, workspace-first behavior, org-switch isolation, and graceful degradation.

Production API baseline

Current Apex LS client behavior

handleFindMissingArtifact is workspace-first and currently composes multiple Salesforce Services APIs:

Artifact Workspace lookup Org lookup Result
Apex class ComponentSetService Direct Tooling SOQL through ConnectionService Client-owned apex-org-artifact: document
Apex trigger ComponentSetService Direct Tooling SOQL through ConnectionService Client-owned apex-org-artifact: document
sObject ComponentSetService plus local metadata adaptation MetadataDescribeService.describeCustomObject Structured missing-artifact payload

Relevant implementation:

  • src/missing-artifact-handler.ts
  • src/services/org-artifact-adapter.ts
  • src/services/org-artifact-fs.ts
  • src/services/workspace-component-set-adapter.ts
  • src/sobjects/org-sobject-adapter.ts

Recommended delivery approach

Use a phased hybrid migration.

Phase 1: released catalog path for Apex classes and triggers

  1. Upgrade the development API dependency and establish the minimum compatible Salesforce Services extension version containing the catalog.
  2. Add a narrow client adapter over api.services.OrgMetadataCatalog and provide effects with prebuiltServicesDependencies.
  3. Translate parser-derived exact candidates to { type: 'ApexClass' | 'ApexTrigger', fullName } references.
  4. Batch exact candidates through OrgMetadataCatalog.getEntries(...).
  5. Preserve candidate order and select the first matching component. Prefer workspaceUri when the entry is in the workspace; otherwise open its catalog documentUri.
  6. Synchronize sf-org-metadata: Apex class and trigger documents with the language server.
  7. On the catalog path, remove direct client Tooling queries and stop materializing Apex class/trigger source in OrgArtifactFileSystem.
  8. Retain an explicitly transitional capability/version fallback for older Salesforce Services releases. Record whether catalog or legacy resolution handled the request.

Phase 2: catalog-owned sObject descriptions

Continue using MetadataDescribeService.describeCustomObject until Salesforce Services exposes a catalog-owned, batch-oriented description operation such as describeSObjects(names).

When available:

  1. Switch org sObject lookup to the catalog operation.
  2. Keep Apex-specific adaptation, definition targets, and wire-size enforcement in this repository.
  3. Remove the direct public MetadataDescribeService dependency from the supported path.

Options considered

A. Use only the released 67.13.3 catalog now

  • Use getEntries and catalog documents for Apex classes/triggers.
  • Keep direct describe for sObjects.
  • Fastest way to remove duplicate source discovery/storage, but it is intentionally partial.
  • getEntries may acquire a complete metadata-type inventory and does not encapsulate workspace-first document selection as a dedicated finder contract would.

B. Wait for findComponents and describeSObjects

  • Produces the cleanest one-step migration and clearer miss/error semantics.
  • Delays consuming a production catalog that already handles Apex source inventory, workspace correlation, stable documents, caching, persistence, and org isolation.

C. Phased hybrid migration — recommended

  • Delivers value from the production API now.
  • Keeps the compatibility boundary narrow.
  • Avoids inventing a client-side sObject catalog API that Services does not yet expose.
  • Leaves a direct path to the upstream finder/describe contracts when they are published.

Acceptance criteria

  • The client detects catalog capability and uses it when available.
  • Exact Apex class and trigger candidates come only from parser/symbol-derived missing-artifact data; no raw-source semantic heuristics are introduced.
  • Workspace-only, org-only, and both-present Apex classes and triggers resolve with deterministic workspace-first behavior.
  • Org-only source opens through sf-org-metadata: and synchronizes with the language server.
  • Namespaced and unqualified Apex class/trigger candidates retain existing semantic ordering.
  • Missing, protected, authorization-failed, no-active-org, and request-failed outcomes preserve current suppression/degradation behavior.
  • Active-org changes cannot commit stale results or leak documents from the previous org.
  • Concurrent and duplicate requests remain coalesced/bounded.
  • Direct Tooling SOQL and client-owned Apex/trigger VFS storage are not used on the catalog path.
  • Existing sObject semantic payloads and definition navigation remain unchanged while the temporary describe path remains.
  • Telemetry distinguishes catalog versus legacy resolution without recording org, namespace, component, object, or field names.
  • Unit/integration coverage includes catalog capability fallback and the existing missing-artifact scenarios.
  • The minimum supported salesforcedx-vscode-services version and fallback removal condition are documented.

Upstream/package prerequisite to verify

The published @salesforce/vscode-services@67.13.3 tarball contains only 11 files, and out/index.d.ts re-exports SalesforceVSCodeServicesApi from ../../salesforcedx-vscode-services/out/src/index, which is not included in that tarball. Before implementation, verify that a clean external consumer can resolve the catalog types. If not, open/fix the upstream packaging issue or temporarily maintain the existing narrow local interface without importing unpublished internals.

Non-goals

  • Changing the language-server missing-artifact wire protocol.
  • Moving Apex-specific candidate ordering or semantic adaptation into Salesforce Services.
  • Writing automatically resolved org source into the user workspace.
  • Permanently maintaining two discovery/storage implementations.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions