feat(server)!: POST /ingest forks only when 'from' is present

Branch creation becomes opt-in by presence of the request's 'from' field.
Previously the handler defaulted from to 'main' and always auto-created a
missing branch — a typo'd branch name silently forked main and landed the
data there, with the client none the wiser. Now a request without 'from'
against a missing branch returns 404 branch-not-found and creates nothing;
with 'from' set, fork-if-missing behaves as before. The BranchCreate
authority is only consulted when a fork will actually happen.

The handler calls the unified load_as directly (the deprecated ingest_as
shim is no longer used in the server). IngestOutput.base_branch becomes
nullable: it echoes the request's 'from' and is null when absent. OpenAPI
regenerated; the CLI's local ingest arm moves to load_file_as + the new
converter shape.

BREAKING CHANGE: clients that relied on implicit fork-from-main with 'from'
omitted must now pass from='main' explicitly. IngestOutput.base_branch is
now nullable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
aaltshuler 2026-06-11 04:05:29 +03:00
parent c236a4c2df
commit 90676ef52f
6 changed files with 131 additions and 40 deletions

View file

@ -1587,7 +1587,7 @@ fn print_ingest_human(output: &IngestOutput) {
"ingested {} into branch {} from {} with {} ({})",
output.uri,
output.branch,
output.base_branch,
output.base_branch.as_deref().unwrap_or("main"),
output.mode.as_str(),
if output.branch_created {
"branch created"
@ -2729,11 +2729,8 @@ 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(
.load_file_as(
&branch,
Some(&from),
&data.to_string_lossy(),
@ -2741,7 +2738,7 @@ async fn main() -> Result<()> {
actor,
)
.await?;
ingest_output(&uri, &result, None)
ingest_output(&uri, &result, mode.into(), None)
};
if json {
print_json(&payload)?;