Skip to content

Commit f0196f8

Browse files
Pyinerclaude
andcommitted
test(bridge): pending-input attribution merge contract
Asserts a queued input's carried attribution metadata (source / automation_id / origin_run_id) lands on the acknowledged user turn and that built-in queue markers win on conflict. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent d9324ef commit f0196f8

2 files changed

Lines changed: 44 additions & 3 deletions

File tree

garyx-bridge/src/multi_provider/persistence.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -706,9 +706,7 @@ impl StreamingRunSnapshot {
706706
// Attribution carried from the originating dispatch; built-in queue
707707
// markers above win on conflict.
708708
for (key, value) in &pending_input.metadata {
709-
metadata
710-
.entry(key.clone())
711-
.or_insert_with(|| value.clone());
709+
metadata.entry(key.clone()).or_insert_with(|| value.clone());
712710
}
713711
self.session_messages.push(ProviderMessage {
714712
role: ProviderMessageRole::User,

garyx-bridge/src/multi_provider/persistence/tests.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,49 @@ async fn test_save_thread_messages_strips_runtime_only_metadata() {
717717
assert_eq!(messages[0]["metadata"]["source"], "automation");
718718
}
719719

720+
#[test]
721+
fn test_acknowledge_pending_input_merges_attribution_metadata() {
722+
let mut snapshot = StreamingRunSnapshot::default();
723+
let mut origin_metadata = HashMap::new();
724+
origin_metadata.insert("source".to_owned(), json!("automation"));
725+
origin_metadata.insert("automation_id".to_owned(), json!("automation-42"));
726+
origin_metadata.insert("origin_run_id".to_owned(), json!("run-requested"));
727+
// A conflicting carried value must not shadow the built-in queue marker.
728+
origin_metadata.insert("queued_input_id".to_owned(), json!("spoofed"));
729+
730+
let pending_input = PendingUserInput {
731+
id: "queued_input:test".to_owned(),
732+
bridge_run_id: "run-active".to_owned(),
733+
text: "scheduled prompt".to_owned(),
734+
content: json!("scheduled prompt"),
735+
queued_at: "2026-03-01T00:00:00Z".to_owned(),
736+
origin_id: None,
737+
metadata: origin_metadata,
738+
status: PendingUserInputStatus::Queued,
739+
};
740+
assert!(snapshot.acknowledge_pending_input(&pending_input));
741+
742+
let user_turn = snapshot
743+
.session_messages
744+
.iter()
745+
.find(|message| message.role == ProviderMessageRole::User)
746+
.expect("acknowledged user turn");
747+
assert_eq!(user_turn.metadata.get("source"), Some(&json!("automation")));
748+
assert_eq!(
749+
user_turn.metadata.get("automation_id"),
750+
Some(&json!("automation-42"))
751+
);
752+
assert_eq!(
753+
user_turn.metadata.get("origin_run_id"),
754+
Some(&json!("run-requested"))
755+
);
756+
// Built-in queue markers win over carried metadata on conflict.
757+
assert_eq!(
758+
user_turn.metadata.get("queued_input_id"),
759+
Some(&json!("queued_input:test"))
760+
);
761+
}
762+
720763
#[test]
721764
fn test_streaming_run_snapshot_splits_assistant_segments() {
722765
let mut snapshot = StreamingRunSnapshot::default();

0 commit comments

Comments
 (0)