fix(comm,gtd): backlog burn batch A — inbox sender filters, thread cursor pagination, message tags, gtd limit docs (#493 #494 #495 #744)#757
Merged
Conversation
) InboxParams gains optional from_actor (exact match) and from_prefix (prefix match on properties.from_actor), mutually exclusive. When either is set, handle_inbox scans pages beyond the SQL-pushed direction/status/to_actor filters and applies the sender match in Rust (FilterOp has no prefix operator), collecting until limit matches or the store is exhausted. Absent both params, behavior is byte-identical to before. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ThreadParams gains optional order ("asc" default | "desc") and after (a
message id or RFC 3339 timestamp cursor). handle_thread already loads the
full thread into memory before sorting/truncating, so order=desc reverses
the sort comparator so truncate(limit) keeps the newest messages instead of
the oldest, and after filters to created_at strictly greater than the
resolved cursor before sorting. Default behavior (no order/after) is
byte-identical to before.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SendParams and ReplyParams gain optional tags: Vec<String>, persisted verbatim to properties["tags"] on both the outbound and inbound copies (dual_write_message grows a tags parameter, mirroring the existing from_actor/to_actor/references_chain flat-arg pattern). Mirrors the shipped memory.remember tags precedent. deny_unknown_fields is unaffected — typo kwargs are still rejected. Absent tags omits the properties.tags key entirely, unchanged from before. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
) Both handle_next and handle_tasks return a bare JSON array (Value::Array), consumed via .as_array() throughout this crate's own tests and downstream (kkernel, li surfaces) — adding a sibling truncated field per the issue's preferred ask would require wrapping the response in an object, a breaking response-shape change, not an additive one. Implements the issue's stated fallback instead: the limit ParamDef on both verbs now documents the 200 cap, and the clamp call sites carry an inline note explaining why. Cap behavior itself is unchanged (still an unsignaled clamp at the JSON level). Judgment call: issue #744 prefers a truncated response field; this PR implements fallback ask 1 (document the cap) because the response shape cannot change additively. See impl_report_burna.md for detail. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
comm.thread(after=...) previously resolved an id cursor to only the note's created_at timestamp string and compared it lexicographically, so: - two messages sharing the same microsecond created_at (e.g. ADR-057 dual-write self-send copies) could be skipped or duplicated around an id cursor, - non-canonical but valid RFC 3339 timestamp cursors (whole-second Z, +00:00 offset) could compare incorrectly against khive's canonical microsecond ISO format, - order="desc" only flipped the final sort; the cursor filter direction stayed a plain `>` regardless of order. Fix: sort and filter on the total-order tuple (created_at, full_id). An id cursor now carries the referenced note's full tuple for tie-breaking. A timestamp cursor is parsed to microseconds via chrono before comparison (matching the pattern in khive-pack-brain and khive-vcs), and an unparseable/unresolvable after value is now a hard per-op error instead of being silently treated as a literal cursor string. The cursor filter direction is explicit per order (desc keeps strictly-older rows in the desc sequence, not always created_at >). Adds 4 regression tests: equal-created_at id-cursor tie-break, non-canonical RFC 3339 cursor forms, invalid-cursor hard error, and order=desc + after combined. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…emantics (codex r2 Low) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ohdearquant
approved these changes
Jul 9, 2026
ohdearquant
left a comment
Owner
There was a problem hiding this comment.
Gate verified: (created_at, full_id) total-order cursor with fail-loud RFC3339 parsing matches the codex High; 188 pack tests green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backlog-burn batch A, four small fixes off the 2026-07-09 triage.
comm.inbox:from_actor(exact) andfrom_prefix(prefix) sender filters, mutually exclusive, composing with existing status/to_actor filtering. Prefix matching in Rust (no SQL interpolation).comm.thread:order=asc|descwith truncation after ordering (long threads no longer lose the tail), and anaftercursor — id cursors compare on the total order(created_at, full_id)(no skip/dup on equal timestamps), timestamp cursors are RFC 3339 parsed, "after" is defined against the chosen order, invalid cursors fail loudly.comm.send/comm.reply:tagspassthrough stored on both dual-write copies; tag values pass through the runtime secret gate like all structured properties.gtd.next/gtd.taskslimit(docs-only: the issue's preferredtruncatedflag is a breaking response-shape change —gtdlist verbs return a bare JSON array consumed via.as_array()— so this takes the issue's stated fallback).Review: two rounds, final verdict APPROVE (r1 APPROVE-WITH-FIXES → cursor rework in 67d3cc3 + doc-comment alignment; r2 confirmed the High closed, no re-review needed). Gates: fmt/clippy clean, 188 khive-pack-comm tests passing (124 integration + 50 unit + 14 contract), 5 new cursor regression tests.
Closes #493. Closes #494. Closes #495. Closes #744.
🤖 Generated with Claude Code