Tutorials

Diagnose one execution with DevTools

Connect the extension, reproduce a policy conflict, trace one Execution, and disclose only safe application data.

v0.1.0-dev.3Intermediateusecase_forge_devtools

Diagnose one execution with DevTools

This tutorial turns an unclear report — “the second save did not run” — into a traceable lifecycle explanation. The extension remains read-only throughout the session.

01

Install the development tool

Add DevTools directly to the application being inspected, not only to another workspace package.

pubspec.yaml
dev_dependencies:
  usecase_forge_devtools: ^0.1.0-dev.3

Resolve dependencies and restart both the application and DevTools. No application initialize() call is required.

02

Create a policy conflict worth observing

Assume SaveDocument uses the document identifier as its executionKey and rejects a new Command while related work is active.

lib/document_usecase.dart
registerCommand<SaveDocument>(
  _save,
  instructions: const UseCaseInstructionOverrides(
    processing: UseCaseProcessingInstructionOverrides(
      existingExecutionPolicy: UseCaseExistingExecutionPolicy.rejectNew,
    ),
  ),
);

Run a development build, submit two saves for the same document before the first finishes, and keep the UseCase alive while opening DevTools.

03

Find the earliest visible boundary

Open the UseCase Forge tab and select the relevant UseCase. Read the lifecycle in order:

  1. confirm the exact Command type and executionKey;
  2. check whether the second entry reached Admission or Pending;
  3. inspect rejection events before blaming handler duration;
  4. look for activeConflict and the rejectNew policy;
  5. verify that the first Execution continues independently.

The rejected Command does not enter terminal history because processing never started. That absence is part of the contract, not missing telemetry.

04

Trace the accepted Execution

Use its Execution ID to connect positions, Snapshot changes, cancellation events, error routing, and the terminal Entry. Command type and group key explain related work; only the Execution ID identifies one attempt.

05

Expose a safe diagnostic representation

Technical lifecycle metadata is automatic. Application values stay hidden until the UseCase explicitly provides bounded JSON-safe data.

lib/document_usecase.dart
import 'package:usecase_forge/diagnostics.dart';

final class DocumentUseCase extends UseCase<DocumentState>
    with UseCaseDiagnosticsDataProvider {
  @override
  String get useCaseDiagnosticLabel => 'Document editor';

  @override
  Object? encodeUseCaseDiagnosticValue(
    UseCaseDiagnosticValueKind kind,
    Object? value,
  ) {
    if (kind == UseCaseDiagnosticValueKind.state && value is DocumentState) {
      return {'dirty': value.isDirty, 'revision': value.revision};
    }
    return null;
  }
}

Do not expose document contents, credentials, personal data, unrestricted stack traces, or full network payloads. Returning null keeps a value hidden.

06

Write down the diagnosis

A useful result names evidence and ownership:

The second SaveDocument was rejected with activeConflict. Both Commands had the same exact type and document key. The registered rejectNew policy preserved the first active Execution. The save handler did not receive the second Command.

From here, decide whether product behavior requires rejectNew, restart, or coexist. DevTools proves what happened; it does not choose the product policy.

Continue with queue and policy diagnosis, safe diagnostic data, and error-route tracing.

ARKTELOS

Purpose-built engineering systems for software that has to hold.