feat(claim): arbitration per mode (#5) — first claim wins except conspiracy (#23)

This commit is contained in:
Smokey committed 2026-10-28 05:29:57 -06:00
1 parent 46993aaef4
commit 5ff45f355a
2 files changed
+24

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