app.domain.relationships

Relationship resolution across a set of record summaries.

Outbound links are authored by UUID. A link from record S to UUID U resolves to the record with that UUID, preferring, in order:

  1. the same project of the same registration (same_project),

  2. the same registration (same_registration),

  3. any registration (global).

Rows of one logical identity (the published row and its candidates on other refs) are revisions of one decision, not separate targets: each identity is represented by its published row, else by its most recently updated candidate. If several identities (or several published rows of one identity) share the best tier the link is ambiguous: it is left unresolved and reported (ambiguous_target); nothing is picked arbitrarily. An unknown UUID yields missing_target. A record never resolves a link to itself or to another revision of itself.

From the resolved links the index derives, for one record:

  • inbound links: updated_by / obsoleted_by;

  • errata: erratum records whose corrects link (authored as erratum-for) resolves to the record. The erratum’s own outbound corrects link resolves like any other link;

  • display status: obsoleted if anything obsoletes it, else updated if anything updates it, else active;

  • duplicate_uuid issues: an error when another published file of the same identity (same registration, project and UUID) uses the UUID (only for a published record), a warning when other identities use it. Candidates of the record’s own identity are revisions and are never reported.

Records without a valid UUID take no part in UUID relationships.

Callers pass one summary per stored row: normally the published rows plus, optionally, candidate rows (published=False).

Public API: DisplayStatus, InboundType, Resolution, RecordSummary, ResolvedLink, InboundLink, RelationshipView, RelationshipIndex, resolve_relationships().

class app.domain.relationships.DisplayStatus(*values)

Bases: StrEnum

Display status derived from inbound lifecycle links.

ACTIVE = 'active'
UPDATED = 'updated'
OBSOLETED = 'obsoleted'
class app.domain.relationships.InboundType(*values)

Bases: StrEnum

Reverse names of the updates / obsoletes links.

UPDATED_BY = 'updated_by'
OBSOLETED_BY = 'obsoleted_by'
class app.domain.relationships.Resolution(*values)

Bases: StrEnum

Tier at which an outbound link was resolved.

SAME_PROJECT = 'same_project'
SAME_REGISTRATION = 'same_registration'
GLOBAL = 'global'
class app.domain.relationships.RecordSummary(key, identity, adr_uuid, links=Links(updates=(), obsoletes=(), corrects=None), record_kind=RecordKind.DECISION, path='', published=True, updated_at=None)

Bases: object

The relationship-relevant facts about one stored record row.

Parameters:
  • key (str) – Caller-chosen unique row key (e.g. the record id).

  • identity (Identity) – Logical identity of the record.

  • adr_uuid (UUID | None) – Authored UUID, None if missing or invalid.

  • links (Links) – Validated outbound links.

  • record_kind (RecordKind) – Decision or erratum.

  • path (str) – File path, used only in messages.

  • published (bool) – True for a published row, False for a candidate (a revision on another ref).

  • updated_at (datetime | None) – When the row’s content last changed; picks the representative candidate of an unpublished identity.

key: str
identity: Identity
adr_uuid: UUID | None
record_kind: RecordKind
path: str
published: bool
updated_at: datetime | None
property label: str

Human-readable location for messages.

Returns:

<source>/<project>/<path> or the row key.

Bases: object

One outbound link and how it resolved.

Parameters:
  • link_type (LinkType) – The authored relationship.

  • target_uuid (UUID) – The authored target UUID.

  • target_key (str | None) – Row key of the resolved target, or None.

  • resolution (Resolution | None) – Tier used, or None when unresolved.

  • candidates (tuple[str, ...]) – Row keys of equally good targets when ambiguous.

target_uuid: UUID
target_key: str | None
resolution: Resolution | None
candidates: tuple[str, ...]
property ambiguous: bool

Tell whether several targets matched at the best tier.

Returns:

True if the link is ambiguous.

Bases: object

A link from another record to this one.

Parameters:
  • link_type (InboundType) – updated_by or obsoleted_by.

  • source_key (str) – Row key of the linking record.

source_key: str
class app.domain.relationships.RelationshipView(key, outbound, inbound, errata, status, issues)

Bases: object

All relationship facts for one record.

Parameters:
  • key (str) – Row key of the record.

  • outbound (tuple[ResolvedLink, ...]) – Resolved outbound links in authored order.

  • inbound (tuple[InboundLink, ...]) – Inbound updated_by / obsoleted_by links.

  • errata (tuple[str, ...]) – Row keys of errata correcting this record.

  • status (DisplayStatus) – Derived display status.

  • issues (tuple[Issue, ...]) – missing_target, ambiguous_target and duplicate_uuid issues for this record.

key: str
outbound: tuple[ResolvedLink, ...]
inbound: tuple[InboundLink, ...]
errata: tuple[str, ...]
status: DisplayStatus
issues: tuple[Issue, ...]
inbound_keys(link_type)

List the row keys of inbound links of one type.

Parameters:

link_type (InboundType) – The inbound type to select.

Return type:

tuple[str, ...]

Returns:

Source row keys, e.g. the records obsoleting this one.

Find the first outbound link of one type (e.g. corrects).

Parameters:

link_type (LinkType) – The relationship to select.

Return type:

ResolvedLink | None

Returns:

The link, or None if the record has none.

class app.domain.relationships.RelationshipIndex(summaries)

Bases: object

Pre-computed relationships for a set of record summaries.

Build it once per set of summaries, then call view() per record. The index is not modified after construction.

view(key)

Compute the relationship view of one record.

Parameters:

key (str) – Row key of the record.

Return type:

RelationshipView

Returns:

Outbound, inbound, errata, status and issues.

Raises:

KeyError – If key is not in the index.

app.domain.relationships.resolve_relationships(summaries, key)

Compute the relationship view of one record in a single call.

Use RelationshipIndex directly when viewing many records.

Parameters:
  • summaries (Iterable[RecordSummary]) – All summaries to resolve against.

  • key (str) – Row key of the record of interest.

Return type:

RelationshipView

Returns:

The relationship view.

Raises:

KeyError – If key is not among summaries.