# OpenMontage Decision Log Audit Trail Format: How (Category, Subject) Pairs Track Production Choices

> Explore the OpenMontage decision log audit trail format. Discover how (category, subject) pairs precisely track production choices for enhanced filtering and reproducibility in your pipeline.

- Repository: [Calesthio/OpenMontage](https://github.com/calesthio/OpenMontage)
- Tags: internals
- Published: 2026-08-30

---

**OpenMontage records every production decision in a JSON document that pairs a machine-readable `category` enum with a human-readable `subject` string, enabling precise filtering and reproducibility across pipeline stages.**

The decision log serves as the immutable audit trail for the OpenMontage production pipeline. Defined by a strict JSON Schema in [`schemas/artifacts/decision_log.schema.json`](https://github.com/calesthio/OpenMontage/blob/main/schemas/artifacts/decision_log.schema.json), this artifact captures the rationale, alternatives, and final selections for every automated or assisted choice made during project execution.

## Decision Log JSON Schema Structure

The audit trail is a JSON object with three required top-level fields. According to [`schemas/artifacts/decision_log.schema.json`](https://github.com/calesthio/OpenMontage/blob/main/schemas/artifacts/decision_log.schema.json), every decision log must include:

- **`version`**: A constant string `"1.0"` indicating the schema version.
- **`project_id`**: A string identifier linking decisions to a specific project.
- **`decisions`**: An array of decision objects representing the chronological audit trail.

Each object in the `decisions` array contains mandatory properties defined at lines 15-16 of the schema, including `decision_id`, `stage`, `category`, `subject`, `options_considered`, `selected`, and `reason`. This structure ensures every entry documents both what was decided and why.

## How (Category, Subject) Pairs Identify Decision Points

The combination of **`category`** and **`subject`** creates a unique signature for each decision type. As defined in the schema (lines 27-44), `category` is an enumerated string representing the decision class—such as `provider_selection`, `render_runtime_selection`, or `budget_tradeoff`. The `subject` field is a free-form string describing what is being decided, such as `"image generation"` or `"compose"`.

Together, these fields allow downstream tools to query specific decision types without ambiguity. For example, filtering for `category="render_runtime_selection"` returns all runtime choices regardless of subject, while combining both fields isolates a specific decision point like `subject="compose"`.

## Generating Decision Logs in Pipeline Scripts

OpenMontage creates the audit trail programmatically during pipeline execution. The helper function in [`scripts/backlot_screenshot_stage.py`](https://github.com/calesthio/OpenMontage/blob/main/scripts/backlot_screenshot_stage.py) (line 41) constructs the initial log structure:

```python
def decision_log(pid: str) -> dict:
    return {
        "version": "1.0",
        "project_id": pid,
        "decisions": [
            {
                "decision_id": "d-001",
                "stage": "proposal",
                "category": "provider_selection",
                "subject": "image generation",
                # … options, selected, reason, etc.

            },
            {
                "decision_id": "d-002",
                "stage": "proposal",
                "category": "render_runtime_selection",
                "subject": "compose",
                # … options, selected, reason, etc.

            },
        ],
    }

```

When the project staging completes, this structure is serialized to [`artifacts/decision_log.json`](https://github.com/calesthio/OpenMontage/blob/main/artifacts/decision_log.json) (lines 98-99 of the same script), establishing the baseline audit trail for subsequent pipeline stages.

## Merging New Decisions During Checkpoints

As the pipeline progresses, new decisions are appended to the existing log rather than overwriting it. The helper function in [`lib/checkpoint.py`](https://github.com/calesthio/OpenMontage/blob/main/lib/checkpoint.py) (lines 388-401) handles this merge operation, ensuring that decisions from later stages—such as `edit` or `render`—integrate seamlessly with earlier entries while preserving chronological order and schema compliance.

## Querying the Audit Trail by Category and Subject

Because every entry contains normalized `(category, subject)` pairs, you can programmatically extract specific decision rationales. The following example filters for all render runtime selections:

```python
import json
import pathlib

log_path = pathlib.Path("artifacts/decision_log.json")
log = json.loads(log_path.read_text())

# Find all render-runtime selections

runtime_decisions = [
    d for d in log["decisions"] if d["category"] == "render_runtime_selection"
]

for d in runtime_decisions:
    print(f"{d['subject']}: selected {d['selected']} (reason: {d['reason']})")

```

This queryability supports automated auditing, cost analysis, and reproducibility reports by leveraging the consistent tagging enforced by the schema.

## Key Implementation Files

The decision log system spans several critical files in the OpenMontage repository:

- **[`schemas/artifacts/decision_log.schema.json`](https://github.com/calesthio/OpenMontage/blob/main/schemas/artifacts/decision_log.schema.json)**: Defines the JSON Schema including the `category` enumeration and `subject` requirements.
- **[`scripts/backlot_screenshot_stage.py`](https://github.com/calesthio/OpenMontage/blob/main/scripts/backlot_screenshot_stage.py)**: Contains the `decision_log()` factory function (line 41) and write logic (lines 98-99).
- **[`lib/checkpoint.py`](https://github.com/calesthio/OpenMontage/blob/main/lib/checkpoint.py)**: Implements the merge logic (lines 388-401) for updating existing logs.
- **[`tests/tools/test_hyperframes_compose.py`](https://github.com/calesthio/OpenMontage/blob/main/tests/tools/test_hyperframes_compose.py)**: Validates schema compliance for decision entries in unit tests.

## Summary

- The **decision log** is a JSON document conforming to [`decision_log.schema.json`](https://github.com/calesthio/OpenMontage/blob/main/decision_log.schema.json) with `version`, `project_id`, and `decisions` fields.
- Every decision must include a **`category`** (enumerated type) and **`subject`** (free-form string) pair that uniquely identifies the decision point.
- Pipeline scripts generate logs via `decision_log()` in [`backlot_screenshot_stage.py`](https://github.com/calesthio/OpenMontage/blob/main/backlot_screenshot_stage.py) and persist them to [`artifacts/decision_log.json`](https://github.com/calesthio/OpenMontage/blob/main/artifacts/decision_log.json).
- The [`checkpoint.py`](https://github.com/calesthio/OpenMontage/blob/main/checkpoint.py) library merges new decisions into existing logs without breaking schema compliance.
- The `(category, subject)` structure enables precise filtering and auditability across all pipeline stages.

## Frequently Asked Questions

### What values are valid for the `category` field in OpenMontage decision logs?

The `category` field accepts enumerated string values defined in [`schemas/artifacts/decision_log.schema.json`](https://github.com/calesthio/OpenMontage/blob/main/schemas/artifacts/decision_log.schema.json) (lines 27-44). Valid categories include `provider_selection`, `render_runtime_selection`, and `budget_tradeoff`, among others. Each category represents a distinct class of production decision.

### How does OpenMontage ensure (category, subject) pairs remain unique in the audit trail?

The schema enforces that every decision object contains both `category` and `subject` fields, but uniqueness is maintained by the `decision_id` field, which must be unique within the log. The `(category, subject)` pair serves as a semantic identifier for querying and filtering related decisions rather than a strict unique constraint.

### Where is the decision log stored during pipeline execution?

The initial decision log is written to [`artifacts/decision_log.json`](https://github.com/calesthio/OpenMontage/blob/main/artifacts/decision_log.json) during the staging phase by [`scripts/backlot_screenshot_stage.py`](https://github.com/calesthio/OpenMontage/blob/main/scripts/backlot_screenshot_stage.py) (lines 98-99). Subsequent pipeline stages update this file via the checkpoint helper in [`lib/checkpoint.py`](https://github.com/calesthio/OpenMontage/blob/main/lib/checkpoint.py), maintaining a single source of truth for all project decisions.

### Can decision logs be manually edited outside the OpenMontage pipeline?

While the JSON format is human-readable, manual editing is discouraged because the schema requires specific enumerated values for `category` and mandatory fields like `decision_id`, `selected`, and `reason`. Unit tests in [`tests/tools/test_hyperframes_compose.py`](https://github.com/calesthio/OpenMontage/blob/main/tests/tools/test_hyperframes_compose.py) validate schema compliance, ensuring programmatically generated logs remain valid.