Skip to content

fix(trajectory): tolerate partial skill snapshot entries in support capture#71185

Closed
lukeboyett wants to merge 2 commits into
openclaw:mainfrom
lukeboyett:fix/skills-capture-null-safety
Closed

fix(trajectory): tolerate partial skill snapshot entries in support capture#71185
lukeboyett wants to merge 2 commits into
openclaw:mainfrom
lukeboyett:fix/skills-capture-null-safety

Conversation

@lukeboyett

@lukeboyett lukeboyett commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • buildSkillsCapture and redactPathForSupport crash on skill snapshot entries with undefined name/filePath/baseDir, which happens in practice whenever the symlink-escape guard rejects a skill and leaves a partial entry in resolvedSkills.
  • Defensive consumer fix only — security posture of the symlink-escape rejection is unchanged.
  • Repro was deterministic in my environment: every agent turn died in runEmbeddedAttemptbuildTrajectoryRunMetadatabuildSkillsCapture, failing the entire model-fallback chain because every candidate hits the same shared code.

Changes

  • src/logging/diagnostic-support-redaction.ts: redactPathForSupport now accepts string | null | undefined and returns "" for non-string input.
  • src/trajectory/metadata.ts: buildSkillsCapture filters skill entries without a string name. If every resolvedSkills entry is filtered out (i.e. every resolved entry is partial), falls back to skillsSnapshot.skills so support bundles don't lose the skill inventory entirely. Final toSorted comparator is null-safe.
  • src/trajectory/metadata.test.ts: regression tests for partial-snapshot tolerance, fallback when all resolved entries are partial, and direct redaction null-input.

Security posture unchanged

The symlink-escape rejection in src/agents/skills/workspace.ts still refuses to load escaped symlinks and emits the same [skills] Skipping escaped skill path outside its configured root warn log. This PR only prevents the downstream support-capture consumer from crashing on the partial entries the rejection path leaves behind.

Suggested follow-up (not in this PR)

The producer side — src/agents/skills/workspace.ts around the symlink-escape / bundled-symlink-escape reasons — is what leaves partial entries in resolvedSkills. A cleaner producer-side fix (skip the entry, or emit with available: false + placeholder name) would remove the class of problem. Happy to follow up if preferred.

Real behavior proof

  • Behavior or issue addressed: agent turns crashing with TypeError: Cannot read properties of undefined (reading 'startsWith') in runEmbeddedAttemptbuildTrajectoryRunMetadatabuildSkillsCapture whenever skillsSnapshot.resolvedSkills carries a partial entry left behind by the symlink-escape rejection in src/agents/skills/workspace.ts. Every model in the fallback chain hit the same shared code path, so the entire turn would fail with reason=unknown.
  • Real environment tested: production OpenClaw gateway daemon on macOS Sonoma (Darwin 23.6.0), Node 25.6.0, running an 11-account Matrix deployment with mixed text + media traffic. Same gateway was running the unpatched code, then the patched dist for several days continuously.
  • Exact steps or command run after this patch: built patched dist (pnpm build), reloaded the gateway LaunchDaemon (sudo launchctl bootout system/ai.openclaw.gateway && sudo launchctl bootstrap system /Library/LaunchDaemons/ai.openclaw.gateway.plist), and let live Matrix traffic exercise the symlink-escape rejection path (the himalaya skill is a symlink that resolves outside ~/.openclaw/skills, so it triggers the rejection on every skills-snapshot rebuild).
  • Evidence after fix:
    • Pre-patch crash signature in redacted runtime logs at ~/.openclaw/logs/gateway.log — log excerpt:
      2026-04-27T06:43:33.391-04:00 [ws] ⇄ res ✗ agent errorCode=UNAVAILABLE errorMessage=TypeError: Cannot read properties of undefined (reading 'startsWith') runId=1a473ced-1328-46c7-8e23-55813ef3b8f9
      2026-04-27T06:47:43.641-04:00 [ws] ⇄ res ✗ agent errorCode=UNAVAILABLE errorMessage=TypeError: Cannot read properties of undefined (reading 'startsWith') runId=429f610a-6f62-417c-804a-5c7d3aa33d96
      
    • Symlink-escape rejection still firing on the running patched daemon in redacted runtime logs at ~/.openclaw/logs/gateway.err.log — proves the security guard is unchanged and the producer-side path that emits the partial entry is exactly the one this PR catches; live output below:
      [skills] Skipping escaped skill path outside its configured root: source=openclaw-managed root=~/.openclaw/skills reason=symlink-escape requested=~/.openclaw/skills/himalaya resolved=~/moltbot/skills/himalaya
      [skills] Skipping escaped skill path outside its configured root: source=openclaw-workspace root=~/clawd/skills rootResolved=~/.openclaw/skills reason=symlink-escape requested=~/clawd/skills/himalaya resolved=~/moltbot/skills/himalaya
      
    • Post-patch agent turns completing normallygh run list against my fork's recent gateway-driven activity, plus a continuous tail of ~/.openclaw/logs/gateway.log, both confirm no new Cannot read properties of undefined (reading 'startsWith') lines since the patched dist was deployed; daemon process has been continuously up across many turns of real Matrix traffic.
  • Observed result after fix: agent turns that previously failed every time the symlink-escape rejection fired now complete normally. The rejection warn line still emits (security posture unchanged), buildSkillsCapture filters the partial entry instead of crashing, and redactPathForSupport returns "" for the undefined-path case rather than throwing on String.prototype.startsWith. Live openclaw gateway output in the same logs above shows continued ws traffic resolving normally.
  • What was not tested: I do not have a deterministic e2e fixture that re-creates the symlink-escape resolvedSkills shape outside my live deployment, so the regression coverage is the unit tests in src/trajectory/metadata.test.ts plus the live-gateway observation above. The producer-side cleanup (rejecting the partial entry at the workspace.ts source) was not attempted in this PR — it stays as a follow-up.

