prometeu-studio/docs/packer/decisions/001-asset-workspace-registry-and-stable-identity-decision.md
2026-03-24 13:42:38 +00:00

198 lines
6.4 KiB
Markdown

# Asset Workspace, Registry, and Stable Identity Decision
## Status
Accepted
## Date
2026-03-11
## Context
This decision closes the architectural questions raised in [`01.1. Asset Workspace, Registry, and Stable Identity Agenda`](../agendas/01.1.%20Asset%20Workspace,%20Registry,%20and%20Stable%20Identity%20Agenda.md).
The packer needs a stable model for:
- what counts as a managed asset;
- how local asset declaration relates to workspace registry state;
- how asset identity survives rename and relocation;
- how adoption and diagnostics distinguish registered from unregistered asset roots.
If this model remains ambiguous, later specs for `asset.json`, virtual assets, diagnostics, build outputs, and Studio services will inherit unstable semantics.
## Decision
The packer adopts a `registry-authoritative, anchor-declared, identity-stable, path-mutable` model.
### 1. Managed asset unit
A managed asset is one asset root directory.
Rules:
- one managed asset maps to one dedicated asset root directory;
- one asset root contains exactly one anchor `asset.json`;
- files and subdirectories under that root are inputs or support files of that managed asset unless explicitly modeled otherwise in future specs;
- individual source files are not separate managed assets by default.
This allows grouped assets such as atlases, image banks, or palette-driven bundles to be modeled as one managed asset with many inputs.
### 2. Registry authority
`assets/.prometeu/index.json` is the authoritative workspace registry for managed assets.
It defines:
- which assets are officially managed by the packer;
- their stable project-local identities;
- their current registered root locations;
- allocator state and registry-owned metadata.
If an asset root is not present in `index.json`, it is not part of the managed build set.
### 3. Asset-local declaration
`asset.json` is the asset-local declaration anchored at the asset root.
It defines the local declaration of the asset, including the asset contract that later specs will refine.
`asset.json` does not, by itself, make an asset managed.
Registration and build inclusion remain registry-owned concerns.
### 4. Identity model
Each managed asset has:
- `asset_id`: stable project-local identity;
- `asset_uuid`: stable long-lived identity for tooling and migration scenarios.
The following are not primary identity:
- display name;
- filesystem path;
- internal input filenames.
Name and path are mutable presentation or location fields.
However, `asset_name` may still participate in authoring and runtime-facing APIs as a logical reference label.
That does not make it the stable identity of the asset.
Practical consequence:
- changing `asset_name` does not create a new asset identity;
- but changing `asset_name` may still require source-level or tooling-level reference updates where game/runtime APIs refer to assets by name.
### 5. Relocation and rename
Moving or renaming an asset root does not create a new asset.
Rules:
- `asset_id` must remain unchanged;
- `asset_uuid` must remain unchanged;
- registry location is updated to the new asset root;
- this is treated as relocation, not recreation.
### 6. Orphan anchor behavior
An `asset.json` without a corresponding registry entry is an orphan asset declaration.
Rules:
- it does not enter the build automatically;
- it must be surfaced by workspace diagnostics such as `doctor --workspace`;
- it may be incorporated only through explicit adoption flow.
### 7. `asset_id` allocation
`asset_id` allocation is registry-owned and strictly monotonic within the project.
Rules:
- allocation happens once at registration time;
- previously issued IDs must not be silently recycled;
- allocator state is persisted in `index.json`;
- allocator rollback is not allowed as normal behavior.
If audit metadata is useful, it should be recorded separately, for example as creation metadata.
Time should not be encoded into the runtime-facing identity model without a concrete future need.
### 8. Manual copy and identity collision
Manual copy of an asset root that duplicates identity-bearing content must not be reconciled implicitly.
Rules:
- packer must surface identity collision or duplicate-anchor diagnostics explicitly;
- packer must not silently guess whether the copy is a rename, clone, or replacement;
- resolution must happen through explicit user action or future dedicated workflows.
## Invariants and Constraints
The following invariants now apply:
1. One managed asset equals one asset root.
2. One managed asset root contains exactly one anchor `asset.json`.
3. `index.json` is the authoritative managed registry.
4. `asset.json` is the authoritative asset-local declaration.
5. `asset_id` is stable, monotonic, and non-recycled.
6. `asset_uuid` is stable across relocation.
7. Path and display name are mutable and not primary identity.
8. Orphan `asset.json` declarations are diagnosable but not build-active.
9. Copy-induced identity collisions are explicit errors, not heuristic reconciliation cases.
## Explicit Non-Decisions
This decision does not yet define:
- the detailed schema of `asset.json`;
- the field-level boundary between common asset declaration and format-specific declaration;
- CLI or Studio service APIs;
- detailed adoption UX;
- detailed garbage collection and quarantine behavior;
- runtime artifact formats such as `assets.pa`.
Those belong to later decisions and specs.
## Propagation Targets
This decision must propagate to:
- packer workspace and control files specs;
- packer managed asset and identity specs;
- packer registry consistency and diagnostics specs;
- future Studio service contracts for adoption, registration, move, rename, and inspection;
- future implementation of registry persistence and identity allocation.
## Validation Notes
Example: grouped atlas asset
```text
assets/
ui_atlas/
asset.json
sprites/
confirm.png
cancel.png
palettes/
ui_main.pal
```
This is one managed asset, not many.
The internal files are inputs of the asset root declared by `asset.json`.
Example: relocation
- `assets/ui_atlas/` moves to `assets/ui/common_atlas/`
- `asset_id` remains the same
- `asset_uuid` remains the same
- only the registered root path changes
Example: orphan anchor
- `assets/wip/new_bank/asset.json` exists
- no corresponding registry entry exists in `index.json`
- the asset is diagnosable and adoptable, but not part of the managed build set