A reply to a case mail becomes a note on its record
Whatever reads the mailbox publishes on portal.mail.received; portal appends the note after checking the record exists in a bucket this site has and the sender is the address the record itself holds. A note never moves a case: a mailbox is the one door anyone may knock on, so it cannot drive a state machine even if someone forges their way past the checks. The desks show the conversation beside the case. Tested: the address parser, every refusal (a stranger, no address to compare, an empty reply, the same reply twice, an unknown contract), and the whole path through a real JetStream - the note lands, the state does not move, and no event is written. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
4fd60293fa
commit
26c1762dfa
@@ -63,4 +63,33 @@ async fn a_submission_is_created_moved_refused_and_read_back_through_the_real_en
|
||||
let replayed = aggregates::replay(schema, "rec-1", &events).expect("replays");
|
||||
assert_eq!(replayed.state, "won");
|
||||
assert!(replayed.sequence > moved.sequence);
|
||||
|
||||
// A reply to the mail this record was sent becomes a note on it,
|
||||
// through the same store the desks read - and moves nothing: the
|
||||
// record is still where the desk left it.
|
||||
let mut record: Answer = serde_json::from_slice(&store.get("rec-1").await.unwrap().expect("record")).unwrap();
|
||||
let reply = portal::mail::Incoming {
|
||||
v: portal::mail::CONTRACT,
|
||||
id: "mail-1".into(),
|
||||
bucket: bucket.clone(),
|
||||
record: "rec-1".into(),
|
||||
from: "A <A@B.example>".into(),
|
||||
subject: "Re: your enquiry".into(),
|
||||
text: "Thursday suits us.".into(),
|
||||
received_ms: now + 10,
|
||||
};
|
||||
let note = portal::mail::note_for(&reply, &record).expect("the address matches the record");
|
||||
record.notes.push(note);
|
||||
store.put("rec-1", serde_json::to_vec(&record).unwrap().into()).await.expect("note stored");
|
||||
|
||||
let read_back: Answer = serde_json::from_slice(&store.get("rec-1").await.unwrap().expect("record")).unwrap();
|
||||
assert_eq!(read_back.notes.len(), 1);
|
||||
assert_eq!(read_back.notes[0].text, "Thursday suits us.");
|
||||
assert_eq!(read_back.notes[0].from, "a@b.example");
|
||||
assert_eq!(read_back.state, "quoted", "a reply is a note, never a decision");
|
||||
// The same reply read twice adds nothing.
|
||||
assert!(portal::mail::note_for(&reply, &read_back).is_err());
|
||||
// And the event log is untouched by it.
|
||||
let after = load_events(&js, &bucket, "rec-1").await.expect("events");
|
||||
assert_eq!(after.len(), 3, "a note writes no event");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user