feat(engine): unify load/ingest — load_as gains an optional fork base

load_as/load_file_as gain a base: Option<&str> parameter: with Some(base) a
missing target branch is forked from base first (the former ingest
semantics); with None the target branch must exist — staging fails on an
unknown branch, so a typo'd name can never create one. LoadResult gains
branch/base_branch/branch_created metadata (additive).

The ingest family (ingest, ingest_as, ingest_file, ingest_file_as) becomes
#[deprecated] shims over load_as that preserve the historical contract
exactly (from: None still means fork from main; base recorded even when no
fork happened). IngestResult and to_ingest_tables stay for the shims and
the server until the removal release.

The layered policy check is unchanged: Change on the target branch always,
BranchCreate additionally when a fork actually happens (enforced inside
branch_create_from_as with the actor threaded through).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
aaltshuler 2026-06-11 03:53:22 +03:00
parent 43d4e89fde
commit e676c151bb
5 changed files with 170 additions and 68 deletions

View file

@ -2722,6 +2722,9 @@ async fn server_ingest(
.try_admit(&actor_arc, est_bytes)
.map_err(ApiError::from_workload_reject)?;
// Deprecated shim retained until the from-absent semantics change
// lands; the handler then calls `load_as` directly.
#[allow(deprecated)]
let result = {
let db = &handle.engine;
db.ingest_as(&branch, Some(&from), &request.data, mode, actor_id)