accordant-quickref

$npx mdskill add microsoft/accordant/accordant-quickref

```csharp [State] public partial class MyState { public Dictionary<string, decimal> Balances { get; set; } = new(); public Dictionary<string, UserState> Users { get; set; } = new(); }

SKILL.md

.github/skills/accordant-quickrefView on GitHub ↗
---
name: accordant-quickref
description: Quick reference and cheatsheet for Accordant API - use this skill for quick syntax lookup or code snippets
---

# Accordant Quick Reference

## State Definition

```csharp
[State]
public partial class MyState
{
    public Dictionary<string, decimal> Balances { get; set; } = new();
    public Dictionary<string, UserState> Users { get; set; } = new();
}

[State]
public partial class UserState
{
    public string Name { get; set; } = string.Empty;
    public List<string> Tags { get; set; } = new();
}
```

## Create a Spec

```csharp
var spec = new Spec<MyState>()
    .WithJsonPrinters();  // Optional: nice logging
```

## Define Operations

### Inline Syntax

```csharp
spec.Operation<TRequest, TResponse>("OperationName", (request, state) =>
{
    // Return ExpectedOutcomes
});
```

### Examples

```csharp
// Simple request (single value)
spec.Operation<string, ApiResult<User>>("GetUser", (userId, state) => { ... });

// Tuple request (multiple values)
spec.Operation<(string Id, decimal Amount), ApiResult<decimal>>("Deposit", (request, state) =>
{
    var (id, amount) = request;  // Destructure
    // ...
});

// Class-based request
spec.Operation<CreateUserRequest, ApiResult<User>>("CreateUser", (request, state) => { ... });
```

## Expected Outcomes

### Basic Expectation

```csharp
Expect.That<TResponse>(response => /* predicate */)
```

### With Explanation (Recommended)

```csharp
Expect.That<ApiResult<decimal>>(
    r => r.IsSuccess && r.Data == expectedValue,
    $"Expected success with value {expectedValue}")
```

### With ValidationResult

```csharp
Expect.That<User>(response =>
{
    if (response.Name != expected)
        return ValidationResult.Invalid($"Name mismatch: {response.Name}");
    return ValidationResult.Valid();
})
```

### Exception Expectation

```csharp
Expect.Throws<NotFoundException>("Resource not found")
```

### Multiple Valid Outcomes

```csharp
Expect.OneOf(
    Expect.That<T>(r => /* outcome 1 */).ThenState(...),
    Expect.That<T>(r => /* outcome 2 */).SameState(),
    Expect.That<T>(r => /* outcome 3 */).ThenState(...)
)
```

## State Transitions

### No Change

```csharp
.SameState()
```

### State Changes

```csharp
.ThenState<MyState>(nextState => nextState.Items[id] = newValue)
```

### Response-Dependent State

```csharp
.ThenState<MyState>(
    (TResponse response, MyState nextState) =>
        nextState.Items[response.Id] = new Item { ... },
    mock: () => new TResponse { Id = Guid.NewGuid().ToString() })
```

## Async Operations

```csharp
.ThenState<MyState>(next => next.Jobs[id] = JobStatus.Pending)
.Triggers(AsyncOperation.Create<MyState>(
    isTerminal: s => s.Jobs[id] != JobStatus.Pending,
    transitions: new Action<MyState>[] {
        next => next.Jobs[id] = JobStatus.Completed,
        next => next.Jobs[id] = JobStatus.Failed
    }
))
```

## Bind Execution

```csharp
spec.ExecuteWith<ApiClient>()
    .Bind<TRequest, TResponse>("OperationName",
        (client, request) => client.Method(request).Result)
    .BindAsync<TRequest, TResponse>("AsyncOperation",
        async (client, request) => await client.MethodAsync(request));
```

## Test Generation

### Define Inputs

```csharp
var inputs = new InputSet
{
    spec.GetOperation<string, ApiResult<User>>("CreateUser").With("alice", "Create Alice"),
    spec.GetOperation<(string, decimal), ApiResult<decimal>>("Deposit").With(("alice", 100m), "Deposit 100"),
};
```

### Generate Tests

```csharp
var testCases = spec.GenerateTests(initialState, inputs, new TestGenerationOptions
{
    MaxDepth = 5,
    StateConstraint = state => ((MyState)state).Items.Count <= 3
});
```

### Run Tests

```csharp
var context = spec.CreateTestingContext();
context.Register(new ApiClient(httpClient));

