Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions kits/webhook-reliability-architect/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
WEBHOOK_RELIABILITY_ARCHITECT_FLOW_ID=your_deployed_flow_id
LAMATIC_API_URL=https://your-project-endpoint.example.com
LAMATIC_PROJECT_ID=your_project_id
LAMATIC_API_KEY=your_api_key
6 changes: 6 additions & 0 deletions kits/webhook-reliability-architect/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.env
.env.local
node_modules/
.next/
dist/
*.log
119 changes: 119 additions & 0 deletions kits/webhook-reliability-architect/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Webhook Reliability Architect

Webhook Reliability Architect turns a webhook delivery contract into a concrete engineering brief: an idempotency key design, bounded retry schedule, dead-letter and replay procedure, observability SLO, failure-mode analysis, and failure-injection test matrix.

It is designed for backend engineers reviewing webhooks that trigger real side effects such as payments, inventory updates, entitlements, or notifications.

## Problem

Webhook failures are deceptive. A receiver can commit the business mutation and still lose the acknowledgement. The sender then retries a request that appears failed even though the side effect already happened. Fixed-interval retries, unbounded queues, and informal replay procedures can multiply the damage.

Teams need a repeatable way to answer:

- What uniquely identifies one business event?
- How is the receipt stored atomically with the side effect?
- Which failures are retryable, and for how long?
- What moves to quarantine instead of retrying forever?
- How can an operator replay safely?
- Which metrics and failure tests prove the design?

## Why this contribution is distinct

The AgentKit registry already includes API review, incident analysis, generic debugging, and data-quality tools. This kit focuses specifically on **delivery semantics and side-effect safety**. It does not review source code or summarize an incident. It converts one webhook scenario into an operational contract that can be tested before production rollout.

## What it produces

- Risk score and concise executive summary
- Idempotency key, payload-hash conflict policy, storage model, and retention window
- Exponential backoff schedule with full jitter and delivery-age budget
- Retryable and non-retryable response classification
- Dead-letter record and operator replay checklist
- Delivery SLO, metrics, alert conditions, and structured log fields
- Failure-mode table and five failure-injection tests
- Staged rollout plan

## Architecture

```text
Next.js form
Server Action ── DEMO_MODE=true ──► deterministic local report
└── live mode ──► Lamatic flow ──► structured reliability report
```

The Next.js application keeps Lamatic credentials on the server. In live mode it calls the deployed `webhook-reliability-architect` flow through the Lamatic SDK. Demo mode creates a deterministic report from the supplied scenario so reviewers can evaluate the interface without credentials.

## Inputs

The web interface collects the fields below and sends them to Lamatic as one JSON-encoded `scenario` string. Keeping a single flow input makes the contract easy to version while the application continues to validate every field before transmission.

| Field | Purpose |
|---|---|
| System name | Human-readable workflow name |
| Event type | Stable event contract name, such as `payment.succeeded` |
| Business effect | Read-only, reversible write, notification, inventory, or financial |
| Delivery semantics | At-least-once, at-most-once, best effort, or unknown |
| Ordering required | Whether an older event may overwrite newer aggregate state |
| Max attempts / timeout / delivery age | Bounds for the proposed retry plan |
| Existing safeguards | Current signature, retry, deduplication, queue, and logging controls |
| Sample payload | Sanitized example used to identify event-key candidates |
| Failure context | Known incident or design concern |

Do not submit credentials, secrets, personal data, or production payloads.

## Run the app locally

```bash
cd kits/webhook-reliability-architect/apps
npm install
cp .env.example .env.local
npm run dev
```

The example environment enables `DEMO_MODE=true`. Open `http://localhost:3000`, load the included payment-event scenario, and generate a report.

## Connect a deployed Lamatic flow

1. Import or recreate `flows/webhook-reliability-architect.ts` in Lamatic Studio.
2. Select a supported structured-output model and deploy the flow.
3. Set `DEMO_MODE=false` in `apps/.env.local`.
4. Add:

```bash
WEBHOOK_RELIABILITY_ARCHITECT_FLOW_ID=your_deployed_flow_id
LAMATIC_API_URL=https://your-project-endpoint.example.com
LAMATIC_PROJECT_ID=your_project_id
LAMATIC_API_KEY=your_api_key
```

5. Restart the app and verify that the report header says **Live flow**.

## Safety boundaries

- This kit produces architecture guidance; it never changes queues, databases, retry settings, or production traffic.
- It does not guarantee exactly-once delivery. It recommends idempotent processing that contains duplicate delivery.
- A human engineer must validate retention, privacy, capacity, compliance, and transaction-boundary assumptions.
- Dead-letter replay is always operator-controlled and must reuse the original idempotency key.
- Raw secrets and personal data must not be included in prompts, payload examples, logs, or reports.

