Skip to content

fix(plugin): archive idle low-eta skills - #2209

Open
CovD831 wants to merge 6 commits into
MemTensor:dev-v2.0.29from
CovD831:codex/fix-skill-idle-archive
Open

fix(plugin): archive idle low-eta skills#2209
CovD831 wants to merge 6 commits into
MemTensor:dev-v2.0.29from
CovD831:codex/fix-skill-idle-archive

Conversation

@CovD831

@CovD831 CovD831 commented Aug 4, 2026

Copy link
Copy Markdown

Description

Archive active Skills that remain below the retrieval ETA threshold after a configurable period of retrieval inactivity.

This change:

  • adds algorithm.skill.idleArchiveMs (30 days by default);
  • uses lastUsedAt ?? createdAt as the idle baseline;
  • queries eligible candidates directly in SQLite and drains 500-row batches oldest-first;
  • runs the scan from the existing lifecycle tick without adding a timer;
  • preserves the public four-argument shouldArchiveIdle API;
  • emits structured lifecycle status events/logs and documents the behavior.

No new dependencies.

Related Issue (Required): Fixes #2144

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Documentation update

How Has This Been Tested?

  • Unit Test
  • Test Script Or Test Steps (please provide)
  • Pipeline Automated API Test (not applicable)

Commands and results:

  • Focused lifecycle/storage/config/OpenClaw integration suite: 67/67 passed.
  • Broader skill/config/storage/pipeline/OpenClaw suite: 257/257 passed.
  • Full unit suite: 1302 passed, 1 skipped. Two repository-layout tests failed only because the remote test copy was outside the normal apps/memos-local-plugin layout and could not resolve repository-level workflow files.
  • tsc --noEmit: passed.
  • tsc -p tsconfig.build.json: passed.
  • git diff --check: passed.

Additional verification:

  • a 501-candidate backlog test verifies that one lifecycle tick drains multiple batches;
  • mutation checks verify the suite catches wrong idle baselines, an inclusive ETA boundary, disabled lifecycle invocation, single-batch starvation, and missing recordUse persistence.

make format could not start locally because Poetry is unavailable. This change is confined to the TypeScript plugin and does not modify Python files.

Checklist

  • I have performed a self-review of my own code | 我已自行检查了自己的代码
  • I have commented my code in hard-to-understand areas | 我已在难以理解的地方对代码进行了注释
  • I have added tests that prove my fix is effective or that my feature works | 我已添加测试以证明我的修复有效或功能正常
  • MemOS-Docs issue/PR is not applicable; plugin-local documentation is updated
  • I have linked the issue to this PR (if applicable) | 我已将 issue 链接到此 PR(如果适用)
  • I have mentioned the person who will review this PR | Maintainer assignment requested after submission

Reviewer Checklist

Hun-ger and others added 2 commits August 4, 2026 21:00
…Tensor#2208)

* fix(plugin): synchronize Hermes release version metadata

* fix(plugin): keep Hermes compression turn read-only

* fix(plugin): reload Hermes config on restart

* fix(plugin): share Hermes bridge across providers

* fix(plugin): isolate Hermes bridges by data home

* fix(plugin): harden Hermes recovery lifecycle

* release: @memtensor/memos-local-plugin v2.0.12-beta.1

* fix(plugin): satisfy Python lint checks

* fix(plugin): improve retrieval relevance ranking

* fix(plugin): use clean OpenClaw user input

* fix(plugin): ignore OpenClaw internal wakeups

* fix(plugin): recall compacted same-session history

* style(plugin): format Hermes provider pipeline test

* fix(plugin): bound foreground retries and shutdown

* fix(plugin): unblock Hermes bridge reader

* fix(plugin): honor long Retry-After cooldowns

* fix(plugin): show memory add roles correctly

* style(plugin): format Hermes bridge changes

---------

Co-authored-by: 谁在吵着吃糖 <gyunhang@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
@Memtensor-AI Memtensor-AI added area:plugin OpenClaw & Hermes status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Aug 4, 2026
@Memtensor-AI

Memtensor-AI commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

🤖 Open Code Review

Target: PR #2209
Task: d48df831a127afae
Base: dev-v2.0.29
Head: codex/fix-skill-idle-archive

🔍 OpenCodeReview found 3 issue(s) in this PR.

⚠️ 1 warning(s) occurred during review.


1. apps/memos-local-plugin/core/skill/subscriber.ts (L275-L281)

This warning is dead code and will never fire. The while condition is batchesProcessed < IDLE_ARCHIVE_MAX_BATCHES_PER_TICK, so once batchesProcessed is incremented to equal IDLE_ARCHIVE_MAX_BATCHES_PER_TICK (10), the next iteration's while guard will be 10 < 10 → false and the loop body is never entered again — meaning line 275 is never reached at the moment the equality holds. The batch-limit warning is silently suppressed, which masks runaway archive scenarios.

Fix: move the log outside and after the while-loop, guarding on the final batchesProcessed value:

💡 Suggested Change

Before:

      if (batchesProcessed === IDLE_ARCHIVE_MAX_BATCHES_PER_TICK) {
        log.warn("skill.idle_archive_batch_limit_reached", {
          batchCount: batchesProcessed,
          archivedCount: archivedTotal,
          batchSize: IDLE_ARCHIVE_BATCH_LIMIT,
        });
      }

