Depends on
None.
Blocks
- File-tail logs endpoint (needs
FileSink + JobLogTransport)
Problem
ProgressDisplay writes to stdout directly. The CLI epic needs per-job log capture so an HTTP client can tail a single job's output without seeing every other job's lines mixed in.
Proposed
Introduce two traits in ccas.server.jobs:
trait JobLogSink:
def write(line: String): UIO[Unit]
trait JobLogTransport:
def subscribe(jobId: JobRunId): ZStream[Any, Throwable, String]
Two JobLogSink impls in this issue:
StdoutSink — current behaviour, default for non-job code paths.
FileSink(path) — writes a per-job log file to ${log_dir}/<job_id>.log and tees to stdout so the server console still shows everything.
JobLogTransport is sketched (interface only); the FileTail impl arrives in the file-tail logs endpoint issue.
ProgressDisplay is parameterised by JobLogSink instead of writing to stdout directly. JobRunner.submit injects a FileSink per job into the job's effect environment via a ZLayer.
Acceptance
- All existing usages of
ProgressDisplay compile via the StdoutSink-injected layer.
JobRunner.submit threads a fresh FileSink per job.
- New test asserts an in-memory sink captures expected output lines for a recorded job (use the existing test fixtures for any
ProgressDisplay-heavy app).
Files
src/main/scala/ccas/utils/prettyprinting/ProgressDisplay.scala
src/main/scala/ccas/server/jobs/JobRunner.scala
- new
src/main/scala/ccas/server/jobs/JobLogSink.scala
- new
src/main/scala/ccas/server/jobs/JobLogTransport.scala
Reference
Tracked under epic #40 (CLI v0). Roadmap: ~/.claude/plans/ultra-sparkling-unicorn.md § "Phase 1, new work #5" + log-transport architecture note.
Depends on
None.
Blocks
FileSink+JobLogTransport)Problem
ProgressDisplaywrites to stdout directly. The CLI epic needs per-job log capture so an HTTP client can tail a single job's output without seeing every other job's lines mixed in.Proposed
Introduce two traits in
ccas.server.jobs:Two
JobLogSinkimpls in this issue:StdoutSink— current behaviour, default for non-job code paths.FileSink(path)— writes a per-job log file to${log_dir}/<job_id>.logand tees to stdout so the server console still shows everything.JobLogTransportis sketched (interface only); theFileTailimpl arrives in the file-tail logs endpoint issue.ProgressDisplayis parameterised byJobLogSinkinstead of writing to stdout directly.JobRunner.submitinjects aFileSinkper job into the job's effect environment via a ZLayer.Acceptance
ProgressDisplaycompile via theStdoutSink-injected layer.JobRunner.submitthreads a freshFileSinkper job.ProgressDisplay-heavy app).Files
src/main/scala/ccas/utils/prettyprinting/ProgressDisplay.scalasrc/main/scala/ccas/server/jobs/JobRunner.scalasrc/main/scala/ccas/server/jobs/JobLogSink.scalasrc/main/scala/ccas/server/jobs/JobLogTransport.scalaReference
Tracked under epic #40 (CLI v0). Roadmap:
~/.claude/plans/ultra-sparkling-unicorn.md§ "Phase 1, new work #5" + log-transport architecture note.