Skip to content

fix(memory-core): silence expected operator.admin scope miss in dreaming cleanup#68020

Closed
ImLukeF wants to merge 1 commit into
mainfrom
fix/memory-core-session-cleanup-scope
Closed

fix(memory-core): silence expected operator.admin scope miss in dreaming cleanup#68020
ImLukeF wants to merge 1 commit into
mainfrom
fix/memory-core-session-cleanup-scope

Conversation

@ImLukeF

@ImLukeF ImLukeF commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Dreaming cron's narrative cleanup logs memory-core: narrative session cleanup failed for <phase> phase: missing scope: operator.admin on every dreaming cycle, making healthy instances look broken.

Root cause: subagent.deleteSession dispatches sessions.delete which requires ADMIN_SCOPE. In background-cron context there is no inherited operator scope, so the plugin subagent falls through to a synthetic operator client that intentionally defaults to [WRITE_SCOPE] and does not mint admin — this is codified by the existing rejects fallback session deletion without minting admin scope test in src/gateway/server-plugins.test.ts.

The cleanup was already best-effort (wrapped in try/catch), so functionally nothing was broken — but the warn surfaced on every cycle.

Fix

Suppress the warn only for the specific "missing scope: operator.admin" error (the expected background-cron path). Every other cleanup error — network, timeout, stale run, etc. — still surfaces as warn unchanged.

