Skip to content

fix(runtime): repair sessions and allow staged media through symlinked dirs#100026

Closed
steipete wants to merge 3 commits into
mainfrom
fix/macos-local-infra-tests
Closed

fix(runtime): repair sessions and allow staged media through symlinked dirs#100026
steipete wants to merge 3 commits into
mainfrom
fix/macos-local-infra-tests

Conversation

@steipete

@steipete steipete commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Two runtime fail-closed bugs when OpenClaw state or media roots are reached through symlinked directories (macOS /var -> /private/var tmp paths, or any user-level symlinked state/media dir):

  1. sessions cleanup silently skipped both stale-generated-metadata repair and missing-transcript pruning: the resolver realpaths the sessions dir, a stored sessionFile addressed through the symlink failed containment, and the canonical-transcript fallback masked the stale row forever.
  2. Outbound media that does not exist on disk yet (host-read staged media, bytes served via callbacks) cannot be realpathed, so its raw path failed the allowed-roots containment check and sends failed closed with "Local media path is not under an allowed directory".

Related to #100025 (the test-gate side of that issue was fixed by #100069; these are the two production bugs uncovered by the same investigation).

Why This Change Was Made

  • src/config/sessions/cleanup-service.ts: cleanup now resolves a stored absolute sessionFile directly when its realpathed parent equals the realpathed sessions dir, instead of letting the resolver fall back to the canonical transcript. Agents-shaped fallbacks and every existing path pin are untouched.
  • src/media/local-media-access.ts: missing candidates realpath their parent dir and rejoin the basename before the containment check. The invariant (path must be inside a resolved allowed root) is unchanged; only the previously fail-closed symlink form is corrected.

Both come with cross-platform regression tests that build an explicit fs.symlink dir, so they exercise the fixed branches on Linux CI too — not only on macOS.

User Impact

Sessions cleanup repairs/prunes correctly for stores on symlinked paths; outbound media staged via host-read callbacks under symlinked allowed roots now sends instead of erroring. No behavior change for non-symlinked setups.

Evidence

  • New regression tests fail on main without the fixes and pass with them (verified both directions):
    • store.pruning.integration.test.ts "repairs stale generated metadata when the store is reached through a symlinked dir" — repaired 0 -> 1
    • local-media-access.test.ts "allows missing files under a root reached through a symlinked dir" — path-not-allowed -> allowed
  • Full runtime-config shard 165 files / 2116+ tests green; media access suites green; pnpm tsgo clean.
  • Root-cause probes and the fail-closed error strings are documented in the PR history and Infra tests fail on macOS main: quoted host python breaks Windows-render regex; late-SQLite guard test misses realpathed state dir #100025.

@openclaw-barnacle openclaw-barnacle Bot added size: XS maintainer Maintainer-authored PR labels Jul 4, 2026
@clawsweeper

clawsweeper Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge. Reviewed July 4, 2026, 4:23 PM ET / 20:23 UTC.

Summary
The branch adjusts macOS-sensitive infra, QQBot, CLI, and process-helper tests while adding runtime path-resolution changes for symlinked session cleanup and missing local media paths.

PR surface: Source +62, Tests +23. Total +85 across 9 files.

Reproducibility: yes. source-reproducible. The linked issue and PR body give the exact macOS Vitest command for the original failures, and the remaining cleanup defects follow from the PR helper overriding the existing realpath containment path.

Review metrics: 1 noteworthy metric.

  • Runtime Path Resolution Changes: 2 added runtime resolution branches. Although the title is test-infra focused, the diff changes session cleanup and local media allowlist runtime behavior before merge.

Stored data model
Persistent data-model change detected: serialized state: src/config/sessions/cleanup-service.ts, serialized state: src/config/sessions/store.pruning.integration.test.ts, serialized state: src/test-utils/process-tree.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #100025
Summary: The linked issue is the canonical macOS local test-gate report; this PR and the broader fixture-layer PR are competing open candidate fixes rather than resolved duplicates.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🦞 diamond lobster
Patch quality: 🧂 unranked krab
Result: blocked by patch quality or review findings.

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

Rank-up moves:

  • [P2] Fix resolveStoredFileWithinDir containment and add focused pruning regressions for escaping symlinks and dot-segment sessionFile values.
  • Resolve the live merge conflict or switch to a repaired replacement branch if maintainers choose the broader fixture-layer approach.

Risk before merge

  • [P1] Merging current head can let sessions cleanup keep or read a stored sessionFile through an existing symlink inside the sessions directory even when the symlink target is outside the agent sessions directory.
  • [P1] A corrupted absolute sessionFile ending in . or .. can normalize to a directory and be treated as a valid transcript, leaving stale session metadata unpruned.
  • [P1] Live GitHub marks this PR conflicting, and the broader fixture-layer PR that claims to supersede it is also open and not yet a safe replacement.

Maintainer options:

  1. Fix Cleanup Containment Before Merge (recommended)
    Realpath existing stored sessionFile candidates, reject dot-segment basenames, and reserve parent-realpath reconstruction for genuinely missing files under the real sessions directory.
  2. Prefer The Fixture-Layer Replacement
    If maintainers want the macOS test-gate fix without production session/media changes, pause this branch and evaluate a repaired version of test: make the local pnpm test gate green on macOS hosts #100069 instead.
  3. Accept Corrupt-State Trust Explicitly
    Maintainers could intentionally accept that cleanup trusts parent-contained corrupted sessionFile values, but that would weaken the resolver containment behavior used by sibling session readers.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
In src/config/sessions/cleanup-service.ts, update resolveStoredFileWithinDir to reject . and .. basenames, realpath existing candidate files and accept them only when the resolved target remains inside the real sessions dir, and use parent-realpath reconstruction only for genuinely missing files. Add focused pruning integration tests for an escaping symlink sessionFile and a dot-segment sessionFile.

Next step before merge

  • [P2] A narrow mechanical repair can address both cleanup findings, though the worker may need a replacement branch because the live PR is conflicting and maintainerCanModify is false.

Security
Needs attention: Needs attention: the cleanup change can weaken stored transcript containment for symlinked sessionFile values.

Review findings

  • [P2] Preserve symlink target containment — src/config/sessions/cleanup-service.ts:343
  • [P2] Reject dot-segment stored session files — src/config/sessions/cleanup-service.ts:343
Review details

Best possible solution:

Preserve the macOS test-gate fix only after restoring session cleanup containment for existing symlinks and dot segments, or move to a repaired fixture-layer replacement if maintainers want no production runtime changes here.

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

Yes, source-reproducible. The linked issue and PR body give the exact macOS Vitest command for the original failures, and the remaining cleanup defects follow from the PR helper overriding the existing realpath containment path.

Is this the best way to solve the issue?

No. The macOS test fixes are useful, but the runtime cleanup helper is not the best mergeable shape until it preserves existing-file symlink containment and rejects dot-segment stored paths.

Full review comments:

  • [P2] Preserve symlink target containment — src/config/sessions/cleanup-service.ts:343
    This still accepts a stored sessionFile when only its parent realpaths to sessions/. If the file itself is a symlink to an outside transcript, cleanup bypasses resolveSessionFilePath's target realpath check and can keep or read data outside the agent sessions directory; realpath existing candidates and only use parent-realpath recovery for missing files.
    Confidence: 0.9
  • [P2] Reject dot-segment stored session files — src/config/sessions/cleanup-service.ts:343
    Late discovery: this helper was already present in an earlier reviewed head. A corrupted absolute sessionFile ending in . or .. is joined back to the sessions directory or its parent, and transcriptExistsWithMessages treats an existing directory as valid, so cleanup keeps a stale row instead of falling back or pruning; reject dot basenames before returning.
    Confidence: 0.86
    Late finding: first raised on code an earlier review cycle already covered.

Overall correctness: patch is incorrect
Overall confidence: 0.9

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 7a0188cbd20d.

Label changes

Label justifications:

  • P2: The PR targets a reproducible maintainer-local macOS test gate failure and has focused session cleanup blockers with limited blast radius.
  • merge-risk: 🚨 session-state: The diff changes how cleanup resolves persisted sessionFile metadata before deciding whether to keep, repair, or prune session entries.
  • merge-risk: 🚨 security-boundary: The new cleanup branch can trust a symlink path based on its parent directory without proving the symlink target remains inside the sessions directory.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦞 diamond lobster and patch quality is 🧂 unranked krab.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (terminal): The PR body includes after-fix macOS terminal output for the focused Vitest command, and live labels mark proof sufficient.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix macOS terminal output for the focused Vitest command, and live labels mark proof sufficient.