Test plan

  • pnpm test src/trajectory/metadata.test.ts passes (6/6, was 3/3)
  • pnpm build passes locally
  • pnpm check passes locally
  • codex review --base upstream/main run locally — one P2 finding (fallback on fully-filtered resolvedSkills) addressed in-branch; re-ran clean
  • Verified in-tree: with patched dist, agent turns that previously crashed every time now complete normally; no weakening of symlink-escape rejection path

Degree of testing

Lightly tested — unit tests cover the three failure modes, and the running gateway in my environment has been stable with the patched dist across hours of live traffic on an 11-account Matrix deployment. No integration or e2e coverage added.

🤖 Generated with Claude Code

@greptile-apps

greptile-apps Bot commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds defensive guards to prevent crashes in buildSkillsCapture and redactPathForSupport when a skill's resolvedSkills entry is partially populated (e.g., name/filePath/baseDir undefined) due to the symlink-escape rejection path in workspace.ts. The fix is correctly scoped to the consumer side; the security posture of the symlink-escape guard is unchanged.

The fallback logic, filtering, null-safe comparator, and widened redactPathForSupport signature are all correct. Three targeted regression tests cover the three failure modes.

Confidence Score: 5/5

Safe to merge — defensive fix with no behavior change to the security-sensitive symlink-escape rejection path.

All changes are narrowly scoped defensive guards on the support-capture consumer path. Filtering logic, fallback, and null-safety are all correct. Tests cover each failure mode. No P0 or P1 findings.

No files require special attention.

Reviews (1): Last reviewed commit: "fix(trajectory): tolerate partial skill ..." | Re-trigger Greptile

@lukeboyett

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

ℹ️ 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".

@clawsweeper

clawsweeper Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge.

Workflow note: Future ClawSweeper reviews update this same comment in place.

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.

Summary
The PR makes trajectory support metadata tolerate partial skill snapshot entries by widening path redaction null handling, filtering invalid resolved skills with fallback to the lightweight skill list, and adding regression tests.

Reproducibility: yes. Source inspection shows a malformed skillsSnapshot.resolvedSkills entry can throw in current main, and the PR body supplies redacted live before/after gateway logs for that path.

PR rating
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Summary: Strong live-log proof and a small, well-scoped defensive patch with regression tests make this ready for ordinary maintainer landing review once checks are handled.

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.

Real behavior proof
Sufficient (logs): The PR body provides sufficient log proof: redacted pre-patch crashes, patched live gateway operation, continued symlink-escape warnings, and observed recovered Matrix traffic after deploying the patch.

Risk before merge

  • Latest PR-head CI is not green; inspected failures appear outside this patch's touched files, so this is a landing/checks blocker rather than a code-review finding.

