diff --git a/templates/agent/HEARTBEAT.md b/templates/agent/HEARTBEAT.md index 2b447d006b..0fdaf70580 100644 --- a/templates/agent/HEARTBEAT.md +++ b/templates/agent/HEARTBEAT.md @@ -175,11 +175,27 @@ timeout and it still failed" reports tonight never actually tested a raised time **RUN EACH FILE AS A BACKGROUND / UNCAPPED CALL. NEVER GATE COMPLETION ON A TIMEOUT, EXIT CODE, OR ELAPSED TIME.** ```bash cortextos bus kb-ingest "$f" --org "$CTX_ORG" --agent "$CTX_AGENT_NAME" --scope private --force \ - > "/tmp/kb-ingest-${CTX_AGENT_NAME}-$$-$(basename "$f").log" 2>&1 & + > "/tmp/kb-ingest-${CTX_AGENT_NAME}-$(date -u +%Y%m%d-%H%M%S)-$$-$(basename "$f").log" 2>&1 & ``` `$$` alone collides across concurrent agent sessions on a shared host — `$CTX_AGENT_NAME` in the filename is required, not cosmetic (infra, 2026-08-25: a single heartbeat's log came back -interleaved with 7+ other agents' ingest output under the un-namespaced path). +interleaved with 7+ other agents' ingest output under the un-namespaced path). `$CTX_AGENT_NAME-$$` +alone is still not sufficient: PIDs get reused across days on a long-running box, and time-of-day-only +labels (`hb2342`, `hb0342`) collide identically — infra, 2026-09-05, caught its own prior-day 429 log +being misread as current via an hb-time-only filename. The UTC date+time component kills both the +cross-agent and cross-day/cross-hour collisions in one form. + +⚠️ **`${BASHPID}` was tried and reverted the same day (CodeRabbit's original suggestion on PR #178): +it is a BASH-ONLY special variable and is UNDEFINED in zsh, which is the actual shell every agent's +Bash tool (and this box's `$SHELL`) executes commands in — verified directly (`ZSH_VERSION` set, +`BASH_VERSION` empty, `${BASHPID}` expands to nothing). Shipping it produced literal double-hyphen, +empty-differentiator filenames in the real execution environment despite passing verification via an +explicit `bash script.sh` subprocess — a different, non-representative shell context. `$$` remains +the working differentiator here; it does not distinguish two `&`-launched siblings from the exact +same loop iteration, but the Step 10 loop always launches DISTINCT files per iteration (basename +already differentiates), so that theoretical gap does not occur in the documented usage.** PID +remains only as the final tiebreaker +for two calls landing in the same second. The only valid completion signal is the literal text `Ingest complete` appearing in that log — not `rc=0`, not a chunk count alone, not silence. If it hasn't appeared by the time you move on to other work, check