Skip to content

Integration: performance, MCP schemas and errors, flight switches, archives - #134

Merged
jlrickert merged 18 commits into
mainfrom
integration/all
Oct 21, 2026
Merged

jlrickert merged 18 commits into
mainfrom
integration/all

Conversation

@jlrickert

Copy link
Copy Markdown
Owner

Summary

Eighteen commits of client, MCP, keg-engine, and relay work, each a self-contained step that builds and vets on its own.

Performance

  • tap info fetches its context in one call with a parallel fallback; orient stops fetching the keg catalog twice; hub API discovery is cached on disk.
  • Touch is cheap and its keg-lock wait is bounded; snapshot timelines and dirty-index reads are batched.

MCP

  • Every tool declares an output schema, and relays carry it to Hub. Failed results carry no structured content.
  • node_search takes one kegs list scoped to the call's flight; id_only is dropped in favor of format: "%i".
  • Failures are classified by kind (conflict, restoring, rate limit, invalid input, not found) and reported as refusals; repeated identical failures are flagged; missing-hash errors point at node_read, and bad node_edit schema values are explained.
  • Local attachment uploads and downloads are confined to the working directory; downloads create new owner-only files and never overwrite.
  • Tool and parameter descriptions are tidied; flight is explained once, on its parameter.

Flights

  • A flight's manageKegs switch lets a request rooted on it create, delete, and administer the KEGs of its namespace; manageFlights lets it create, edit, and delete the namespace's flights. Both work on the CLI and MCP, and neither passes the user's own role.
  • Agent sessions are described by their allowlist and flight; lock acquisition waits a bounded time; bare flight refs resolve the same way in tap info and orient.

Archives

  • Archives are indexed by offset instead of loaded into memory, share their limits between export and import, and replace a keg's contents on import while keeping snapshot content hashes.
  • Staging enforces the tar size limit, refuses hostile asset names and oversized entries before sizing them, and bounds index memory. Archive import reports unsupported against a hub.

Auth, telemetry, and relay

  • The auth store refreshes in one process at a time, and logout and login stay authoritative over a running refresh. Only invalid_grant and invalid_client count as a refused refresh.
  • Telemetry spools key on a stable account key, stay with the hub login that recorded them, and a refused credential stops only the current process.
  • Relays reauth in band with protocol 4 frames and end codes, reconnect on credential_expired, and retry a failed token refresh.
  • Adopts API contract revision 2026-10-17.

Includes the attachment confinement change from #117.

Testing

  • go build ./..., go vet ./..., and go test ./...
  • -race for pkg/keg, pkg/tapper, and pkg/parity
  • task lint:docs, task lint:fs
  • Every commit builds and vets on its own with GOWORK=off

tap info fetches its context in one call with a parallel fallback,
orient stops fetching the keg catalog twice, telemetry spools events
instead of flushing at exit, and the auth store is guarded against
concurrent access.

- fix(auth): guard the auth store against concurrent access
- perf(info): fetch context in one call with parallel fallback
- perf(orient): drop the duplicate keg catalog fetch
- perf(telemetry): spool events instead of flushing at exit
- perf(api): cache hub API discovery on disk
- fix(info): decode the hub's context shape and send bare slugs
- fix(mcp): point missing-hash errors at node_read
- fix(mcp): constrain and explain node_edit schema values
- feat(mcp): flag repeated identical tool failures
Archives are read through one lookup interface and indexed by offset
instead of loaded, export and import share their limits, an import
replaces the keg's contents, and snapshot content hashes survive it.

- refactor(keg): read archive entries through one lookup interface
- feat(keg): index archives by offset instead of loading them
- feat(keg): share archive limits and replace keg contents on import
- fix(keg): keep snapshot content hashes through archive import
- refactor(keg): drop the in-memory archive reader
A batch placeholder used as a bare link target resolves, each hub
login's spooled telemetry stays with that login, bare flight slugs agree
with orientation, and the archive spool belongs to the process that
wrote it.

