refactor(events): record tool capabilities on the invocation event

Capability is the canonical signal the plane-2 gates dispatch on, but
ToolInvocationRequestedEvent only carried the tool name — so ReadFilesProjection
classified reads by a hardcoded "file_read" string, bypassing the abstraction and
(worse) re-deriving a semantic fact at replay from whatever the name meant. That
violates the event-sourcing invariant that replay reads recorded facts, not live
state.

Now the tool's requiredCapabilities are recorded on the event at emission, and the
projection classifies by ToolCapability.FILE_READ. To let the lowest module carry
it, ToolCapability moves from core:tools into core:events keeping its package, so
every existing import resolves unchanged and core:tools imports it from below. The
field is defaulted, so pre-existing events deserialize as empty.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-24 19:46:44 +00:00
parent 78e7a4fefb
commit 9b003d02ea
6 changed files with 37 additions and 19 deletions
@@ -648,6 +648,7 @@ abstract class SessionOrchestrator(
toolName = toolCall.function.name,
tier = tier,
request = request,
capabilities = tool?.requiredCapabilities ?: emptySet(),
),
)
if (toolCall.function.name != STAGE_COMPLETE_TOOL &&