YAML Source is the Network Storage authoring standard.
Use the s&box Library Manager install for auto-updates. GitHub is best for agents, source review, contributions, and manual installs.

Creating Endpoint Validation Fixtures

When endpoint validation fails in production, the error response now includes diagnostic context that can be used to create local regression tests.

# Creating Endpoint Validation Fixtures

When endpoint validation fails in production, the error response now includes diagnostic context that can be used to create local regression tests.

## Diagnostic Context Structure

When a random/weighted step fails to resolve its item source, the error includes:

```yml
error:
code: ENDPOINT_ERROR.RANDOM
message: "Random \"fish\": could not resolve item source (game values table \"fish_types\"\
\ not found. Available tables: [ore_types, loot_table])."
step:
id: fish
type: random
diagnostic:
projectId: 85ed638340264f44
endpointId: ep-123
endpointSlug: cast-fish
method: POST
stepId: fish
stepType: random
sourceReference:
type: values
table: fish_types
from: null
weightField: rarity
availableSources:
tables:
- ore_types
- loot_table
collections:
- players
- inventory
failureReason: "game values table \"fish_types\" not found. Available tables:\
\ [ore_types, loot_table]"
missing: table
resolvedTo: null
fixture:
_fixtureComment: Auto-generated from validation failure. Replace <redacted>
values with test data.
projectId: test_project
endpoint:
slug: cast-fish
method: POST
failingStep:
id: fish
type: random
source: values
table: fish_types
weightField: rarity
availableTables:
- ore_types
- loot_table
gameValuesFixture:
fish_types:
- id: example_row
rarity: 100
expectedOutcome: pass after adding missing table/source
```

## Creating a Local Regression Test

### Step 1: Copy the Diagnostic Context

From a production error log or admin validation report, copy the `diagnostic` and `fixture` objects from the error response.

### Step 2: Create a Test File

Add a new test case in `tests/endpoint-runner.test.js`:

```javascript
test("REGRESSION: cast-fish missing fish_types table", async () => {
// Endpoint definition matching production config
const endpoint = {
slug: "cast-fish",
method: "POST",
steps: [
{
id: "fish",
type: "random",
mode: "weighted",
source: "values",
table: "fish_types", // The table that was missing
weightField: "rarity",
},
],
response: { status: 200, body: { caught: "{{fish.name}}" } },
};

// Reproduce the failure: no fish_types table
const failResult = await executeEndpoint(endpoint, dryCtx({
gameValues: {
ore_types: [{ id: "gold", weight: 10 }], // Available tables from diagnostic
loot_table: [{ id: "sword", weight: 50 }],
},
}));

expect(failResult.ok).toBe(false);
expect(failResult.body.error.step.diagnostic.sourceReference.table).toBe("fish_types");
expect(failResult.body.error.step.diagnostic.availableSources.tables).toContain("ore_types");

// Verify the fix: add the missing table
const passResult = await executeEndpoint(endpoint, dryCtx({
gameValues: {
fish_types: [
{ name: "Bass", rarity: 50 },
{ name: "Salmon", rarity: 30 },
],
},
}));

expect(passResult.ok).toBe(true);
});
```

### Step 3: Use the Fixture Hint

The `fixture.gameValuesFixture` object shows the minimum data structure needed to make the step pass:

```javascript
// From fixture.gameValuesFixture
gameValues: {
fish_types: [{ id: "example_row", rarity: 100 }]
}
```

## Common Failure Patterns

### Missing Table

**Error**: `game values table "X" not found`

**Diagnostic fields**:
- `sourceReference.type`: "values"
- `sourceReference.table`: the table that was requested
- `availableSources.tables`: tables that do exist

**Fix**: Add the missing table to game values, or correct the table name if it's a typo.

### Missing From Step

**Error**: `from "{{X}}" resolved to null/undefined`

**Diagnostic fields**:
- `sourceReference.type`: "from"
- `sourceReference.fromRef`: the step reference that failed
- `resolvedTo`: what the reference resolved to

**Fix**: Ensure the referenced step exists and returns an array.

### Empty Items Array

**Error**: `inline items resolved to an empty array`

**Diagnostic fields**:
- `sourceReference.type`: "inline"
- `missing`: "items"

**Fix**: Add at least one item to the items array.

## Static Validation Diagnostics

The `validateEndpointStatic` function also returns structured diagnostics:

```javascript
const { warnings, diagnostics } = validateEndpointStatic(endpoint, gameValues, collections);

for (const diag of diagnostics) {
console.log(`Step ${diag.stepId}: ${diag.issueType}`);
console.log(` Available tables: ${diag.availableTables.join(", ")}`);
console.log(` Fix hint: ${diag.fixtureHint}`);
}
```

## Sanitization

Diagnostic context is sanitized before being returned:
- No API keys, auth tokens, or secrets
- No raw player data or large payloads
- Collection names only (no schema details)
- Where clause values are redacted if over 100 characters