Skip to main content

khive_runtime/
atomic_prepare.rs

1//! ADR-099: the per-verb async prepare pass for the KG-substrate v1
2//! admissible verbs (`update`, `delete`, `link`, `merge`), plus
3//! [`prepare_add_entity`]/[`prepare_add_note`] for the ADR-046 proposal
4//! changeset `AddEntity`/`AddNote` arms. Each `prepare_*` function reads
5//! current state (async, outside any transaction) and returns a plain-data
6//! [`crate::atomic_runner::AtomicOpPlan`] ([`crate::atomic_plan`]) for the
7//! synchronous commit pass ([`crate::atomic_runner::run_atomic_unit`]) to
8//! apply.
9//!
10//! `gtd.transition`/`gtd.complete` prepare is deliberately not here (lives in
11//! `kkernel` instead), and `propose`/`review`/`withdraw`/`merge` are on the
12//! v1 admissible list but have no working prepare implementation in this
13//! module (`prepare_governance_unimplemented` fails loudly rather than
14//! silently no-opping; `prepare_merge` is unreachable through `--atomic` and
15//! kept only for its own tests and as defense in depth). See
16//! `docs/api/atomic_prepare.md#scope-what-is-excluded-and-why` for why each of these is excluded
17//! and what would be required to admit them.
18
19use serde_json::Value;
20use uuid::Uuid;
21
22mod index_purge;
23
24pub(crate) use index_purge::event_append_statements;
25use index_purge::push_index_purge_statements;
26
27use khive_storage::types::SqlValue;
28use khive_storage::{AttachmentSubstrate, EdgeRelation, EdgeUpsertDisposition, SqlStatement};
29use khive_types::pack::pack_registry_tag;
30use khive_types::{EventKind, SubstrateKind};
31
32use crate::atomic_plan::{
33    AddEntityPlan, AddNotePlan, AffectedRowGuard, DeletePlan, EdgeNaturalKey, LinkPlan, MergePlan,
34    PlanStatement, PostCommitEffect, UpdatePlan,
35};
36use crate::atomic_runner::AtomicOpPlan;
37use crate::atomic_runner::CommittedPostCommitEffects;
38use crate::curation::{entity_fts_document, note_fts_document};
39use crate::error::{RuntimeError, RuntimeResult};
40use crate::operations::{
41    canonical_edge_endpoint_kinds, canonical_edge_endpoints, merge_dependency_kind,
42    validate_edge_metadata, validate_edge_weight, Resolved,
43};
44use crate::runtime::{KhiveRuntime, NamespaceToken};
45
46use khive_db::stores::attachment::delete_record_attachments_statement;
47use khive_db::stores::entity::{
48    entity_hard_delete_statement, entity_replace_if_unchanged_statement,
49    entity_soft_delete_statement, entity_upsert_statement,
50};
51use khive_db::stores::event::event_insert_statements;
52use khive_db::stores::event::hard_delete_lineage_warning_statements;
53use khive_db::stores::graph::{
54    edge_hard_delete_statement, edge_insert_new_guarded_by_endpoints_statement,
55    edge_link_replace_if_unchanged_and_endpoints_exist_statement,
56    edge_replace_if_unchanged_statement, edge_soft_delete_statement,
57    edge_symmetric_absorb_or_update_inplace_statement, edge_symmetric_delete_if_conflict_statement,
58    purge_incident_edges_statement,
59};
60use khive_db::stores::note::{
61    note_hard_delete_statement, note_soft_delete_statement, note_upsert_statement,
62};
63use khive_db::stores::text::{delete_document_statements, insert_document_statements};
64
65mod add_update;
66pub use add_update::{
67    prepare_add_entity, prepare_add_note, prepare_op, prepare_update, prepare_update_entity_plan,
68    prepare_update_from_note_snapshot, validate_note_update_expected_kind, AtomicUpdateKind,
69};
70use add_update::{
71    prepare_update_entity_plan_with_version_and_type, reject_inapplicable_update_fields,
72};
73
74mod note_reindex_effect;
75mod patch_helpers;
76
77use patch_helpers::{
78    entity_name_patch, obj, optional_create_string, optional_entity_type_patch, optional_f64,
79    optional_f64_patch, optional_properties, optional_str, optional_string_patch, optional_tags,
80    refuse_pack_registry_tags, require_str, require_uuid,
81};
82
83pub(crate) async fn prepare_update_entity_plan_with_version(
84    runtime: &KhiveRuntime,
85    token: &NamespaceToken,
86    id: Uuid,
87    patch: crate::curation::EntityPatch,
88    expected_version: Option<i64>,
89) -> RuntimeResult<AtomicOpPlan> {
90    prepare_update_entity_plan_with_version_and_type(
91        runtime,
92        token,
93        id,
94        patch,
95        expected_version,
96        None,
97    )
98    .await
99}
100
101// ---------------------------------------------------------------------------
102// post-commit effects
103// ---------------------------------------------------------------------------
104
105mod embedding_outcome;
106pub use embedding_outcome::{
107    apply_post_commit_effects_with_failures, PostCommitEffectsReport, PostCommitEmbeddingOutcome,
108    ReindexModelFailure, ReindexModelStage,
109};
110
111mod link_merge;
112use link_merge::{parse_edge_relation, prepare_link, prepare_merge};
113
114mod post_commit;
115use post_commit::apply_one_post_commit_effect;
116pub use post_commit::{apply_post_commit_effects, apply_post_commit_effects_with_report};
117
118mod edge_delete;
119pub use edge_delete::{prepare_delete, AtomicDeleteKind};
120use edge_delete::{prepare_delete_edge, prepare_update_edge};
121
122#[cfg(test)]
123#[path = "atomic_prepare_tests.rs"]
124mod tests;