This preserves the existing security invariant (background plugin calls don't auto-mint admin) rather than weakening scope enforcement just to quiet the log.

Why not grant admin to the synthetic client?

The existing test rejects fallback session deletion without minting admin scope locks in that behaviour as a deliberate security choice. Auto-minting admin in the fallback path would broaden privilege escalation surface for any plugin running in background context, which reviewers would correctly reject. Handling the known-expected error at the memory-core call site is the minimally invasive fix.

Known caveat

Orphan narrative subagent sessions still accumulate because the delete is a no-op from the cron path. This PR does not address that — tracked separately. A follow-up could expose a privileged self-cleanup path (e.g. sessions.delete.owned) scoped to sessions the caller created, but that's a larger design change.

Test plan

  • New test: does not warn when cleanup fails with missing operator.admin scope (background cron fallback path) — asserts logger.warn is not called with the cleanup message when deleteSession rejects with missing scope: operator.admin
  • Existing test: waits once more before cleanup after timeout and logs cleanup failures — unchanged, still passes (mock rejects with "still active", which is not the operator.admin case, so warn still fires)
  • All 43 dreaming-narrative.test.ts tests pass
  • All 35 server-plugins.test.ts tests pass (including the scope-enforcement test)
  • Typecheck clean
  • Lint / import-cycle / madge checks all green

Before / After

Before (every dreaming cycle, log level warn):

2026-04-17T03:02:32.816+10:00 [plugins] memory-core: narrative session cleanup failed for light phase: missing scope: operator.admin
2026-04-17T03:03:01.502+10:00 [plugins] memory-core: narrative session cleanup failed for rem phase: missing scope: operator.admin

After: silent on the scope-mismatch case, still warns on genuine failures.

… dreaming cleanup

The dreaming cron's narrative cleanup calls subagent.deleteSession, which
dispatches sessions.delete (ADMIN_SCOPE). From a background cron there is
no inherited operator scope, so the plugin subagent falls through to a
synthetic operator client that intentionally defaults to [WRITE_SCOPE] and
does not mint admin (codified by 'rejects fallback session deletion
without minting admin scope' in src/gateway/server-plugins.test.ts).

Result: every dreaming cycle logged
  memory-core: narrative session cleanup failed for <phase> phase: missing scope: operator.admin

The cleanup was already best-effort (try/catch), but the warn surfaced to
users on every cycle and made healthy instances look broken.

Treat the 'missing scope: operator.admin' case as an expected no-op and
suppress the warn for just that specific error. Any other cleanup error
(network, timeout, etc.) still surfaces as warn.

Adds a test locking in the new behavior; existing test covering non-scope
cleanup failures continues to pass unchanged.
Copilot AI review requested due to automatic review settings April 17, 2026 06:54
@openclaw-barnacle openclaw-barnacle Bot added extensions: memory-core Extension: memory-core size: XS maintainer Maintainer-authored PR labels Apr 17, 2026
@greptile-apps

greptile-apps Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Silences the expected missing scope: operator.admin warning that fired on every dreaming cycle by filtering it out in the deleteSession catch block. The fix is intentionally narrow: only the known-expected scope error is suppressed; all other cleanup failures still surface as warn. A new test locks in the suppression behaviour, and the existing test confirming non-admin-scope errors still warn is unchanged.

Confidence Score: 5/5

Safe to merge — change is a one-line log-suppression with a targeted test; no security invariants are weakened.

Only finding is P2: includes() on the cause-chain-expanded formatted message is slightly broader than cleanupErr.message ===. This is a minor robustness nit with no current impact; the error format is stable across the codebase and the primary message will always be the exact string.

No files require special attention.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/memory-core/src/dreaming-narrative.ts
Line: 945

Comment:
**`includes()` on formatted message can match cause-chain text**

`formatErrorMessage` appends nested `.cause` messages (separated by ` | `). If a future error wraps an unrelated primary error with `missing scope: operator.admin` as a cause, the warning would be silently dropped. Matching on the raw error or `startsWith` guards against this.

```suggestion
      if (!(cleanupErr instanceof Error && cleanupErr.message === "missing scope: operator.admin")) {
```

This also makes the intent clearer: we are matching the primary error only, not anything in the full cause chain.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(memory-core): silence expected 'miss..." | Re-trigger Greptile

// delete with "missing scope: operator.admin" on every cycle, so treat
// it as an expected no-op rather than emitting noise. Genuine failures
// (any other error) are still surfaced as warn.
if (!errMessage.includes("missing scope: operator.admin")) {

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 includes() on formatted message can match cause-chain text

formatErrorMessage appends nested .cause messages (separated by |). If a future error wraps an unrelated primary error with missing scope: operator.admin as a cause, the warning would be silently dropped. Matching on the raw error or startsWith guards against this.

Suggested change
if (!errMessage.includes("missing scope: operator.admin")) {
if (!(cleanupErr instanceof Error && cleanupErr.message === "missing scope: operator.admin")) {

This also makes the intent clearer: we are matching the primary error only, not anything in the full cause chain.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/memory-core/src/dreaming-narrative.ts
Line: 945

Comment:
**`includes()` on formatted message can match cause-chain text**

`formatErrorMessage` appends nested `.cause` messages (separated by ` | `). If a future error wraps an unrelated primary error with `missing scope: operator.admin` as a cause, the warning would be silently dropped. Matching on the raw error or `startsWith` guards against this.

```suggestion
      if (!(cleanupErr instanceof Error && cleanupErr.message === "missing scope: operator.admin")) {
```

This also makes the intent clearer: we are matching the primary error only, not anything in the full cause chain.

How can I resolve this? If you propose a fix, please make it concise.

Copilot AI 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.

Pull request overview

This PR reduces noisy logging in the memory-core “dreaming narrative” cleanup path by suppressing a known-expected authorization failure that occurs when the dreaming cron runs without inherited operator admin scope.

Changes:

  • Suppress the cleanup logger.warn only when deleteSession fails with "missing scope: operator.admin".
  • Add a focused unit test ensuring the warning is not emitted for that expected background-cron fallback error.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
extensions/memory-core/src/dreaming-narrative.ts Filters the specific expected "missing scope: operator.admin" cleanup error to avoid warning spam while preserving warnings for all other failures.
extensions/memory-core/src/dreaming-narrative.test.ts Adds coverage asserting the cleanup warning is suppressed for the expected missing-admin-scope error case.

@prtags

prtags Bot commented Apr 23, 2026

Copy link
Copy Markdown

Related work from PRtags group ultimate-chow-4ei0

Title: Open PR duplicate: [Bug]: memory-core: narrative session cleanup fails with "missing scope: operator.admin"

Number Title
#68020* fix(memory-core): silence expected operator.admin scope miss in dreaming cleanup
#68087 fix(memory-core): downgrade cleanup warning to debug when missing operator.admin scope
#68130 fix: reduce log level for narrative session cleanup scope failures
#68312 fix(memory-core): downgrade narrative cleanup WARN to debug for missing-scope errors
#68681 fix(memory-core): suppress expected dreaming cleanup scope warnings

* This PR

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jun 14, 2026
@clawsweeper

clawsweeper Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 15, 2026, 1:02 PM ET / 17:02 UTC.

Summary
The PR suppresses memory-core dreaming narrative cleanup warnings when formatted cleanup errors contain missing scope: operator.admin and adds a unit test for that suppression.

PR surface: Source +12, Tests +25. Total +37 across 2 files.

Reproducibility: no. I did not establish a current-main reproduction; the old release-era warning path is source-plausible, but current main now uses isolated cron plus owner-scoped plugin cleanup.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: vector/embedding metadata: extensions/memory-core/src/dreaming-narrative.test.ts, vector/embedding metadata: extensions/memory-core/src/dreaming-narrative.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦪 silver shellfish
Result: blocked until real behavior proof is added.

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

Rank-up moves:

  • Rebase against current main and re-check whether the warning still reproduces after isolated cron plus plugin-owned cleanup.
  • [P1] Add redacted after-fix runtime logs or terminal output from an actual dreaming cycle.
  • If a guard remains necessary, match only the primary expected error and keep warnings for other cleanup failures.

Proof guidance:

  • [P1] Needs real behavior proof before merge: Missing: the PR body lists unit/CI checks and before logs, but no after-patch terminal output or redacted runtime logs from an actual dreaming cycle. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] Merging the branch as-is could hide genuine memory-core cleanup failures or owner-scope regressions that current main is expected to surface.
  • [P1] The PR body lists unit and CI checks plus before logs, but it does not include after-patch runtime logs from an actual dreaming cycle.
  • [P1] The live branch is conflicting and not maintainer-modifiable, so there is no direct maintainer repair path on the contributor branch.
  • [P1] The protected maintainer label requires explicit maintainer handling rather than automated cleanup closure.

Maintainer options:

  1. Rebase And Reprove Current Behavior (recommended)
    Refresh the branch against current main, verify an actual dreaming cycle, and drop the suppression if owner-scoped cleanup already resolves the warning.
  2. Keep Only A Primary-Error Guard
    If the warning still reproduces on current main, keep a guard that matches the primary cleanup error exactly and include focused runtime proof.
  3. Pause Or Close The Stale Branch
    If maintainers accept current main as the canonical fix, leave this PR for closure instead of merging redundant log suppression.

Next step before merge

  • [P1] Needs maintainer disposition rather than automated repair because the PR is protected, conflicting, not maintainer-modifiable, missing real proof, and likely superseded by current-main cleanup ownership work.

Security
Cleared: No concrete security or supply-chain concern found; the diff does not add permissions, dependencies, workflows, secret handling, or auth minting.

Review findings

  • [P2] Remove the stale missing-scope suppression — extensions/memory-core/src/dreaming-narrative.ts:945
Review details

Best possible solution:

Keep current main's isolated cron and owner-scoped plugin cleanup as the canonical fix, and only accept a rebased primary-error-only guard if current-main runtime proof still shows expected scope noise.

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

No. I did not establish a current-main reproduction; the old release-era warning path is source-plausible, but current main now uses isolated cron plus owner-scoped plugin cleanup.

Is this the best way to solve the issue?

No. The log suppression was a plausible old-branch mitigation, but current main's isolated cron and plugin-owned cleanup are the cleaner owner-boundary solution; any remaining guard should be rebased, proof-backed, and primary-error-only.

Full review comments:

  • [P2] Remove the stale missing-scope suppression — extensions/memory-core/src/dreaming-narrative.ts:945
    Current main preserves plugin identity and uses owner-scoped synthetic admin for same-plugin deleteSession cleanup, with tests and docs covering that contract. Suppressing any formatted error containing missing scope: operator.admin can now hide real cleanup or owner-scope failures; rebase and drop this guard unless current main still reproduces the warning, then match only the primary error.
    Confidence: 0.88

Overall correctness: patch is incorrect
Overall confidence: 0.87

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 8ded75628437.

Label changes

Label justifications:

  • P2: This is a bounded memory-core cleanup/logging PR with real observability impact, but it is not an urgent outage, data-loss, or security emergency.
  • merge-risk: 🚨 other: Merging the stale suppression could hide current-main cleanup or owner-scope regressions that should remain visible.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦪 silver shellfish.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: Missing: the PR body lists unit/CI checks and before logs, but no after-patch terminal output or redacted runtime logs from an actual dreaming cycle. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +12, Tests +25. Total +37 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 15 3 +12
Tests 1 25 0 +25
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 40 3 +37

What I checked:

  • Repository policy read: Root and scoped extension review policy were read and applied, including protected-label handling, plugin-boundary review, best-fix review, and real behavior proof requirements. (AGENTS.md:21, 8ded75628437)
  • PR patch suppression: The branch changes the final narrative cleanup catch to suppress any formatted cleanup error containing missing scope: operator.admin. (extensions/memory-core/src/dreaming-narrative.ts:945, d7c14b5c7bb7)
  • Current main cleanup path: Current main still warns on final narrative cleanup failures, after attempting deletion for accepted narrative runs. (extensions/memory-core/src/dreaming-narrative.ts:1149, 8ded75628437)
  • Current main owner-scoped deletion: Current main passes plugin owner metadata and synthetic admin scope for plugin-owned subagent cleanup instead of relying on memory-core to hide the missing-admin failure. (src/gateway/server-plugins.ts:624, 8ded75628437)
  • Cleanup contract tests: Gateway tests still reject arbitrary fallback session deletion without admin, but verify same-plugin cleanup succeeds with owner-scoped synthetic admin. (src/gateway/server-plugins.test.ts:1173, 8ded75628437)
  • Formatted error cause chain: formatErrorMessage begins with the primary error message and appends nested cause messages, so substring matching can suppress a different primary cleanup failure that happens to wrap the admin-scope text. (src/infra/errors.ts:69, 8ded75628437)

Likely related people:

  • steipete: Authored the owner-scoped plugin subagent cleanup path and related tests/docs that make same-plugin deleteSession cleanup succeed without broadening arbitrary session deletion. (role: recent gateway and plugin-runtime cleanup contributor; confidence: high; commits: 72f7d7e4ea7a, 6f2fbaaaf86d; files: src/gateway/server-plugins.ts, src/gateway/server-plugins.test.ts, src/gateway/server-methods/sessions.ts)
  • Patrick-Erichsen: Authored the managed dreaming cron isolation work that moved the old main-session warning path toward the current-main solution. (role: recent memory-core dreaming cron contributor; confidence: high; commits: aca92b29065f; files: extensions/memory-core/src/dreaming.ts, extensions/memory-core/src/dreaming.test.ts)
  • Alix-007: Authored recent dreaming narrative cleanup and fallback-safety work in the same module and tests. (role: recent memory-core narrative cleanup contributor; confidence: medium; commits: 2870a28aa906, bc95af1b7c6f; files: extensions/memory-core/src/dreaming-narrative.ts, extensions/memory-core/src/dreaming-narrative.test.ts)
  • vignesh07: GitHub timeline shows this person was assigned to this PR on April 17, 2026, making them a likely routing candidate for final maintainer disposition. (role: assigned follow-up owner; confidence: medium)
  • zhang-guiping: Current checkout blame shows the latest grafted main commit carrying the relevant memory-core and gateway files through the current branch state. (role: recent current-main line owner; confidence: low; commits: ba1be23821da; files: extensions/memory-core/src/dreaming-narrative.ts, extensions/memory-core/src/dreaming.ts, src/gateway/server-plugins.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.

@clawsweeper clawsweeper Bot added merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. and removed merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. labels Jun 14, 2026
@vincentkoc

Copy link
Copy Markdown
Member

Thanks @ImLukeF for the focused cleanup work here. I am closing this because the underlying memory-core dreaming cleanup path was fixed by the merged Clownfish replacement PR #84802 (#84802), which carried forward the credited contributor trail from the source work and landed the bounded session cleanup on May 21, 2026.

This PR (#68020, #68020) covered the same expected operator.admin cleanup warning/session-cleanup family, and #84802 is now the canonical landed fix path. If this still reproduces on current main after #84802, please reply with the new reproduction details and we can reopen or split a follow-up.

@vincentkoc vincentkoc closed this Jun 16, 2026
@vincentkoc vincentkoc added the clownfish Tracked by Clownfish automation label Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clownfish Tracked by Clownfish automation extensions: memory-core Extension: memory-core maintainer Maintainer-authored PR merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants