Repository navigation
perf(skills): detach cached metadata from source strings - #139478
Conversation
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: needs maintainer review before merge. Reviewed September 5, 2026, 6:53 PM ET / 22:53 UTC. ClawSweeper reviewWhat this changesCopies parsed skill metadata and display titles so cached metadata does not retain entire skill files in the measured Node workload. Merge readiness✅ Ready for maintainer review This remains a useful, focused performance fix: current main lacks both metadata copies, and the supplied Node measurements support the intended improvement. No actionable introduced defect was found. Priority: P2 Review scores
Verification
How this fits togetherOpenClaw loads skill files into metadata used by workspace caches, pinned library selections, and session resources. These metadata producers feed skill discovery and prompt preparation after local file contents are discarded. flowchart TD
A[Skill files] --> B[Parse frontmatter]
A --> C[Resolve display title]
B --> D[Copy metadata strings]
C --> D
D --> E[Workspace metadata cache]
D --> F[Library and session resources]
E --> G[Skill discovery and prompts]
F --> G
Before mergeNone. Agent review detailsSecurityNone. PR surfaceSource +5. Total +5 across 2 files. View PR surface stats
Review metrics
Technical reviewBest possible solution: Keep metadata ownership at the shared producers while preserving string values, cache identity, and existing refresh behavior. Do we have a high-confidence way to reproduce the issue? Yes for the reported Node workload: the body describes repeated real-loader runs and retained-object measurements, and source inspection confirms the ownership path. This read-only review did not independently reproduce the heap result on current main. Is this the best way to solve the issue? Yes. Copying the finalized string metadata at its shared producers covers workspace, library, and session consumers without changing cache limits, parsing policy, or persisted data. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against 7528edb1ba5c. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
|
|
Merged via squash.
|
* origin/main: (95 commits) perf(build): avoid unrelated gateway artifact scans (#127757) fix(update): deliver terminal progress after long updates (#139289) fix(ui): show session hover cards for local chat URLs (#139384) perf(ui): reuse unchanged transcript key snapshots (#139400) fix(ui): make subagent sessions view-only (#139381) fix: open agent state on SQLite builds without extensions (#139487) perf(skills): detach cached metadata from source strings (#139478) fix(ui): show primary user in multi-agent profile hero (#136736) perf(sessions): stop decoding the session row four times per SQLite entry patch (#136361) refactor(exec): share package-manager option scans (#139482) fix(ci): authorize frozen mobile release candidates (#139441) fix: avoid session deletion slowdown in large session stores (#139467) perf(gateway): reuse node invocation idle timers (#139354) fix(auth): preserve selected profiles across plugin scopes (#139413) fix(discord): retain voice input until transcription completes (#139484) fix(agents): name Gateway storage failures in run-failure copy (#139409) fix: keep subagent checks responsive in large session stores (#139450) fix(memory): index notes when optional embeddings cannot start (#139463) fix: refresh pending approvals when reopening chat (#139457) fix(tooling): preserve Git hook choices during install (#139461) ...
What Problem This Solves
Resolves retained skill source bodies in the measured Node workspace-cache workload. Short display titles and frontmatter values can remain sliced strings backed by the full SKILL.md, even after loading deliberately drops content from cached entries. Limiting cache entries alone does not remove that backing storage.
Why This Change Was Made
The shared metadata producers copy their finalized results:
src/skills/loading/frontmatter.tsapplies nativestructuredCloneto the normalized string record, andsrc/skills/loading/skill-contract.tscopies the display title through lossless UTF-16LE encoding/decoding. Parser validation/recovery, key order, fallback titles, and every string code unit remain unchanged; no universal string/key-identity guarantee is introduced.Workspace caching, pinned library selection, and session resource loading share these producers. A cache-only repair would miss siblings; copying headings alone would miss frontmatter. An initial JSON roundtrip passed values but failed the existing prefer-structured-clone lint rule; the final native clone has fresh proof without suppression. Production: +7/-2 lines (net +5); tests/support: +0/-0. Those lines establish metadata ownership without cloning complete entries/files or adding a cache, parser, or fallback.
User Impact
Cached local skill metadata retains fewer source-body strings in the measured Node cohorts while preserving titles, metadata, prompts, pins, refresh behavior, and cache-hit entry identity. Remote skills deliberately retain content and have no claimed memory reduction. Small metadata copies add transient work on cache misses.
Evidence
The real exported workspace loader loads 100 synthetic 240,000-byte files, advances the real watcher snapshot, and loads a second generation under existing limits. Files/results leave scope, files are removed, and three explicit GCs separated by event-loop turns precede heap inspection.
In each independently run large cohort—heading plus metadata, frontmatter without H1, and heading with tiny/reconstructed metadata—the baseline cache payload retains 200 marked source bodies totaling 48,003,200 string self-bytes; the final Node candidate retains zero. Full entries/prompts and cache-hit entry identity match. The 512-byte control preserves outputs; the large-body classifier intentionally does not measure its small strings.
After 65 normal empty-snapshot insertions, neither arm retains a marked body through cache payloads. One baseline body remains engine-global in two cohorts through regexp last-match state. Earlier graph analyses incorrectly labeled that cache ownership; final v3 follows payload edges while excluding prototypes, runtime shapes, functions, and contexts. It preserves all 200 direct retained-entry paths and zero after eviction, without changing the cache or snapshots.
Whole-process heap deltas are noisy as warmed imports release memory; external memory remains 4,983,782 bytes at retained endpoints and ArrayBuffers near 2.31 MB. The attributed result is 200 source bodies → zero in these Node 26.8.1 cohorts, not universal engine/key detachment, Bun heap behavior, zero allocation, latency, RSS, or leak freedom. Bun was not executed.
All 131,390 full value results match, covering every UTF-16 code unit, YAML variants, parser errors, and policy/manifest projections. A real library/session proof preserves six pin/cache/revision/refresh/resource-replacement boundaries with a 900,429-byte fixture; normalized metadata/prompt bytes match. This sibling proof measures behavior, not heap or latency.
All 84 tests across six files pass before/after. Final formatting, exact-file typed lint, and changed-plan classification pass. Independent P2 review recorded no actionable findings. Broad integration/build checks remain separate; required exact-head hosted CI/native landing gates remain mandatory.
Current-context composition at main
3dff8818ef42872cecc3899b41dffd95942fe70fpreserves the upstream puredecodeSkillXmlandcompactSkillsPromptForContexthelpers and every previously reviewed producer statement. Independent static assessment confirms the original clean P2 remains applicable to this producer-copy change. The expected composedskill-contract.tsSHA-256 isbae17b2bf0dd717ab51bb1e9a49634e2e0518c715050fff731fa84da3af3feef. This adds no current-main runtime/heap experiment or Bun heap claim; the original measured Node cache cohorts remain the performance evidence.