(#23) Claim arbitration per mode #30

Merged
jacisjake merged 2 commits from task/23-claim-arbitration into main 2026-10-28 11:30:19 +00:00
2 changed files with 24 additions and 0 deletions
Showing only changes of commit 5ff45f355a - Show all commits

No files matched your search

+11
View File
@@ -132,6 +132,17 @@ func (s *Server) postNestMessage(w http.ResponseWriter, r *http.Request) {
// Mode (Epic C, same rule shape as kind): Jev first, header escape, "" when unsure. // Mode (Epic C, same rule shape as kind): Jev first, header escape, "" when unsure.
mode, modeBy := s.tagMode(kind, body.Mode, body.Text) mode, modeBy := s.tagMode(kind, body.Mode, body.Text)
// Claim arbitration (#5, Epic C): first claim wins unless the referent is a
// conspiracy, which expects multiple claims.
if kind == "claim" && body.RefersTo != "" {
if origin, found := s.msgs.ByMsgID(body.RefersTo); found && origin.Mode != "conspiracy" {
if owner, claimed := s.msgs.FirstClaim(origin.NestID, origin.MsgID()); claimed {
httpError(w, http.StatusConflict, origin.MsgID()+" is claimed by "+owner+"; review it instead of redoing it.")
return
}
}
}
msg := Message{ msg := Message{
NestID: nestID, NestID: nestID,
Kind: kind, Kind: kind,
+13
View File
@@ -119,6 +119,19 @@ func (s *MessageStore) ByMsgID(msgID string) (Message, bool) {
return Message{}, false return Message{}, false
} }
// FirstClaim returns the author of the first claim against a message, and
// whether any claim exists.
func (s *MessageStore) FirstClaim(nestID, referentID string) (string, bool) {
s.mu.Lock()
defer s.mu.Unlock()
for _, m := range s.log[nestID] {
if m.Kind == "claim" && m.RefersTo == referentID {
return m.Author, true
}
}
return "", false
}
func (s *MessageStore) save(nestID string) error { func (s *MessageStore) save(nestID string) error {
if err := os.MkdirAll(s.dir, 0o755); err != nil { if err := os.MkdirAll(s.dir, 0o755); err != nil {
return err return err