testing/cross_backend/method_coverage.ts

Reconcile a backend's live-mounted RPC method set against a tagged coverage manifest, so the off-declared-surface methods stay as drift-proof as the declared ones.

The spec-derived suites (describe_rpc_round_trip_tests / describe_rpc_attack_surface_tests) auto-enumerate the declared surface — add a method to a registry in create_spine_surface_spec and it is tested automatically. But a backend's live RPC endpoint also mounts methods kept *off* that surface (stateful cell verbs, opt-in resolvers, _testing_* backdoors); those rely on hand-wired imperative suites and get no auto-enumeration. Nothing structurally guaranteed every live method was actually claimed by a suite — so a newly mounted-but-untested method could ship silently.

{@link assert_rpc_method_coverage} closes that gap: it diffs the live method set against a {@link MethodCoverageEntry} manifest (both directions — a mounted-but-unclaimed method *and* a stale manifest row both fail loud) and checks each entry's tier is consistent with the declared surface + the backdoor prefix. The manifest becomes the forcing function — a new method can't reach the live mount without a manifest row naming the suite that covers it.

Pairs with surface_invariants.ts assert_no_testing_methods (which guards the *reverse* — a backdoor must never leak *onto* the declared surface).

view source

Declarations
#

4 declarations

assert_rpc_method_coverage
#

testing/cross_backend/method_coverage.ts view source

(input: RpcMethodCoverageInput): void import {assert_rpc_method_coverage} from '@fuzdev/fuz_app/testing/cross_backend/method_coverage.js';

Assert the live RPC method set reconciles exactly with the coverage manifest, and that every manifest entry's tier is internally consistent.

Fails loud on: a live method missing from the manifest (mounted-but-unclaimed), a manifest row naming a method the live mount no longer exposes (stale row), a declared-surface method absent from the live mount (the full mount must be a superset), a duplicate manifest entry, or any tier/declared/backdoor inconsistency (e.g. an off_surface row that is actually on the declared surface, or one missing its suite).

input

returns

void

throws

  • AssertionError - naming the specific divergence.

MethodCoverageEntry
#

testing/cross_backend/method_coverage.ts view source

MethodCoverageEntry import type {MethodCoverageEntry} from '@fuzdev/fuz_app/testing/cross_backend/method_coverage.js';

One row of the live-RPC-method coverage manifest.

method

The RPC method name (action.spec.method).

type string

readonly

tier

How this method is covered.

type MethodCoverageTier

readonly

capability?

The BackendCapabilities flag gating this method's cross suite, when it is capability-gated. Typed against the real interface so a stale flag is a compile error. Omit for ungated off-surface families (always-mounted, the suite runs unconditionally) and for declared / backdoor tiers.

type keyof BackendCapabilities

readonly

suite?

The cross-backend suite (or test file) that covers this method. Required for off_surface — the manifest's whole point is to name the suite a method without auto-enumeration relies on. Optional for declared (auto-enumerated) / backdoor (infra).

type string

readonly

note?

Optional free-text note printed nowhere — documentation for the reader.

type string

readonly

MethodCoverageTier
#

RpcMethodCoverageInput
#

testing/cross_backend/method_coverage.ts view source

RpcMethodCoverageInput import type {RpcMethodCoverageInput} from '@fuzdev/fuz_app/testing/cross_backend/method_coverage.js';

Inputs for .

live_methods

Every method the live RPC endpoint mounts (action.spec.method).

type ReadonlyArray<string>

readonly

declared_methods

The declared-surface method names (from create_*_surface_spec).

type ReadonlyArray<string>

readonly

manifest

The tagged manifest the live set must reconcile against.

type ReadonlyArray<MethodCoverageEntry>

readonly

testing_method_prefix?

Backdoor method prefix. Defaults to '_testing_'.

type string

readonly

Depends on
#