---
id: LSN-0039
ticket: packer-pipeline-metadata-ownership
title: Runtime Header Boundary and Tooling-Owned Pipeline Metadata
created: 2026-04-10
tags: [packer, metadata, runtime-contract, tooling, codec, assets-pa]
---

## Context

The packer had drift between implementation and spec around `output.pipeline` ownership. The runtime-facing artifact `assets.pa` was documented as if pipeline metadata should materialize under `asset_table[].metadata.pipeline`, while the implementation already treated at least part of that surface as tooling-oriented and excluded palette payloads from the runtime header.

This created the wrong architectural pressure: Studio and third-party tools could start depending on `assets.pa` for authoring/build provenance, and runtime-facing specs could silently absorb build-time structures that do not belong in the execution contract.

The discussion resolved that split explicitly and implemented it end to end in specs, packer materialization, and tests.

## Key Decisions

### Tooling Metadata Must Not Leak Into the Runtime Header

**What:**
`output.pipeline` remains tooling-only metadata in `asset.json` and related sidecar outputs. The runtime-facing `assets.pa` header must not mirror `output.pipeline` by default. Runtime-owned metadata remains under explicit, normalized fields in `asset_table[].metadata`.

**Why:**
`assets.pa` is the authoritative runtime artifact. If it starts carrying build provenance, editor-oriented structures, or reverse-sync payloads merely because they exist in the authoring manifest, the runtime contract becomes larger, noisier, and harder to evolve safely.

**Trade-offs:**
Tools that want provenance cannot rely on one binary artifact alone. They must read `asset.json` and/or `build/asset_table_metadata.json`. That is a deliberate trade-off in favor of a cleaner runtime boundary.

### Promotion Must Be Explicit, Not a Bulk Mirror

**What:**
If pipeline-derived information is needed at runtime, it must be promoted into an explicit normative field under runtime-owned metadata. The packer must not reintroduce a generic mirrored `pipeline` object under another name.

**Why:**
Bulk mirroring hides product decisions inside implementation convenience. Explicit promotion forces each field to justify its presence in the runtime contract.

**Trade-offs:**
This adds small editorial and implementation work whenever a new runtime-facing derived field is introduced, but it keeps the contract intentional and testable.

### Codec Serialization Must Stay in `SCREAMING_SNAKE_CASE`

**What:**
Serialized asset entry `codec` values are locked to `SCREAMING_SNAKE_CASE`. The currently known `NONE` value remains serialized as `NONE`.

**Why:**
The implementation already had a stable manifest/runtime representation through `OutputCodecCatalog`. Recording that casing in spec prevents future drift when more codecs are added.

**Trade-offs:**
Future codec additions must preserve the established serialized style unless a new decision explicitly revises the contract.

## Patterns and Algorithms

- Use separate surfaces for separate consumers: `assets.pa` for runtime contract, `asset_table_metadata.json` for tooling-oriented provenance, and `asset.json` for authoring intent.
- Build runtime metadata from explicit normalized fields first, then derive tooling sidecars from a superset when needed.
- Keep the runtime header free of raw authoring/build objects even if the sidecar keeps them intact for Studio or inspection tools.
- Lock serialized enum casing in spec as soon as the first value ships, even if the current catalog is minimal.

## Pitfalls

- Do not treat “already present in the manifest” as sufficient reason to serialize a field into the runtime header.
- Do not let sidecar convenience become implicit runtime compatibility.
- Do not partially filter a tooling object and leave an empty placeholder in runtime metadata unless that placeholder has explicit runtime meaning.
- Do not leave enum casing as an implementation accident. If the manifest value matters, the spec must say so.

## Takeaways

- The runtime header is a contract surface, not a metadata dump.
- Tooling provenance belongs in `asset.json` and `build/asset_table_metadata.json`, not in `assets.pa`.
- Runtime-facing derived metadata must be promoted explicitly field by field.
- Stable serialized casing rules should be fixed in spec before the value set grows.
