Skip to content

perf(tapper): run whole TAP operations and grep on the Hub - #121

Merged
jlrickert merged 6 commits into
mainfrom
feat/tap-operations
Sep 29, 2026
Merged

jlrickert merged 6 commits into
mainfrom
feat/tap-operations

Conversation

@jlrickert

Copy link
Copy Markdown
Owner

Client half of the Hub's shared-application-API work (foldwise/tapper-hub#149–#153). It moves whole TAP operations and searches to the server, so one agent action is one request instead of hundreds, and adopts REST contract 2026-09-28.

  • Listing fields in one batch (6ef218e). Grep, links, backlinks, and tags against a Hub KEG read metadata once per rendered node, so one agent grep could make hundreds of sequential requests. GrepOptions gains fields/offset/limit, ListViewOptions gains node_ids, and RelatedNodes returns the pairs that produced each entry.
  • Whole TAP operations (5a28410). The new pkg/tapapi holds the wire types. Tap.Operations sends links, backlinks, tags, and cat for a Hub KEG to /api/v1/tap/*, and composes the individual KEG operations only when there's no Hub. tap mcp reuses a session's resolved orientation for up to ten seconds instead of rebuilding it on every tool call.
  • Replacement routes (ab3ea8e). RemoteKeg stops calling the retired single-item and per-kind routes. Move, snapshot restore, and remove become batches of one, and files and images use the kind-qualified attachment routes. The REST contract revision becomes 2026-09-28.
  • Streaming grep and metadata-only reads (e3f1d5b). Grep streams a repository's content scan and keeps only matching lines, so memory follows the result rather than the KEG. ReadNodes gains MetaOnly: metadata and stats without content, in one consistent read.
  • Repository-side grep (2336e82). A repository implementing RepositoryGrep runs the whole search in its own regex engine and returns only matching lines. The Hub uses this to grep inside PostgreSQL. Local KEGs keep Go RE2, and node_search says which dialect applies.
  • Test (aa17d20). A metadata-only read of a node with no metadata and old stats returns empty metadata and the same hash a full read gives.

Compatibility: coordinated upgrade. This client requires a Hub that serves 2026-09-28, and that Hub (tapper-hub#152) removes the routes older clients call. Merge this before the Hub stack. Pinning the Hub to the merged SHA is left for release planning.

Verification: go build, go vet, and go test ./... pass; so do go test -race for pkg/keg, pkg/tapper, and pkg/parity, and task lint:docs and task lint:fs.

A formatted grep, links, backlinks, or tags listing against a Hub keg read
metadata once per rendered node, so one agent grep could make hundreds of
sequential requests. Fields are now resolved where the data lives:

- GrepOptions gains fields, offset, and limit; the keg pages matches and
  projects fields, so a formatted grep is one request.
- ListViewOptions gains node_ids, so any known result set resolves its fields
  with one listing call.
- RelatedNodes returns the pairs that produced each entry, replacing the
  per-input lookups the relationship observer made.
- An optional RepositoryContentScan capability lets a backend answer grep in
  one scan, narrowed by an index when the pattern is a plain literal.
- pkg/tapapi defines the wire contract for complete TAP operations a Hub
  executes under /api/v1/tap/*.
- The client-side listing fallback for hubs without /list/view is removed, and
  the REST contract revision moves to 2026-09-28.
Links, backlinks, and tags against a Hub KEG composed several requests on the
client, and every MCP tool call rebuilt the session's orientation from about
five Hub requests (#123):

- Tap.Operations executes links, backlinks, and tags as one unit.
  DefaultOperations forwards a Hub KEG's operation to /api/v1/tap/* through
  RemoteKeg.HubPost and composes KEG operations only without a Hub.
- tap mcp reuses a session's resolved orientation for up to ten seconds.
  orient, session_refresh, flight mutations, and failed calls discard it; the
  Hub still rechecks authority on every request.
- Single-node cat reads and touches in one request.
- An invalid grep pattern is reported as invalid input.
RemoteKeg still reached the Hub through retired single-item and per-kind
routes. Route every call through its replacement so those routes can go:

- Move is a batch of one on POST /nodes/move.
- RestoreSnapshot is a batch of one on POST /nodes/snapshots/restore,
  guarded by the hash from the node's metadata ETag.
- File and image calls use the kind-qualified attachment routes.
- RemoveBatch adapts POST /nodes/remove, the Hub's single removal contract;
  it previously expected a response shape the Hub never sent.

Batch restore now accepts the root node, which can be restored from its own
history; move and remove still refuse it.
Grep now streams a repository's content scan and keeps only matching
lines, so memory follows the result rather than the KEG. The scan is
narrowed by every substring a match must contain, taken from the parsed
regular expression, so an index can serve regex patterns and not just
plain literals. Case-insensitive substrings are limited to ASCII and
split at 's' so a lowercase comparison never drops a match Go's case
folding would find.

ReadNodes gains meta_only: metadata and stats in one consistent read,
without content or asset lists, for rendering metadata fields.
A repository implementing RepositoryGrep now runs the whole content
search itself and returns only matching lines, so node content never has
to be read out to be searched. The backend owns its regex dialect and
reports a pattern it cannot evaluate as invalid; local KEGs keep Go's
RE2 matcher. This replaces the content-scan capability and its
substring extraction.

The node_search tool now says which dialect applies: Go RE2 locally,
PostgreSQL regular expressions on a Hub.
A node with no metadata whose stats predate the state hash still reads as a node: empty metadata and a hash derived from its content, matching a full read.
@jlrickert
jlrickert merged commit 0417746 into main Sep 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant