Skip to content

fix(heartbeat): bound HEARTBEAT.md file read size#101775

Merged
steipete merged 3 commits into
openclaw:mainfrom
cxbAsDev:fix/bound-heartbeat-file-read
Jul 18, 2026
Merged

fix(heartbeat): bound HEARTBEAT.md file read size#101775
steipete merged 3 commits into
openclaw:mainfrom
cxbAsDev:fix/bound-heartbeat-file-read

Conversation

@cxbAsDev

@cxbAsDev cxbAsDev commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

resolveHeartbeatPreflight in src/infra/heartbeat-runner.ts read the workspace HEARTBEAT.md with an unbounded fs.readFile, allowing an arbitrarily large file to be loaded into memory and processed by the heartbeat pipeline.

Why This Change Was Made

Switch to readRegularFile with a 16 MiB cap so the read is bounded and rejects non-regular files. Symlinks are resolved via fs.realpath first, so a HEARTBEAT.md symlinked to a valid regular file keeps working while dangling symlinks still surface as ENOENT (treated as missing, by design). This aligns with other bounded-read fixes in the repo and prevents accidental or malicious oversized heartbeat files from causing memory pressure.

User Impact

Oversized HEARTBEAT.md files are now skipped: the heartbeat run continues without the file content, and the operator sees a gateway/heartbeat warning (skipping oversized HEARTBEAT.md: File exceeds 16777216 bytes: ...) explaining why the file no longer applies. Normal-sized and symlinked heartbeat files behave exactly as before.

Evidence

  • src/infra/heartbeat-runner.oversized-heartbeat-file.test.ts: regression tests for (a) a symlinked HEARTBEAT.md loading through realpath and (b) a 16 MiB + 1 byte file being skipped while the run continues and the operator-visible warning fires.
  • Final-head runtime proof (a6074aaceeafc379434e5207500a3e46f52c5f6f, rebased onto upstream/main 851f76cb0d0): standalone driver invoking the real exported runHeartbeatOnce path against /tmp fixtures with an isolated HOME, model reply and Slack delivery stubbed via HeartbeatDeps. Transcript in the comments.
  • Focused tests on the final head: node scripts/run-vitest.mjs src/infra/heartbeat-runner.oversized-heartbeat-file.test.ts --run passes (2/2).

Real behavior proof

Final head a6074aaceeafc379434e5207500a3e46f52c5f6f. Fixture paths are throwaway /tmp dirs.

--- case: symlink ---
HEARTBEAT.md lstat: isSymbolicLink=true size=58 (cap=16777216)
runHeartbeatOnce status: ran
captured prompt contains PROOF-MARKER: true
captured prompt bytes: 626
slack deliveries: 1

[heartbeat] skipping oversized HEARTBEAT.md: File exceeds 16777216 bytes: /tmp/openclaw-hb-proof/oversized/workspace/HEARTBEAT.md
--- case: oversized ---
HEARTBEAT.md lstat: isSymbolicLink=false size=16777246 (cap=16777216)
runHeartbeatOnce status: ran
captured prompt contains PROOF-MARKER: false
captured prompt bytes: 559
slack deliveries: 1
$ node scripts/run-vitest.mjs src/infra/heartbeat-runner.oversized-heartbeat-file.test.ts --run
 ✓ |infra| src/infra/heartbeat-runner.oversized-heartbeat-file.test.ts (2 tests) 942ms
     ✓ follows a symlinked HEARTBEAT.md to a regular file  833ms
 Test Files  1 passed (1)
      Tests  2 passed (2)
[test] passed 1 Vitest shard in 14.88s

@clawsweeper

clawsweeper Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 15, 2026, 11:31 PM ET / July 16, 2026, 03:31 UTC.

Summary
The PR replaces the unbounded HEARTBEAT.md read with a 16 MiB regular-file read, preserves symlinked regular files, warns when oversized content is skipped, and adds regression tests.

PR surface: Source +16, Tests +112. Total +128 across 2 files.

Reproducibility: yes. from source: the prior path uses an unbounded whole-file read, and a file over the proposed threshold reaches that path; the supplied final-head driver verifies the corrected behavior, although it does not measure a current-main out-of-memory event.

Review metrics: 1 noteworthy metric.

  • Heartbeat file limit: 1 hard limit added: 16 MiB. This turns a previously unbounded accepted input into an upgrade-sensitive runtime policy that maintainers should explicitly approve.

Stored data model
Persistent data-model change detected: serialized state: src/infra/heartbeat-runner.oversized-heartbeat-file.test.ts, serialized state: src/infra/heartbeat-runner.ts. Migration or upgrade compatibility proof is recorded; maintainers should verify it before merge.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Obtain maintainer approval for the 16 MiB fail-open behavior and refresh the branch against current main.

Risk before merge

  • [P1] After merge, an existing HEARTBEAT.md larger than 16 MiB stops contributing instructions even though the heartbeat still reports a successful run and continues delivery; the only direct signal is a gateway warning.
  • [P1] The hardcoded 16 MiB threshold and fail-open behavior are new compatibility policy, not merely an internal implementation detail, and no maintainer approval is visible in the supplied discussion.
  • [P1] The branch is behind current main; GitHub reports it mergeable, but the exact merged result should receive a refreshed review and check pass after updating the base.

Maintainer options:

  1. Land the bounded fail-open policy (recommended)
    Accept the 16 MiB limit and gateway warning as the supported upgrade behavior, then refresh the branch and exact-head checks.
  2. Make rejection impossible to miss
    Change oversized-file handling to surface a failed heartbeat outcome or equivalent operator-visible status before merge.
  3. Pause pending a different compatibility contract
    Hold the PR if maintainers want configurable limits or continued support for unusually large heartbeat files.

Next step before merge

  • [P2] A maintainer should choose and own the oversized-file upgrade contract; there is no discrete code defect for an automated repair worker.

Maintainer decision needed

  • Question: Should OpenClaw intentionally stop applying HEARTBEAT.md files over 16 MiB while allowing the heartbeat run and delivery to continue with only a gateway warning?
  • Rationale: This is a sensible safety bound, but it changes previously accepted user input and can make automation instructions disappear after upgrade without failing the run; the permanent threshold and failure experience require maintainer ownership.
  • Likely owner: @gumadeiras — They are the strongest available routing signal for the heartbeat runner and its missing-file compatibility behavior.
  • Options:
    • Accept bounded fail-open behavior (recommended): Keep the 16 MiB cap and warning, accepting that oversized instructions are ignored so a malicious or accidental file cannot drive unbounded memory use.
    • Fail the heartbeat visibly: Reject the run with a surfaced operator error when the file is oversized, trading availability for stronger assurance that instructions never disappear behind a successful status.
    • Preserve oversized compatibility: Retain large-file support or add an explicit limit setting, preserving unusual existing setups at the cost of more configuration or continued resource exposure.

Security
Cleared: The diff reduces resource-exhaustion exposure, preserves prior symlink semantics, and introduces no dependency, permission, secret, or code-execution change.

Review details

Best possible solution:

Use the shared bounded regular-file path without adding configuration, preserve normal and symlinked files, emit an unmistakable operator diagnostic for rejected files, and land only after maintainers explicitly accept the 16 MiB fail-open upgrade behavior.

Do we have a high-confidence way to reproduce the issue?

Yes from source: the prior path uses an unbounded whole-file read, and a file over the proposed threshold reaches that path; the supplied final-head driver verifies the corrected behavior, although it does not measure a current-main out-of-memory event.

Is this the best way to solve the issue?

Yes technically: resolving symlinks before the shared bounded regular-file helper is a narrow, maintainable fix that preserves ordinary behavior; the remaining question is whether the selected limit and successful-run semantics are the product's preferred upgrade contract.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 957cc81175a3.

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. Final-head live output demonstrates both changed runtime paths: a symlinked file reaches the real prompt, while oversized content is excluded, warns, and does not prevent delivery.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): Final-head live output demonstrates both changed runtime paths: a symlinked file reaches the real prompt, while oversized content is excluded, warns, and does not prevent delivery.
  • remove rating: 🦐 gold shrimp: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.
  • remove status: 📣 needs proof: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P2: The patch addresses bounded memory use in a limited heartbeat path without evidence of an active outage or emergency.
  • merge-risk: 🚨 compatibility: Merging changes previously accepted oversized heartbeat files into skipped instructions while the surrounding run still succeeds.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): Final-head live output demonstrates both changed runtime paths: a symlinked file reaches the real prompt, while oversized content is excluded, warns, and does not prevent delivery.
  • proof: sufficient: Contributor real behavior proof is sufficient. Final-head live output demonstrates both changed runtime paths: a symlinked file reaches the real prompt, while oversized content is excluded, warns, and does not prevent delivery.
Evidence reviewed

PR surface:

Source +16, Tests +112. Total +128 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 17 1 +16
Tests 1 112 0 +112
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 129 1 +128

What I checked:

  • Changed runtime path: resolveHeartbeatPreflight resolves HEARTBEAT.md symlinks, reads the resolved regular file through the shared bounded helper, and continues the heartbeat without file content when the 16 MiB limit is exceeded. (src/infra/heartbeat-runner.ts:1082, a6074aaceeaf)
  • Compatibility behavior: The new catch branch warns only for the helper's oversized-file error and otherwise retains the established proceed-without-file behavior, so a previously accepted file over 16 MiB no longer contributes instructions while the run still succeeds. (src/infra/heartbeat-runner.ts:1120, a6074aaceeaf)
  • Regression coverage: The added tests exercise a symlinked regular HEARTBEAT.md and an oversized file, including prompt-content exclusion, continued delivery, and the operator warning. (src/infra/heartbeat-runner.oversized-heartbeat-file.test.ts:20, a6074aaceeaf)
  • Final-head behavior proof: The PR discussion includes final-head live output showing the symlink marker reaches the prompt, the oversized marker does not, the warning is emitted, and both heartbeat runs still deliver. (src/infra/heartbeat-runner.ts:1082, a6074aaceeaf)
  • Re-review continuity: Earlier findings to preserve symlinked heartbeat files and prove oversized content is absent from model input are resolved on the final head; no prior blocking finding remains. (src/infra/heartbeat-runner.oversized-heartbeat-file.test.ts:20, a6074aaceeaf)
  • Current-main verification gap: The checkout's read-only shell failed before executing repository inspection commands, so an independent current-main comparison and local git-history pass could not be completed; this prevents an implemented-on-main close and lowers confidence. (957cc81175a3)

Likely related people:

  • @gumadeiras: The live PR timeline routes this heartbeat change to this person, and nearby heartbeat history associates them with review or merge work around missing HEARTBEAT.md behavior that this catch path preserves. (role: reviewer and likely follow-up owner; confidence: medium; commits: cf4ffff3e1; files: src/infra/heartbeat-runner.ts)
  • @zeroaltitude: Recent shipped heartbeat work credits this person for substantial changes to heartbeat prompt loading and runner behavior, making them relevant to the file-read and prompt-injection boundary. (role: recent area contributor; confidence: medium; files: src/infra/heartbeat-runner.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (30 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-13T05:41:53.359Z sha 89638b5 :: needs real behavior proof before merge. :: [P1] Preserve symlinked heartbeat files | [P2] Assert oversized content is absent from reply input
  • reviewed 2026-07-14T13:42:55.638Z sha 1fc6a7d :: needs real behavior proof before merge. :: [P1] Preserve symlinked heartbeat files | [P2] Assert oversized content is absent from reply input
  • reviewed 2026-07-14T14:10:53.894Z sha 1fc6a7d :: needs real behavior proof before merge. :: [P1] Preserve symlinked heartbeat files | [P2] Assert oversized content is absent from reply input
  • reviewed 2026-07-14T14:34:05.316Z sha 1fc6a7d :: needs real behavior proof before merge. :: [P1] Preserve symlinked heartbeat files | [P2] Assert oversized content is absent from reply input
  • reviewed 2026-07-14T15:01:25.030Z sha 1fc6a7d :: needs real behavior proof before merge. :: [P1] Preserve symlinked heartbeat files | [P2] Assert oversized content is absent from reply input
  • reviewed 2026-07-14T15:28:23.835Z sha 1fc6a7d :: needs real behavior proof before merge. :: [P1] Preserve symlinked heartbeat files | [P2] Assert oversized content is absent from reply input
  • reviewed 2026-07-15T04:20:57.146Z sha 4a55366 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-15T05:32:30.214Z sha 531d467 :: needs real behavior proof before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jul 7, 2026
@cxbAsDev

cxbAsDev commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review — added real behavior proof for the bounded HEARTBEAT.md read.

Focused regression test run on this branch:

$ node scripts/run-vitest.mjs src/infra/heartbeat-runner.oversized-heartbeat-file.test.ts --run
[test] starting test/vitest/vitest.infra.config.ts
 RUN  v4.1.9
 ✓ |infra| src/infra/heartbeat-runner.oversized-heartbeat-file.test.ts (1 test) 294ms
     ✓ treats an oversized HEARTBEAT.md like a missing file and continues the run
 Test Files  1 passed (1)
      Tests  1 passed (1)
[test] passed 1 Vitest shard in 16.19s

The test writes a 16 MiB + 1 byte HEARTBEAT.md, calls runHeartbeatOnce, and asserts the run status is ran with the heartbeat send still completing, confirming the oversized file is treated as missing and the heartbeat continues safely.

@clawsweeper

clawsweeper Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@cxbAsDev
cxbAsDev force-pushed the fix/bound-heartbeat-file-read branch from 0cc4603 to f3c9007 Compare July 7, 2026 16:32
@cxbAsDev

cxbAsDev commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review — added a real runtime proof for the bounded HEARTBEAT.md read.

I ran a standalone script that uses the actual runHeartbeatOnce function with a temporary workspace. The script writes a 16 MiB + 1 byte HEARTBEAT.md, seeds a real session store, and calls runHeartbeatOnce with a Slack delivery stub. A clean HOME was used so no private config leaks into the output.

$ ls -l /tmp/openclaw-hb-*/HEARTBEAT.md
-rw-r--r-- 1 user user 16777217 ... /tmp/openclaw-hb-oversized-proof-XXXXXX/HEARTBEAT.md

$ HOME=/tmp/heartbeat-proof-home node_modules/.bin/tsx heartbeat-proof.mts
{
  "status": "ran",
  "durationMs": 1783443060846
}
EXIT:0

status: "ran" confirms the oversized HEARTBEAT.md is treated as missing and the heartbeat run continues instead of buffering the file into memory.

@clawsweeper

clawsweeper Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 7, 2026
@cxbAsDev
cxbAsDev force-pushed the fix/bound-heartbeat-file-read branch from f3c9007 to 3be167b Compare July 11, 2026 14:31
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 11, 2026
@cxbAsDev
cxbAsDev force-pushed the fix/bound-heartbeat-file-read branch 3 times, most recently from 1a520e4 to e1eca00 Compare July 11, 2026 19:39
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jul 11, 2026
@cxbAsDev
cxbAsDev force-pushed the fix/bound-heartbeat-file-read branch from e1eca00 to d92effd Compare July 11, 2026 22:28
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jul 12, 2026
@cxbAsDev
cxbAsDev force-pushed the fix/bound-heartbeat-file-read branch 4 times, most recently from 6f6ecaa to ca98bb2 Compare July 12, 2026 22:38
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jul 12, 2026
@cxbAsDev
cxbAsDev force-pushed the fix/bound-heartbeat-file-read branch 4 times, most recently from 2fc6cb5 to e0efd5e Compare July 15, 2026 02:16
@cxbAsDev

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review — branch rebased onto latest upstream/main and now follows symlinked HEARTBEAT.md files before applying the bounded read.

CI=true pnpm test src/infra/heartbeat-runner.oversized-heartbeat-file.test.ts

Result: 2/2 tests passed:

  • follows a symlinked HEARTBEAT.md to a regular file and completes the run
  • treats an oversized HEARTBEAT.md as missing and continues the run

Ready for review/land.

@clawsweeper

clawsweeper Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@cxbAsDev

Copy link
Copy Markdown
Contributor Author

Rebased onto latest upstream/main (851f76cb0d0); new head: a6074aaceeafc379434e5207500a3e46f52c5f6f. Final-head runtime proof for both requested scenarios below.

Oversized-diagnostic question: resolved with a code change. On the previous head, an oversized HEARTBEAT.md was silently skipped: readRegularFile throws File exceeds <cap> bytes: <path>, and the preflight catch swallowed it like any other non-ENOENT read error, so the operator saw nothing. Because oversized files loaded in full before this PR, silently dropping them would leave operators with no signal about why their heartbeat instructions stopped applying. The module already owns a subsystem logger (createSubsystemLogger("gateway/heartbeat")) and uses log.warn throughout, so I added an operator-visible warning scoped to the size-cap error only (a6074aaceea), consistent with neighboring behavior — no redesign:

[heartbeat] skipping oversized HEARTBEAT.md: File exceeds 16777216 bytes: <workspace>/HEARTBEAT.md

ENOENT (missing file / dangling symlink) still keeps the run active silently by design, and other read errors keep the established proceed-without-the-file behavior.

Runtime proof on the final head. Standalone driver invoking the real exported runHeartbeatOnce path (resolveHeartbeatPreflightfs.realpathreadRegularFile with the 16 MiB cap) against /tmp fixtures with an isolated HOME; model reply and Slack delivery stubbed via HeartbeatDeps, the same seam the colocated regression test uses. Fixture paths are throwaway /tmp dirs; nothing else to redact.

(a) HEARTBEAT.md as a symlink to a valid regular file → loads successfully (prompt contains the file's marker; run delivers):

--- case: symlink ---
HEARTBEAT.md lstat: isSymbolicLink=true size=58 (cap=16777216)
runHeartbeatOnce status: ran
captured prompt contains PROOF-MARKER: true
captured prompt bytes: 626
slack deliveries: 1

(b) HEARTBEAT.md oversized (16,777,246 bytes > 16,777,216 cap) → safely rejected: operator-visible warning fires, file content never enters the prompt (559 prompt bytes, marker absent), run still continues and delivers:

[heartbeat] skipping oversized HEARTBEAT.md: File exceeds 16777216 bytes: /tmp/openclaw-hb-proof/oversized/workspace/HEARTBEAT.md
--- case: oversized ---
HEARTBEAT.md lstat: isSymbolicLink=false size=16777246 (cap=16777216)
runHeartbeatOnce status: ran
captured prompt contains PROOF-MARKER: false
captured prompt bytes: 559
slack deliveries: 1

Focused tests on the final head:

$ node scripts/run-vitest.mjs src/infra/heartbeat-runner.oversized-heartbeat-file.test.ts --run
 ✓ |infra| src/infra/heartbeat-runner.oversized-heartbeat-file.test.ts (2 tests) 942ms
     ✓ follows a symlinked HEARTBEAT.md to a regular file  833ms
 Test Files  1 passed (1)
      Tests  2 passed (2)
[test] passed 1 Vitest shard in 14.88s

The oversized test now also asserts the warning reaches the console. PR body Evidence section refreshed with this proof.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@steipete

Copy link
Copy Markdown
Contributor

Merged via squash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants