# Audit Export JSON Schema

Complete schema for the structured JSON audit document produced by `/fluent-session export`.

## Top-Level Structure

```json
{
  "$schema": "fluent-session-audit/v1",
  "sessionId": "string (UUID v4)",
  "startedAt": "string (ISO-8601 timestamp of first tracked change)",
  "endedAt": "string (ISO-8601 timestamp of last tracked change)",
  "context": {
    "profile": "string (Fluent CLI profile name)",
    "account": "string (API base URL)",
    "retailer": {
      "ref": "string (retailer reference)",
      "id": "number (retailer ID)"
    },
    "user": "string (authenticated username)",
    "agentModel": "string (AI model identifier)"
  },
  "summary": {
    "codeChanges": "number",
    "environmentMutations": "number",
    "eventsSent": "number",
    "deploymentsCompleted": "number",
    "testsRun": "number",
    "testsPassed": "number",
    "testsFailed": "number",
    "irreversibleActions": "number",
    "skillsInvoked": "number",
    "toolCallsWrite": "number",
    "toolCallsRead": "number (only when --include-readonly)",
    "decisionTrailEntries": "number"
  },
  "changes": ["array of Change objects"],
  "skillInvocations": ["array of SkillInvocation objects"],
  "toolCalls": ["array of ToolCall objects"],
  "decisionTrail": ["array of DecisionEntry objects"],
  "compliance": { "..." }
}
```

## Change Object

```json
{
  "seq": "number (1-based)",
  "timestamp": "string (ISO-8601)",
  "category": "string (CODE|ENVIRONMENT|TEST|CONFIG)",
  "action": "string (see Action Enum below)",
  "target": { "type": "string", "...additional fields by type" },
  "details": "string",
  "reversible": "boolean",
  "rollbackCommand": "string|undefined",
  "outcome": "string|undefined (SUCCESS|FAILED|NO_MATCH|PENDING)",
  "previousValue": "any|undefined",
  "newValue": "any|undefined",
  "diff": { "linesAdded": "number", "linesRemoved": "number" },
  "result": "string|undefined (PASS|FAIL -- TEST category)",
  "tool": "string|undefined (MCP tool name)",
  "skill": "string|undefined",
  "storyRef": "string|undefined"
}
```

Fields marked `|undefined` are only present when applicable. The `diff` object is only present for CODE MODIFY actions.

## SkillInvocation Object

```json
{
  "seq": "number (1-based, separate sequence)",
  "timestamp": "string (ISO-8601)",
  "skill": "string (e.g. fluent-rule-scaffold)",
  "arguments": "object (sanitized key args, NOT full file contents)",
  "gateResult": "string|undefined (PASS|BLOCKED|SKIPPED)",
  "gateErrorCode": "string|undefined (PLAN_REQUIRED, PREREQ_MISSING, etc.)",
  "outcome": "string (completed|failed|skipped|blocked)",
  "failureReason": "string|undefined",
  "handoffSignal": "string|undefined (e.g. '-> READY: ...path')",
  "triggeredBy": "number|undefined (seq of parent invocation)",
  "duration": "string|undefined (e.g. '45s', '2m30s')",
  "changesProduced": "number[] (seq from changes[])",
  "toolCallsProduced": "number[] (seq from toolCalls[])",
  "nextRecommended": "string|undefined"
}
```

## ToolCall Object

```json
{
  "seq": "number (1-based, separate sequence)",
  "timestamp": "string (ISO-8601)",
  "tool": "string (MCP tool name)",
  "server": "string (fluent-mcp or fluent-mcp-extn)",
  "isWrite": "boolean",
  "target": {
    "entityType": "string|undefined",
    "entityRef": "string|undefined",
    "description": "string"
  },
  "outcome": "string (ok|error)",
  "errorCode": "string|undefined",
  "dryRun": "boolean",
  "skill": "string|undefined"
}
```

Read-only tool calls (`isWrite: false`) are only included when `--include-readonly` is specified.

## DecisionEntry Object

```json
{
  "seq": "number (1-based, separate sequence)",
  "timestamp": "string (ISO-8601)",
  "trigger": "string",
  "options": "string[]",
  "selected": "string",
  "rationale": "string",
  "confidence": "string (high|medium|low)",
  "assumptions": "string[]",
  "skill": "string|undefined",
  "triggeredBy": "number|undefined (seq from skillInvocations[])",
  "resultingChanges": "number[] (seq from changes[])"
}
```

## Compliance Object

```json
{
  "scopeDocumentRef": "string|null",
  "tasksCompleted": "number",
  "tasksTotal": "number",
  "traceability": {
    "<storyRef>": {
      "tasks": ["array of task IDs"],
      "status": "string (complete|partial|not_started)",
      "changes": ["array of seq numbers from changes[]"]
    }
  },
  "preDeployChecklist": "string|null",
  "irreversibleActions": [
    { "seq": "number", "description": "string", "risk": "string (LOW|MEDIUM|HIGH|CRITICAL)" }
  ]
}
```

## Target Object Shapes by Category

**CODE targets:**

| Action | target.type | Additional fields |
|--------|-------------|-------------------|
| `CREATE` | `file` | `path` (string) |
| `MODIFY` | `file` | `path` (string) |
| `DELETE` | `file` | `path` (string) |
| `COMMIT` | `git` | `repo`, `branch`, `hash` |
| `PUSH` | `git` | `repo`, `branch`, `remote` |

**ENVIRONMENT targets:**

| Action | target.type | Additional fields |
|--------|-------------|-------------------|
| `MUTATION` | `entity` | `entityType`, `entityRef`, `entityId`, `fields` (string[]) |
| `DEPLOY` (module) | `module` | `name`, `version`, `retailer` |
| `DEPLOY` (workflow) | `workflow` | `name`, `version`, `retailer` |
| `EVENT` | `event` | `eventName`, `entityType`, `entityRef`, `mode` (async\|sync) |
| `BATCH` | `batch` | `jobName`, `jobId`, `entityType`, `recordCount` |

**TEST targets:**

| Action | target.type | Additional fields |
|--------|-------------|-------------------|
| `ASSERT` | `assertion` | `entityType`, `entityRef`, `expectedStatus`, `actualStatus` |
| `BUILD` | `build` | `command`, `exitCode`, `testCount`, `failureCount` |
| `VALIDATE` | `validation` | `validationType`, `target` |

**CONFIG targets:**

| Action | target.type | Additional fields |
|--------|-------------|-------------------|
| `SETTING_CREATE` | `setting` | `key`, `context`, `contextId` |
| `SETTING_UPDATE` | `setting` | `key`, `context`, `contextId` |

## Action Enum Values

| Category | Valid Actions |
|----------|-------------|
| `CODE` | `CREATE`, `MODIFY`, `DELETE`, `COMMIT`, `PUSH` |
| `ENVIRONMENT` | `MUTATION`, `DEPLOY`, `EVENT`, `BATCH` |
| `TEST` | `ASSERT`, `BUILD`, `VALIDATE` |
| `CONFIG` | `SETTING_CREATE`, `SETTING_UPDATE` |

## Rollback Commands

| Action | Rollback Command Pattern |
|--------|------------------------|
| `DEPLOY` (module) | `fluent module install -p <PROFILE> -r <RETAILER> -m <module-name>:<previousVersion>` |
| `DEPLOY` (workflow) | Re-upload the previous version workflow JSON via `workflow.upload` |
| `MUTATION` (entity status) | `entity.update({ entityType, id, fields: { status: "<previousValue>" } })` |
| `SETTING_CREATE` | Delete the setting (manual via GraphQL) |
| `SETTING_UPDATE` | `setting.upsert({ name, value: "<previousValue>", context, contextId })` |
| `COMMIT` | `git revert <hash>` |
| `PUSH` | `git push origin <branch> --force` (flag as destructive) |
| `EVENT` | Not reversible — events cannot be un-sent |
| `BATCH` | Not reversible — batch records are processed |
| `CODE CREATE` | `rm <path>` or `git checkout -- <path>` |
| `CODE MODIFY` | `git checkout -- <path>` |

Changes with `reversible: false` do not have a `rollbackCommand` field.

## Sensitive Value Redaction

**Always redact (replace with `"[REDACTED]"`):**
- Access tokens and bearer tokens
- Passwords and client secrets
- API keys
- PII: customer email addresses, phone numbers, full names in entity attributes
- Setting values containing `password`, `secret`, `token`, `key` in the setting name

**Never redact (keep as-is):**
- Entity refs, IDs, and statuses
- Event names and entity types
- File paths, version numbers, workflow names, ruleset names
- Setting keys (the name itself, not secret values)
- Retailer refs and IDs, user story references
- Git commit hashes and branch names

## JSONL Format

When `--format jsonl` is specified:

```
Line 1: {"$schema":"fluent-session-audit/v1","sessionId":"...","context":{...},"summary":{...},"compliance":{...}}
Line 2: {"seq":1,"timestamp":"...","category":"CODE","action":"CREATE","target":{...},...}
Line 3: {"seq":2,"timestamp":"...","category":"CODE","action":"MODIFY","target":{...},...}
```

First line is session metadata (everything except `changes`). Each subsequent line is one change record. File extension: `.audit.jsonl`.

## External System Mapping

| System | Field Mapping | Consumption Pattern |
|--------|--------------|-------------------|
| **Jira** | `changes[].storyRef` | Create work log entries; update story status from `compliance.traceability[].status` |
| **Confluence** | Full audit document | Generate deployment record pages |
| **CI/CD** | `compliance.irreversibleActions`, `summary.testsFailed` | Deployment gate artifact |
| **Git** | `changes[].target` where `type == "git"` | Cross-reference with PR metadata |
| **Feedback Loop** | `compliance.tasksCompleted / tasksTotal` | Measure scope completion percentage |