Maintainer options:

  1. Decide the mitigation before merge
    Land the focused consumer hardening once required checks are green or confirmed unrelated, and keep producer-side normalization of rejected skill entries as a separate cleanup if maintainers want a stricter contract.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge
No ClawSweeper repair lane is needed; the patch has no concrete code defect and the remaining action is maintainer landing plus normal CI handling.

Security
Cleared: The diff only broadens null handling in diagnostic support redaction and trajectory metadata plus tests, without changing dependency sources, secret handling, CI, publishing, or code-execution paths.

Review details

Best possible solution:

Land the focused consumer hardening once required checks are green or confirmed unrelated, and keep producer-side normalization of rejected skill entries as a separate cleanup if maintainers want a stricter contract.

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

Yes. Source inspection shows a malformed skillsSnapshot.resolvedSkills entry can throw in current main, and the PR body supplies redacted live before/after gateway logs for that path.

Is this the best way to solve the issue?

Yes. Defensive tolerance in the support-capture consumers is the narrowest immediate fix for preventing trajectory metadata from failing agent turns while preserving the symlink-escape rejection behavior.

Label justifications:

  • P1: The reported failure can make real agent turns fail through the shared embedded-attempt trajectory metadata path when malformed skill snapshot entries are present.
  • rating: 🦞 diamond lobster: Current PR rating is 🦞 diamond lobster because proof is 🦞 diamond lobster, patch quality is 🦞 diamond lobster, and Strong live-log proof and a small, well-scoped defensive patch with regression tests make this ready for ordinary maintainer landing review once checks are handled.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (logs): The PR body provides sufficient log proof: redacted pre-patch crashes, patched live gateway operation, continued symlink-escape warnings, and observed recovered Matrix traffic after deploying the patch.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body provides sufficient log proof: redacted pre-patch crashes, patched live gateway operation, continued symlink-escape warnings, and observed recovered Matrix traffic after deploying the patch.

What I checked:

  • current-main crash path: Current main maps every resolved skill through redactPathForSupport(skill.filePath, ...) and sorts with left.name.localeCompare(right.name), so a runtime entry with undefined filePath or name can throw during metadata capture. (src/trajectory/metadata.ts:180, 384451343191)
  • current-main redaction assumption: redactPathForSupport currently accepts string and immediately calls file.startsWith, matching the reported Cannot read properties of undefined (reading 'startsWith') failure if a malformed path reaches support redaction. (src/logging/diagnostic-support-redaction.ts:238, 384451343191)
  • agent-turn surface: runEmbeddedAttempt records trace.metadata by calling buildTrajectoryRunMetadata with params.skillsSnapshot, so the crash can affect live agent turns rather than only offline export. (src/agents/pi-embedded-runner/run/attempt.ts:2577, 384451343191)
  • symlink guard remains separate: Current main still rejects escaped skill paths with reason=symlink-escape/bundled-symlink-escape and returns null; the PR diff does not alter that producer-side security guard. (src/agents/skills/workspace.ts:250, 384451343191)
  • PR diff behavior: The PR widens redactPathForSupport, filters resolved skill entries without non-empty string names, falls back to skillsSnapshot.skills when all resolved entries are filtered, and adds focused tests for mixed partial entries, all-partial fallback, and nullish redaction input. (src/trajectory/metadata.ts:177, 9d8e173017da)
  • real behavior proof: The PR body supplies redacted pre-patch gateway crash logs, patched live gateway operation, continued symlink-escape warnings, and observed recovered Matrix traffic after deploying the patched dist. (9d8e173017da)

Likely related people:

  • scoootscooob: Introduced src/trajectory/metadata.ts and the trajectory bundle/runtime capture surface that consumes the skill snapshot metadata hardened by this PR. (role: trajectory metadata introducer; confidence: high; commits: a3d9c53db299; files: src/trajectory/metadata.ts, src/trajectory/metadata.test.ts, src/agents/pi-embedded-runner/run/attempt.ts)
  • gumadeiras: Introduced the diagnostic support export/redaction surface containing redactPathForSupport, whose null handling is widened here. (role: diagnostic redaction introducer; confidence: medium; commits: 28818f914074; files: src/logging/diagnostic-support-redaction.ts, src/logging/diagnostic-support-export.ts)
  • steipete: Recent commits changed trusted/managed skill symlink handling in src/agents/skills/workspace.ts, the producer-side area related to the partial entries discussed in the PR. (role: recent skills-area contributor; confidence: high; commits: 5618a8f8f659, 926bf66ee336, cca4f3c63cc1; files: src/agents/skills/workspace.ts)
  • joshavant: Recently touched src/trajectory/metadata.ts in adjacent agent-turn delivery work, making them a useful routing candidate for current trajectory metadata behavior. (role: recent trajectory metadata contributor; confidence: medium; commits: 422a1374e02b; files: src/trajectory/metadata.ts)

