╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ──────────╮ │src/event/Patch.zig│ ╰───────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │217 } │ │218 } │ │219 │ │164 - if (record.event.status == .merged) { │ │165 - const id = revision_id orelse return error.InvalidPatch; │ │166 - const selected = record.event.revision orelse return error.InvalidPatch; │ │167 - const revision = (try evt.PatchRev.readById(DB, hash_kind, haxy_moment.readOnly(), arena, &id)) orelse return error.InvalidPatch; │ │168 - if (!selected.matches(revision)) return error.InvalidPatch; │ │220 + switch (record.event.status) { │ │221 + .open, .closed => {}, │ │222 + .merged => |merged_oid| { │ │223 + try evt.PatchRev.validateOid(hash_kind, merged_oid); │ │224 + const id = revision_id orelse return error.InvalidPatch; │ │225 + const selected = record.event.revision orelse return error.InvalidPatch; │ │226 + if (!selected.includesOid(merged_oid)) return error.InvalidPatch; │ │227 + const revision = (try evt.PatchRev.readById(DB, hash_kind, haxy_moment.readOnly(), arena, &id)) orelse return error.InvalidPatch;│ │228 + if (!selected.matches(revision)) return error.InvalidPatch; │ │229 + }, │ │230 } │ │231 │ │232 const order_key = evt.orderKeyDesc(record.created_order, event_id); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │233 if (existing_maybe) |existing| { │ │234 if (event_oid != null or record.removed) _ = try conflicts.remove(&order_key); │ │235 if (!existing.removed) { │ │175 - const old_status = try statusSet(DB, statuses, existing.event.status); │ │236 + const existing_status_kind = existing.event.status.kind(); │ │237 + const old_status = try statusSet(DB, statuses, existing_status_kind); │ │238 _ = try old_status.remove(&order_key); │ │177 - try removeFromTagSets(DB, tag_statuses, existing.event.tags, existing.event.status, &order_key); │ │178 - if (existing.event.status != .merged) { │ │239 + try removeFromTagSets(DB, tag_statuses, existing.event.tags, existing_status_kind, &order_key); │ │240 + if (existing_status_kind != .merged) { │ │241 if (existing.event.revision) |revision| { │ │242 const revisions = try DB.HashMap(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, revision_to_id_set_key)));│ │243 for ([_][]const u8{ revision.squash_oid, revision.source_oid }, 0..) |oid, i| { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────╮ │269 } │ │270 │ │271 if (!record.removed) { │ │210 - const status = try statusSet(DB, statuses, record.event.status);│ │272 + const status = try statusSet(DB, statuses, status_kind); │ │273 try status.put(&order_key); │ │274 │ │275 var tag_iter = tagIterator(record.event.tags); │ ╰─────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │276 while (tag_iter.next()) |tag| { │ │277 if (tag.len == 0 or tag.len > tag_max_len) continue; │ │278 var key_buffer: TagStatusKey = undefined; │ │217 - const set = try DB.SortedSet(.read_write).init(try tag_statuses.putCursor(try tagStatusKey(&key_buffer, tag, record.event.status)));│ │279 + const set = try DB.SortedSet(.read_write).init(try tag_statuses.putCursor(try tagStatusKey(&key_buffer, tag, status_kind))); │ │280 try set.put(&order_key); │ │281 } │ │282 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │221 - if (record.event.status != .merged) { │ │283 + if (status_kind != .merged) { │ │284 if (record.event.revision) |revision| { │ │285 const revisions = try DB.HashMap(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, revision_to_id_set_key)));│ │286 for ([_][]const u8{ revision.squash_oid, revision.source_oid }, 0..) |oid, i| { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │304 const revision_index = std.meta.fieldIndex(Self, "revision") orelse @compileError("Patch.revision not found");│ │305 if (outcome[status_index] != .conflicted or outcome[revision_index] == .conflicted) return; │ │306 │ │245 - if (target.status == .merged and evt.fieldEqual(?Revision, target.revision, merged.revision)) { │ │246 - merged.status = .merged; │ │307 + if (target.status.kind() == .merged and evt.fieldEqual(?Revision, target.revision, merged.revision)) { │ │308 + merged.status = target.status; │ │309 outcome[status_index] = .kept; │ │248 - } else if (parent.status == .merged and evt.fieldEqual(?Revision, parent.revision, merged.revision)) { │ │249 - merged.status = .merged; │ │310 + } else if (parent.status.kind() == .merged and evt.fieldEqual(?Revision, parent.revision, merged.revision)) { │ │311 + merged.status = parent.status; │ │312 outcome[status_index] = .parent; │ │313 } │ │314 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────╮ │331 var updated = record.event; │ │332 switch (change) { │ │333 .status => |status| { │ │272 - if (updated.status == status) return; │ │273 - updated.status = status; │ │334 + if (updated.status.kind() == status) return; │ │335 + updated.status = switch (status) { │ │336 + .open => .open, │ │337 + .closed => .closed, │ │338 + .merged => return error.InvalidPatchStatus,│ │339 + }; │ │340 }, │ │341 .fields => |fields| { │ │342 updated.title = fields.title; │ ╰────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │449 fn statusSet( │ │450 comptime DB: type, │ │451 statuses: DB.SortedMap(.read_write), │ │386 - status: Status, │ │452 + status: StatusKind, │ │453 ) !DB.SortedSet(.read_write) { │ │454 return DB.SortedSet(.read_write).init(try statuses.putCursor(@tagName(status)));│ │455 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────╮ │458 comptime DB: type, │ │459 tag_statuses: DB.SortedMap(.read_write),│ │460 tags: []const u8, │ │395 - status: Status, │ │461 + status: StatusKind, │ │462 order_key: []const u8, │ │463 ) !void { │ │464 var tag_iter = tagIterator(tags); │ ╰─────────────────────────────────────────────────╯ ╭ changed ───╮ │src/fork.zig│ ╰────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │225 if (fork_patch.removed and target_patch == null) return error.PatchDataUnavailable; │ │226 if (target_patch) |patch| { │ │227 if (!std.mem.eql(u8, patch.author_email orelse "", author.email)) return error.PatchDataUnavailable;│ │228 - if (patch.event.status == .merged) return error.PatchAlreadyMerged; │ │228 + if (patch.event.status.kind() == .merged) return error.PatchAlreadyMerged; │ │229 } │ │230 const published = target_patch != null; │ │231 const title = if (target_patch) |patch| patch.event.title else fork_patch.event.title; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