Define a single “success contract” for each step: only report ok/success if the operation is actually accepted; for optional steps, convert failures into a structured soft-skip (but still record a diagnostic reason).

Apply these rules: 1) Optional work ⇒ soft-skip with reason

2) Required work ⇒ hard-fail

3) API writes ⇒ treat provider error channels as failures

Example (optional step soft-skip)

async function stageBrowser({ hasNode, skipReasonRef, SkipChromium }) {
  if (!hasNode) {
    skipReasonRef.value = 'Node.js unavailable; optional browser tooling skipped';
    return { skipped: true };
  }
  try {
    await InstallAgentBrowser({ SkipChromium });
    return { skipped: false };
  } catch (e) {
    skipReasonRef.value = `agent-browser install failed: ${String(e?.message || e)}`;
    // Do NOT rethrow: optional degradation
    return { skipped: true };
  }
}

Example (GraphQL mutation userErrors)

async function applyMutationOrFail(client, mutation, variables) {
  const data = await gql(client, mutation, variables);
  const result = data?.[/* mutation root field */] || data;
  const userErrors = result?.userErrors || [];
  if (userErrors.length) {
    throw new Error(`Mutation rejected by API: ${JSON.stringify(userErrors)}`);
  }
  // Optionally verify returned fields match the approved inputs here.
  return result;
}

Outcome: fewer false “ok:true” results, predictable graceful degradation for optional features, and consistent diagnostics when failures happen.