After:

    }
    if (batchesProcessed >= IDLE_ARCHIVE_MAX_BATCHES_PER_TICK) {
      log.warn("skill.idle_archive_batch_limit_reached", {
        batchCount: batchesProcessed,
        archivedCount: archivedTotal,
        batchSize: IDLE_ARCHIVE_BATCH_LIMIT,
      });
    }

2. apps/memos-local-plugin/core/skill/subscriber.ts (L236)

archivedTotal is only referenced inside the skill.idle_archive_batch_limit_reached log block, which is dead code (see above). Until the dead-code bug is fixed by moving the log outside the loop, archivedTotal is effectively a write-only variable in all reachable code paths, adding noise without benefit.


3. apps/memos-local-plugin/core/storage/repos/skills.ts (L171-L172)

The COALESCE(last_used_at, created_at) expression is evaluated twice per row — once in the WHERE clause and once in ORDER BY. SQLite does not deduplicate sub-expression evaluation across clauses. For a table that may contain many active skills this causes unnecessary per-row overhead. Wrapping the query in a CTE or sub-select to materialise the expression once removes the duplication:

SELECT ${COLUMNS.join(", ")}
  FROM (
    SELECT *, COALESCE(last_used_at, created_at) AS idle_since
      FROM skills
     WHERE status = 'active'
  )
 WHERE eta < @min_eta
   AND idle_since <= @cutoff
 ORDER BY idle_since ASC
 LIMIT @limit

🧹 Filtered 1 low-confidence OCR finding(s) before posting/fix-loop (existing_code_mismatch: 1).

Generated by cloud-assistant via Open Code Review.

@CovD831

CovD831 commented Aug 4, 2026

Copy link
Copy Markdown
Author

Addressed the actionable Open Code Review findings in c5c0d0c:

  • Enforced a one-hour minimum for idleArchiveMs, with boundary tests and documentation updates, so 0 cannot trigger immediate bulk archival.
  • Renamed the inner list to archiveCandidates.
  • Shared IDLE_ARCHIVE_BATCH_LIMIT between the repository and subscriber.
  • Reordered the zero-progress and partial-batch exits so any non-empty stalled batch is logged consistently.

I did not add cursor pagination for finding 3: the repository query already returns only rows satisfying the archive predicate, and synchronous setStatus removes processed rows from the next active-only query. The existing zero-progress guard still bounds unexpected repository behavior.

I also retained the direct COALESCE expressions for finding 6. They are trivial, and a SQLite CTE may be inlined without reducing evaluation while making the query less direct.

Verification:

  • focused lifecycle/storage/config/OpenClaw suite: 67/67 passed
  • broader related suite: 331/331 passed
  • tsc --noEmit: passed
  • production TypeScript build: passed

@MatthewZhuang
MatthewZhuang changed the base branch from main to dev-v2.0.29 August 4, 2026 15:16
@CovD831

CovD831 commented Aug 4, 2026

Copy link
Copy Markdown
Author

The PR was retargeted from main to dev-v2.0.29 after the review update. I aligned the branch in 243b0a6 without rewriting published history and removed the unrelated #2208 delta. The final diff against the new base remains scoped to the 16 idle-archive files (392 additions, 10 deletions).

Fresh verification from the new base composition:

  • focused suite: 67/67 passed
  • broader related suite: 329/329 passed
  • TypeScript typecheck and production build: passed

@Memtensor-AI

Copy link
Copy Markdown
Collaborator

✅ Automated Test Results: PASSED

All tests passed (67/67 executed). memos_local_plugin/unit: 67/67. Duration: 9s [advisory, non-gating] AI-generated tests on branch test/auto-gen-83c5b20bcb739226-20260804233503: 40/40 passed — these do NOT affect the PR verdict; review the branch manually.

Branch: codex/fix-skill-idle-archive

@Memtensor-AI Memtensor-AI added status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发 and removed status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Aug 4, 2026
@Memtensor-AI Memtensor-AI added status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 and removed status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发 labels Aug 4, 2026
@CovD831

CovD831 commented Aug 4, 2026

Copy link
Copy Markdown
Author

Addressed the latest Open Code Review finding in 0ff0a72.

The idle-archive loop now processes at most 10 batches per lifecycle tick (5,000 Skills at the existing 500-row batch size). Reaching the cap emits skill.idle_archive_batch_limit_reached with batch and archive counts; any remaining eligible Skills stay active and are processed by the next lifecycle tick.

The regression test first demonstrated the old behavior by archiving all 5,001 rows, then verifies the bounded behavior: 5,000 archived and 1 deferred after the first tick, followed by all 5,001 archived after the second tick.

Verification:

  • focused lifecycle/storage/config/OpenClaw suite: 68/68 passed
  • broader related suite: 330/330 passed
  • TypeScript typecheck and production build: passed

@Memtensor-AI

Copy link
Copy Markdown
Collaborator

✅ Automated Test Results: PASSED

All tests passed (68/68 executed). memos_local_plugin/unit: 68/68. Duration: 18s [advisory, non-gating] AI-generated tests on branch test/auto-gen-d48df831a127afae-20260805003545: 56/56 passed — these do NOT affect the PR verdict; review the branch manually.

Branch: codex/fix-skill-idle-archive

@Memtensor-AI Memtensor-AI added status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发 and removed status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:plugin OpenClaw & Hermes status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发

Projects

None yet

Development

Successfully merging this pull request may close these issues.

memos-local-plugin: 技能归档(archived)状态从未被触发

4 participants