Repository navigation
BE-847: atlas: store hydration and the generation runtime #9711
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
indietyp
merged 3 commits into
bm/be-846-atlas-delta-feed-placement-and-projector
from
bm/be-847-atlas-store-hydration-and-the-generation-runtime
Sep 17, 2026
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or 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,23 @@ | ||
| //! Slot ID domains for one hydration read. | ||
| //! | ||
| //! [`NodeSlot`] and [`EdgeSlot`] index a response's delivered nodes and edges in delivered order, | ||
| //! so hydration, assembly and encoding all address the same point or link by the same number | ||
| //! without re-deriving it from an entity id. | ||
|
|
||
| hashql_core::id::newtype! { | ||
| /// A reference to a delivered node by its slot in one response's delivered order. | ||
| /// | ||
| /// Slots are dense and zero-based over one response's delivered nodes. Every node detail | ||
| /// column aligns to this domain. A slot is valid only against the response that delivered it, | ||
| /// because two responses share no slot vocabulary. | ||
| pub(crate) struct NodeSlot(u32) | ||
| } | ||
|
|
||
| hashql_core::id::newtype! { | ||
| /// A reference to a delivered edge by its slot in one response's edge order. | ||
| /// | ||
| /// Slots are dense and zero-based over one response's delivered edges. Every link detail | ||
| /// column aligns to this domain. A slot is valid only against the response that delivered it, | ||
| /// because two responses share no slot vocabulary. | ||
| pub(crate) struct EdgeSlot(u32) | ||
| } |
This file contains hidden or 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,123 @@ | ||
| //! Live properties and type URLs for locate documents. | ||
| //! | ||
| //! Each requested identity retains its slot when the store no longer serves it. | ||
|
|
||
| use alloc::sync::Arc; | ||
|
|
||
| use error_stack::Report; | ||
| use hashql_core::id::{IdSlice, IdVec}; | ||
| use type_system::ontology::VersionedUrl; | ||
|
|
||
| use super::{EdgeSlot, NodeSlot, client::HydrateError, scalar::ScalarProperties}; | ||
| use crate::{postgres::id::ArchivedEntityId, serve::visibility::VisibilityActor}; | ||
|
|
||
| /// One requested entity and the details the store still serves for it. | ||
| #[derive(Debug, PartialEq)] | ||
| pub(crate) struct LocateEntity<T> { | ||
| pub identity: ArchivedEntityId, | ||
| pub details: Option<T>, | ||
| } | ||
|
|
||
| impl<T> LocateEntity<T> { | ||
| /// Builds an entity requested by `identity`, with no details resolved yet. | ||
| pub(crate) const fn new(identity: ArchivedEntityId) -> Self { | ||
| Self { | ||
| identity, | ||
| details: None, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// The live detail for one delivered node: its direct-type versioned URLs. | ||
| #[derive(Debug, PartialEq)] | ||
| pub(crate) struct LocateNode { | ||
| /// Direct-type versioned URLs in canonical order. | ||
| pub type_urls: Vec<VersionedUrl>, | ||
| } | ||
|
|
||
| /// One entity's resolved scalar properties and whether they are its whole deliverable set. | ||
| #[derive(Debug, PartialEq)] | ||
| pub(crate) struct LocateProperties { | ||
| pub values: ScalarProperties, | ||
| /// Whether the map contains the entity's whole deliverable property set. | ||
| pub complete: bool, | ||
| } | ||
|
|
||
| /// The live detail for one delivered link: its capped direct types and scalar properties. | ||
| #[derive(Debug, PartialEq)] | ||
| pub(crate) struct LocateLink { | ||
| /// Capped direct-type versioned URLs in canonical order. | ||
| pub type_urls: Vec<VersionedUrl>, | ||
| /// Whether the list contains the link's whole direct-type set. | ||
| pub type_urls_complete: bool, | ||
| pub properties: LocateProperties, | ||
| } | ||
|
|
||
| /// One locate request's live-detail slots. | ||
| /// | ||
| /// The slots arrive with the caps and the actor a [`LocateResolver`] resolves them under. | ||
| #[derive(Debug)] | ||
| pub(crate) struct LocateRequest<'doc> { | ||
| /// The resolved actor the store masks properties for. | ||
| pub actor: VisibilityActor, | ||
| /// Delivered nodes, source first. | ||
| pub nodes: &'doc mut IdSlice<NodeSlot, LocateEntity<LocateNode>>, | ||
| /// Delivered link entities, ascending identity bytes. | ||
| pub links: &'doc mut IdSlice<EdgeSlot, LocateEntity<LocateLink>>, | ||
| /// Most properties the source's map delivers. | ||
| pub properties: u32, | ||
| /// Most direct-type URLs each link delivers. | ||
| pub link_type_ids: u32, | ||
| /// Most properties each link's map delivers. | ||
| pub link_properties: u32, | ||
| } | ||
|
|
||
| /// The resolved live detail for one locate document. | ||
| /// | ||
| /// It holds every requested node and link, plus the source's own properties. | ||
| #[derive(Debug, PartialEq)] | ||
| pub(crate) struct LocateResponse { | ||
| pub nodes: IdVec<NodeSlot, LocateEntity<LocateNode>>, | ||
| pub links: IdVec<EdgeSlot, LocateEntity<LocateLink>>, | ||
| pub source_properties: Option<LocateProperties>, | ||
| } | ||
|
|
||
| /// Live detail resolution within the supplied entity slots. | ||
| pub(crate) trait LocateResolver { | ||
| /// Fills the requested slots and returns the source's capped properties. | ||
| /// | ||
| /// Unavailable entities remain unresolved. | ||
| /// | ||
| /// # Errors | ||
| /// | ||
| /// Returns [`HydrateError`] when a store read fails. Errors may leave partially populated | ||
| /// slots. Discard those results. Reset all slot details to [`None`] before retrying. | ||
| fn resolve( | ||
| &self, | ||
| request: LocateRequest<'_>, | ||
| ) -> Result<Option<LocateProperties>, Report<HydrateError>>; | ||
| } | ||
|
|
||
| impl<T> LocateResolver for &T | ||
| where | ||
| T: LocateResolver, | ||
| { | ||
| fn resolve( | ||
| &self, | ||
| request: LocateRequest<'_>, | ||
| ) -> Result<Option<LocateProperties>, Report<HydrateError>> { | ||
| T::resolve(self, request) | ||
| } | ||
| } | ||
|
|
||
| impl<T> LocateResolver for Arc<T> | ||
| where | ||
| T: LocateResolver, | ||
| { | ||
| fn resolve( | ||
| &self, | ||
| request: LocateRequest<'_>, | ||
| ) -> Result<Option<LocateProperties>, Report<HydrateError>> { | ||
| T::resolve(self, request) | ||
| } | ||
| } |
This file contains hidden or 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,43 @@ | ||
| //! Request-time store reads for the detail a response's trailer carries. | ||
| //! | ||
| //! Hydration is graph-store enrichment performed while the request runs: an entity's direct-type | ||
| //! URLs and its scalar property values, read from the live store. The edges and locate trailers | ||
| //! hydrate. A tile trailer does not, because its labels and icons come from the publication the | ||
| //! request captured, as positions do. | ||
| //! | ||
| //! Hydration is one of the two reasons a detailed response is not reusable as an immutable | ||
| //! generation tile, and the two differ in the data lifetime a value follows. A captured label | ||
| //! follows the epoch the caller's scope resolved against, and moves when that scope re-resolves - | ||
| //! which is why even a tile trailer, reading no store, is not stable across requests. A | ||
| //! request-time read follows the read instead, and can observe an edition later than the one the | ||
| //! captured scope holds. | ||
| //! | ||
| //! [`LocateResolver`] fills one locate document's node and link slots and returns the source's | ||
| //! capped properties, reading both against the live temporal axes. [`TypeUrlResolver`] resolves | ||
| //! ontology type uuids to versioned URLs for the edges trailer, a lookup with no temporal axes | ||
| //! and no entity edition in it. A uuid derives from the versioned URL it names, which holds the | ||
| //! pair steady once resolved. [`CachedTypeUrlResolver`] answers a repeat from its retained result. | ||
| //! [`GraphDatabaseClient`] answers both resolvers against the serving store pool. [`NodeSlot`] | ||
| //! and [`EdgeSlot`] are the slot domains a resolver fills in place, and [`scalar`] is the value | ||
| //! shape a property read can take. | ||
| //! | ||
| //! The module also holds [`visibility::visibility_proof`], which resolves the rows an actor may | ||
| //! receive before any document gathers from the captured scene. | ||
|
|
||
| mod client; | ||
| mod columns; | ||
| mod locate; | ||
| pub(crate) mod scalar; | ||
| mod statements; | ||
| mod type_urls; | ||
| pub(crate) mod visibility; | ||
|
|
||
| // Locate document fixtures construct typed resolver answers. | ||
| #[cfg(test)] | ||
| pub(crate) use self::locate::{LocateLink, LocateNode, LocateProperties}; | ||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| pub(crate) use self::{ | ||
| client::{GraphDatabaseClient, HydrateError}, | ||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| columns::{EdgeSlot, NodeSlot}, | ||
| locate::{LocateEntity, LocateRequest, LocateResolver, LocateResponse}, | ||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| type_urls::{CachedTypeUrlResolver, TypeUrlResolver}, | ||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| }; | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.