- fix(keg): link batch placeholders used as bare link targets
- docs(mcp): show the ../ prefix for batch node links
- fix(telemetry): keep each hub login's spooled events to that login
- test(info): check bare flight slugs agree with orientation
- fix(keg): make touch cheap
- fix(keg): bound how long touch waits for the keg lock
- perf(keg): load the snapshot timeline once per batch
- perf(keg): batch dirty index reads
- fix(mcp): describe tools for hub-hosted KEGs only
- fix(mcp): explain flight once, on the flight parameter
- docs(mcp): tidy tool and parameter descriptions
- refactor(mcp): drop id_only in favor of format %i
Every tool declares an output schema that relays carry to Hub,
node_search takes one kegs list scoped to the call's flight, and failed
results carry no structured content.

- feat(mcp): scope node_search to the call's flight with one kegs list
- feat(mcp): declare an output schema for every tool
- feat(relay): carry each tool's output schema to Hub
- docs(mcp): document output schemas, kegs scope, and retired arguments
- fix(mcp): send failed tool results without structured content
- feat(relay): reconnect when Hub reports credential_expired
- fix(relay): retry when refreshing the relay token fails
- fix(relay): leave off output schemas before dropping MCP servers
Telemetry spools key on a stable account key minted under the auth store
lock and stop only the current process on a refused credential, search
keeps only the cover KEGs the role check grants, archive entry names and
index memory are bounded, and flights are read fresh.

- fix(telemetry): key the spool on a stable account key
- fix(telemetry): remember a hub's rejection for a day per version
- docs(keg): say the keg lock wait bound is advisory and in-process
- fix(search): keep only cover KEGs the role check grants
- fix(keg): bound archive entry names and import index memory
- fix(flight): read flights fresh for flight_read and flight show
- fix(telemetry): mint the account key under the auth store lock
- fix(telemetry): stop only this process on a refused credential
Only invalid_grant and invalid_client count as a refused refresh, bare
flight refs are described as the hub resolves them, and archive import
reports unsupported on a hub.

- fix(auth): treat only invalid_grant and invalid_client as a refused
  refresh
- docs(tapper): describe bare flight refs as the hub resolves them
- fix(keg): report archive import as unsupported on a hub
- feat(apicontract): adopt revision 2026-10-17
- fix(auth): keep logout and login authoritative over a running refresh
- docs(auth): describe the store lock around login, logout and refresh
- fix(orient): describe agent sessions by allowlist and flight, not
  identity authority
- feat(lock): bound how long lock acquisition waits for a held lock
- test(parity): exclude ActiveAgent from surface coverage as an internal
  read
- feat(relaycontract): add protocol 4 reauth frames and end codes
- fix(relay): reauth before credential expiry and map each end code
- fix(relay): force a token refresh when the hub expires or refuses it
- docs(relay): describe in-band reauth and the end codes
- fix(mcp): report conflicts, restores and rate limits as refusals
- fix(keg): classify caller query and settings parse errors as invalid
- fix(tapper): wrap caller-supplied node ids and guide topics as invalid
- fix(mcp): classify upload sources and locked sessions
- fix(mcp): count repeat failures on the arguments as sent
- test(mcp): cover error classification by kind and tool
- docs: document the MCP failure result shape
- fix(mcp): classify remaining caller-input and missing-node failures
- refactor(keg): remove node import and narrow it to engine kegs
- fix(keg): count raw tar bytes and stop staging at the size limit
- fix(keg): refuse hostile asset names when staging an archive
- fix(keg): refuse an entry larger than the tar limit before sizing it
A flight's manageKegs switch lets a request rooted on it create, delete,
and administer the KEGs of its namespace, and manageFlights lets it
create, edit, and delete the namespace's flights, on the CLI and MCP
alike. Neither passes the user's own role.

- feat(flight): let a flight manage its namespace
@jlrickert
jlrickert merged commit 3645bda into main Oct 21, 2026
1 check passed
@jlrickert
jlrickert deleted the integration/all branch October 21, 2026 07:04
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