Evidence reviewed

PR surface:

Source +62, Tests +23. Total +85 across 9 files.

View PR surface stats
Area Files Added Removed Net
Source 3 65 3 +62
Tests 6 30 7 +23
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 9 95 10 +85

Security concerns:

  • [medium] Stored sessionFile symlink can escape containment — src/config/sessions/cleanup-service.ts:343
    Because existing symlink targets are not realpathed before the PR branch overrides transcriptPath, cleanup can read or keep a transcript outside the agent sessions directory when a symlink exists inside it.
    Confidence: 0.88

Acceptance criteria:

  • [P1] node scripts/run-vitest.mjs run --config test/vitest/vitest.infra.config.ts src/config/sessions/store.pruning.integration.test.ts src/config/sessions/sessions.test.ts.
  • [P1] node scripts/run-vitest.mjs run --config test/vitest/vitest.infra.config.ts src/infra/backup-create.test.ts src/infra/exec-approvals-analysis.test.ts extensions/qqbot/src/engine/gateway/outbound-dispatch.test.ts extensions/qqbot/src/engine/messaging/outbound-media-send.test.ts src/cli/logs-cli.test.ts.

What I checked:

  • Root and scoped policy read: Read root AGENTS.md and extensions/AGENTS.md; the deep-review, macOS tmpdir realpath, session-state, and plugin-boundary guidance affected this review. (AGENTS.md:1, 7a0188cbd20d)
  • Live PR state: Live GitHub data shows this PR is open, conflicting, carries the protected maintainer label, closes the canonical macOS test-gate issue, and has proof marked sufficient. (a77ef11dc3bb)
  • Current resolver containment contract: Current main realpaths existing absolute sessionFile candidates before comparing them to the real sessions directory, so existing symlinks escaping the sessions directory fall back instead of being trusted. (src/config/sessions/paths.ts:194, 7a0188cbd20d)
  • PR head helper bypasses that contract: At PR head, resolveStoredFileWithinDir accepts a candidate when only its parent realpaths to the sessions directory, then returns path.join(parentReal, basename) without realpathing existing file targets or rejecting dot basenames. (src/config/sessions/cleanup-service.ts:343, a77ef11dc3bb)
  • Directory paths are treated as live transcripts: transcriptExistsWithMessages returns true for existing non-file paths because transcriptHasNoMessageRecords returns false for non-files, so a normalized dot-segment directory can keep a stale row. (src/config/sessions/cleanup-service.ts:149, a77ef11dc3bb)
  • Prior cleanup blocker remains unchanged: The cleanup-service diff from the previously reviewed head to current head is empty, so the prior symlink-containment finding is still present. (src/config/sessions/cleanup-service.ts:343, a77ef11dc3bb)

