hunksPerFile int Exact number of hunks per modified or renamed file. Added and deleted files always have exactly one whole-file hunk; mode-only and binary changes have none.
Unified diff fixtures whose hunk headers actually reconcile — correct @@ line counts, shared context lines, and rename, mode and binary forms.
Generated test data for fixtures and development
Each record is one changed file: its paths and modes, the summed insertions/deletions, the structured hunks, and the rendered patch derived from them.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
hunksPerFile | int | default: 2 allowed: 1 – 6 example: 3 | Exact number of hunks per modified or renamed file. Added and deleted files always have exactly one whole-file hunk; mode-only and binary changes have none. |
contextLines | int | default: 3 allowed: 0 – 5 example: 0 | Unchanged context lines on each side of every change group, like `git diff -U<n>`. 0 reproduces `-U0` output, where hunks contain only changed lines and empty ranges appear as `-12,0`. |
changeType | enum | default: mixed allowed: mixed | modify | add | delete | rename | mode | binary example: rename | Change type to emit. Any value other than 'mixed' is a hard guarantee — every file in the response has that exact type. 'mixed' weights modifications highest. |
language | enum | allowed: javascript | typescript | python | go | ruby | java | json | markdown example: typescript | Drives plausible file paths, extensions and line content. Omit to vary the language per file. Binary files keep asset paths (.png, .zip…) and carry no line content, so `changeType=binary` ignores this parameter entirely and warns when it is set. |
from | date | example: 2026-01-01 | Earliest change date, inclusive. YYYY-MM-DD (= midnight UTC) or a full ISO 8601 timestamp. Defaults to 90 days before today (UTC). |
to | date | example: 2026-03-31 | Latest change date, inclusive. Must be ≥ `from`. Defaults to today at UTC midnight; the resolved window is echoed in `meta.params`. |
hunksPerFile int Exact number of hunks per modified or renamed file. Added and deleted files always have exactly one whole-file hunk; mode-only and binary changes have none.
contextLines int Unchanged context lines on each side of every change group, like `git diff -U<n>`. 0 reproduces `-U0` output, where hunks contain only changed lines and empty ranges appear as `-12,0`.
changeType enum Change type to emit. Any value other than 'mixed' is a hard guarantee — every file in the response has that exact type. 'mixed' weights modifications highest.
language enum Drives plausible file paths, extensions and line content. Omit to vary the language per file. Binary files keep asset paths (.png, .zip…) and carry no line content, so `changeType=binary` ignores this parameter entirely and warns when it is set.
from date Earliest change date, inclusive. YYYY-MM-DD (= midnight UTC) or a full ISO 8601 timestamp. Defaults to 90 days before today (UTC).
to date Latest change date, inclusive. Must be ≥ `from`. Defaults to today at UTC midnight; the resolved window is echoed in `meta.params`.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
count | int | default: 10 allowed: 1 – 100 example: 3 | How many records to generate (1–100). |
seed | int | example: 42 | Deterministic output: the same seed always returns the same records. Omit for random (the used seed is echoed in meta.seed). |
fields | list | example: path,oldPath | Return only these fields (comma-separated). Mutually exclusive with 'exclude'. |
exclude | list | example: patch | Return all fields except these (comma-separated). |
format | enum | default: json allowed: json | ndjson | csv example: csv | Response format: json envelope, ndjson (one record per line) or csv. |
pretty | boolean | default: false example: true | Pretty-print the JSON response. |
unwrap | boolean | default: false example: true | Drop the envelope: return the raw array/object without data/meta wrapper. |
count int How many records to generate (1–100).
seed int Deterministic output: the same seed always returns the same records. Omit for random (the used seed is echoed in meta.seed).
fields list Return only these fields (comma-separated). Mutually exclusive with 'exclude'.
exclude list Return all fields except these (comma-separated).
format enum Response format: json envelope, ndjson (one record per line) or csv.
pretty boolean Pretty-print the JSON response.
unwrap boolean Drop the envelope: return the raw array/object without data/meta wrapper.
| Field | Type | Description | Example |
|---|---|---|---|
path | string | Post-image path (the `b/` side). For a deletion this is the path that was removed. | src/lib/cache.js |
oldPath nullable | string | Pre-image path (the `a/` side); `null` for an added file. Differs from `path` only for a rename. | src/lib/cache.js |
changeType | string | modify | add | delete | rename | mode | binary. | modify |
oldMode nullable | string | Six-digit octal pre-image mode (100644 regular, 100755 executable); `null` for an added file. | 100644 |
newMode nullable | string | Six-digit octal post-image mode; `null` for a deleted file. Differs from `oldMode` only for a mode change. | 100644 |
insertions | integer | Added lines, summed from the hunks. Always 0 for mode-only and binary changes. | 2 |
deletions | integer | Removed lines, summed from the hunks. Always 0 for mode-only and binary changes. | 1 |
date | string (ISO 8601) | Authoring date in UTC, uniformly random within [`from`, `to`] — whole seconds, like real git timestamps, dropping to millisecond precision only when the window is narrower than one second and holds no whole-second instant. Metadata only: git's own patch output carries no timestamps, so this is not part of `patch`. | 2026-03-14T09:26:53Z |
hunks | object[] | Structured hunks: `header`, `oldStart`, `oldLines`, `newStart`, `newLines` and `lines` (each `{ type: context|add|remove, text }`, plus `noNewline: true` on a line whose file version has no trailing newline). `oldLines` always equals the context+removed line count and `newLines` the context+added count. Empty for mode-only and binary changes. | [{"header":"@@ -12,2 +12,3 @@","oldStart":12,"oldLines":2,"newStart":12,"newLines":3,"lines":[{"type":"context","text":" const cache = new Map();"},{"type":"remove","text":" return cache.get(key);"},{"type":"add","text":" const hit = cache.get(key);"},{"type":"add","text":" return hit ?? null;"}]}] |
patch | string | The complete git-style patch for this file, rendered from `hunks` (never authored separately) and terminated with a newline. | diff --git a/src/lib/cache.js b/src/lib/cache.js index 4b1e2c7..9af0d31 100644 --- a/src/lib/cache.js +++ b/src/lib/cache.js @@ -12,2 +12,3 @@ const cache = new Map(); - return cache.get(key); + const hit = cache.get(key); + return hit ?? null; |
path string Post-image path (the `b/` side). For a deletion this is the path that was removed.
example: src/lib/cache.js
oldPath string nullable Pre-image path (the `a/` side); `null` for an added file. Differs from `path` only for a rename.
example: src/lib/cache.js
changeType string modify | add | delete | rename | mode | binary.
example: modify
oldMode string nullable Six-digit octal pre-image mode (100644 regular, 100755 executable); `null` for an added file.
example: 100644
newMode string nullable Six-digit octal post-image mode; `null` for a deleted file. Differs from `oldMode` only for a mode change.
example: 100644
insertions integer Added lines, summed from the hunks. Always 0 for mode-only and binary changes.
example: 2
deletions integer Removed lines, summed from the hunks. Always 0 for mode-only and binary changes.
example: 1
date string (ISO 8601) Authoring date in UTC, uniformly random within [`from`, `to`] — whole seconds, like real git timestamps, dropping to millisecond precision only when the window is narrower than one second and holds no whole-second instant. Metadata only: git's own patch output carries no timestamps, so this is not part of `patch`.
example: 2026-03-14T09:26:53Z
hunks object[] Structured hunks: `header`, `oldStart`, `oldLines`, `newStart`, `newLines` and `lines` (each `{ type: context|add|remove, text }`, plus `noNewline: true` on a line whose file version has no trailing newline). `oldLines` always equals the context+removed line count and `newLines` the context+added count. Empty for mode-only and binary changes.
example: [{"header":"@@ -12,2 +12,3 @@","oldStart":12,"oldLines":2,"newStart":12,"newLines":3,"lines":[{"type":"context","text":" const cache = new Map();"},{"type":"remove","text":" return cache.get(key);"},{"type":"add","text":" const hit = cache.get(key);"},{"type":"add","text":" return hit ?? null;"}]}]
patch string The complete git-style patch for this file, rendered from `hunks` (never authored separately) and terminated with a newline.
example: diff --git a/src/lib/cache.js b/src/lib/cache.js index 4b1e2c7..9af0d31 100644 --- a/src/lib/cache.js +++ b/src/lib/cache.js @@ -12,2 +12,3 @@ const cache = new Map(); - return cache.get(key); + const hit = cache.get(key); + return hit ?? null;
/api/diffs {
"data": [
{
"path": "src/test/java/com/example/app/UserClient.java",
"oldPath": "src/test/java/com/example/app/UserClient.java",
"changeType": "modify",
"oldMode": "100644",
"newMode": "100644",
"insertions": 3,
"deletions": 2,
"date": "2026-07-16T12:30:10Z",
"hunks": [
{
"header": "@@ -12,6 +12,7 @@",
"oldStart": 12,
"oldLines": 6,
"newStart": 12,
"newLines": 7,
"lines": [
{
"type": "context",
"text": "package com.example.app;"
},
{
"type": "context",
"text": ""
},
{
"type": "context",
"text": "import java.util.List;"
},
{
"type": "add",
"text": "import java.util.Objects;"
},
{
"type": "context",
"text": "import java.util.Optional;"
},
{
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/diffs?seed=42&changeType=modify&language=typescript&count=5 {
"data": [
{
"path": "src/api/router-service.ts",
"oldPath": "src/api/router-service.ts",
"changeType": "modify",
"oldMode": "100755",
"newMode": "100755",
"insertions": 3,
"deletions": 0,
"date": "2026-07-11T23:58:46Z",
"hunks": [
{
"header": "@@ -14,6 +14,7 @@",
"oldStart": 14,
"oldLines": 6,
"newStart": 14,
"newLines": 7,
"lines": [
{
"type": "context",
"text": "import { z } from 'zod';"
},
{
"type": "context",
"text": ""
},
{
"type": "context",
"text": "export interface ClientOptions {"
},
{
"type": "add",
"text": " const cached = cache.get(url.href);"
},
{
"type": "context",
"text": " readonly baseUrl: string;"
},
{
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/diffs?contextLines=0&hunksPerFile=3&count=4&seed=7 {
"data": [
{
"path": "test/fixtures/settings.json",
"oldPath": null,
"changeType": "add",
"oldMode": null,
"newMode": "100644",
"insertions": 5,
"deletions": 0,
"date": "2026-06-05T17:46:03Z",
"hunks": [
{
"header": "@@ -0,0 +1,5 @@",
"oldStart": 0,
"oldLines": 0,
"newStart": 1,
"newLines": 5,
"lines": [
{
"type": "add",
"text": " \"dependencies\": {"
},
{
"type": "add",
"text": " \"zod\": \"^3.23.8\""
},
{
"type": "add",
"text": " },"
},
{
"type": "add",
"text": " \"devDependencies\": {"
},
{
"type": "add",
"text": " \"typescript\": \"^5.5.4\","
}
]
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/diffs?changeType=rename&count=3&seed=11 {
"data": [
{
"path": "src/components/parser.js",
"oldPath": "lib/queue-worker.js",
"changeType": "rename",
"oldMode": "100644",
"newMode": "100644",
"insertions": 3,
"deletions": 2,
"date": "2026-07-15T20:47:58Z",
"hunks": [
{
"header": "@@ -17,8 +17,7 @@",
"oldStart": 17,
"oldLines": 8,
"newStart": 17,
"newLines": 7,
"lines": [
{
"type": "context",
"text": "module.exports = { createClient };"
},
{
"type": "context",
"text": "'use strict';"
},
{
"type": "context",
"text": ""
},
{
"type": "remove",
"text": "const { readFile } = require('fs/promises');"
},
{
"type": "remove",
"text": "const { URL } = require('url');"
},
{
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/diffs?fields=patch&format=ndjson&count=5 {"patch":"diff --git a/src/test/java/com/example/app/UserClient.java b/src/test/java/com/example/app/UserClient.java\nindex 8ea741c..cd24a06 100644\n--- a/src/test/java/com/example/app/UserClient.java\n+++ b/src/test/java/com/example/app/UserClient.java\n@@ -12,6 +12,7 @@\n package com.example.app;\n \n import java.util.List;\n+import java.util.Objects;\n import java.util.Optional;\n \n public final class OrderService {\n@@ -25,8 +26,8 @@\n public Optional<Order> findById(long id) {\n return repository.findById(id);\n }\n-\n- public long total(List<Item> items) {\n+ if (items.isEmpty()) {\n+ return 0L;\n long total = 0;\n for (Item item : items) {\n total += item.quantity() * item.price();\n"}
{"patch":"diff --git a/lib/client-store.js b/lib/client-store.js\nindex f70c9b4..93a911a 100644\n--- a/lib/client-store.js\n+++ b/lib/client-store.js\n@@ -16,6 +16,8 @@\n \n const { readFile } = require('fs/promises');\n const { URL } = require('url');\n+ attempt += 1;\n+ const cached = cache.get(url.href);\n \n const DEFAULT_TIMEOUT = 5000;\n const cache = new Map();\n@@ -28,5 +30,5 @@\n const url = new URL(path, baseUrl);\n const response = await fetch(url, { timeout });\n if (!response.ok) {\n- throw new Error('request failed');\n- }\n\\ No newline at end of file\n+ cache.set(url.href, payload);\n+ function clear() { cache.clear(); }\n\\ No newline at end of file\n"}
{"patch":"diff --git a/src/client.js b/src/components/cache.js\nsimilarity index 56%\nrename from src/client.js\nrename to src/components/cache.js\nindex b436a5c..931543d 100755\n--- a/src/client.js\n+++ b/src/components/cache.js\n@@ -11,7 +11,8 @@\n return response.json();\n }\n \n- return { request };\n+ cache.set(url.href, payload);\n+ function clear() { cache.clear(); }\n }\n \n module.exports = { createClient };\n@@ -26,6 +27,8 @@\n function createClient(options = {}) {\n const timeout = options.timeout ?? DEFAULT_TIMEOUT;\n const baseUrl = options.baseUrl;\n+ attempt += 1;\n+ const cached = cache.get(url.href);\n \n async function request(path) {\n const url = new URL(path, baseUrl);\n"}
{"patch":"diff --git a/app/jobs/report.rb b/app/jobs/report.rb\nindex 68ff2bd..99f958d 100644\n--- a/app/jobs/report.rb\n+++ b/app/jobs/report.rb\n@@ -17,11 +17,7 @@\n JSON.parse(response.body)\n end\n \n- private\n-\n def get(path)\n- Net::HTTP.get_response(URI(@base_url + path))\n- end\n end\n end\n # frozen_string_literal: true\n@@ -34,8 +30,7 @@\n def initialize(base_url:, timeout: 5)\n @base_url = base_url\n @timeout = timeout\n- end\n-\n+ @retries = retries\n def fetch(path)\n raise ArgumentError, 'path' if path.nil?\n \n"}
{"patch":"diff --git a/src/test/java/com/example/app/SessionTest.java b/src/main/java/com/example/app/Report.java\nsimilarity index 68%\nrename from src/test/java/com/example/app/SessionTest.java\nrename to src/main/java/com/example/app/Report.java\nindex 12d9827..3ff0d8b 100644\n--- a/src/test/java/com/example/app/SessionTest.java\n+++ b/src/main/java/com/example/app/Report.java\n@@ -1,4 +1,5 @@\n this.repository = repository;\n+ @Override\n }\n \n public Optional<Order> findById(long id) {\n@@ -10,5 +11,4 @@\n for (Item item : items) {\n total += item.quantity() * item.price();\n }\n- return total;\n- }\n+ return 0L;\n\\ No newline at end of file\n"}
Returns a single patch string covering files files in ascending path order, plus a per-file summary whose insertions, deletions and hunk counts sum exactly to the totals.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
files | int | default: 3 allowed: 1 – 10 example: 5 | Number of files in the patch. Paths are unique within one patch and sorted ascending, like `git diff`. |
hunksPerFile | int | default: 2 allowed: 1 – 6 example: 3 | Exact number of hunks per modified or renamed file. Added and deleted files always have exactly one whole-file hunk; mode-only and binary changes have none. |
contextLines | int | default: 3 allowed: 0 – 5 example: 0 | Unchanged context lines on each side of every change group, like `git diff -U<n>`. 0 reproduces `-U0` output, where hunks contain only changed lines and empty ranges appear as `-12,0`. |
changeType | enum | default: mixed allowed: mixed | modify | add | delete | rename | mode | binary example: rename | Change type to emit. Any value other than 'mixed' is a hard guarantee — every file in the response has that exact type. 'mixed' weights modifications highest. |
language | enum | allowed: javascript | typescript | python | go | ruby | java | json | markdown example: typescript | Drives plausible file paths, extensions and line content. Omit to vary the language per file. Binary files keep asset paths (.png, .zip…) and carry no line content, so `changeType=binary` ignores this parameter entirely and warns when it is set. |
seed | int | default: 1 allowed: 0 – 4294967295 example: 99 | Determinism: the same seed and parameters always render the byte-identical patch. |
files int Number of files in the patch. Paths are unique within one patch and sorted ascending, like `git diff`.
hunksPerFile int Exact number of hunks per modified or renamed file. Added and deleted files always have exactly one whole-file hunk; mode-only and binary changes have none.
contextLines int Unchanged context lines on each side of every change group, like `git diff -U<n>`. 0 reproduces `-U0` output, where hunks contain only changed lines and empty ranges appear as `-12,0`.
changeType enum Change type to emit. Any value other than 'mixed' is a hard guarantee — every file in the response has that exact type. 'mixed' weights modifications highest.
language enum Drives plausible file paths, extensions and line content. Omit to vary the language per file. Binary files keep asset paths (.png, .zip…) and carry no line content, so `changeType=binary` ignores this parameter entirely and warns when it is set.
seed int Determinism: the same seed and parameters always render the byte-identical patch.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
fields | list | example: patch,files | Return only these fields (comma-separated). Mutually exclusive with 'exclude'. |
exclude | list | example: summary | Return all fields except these (comma-separated). |
pretty | boolean | default: false example: true | Pretty-print the JSON response. |
unwrap | boolean | default: false example: true | Drop the envelope: return the raw array/object without data/meta wrapper. |
fields list Return only these fields (comma-separated). Mutually exclusive with 'exclude'.
exclude list Return all fields except these (comma-separated).
pretty boolean Pretty-print the JSON response.
unwrap boolean Drop the envelope: return the raw array/object without data/meta wrapper.
| Field | Type | Description | Example |
|---|---|---|---|
patch | string | The complete multi-file unified patch, files concatenated in ascending path order and terminated with a newline. | diff --git a/src/lib/cache.js b/src/lib/cache.js index 4b1e2c7..9af0d31 100644 --- a/src/lib/cache.js +++ b/src/lib/cache.js @@ -12,2 +12,3 @@ const cache = new Map(); - return cache.get(key); + const hit = cache.get(key); + return hit ?? null; |
files | integer | Number of files in the patch. | 3 |
hunks | integer | Total hunk count across every file in the patch. | 4 |
insertions | integer | Total added lines — the sum of `summary[].insertions`. | 9 |
deletions | integer | Total removed lines — the sum of `summary[].deletions`. | 5 |
summary | object[] | Per-file entries in patch order: `path`, `oldPath`, `changeType`, `insertions`, `deletions` and `hunks`. | [{"path":"src/lib/cache.js","oldPath":"src/lib/cache.js","changeType":"modify","insertions":5,"deletions":3,"hunks":2},{"path":"src/lib/queue.js","oldPath":null,"changeType":"add","insertions":4,"deletions":0,"hunks":1}] |
patch string The complete multi-file unified patch, files concatenated in ascending path order and terminated with a newline.
example: diff --git a/src/lib/cache.js b/src/lib/cache.js index 4b1e2c7..9af0d31 100644 --- a/src/lib/cache.js +++ b/src/lib/cache.js @@ -12,2 +12,3 @@ const cache = new Map(); - return cache.get(key); + const hit = cache.get(key); + return hit ?? null;
files integer Number of files in the patch.
example: 3
hunks integer Total hunk count across every file in the patch.
example: 4
insertions integer Total added lines — the sum of `summary[].insertions`.
example: 9
deletions integer Total removed lines — the sum of `summary[].deletions`.
example: 5
summary object[] Per-file entries in patch order: `path`, `oldPath`, `changeType`, `insertions`, `deletions` and `hunks`.
example: [{"path":"src/lib/cache.js","oldPath":"src/lib/cache.js","changeType":"modify","insertions":5,"deletions":3,"hunks":2},{"path":"src/lib/queue.js","oldPath":null,"changeType":"add","insertions":4,"deletions":0,"hunks":1}]
/api/diffs/patch {
"data": {
"patch": "diff --git a/docs/reference/getting-started-overview.md b/docs/reference/getting-started-overview.md\nindex dce7d29..cb2c8e4 100644\n--- a/docs/reference/getting-started-overview.md\n+++ b/docs/reference/getting-started-overview.md\n@@ -4,8 +4,9 @@\n npm install @example/app\n ```\n \n+## Troubleshooting\n ## Configuration\n-\n+4. Restart the development server.\n - `baseUrl` — the API origin to call.\n - `timeoutMs` — request timeout in milliseconds.\n \n@@ -20,5 +21,5 @@\n \n A small client for the Example API.\n \n-## Installation\n-\n+> Warning: rotate tokens every 90 days.\n+```js\n\\ No newline at end of file\ndiff --git a/fixtures/package.json b/fixtures/package.json\nindex 93520ce..60ba424 100644\n--- a/fixtures/package.json\n+++ b/fixtures/package.json\n@@ -5,7 +5,8 @@\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n- \"build\": \"tsc --build\",\n+ \"license\": \"MIT\",\n+ \"description\": \"Example API client\",\n \"lint\": \"eslint .\",\n \"test\": \"vitest run\"\n },\n@@ -19,7 +20,7 @@\n }\n {\n \"name\": \"@example/app\",\n- \"version\": \"1.4.0\",\n+ \"description\": \"Example API client\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\ndiff --git a/internal/http/client-registry.go b/internal/http/client-registry.go\nindex b4f35e4..a6d44e5 100644\n--- a/internal/http/client-registry.go\n+++ b/internal/http/client-registry.go\n@@ -18,6 +18,8 @@\n \tif err != nil {\n \t\treturn fmt.Errorf(\"get: %w\", err)\n \t}\n+\tfor attempt := 0; attempt < c.retries; attempt++ {\n+\t\tif err == nil {\n \tdefer resp.Body.Close()\n \treturn nil\n }\n@@ -32,10 +34,8 @@\n type Client struct {\n \ttimeout time.Duration\n }\n-\n func NewClient(timeout time.Duration) *Client {\n-\treturn &Client{timeout: timeout}\n-}\n+\t\tif err == nil {\n \n func (c *Client) Get(ctx context.Context) error {\n \tctx, cancel := context.WithTimeout(ctx, c.timeout)\n",
"files": 3,
"hunks": 6,
"insertions": 10,
"deletions": 8,
"summary": [
{
"path": "docs/reference/getting-started-overview.md",
"oldPath": "docs/reference/getting-started-overview.md",
"changeType": "modify",
"insertions": 4,
"deletions": 3,
"hunks": 2
},
{
"path": "fixtures/package.json",
"oldPath": "fixtures/package.json",
"changeType": "modify",
"insertions": 3,
"deletions": 2,
"hunks": 2
},
{
"path": "internal/http/client-registry.go",
"oldPath": "internal/http/client-registry.go",
"changeType": "modify",
"insertions": 3,
"deletions": 3,
"hunks": 2
}
]
},
"meta": {
"endpoint": "diffs",
"route": "/patch",
"params": {
"files": 3,
"hunksPerFile": 2,
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/diffs/patch?files=10&language=go&seed=99 {
"data": {
"patch": "diff --git a/cmd/server/client-registry.go b/cmd/server/client-registry.go\ndeleted file mode 100644\nindex 841c87a..0000000\n--- a/cmd/server/client-registry.go\n+++ /dev/null\n@@ -1,8 +0,0 @@\n-func (c *Client) Get(ctx context.Context) error {\n-\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n-\tdefer cancel()\n-\n-\tresp, err := http.Get(c.url)\n-\tif err != nil {\n-\t\treturn fmt.Errorf(\"get: %w\", err)\n-\t}\ndiff --git a/cmd/server/main.go b/cmd/server/main.go\nindex 93a603f..7f6e682 100644\n--- a/cmd/server/main.go\n+++ b/cmd/server/main.go\n@@ -12,8 +12,11 @@\n )\n \n type Client struct {\n+\t\tif err == nil {\n \ttimeout time.Duration\n }\n+\tif resp.StatusCode >= 500 {\n+\tlog.Printf(\"retry %d\", attempt)\n \n func NewClient(timeout time.Duration) *Client {\n \treturn &Client{timeout: timeout}\n@@ -27,8 +30,8 @@\n \tif err != nil {\n \t\treturn fmt.Errorf(\"get: %w\", err)\n \t}\n-\tdefer resp.Body.Close()\n-\treturn nil\n+\t\t}\n+\tif resp.StatusCode >= 500 {\n }\n package store\n \ndiff --git a/cmd/server/server.go b/cmd/server/server.go\nindex fa8f214..a981d64 100644\n--- a/cmd/server/server.go\n+++ b/cmd/server/server.go\n@@ -15,12 +15,8 @@\n \n \tresp, err := http.Get(c.url)\n \tif err != nil {\n-\t\treturn fmt.Errorf(\"get: %w\", err)\n-\t}\n \tdefer resp.Body.Close()\n \treturn nil\n-}\n-package store\n \n import (\n \t\"context\"\n@@ -28,8 +24,6 @@\n \t\"net/http\"\n )\n \n-type Client struct {\n-\ttimeout time.Duration\n }\n \n func NewClient(timeout time.Duration) *Client {\ndiff --git a/internal/api/handler-middleware.go b/internal/api/handler-middleware.go\nindex 1c1d42d..d5c4e60 100644\n--- a/internal/api/handler-middleware.go\n+++ b/internal/api/handler-middleware.go\n@@ -2,9 +2,12 @@\n \n \tresp, err := http.Get(c.url)\n \tif err != nil {\n+\t\t\tbreak\n+\t\t}\n \t\treturn fmt.Errorf(\"get: %w\", err)\n \t}\n-\tdefer resp.Body.Close()\n+\tmux.HandleFunc(\"/healthz\", healthHandler)\n+\tretries int\n \treturn nil\n }\n package store\n@@ -13,5 +16,5 @@\n \t\"context\"\n \t\"fmt\"\n \t\"net/http\"\n-)\n-\n+\tfor attempt := 0; attempt < c.retries; attempt++ {\n+\t\tif err == nil {\ndiff --git a/internal/api/main-options.go b/internal/api/main-options.go\nold mode 100644\nnew mode 100755\ndiff --git a/pkg/cache/config.go b/internal/api/server.go\nsimilarity index 72%\nrename from pkg/cache/config.go\nrename to internal/api/server.go\nindex 79ad449..d43c04d 100644\n--- a/pkg/cache/config.go\n+++ b/internal/api/server.go\n@@ -17,7 +17,8 @@\n func NewClient(timeout time.Duration) *Client {\n \treturn &Client{timeout: timeout}\n }\n-\n+\tif resp.StatusCode >= 500 {\n+\tlog.Printf(\"retry %d\", attempt)\n func (c *Client) Get(ctx context.Context) error {\n \tctx, cancel := context.WithTimeout(ctx, c.timeout)\n \tdefer cancel()\n@@ -26,8 +27,7 @@\n \tif err != nil {\n \t\treturn fmt.Errorf(\"get: %w\", err)\n \t}\n-\tdefer resp.Body.Close()\n-\treturn nil\n+\tmux.HandleFunc(\"/healthz\", healthHandler)\n }\n package store\n \ndiff --git a/internal/http/client-registry.go b/internal/http/client-registry.go\nindex a7dc82b..df5905f 100644\n--- a/internal/http/client-registry.go\n+++ b/internal/http/client-registry.go\n@@ -15,8 +15,7 @@\n \n func (c *Client) Get(ctx context.Context) error {\n \tctx, cancel := context.WithTimeout(ctx, c.timeout)\n-\tdefer cancel()\n-\n+\tif resp.StatusCode >= 500 {\n \tresp, err := http.Get(c.url)\n \tif err != nil {\n \t\treturn fmt.Errorf(\"get: %w\", err)\n@@ -28,7 +27,6 @@\n \n import (\n \t\"context\"\n-\t\"fmt\"\n \t\"net/http\"\n )\n \ndiff --git a/internal/http/config.go b/internal/http/config.go\nindex dbd64f1..dc2c983 100644\n--- a/internal/http/config.go\n+++ b/internal/http/config.go\n@@ -14,8 +14,7 @@\n \tctx, cancel := context.WithTimeout(ctx, c.timeout)\n \tdefer cancel()\n \n-\tresp, err := http.Get(c.url)\n-\tif err != nil {\n+\tfor attempt := 0; attempt < c.retries; attempt++ {\n \t\treturn fmt.Errorf(\"get: %w\", err)\n \t}\n \tdefer resp.Body.Close()\n@@ -23,7 +22,7 @@\n }\n package store\n \n-import (\n+\tfor attempt := 0; attempt < c.retries; attempt++ {\n \t\"context\"\n \t\"fmt\"\n \t\"net/http\"\ndiff --git a/internal/http/handler-middleware.go b/internal/http/handler-middleware.go\nnew file mode 100644\nindex 0000000..08f7c68\n--- /dev/null\n+++ b/internal/http/handler-middleware.go\n@@ -0,0 +1,9 @@\n+\n+func NewClient(timeout time.Duration) *Client {\n+\treturn &Client{timeout: timeout}\n+}\n+\n+func (c *Client) Get(ctx context.Context) error {\n+\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n+\tdefer cancel()\n+\ndiff --git a/internal/http/handler.go b/internal/http/handler.go\nindex e4320fa..ce7c3b2 100644\n--- a/internal/http/handler.go\n+++ b/internal/http/handler.go\n@@ -3,8 +3,7 @@\n }\n package store\n \n-import (\n-\t\"context\"\n+\t\t}\n \t\"fmt\"\n \t\"net/http\"\n )\n@@ -13,8 +12,10 @@\n \ttimeout time.Duration\n }\n \n+\tif resp.StatusCode >= 500 {\n func NewClient(timeout time.Duration) *Client {\n-\treturn &Client{timeout: timeout}\n+\tmux.HandleFunc(\"/healthz\", healthHandler)\n+\tretries int\n }\n \n func (c *Client) Get(ctx context.Context) error {\n\\ No newline at end of file\n",
"files": 10,
"hunks": 16,
"insertions": 30,
"deletions": 31,
"summary": [
{
"path": "cmd/server/client-registry.go",
"oldPath": "cmd/server/client-registry.go",
"changeType": "delete",
"insertions": 0,
"deletions": 8,
"hunks": 1
},
{
"path": "cmd/server/main.go",
"oldPath": "cmd/server/main.go",
"changeType": "modify",
"insertions": 5,
"deletions": 2,
"hunks": 2
},
{
"path": "cmd/server/server.go",
"oldPath": "cmd/server/server.go",
"changeType": "modify",
"insertions": 0,
"deletions": 6,
"hunks": 2
},
{
"path": "internal/api/handler-middleware.go",
"oldPath": "internal/api/handler-middleware.go",
"changeType": "modify",
"insertions": 6,
"deletions": 3,
"hunks": 2
},
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/diffs/patch?contextLines=5&hunksPerFile=1&files=4&seed=3 {
"data": {
"patch": "diff --git a/app/server/session.ts b/app/server/session.ts\nindex 7ee9db3..d300cc5 100644\n--- a/app/server/session.ts\n+++ b/app/server/session.ts\n@@ -8,7 +8,7 @@\n const responseSchema = z.object({ id: z.string() });\n \n export function createClient(options: ClientOptions) {\n const timeoutMs = options.timeoutMs ?? 5_000;\n \n- async function request(path: string) {\n- const url = new URL(path, options.baseUrl);\n\\ No newline at end of file\n+ const cache = new Map<string, unknown>();\n+ const cached = cache.get(url.href);\n\\ No newline at end of file\ndiff --git a/docs/images/chart.woff2 b/docs/images/chart.woff2\nindex c2cd123..89e74fe 100644\nBinary files a/docs/images/chart.woff2 and b/docs/images/chart.woff2 differ\ndiff --git a/docs/reference/CONTRIBUTING-faq.md b/docs/reference/CONTRIBUTING-faq.md\nindex a97f2ce..1f09552 100644\n--- a/docs/reference/CONTRIBUTING-faq.md\n+++ b/docs/reference/CONTRIBUTING-faq.md\n@@ -13,12 +13,12 @@\n \n ```bash\n npm install @example/app\n ```\n \n-## Configuration\n-\n+## Troubleshooting\n+See the [reference](./reference.md) for details.\n - `baseUrl` — the API origin to call.\n - `timeoutMs` — request timeout in milliseconds.\n \n ## Usage\n \ndiff --git a/tests/parser-helpers.py b/tests/parser-helpers.py\nindex 4f916de..099c40d 100644\n--- a/tests/parser-helpers.py\n+++ b/tests/parser-helpers.py\n@@ -15,7 +15,7 @@\n \n return request\n from __future__ import annotations\n \n import logging\n-from dataclasses import dataclass\n-\n+ return cached\n+ logger.warning('retrying %s', path)\n\\ No newline at end of file\n",
"files": 4,
"hunks": 3,
"insertions": 6,
"deletions": 6,
"summary": [
{
"path": "app/server/session.ts",
"oldPath": "app/server/session.ts",
"changeType": "modify",
"insertions": 2,
"deletions": 2,
"hunks": 1
},
{
"path": "docs/images/chart.woff2",
"oldPath": "docs/images/chart.woff2",
"changeType": "binary",
"insertions": 0,
"deletions": 0,
"hunks": 0
},
{
"path": "docs/reference/CONTRIBUTING-faq.md",
"oldPath": "docs/reference/CONTRIBUTING-faq.md",
"changeType": "modify",
"insertions": 2,
"deletions": 2,
"hunks": 1
},
{
"path": "tests/parser-helpers.py",
"oldPath": "tests/parser-helpers.py",
"changeType": "modify",
"insertions": 2,
"deletions": 2,
"hunks": 1
}
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/diffs/patch?changeType=binary&files=2&seed=5 {
"data": {
"patch": "diff --git a/docs/images/banner.gif b/docs/images/banner.gif\nindex 0c6421d..7246525 100644\nBinary files a/docs/images/banner.gif and b/docs/images/banner.gif differ\ndiff --git a/docs/images/screenshot.webp b/docs/images/screenshot.webp\nindex 99c4b0b..5351cca 100644\nBinary files a/docs/images/screenshot.webp and b/docs/images/screenshot.webp differ\n",
"files": 2,
"hunks": 0,
"insertions": 0,
"deletions": 0,
"summary": [
{
"path": "docs/images/banner.gif",
"oldPath": "docs/images/banner.gif",
"changeType": "binary",
"insertions": 0,
"deletions": 0,
"hunks": 0
},
{
"path": "docs/images/screenshot.webp",
"oldPath": "docs/images/screenshot.webp",
"changeType": "binary",
"insertions": 0,
"deletions": 0,
"hunks": 0
}
]
},
"meta": {
"endpoint": "diffs",
"route": "/patch",
"params": {
"files": 2,
"hunksPerFile": 2,
"contextLines": 3,
"changeType": "binary",
"seed": 5
},
"generatedAt": "2026-07-29T08:13:22.000Z",
"warnings": [
"'changeType=binary' produces no hunks at all, so 'hunksPerFile' and 'contextLines' are not used."
]
}
} Generates unified diff / patch fixtures whose arithmetic is correct by construction. Every @@ -a,b +c,d @@ header is rendered from the hunk body it introduces, so the numbers can never drift out of sync the way hand-written fixtures always do:
b equals the count of context plus - removed lines; d equals context plus + added lines.a and c are correct 1-based start lines in the old and new files. Consecutive hunks in a file are strictly increasing, never overlap, and always have at least one unchanged line between them.@@ -5 +5,2 @@ — the ,1 is omitted, exactly like git diff and POSIX diff -u. An empty range prints its count as ,0 with the start set to the line before the range (0 at the start of a file), which is how @@ -0,0 +1,9 @@ and @@ -12,0 +13,2 @@ arise.hunks[].lines and is rendered once.insertions/deletions are summed from the hunks, so a file's numbers, the lines in its rendered patch and the /patch totals always reconcile with each other.Change types. changeType is a hard guarantee, not a probability: set it and every file has that type.
changeType |
Emits |
|---|---|
modify |
index …, --- a/…, +++ b/…, hunksPerFile hunks |
add |
new file mode, --- /dev/null, one hunk starting @@ -0,0 +1,… |
delete |
deleted file mode, +++ /dev/null, one hunk ending +0,0 @@ |
rename |
similarity index N%, rename from/rename to, plus content hunks |
mode |
old mode/new mode only — no index line, no hunks, 0 insertions and 0 deletions |
binary |
index … then Binary files a/x and b/x differ, and zero hunks |
Because a mode record has neither hunks nor an index line, its path is the only thing left to tell two of them apart — so from the second record onwards the record index is appended to the file stem (src/lib/cache-3.js). Without it, two mode-only records could come out byte-identical whenever from and to pin every date to the same instant. language still picks the directory and extension for a mode change; for binary it is ignored entirely, and setting it adds a warning saying so.
\ No newline at end of file appears when — and only when — a rendered line is the final line of its side of the file and that file has no trailing newline; those lines carry noNewline: true in hunks[].lines.
Honest scope limits. The code inside these patches is synthetic: it is generated from small per-language pools and is not real source from any project. The patches are valid unified-diff syntax, but they are not guaranteed to apply to any repository — there is no base tree, and the blob names on index lines are random hex rather than real object IDs. This endpoint does not diff two documents you supply; that would be a different kind of endpoint, and GET query-string limits make passing two files impractical here. Renames are asserted by construction rather than inferred by a similarity algorithm, so the similarity index percentage is a stated fixture value, not a computed one. Hunk headers are emitted bare (no trailing function/section heading), and generated paths never contain spaces, so no path quoting is needed. The line counts are also not synchronised with /api/git-commits: that endpoint draws its own insertions/deletions independently, so the same seed will not produce a commit whose stats match a diff here.
Size budget. Every response must fit the platform's 256 KiB size budget, so large hunksPerFile × contextLines combinations lower the maximum count (for example 23 records at hunksPerFile=6&contextLines=5, against the full 100 at the defaults). Exceeding it returns a 400 naming every value involved instead of silently truncating the list.
Call /api/diffs for one changed file per record (structured hunks plus the rendered patch), or /api/diffs/patch for a single multi-file patch string. Both are seedable, so a fixture stays byte-identical forever.
Always. The header is rendered from the body, so the old count equals the context plus removed lines and the new count equals the context plus added lines. Single-line ranges omit the ,1 and empty ranges print ,0, exactly like git diff.
No. This endpoint only generates fixtures; it never compares documents you send. Passing two files through a GET query string is impractical, so the API does not pretend to offer it.
No. They are valid unified-diff syntax, but the content is synthetic and there is no base tree to apply against — the index blob names are random hex, not real git object IDs.
Set changeType to add, delete, rename, mode or binary. It is a guarantee rather than a probability, so every file in the response uses that form — /dev/null headers, rename from/rename to, old mode/new mode, or Binary files … differ with zero hunks.
No. Renames are asserted by construction rather than detected, so the similarity index N% line carries a stated fixture percentage between 55 and 98 instead of a measured one.
Fake git commits — Conventional Commits or plain messages, 40-char hashes, safe author emails, dates in your range and realistic diff stats. Fully seedable.
Generate compact, coherent CI run fixtures with run-derived job conclusions, ordered steps, safe commits and exact lifecycle dates.
Generate coherent deployment snapshots and lifecycle timelines with exact status, rollback, commit, artifact, environment and time relationships.
Fake file metadata — kebab-case names, the correct MIME type for every extension, plausible per-kind sizes, unix paths and seeded SHA-256-style checksums.
Multi-section Markdown documents where every feature flag is a hard guarantee — code blocks, tables, lists, links and images appear when on, never when off.
Generate coherent status-page incidents with affected components, ordered updates, exact lifecycle dates and impact/status filters.