var results = await spec.RunTests(context, initialState, testCases, new TestExecutionOptions
{
    BeforeEachAsync = async _ => await ResetDatabase()
});

Assert.That(results.All(r => r.Success));
```

## Concurrent Tests

```csharp
var concurrentTestCases = spec.GenerateConcurrentTests(initialState, inputs,
    new TestGenerationOptions { MaxDepth = 4 });

var results = await spec.RunTests(context, initialState, concurrentTestCases,
    new TestExecutionOptions { ... });
```

## Manual Conformance Testing

```csharp
var stateProfile = new StateProfile(initialState);

var response = await client.CreateUser("alice");
(bool isValid, string message, stateProfile) = 
    spec.Allows(createUserOp, "alice", response, stateProfile);

Assert.IsTrue(isValid, message);
```

## Visualization

```csharp
var dot = spec.VisualizeStateSpace(initialState, inputs, options);
File.WriteAllText("graph.dot", dot);
// Convert: dot -Tpng graph.dot -o graph.png
```

## TestGenerationOptions

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `MaxDepth` | int | 5 | Max sequence length |
| `StateConstraint` | Func<State, bool> | null | Prune states |
| `MaxConcurrencyLevel` | int | 3 | Concurrent ops |
| `SequentialTestCaseAlgorithm` | delegate | StateCoverage | Walk algorithm |

## Test Case Algorithms

```csharp
// State coverage (default)
SequentialTestCaseAlgorithms.StateCoverage

// Transition coverage
SequentialTestCaseAlgorithms.CreateTransitionCoverage(maxSequenceLength: 4)

// Random walk
SequentialTestCaseAlgorithms.CreateRandomWalk(numberOfWalks: 100, maxWalkLength: 8, seed: 42)
```

## Common Operation Pattern

```csharp
spec.Operation<(string Id, decimal Amount), ApiResult<decimal>>("Withdraw", (request, state) =>
{
    var (accountId, amount) = request;
    
    // Guard 1: Resource exists?
    if (!state.Accounts.TryGetValue(accountId, out var balance))
        return Expect.That<ApiResult<decimal>>(r => r.IsNotFound, "Account not found")
               .SameState();
    
    // Guard 2: Business rule
    if (balance < amount)
        return Expect.That<ApiResult<decimal>>(r => r.IsBadRequest, "Insufficient funds")
               .SameState();
    
    // Success path
    var newBalance = balance - amount;
    return Expect.That<ApiResult<decimal>>(
               r => r.IsSuccess && r.Data == newBalance,
               $"Expected new balance {newBalance}")
           .ThenState<BankState>(next => next.Accounts[accountId] = newBalance);
});
```

## Namespace

```csharp
using Microsoft.Accordant;
```

## NuGet Package

```bash
dotnet add package Microsoft.Accordant
```

More from microsoft/accordant

SkillDescription
accordant-async-operationsHow to model background work, step functions, and polling - use this skill when testing async workflows, job queues, or operations that complete in the background
accordant-concurrencyHow to test for race conditions using concurrent tests and linearizability - use this skill when testing concurrent operations or finding race condition bugs
accordant-cross-languageTesting systems not written in .NET - trace-based conformance testing, JSON test plan export, and executing from any language. Use when the user's system is in Python, Go, Java, Rust, C++, or any non-.NET language, or when they ask about trace validation or exporting test cases.
accordant-operationsHow to define operations with Apply and Execute methods - use this skill when creating spec operations or understanding the Apply/Execute pattern
accordant-overviewWhat Accordant is, when to use model-based testing, and core concepts - use this skill when starting with Accordant or explaining its purpose
accordant-patternsCommon patterns in Accordant - response-dependent state, request derivations, error handling, and HTTP integration
accordant-stateHow to design state models in Accordant - use this skill when defining what your system tracks between operations
accordant-test-generationHow Accordant generates and runs tests - use this skill when configuring test generation, understanding state graphs, or running tests
accordant-troubleshootingCommon mistakes and debugging tips for Accordant specs - use this skill when tests fail unexpectedly or specs don't behave as expected