spec log spool batch uploads

This commit is contained in:
npc0-hue
2026-08-10 18:32:31 +08:00
parent ba2b1a9d9f
commit bd444f04b9
5 changed files with 114 additions and 0 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-08-10
@@ -0,0 +1,37 @@
## Context
The Run process captures supervised stdout and stderr correctly, but `SpoolLogSink` persists one request per line. The durable uploader scans and uploads those files once per second within a five-second deadline. A startup burst therefore creates a durable backlog that reaches the platform long after the process emitted it.
## Goals / Non-Goals
**Goals:**
- Persist and upload contiguous same-stream entries in bounded multi-entry batches.
- Drain pending log work promptly while retaining retryable, acknowledgement-driven durability.
- Keep log upload independent from control, job, and artifact work.
**Non-Goals:**
- Change platform log ingest routes or their contiguous-range contract.
- Add game-specific log behavior, browser polling, or unbounded in-memory buffering.
## Decisions
- Aggregate at the Run spool boundary. A short bounded in-memory builder groups entries only when their stream identity and sequence are contiguous, then writes one durable spool segment. This reduces both filesystem and HTTP work while preserving the existing spool retry model. Aggregating only in the uploader would retain thousands of per-line files and would not address disk pressure.
- Bound each durable batch by entry count and serialized payload size. A full batch is committed before later entries are accepted, so a crash can lose at most uncommitted in-memory lines; process capture will surface errors rather than silently discarding a committed range. A timer flush bounds latency for low-volume output.
- Flush pending batches repeatedly until no work remains or the channel work budget expires. The uploader remains in its own loop and uses a bounded context, so control and job loops remain independent.
- Keep platform acknowledgements range-based. Batches remain immutable after persistence and are removed only when the existing accepted range covers them.
## Risks / Trade-offs
- [Crash before a partial batch is committed] → Keep the aggregation window small and flush on process completion and uploader shutdown.
- [Large entry or encoded payload] → Commit that entry alone only when it satisfies the existing protocol bounds; reject unsafe oversized entries through the current validation path.
- [Backlog monopolizes a tick] → Use a finite per-cycle deadline and yield to the next scheduler turn.
## Migration Plan
Existing one-entry spool files remain valid and flush through the unchanged acknowledgement logic. New Run binaries begin producing multi-entry segments; rollback remains safe because the old spool reader already accepts a batch with multiple entries.
## Open Questions
- None.
@@ -0,0 +1,24 @@
## Why
Run currently persists and uploads one HTTP log batch for every captured output line. High-volume startup output can create thousands of pending requests faster than the five-second uploader window can acknowledge them, leaving the management terminal far behind the supervised process.
## What Changes
- Coalesce contiguous pending entries from the same Run log stream into bounded durable upload batches.
- Drain available log backlog continuously within bounded upload work so current output reaches the platform promptly without blocking control, job, or artifact channels.
- Preserve per-stream sequence continuity, checksums, retry retention, and acknowledgement semantics when a batch is rebuilt or retried.
## Capabilities
### New Capabilities
- `run-log-batch-upload`: Run-side durable aggregation and bounded delivery of supervised-process log streams.
### Modified Capabilities
- None.
## Impact
- Affects `run/spool` pending-log representation and flush behavior, plus `run/runtime` process-log spooling and uploader scheduling.
- Does not change platform API routes, browser contracts, game-specific lifecycle behavior, or artifact/control/job channels.
@@ -0,0 +1,30 @@
## ADDED Requirements
### Requirement: Run aggregates contiguous process log entries durably
The Run log spool SHALL persist contiguous entries from one stream as bounded multi-entry batches before upload. Each persisted batch MUST retain one stream identity, an ordered contiguous sequence range, and a checksum covering its complete entries.
#### Scenario: High-volume process output is captured
- **WHEN** a supervised process emits consecutive lines on the same declared stream
- **THEN** Run MUST persist them in bounded multi-entry batches instead of one durable upload batch per line
#### Scenario: Stream changes or bounds are reached
- **WHEN** a line belongs to another stream or adding it would exceed an aggregation bound
- **THEN** Run MUST commit the current batch and begin a separate batch without creating a sequence gap
### Requirement: Run drains pending log backlog within bounded channel work
The Run log uploader SHALL continue flushing acknowledged pending log batches while backlog exists, subject to its bounded log-channel work budget, without blocking control, job, or artifact channels.
#### Scenario: Backlog is present
- **WHEN** the spool contains more than one pending log batch
- **THEN** the uploader MUST attempt consecutive batches until the backlog is drained or its work budget expires
#### Scenario: Platform acknowledgement succeeds
- **WHEN** the platform acknowledges a multi-entry batch range
- **THEN** Run MUST remove that batch from the spool and advance the acknowledged watermark through the acknowledged sequence
### Requirement: Retry compatibility is preserved for old and new spool segments
The Run spool SHALL retain unacknowledged aggregated batches for retry and SHALL continue to flush existing one-entry segments using the same range acknowledgement semantics.
#### Scenario: Run restarts with pending segments
- **WHEN** Run restarts while old or aggregated log segments remain unacknowledged
- **THEN** it MUST retry each persisted segment without duplicating or skipping acknowledged sequences
@@ -0,0 +1,21 @@
## 1. Durable Batch Aggregation
- [x] 1.1 Add bounded same-stream entry aggregation to the Run log spool while preserving contiguous sequence and checksum validation.
- [x] 1.2 Flush partial aggregation state at lifecycle/process completion and durable-uploader shutdown.
## 2. Backlog Delivery
- [x] 2.1 Update the log uploader to keep draining pending batches within its bounded log-channel work budget.
- [x] 2.2 Preserve retry, acknowledgement, and old one-entry spool segment compatibility.
## 3. Verification
- [x] 3.1 Add unit coverage for aggregation boundaries, restart/retry behavior, and multi-entry acknowledgement cleanup.
- [x] 3.2 Add runtime coverage proving a high-volume stream catches up through bounded aggregated uploads.
- [x] 3.3 Run `go test ./...` in `run/`, `scripts/check-structure.sh`, and `openspec validate batch-run-log-spool-upload --strict`.
## Evidence
- 2026-08-10: `go test ./...` from `run/` passed.
- 2026-08-10: `scripts/check-structure.sh` passed.
- 2026-08-10: `openspec validate batch-run-log-spool-upload --strict` passed.