app.services.record_detail¶
Read-only record detail assembly.
get_record_detail() takes a
CatalogStore (already inside a unit of work opened by the caller) plus
plain values, and returns a plain RecordDetail; nothing here
imports FastAPI or a source adapter. Routers convert it with
RecordDetailOut.model_validate(value).
The relationship part comes from
app.services.record_relationships, the errata part from
app.services.errata_view, the approval part from
app.services.approval_view; this module adds metadata,
provenance, freshness, identity siblings and legacy sign-offs.
Public API: RecordMetadata, RecordProvenance,
RecordFreshness, SiblingInfo, RecordDetail,
get_record_detail().
- class app.services.record_detail.RecordDetail(*, metadata, issues, rendered_html, provenance, freshness, outbound_links, inbound_links, errata, errata_summary, erratum, erratum_for, status, siblings, legacy_signoff_unverified, approval)¶
Bases:
objectEverything the record detail page shows.
- Parameters:
metadata (
RecordMetadata) – Identity and authored metadata.issues (
tuple[Issue,...]) – Stored validation issues followed by read-time relationship issues (missing_target,ambiguous_target,duplicate_uuid).rendered_html (
str) – Sanitized HTML rendering of the body.provenance (
RecordProvenance) – Where the content came from.freshness (
RecordFreshness) – Freshness of the owning registration.outbound_links (
tuple[OutboundLinkInfo,...]) – Resolved outbound links, authored order.inbound_links (
tuple[InboundLinkInfo,...]) – Inboundupdated_by/obsoleted_bylinks.errata (
tuple[ErratumInfo,...]) – Errata correcting this record (published first, then candidates), each with its own approval state.errata_summary (
ErrataSummary) – Counts for the top notice.erratum (
ErratumContentInfo|None) – For an erratum, its structured content.erratum_for (
ErratumForInfo|None) – For an erratum, the decision it corrects.status (
DisplayStatus) – Derived display status.siblings (
tuple[SiblingInfo,...]) – Every row (published and candidates) of this record’s identity, including this one.legacy_signoff_unverified (
tuple[str,...]) – Unverified legacysigned-off-byvalues; never an approval.approval (
ApprovalSummary) – Approval state, policy summary and history.
- metadata: RecordMetadata¶
- provenance: RecordProvenance¶
- freshness: RecordFreshness¶
- outbound_links: tuple[OutboundLinkInfo, ...]¶
- inbound_links: tuple[InboundLinkInfo, ...]¶
- errata: tuple[ErratumInfo, ...]¶
- errata_summary: ErrataSummary¶
- erratum: ErratumContentInfo | None¶
- erratum_for: ErratumForInfo | None¶
- status: DisplayStatus¶
- siblings: tuple[SiblingInfo, ...]¶
- approval: ApprovalSummary¶
- class app.services.record_detail.RecordFreshness(*, last_attempt_at, last_success_at, last_status, stale, intake)¶
Bases:
objectFreshness of a record’s owning registration.
- Parameters:
last_attempt_at (
datetime|None) – Start of the registration’s latest poll attempt.last_success_at (
datetime|None) – Start of its latest fully successful poll.last_status (
PollStatus) – Outcome of its latest poll.stale (
bool) – Whether the indexed content may not reflect the current published source (seeis_stale()).intake (
tuple[IntakeKind,...]) – The owning registration’s configured intake mechanisms (poll,push, or both); empty when the registration is unknown. A registration withoutpollintake is never polled, so staleness-by-polling does not apply to it.
- last_status: PollStatus¶
- intake: tuple[IntakeKind, ...]¶
- class app.services.record_detail.RecordMetadata(*, id, adr_uuid, decision_date, decision_date_inferred, kind, record_kind, title, title_source, digest, previous_digest)¶
Bases:
objectIdentity and authored metadata of one record.
- Parameters:
id (
UUID) – Record id.decision_date_inferred (
bool) – Whether the date is only inferred from the filename.kind (
RecordState) – Published or candidate.record_kind (
RecordKind) – Decision or erratum.title (
str) – Display title.title_source (
TitleSource) – Where the title came from.digest (
str) – Canonical digest of the current content.previous_digest (
str|None) – Digest before the latest content change.
- kind: RecordState¶
- record_kind: RecordKind¶
- title_source: TitleSource¶
- class app.services.record_detail.RecordProvenance(*, source_id, project, path, ref, source_url, updated_at)¶
Bases:
objectWhere a record’s content came from.
- Parameters:
source_id (
str) – Registration id.project (
str) – Project path.path (
str) – File path inside the project.ref (
str) – Branch/ref the content came from.source_url (
str|None) – Link to the content at the source, if any.updated_at (
datetime) – When this row’s content digest last changed (for a candidate, effectively when it was last submitted).
- class app.services.record_detail.SiblingInfo(*, id, kind, source_id, project, path, ref, digest, title, decision_date, decision_date_inferred, approval_state, approvable)¶
Bases:
objectOne published or candidate row sharing a record’s logical identity.
- Parameters:
id (
UUID) – Record id.kind (
RecordState) – Published or candidate.source_id (
str) – Registration id.project (
str) – Project path.path (
str) – File path inside the project.ref (
str) – Branch/ref of the content.digest (
str) – Content digest.title (
str) – Display title.decision_date_inferred (
bool) – Whether the date is only inferred.approval_state (
ApprovalStateCode) – Approval state of this sibling’s digest.approvable (
bool) – Whether this sibling’s content can be decided.
- kind: RecordState¶
- approval_state: ApprovalStateCode¶
- app.services.record_detail.get_record_detail(store, record_id, *, policy, policy_status, now, stale_after_minutes, reviewer=None, config_sources=())¶
Assemble everything the record detail page shows.
- Parameters:
store (
CatalogStore) – Store of the caller’s unit of work.record_id (
UUID) – Record id.policy (
Policy|None) – The configured policy, orNoneif missing or invalid.policy_status (
PolicyStatus) – Configuration status of the policy.now (
datetime) – The current time (injected for testability).stale_after_minutes (
int) – Configured staleness threshold.reviewer (
Reviewer|None) – The caller, forapproval.can_decide;Nonemeans nobody can decide.config_sources (
Sequence[SourceRegistration]) – The current configuration’s registrations, forfreshness.intake(empty for a registration removed fromcatalog.yaml).
- Return type:
- Returns:
The detail, or
Noneif the record does not exist.