app.storage.port¶
DB-neutral storage port of the catalog.
Services depend only on this module: the CatalogStoreProvider
protocol hands out CatalogStore instances bound to one unit of
work (one transaction). Everything crossing the port is a plain value
type from app.storage.values (re-exported here) or
app.domain; no ORM object leaks out.
Unit-of-work rules:
CatalogStoreProvider.unit_of_work()commits when the block exits normally and rolls back when it raises.CatalogStoreProvider.lock_registration()is a unit of work that first takes an exclusive per-registration lock, held until the unit of work ends. All writes for one registration (poll, push) run inside it, which makes concurrent workers and replicas safe.Conflicts are reported with domain errors from
app.errors(DecisionExistsError,CandidateExistsError,DeliveryExistsError); they leave the unit of work usable.
Public API:
every value type of
app.storage.valuesandapp.storage.errata_values(re-exported here)protocols
CatalogStore,CatalogStoreProvider
- class app.storage.port.CatalogStore(*args, **kwargs)¶
Bases:
ProtocolCatalog operations inside one unit of work.
- sync_registrations(registrations)¶
Make stored registrations match the configuration.
Listed registrations are inserted or updated; an invalid one gets status
disabled, and a re-enabled one leavesdisabledfornever. Registrations missing from the list are disabled, never deleted.- Parameters:
registrations (
Sequence[RegistrationConfig]) – All configured registrations.- Return type:
- get_registration(source_id)¶
Fetch one registration.
- Parameters:
source_id (
str) – Registration id.- Return type:
- Returns:
The registration, or
None.
- list_registrations()¶
List all registrations, enabled or not, ordered by id.
- Return type:
- Returns:
The registrations.
- update_poll_status(source_id, status, attempted_at, error=None)¶
Record the outcome of a poll.
last_success_atis set to attempted_at only forPollStatus.OK.- Parameters:
source_id (
str) – Registration id.status (
PollStatus) – Poll outcome.attempted_at (
datetime) – When the poll started.error (
JsonValue) – Error details,Noneon success.
- Return type:
- put_revision(digest, content)¶
Store a snapshot unless it exists (snapshots are immutable).
- get_revision(digest)¶
Fetch a snapshot.
- upsert_published(record)¶
Insert or replace the published row at a location.
Keyed by
(source_id, project, path).- Parameters:
record (
RecordWrite) – Row content.- Return type:
- Returns:
The outcome.
- upsert_candidate(record)¶
Insert or replace a candidate row.
Keyed by
(source_id, project, record_key, ref).- Parameters:
record (
RecordWrite) – Row content.- Return type:
- Returns:
The outcome.
- create_candidate(record)¶
Insert a candidate row only if its key is free.
- Parameters:
record (
RecordWrite) – Row content.- Return type:
- Returns:
The outcome (always
created).- Raises:
app.errors.CandidateExistsError – If the candidate
(source_id, project, record_key, ref)exists.
- get_record(record_id)¶
Fetch one record row.
- Parameters:
record_id (
UUID) – Record id.- Return type:
- Returns:
The row, or
None.
- list_change_tokens(source_id, project=None)¶
List the stored change state of published files.
- Parameters:
- Return type:
- Returns:
Entries ordered by project and path.
- delete_published(record_ids)¶
Delete published rows (reconciliation). Candidates are kept.
- Parameters:
record_ids (
Collection[UUID]) – Ids to delete.- Return type:
- Returns:
Number of deleted rows.
- list_identity_siblings(identity)¶
List every row (published and candidates) of an identity.
- Parameters:
identity (
Identity) – Logical identity.- Return type:
- Returns:
Rows, published first, then by ref and path.
- list_relationship_summaries(kind=RecordState.PUBLISHED)¶
List relationship summaries, keyed by
str(record id).- Parameters:
kind (
RecordState|None) – Restrict to one state;Nonemeans all rows.- Return type:
- Returns:
One summary per row.
- list_relationship_candidates(self_uuid, link_targets)¶
List published rows that can affect one record’s relationships.
A bounded alternative to
list_relationship_summaries( RecordState.PUBLISHED)for a single detail request: seeapp.storage.postgres.records.list_relationship_candidates()for exactly which rows this returns and why the result is equivalent for that one record’sview().- Parameters:
self_uuid (
UUID) – The viewed record’s own UUID.link_targets (
Collection[UUID]) – UUIDs the viewed record’s ownupdates,obsoletesandcorrectslinks target.
- Return type:
- Returns:
The matching published rows.
- list_errata_for(target_uuid)¶
List the erratum rows whose
correctslink is target_uuid.Includes published rows and candidates (proposed errata), from every registration and project; resolving which decision an erratum applies to when the UUID is shared is up to the caller (
app.domain.relationshipsrules). Decisions are never returned.- Parameters:
target_uuid (
UUID) – UUID of the corrected decision.- Return type:
- Returns:
Published rows first, then by source, project, path, ref and id.
- list_published_by_uuid(uuids)¶
List the published rows holding any of uuids, with titles.
One query for a whole search page (erratum hits’ targets).
- Parameters:
uuids (
Collection[UUID]) – Authored UUIDs.- Return type:
- Returns:
One entry per matching published row of any record kind (decisions and errata), with its full links.
- list_facets()¶
Count decision rows per
(source_id, project), for filter UIs.Counts include both published and candidate rows, but not errata (matching the default
record_type=decisionsearch).- Return type:
- Returns:
One entry per non-empty
(source_id, project)pair, ordered by source id then project.
- search(query, filters, page, page_size, *, policy, sort=SearchSort.RELEVANCE)¶
Full-text search with filters and bounded pagination.
Hits are ordered by sort (see
SearchSort); the default ranks by relevance when query is given, else orders by title.- Parameters:
query (
str|None) – Free text (titles, bodies, UUIDs, paths); blank orNonematches everything.filters (
SearchFilters) – Filters.page (
int) – 1-based page number.page_size (
int) – Page size, 1 toMAX_PAGE_SIZE.policy (
Policy|None) – The configured policy (Nonewhen missing or invalid), used for approval states.sort (
SearchSort) – Result order;relevancewithout a query falls back totitle.
- Return type:
- Returns:
The page.
- Raises:
ValueError – If page or page_size is out of bounds.
- append_decision(decision)¶
Append a decision event; the server sets id and timestamp.
- Parameters:
decision (
NewDecision) – The decision.- Return type:
- Returns:
The stored event.
- Raises:
app.errors.DecisionExistsError – If the identity already has a decision for the digest.
- list_decisions(identity)¶
List all decision events of an identity, any digest.
- Parameters:
identity (
Identity) – Logical identity.- Return type:
- Returns:
Events, oldest first.
- list_decisions_for(identities)¶
List all decision events of several identities in one query.
- Parameters:
identities (
Collection[Identity]) – Logical identities.- Return type:
- Returns:
Events of all of them, oldest first; group them by
identity.
- start_intake_run(source_id, kind, *, identity=None, delivery_id=None)¶
Record the start of an intake run.
- Parameters:
source_id (
str) – Registration id as requested.kind (
IntakeKind) – Poll or push.identity (
JsonValue) – Who triggered the run (no secrets).
- Return type:
- Returns:
The running run.
- Raises:
app.errors.DeliveryExistsError – If delivery_id was already used for source_id.
- finish_intake_run(run_id, status, *, counts=None, errors=None)¶
Record the end of an intake run.
- Parameters:
run_id (
UUID) – Run id.status (
IntakeStatus) – Final status.counts (
JsonValue) – Outcome counters.errors (
JsonValue) – Error details.
- Return type:
- Returns:
The finished run.
- Raises:
LookupError – If the run does not exist.
- class app.storage.port.CatalogStoreProvider(*args, **kwargs)¶
Bases:
ProtocolHands out
CatalogStoreinstances per unit of work.- unit_of_work()¶
Open a unit of work (one transaction).
- Return type:
- Returns:
A context manager yielding the store; it commits on normal exit and rolls back on error.
- lock_registration(source_id)¶
Open a unit of work holding the registration’s exclusive lock.
The lock is taken before the store is yielded and released when the unit of work commits or rolls back. Other units of work for the same registration wait; other registrations are unaffected.
- Parameters:
source_id (
str) – Registration id.- Return type:
- Returns:
A context manager yielding the store.
- class app.storage.port.ChangeTokenEntry(*, id, project, path, change_token, digest)¶
Bases:
objectStored change state of one published file.
- Parameters:
- class app.storage.port.DecisionEvent(*, identity, adr_uuid, digest, action, actor_issuer, actor_subject, actor_display, actor_email, comment, policy_id, policy_version, provenance=dict(), id, created_at)¶
Bases:
NewDecisionA stored, append-only decision event.
- as_view()¶
Convert to the domain view used by approval evaluation.
- Return type:
- Returns:
The event view.
- class app.storage.port.ErratumRow(*, id, kind, source_id, project, path, ref, adr_uuid, record_key, digest, title, erratum, updated_at, issues)¶
Bases:
objectOne erratum row (published or candidate) correcting a decision.
- 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.record_key (
str) – Identity key of the erratum.digest (
str) – Current digest.title (
str) – Display title.erratum (
StoredErratum|None) – Stored content;Noneonly for a row ingested before content was stored (the next ingest fills it).updated_at (
datetime) – When the content digest last changed.
- kind: RecordState¶
- erratum: StoredErratum | None¶
- class app.storage.port.FacetEntry(*, source_id, project, count)¶
Bases:
objectRow count for one
(source_id, project)pair.Used to populate the source/project filter select in the UI (
app.storage.port.CatalogStore.list_facets()); counts include both published and candidate decision rows, never errata.- Parameters:
- class app.storage.port.IntakeKind(*values)¶
Bases:
StrEnumHow content entered the catalog.
- POLL = 'poll'¶
- PUSH = 'push'¶
- class app.storage.port.IntakeRun(*, id, source_id, kind, identity, delivery_id, started_at, finished_at, status, counts, errors)¶
Bases:
objectOne poll or push intake run.
- Parameters:
id (
UUID) – Run id.source_id (
str) – Registration id as requested.kind (
IntakeKind) – Poll or push.identity (
JsonValue) – Who triggered the run (no secrets).delivery_id (
str|None) – Client-supplied push delivery id, if any.started_at (
datetime) – Start time.finished_at (
datetime|None) – End time,Nonewhile running.status (
IntakeStatus) – Run status.counts (
JsonValue) – Outcome counters.errors (
JsonValue) – Error details.
- kind: IntakeKind¶
- status: IntakeStatus¶
- class app.storage.port.IntakeStatus(*values)¶
Bases:
StrEnumStatus of one intake run.
- RUNNING = 'running'¶
- OK = 'ok'¶
- PARTIAL = 'partial'¶
- FAILED = 'failed'¶
- class app.storage.port.LinkTarget(*, summary, title)¶
Bases:
objectA published row that a link may resolve to, with its title.
Used to label erratum search hits (“Erratum for <title>”) without one query per hit.
- Parameters:
summary (
RecordSummary) – Relationship summary, keyed bystr(record id).title (
str) – Display title of the row.
- summary: RecordSummary¶
- class app.storage.port.NewDecision(*, identity, adr_uuid, digest, action, actor_issuer, actor_subject, actor_display, actor_email, comment, policy_id, policy_version, provenance=dict())¶
Bases:
objectA decision to append.
- Parameters:
identity (
Identity) – Logical identity decided on.adr_uuid (
UUID) – The record UUID.digest (
str) – Digest of the decided content.action (
DecisionAction) – Accepted or rejected.actor_issuer (
str) – Reviewer token issuer.actor_subject (
str) – Reviewer token subject.actor_display (
str|None) – Reviewer display name, if known.actor_email (
str|None) – Reviewer verified email, if known.policy_id (
str) – Applied policy id.policy_version (
int) – Applied policy version.provenance (
JsonObject) – Record id, kind, ref, path and source URL at decision time.
- action: DecisionAction¶
- provenance: JsonObject¶
- class app.storage.port.PollStatus(*values)¶
Bases:
StrEnumOutcome of the latest poll of a registration.
- NEVER = 'never'¶
- OK = 'ok'¶
- PARTIAL = 'partial'¶
- FAILED = 'failed'¶
- DISABLED = 'disabled'¶
- class app.storage.port.RecordState(*values)¶
Bases:
StrEnumLifecycle state of a stored record row.
- PUBLISHED = 'published'¶
- CANDIDATE = 'candidate'¶
- class app.storage.port.RecordWrite(*, source_id, project, path, ref, adr_uuid, record_key, digest, change_token, metadata, title, title_source, decision_date, decision_date_inferred, record_kind, links, rendered_html, issues, source_url=None, author=None, erratum=None)¶
Bases:
objectEverything ingest writes for one record row.
The revision for
digestmust have been stored first (app.storage.port.CatalogStore.put_revision()).- Parameters:
source_id (
str) – Owning registration id.project (
str) – Owning project path.path (
str) – File path inside the project.ref (
str) – Branch/ref the content came from.adr_uuid (
UUID|None) – Authored UUID,Noneif missing or invalid.record_key (
str) – Identity key (app.domain.values.record_key()).digest (
str) – Digest string of the current content.change_token (
str|None) – Source change token (Nonefor pushes).metadata (
JsonObject) – Parsed frontmatter.title (
str) – Display title.title_source (
TitleSource) – Where the title came from.decision_date_inferred (
bool) – Whether the date is only inferred from the filename.record_kind (
RecordKind) – Decision or erratum.links (
Links) – Validated outbound links.rendered_html (
str) – Sanitized HTML rendering of the body.source_url (
str|None) – Link to the content at the source, if any.erratum (
StoredErratum|None) – Rendered erratum content;Nonefor decisions.
- metadata: JsonObject¶
- title_source: TitleSource¶
- record_kind: RecordKind¶
- erratum: StoredErratum | None¶
- class app.storage.port.Registration(*, id, type, config, enabled, config_error, last_attempt_at, last_success_at, last_status, last_error)¶
Bases:
objectA stored source registration with its poll status.
- Parameters:
id (
str) – Stable registration id.type (
str) – Source type.config (
JsonObject) – Type-specific settings, secrets excluded.enabled (
bool) – Whether the registration may be polled / pushed to.config_error (
str|None) – Why the registration is disabled, if invalid.last_attempt_at (
datetime|None) – Start of the latest poll attempt.last_success_at (
datetime|None) – Start of the latest fully successful poll.last_status (
PollStatus) – Outcome of the latest poll.last_error (
JsonValue) – Error details of the latest poll, if any.
- config: JsonObject¶
- last_status: PollStatus¶
- class app.storage.port.RegistrationConfig(*, id, type, config, enabled=True, config_error=None)¶
Bases:
objectOne source registration as read from
catalog.yaml.- Parameters:
- config: JsonObject¶
- class app.storage.port.Revision(*, digest, content, created_at)¶
Bases:
objectAn immutable, content-addressed snapshot.
- Parameters:
- class app.storage.port.SearchFilters(*, source_id=None, project=None, kind=None, needs_approval=False, record_kind=None)¶
Bases:
objectSearch filters;
None/Falsemeans “no filter”.- Parameters:
kind (
RecordState|None) – Published or candidate.needs_approval (
bool) – Only records whose approval state needs approval (app.domain.approval.evaluate()).record_kind (
RecordKind|None) – Only decisions or only errata.
- kind: RecordState | None¶
- record_kind: RecordKind | None¶
- class app.storage.port.SearchItem(*, id, kind, source_id, project, path, ref, adr_uuid, record_key, digest, title, record_kind, decision_date, decision_date_inferred, issues, approval_state, corrects=None)¶
Bases:
objectOne search hit.
- 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.record_key (
str) – Identity key.digest (
str) – Current digest.title (
str) – Display title.record_kind (
RecordKind) – Decision or erratum.decision_date_inferred (
bool) – Whether the date is inferred.approval_state (
ApprovalStateCode) – Approval state of the current digest, computed by the store with the same rules asapp.domain.approval.evaluate().corrects (
UUID|None) – UUID an erratum corrects (Nonefor decisions).
- kind: RecordState¶
- record_kind: RecordKind¶
- approval_state: ApprovalStateCode¶
- class app.storage.port.SearchPage(*, items, total, page, page_size)¶
Bases:
objectOne page of search results.
- Parameters:
- items: tuple[SearchItem, ...]¶
- class app.storage.port.SearchSort(*values)¶
Bases:
StrEnumResult order of
app.storage.port.CatalogStore.search().Every order ends with the lower-cased title and the record id, so pages are stable even when the leading key ties.
relevance: text rank, best first; without a text query it is the same astitle.title: lower-cased title A-Z.recent:record.updated_at(when the content digest last changed), newest first.
- RELEVANCE = 'relevance'¶
- TITLE = 'title'¶
- RECENT = 'recent'¶
- class app.storage.port.StoredErratum(*, type, section, reported_by, reported_date, original_html, corrected_html, notes_html)¶
Bases:
objectThe stored content of one erratum record.
- Parameters:
type (
ErratumType|None) – Erratum type,Noneif missing or invalid.section (
str|None) – Where in the decision the error is, if given.reported_by (
str|None) – Free-text reporter; informational only, never an identity.reported_date (
date|None) – Authored report date, if valid.original_html (
str|None) – Sanitized HTML of “Original text”, if any.corrected_html (
str) – Sanitized HTML of “Corrected text”; empty when the section is missing.notes_html (
str|None) – Sanitized HTML of the notes, if any.
- type: ErratumType | None¶
- class app.storage.port.StoredRecord(*, source_id, project, path, ref, adr_uuid, record_key, digest, change_token, metadata, title, title_source, decision_date, decision_date_inferred, record_kind, links, rendered_html, issues, source_url=None, author=None, erratum=None, id, kind, previous_digest, first_seen_at, updated_at, last_seen_at)¶
Bases:
RecordWriteA stored record row.
- Parameters:
id (
UUID) – Surrogate id used in URLs.kind (
RecordState) – Published or candidate.previous_digest (
str|None) – Digest before the latest content change.first_seen_at (
datetime) – When the row was created.updated_at (
datetime) – When the content digest last changed.last_seen_at (
datetime) – When ingest last wrote the row.
- kind: RecordState¶