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

@ -2669,7 +2669,7 @@ async fn main() -> Result<()> {
let db = open_local_db_with_policy(&graph).await?;
let actor = resolve_cli_actor(cli.as_actor.as_deref(), &config);
let result = db
.load_file_as(&branch, &data.to_string_lossy(), mode.into(), actor)
.load_file_as(&branch, None, &data.to_string_lossy(), mode.into(), actor)
.await?;
let payload = LoadOutput {
uri: &uri,
@ -2729,6 +2729,9 @@ async fn main() -> Result<()> {
} else {
let db = open_local_db_with_policy(&graph).await?;
let actor = resolve_cli_actor(cli.as_actor.as_deref(), &config);
// Deprecated shim retained until the CLI ingest command
// becomes an alias of the unified `load` handler.
#[allow(deprecated)]
let result = db
.ingest_file_as(
&branch,