forked from OpenAssetIO/OpenAssetIO
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Docs] Add DR covering canonical use of
managementPolicy
.
Part of #778, this aspect of the API has not been documented in any detail. Signed-off-by: Tom Cowland <tom@foundry.com>
- Loading branch information
1 parent
198ec3d
commit d2ff313
Showing
1 changed file
with
307 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,307 @@ | ||
# DR014 Management Policy responses | ||
|
||
- **Status:** Proposed | ||
- **Driver:** @foundrytom | ||
- **Approver:** @feltech @ecmorris @antirotor @mattdaw | ||
- **Outcome:** A Manager should additionally imbue a `managementPolicy` | ||
response with the traits that it is capable of resolving/persisting | ||
for each trait set. | ||
|
||
## Background | ||
|
||
The ability for a host to query a manager's capabilities and intent is a | ||
critical part of the OpenAssetIO abstraction. | ||
|
||
OpenAssetIO classifies entities (assets) using a Trait Set, which lists | ||
one or more traits that describe its nature. For example, an image | ||
file may have the trait set `{'file', 'image', 'colorManaged'}`. | ||
|
||
The `managementPolicy` method is a high-level (i.e. not entity specific) | ||
query that a host can use to determine a manager's behaviour in relation | ||
to a specific trait set. | ||
|
||
The answer to this query is commonly used by a Host to conditionally | ||
enable user-facing functionality based on the behaviour of the specific | ||
manager that is in use. | ||
|
||
This mechanism is flexible, and so exactly how a manager should | ||
implement its response is potentially ambiguous. This document outlines | ||
the rationale behind the defined canonical behaviour. | ||
|
||
## Relevant data | ||
|
||
Documentation pertaining to the OpenAssetIO data model: | ||
|
||
- [Entities, Traits and Specifications overview](../doxygen/src/EntitiesTraitsSpecifications.dox) | ||
- [Compositional data model decision record](./DR007-Hierarchical-or-compositional-traits-for-specifications.md) | ||
- [Unified Entity data model decision record](./DR008-Unify-the-entity-data-model.md) | ||
|
||
Notable points: | ||
|
||
- A Trait is how OpenAssetIO describes a behaviour or quality. | ||
- Traits consist of a unique ID, and zero or more simple-typed | ||
properties that further describe that trait. | ||
- A Trait Set is an un-ordered collection of unique trait IDs. | ||
- Trait Sets combine multiple traits to increase specificity, rather | ||
than meaning "or". | ||
- A `TraitsData` instance is a dict of dicts, that can be "imbued" with | ||
zero or more traits and the values for any associated properties those | ||
traits may have. The top-level keys of this container form a Trait | ||
Set. | ||
- The `managementPolicy` result is a `TraitsData` instance for each | ||
supplied Trait Set. | ||
- Some managers may only care about certain specific Traits (such as | ||
those describing the assets content disposition), and handle all | ||
'derivative entity types' the same. | ||
- The `managementPolicy` query is not a required pre-requisite in the | ||
use of `resolve`, et. al. but is used to adapt application behaviour | ||
to improve user experience. | ||
|
||
## Illustrative scenario | ||
|
||
Consider a manager that manages the files for assets used in 2D | ||
compositing. | ||
|
||
It happily manages the node graphs used to define a comp, plus any | ||
associated images read/written by the process. It does however, have | ||
no interest in managing intermediate cache files that may be used | ||
to speed up interactivity. | ||
|
||
Its implementation pivots all behaviour around two (imaginary) traits: | ||
|
||
- The `file` trait - indicating the entity's data is stored in a file. | ||
- The `cache` trait - indicating that the data is re-creatable. | ||
|
||
The manager has a fairly simple database and isn't capable of storing | ||
arbitrary data for an entity, just the appropriate file path. It | ||
fulfills the API contract, by ensuring it can also store an entity's | ||
trait set - allowing it to filter lookups later, and properly | ||
re-classify any given entity as required. However, it can't persist the | ||
data for any other traits these entities may have. | ||
|
||
A Host that manages several file-based entities (eg: its | ||
main document and assorted data files that it reads/writes), | ||
will query the manager's `managementPolicy` to determine for which of | ||
these the manager should be involved with. | ||
|
||
If a manager opts-out of managing any given trait set, then the host | ||
will use its native UI/workflows for browsing and saving, if it opts-in, | ||
then it will delegate UI and data locality responsibilities to the | ||
manager. | ||
|
||
So, how should this manager respond to the `managementPolicy` query for | ||
any specific trait set? | ||
|
||
Lets explore the scenario where the host is querying the manager's | ||
policy for its native document format, and for images it generates, and | ||
its temporary cache: | ||
|
||
```python | ||
traitSets =[ | ||
{ 'file', 'nodeGraph' }, # Main document | ||
{ 'file', 'image', 'colorManaged' } # Generated images | ||
{ 'file', 'image', 'latlong', 'colorManaged' } # Generated maps | ||
{ 'file', 'image', 'cache' } # Temporary cache | ||
] | ||
``` | ||
|
||
Keep in mind, that the manager is only interested in `file` based | ||
entities, and needs to be able to explicitly opt-out of certain trait | ||
sets. | ||
|
||
## Options considered | ||
|
||
### Option 1 - Any Matching | ||
|
||
The manager should respond on the basis of matching any of the traits in | ||
the set, even if it doesn't understand many others, unless it explicitly | ||
needs to opt-out: | ||
|
||
```python | ||
if CacheTrait.kId in traitSet: | ||
continue | ||
if FileTrait.kId in traitSet: | ||
ManagedTrait.imbueTo(policy) | ||
``` | ||
|
||
Such that it opts-in to managing all entities with the file trait in | ||
their set, aside from caches: | ||
|
||
```python | ||
policies = [ | ||
{ 'managed': {...} }, # Main document | ||
{ 'managed': {...} }, # Generated images | ||
{ 'managed': {...} }, # Generated maps | ||
{}, # Temporary cache | ||
] | ||
``` | ||
|
||
Any other queries for trait sets without the file trait would be empty | ||
`{}` indicating un-managed status. | ||
|
||
#### Pros | ||
|
||
- Hosts can query specific and precise trait sets, but the manager does | ||
not need to worry about all possible permutations. | ||
|
||
#### Cons | ||
|
||
- There is no way for a host to determine what traits can be resolved | ||
(or persisted) for any given entity, and so must tolerate missing data | ||
at a later date (e.g. the color space for the `colorManaged` trait, if | ||
the manager can't ever provide this). | ||
|
||
### Option 2 - Exact Matching | ||
|
||
The manager should respond only to sets where it is capable of resolving | ||
or persisting all of the requested trait set: | ||
|
||
```python | ||
if traitSet == { FileTrait.kId }: | ||
ManagedTrait.imbueTo(policy) | ||
``` | ||
|
||
Such that it _only_ opts into managing the specifically limited trait | ||
set that it can support: | ||
|
||
```python | ||
policies = [ | ||
{}, # Main document | ||
{}, # Generated Images | ||
{}, # Generated maps | ||
{} # Temporary caches | ||
] | ||
``` | ||
|
||
The Host would receive empty responses (`{}`) for all of the original | ||
trait sets, and so must potentially decompose and re-try its queried | ||
trait sets to reveal some supported sub-set. For example, if ultimately | ||
it just needed the file path, it could try these combinations: | ||
|
||
```python | ||
traitSets = [ | ||
{ 'file', 'nodeGraph' }, | ||
{ 'file', 'image', 'colorManaged' }, | ||
{ 'file', 'image' }, | ||
{ 'file', 'image', 'latLong', 'colorManaged' }, | ||
{ 'file', 'image', 'latLong' }, | ||
{ 'file', 'cache' }, | ||
{ 'file' } | ||
] | ||
``` | ||
|
||
Resulting in: | ||
|
||
```python | ||
policies = [ | ||
{}, | ||
{}, | ||
{}, | ||
{}, | ||
{}, | ||
{}, | ||
{ 'managed': {...} } | ||
] | ||
``` | ||
|
||
#### Pros | ||
|
||
- Conveys only what traits are supported to the host, allowing | ||
behaviour to be properly adapted to the manager's capabilities. | ||
|
||
#### Cons | ||
|
||
- No way to know that actually the manager was interested in managing | ||
all but one of the requested trait sets. | ||
- Host implementation is significantly more complicated. | ||
- No way to hint at any additional traits that may be resolvable | ||
outside the typing trait set. | ||
|
||
### Option 3 - Supported Traits Response | ||
|
||
The host should also include any additional traits that it may attempt | ||
to resolve in the future, e.g. if it supported the ability to customise | ||
the file format used for writing images, or cache lifetime by resolving | ||
a custom trait: | ||
|
||
```python | ||
traitSets =[ | ||
{ 'file', 'nodeGraph' }, | ||
{ 'file', 'image', 'colorManaged', 'fileFormatOptions' } | ||
{ 'file', 'image', 'latLong', 'colorManaged', 'fileFormatOptions' } | ||
{ 'file', 'cache', 'retention' } | ||
] | ||
``` | ||
|
||
The manager should respond as per Option 1, but in addition, imbue any | ||
of the queried traits that the manager is capable of resolving: | ||
|
||
```python | ||
if CacheTrait.kId in traitSet: | ||
continue | ||
if FileTrait.kId in traitSet: | ||
ManagerTrait.imbueTo(policy) | ||
FileTrait.imbueTo(policy) | ||
``` | ||
|
||
This would then look like the following: | ||
|
||
```python | ||
policies = [ | ||
{ 'managed': {...}, 'file': {} }, # Main document | ||
{ 'managed': {...}, 'file': {} }, # Generated images | ||
{ 'managed': {...}, 'file': {} }, # Generated maps | ||
{} # Temporary caches | ||
] | ||
``` | ||
|
||
This indicates that the manager would like to handle interactions for | ||
entities with all except the cache traits set, but it can only resolve | ||
the `file` trait for these. | ||
|
||
> Note: | ||
> We keep the concept of additionally imbuing the `managed` trait | ||
> (though it may seem superfluous, as an empty trait set is equivalent to | ||
> un-managed) as in practical use cases it may well have other properties | ||
> that cover topics such as exclusivity/etc. | ||
> There are also additional traits that may be imbued by the manager to | ||
> determine how it handles various aspects of the publishing process, | ||
> e.g. thumbnails. | ||
#### Pros | ||
|
||
- Hosts can query specific and precise trait sets, but the manager does | ||
not need to worry about all possible permutations. | ||
- Explicit communication of exact capabilities, so hosts and managers | ||
can suitably adapt behaviour. | ||
- Facilitates functional workflows where the result of `managementPolicy` | ||
can be passed as the requested trait set for `resolve`. | ||
|
||
#### Cons | ||
|
||
- Implementation in the manager and host may be slightly more involved | ||
than other options in some scenarios in order to parse the additional | ||
data in the response. | ||
|
||
## Outcome | ||
|
||
The `managementPolicy` mechanism should always be queried with the full | ||
trait set for any given entity specification, and any additional traits | ||
a host may attempt to resolve/publish for that type (if known). | ||
|
||
The response populated by a manager should include all | ||
resolvable/persisted traits from that set, along with any additional | ||
traits that describe the manager's behaviour. | ||
|
||
## Rationale | ||
|
||
Option 3 (chosen) provides the highest quality information to both hosts | ||
and managers, whilst keeping the additional programming overhead to a | ||
minimum. It allows both parties to adapt their business logic in an | ||
explicit and coordinated fashion. | ||
|
||
Option 1 conveys which trait sets may be managed, but not that some | ||
traits are unresolvable. | ||
|
||
Option 2 precludes the ability to differentiate between unmanaged trait | ||
sets and unresolvable component traits and so is not a viable option. |