## Validation

From `apps/`:

```bash
npm run typecheck
npm run build
```

Before contribution, also verify:

- The Lamatic flow imports and runs in Studio.
- The live response matches the structured report contract.
- Demo and live modes render the same report shape.
- Only `kits/webhook-reliability-architect/` is changed in the PR.

## Author

Built by [Amar Kumar](https://github.com/amarkumar00) for the Lamatic AgentKit Challenge.
76 changes: 76 additions & 0 deletions kits/webhook-reliability-architect/agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Webhook Reliability Architect — Agent Guide

## Overview

Webhook Reliability Architect is a design-review agent for webhook systems that can trigger business side effects. It converts a sanitized delivery scenario into a structured reliability report covering idempotency, retries, dead-letter handling, observability, failure modes, failure injection, and staged rollout.

## Purpose

Distributed delivery is usually at least once: timeouts and lost acknowledgements make redelivery normal. The agent helps engineers replace informal retry logic with an explicit contract that prevents a duplicate request from becoming a duplicate business mutation.

The goal is not to claim exactly-once transport. The goal is to make duplicate delivery safe, bound recovery work, and define evidence that the system behaves as designed.

## Flow

### `webhook-reliability-architect`

- **Trigger:** Lamatic API Request node.
- **Inputs:** one JSON-encoded `scenario` string containing the system name, event type, business effect, delivery semantics, ordering requirement, retry bounds, current safeguards, sanitized payload, and failure context.
- **Processing:** A structured-output model evaluates duplicate-delivery risk and produces one report under a fixed schema.
- **Response:** Lamatic API Response node returns the report as `analysis`.
- **Use when:** Reviewing a new webhook, preparing a reliability hardening sprint, or converting an incident lesson into a testable design.
- **Do not use when:** The caller expects code deployment, queue mutation, production replay, security certification, or a guarantee of exactly-once delivery.

## Required output

The report must include:

1. Executive summary, risk score, and risk level.
2. Explicit assumptions.
3. Idempotency key strategy and conflict behavior.
4. Bounded retry policy and attempt schedule.
5. Dead-letter record and safe replay checklist.
6. Delivery SLO, metrics, alerts, and log fields.
7. Failure modes with impact, signals, and mitigations.
8. Failure-injection tests with expected evidence.
9. Staged rollout steps.

## Guardrails

- Never ask for or expose API keys, signing secrets, customer data, payment credentials, or unredacted production payloads.
- Never recommend retrying invalid signatures, authorization failures, schema violations, or deterministic business-rule failures.
- Never claim exactly-once delivery. Prefer idempotent effects, atomic state transitions, or an inbox/outbox pattern.
- Never invent provider behavior. State assumptions when sender guarantees are missing.
- Never recommend blind bulk replay. Reuse original event identities and start with a canary.
- Separate transport acceptance from business completion where asynchronous processing is proposed.
- Treat financial, inventory, and entitlement mutations as high consequence.

## Integration reference

| Component | Purpose | Configuration |
|---|---|---|
| Lamatic API Request | Receives the scenario | Deployed flow endpoint |
| Structured-output model | Creates the report | Model selected in Lamatic Studio |
| Lamatic API Response | Returns `analysis` | Output mapping in the flow |
| Next.js app | Collects input and renders the report | Server-side Lamatic SDK |

## Environment setup

| Variable | Purpose |
|---|---|
| `WEBHOOK_RELIABILITY_ARCHITECT_FLOW_ID` | Deployed Lamatic flow ID |
| `LAMATIC_API_URL` | Lamatic project endpoint |
| `LAMATIC_PROJECT_ID` | Lamatic project identifier |
| `LAMATIC_API_KEY` | Server-side API key; never expose to the browser |
| `DEMO_MODE` | Uses the deterministic local report when `true` |

## Common failure modes

| Symptom | Likely cause | Fix |
|---|---|---|
| App says the flow ID is missing | Live mode is enabled without `WEBHOOK_RELIABILITY_ARCHITECT_FLOW_ID` | Add the deployed flow ID or enable demo mode |
| Lamatic returns an unexpected shape | Flow response mapping or structured schema drifted | Verify the response field is `analysis` and matches the documented object |
| Report proposes an unstable key | Payload has no provider event ID | Require a stable event ID or derive a signed canonical hash with an explicit namespace |
| Retry schedule exceeds business value | Delivery-age input is too large | Set a realistic age budget and move expired events to quarantine |
| Duplicate still repeats a side effect | Receipt and mutation are not atomic | Use the same transaction or a durable state machine before acknowledging |
| Replay creates new duplicates | Operator minted a new idempotency key | Replay using the original identity and inspect the existing receipt first |
7 changes: 7 additions & 0 deletions kits/webhook-reliability-architect/apps/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Set to true to explore a deterministic sample report without Lamatic credentials.
DEMO_MODE=true

WEBHOOK_RELIABILITY_ARCHITECT_FLOW_ID=your_deployed_flow_id
LAMATIC_API_URL=https://your-project-endpoint.example.com
LAMATIC_PROJECT_ID=your_project_id
LAMATIC_API_KEY=your_api_key
6 changes: 6 additions & 0 deletions kits/webhook-reliability-architect/apps/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.env
.env.local
.next/
node_modules/
*.log
*.tsbuildinfo
9 changes: 9 additions & 0 deletions kits/webhook-reliability-architect/apps/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!-- BEGIN:nextjs-agent-rules -->

# This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.

This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.

<!-- END:nextjs-agent-rules -->
1 change: 1 addition & 0 deletions kits/webhook-reliability-architect/apps/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
101 changes: 101 additions & 0 deletions kits/webhook-reliability-architect/apps/actions/orchestrate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"use server";

import lamaticConfig from "../../lamatic.config";
import { buildDemoReport } from "@/lib/demo";
import { getLamaticClient } from "@/lib/lamatic-client";
import type { AnalysisResult, ReliabilityReport, WebhookScenario } from "@/lib/types";

const FLOW_ENV_KEY =
lamaticConfig.steps[0]?.envKey ?? "WEBHOOK_RELIABILITY_ARCHITECT_FLOW_ID";

function validateScenario(scenario: WebhookScenario): string | null {
if (!scenario.systemName.trim()) return "System name is required.";
if (!scenario.eventType.trim()) return "Event type is required.";
if (scenario.maxAttempts < 1 || scenario.maxAttempts > 12) {
return "Max attempts must be between 1 and 12.";
}
if (scenario.timeoutSeconds < 1 || scenario.timeoutSeconds > 300) {
return "Timeout must be between 1 and 300 seconds.";
}
if (scenario.maxDeliveryAgeMinutes < 1 || scenario.maxDeliveryAgeMinutes > 10_080) {
return "Delivery age must be between 1 minute and 7 days.";
}
if (scenario.samplePayload.length > 20_000) return "Sample payload is too large.";
if (scenario.currentSafeguards.length > 8_000) return "Safeguard notes are too large.";
if (scenario.failureContext.length > 8_000) return "Failure context is too large.";
return null;
}

function isReliabilityReport(value: unknown): value is ReliabilityReport {
if (!value || typeof value !== "object") return false;
const candidate = value as Partial<ReliabilityReport>;
return (
typeof candidate.executiveSummary === "string" &&
typeof candidate.riskScore === "number" &&
typeof candidate.riskLevel === "string" &&
Boolean(candidate.idempotencyPlan) &&
Boolean(candidate.retryPlan) &&
Array.isArray(candidate.failureModes) &&
Array.isArray(candidate.testMatrix)
);
}

function parseReport(response: unknown): ReliabilityReport | null {
const envelope = response as {
result?: { analysis?: unknown; report?: unknown };
analysis?: unknown;
report?: unknown;
};
const raw =
envelope?.result?.analysis ??
envelope?.result?.report ??
envelope?.analysis ??
envelope?.report;

if (isReliabilityReport(raw)) return raw;
if (typeof raw !== "string") return null;

try {
const parsed = JSON.parse(raw) as unknown;
return isReliabilityReport(parsed) ? parsed : null;
} catch {
return null;
}
}

export async function analyzeWebhookScenario(
scenario: WebhookScenario,
): Promise<AnalysisResult> {
const validationError = validateScenario(scenario);
if (validationError) return { success: false, error: validationError };

if (process.env.DEMO_MODE === "true") {
return { success: true, report: buildDemoReport(scenario), mode: "demo" };
}

const flowId = process.env[FLOW_ENV_KEY];
if (!flowId) {
return {
success: false,
error: `${FLOW_ENV_KEY} is not configured. Set it in apps/.env.local or enable DEMO_MODE.`,
};
}

try {
const client = getLamaticClient();
const response = await client.executeFlow(flowId, {
scenario: JSON.stringify(scenario),
});
const report = parseReport(response);
if (!report) {
return {
success: false,
error: "Lamatic returned an unexpected response shape. Verify the deployed flow output schema.",
};
}
return { success: true, report, mode: "live" };
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown Lamatic error.";
return { success: false, error: message };
}
}
Loading
Loading