npm package: @inariwatch/substrate-agent
Description: Record and replay Node.js I/O — the execution layer for autonomous software
Author: Jesus Bernal
Latest version: 0.1.0

# @inariwatch/substrate-agent

Record and replay Node.js I/O for deterministic debugging and AI-powered fix verification.

Substrate captures every external interaction your app makes — HTTP requests, database queries, file reads, randomness, DNS lookups — and can replay them deterministically against new code to verify fixes before deployment.

## Install

```bash
npm install @inariwatch/substrate-agent
```

## Quick Start

### SDK Mode (recommended)

Import and initialize in your app's entry point:

```typescript
import { init, flush } from "@inariwatch/substrate-agent";

init({
  bufferSeconds: 60,  // Keep last 60 seconds of events
  dsn: process.env.INARIWATCH_DSN,  // Optional: auto-upload on exceptions
});
```

Flush the recording buffer on demand:

```typescript
// Get the recording object
const recording = flush();

// Or upload directly to InariWatch
await flush("https://app.inariwatch.com/api/recordings/upload");
```

### With @inariwatch/capture

If you're already using `@inariwatch/capture`, enable Substrate with one flag:

```typescript
import { init } from "@inariwatch/capture";

init({
  dsn: "your-dsn",
  substrate: true,  // Enables I/O recording
});
```

Or via environment variable:

```bash
INARIWATCH_SUBSTRATE=true node app.js
```

## What Gets Recorded

| Category | APIs Patched | Events |
|---|---|---|
| **HTTP** | `http.request`, `https.request`, `fetch` | Request URL, method, status, response body, duration |
| **Database** | `pg` (PostgreSQL), `mysql2`, `ioredis` | Query text, row count, duration, errors |
| **Time** | `Date.now` | Timestamp values |
| **Randomness** | `Math.random`, `crypto.randomBytes` | Generated values |
| **DNS** | `dns.lookup` | Hostname, resolved addresses |
| **File I/O** | `fs.readFile`, `fs.writeFile` | Path, content, errors |
| **Exceptions** | `uncaughtException`, `unhandledRejection` | Error name, message, stack trace |

## Deterministic Replay

Substrate can replay recorded I/O against modified code to detect behavioral changes:

```bash
# Record a session
SUBSTRATE_RECORDER_PORT=9302 node --require @inariwatch/substrate-agent app.js

# Replay against new code
SUBSTRATE_REPLAY_FILE=recording.json node --require @inariwatch/substrate-agent/replay app.js
```

During replay:
- HTTP requests return recorded responses (no network calls)
- Database queries return recorded results (no DB connection)
- `Date.now()` and `Math.random()` return recorded values
- File reads return recorded content
- File writes become no-ops
- **Divergences** (extra HTTP calls, different queries) are detected and reported

## Privacy & Redaction

Substrate redacts sensitive data by default:

```typescript
init({
  redact: {
    headers: ["authorization", "cookie", "x-api-key"],
    body_urls: ["/api/auth/*", "/api/tokens/*"],
    query_patterns: ["password", "secret", "token"],
  },
});
```

## API

### `init(config?)`

Initialize Substrate instrumentation. Call once at app startup.

| Option | Type | Default | Description |
|---|---|---|---|
| `bufferSeconds` | `number` | `60` | Ring buffer duration (0 = unlimited) |
| `redact` | `object` | Default rules | Redaction configuration |
| `dsn` | `string` | — | InariWatch DSN for auto-notification on exceptions |

### `flush(dsn?)`

Flush the event buffer and return a Recording object. If `dsn` is provided, uploads the recording to InariWatch.

### `getBuffer()`

Get the current event buffer without clearing it. Returns `{ events, count }`.

## How InariWatch Uses Substrate

When InariWatch's AI remediation pipeline generates a fix:

1. **Shadow Replay** — replays your production recording against the fix code
2. **Divergence Detection** — identifies behavioral changes (new HTTP calls, different DB queries)
3. **Risk Scoring** — assigns a risk score based on divergence severity
4. **Safety Gate** — blocks auto-merge if replay risk exceeds threshold

This gives you confidence that the AI's fix doesn't change your app's behavior in unexpected ways.

## License

MIT