Likely related people:

  • Vincent Koc: git log -S shows Vincent Koc carried the session path and cleanup surfaces in the release-history commits that define current resolver behavior. (role: session path hardening contributor; confidence: medium; commits: e085fa1a3ffd; files: src/config/sessions/paths.ts, src/config/sessions/cleanup-service.ts)
  • steipete: Peter Steinberger appears in prior session path hardening history and authored this PR's current head, including the affected session cleanup helper. (role: recent adjacent contributor and candidate-fix author; confidence: high; commits: 4199f9889f0c, a77ef11dc3bb; files: src/config/sessions/paths.ts, src/config/sessions/cleanup-service.ts, src/infra/exec-approvals-analysis.test.ts)
  • Gio Della-Libera: git show identifies Gio Della-Libera as committer for the current-main snapshot commit that carries the touched session, infra, media, and test helper files in this checkout. (role: recent current-main committer; confidence: low; commits: c79c38035873; files: src/config/sessions/cleanup-service.ts, src/config/sessions/paths.ts, src/media/local-media-access.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 (5 earlier review cycles)
  • reviewed 2026-07-04T17:08:19.112Z sha ecf2e7d :: needs maintainer review before merge. :: none
  • reviewed 2026-07-04T17:13:37.874Z sha ecf2e7d :: needs maintainer review before merge. :: none
  • reviewed 2026-07-04T17:53:00.428Z sha 2a1ae2c :: needs maintainer review before merge. :: none
  • reviewed 2026-07-04T17:59:16.136Z sha 2a1ae2c :: needs maintainer review before merge. :: none
  • reviewed 2026-07-04T19:15:19.989Z sha 976d13d :: needs changes before merge. :: [P2] Realpath existing stored files before accepting them

@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. P3 Low-priority cleanup, docs, polish, ergonomics, or speculative work. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. and removed P3 Low-priority cleanup, docs, polish, ergonomics, or speculative work. labels Jul 4, 2026
@steipete
steipete force-pushed the fix/macos-local-infra-tests branch from 2a1ae2c to 976d13d Compare July 4, 2026 19:08

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 976d13da25

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +340 to +343
if (parentReal !== realSessionsDir) {
return undefined;
}
return path.join(parentReal, path.basename(trimmed));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve containment when stored files are symlinks

When sessionFile names a symlink in the sessions directory, this parent-only realpath check accepts it and returns the symlink path without resolving the file target. That bypasses the containment behavior in resolveSessionFilePath, so sessions cleanup --fix-missing can read/keep an entry based on a transcript outside the agent sessions directory instead of falling back to the canonical transcript or pruning the stale row. This only needs a corrupt or user-created symlinked sessionFile; realpath the candidate when it exists and only use the parent-realpath path for genuinely missing files.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. 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 4, 2026
@openclaw-barnacle openclaw-barnacle Bot added cli CLI command changes channel: qqbot labels Jul 4, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a77ef11dc3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (parentReal !== realSessionsDir) {
return undefined;
}
return path.join(parentReal, path.basename(trimmed));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject dot-segment stored session files

When a corrupted absolute sessionFile is exactly under the sessions dir but names . or .. (for example <sessions>/..), this join normalizes the basename and returns the sessions directory or its parent. transcriptExistsWithMessages() then treats an existing directory as a valid transcript, so sessions cleanup --fix-missing keeps the stale row instead of falling back to the canonical transcript path and pruning it as before. Reject ./.. basenames before returning this path.

Useful? React with 👍 / 👎.

@steipete

steipete commented Jul 4, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #100069, landed as bbb7442.

Both failures this PR targets are fixed there at the fixture layer instead of per-test patches: the shared temp-root helpers (src/test-utils/openclaw-test-state.ts, src/test-helpers/temp-dir.ts, src/test-utils/fixture-suite.ts) now canonicalize their mkdtemp roots, so the backup-create late-SQLite readdir spy matches the realpathed state dir, and the Windows-render test resolves python3 from a fixture PATH with an exact-equality assertion (which also fixes Windows hosts, where the loosened regex here still breaks on python3.exe).

The paths.ts realpath-parent fallback isn't needed once fixture roots are canonical — the store.pruning.integration repair tests pass on macOS without it (full 89-shard local suite green on Darwin 25.5 at the landed commit). If a real deployment surfaces symlinked session dirs with missing transcript files, that's the observed case that would justify revisiting it.

Verification on macOS: the issue's repro (node scripts/run-vitest.mjs run --config test/vitest/vitest.infra.config.ts src/infra/exec-approvals-analysis.test.ts src/infra/backup-create.test.ts) is 59/59, and the full pnpm test gate is 89/89 shards green.

@steipete steipete closed this Jul 4, 2026
@steipete steipete changed the title test(infra): make Windows-render and late-SQLite guard tests pass on macOS hosts fix(runtime): repair sessions and allow staged media through symlinked dirs Jul 5, 2026
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

Rescoped: the original test-gate stabilization here was superseded by #100069 (nice fixture-root canonicalization — better boundary than my per-assertion edits) and #100053. What remains are the two production fail-closed bugs on symlinked dirs that the same investigation uncovered, now with explicit-symlink regression tests that run meaningfully on Linux CI as well. Verified both directions: tests fail on main without the fixes, pass with them.

steipete added a commit that referenced this pull request Jul 5, 2026
… gate

Concurrent scripts/pr gate runs across .worktrees queued on the shared
heavy-check lock mid-test: the queued run's children hit the 10-minute
lock timeout while its unlocked build stage piled CPU load onto the
holder's vitest shards, which then stalled past the 120s no-output
watchdog and were SIGTERMed with zero real test failures (observed
landing PRs #99935/#100026 on a loaded maintainer Mac).

- scripts/pr-gates-lock.mjs holds the shared heavy-check lock for the
  whole local gate block; gate stages inherit the existing *_LOCK_HELD
  child contract, so concurrent gate runs now queue as whole units
  before their first command.
- OPENCLAW_PR_GATES_REMOTE=testbox runs the full-suite pnpm test gate on
  a Blacksmith Testbox via scripts/crabbox-wrapper.mjs (same delegation
  as check:changed). The tbx_ lease id and Actions run URL from the
  crabbox --timing-json report are recorded in .local/gates.env
  (REMOTE_GATES_*) and .local/prep.md. Local remains the default;
  pnpm build/check stay local.

Formatting verified with the primary checkout's oxfmt (hook bypassed:
linked worktree has no hydrated node_modules).
steipete added a commit that referenced this pull request Jul 5, 2026
… gate

Concurrent scripts/pr gate runs across .worktrees queued on the shared
heavy-check lock mid-test: the queued run's children hit the 10-minute
lock timeout while its unlocked build stage piled CPU load onto the
holder's vitest shards, which then stalled past the 120s no-output
watchdog and were SIGTERMed with zero real test failures (observed
landing PRs #99935/#100026 on a loaded maintainer Mac).

- scripts/pr-gates-lock.mjs holds the shared heavy-check lock for the
  whole local gate block; gate stages inherit the existing *_LOCK_HELD
  child contract, so concurrent gate runs now queue as whole units
  before their first command.
- OPENCLAW_PR_GATES_REMOTE=testbox runs the full-suite pnpm test gate on
  a Blacksmith Testbox via scripts/crabbox-wrapper.mjs (same delegation
  as check:changed). The tbx_ lease id and Actions run URL from the
  crabbox --timing-json report are recorded in .local/gates.env
  (REMOTE_GATES_*) and .local/prep.md. Local remains the default;
  pnpm build/check stay local.

Formatting verified with the primary checkout's oxfmt (hook bypassed:
linked worktree has no hydrated node_modules).
steipete added a commit that referenced this pull request Jul 5, 2026
… gate

Concurrent scripts/pr gate runs across .worktrees queued on the shared
heavy-check lock mid-test: the queued run's children hit the 10-minute
lock timeout while its unlocked build stage piled CPU load onto the
holder's vitest shards, which then stalled past the 120s no-output
watchdog and were SIGTERMed with zero real test failures (observed
landing PRs #99935/#100026 on a loaded maintainer Mac).

- scripts/pr-gates-lock.mjs holds the shared heavy-check lock for the
  whole local gate block; gate stages inherit the existing *_LOCK_HELD
  child contract, so concurrent gate runs now queue as whole units
  before their first command.
- OPENCLAW_PR_GATES_REMOTE=testbox runs the full-suite pnpm test gate on
  a Blacksmith Testbox via scripts/crabbox-wrapper.mjs (same delegation
  as check:changed). The tbx_ lease id and Actions run URL from the
  crabbox --timing-json report are recorded in .local/gates.env
  (REMOTE_GATES_*) and .local/prep.md. Local remains the default;
  pnpm build/check stay local.

Formatting verified with the primary checkout's oxfmt (hook bypassed:
linked worktree has no hydrated node_modules).
steipete added a commit that referenced this pull request Jul 5, 2026
… gate

Concurrent scripts/pr gate runs across .worktrees queued on the shared
heavy-check lock mid-test: the queued run's children hit the 10-minute
lock timeout while its unlocked build stage piled CPU load onto the
holder's vitest shards, which then stalled past the 120s no-output
watchdog and were SIGTERMed with zero real test failures (observed
landing PRs #99935/#100026 on a loaded maintainer Mac).

- scripts/pr-gates-lock.mjs holds the shared heavy-check lock for the
  whole local gate block; gate stages inherit the existing *_LOCK_HELD
  child contract, so concurrent gate runs now queue as whole units
  before their first command.
- OPENCLAW_PR_GATES_REMOTE=testbox runs the full-suite pnpm test gate on
  a Blacksmith Testbox via scripts/crabbox-wrapper.mjs (same delegation
  as check:changed). The tbx_ lease id and Actions run URL from the
  crabbox --timing-json report are recorded in .local/gates.env
  (REMOTE_GATES_*) and .local/prep.md. Local remains the default;
  pnpm build/check stay local.

Formatting verified with the primary checkout's oxfmt (hook bypassed:
linked worktree has no hydrated node_modules).
steipete added a commit that referenced this pull request Jul 5, 2026
… gate (#100242)

* feat(scripts): serialize pr prepare gates and add remote testbox test gate

Concurrent scripts/pr gate runs across .worktrees queued on the shared
heavy-check lock mid-test: the queued run's children hit the 10-minute
lock timeout while its unlocked build stage piled CPU load onto the
holder's vitest shards, which then stalled past the 120s no-output
watchdog and were SIGTERMed with zero real test failures (observed
landing PRs #99935/#100026 on a loaded maintainer Mac).

- scripts/pr-gates-lock.mjs holds the shared heavy-check lock for the
  whole local gate block; gate stages inherit the existing *_LOCK_HELD
  child contract, so concurrent gate runs now queue as whole units
  before their first command.
- OPENCLAW_PR_GATES_REMOTE=testbox runs the full-suite pnpm test gate on
  a Blacksmith Testbox via scripts/crabbox-wrapper.mjs (same delegation
  as check:changed). The tbx_ lease id and Actions run URL from the
  crabbox --timing-json report are recorded in .local/gates.env
  (REMOTE_GATES_*) and .local/prep.md. Local remains the default;
  pnpm build/check stay local.

Formatting verified with the primary checkout's oxfmt (hook bypassed:
linked worktree has no hydrated node_modules).

* fix(scripts): refresh the gate stamp when lease-retry gates rerun for a rebased head

The lease-retry path reran build/check/test for the rebased prep head but
left .local/gates.env describing the pre-push head, so prep.md/prep.env
attributed stale evidence (including the new remote testbox lease id) to
the pushed commit. Extract write_gates_env_stamp as the single stamp
writer, rewrite the stamp from the retry path for all modes, and re-source
gates.env in prepare_push after the push settles.

Found by autoreview (codex/gpt-5.5); formatting verified with the primary
checkout's oxfmt (hook bypassed: linked worktree has no node_modules).

* fix(scripts): harden remote PR gate evidence

* fix(scripts): serialize complete gate setup

* fix(scripts): clear stale docs gate proof
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 6, 2026
… gate (openclaw#100242)

* feat(scripts): serialize pr prepare gates and add remote testbox test gate

Concurrent scripts/pr gate runs across .worktrees queued on the shared
heavy-check lock mid-test: the queued run's children hit the 10-minute
lock timeout while its unlocked build stage piled CPU load onto the
holder's vitest shards, which then stalled past the 120s no-output
watchdog and were SIGTERMed with zero real test failures (observed
landing PRs openclaw#99935/openclaw#100026 on a loaded maintainer Mac).

- scripts/pr-gates-lock.mjs holds the shared heavy-check lock for the
  whole local gate block; gate stages inherit the existing *_LOCK_HELD
  child contract, so concurrent gate runs now queue as whole units
  before their first command.
- OPENCLAW_PR_GATES_REMOTE=testbox runs the full-suite pnpm test gate on
  a Blacksmith Testbox via scripts/crabbox-wrapper.mjs (same delegation
  as check:changed). The tbx_ lease id and Actions run URL from the
  crabbox --timing-json report are recorded in .local/gates.env
  (REMOTE_GATES_*) and .local/prep.md. Local remains the default;
  pnpm build/check stay local.

Formatting verified with the primary checkout's oxfmt (hook bypassed:
linked worktree has no hydrated node_modules).

* fix(scripts): refresh the gate stamp when lease-retry gates rerun for a rebased head

The lease-retry path reran build/check/test for the rebased prep head but
left .local/gates.env describing the pre-push head, so prep.md/prep.env
attributed stale evidence (including the new remote testbox lease id) to
the pushed commit. Extract write_gates_env_stamp as the single stamp
writer, rewrite the stamp from the retry path for all modes, and re-source
gates.env in prepare_push after the push settles.

Found by autoreview (codex/gpt-5.5); formatting verified with the primary
checkout's oxfmt (hook bypassed: linked worktree has no node_modules).

* fix(scripts): harden remote PR gate evidence

* fix(scripts): serialize complete gate setup

* fix(scripts): clear stale docs gate proof
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: qqbot cli CLI command changes maintainer Maintainer-authored PR merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant