A file-based task manager
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Bounce rejected inbox items back to the sender's inbox

reject_inbox previously discarded the stable id, leaving the sender
unaware. Now it parses the source queue out of the inbox key and
re-inboxes the task there with a return key (`<receiver>-<seq>`), so
each round-trip is uniquely identified.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

+39 -2
+5 -1
src/lib.rs
··· 590 590 } 591 591 }; 592 592 ws.reject_inbox(&key)?; 593 - println!("Rejected {key}"); 593 + if let Some((src, _)) = key.rsplit_once('-') { 594 + println!("Rejected {key} (returned to '{src}' inbox)"); 595 + } else { 596 + println!("Rejected {key}"); 597 + } 594 598 if let Some(r) = effective_remote(remote) { 595 599 let _ = ws.git_push(&r); 596 600 }
+34 -1
src/workspace.rs
··· 663 663 Ok(Id(human)) 664 664 } 665 665 666 + /// Reject an inbox item: remove it from the active queue's inbox and 667 + /// bounce it back to the sender's inbox so they see the return. The 668 + /// source queue is recovered from the key (`<src>-<seq>`); the return 669 + /// key is `<active>-<seq>` so each round-trip is uniquely identified. 666 670 pub fn reject_inbox(&self, key: &str) -> Result<()> { 667 671 let repo = self.repo()?; 668 - queue::take_from_inbox(&repo, &self.queue(), key, "reject")? 672 + let stable = queue::take_from_inbox(&repo, &self.queue(), key, "reject")? 669 673 .ok_or_else(|| Error::Parse(format!("Inbox item '{key}' not found")))?; 674 + if let Some((src, seq)) = key.rsplit_once('-') { 675 + let cur = self.queue(); 676 + if src != cur { 677 + let return_key = format!("{cur}-{seq}"); 678 + queue::add_to_inbox(&repo, src, return_key, stable, "reject-return")?; 679 + } 680 + } 670 681 Ok(()) 671 682 } 672 683 ··· 885 896 assert_eq!(accepted.0, id.0); 886 897 let stack = ws.read_stack().unwrap(); 887 898 assert_eq!(stack.len(), 1); 899 + } 900 + 901 + #[test] 902 + fn reject_returns_to_source_inbox() { 903 + let (_d, ws) = fresh_workspace(); 904 + ws.create_queue("review", None).unwrap(); 905 + let t = ws.new_task("bounce me".into(), "".into()).unwrap(); 906 + let id = t.id; 907 + let stable = t.stable.clone(); 908 + ws.push_task(t).unwrap(); 909 + let assign_key = ws 910 + .assign_to_queue(TaskIdentifier::Id(id), "review") 911 + .unwrap(); 912 + ws.switch_queue("review").unwrap(); 913 + ws.reject_inbox(&assign_key).unwrap(); 914 + let inbox_here = ws.list_inbox().unwrap(); 915 + assert!(inbox_here.is_empty(), "rejected item must leave receiver inbox"); 916 + ws.switch_queue("tsk").unwrap(); 917 + let returned = ws.list_inbox().unwrap(); 918 + assert_eq!(returned.len(), 1, "rejected item must land in sender inbox"); 919 + assert_eq!(returned[0].source_queue, "review"); 920 + assert_eq!(returned[0].stable, stable); 888 921 } 889 922 890 923 #[test]