testing/cross_backend/action_manifest_parity.ts

Cross-impl action-manifest parity — structural diff + assertion over two ActionManifests captured via the _testing_action_manifest RPC action.

The action-surface twin of schema_parity.ts: two live impls (the TS fuz_app spine and the Rust testing_spine_stub) are each other's parity reference. After both bootstrap, dump each one's live RPC method set, diff, fail loudly on drift. The diff entries name the specific divergence (a method only one impl mounts, a per-method auth-axis or side-effect mismatch) so the error message points at the source.

const manifest_a = await capture_action_manifest(ts_handle); const manifest_b = await capture_action_manifest(rust_handle); assert_action_manifests_equal(manifest_a, manifest_b, {a: 'ts', b: 'rust'});

Non-coverage: the manifest captures `{method, side_effects, account, actor, roles, credential_types}` — the wire-relevant auth shape. It does not capture input/output schemas (the declared-surface wire shape is gated by rpc_round_trip) nor the protocol actions heartbeat / cancel (excluded by construction — see action_manifest.ts).

view source

Declarations
#

5 declarations

ActionManifestDiff
#

ActionManifestDiffLabels
#

testing/cross_backend/action_manifest_parity.ts view source

ActionManifestDiffLabels import type {ActionManifestDiffLabels} from '@fuzdev/fuz_app/testing/cross_backend/action_manifest_parity.js';

Labels used in formatted output — defaults to 'a' and 'b'.

a?

type string

readonly

b?

type string

readonly

assert_action_manifests_equal
#

testing/cross_backend/action_manifest_parity.ts view source

(a: { methods: { method: string; side_effects: boolean; account: "none" | "optional" | "required"; actor: "none" | "optional" | "required"; roles: string[]; credential_types: string[]; }[]; }, b: { ...; }, labels?: ActionManifestDiffLabels): void import {assert_action_manifests_equal} from '@fuzdev/fuz_app/testing/cross_backend/action_manifest_parity.js';

Throw if the two manifests disagree. The error message names the impls (via labels) and lists every diff, so the failure is self-diagnosing.

a

type { methods: { method: string; side_effects: boolean; account: "none" | "optional" | "required"; actor: "none" | "optional" | "required"; roles: string[]; credential_types: string[]; }[]; }

b

type { methods: { method: string; side_effects: boolean; account: "none" | "optional" | "required"; actor: "none" | "optional" | "required"; roles: string[]; credential_types: string[]; }[]; }

labels

default {}

returns

void

diff_action_manifests
#

testing/cross_backend/action_manifest_parity.ts view source

(a: { methods: { method: string; side_effects: boolean; account: "none" | "optional" | "required"; actor: "none" | "optional" | "required"; roles: string[]; credential_types: string[]; }[]; }, b: { ...; }): ActionManifestDiff[] import {diff_action_manifests} from '@fuzdev/fuz_app/testing/cross_backend/action_manifest_parity.js';

Structural diff between two manifests — empty array means parity holds.

Order is deterministic: methods in sorted order, with each method's side-effect + auth-field sub-diffs grouped together.

a

type { methods: { method: string; side_effects: boolean; account: "none" | "optional" | "required"; actor: "none" | "optional" | "required"; roles: string[]; credential_types: string[]; }[]; }

b

type { methods: { method: string; side_effects: boolean; account: "none" | "optional" | "required"; actor: "none" | "optional" | "required"; roles: string[]; credential_types: string[]; }[]; }

returns

ActionManifestDiff[]

format_action_manifest_diffs
#

testing/cross_backend/action_manifest_parity.ts view source

(diffs: readonly ActionManifestDiff[], labels?: ActionManifestDiffLabels): string import {format_action_manifest_diffs} from '@fuzdev/fuz_app/testing/cross_backend/action_manifest_parity.js';

Render a diff list as a human-readable multi-line string. Empty diffs produce an empty string.

diffs

type readonly ActionManifestDiff[]

labels

default {}

returns

string

Depends on
#