Skip to content

fix: bound shell output and exclude runtime files from recursive search - #1603

Open
santoshkumarradha wants to merge 21 commits into
devfrom
fix/1599-bounded-job-logs
Open

santoshkumarradha wants to merge 21 commits into
devfrom
fix/1599-bounded-job-logs

Conversation

@santoshkumarradha

@santoshkumarradha santoshkumarradha commented Sep 27, 2026 •

Copy link
Copy Markdown
Member

What changed

A recursive search could read its own runtime output and fill the disk. Both shell output paths now have explicit storage limits: background jobs keep their latest two 4 MiB chunks, while foreground bash retains an initial 8 MiB snapshot alongside its latest in-memory result tail. Foreground snapshots include the initial bytes; incomplete or failed snapshots no longer claim to contain full output.

Completed managed job logs and foreground snapshots each have a 128 MiB / 64-file budget per directory with seven-day expiry. Independent file leases protect active writers across processes. Background job IDs remain durable across cleanup. Foreground snapshots use exclusive random names under the state home's logs/bash/; promotion closes that snapshot before forwarding later output to the job sink. Logging failures remain visible while the child keeps draining.

Structured recursive search excludes known runtime output, including custom state homes, foreground snapshots, input history and project task indexes, and legacy pi-bash-*.log files in the current temporary directory. Source worktrees remain searchable; explicit file inspection is bounded. Arbitrary shell commands still need explicit search exclusions, and their captured output is bounded independently.

Selected workspace/session folder aliases are resolved before opening owned log storage. Links inside that storage remain refused. This prevents the new retention checks from breaking jobs for users with symlinked home/workspace paths.

Fixes #1599
Fixes #1600
Fixes #1601
Fixes #1602
Fixes #1606

Validation

  • Actual default hosted tmux chat on final combined revision 830d4c2eb passed all three corrected probes: structured search in 1.9 seconds returned only the source marker, foreground output completed in 1.7 seconds with an exactly 8,388,608-byte snapshot and a truthful limit notice, and a managed background job completed in 2.3 seconds with exit 0 and retained chunks of 4,194,304 and 3,097 bytes. All 13 completed calls used deepseek/deepseek-v4.1-flash through OpenRouter, including auxiliary roles; no call errors occurred.

  • The initial terminal search exposed prompt-history self-ingestion. The corrected exact-path exclusions were added and the final terminal probe above verified that runtime history no longer enters source results. Live test configuration now pins all 22 text roles from the canonical role vocabulary, every tier, and fallback settings.

  • On Spark, a controlled reproduction against the original PR revision b22359d07 wrote a 12,582,912-byte foreground spill. The fixed real-shell regression retains exactly 8 MiB and preserves the latest result tail with an explicit incomplete-snapshot notice.

  • Both engines reproduced the prompt-history self-ingestion before the fix; the final history/task-index and foreground-spill exclusion regressions passed in 0.87 seconds.

  • Full internal/exec/bare suite passed in 12.06 seconds. Focused race checks covering foreground spills, cross-process writer leases, retention, promotion, failures, and both search engines passed in 4.05 seconds.

  • Focused background spool/retention suite passed in 14.27 seconds. Final regressions for selected-folder aliases, startup expiry, unsafe linked descendants, and an actual shell search consuming its own job log passed in 0.52 seconds.

  • make build passed at 9dbd1c286. Manual, performance limits, and change entries describe both storage contracts and their limits.

  • The local light gate passed build, vet, manual checks, changelog validation, all 30 law packages, and the affected bare/e2e package suites. The final two-shard session suite ran for 423 seconds and had one failing test: TestAChildLandingAfterItsParentSettledReachesTheConversation timed out while observing its transient steering queue. The same failure reproduced on the original PR revision (4/30 runs); diagnostic repeats proved all four sampled failures had already delivered the exact message (queued=false, durable=true). The assertion now reads the existing transcript-plus-queues helper and preserves its timeout, expected content, and settled-parent report check. The corrected test passed 100 repeats in 3.686 seconds at 734d6eb3d. This full local gate remains recorded as failed. Fresh isolated CI at public head 734d6eb3d0bbd9eb311ca70a6e3e42c9a2dfda80 subsequently passed all checks, including touched packages: https://github.com/Agent-Field/CodeAF/actions/runs/36329255094.

Boundaries

These are per-job/per-directory limits, not a machine-wide disk quota. Active writers and unmarked/unsafe legacy files are outside completed-file retention. Existing large legacy files are preserved. No production logs were deleted by this change.

agentfield-bot and others added 12 commits September 27, 2026 00:43
A background job's log used to grow without limit: every byte the job
wrote went to one <id>.log forever, a single huge Write grew the
in-memory ring by its whole length before trimming, and a failed or
short or unclosable spool write was swallowed whole. A watcher that
prints for a week filled the disk at whatever rate it printed.

The spool is now a window: at most jobSpoolChunks chunks of
jobSpoolChunkBytes (4MB) on disk — <id>.log live, <id>.log.1 kept —
rotated by rename and never rewritten per write, the chunk beyond the
window deleted and counted. One huge Write spools in chunk-sized
pieces and hands only its newest 64KB to the ring, so no temporary
grows to match it. A failed, short or failed-to-close spool write
records one notice, stops the retries, and never stops the drain or
kills the job.

Every footer a model reads — jobs output and the completion note alike
— stays honest about the bound: full log while the file is everything
the job wrote, the truncation or the failure named beside the path
where it is not. The manual's promises of the whole log, the jobs tool
description and PERF.md move with it.

Retained output stays addressable by the read tool exactly as before.
Aggregate retention across jobs and search exclusion are deliberately
not in this change. Issue #1599.

Assisted-by: CodeAF
Co-Authored-By: CodeAF <267109073+agentfield-bot@users.noreply.github.com>
@santoshkumarradha santoshkumarradha added this to the Reliable agent milestone Sep 27, 2026
@santoshkumarradha santoshkumarradha added bug Something the code does that it should not area:session The engine — turns, tasks, the toolbelt, checkpoints area:tools The tool layer: built-in tools, registries, belts area:logging The debug record: call log, trace, journal sev:critical Data loss, money spent wrongly, a false done, or the merge queue blocked labels Sep 27, 2026
@santoshkumarradha
santoshkumarradha marked this pull request as ready for review September 27, 2026 05:50
@santoshkumarradha santoshkumarradha changed the title fix: bound background logs and exclude runtime output from search fix: bound shell output and exclude runtime files from recursive search Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:logging The debug record: call log, trace, journal area:session The engine — turns, tasks, the toolbelt, checkpoints area:tools The tool layer: built-in tools, registries, belts bug Something the code does that it should not sev:critical Data loss, money spent wrongly, a false done, or the merge queue blocked

Projects

None yet

2 participants