Quality gates
Release runtime matrix
Detailed page. Use “On this page” to jump directly to the section you need.
This is the minimum release contract for Record Health Check. It applies to every package release, including patch builds. A missing, skipped, timed-out, inconclusive, or stale result is a failure. Static analysis and unit tests do not substitute for a live Salesforce result.
Scratch-org and package-version creation are scarce, owner-controlled release operations. Pull requests run no-org CI only. Salesforce workflows are dispatched manually, after known defects have been diagnosed without creating new orgs. A shared no-org preflight and blocking source analyzer must pass before source runtime jobs can create anything. Namespaced LWS runs before portable LWS, which runs before the one-at-a-time Locker matrix. Subscriber stages also run one org at a time and require exact-commit hosted source evidence. Queued matrix work stops on failure.
GitHub artifact uploads use a Node 24 action; project npm commands use the Node major pinned in
config/toolchain.json. These are separate runtimes. Deprecated action runtimes must not be restored
by enabling an insecure-runtime opt-out. Missing evidence remains a failure, not a warning to ignore.
The machine-readable dimensions are in
config/release-runtime-matrix.json. The CI guard
npm run check:release-runtime-matrix rejects missing dimensions, missing evidence files, weakened
workflow wiring, or incomplete package-install verification.
Version identity
Section titled “Version identity”The package version is major.minor.patch.build. Use the candidate and stable package IDs from
the release configuration for the upgrade path. A package candidate is identified by its exact 04t version ID and Git commit SHA.
Evidence from another build, branch head, pull-request merge commit, or package ID cannot satisfy a
candidate’s gate.
Gate sequence
Section titled “Gate sequence”| Stage | Required result | Failure behavior |
|---|---|---|
| Pull request and committed source | Every tracked check in .github/workflows/ci.yml passes | Do not merge or call the source CI-ready |
| Optional hosted source validation | When explicitly authorized, namespaced LWS and Locker jobs report additional evidence for the exact commit | Record failures without blocking package creation |
| Package creation | Code coverage, artifact membership, version identity, and dependency checks pass | Do not publish a candidate for subscriber testing |
| Optional subscriber testing | When explicitly authorized, clean installation and reviewed upgrades exercise the exact candidate | Record the result as additional evidence |
| Optional representative sandbox | A reviewer may record exact-candidate acceptance of the affected customer experience | Retain the result as human evidence |
| Promotion | Local creation evidence and the Dev Hub package report identify the exact candidate and commit | Promotion command must fail closed on an identity mismatch |
| Release publication | Release registry, changelog, install links, tag, and rollback information identify the promoted 04t | Do not announce the release |
Package creation and promotion require a clean Git worktree and exact local creation evidence before
invoking a Salesforce mutation. Hosted workflows are optional and require explicit scratch-org
authorization. Every workflow artifact upload uses
if-no-files-found: error; a successful test without its retained evidence is a failed release gate.
Apex result collection
Section titled “Apex result collection”The exact-inventory runner requests global --json as well as JSON result files. Global JSON mode
bypasses the Salesforce CLI’s styled console formatter, which can exhaust the Node heap on large
per-test coverage payloads even when stdout is ignored. Preserve that flag when changing the runner.
The checked-in inventory and command-exit guards are the executable fixtures for this repository-only
reporting behavior; no Check or Check Set configuration is involved.
A passing result file does not turn an aborted CLI command into a successful invocation. Retain the
failed command evidence, retrieve the same completed run with sf apex get test --json, and reconcile
its class/method inventory and command exit. If Streaming API reporting stalls, retrieve
ApexTestRunResult and ApexTestResult through the Tooling API and reconcile the actual class and
method rows, including IsTestSetup; summary completion counters alone are not sufficient.
Do not submit duplicate tests solely to recover a report.
Salesforce environment matrix
Section titled “Salesforce environment matrix”Source validation uses the package’s real namespace in both supported Lightning security modes:
| Namespace topology | Lightning security mode | Browser engines |
|---|---|---|
rhc namespaced | Lightning Web Security | Chromium and Firefox |
rhc namespaced | Lightning Locker | Chromium and Firefox |
Each org must be newly created from the tracked scratch definition. The workflow records the org
shape, deploy result, test result, and browser artifacts. Reusing an org is not evidence for the
hosted release gate. A no-namespace deployment of unpackaged source remains an optional contributor
portability check; it is not another form of the released rhc package.
Evaluation and entry-point matrix
Section titled “Evaluation and entry-point matrix”Every entry point must execute a Check Set containing all four evaluation types:
- Formula
- Query
- Compare Two Queries
- Apex
The required entry points are:
| Entry point | Required live proof |
|---|---|
| Lightning Web Component, manual | Component renders without a page-level or component spinner, Run completes, and all four types return results |
| Lightning Web Component, run on load | Initial shell remains quiet, deferred run completes, and no manual Run button is shown |
| Apex API | Public Apex API returns all four evaluation types |
| Flow | A real Flow interview invokes the packaged action and returns all four types |
| REST/MCP | Authenticated REST request and MCP contract return all four types through the namespaced package API |
| Native Agentforce actions | The packaged Check Set action crosses the invocable boundary and accounts for every Check in the four-type set |
| Platform Events | ALL publication emits one Check Result per executed Check and one Set Run event, and subscriber-owned triggers receive them |
| Queueable | Job completes and its Check Set covers all four types |
| Batch | Job completes and its Check Set covers all four types |
| Scheduled | Scheduled adapter launches the work, it completes, and its Check Set covers all four types |
An Apex unit test that calls the shared service directly does not replace the Flow, REST, browser, or asynchronous adapter test. Every adapter must cross its real platform boundary.
Lightning lifecycle matrix
Section titled “Lightning lifecycle matrix”Browser validation must reject uncaught JavaScript errors, Salesforce component error dialogs, the
reported Invalid contextElement failure, incomplete runs, and persistent spinners. It covers:
- a configured component in Lightning App Builder;
- a component with no selected Check Set in App Builder;
- a saved record page in normal view mode;
- manual and run-on-load components on the same page;
- initial load without a page-level loading overlay;
- RefreshView registration and refresh execution;
- record-to-record navigation without a full browser reload;
- component disconnect/reconnect without stale handlers or duplicate work;
- LWS and Locker with the package’s
rhcnamespace; - Chromium and Firefox;
- administrator and restricted-user permission assignments;
- post-install and post-upgrade rendering.
The builder canvas must remain inert: it may show configuration guidance, but it must not run a record check, show an operational spinner, register an invalid RefreshView context, or require a record ID. At runtime, the component renders its shell first and defers on-load work; it does not put a loading overlay on the record page.
The source automatic fixture is Release_On_Load, with exactly one Check of each type. Its seeded
Account yields three passes and the expected recent-activity failure. The installed fixture is
Subscriber_On_Load, with four expected passes. Both reject Unable and System Error results.
The restricted browser user receives Card User, not the broader User permission set.
Each browser/scenario run retains its own JSON verdict and evidence directory. Skipped,
failed, and flaky/retry-recovered tests block the gate; later runs cannot overwrite earlier
results.
The release runner redacts login URLs, session IDs, and generated passwords before retaining JSON and a readable HTML view. Raw traces, videos, and screenshots are disabled for this authentication- inclusive run to keep credentials out of uploaded artifacts. Unredacted reporter output stays in a temporary directory outside the upload paths and is removed when the browser process finishes.
Apex and server-side gates
Section titled “Apex and server-side gates”The namespaced source org runs two explicit, reconciled inventories: package-only tests before
fixtures, then the final package-plus-integration identity set after the harness is deployed.
npm run test:apex:exact inventories every repository class with a real class-level @IsTest
annotation, passes every discovered class explicitly to Salesforce, and reconciles the returned
methods and class names against that inventory. A missing, unexpected, skipped, failing, or
unreported class fails the gate.
The raw Salesforce result and reconciliation verdict are kept for 90 days as two artifacts:
namespaced package and namespaced full. The 18 test
identities intentionally overlaid by fixture-aware integration variants are pinned in
config/apex-test-overlays.json; the package variant runs in the first phase and the integration
variant runs in the second. Any new duplicate identity or missing side of an approved overlay fails
before Salesforce is called. The gate includes:
- CRUD, field-level security, sharing, and restricted-user behavior;
- injection-resistant dynamic SOQL and merge-token validation;
- bulk input and governor-limit behavior;
- all public Apex entry points and invocable actions;
- Queueable, Batch, Scheduled, REST, and platform-event behavior;
- positive, negative, null, malformed, unauthorized, and partial-failure paths;
- package namespace resolution, with optional no-namespace portability available to contributors;
- blocking Code Analyzer
AppExchange,Recommended:Security, and every Flow Scanner rule for package, integration, and subscriber-harness source, plus an all-rules advisory report; - exact package test coverage, with no coverage bypass.
The installed-package tests repeat the public API, Flow interview, four evaluation types,
REST/MCP, Queueable, Batch, Scheduled, and LWC gates after both a clean installation and the
upgrade. The matrix remains blocked unless the subscriber-owned Flow and its Apex interview test
exist; an Apex-only substitute does not satisfy the Flow entry-point gate.
Subscriber execution also discovers and reconciles every executable test class under
subscriber-app/main/default/classes, including RHCSubscriberFlowSmokeTest; each selected stage
retains a separate mandatory Apex artifact for each security mode.
Security release contract
Section titled “Security release contract”Security is checked at source, deployed-source, clean-install, and upgrade boundaries. A scanner result is not accepted if its engine logs contain a processing exception, even when the scanner returns exit code zero and reports zero violations.
Apex execution and data access
Section titled “Apex execution and data access”- Runtime service and adapter classes declare
with sharing; packaged invocable classes, methods, request types, response types, and variables areglobalso the exact subscriber-namespace boundary is compiled and exercised rather than assumed. - Every execution surface requires the packaged Run custom permission. Restricted-user tests must prove denial through the Apex API, Flow action, REST/MCP adapter, Agentforce action, Queueable, Batch, and Scheduled submission, with no record-health detail in the denial response.
- Customer-record queries use
WITH USER_MODEorAccessLevel.USER_MODE, Schema-derived object and field identifiers, and bind variables. Admin-authored query templates cannot requestWITH SYSTEM_MODE, add executable syntax through merge tokens, or access an undisclosed field. - Exactly five reviewed system-mode operations are pinned by
check:apex-surface: one direct packaged-permission assignment query inRecordHealthCheckAccess, one Custom Metadata definition query inRecordHealthCheckScopePlanner, and two bounded queries plus one bounded delete for private readiness evidence inRecordHealthCheckReadinessService. None reads or changes customer business records. Any additional or relocatedSYSTEM_MODEuse requires a reviewed source-policy change, an exact-count gate update, and new restricted-user and package-build evidence. - Formula, relationship, currency, polymorphic, aggregate, grouped, dual-query, and plugin paths enforce object access, field access, sharing, type compatibility, bounded scope, query-row, query, CPU, heap, serialization, and response-size ceilings. Tests cover bulk, null, malformed, inaccessible, partial-failure, and exception paths.
- The package does not grant object or field access to customer business objects. The executing user’s permissions remain in control, and subscriber plugin code runs in its declared sharing context.
LWC, browser, and Lightning security
Section titled “LWC, browser, and Lightning security”- Shipped LWC source is checked by Salesforce’s LWC lint rules, the Locker security rules, the release compatibility scanner, ESLint Recommended, RetireJS Recommended, Jest, SLDS 1/2 linting, and real browsers in both Lightning Web Security and Lightning Locker.
- Shipped code cannot use page-owned
documentDOM,innerHTML,outerHTML,shadowRoot, dynamic code evaluation, browser storage, worker escape APIs, Aura globals, manual DOM, or executable URL schemes. Guided-action URLs accept only an in-app absolute path or explicit HTTPS URL. - RefreshView must retain both supported registration protocols: the LWS component form first and the Locker host-plus-bound-handler fallback. Registration failure is fail-open for rendering, and disconnect unregisters the accepted handler.
- Initial configuration and run-on-load work is deferred until after the shell renders. No component spinner or page-level loading overlay is permitted on initial load, in App Builder, or during automatic execution. Progress after a deliberate user click stays inside the clicked action control.
- A configured App Builder preview makes one lightweight shell request so it can identify the selected Check Set and show active/inactive counts. An unconfigured preview remains server-inert. Neither preview loads definitions, evaluates a Check, accesses sample-record data, or renders a runtime action.
- Browser tests fail on any uncaught page error, Salesforce component-error dialog, incomplete
result count, persistent spinner, duplicate automatic run, stale handler, full reload during
record navigation, or the reported
Invalid contextElementsignature.
REST, MCP, Agentforce, Flow, async, and events
Section titled “REST, MCP, Agentforce, Flow, async, and events”- REST accepts only authenticated callers with the Run custom permission, JSON content type, a bounded request body, an approved operation, one syntactically valid record ID, exact qualified metadata identity, and a bounded safe correlation ID. It returns versioned, redacted validation, authorization, limit, or execution envelopes rather than raw exceptions.
- MCP and Agentforce inputs use the same exact qualified identity contract. Agentforce/MCP-backed invocable methods are global, run as the authenticated user, use sharing, and return aligned, bounded output. Flow tests must use a real Flow interview; a direct Apex call is supplemental.
- Queueable, Batch, and Scheduled adapters recheck authorization at both submission and execution
boundaries, defensively copy and bound explicit record populations, and publish no event unless
the caller requests an allowed publication mode. Their release tests capture every result event,
resolve each event’s exact Check identity back to Custom Metadata, and require the resulting set
to contain
APEX,COMPARE_TWO_QUERIES,FORMULA, andQUERY; job completion or event counts alone are insufficient evidence. - Platform Events contain stable IDs, counts, status, reason code, source, and record identity but no raw exception or restricted diagnostic detail. Publication is chunked, publish failures are inspected, subscriber triggers are exercised, and recursion is suppressed.
Static-analysis and exception integrity
Section titled “Static-analysis and exception integrity”- The blocking Apex/XML profile runs Salesforce Code Analyzer’s
AppExchange,Recommended:Security, andflow:allselectors. Shipped JavaScript runseslint:Recommendedandretire-js:Recommended; the all-rules reports remain retained advisory evidence. - Analyzer JSON must be complete and every analyzer log must be free of engine processing errors and null-pointer failures. This prevents a scanner crash from becoming a false green release result.
code-analyzer.ymlhas an exact approved list of five file-scopedProtectSensitiveDatafalse positives. Each permits one finding and carries a specific reason. A new path, a second finding, a widened limit, or globally disabling that security rule fails CI and release preflight.- Inline Apex suppressions remain visible beside the guarded statement and are reviewed with the code. Hosted reports, scanner versions, configurations, logs, and HTML/JSON results are retained for 90 days against the exact commit.
Upgrade and data-preservation gates
Section titled “Upgrade and data-preservation gates”Each upgrade org starts with the exact reviewed release declared in upgradeBases. Before upgrading,
the workflow creates subscriber-owned Check Sets and Checks and records their identities and values.
It then:
- deploys only the subscriber-owned preservation fixture and proves the stable package global Apex API can execute it;
- installs the exact candidate package using the tracked upgrade mode;
- verifies the installed package version ID;
- proves the subscriber-owned metadata is unchanged;
- reassigns and verifies permissions;
- deploys the candidate-only subscriber harness, then runs Apex, asynchronous, REST/MCP, Flow, Agentforce, Platform Event, App Builder, restricted-user, and browser gates under both LWS and Locker;
- retains install requests, test output, sanitized browser reports, and the exact before/after Custom Metadata preservation snapshot for 90 days.
A clean install cannot satisfy the upgrade gate. An upgrade that succeeds but loses configuration or fails an entry point is a failed release.
The optional subscriber workflow offers only the stages declared by expectedStages. Each
authorized stage creates two fresh orgs (LWS and Locker). Daily quotas may require the staged plan in the
scratch org lifecycle. Shared workflow
concurrency prevents release workflows from overlapping but does not reserve Dev Hub quota.
The five representative-sandbox scenarios in the manual release-owner checklist remain available for optional human review. The guarded promotion command does not require that attestation.
Supply-chain, metadata, and documentation gates
Section titled “Supply-chain, metadata, and documentation gates”The release also requires:
- pinned Node, Salesforce CLI, Java, Python, and Code Analyzer policy versions;
- separate audits of the root and MCP service lockfiles: production dependencies fail on any
known vulnerability, and the complete dependency trees fail on moderate or higher severity. Run
npm run check:dependency-securityto audit both. The patched@babel/coretransitive override is lockfile-pinned and must remain compatible with the Salesforce LWC compiler and Jest suite; - package-boundary, manifest, converted-artifact, permission, namespace-token, API-surface, query, field-limit, XML, formatting, lint, SLDS, JavaScript, and documentation checks;
- every intended Custom Metadata record in both the manifest and physical package artifact;
- permanent regression tests for every escaped defect;
- release notes that describe user-visible behavior, upgrade impact, and rollback steps;
- retained evidence tied to the exact commit and
04tcandidate.
For an explicitly authorized optional workflow, missing credentials, unavailable scratch capacity, and test failures must remain visible failures. They do not block package creation or promotion.
Evidence and exceptions
Section titled “Evidence and exceptions”Evidence belongs in hosted workflow logs and retained artifacts for the exact source revision. Record deploy IDs, Apex run IDs, org shape, security mode, sanitized browser reports, package install request IDs, before/after metadata snapshots, candidate ID, and workflow URL.
The hosted checker verifies successful named jobs and nonempty, unexpired artifacts created in the current attempt, not merely the overall workflow conclusion. Artifact presence is not an independent content audit: the test runners must validate their results before publishing evidence.
There is no informal release exception. Reducing supported scope or waiving a gate requires a reviewed source change to this contract and the machine-readable matrix before a candidate exists; it must not be done to make a failing candidate pass.