# Audit Batch Output Format Specification

This document specifies the structured Markdown format produced by the
`agdt-audit-prepare` command. The evaluation agent consumes these files
as its primary input.

For PR lifecycle and loop-label behavior of evaluation vs instruction-update PRs,
see [`docs/audit-pr-label-lifecycle.md`](./audit-pr-label-lifecycle.md).

## Output Directory Structure

```text
audit-batches/{batch_id}/
├── batch-summary.md       # Metadata, PR list, statistics
├── batch-data.md          # Full structured review data
└── instruction-files.md   # Preloaded instruction file contents
```

After prepare, the workflow writes `batch-meta.json` and pushes the directory to
`audit/batch-{batch_id[:8]}` as the durable handoff point for evaluation/apply.
Dispatch then assigns the coding agent to the tracking issue (instead of posting
an `@copilot` comment) so the evaluation run is validated by an active session.

```text
audit-batches/{batch_id}/
├── batch-summary.md
├── batch-data.md
├── instruction-files.md
├── batch-meta.json        # Batch/apply contract metadata
└── agent-output/          # Written later by evaluation agent
    ├── audit-summary-report.md
    └── .../copilot-instructions.md
```

## File: `batch-meta.json`

JSON contract consumed by the apply workflow:

```json
{
  "batch_id": "<uuid>",
  "pr_numbers": [1, 2, 3],
  "tracking_issue": 2042,
  "batch_branch": "audit/batch-1234abcd",
  "output_dir": "audit-batches/<uuid>",
  "repo": "owner/repo"
}
```

The apply workflow reads this file and invokes:

```bash
agdt-audit-apply --repo <repo> --batch-id <batch_id> --output-dir <output_dir> --pr-numbers <csv> --tracking-issue <issue>
```

## File: `batch-summary.md`

### Schema

```markdown
# Review Feedback Audit Batch — {pr_count} PRs

**Batch ID:** {batch_id}
**PRs audited:** {pr_count}
**Total observations:** {total_count}
**Stale observations:** {stale_count}
**PR numbers:** #N1, #N2, ...

## PRs Included

- **#N**: {title} (merged|closed (not merged))

## Category Distribution

- **{category}**: {count}
```

## File: `batch-data.md`

### Per-PR Section Schema

````markdown
## PR #{number}: {title}

- **State:** merged|closed (not merged)
- **Closed at:** {iso8601_timestamp}
- **URL:** {pr_url}

### Observation {index} — `{file_path}` L{line}[ ⚠️ STALE]

- **Reviewer:** {reviewer_login}
- **Category:** {primary}[ / {secondary}]
- **Resolved:** yes|no
- **Body:**
{fence_body}text
{comment_body}
{fence_body}

**Diff hunk:**
{fence_diff}diff
{diff_hunk_content}
{fence_diff}
````

> **Note:** Both the comment body and diff hunk are wrapped in dynamically-sized
> code fences (minimum ` ``` `, extended when the content itself contains backtick runs)
> so that embedded backtick sequences never terminate the outer fence prematurely.

### Field Definitions

| Field | Type | Description |
|-------|------|-------------|
| `number` | integer | PR number |
| `title` | string | PR title |
| `state` | string | "merged" or "closed (not merged)" |
| `closed_at` | string | ISO 8601 timestamp |
| `url` | string | Full PR URL |
| `file_path` | string | Repo-relative file path |
| `line` | integer or "?" | Line number (? if unavailable) |
| `reviewer` | string | Reviewer login name |
| `primary_category` | string | Primary category from taxonomy |
| `secondary_category` | string | Optional secondary category |
| `resolved` | boolean | Whether the thread was resolved |
| `body` | string | Full comment body text |
| `diff_hunk` | string | Diff context (may be multi-line) |
| `is_stale` | boolean | Whether file no longer exists at HEAD |

## File: `instruction-files.md`

### Schema

````markdown
# Preloaded Instruction Files

## File: `{repo_relative_path}`

**Path:** {repo_relative_path}
**Status:** exists (update allowed)|does not exist (creation allowed)

[**Content:**

{fence}markdown
{file_content}
{fence}]
````

> **Note:** The `**Content:**` block is present only when the file exists **and** its content
> is non-empty. Files with empty content or read errors omit the block entirely.
> When content is present it is wrapped in a dynamically-sized fence (minimum ` ``` `,
> extended when the content contains backtick runs).

## Category Taxonomy

The 13 review feedback categories:

| Category | Keywords (heuristic) |
|----------|---------------------|
| `input_validation` | validation, bounds, range check, sanitize |
| `error_handling` | error, exception, try, catch, retry |
| `cross_platform` | platform, windows, linux, portable |
| `type_safety` | type, annotation, isinstance, generic |
| `concurrency` | concurrent, thread, async, lock, race |
| `documentation` | docstring, documentation, readme |
| `test_reliability` | test, flaky, assertion, mock, fixture |
| `performance` | performance, optimize, cache, memory |
| `security` | security, injection, auth, credential |
| `naming` | naming, rename, misleading, clarity |
| `api_interface` | api, interface, contract, breaking change |
| `dependencies` | dependency, package, version, deprecated |
| `other` | (no keyword match) |

## Instruction File Inclusion Rules

1. `.github/copilot-instructions.md` is **always** included (root scope)
2. For each file path in review observations, walk up the directory tree
3. Include any `copilot-instructions.md` found in parent directories
4. Deduplicate by path (each file appears once)
5. Non-existent files are included with "creation allowed" status

## CI Provider Portability

This format is provider-agnostic. Any CI provider implementation that
produces these three files with the documented structure enables the
evaluation agent to function without modification.

Required provider capabilities:

- List closed PRs with label filtering
- Fetch review comments with file/line context
- Provide diff hunks for commented lines
- Report PR state (merged vs closed-without-merge)
