Repository navigation
feat(mcp): events_query answers what happened at a time - #55
Conversation
A new read tool asks the box's control journal (events.get, scope ftw.events.read) about a past window: each span in which a device, a source, dispatch or the mode held one verdict, each scored plan slot, and the notices the box sent. It is for questions such as why the app said FTW was not in control this morning, what happened at 06:14, or whether the battery did what FTW asked. - Inputs: since and until (RFC 3339, Unix ms, or a local time read in the home's zone; the last 24 hours by default), source, min_severity (warning or alarm) and limit (at most protocol.EventsMax). - Each span gives from and to (or ongoing) in the zone the box names in hello_ok, UTC without one; duration; kind, source, status, reason, severity and mode; askedW beside measuredW as mean, min and max; and the latest verdict's numbers, a *_ms time written as a time. - When the box cut the answer, next names the until that reads on: the oldest start or time of each list the box cut, the later of the two. - A box from before the journal answers E_UNKNOWN_OP for events.get with no field; the model hears "this box does not keep a control journal yet; update FTW". A refused src and E_UNAVAILABLE for the journal get their own words. The stub box answers events.get with spans and notices and records each query. Tests cover the default window and zone, a local since, Unix ms, source, severity, limit, paging, refused arguments and the old box. events_query stays off the public profile until it is reviewed there; events_list stays an unsupported name. Needs srcfl/ftw feat/control-journal (go/protocol EventSpan, Events with spans and notices). internal/mcp grows by about 330 lines of Go without tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 13974efb57
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if hasSpans && len(starts) >= n { | ||
| until, found = spanEnd, true | ||
| } |
There was a problem hiding this comment.
Ensure the next-page boundary advances past repeated spans
When limit is 1 and multiple spans match the window, setting the next until to the returned span's start cannot advance pagination: the inclusive overlap behavior described here includes that same span again, so the next response returns the same span and cursor with more: true. The same problem occurs at larger limits when enough spans share the boundary timestamp. Older control events therefore remain inaccessible by following the supplied paging instructions. Detect non-progress and provide a usable fallback, such as increasing the limit or narrowing the source, rather than repeatedly recommending the same boundary.
Useful? React with 👍 / 👎.
A page full of spans from one moment gave a next until at that same moment, so a caller following next never ended. It now steps past that moment and says what that may leave out. A time at or before 1970 is refused, since the box reads 0 as no bound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem
The box now keeps a control journal and answers the agent read
events.get(srcfl/ftw#1982, merged fd4426a1). Until now this server told models that events were unavailable and sent them tologs_tail, which is a 2,000-line ring in memory, so an assistant could not answer "why did the app say FTW is not in control this morning?".Change
events_query:sinceanduntil(RFC 3339, Unix ms, or a local time read in the home's zone; the last 24 hours by default),source,min_severity(warning or alarm),limit(1–50). It answers with spans (time range in the home's zone, kind, source id, status, reason, severity, duration, asked and measured watts, the verdict's numbers), the notices in the window, and how to page whenmoreis true.E_UNKNOWN_OP; the tool says "This box does not keep a control journal yet; update FTW" and points tologs_tailandhealth_get. A refused source and an unavailable journal get their own messages.README.mdanddocs/public-plugin.mdare updated.go/protocolmoves to srcfl/ftw@fd4426a1, the merge of #1982. This is the second half of a wire pair.The tool is on base
/mcponly.publicToolsays a new tool needs review before the public profile lists it; that is a separate decision.internal/mcpgrows by about 330 lines of Go, not counting tests.Evidence
go vet ./...,go test -race ./...(21 packages),go test -tags ftwclouddev ./...andscripts/check-imports.shpass on this branch with the real pin.internal/mcp/events_test.gocovers the default window and zone, a localsince, Unix ms, source, severity, limit, paging, refused arguments that never reach the box, the old box, NaN and -0 numbers, and UTC output. The e2e stub answers events.get with spans and notices.Sample (from the e2e stub):
🤖 Generated with Claude Code