Skip to content

Upload every channel a producer publishes - #31

Merged
CodingInAVan merged 4 commits into
mainfrom
serving-channel
Oct 29, 2026
Merged

CodingInAVan merged 4 commits into
mainfrom
serving-channel

Conversation

@CodingInAVan

@CodingInAVan CodingInAVan commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Makes the agent a channel-agnostic transport (LLM-serving plan P1.5, revised 2026-10-27). Any producer that writes the session layout (the native gpufl-client, the Python gpufl-serving writer, future tools) gets its channels uploaded with no agent or launcher change for each new producer.

Discovery finds channels instead of listing them. A name is a channel only if the session directory holds .gpufl-window.<channel>.<N>.json that parses as a JSON object with integer payload_bytes and payload_crc32. That file is also what remains as the ACK tombstone, so one rule covers both. A bare *.log never makes a channel, so an application log left in a session folder (a server log can hold prompts) is never uploaded; the only exception is today's legacy pre-v1.2 handling of the four native names, unchanged. Channel names must match [A-Za-z0-9_-]{1,64}, the backend's rule. At most 16 channels per session: a session over the cap tails its first 16, logs an error, is never reported complete and is marked .failed.

--log-types / GPUFL_LOG_TYPES only narrows. Unset (the new default) tails every channel found. Set, it tails only those channels, and a directory is recognized only by them, so a narrowed agent never adopts and marks .uploaded a directory it cannot fully upload. Existing configs and env vars work unchanged.

Late channels. A channel whose first window appears while the session is live gets a tailer on the next scan. Before session-complete, the last tailer rescans under the session's lock, so a channel published just before completion is still uploaded. Completion still waits for the lock release and .tmp/ removal.

Producer contract. docs/session-layout.md (linked from the README) writes down what the agent consumes: directory naming, the lock and how it is probed, .tmp/ staging, window naming, sidecar fields and CRC32, ACK tombstones, markers and lifecycle rows, with what the agent tolerates but producers should not rely on.

Launcher: gpu-flight/gpufl-client#186 stops passing a default list to the agent it starts. An older launcher passes the four native channels, which then act as a filter, so serving users add --log-types=device,scope,system,sass,serving there.

Testing

  • ./gradlew check: 183 tests, 0 failures, 1 skipped (the existing Linux/macOS-only lock test); JaCoCo passes.
  • End to end against a fake backend: a bare server.log next to a serving window is never uploaded and never makes a channel; a native session uploads exactly its four channels; a serving-only session and an unknown producer channel (foo) upload with no configuration; with device,scope,system,sass set, a serving-only directory is not adopted; channels published late (one while live, one just before finish) are uploaded before session-complete; a session over the channel cap is never reported complete.
  • Also checked from the Python side earlier: the gpufl-serving writer's output, uploaded by this branch's jar to a local stand-in backend, round-trips with matching CRCs and one completion.

The Python serving writer produces sessions whose only channel is
serving: serving.<N>.log.gz windows with sidecars, a .tmp/ staging dir
and the session lock, but no device, scope, system or sass file.
Discovery matched only the four native channels, so such a directory
was never tailed, and serving was not tailed by default either.

Add serving to the default log types and derive the discovery patterns
from that one list, so a known channel can no longer be tailed without
being discovered. LogSourceConfig now uses the same constant instead of
its own copy. Window records stay opaque; the agent only transports them.
Discovery matched every known channel while the tailers follow the
configured log types. The launcher still starts the agent with
device,scope,system,sass, so such an agent would adopt a serving-only
directory, tail none of its windows, signal session-complete and mark it
.uploaded once the lock is released, and a later agent that does tail
serving would then skip it: a new way to lose serving data.

Build the discovery patterns from the configured types, with each name
quoted since it comes from configuration. An agent that does not tail
serving now leaves a serving-only directory alone; the default types
still include serving.
The agent is meant to be a channel-agnostic transport: the native client,
the Python serving writer and future producers write the session layout,
and the agent ships whatever channels they publish, with no agent or
client change for each new producer.

Discovery now finds a session's channels. A name is a channel once the
directory holds a window sidecar for it (JSON carrying the payload size
and CRC32 the tailer verifies), which also stays as the ACK tombstone. A
bare *.log file never makes a channel, so an application log next to the
windows, which could hold prompts, is never read or uploaded. The four
native channels keep their legacy recognition by bare window files.
Names follow the backend's [A-Za-z0-9_-]{1,64} rule, and a session is
capped at 16 channels so a broken producer cannot spawn unbounded
tailers; a session over the cap is never reported complete, is marked
.failed and is not pruned.

--log-types becomes an optional filter, empty by default. When set, only
those channels are tailed and a directory is recognized only by them, so
a filtered agent still never adopts a directory it cannot upload.

A channel whose first window appears while the session is live gets a
tailer on the next scan, and the last tailer to finish rescans once more
before session-complete, so a channel published just before the producer
finished is not missed.
With the agent shipping any channel it finds, the on-disk layout is the
contract between it and every producer. Write it down: session
directories, the lock file and how the agent probes it, .tmp/ and what
its removal means, window naming and numbering, the sidecar fields and
CRC32, ACK tombstones, the markers, completion, record contents and the
lifecycle rows. Each statement is taken from the agent code or the
native writer, and what the agent only tolerates is marked so a new
producer does not depend on it.

Link it from the README, which now describes channel discovery and the
--log-types filter.
@CodingInAVan CodingInAVan changed the title Upload serving-only session directories Upload every channel a producer publishes Oct 29, 2026
@CodingInAVan
CodingInAVan merged commit 3c8cccc into main Oct 29, 2026
4 checks 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