Codex review notes: model gpt-5.5, reasoning high; reviewed against 384451343191.

@lukeboyett
lukeboyett force-pushed the fix/skills-capture-null-safety branch 3 times, most recently from 3b33589 to 17c521a Compare April 27, 2026 17:48
@lukeboyett
lukeboyett force-pushed the fix/skills-capture-null-safety branch from 17c521a to 09b7957 Compare May 6, 2026 00:19
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label May 6, 2026
@lukeboyett

Copy link
Copy Markdown
Contributor Author

Status update — rebased onto current main

Rebased onto upstream/main@7af1a87830 (post-v2026.5.4).

  • New HEAD: 09b795706f
  • Branch: lukeboyett:fix/skills-capture-null-safety
  • 2 commits unchanged from prior review:
    1. c01f0b8d15 fix(trajectory): tolerate partial skill snapshot entries in support capture
    2. 09b795706f fix(trajectory): tighten test types for partial skill entries
  • pnpm test -- src/trajectory/metadata.test.ts: 6 passed
  • pnpm tsgo:core:test: clean
  • No conflicts during cherry-pick onto current main.

Forensic on adjacent upstream activity

Commit Effect on this PR
a4b97075ae fix: align support URL redaction Touches diagnostic-support-redaction.ts but only the URL-param regex; coexists with the redactPathForSupport signature widening here.
e7432ae01d fix: redact URL query credentials in diagnostics Same file, URL-redaction work, no overlap.
474bea162b fix: bound trajectory runtime flush (#77154) Touches runtime.ts, not metadata.ts.
a2b84e98e9 fix: clean up trajectory sidecars Sidecar lifecycle, orthogonal to support-capture metadata.

The crash this PR addresses (partial-entry leakage from the symlink-escape-rejection path through buildSkillsCapture / redactPathForSupport) hasn't been fixed elsewhere — producer-side src/agents/skills/workspace.ts still emits the partial shape, and no upstream commit has tightened that path or added a null-safe consumer guard.

Re-review

@codex please re-review the rebased commits. Main question: is the defensive consumer-side guard still the right shape given recent trajectory/support-redaction churn, or should the producer-side cleanup (drop partial entries at the symlink-escape rejection site) be the canonical fix?

@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

Codex Review: Didn't find any major issues. What shall we delve into next?

ℹ️ 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".

@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 6, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@lukeboyett

Copy link
Copy Markdown
Contributor Author

Addressed codex's P3 in 3ddda5ddf2 — added an Unreleased CHANGELOG entry covering the trajectory/support-capture failure-path widening, per OpenClaw policy. No code changes; the consumer-side guard, regression tests, and security posture are unchanged.

Pushing as synchronize should re-fire CI; @codex please re-run when convenient.

@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

To use Codex here, create an environment for this repo.

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@lukeboyett
lukeboyett force-pushed the fix/skills-capture-null-safety branch from 3ddda5d to a4a96ff Compare May 6, 2026 03:44
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@lukeboyett
lukeboyett force-pushed the fix/skills-capture-null-safety branch from a4a96ff to b169d2c Compare May 6, 2026 04:09
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@lukeboyett
lukeboyett force-pushed the fix/skills-capture-null-safety branch from b169d2c to 3a88a7a Compare May 6, 2026 04:20
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@lukeboyett
lukeboyett force-pushed the fix/skills-capture-null-safety branch from 3a88a7a to e515467 Compare May 6, 2026 04:39
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
lukeboyett added a commit to lukeboyett/openclaw that referenced this pull request May 6, 2026
Addresses codex P3 on openclaw#71185.

OpenClaw policy requires a CHANGELOG.md entry when a PR changes a
user-facing failure path; the trajectory/support-capture null-safety
fix in this PR qualifies (every agent turn was failing with
reason=unknown via the shared metadata builder).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@lukeboyett
lukeboyett force-pushed the fix/skills-capture-null-safety branch from e515467 to 6c19dc1 Compare May 6, 2026 11:13
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels May 20, 2026
@clawsweeper

clawsweeper Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

✨ Hatched: 🥚 common Brave Test Hopper

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.

Rarity: 🥚 common.
Trait: sparkles near resolved comments.
Image traits: location proof lagoon; accessory release bell; palette sunrise gold and clean white; mood calm; pose leaning over a miniature review desk; shell starlit enamel shell; lighting warm desk-lamp glow; background tiny shells and proof notes.
Share on X: post this hatch
Copy: My PR egg hatched a 🥚 common Brave Test Hopper in ClawSweeper.

What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

lukeboyett and others added 2 commits May 20, 2026 13:12
…apture

buildSkillsCapture and redactPathForSupport crash with
"Cannot read properties of undefined (reading 'startsWith' | 'localeCompare')"
when skillsSnapshot.resolvedSkills contains entries with undefined
name/filePath/baseDir. This happens in practice when a skill is rejected
by the symlink-escape guard in src/agents/skills/workspace.ts: the [skills]
warn log fires, but a partial entry still reaches the support-capture path.
Downstream, runEmbeddedAttempt builds the trajectory run metadata on every
turn, the undefined fields hit String-method calls, and the entire agent
turn fails with reason=unknown (burning through the model-fallback chain,
which all share this code path).

Defensive consumer fix:
- redactPathForSupport: widen file arg to string | null | undefined,
  return "" for non-string input
- buildSkillsCapture: filter entries without a string name; if every
  resolvedSkills entry is filtered out, fall back to skillsSnapshot.skills
  so support bundles don't lose the skill inventory entirely; null-safe
  localeCompare comparator

Security posture unchanged -- the symlink-escape rejection in
src/agents/skills/workspace.ts still refuses to load escaped symlinks.
This PR only prevents the downstream support-capture consumer from
crashing on the partial entries the rejection path leaves behind.

A producer-side cleanup (making symlink-escape rejects either skip the
entry or emit a placeholder name) is a reasonable follow-up but has
broader ripple; keeping this PR tightly scoped.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
CI check-test-types was failing on src/trajectory/metadata.test.ts because
tsgo:test is stricter than local pnpm check. Rejected sourceInfo: {} and
bare 'undefined' assignments against typed SourceInfo / string fields.

Fill sourceInfo with a real SourceInfo shape for the valid 'alpha' entry,
cast the intentionally-partial entries to ResolvedSkillEntry via an
'as unknown as' bridge so the intent (simulating a symlink-escape reject
leaking through) stays explicit without weakening the type on the valid
branch.

Tests: 6 passed (unchanged). tsgo:core:test clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@lukeboyett
lukeboyett force-pushed the fix/skills-capture-null-safety branch from 6c19dc1 to 9d8e173 Compare May 20, 2026 19:06
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 20, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. P1 High-priority user-facing bug, regression, or broken workflow. labels May 20, 2026
@Takhoffman

Copy link
Copy Markdown
Contributor

@clawsweeper automerge

@clawsweeper clawsweeper Bot added the clawsweeper:automerge Maintainer opted this PR into bounded ClawSweeper-reviewed automerge label May 21, 2026
@clawsweeper

clawsweeper Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

🦞🔧
ClawSweeper automerge is enabled.

Draft PRs stay fix-only until GitHub marks them ready for review. Pause with /clawsweeper stop.

Automerge progress:

  • 2026-05-21 03:51:26 UTC review queued 9d8e173017da (queued)

@clawsweeper

clawsweeper Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper 🐠 reef update

Thanks for the work here. ClawSweeper could not write to the source branch, so it opened a replacement PR rather than letting the fix drift. attribution still points back here.

Why replacement: ClawSweeper could not update the source PR branch directly; GitHub did not grant sufficient push rights to the bot for that branch.
Replacement PR: #84797
Why close: this run explicitly closes the superseded source PR after the credited replacement PR is open, so review continues in one place.
Closing this source PR because this run explicitly enabled source-PR closeout.
Contributor credit is carried into the replacement PR body and changelog plan.
Co-author credit kept:

fish notes: model gpt-5.5, reasoning high; reviewed against 99a204b.

@clawsweeper clawsweeper Bot closed this May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clawsweeper:automerge Maintainer opted this PR into bounded ClawSweeper-reviewed automerge P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦞 diamond lobster Very strong PR readiness with only minor 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