use super::*;
#[test]
fn native_commit_snapshot_survives_an_interleaved_real_commit() {
let dir = repo_with_commit_on_task_branch();
let mut tool = tool(dir.path());
tool.attribution
.as_mut()
.unwrap()
.contributors
.push(newt_core::attribution::Attribution::new(
"earlier-model",
"newt-agent",
"fixture-version",
"earlier@example.invalid",
));
let policy = tool.native_commit_policy().unwrap();
let snapshot = policy
.snapshot_for_commit()
.unwrap_or_else(|| policy.clone());
let expected = snapshot
.finalize_message("native command in flight")
.unwrap();
assert!(expected.contains("earlier-model"));
std::fs::write(dir.path().join("a.txt"), "interleaved change\n").unwrap();
tool.dispatch(
"add",
&serde_json::json!({"paths": ["a.txt"]}),
&GitCaveats::top(),
&Caveats::top(),
)
.unwrap();
tool.dispatch(
"commit",
&serde_json::json!({"message": "other command published"}),
&GitCaveats::top(),
&Caveats::top(),
)
.unwrap();
assert!(head_message(dir.path()).contains("earlier-model"));
assert_eq!(snapshot.finalize_message("native command in flight").unwrap(), expected, "an admitted native transaction must retain its canonical message across hook/sign/ref checks");
let next = policy
.snapshot_for_commit()
.unwrap_or_else(|| policy.clone());
assert!(!next
.finalize_message("later command")
.unwrap()
.contains("earlier-model"));
}
#[test]
fn dispatch_init_creates_a_repo_in_a_non_repo_dir_then_commit_works() {
let dir = tempfile::tempdir().unwrap();
assert!(
GitEngine::open(dir.path(), &Scope::All).is_err(),
"precondition: not a repo yet"
);
let t = tool(dir.path());
let out = t
.dispatch(
"init",
&serde_json::json!({}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
assert!(out.contains("initialized"), "got: {out}");
assert!(
GitEngine::open(dir.path(), &Scope::All).is_ok(),
"init created a real, openable repo"
);
std::fs::write(dir.path().join("f.txt"), "x\n").unwrap();
t.dispatch(
"add",
&serde_json::json!({"paths": ["f.txt"]}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
let c = t
.dispatch(
"commit",
&serde_json::json!({"message": "first"}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
assert!(c.contains("committed"), "got: {c}");
}
#[test]
fn drain_commit_success_signals_only_a_confirmed_landing() {
let dir = tempfile::tempdir().unwrap();
let t = tool(dir.path());
t.dispatch(
"init",
&serde_json::json!({}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
assert_eq!(t.drain_commit_success(), 0);
git(dir.path(), &["checkout", "-q", "-b", "task"]);
std::fs::write(dir.path().join("f.txt"), "x\n").unwrap();
t.dispatch(
"add",
&serde_json::json!({"paths": ["f.txt"]}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
let bad = t.dispatch(
"commit",
&serde_json::json!({"message": " "}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
);
assert!(bad.is_err(), "empty message must be rejected");
assert_eq!(
t.drain_commit_success(),
0,
"a failed commit does not signal"
);
t.dispatch(
"commit",
&serde_json::json!({"message": "first"}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
assert_eq!(t.drain_commit_success(), 1, "one confirmed commit");
assert_eq!(t.drain_commit_success(), 0, "drain resets the counter");
t.dispatch(
"amend",
&serde_json::json!({"message": "first (reworded)"}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
assert_eq!(t.drain_commit_success(), 1, "amend signals a commit");
}
#[test]
fn contributor_snapshot_consumed_at_commit_boundary_not_turn_boundary() {
let dir = tempfile::tempdir().unwrap();
let mut t = tool(dir.path());
if let Some(a) = t.attribution.as_mut() {
a.contributors.push(
newt_core::attribution::Attribution::new(
"model-a",
"newt-agent",
newt_core::build_info::PACKAGE_VERSION,
"noreply@newt-agent.com",
)
.with_build(newt_core::build_info::SOURCE_ID),
);
}
t.dispatch(
"init",
&serde_json::json!({}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
git(dir.path(), &["checkout", "-q", "-b", "task"]);
std::fs::write(dir.path().join("a.txt"), "x\n").unwrap();
t.dispatch(
"add",
&serde_json::json!({"paths": ["a.txt"]}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
t.dispatch(
"commit",
&serde_json::json!({"message": "C1"}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
let c1 = head_message(dir.path());
let version = newt_core::build_info::PACKAGE_VERSION;
let build = newt_core::build_info::SOURCE_ID;
assert!(
c1.contains(&format!(
"Co-authored-by: model-a (newt-agent v{version} {build}) <noreply@newt-agent.com>"
)),
"C1 credits the accumulated contributor A: {c1}"
);
assert!(
c1.contains(&format!(
"Co-authored-by: qwen3:30b (newt-agent v{version} {build}) <noreply@newt-agent.com>"
)),
"C1 credits the active model B: {c1}"
);
std::fs::write(dir.path().join("b.txt"), "y\n").unwrap();
t.dispatch(
"add",
&serde_json::json!({"paths": ["b.txt"]}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
t.dispatch(
"commit",
&serde_json::json!({"message": "C2"}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
let c2 = head_message(dir.path());
assert!(
!c2.contains("model-a"),
"C2 must NOT re-credit A — its snapshot was consumed at C1's boundary: {c2}"
);
assert!(
c2.contains(&format!(
"Co-authored-by: qwen3:30b (newt-agent v{version} {build}) <noreply@newt-agent.com>"
)),
"C2 still credits the active model B: {c2}"
);
assert_eq!(commit_count(dir.path()), 2);
std::fs::write(dir.path().join("c.txt"), "z\n").unwrap();
t.dispatch(
"add",
&serde_json::json!({"paths": ["c.txt"]}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
t.dispatch(
"commit",
&serde_json::json!({"message": "C3"}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
let c3 = head_message(dir.path());
assert!(
!c3.contains("model-a"),
"C3 still does not re-credit A: {c3}"
);
assert_eq!(commit_count(dir.path()), 3);
}
#[test]
fn failed_commit_does_not_consume_contributors() {
let dir = tempfile::tempdir().unwrap();
let mut t = tool(dir.path());
if let Some(a) = t.attribution.as_mut() {
a.contributors.push(
newt_core::attribution::Attribution::new(
"model-a",
"newt-agent",
newt_core::build_info::PACKAGE_VERSION,
"noreply@newt-agent.com",
)
.with_build(newt_core::build_info::SOURCE_ID),
);
}
t.dispatch(
"init",
&serde_json::json!({}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
std::fs::write(dir.path().join("a.txt"), "x\n").unwrap();
t.dispatch(
"add",
&serde_json::json!({"paths": ["a.txt"]}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
let denied = t.dispatch(
"commit",
&serde_json::json!({"message": "denied"}),
&GitCaveats::read_only(),
&newt_core::caveats::Caveats::top(),
);
assert!(denied.is_err(), "read-only caps deny the commit");
let cursor = t
.contributors_consumed
.load(std::sync::atomic::Ordering::Relaxed);
assert_eq!(
cursor, 0,
"a failed commit must NOT consume contributors (cursor still 0): {cursor}"
);
assert_eq!(t.drain_commit_success(), 0);
t.dispatch(
"commit",
&serde_json::json!({"message": "C1"}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
let c1 = head_message(dir.path());
let version = newt_core::build_info::PACKAGE_VERSION;
let build = newt_core::build_info::SOURCE_ID;
assert!(
c1.contains(&format!(
"Co-authored-by: model-a (newt-agent v{version} {build}) <noreply@newt-agent.com>"
)),
"the contributor survived the failed commit and is credited on the retry: {c1}"
);
assert_eq!(commit_count(dir.path()), 1);
assert_eq!(t.drain_commit_success(), 1);
}
#[test]
fn dispatch_init_is_idempotent_on_an_existing_repo() {
let dir = repo_with_commit();
let out = tool(dir.path())
.dispatch(
"init",
&serde_json::json!({}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
assert!(out.contains("already a repository"), "got: {out}");
}
#[test]
fn dispatch_init_is_denied_without_write_permission() {
let dir = tempfile::tempdir().unwrap();
let res = tool(dir.path()).dispatch(
"init",
&serde_json::json!({}),
&GitCaveats::read_only(),
&newt_core::caveats::Caveats::top(),
);
assert!(res.is_err(), "read-only session must not create a repo");
assert!(
GitEngine::open(dir.path(), &Scope::All).is_err(),
"a denied init created nothing"
);
}
#[test]
fn dispatch_checkout_creates_branch_and_branch_delete_removes_it() {
let dir = repo_with_commit();
let t = tool(dir.path());
let out = t
.dispatch(
"checkout",
&serde_json::json!({"name": "feat/dispatch"}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
assert!(out.contains("created and switched"), "{out}");
t.dispatch(
"checkout",
&serde_json::json!({"name": "main", "create": false}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
let del = t
.dispatch(
"branch-delete",
&serde_json::json!({"name": "feat/dispatch"}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap();
assert_eq!(del, "deleted branch 'feat/dispatch'");
}
#[test]
fn dispatch_unknown_op_lists_the_supported_ops() {
let dir = repo_with_commit();
let t = tool(dir.path());
let err = t
.dispatch(
"pull",
&serde_json::json!({}),
&GitCaveats::top(),
&newt_core::caveats::Caveats::top(),
)
.unwrap_err();
assert!(err.contains("unknown git op 'pull'"), "{err}");
assert!(err.contains("checkout"), "{err}");
assert!(err.contains("branch-delete"), "{err}");
}
#[test]
fn finalize_commit_message_owns_attribution_deterministically() {
let t = tool(Path::new(".")); let out = t.finalize_commit_message("fix the parser");
let version = newt_core::build_info::PACKAGE_VERSION;
let build = newt_core::build_info::SOURCE_ID;
assert!(
out.contains(&format!(
"Co-authored-by: qwen3:30b (newt-agent v{version} {build}) <noreply@newt-agent.com>"
)),
"canonical model trailer rendered from the typed value: {out}"
);
assert!(
out.contains("Harness: newt-agent v") && out.contains(" | Model: qwen3:30b | Operator: "),
"canonical provenance line rendered from the same value: {out}"
);
assert!(
!out.contains("Time:"),
"no wall-clock field (deterministic): {out}"
);
assert!(
out.starts_with("fix the parser\n\n"),
"subject preserved verbatim: {out}"
);
let with_third = "feat: x\n\nCo-authored-by: someone <a@b.c>";
let out2 = t.finalize_commit_message(with_third);
assert!(
out2.contains("Co-authored-by: someone <a@b.c>"),
"third-party kept: {out2}"
);
assert!(
out2.contains("Co-authored-by: qwen3:30b"),
"newt model trailer added: {out2}"
);
assert_eq!(
t.finalize_commit_message(&out),
out,
"idempotent re-finalization"
);
let mut t2 = t;
t2.attribution = None;
assert_eq!(t2.finalize_commit_message("m"), "m");
}