Commit graph

840 commits

Author SHA1 Message Date
wings1029
f7cc6ebe1e
fix(agent-core,memory-core): keep compaction summary and memory snippet truncation UTF-16 safe (#102542)
* fix(agent-core,memory-core): keep compaction summary and memory snippet truncation UTF-16 safe

* fix: make compaction and memory truncation UTF-16 safe

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 10:08:11 +01:00
lsr911
6a3834d41d
fix(memory-core): use truncateUtf16Safe for diary context truncation (#102524)
* fix(memory-core): use truncateUtf16Safe for diary context truncation

* test(memory-core): cover utf16 diary truncation

* refactor(memory-core): use plugin sdk text runtime

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 09:49:21 +01:00
xydt-tanshanshan
1d4d8474da
[AI] fix(memory): use truncateUtf16Safe for dreaming snippet truncation (#101946)
* [AI] fix(memory): use truncateUtf16Safe for dreaming snippet truncation

Replace .slice(0, N) with truncateUtf16Safe() at 5 call sites in
dreaming-phases.ts so complex emoji and surrogate pairs near the
truncation boundary are not split into lone surrogates.

truncateUtf16Safe is the standard SDK helper, already used in
session-cost-usage, cron, exec-approval, and node-host modules
for the same purpose.

* [AI] fix(memory): use SDK facade import for truncateUtf16Safe, add surrogate-proof test

Replace direct @openclaw/normalization-core/utf16-slice import with
openclaw/plugin-sdk/memory-core-host-engine-foundation SDK facade,
matching manager-search.ts in the same extension.

Add surrogate-proof.test.ts that runs a full dreaming ingestion sweep
with emoji at the 280-char boundary and verifies zero lone surrogates.

* [AI] fix(memory-proof): use relative imports in surrogate-proof test

* [AI] fix(memory-proof): place emoji at post-prefix 280-char boundary, assert session corpus file

* [AI] fix(memory-proof): avoid unnecessary String callback in oxlint

* [AI] fix(memory-proof): add curly braces per eslint curly rule

* [AI] feat(proof): add standalone dreaming surrogate truncation proof script

* [AI] chore(proof): remove unused SQLite-dependent proof script

* [AI] fix(proof): correct emoji boundary placement for all 5 call sites

* [AI] fix(proof): add curly braces per eslint curly rule in proof script

* [AI] fix(proof): session emoji at actual corpus 280-char boundary

* test: streamline memory dreaming UTF-16 coverage

---------

Co-authored-by: hailory <hailory@xydigit.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 05:40:22 +01:00
Vincent Koc
6765eb0166
refactor(memory-core): localize internal declarations (#101969) 2026-07-07 19:31:25 -07:00
zw-xysk
1aee742d23
fix(memory-core): guard supplement lookup in resolveMemoryReadFailureResult with try-catch (fixes #101809) (#101902)
* fix(memory-core): guard supplement lookup in resolveMemoryReadFailureResult with try-catch (fixes #101809)

* fix(memory-core): preserve primary read errors

---------

Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
2026-07-07 17:34:57 -07:00
Vincent Koc
b88f80940a
refactor: localize internal implementation symbols (#101831) 2026-07-07 10:23:36 -07:00
Vincent Koc
3d206140f3
refactor: localize internal implementation constants (#101758) 2026-07-07 08:34:13 -07:00
Vincent Koc
407443264c
refactor: localize internal reply and plugin types (#101666) 2026-07-07 05:51:47 -07:00
Youssef Hemimy
333a77fde3
fix(memory-core): clamp widen-fallback kNN k to sqlite-vec 4096 limit (#96157)
* fix(memory-core): clamp widen-fallback kNN k to sqlite-vec 4096 limit

The widen fallback in searchVector re-runs the kNN with k = vectorCount
(the full vector table size), unclamped. sqlite-vec hard-caps `k` at 4096,
so once a memory index exceeds 4096 chunks any query that triggers the
fallback fails with "k value in knn query too large".

Clamp the widen re-query to MAX_VECTOR_KNN_K (4096). 4096 oversampled
candidates is far more than enough to feed top-N hybrid ranking, so there
is no meaningful recall loss.

* test(memory-core): cover widen-fallback kNN clamp to sqlite-vec 4096 ceiling

Add two regression tests for the searchVector widen-fallback clamp:
- asserts a >4096-vector widen re-query caps k at 4096 (out-of-range k
  would raise sqlite-vec "k out of range" and kill the whole search)
- asserts a sub-ceiling widen (30) passes through untouched, proving the
  clamp is a ceiling and not a fixed value

Uses a prepare-mock on the KNN/COUNT statements rather than materializing
4097+ real vectors plus the native extension; the assertion is purely on
the k bind handed to the widen re-query.

* fix(memory-core): preserve filtered recall beyond KNN cap

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-06 16:53:34 -07:00
Alix-007
962d1096d4
fix(memory-core): keep daily ingestion outside session repair (#93389)
* fix(memory-core): clear daily-ingestion sqlite namespace on dreaming repair

repairDreamingArtifacts() cleared the dreaming-session-ingestion-files and
dreaming-session-ingestion-seen namespaces but not the migrated
dreaming-daily-ingestion namespace. After #92020 taught auditDreamingArtifacts()
to treat all three ingestion namespaces as ingestion state, the repair path
became asymmetric: the memory status --fix re-audit still reported
sessionIngestionExists=true from the surviving daily rows, and the daily
ingestion bookkeeping leaked past repair so daily memory files were not
re-ingested on the next sweep.

Clear DREAMING_DAILY_INGESTION_NAMESPACE alongside the session files/seen
namespaces so repair fully resets dreaming ingestion state, matching the audit.

* chore: retrigger CI for real behavior proof check

* fix(memory-core): keep daily ingestion outside session repair

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: Alix-007 <li.long15@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-06 19:16:26 +01:00
mushuiyu886
9042e8020f
fix(memory): fall back to wiki for missing all-corpus reads (#100904)
* Fix memory_get all supplement fallback

* refactor(memory): use typed missing-read contract

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-06 07:19:51 -07:00
xydt-tanshanshan
738654d20c
fix(memory): add batch completed log after embedding batch finishes (#94732)
* [AI] fix(memory): add batch completed and batch failed logs for embedding ops

The embedBatchWithRetry function logged 'batch start' but never logged
'batch completed' or 'batch failed' after the embedding batch call,
leaving operators with no post-request feedback. When batches hang or
time out, only 'batch start' appears in logs with no diagnostic signal.

Add 'batch completed' log after runEmbeddingOperationWithTimeout success
and 'batch failed' log in the catch handler. This is an observability
improvement, not a functional fix for the underlying hang (#93312).

Related to #93312

* [AI] fix(memory): use formatErrorMessage for embedding batch error log

Replace String(err) with formatErrorMessage(err) in the batch failed
catch handler to redact sensitive provider error text (e.g. API keys
and tokens embedded in error messages) before logging.

Related to #94732

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-06 03:10:51 -07:00
Vincent Koc
c9abc75884
refactor: remove dead code and consolidate repeated paths (#100650)
* refactor(search): reuse provider setup finalizer

* refactor(android): remove unused helpers

* refactor(apps): remove unused Swift declarations

* refactor(diagnostics): reuse private reply delivery

* refactor(memory): reuse raw short-term store writer

* refactor(logbook): reuse batch row mapping

* refactor(scripts): centralize oxlint format policy

* refactor(memory): share qmd cache context hashing

* refactor(doctor): share auth issue classification

* chore(i18n): refresh native source inventory
2026-07-06 02:24:37 -07:00
Miorbnli
7d939b6456
fix(memory-core): guard qmd mcporter JSON.parse against non-JSON stdout (#98381)
* fix(memory-core): guard qmd mcporter JSON.parse against non-JSON stdout

runQmdSearchViaMcporter parsed mcporter subprocess stdout with JSON.parse
outside the runMcporter try/catch (qmd-manager.ts:2722). A non-JSON stdout
(daemon warning bleeding onto stdout, output truncated by maxOutputChars, CLI
killed early, or flag mismatch) threw a raw SyntaxError that propagated
uncaught out of runQmdSearchViaMcporter, surfacing in agent logs as a
context-free SyntaxError with no hint of the actual mcporter failure.

Wrap JSON.parse in try/catch and throw a typed Error carrying a stdout snippet
(matching the guard pattern already used in parseListedCollections in this
file, and the recent matrix #97973 / sms #97999 / signal #98073 /
telegram-ingress #98372 JSON.parse guard series).

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(memory-core): preserve cause in qmd mcporter JSON.parse guard

Add { cause: err } to the re-thrown Error to satisfy the preserve-caught-error
lint rule; the original SyntaxError is now chained, improving diagnosability.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(memory-core): redact raw stdout from qmd mcporter error (security-boundary)

ClawSweeper flagged that the previous error message exposed raw mcporter
stdout (first 200 chars) before session visibility filtering, which could
leak sensitive content. Drop the stdout preview from the thrown message;
keep the original SyntaxError as `cause` for diagnostics so the parse-failure
reason is still reachable without surfacing unfiltered subprocess output.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(memory-core): keep qmd mcporter error message generic (no raw stdout leak)

The SyntaxError thrown by JSON.parse embeds a snippet of the raw input in its
message (e.g. Unexpected token '<', then the raw bytes). Including that
SyntaxError message in the thrown Error would surface unfiltered mcporter
stdout before session visibility filtering. Drop the parse-error message from
the thrown Error; keep the original SyntaxError as cause for developer
diagnostics only.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(memory-core): keep qmd mcporter cause generic (no raw stdout leak via formatErrorMessage)

formatErrorMessage walks the .cause chain into the user-visible path.
Keeping the JSON.parse SyntaxError on .cause leaked its embedded raw
stdout snippet through formatErrorMessage even with a generic message.
Give the cause a generic message too; the raw snippet no longer reaches
the user.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-06 06:57:41 +00:00
Peter Steinberger
b22c36f112
fix: land ten small reliability fixes (#100399)
* fix(cron): reject sub-millisecond durations

* fix(skill-workshop): preserve proposal terminal newline

Preserve proposal_content exactly at the agent tool boundary and make
renderProposalMarkdown defensively emit a terminal newline.

Add focused regressions for the tool write path and markdown renderer.

* fix(skill-workshop): reject blank raw proposal content

* fix: treat empty-string optional integer tool params as unset

Optional positive-integer tool params (e.g. Telegram replyTo/threadId)
threw ToolInputError when a tool-calling model populated them with an
empty-string or whitespace-only default. Those defaults carry no value,
so readPositiveIntegerParam/readNonNegativeIntegerParam now treat a
blank string as unset (undefined) instead of throwing, while still
rejecting genuinely invalid present values (0, "42.5", "-3"). This
prevents silent message-delivery failures when models emit empty
routing-param defaults. Adds unit tests covering blank vs invalid.

* fix(gateway): log start session persistence failures

The gateway session-lifecycle "start" event persistence
(persistGatewaySessionLifecycleEvent, which surfaces write failures via
requireWriteSuccess) was fired as void ...catch(() => undefined), swallowing
the rejection with zero logging. A failed start-marker write silently dropped
the run's start record from restart-recovery accounting, with no
operator-visible trace.

The sibling terminal-phase catch already logs this since #97839; the start
path was the unfixed sibling. Mirror that fix: log the swallowed start-phase
persistence failure with the same redacted message shape via formatForLog,
keeping the fire-and-forget semantics unchanged. Adds a focused regression
test asserting the log fires on start-persist rejection.

* fix(memory): report close-time pending work failures

* fix(shared): return "" from sliceUtf16Safe when end <= start, matching native .slice

sliceUtf16Safe silently swapped reversed bounds (to < from) instead of
returning "" like String.prototype.slice, creating a subtle footgun for
callers with dynamic start/end pairs.

Caller scan across src/, extensions/, and packages/ confirmed no production
code relies on the old swap behavior — all callers use (text, 0, N) or
(text, -N) forms only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(plugins): require plugin manifest in npm verifier

* fix(android): propagate CancellationException in CameraHandler catch blocks

Catch (err: Throwable) swallows kotlinx.coroutines.CancellationException,
breaking structured concurrency when the coroutine scope is cancelled
during camera operations (handleList/handleSnap/handleClip).

Add CancellationException rethrow before each Throwable catch to match
the existing pattern used in GatewaySession and TalkModeManager.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(android): propagate CancellationException past GatewaySession invoke boundary

* chore: sync native i18n inventory after gateway session line shift

* fix(agents): prevent native hook relay bridge race condition on renew and registration

Remove synchronous bridge record write after server.listen() that races
before the TCP server binds, and guard renew handler with server.listening
check to prevent stale relay registrations.

Closes #98650

* fix: harden small reliability fixes

Co-authored-by: cxbAsDev <cxbAsDev@users.noreply.github.com>

* docs(agents): explain buffered LSP spawn failures

* docs(agents): clarify LSP spawn timeout invariant

---------

Co-authored-by: qingminlong <qing.minlong@xydigit.com>
Co-authored-by: anyech <anyech@gmail.com>
Co-authored-by: snotty <snotty@users.noreply.github.com>
Co-authored-by: masatohoshino <g515hoshino@gmail.com>
Co-authored-by: lin-hongkuan <lin-hongkuan@users.noreply.github.com>
Co-authored-by: simon-w <weng.qimeng@xydigit.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: 宇宙熊Yzx <53250620+849261680@users.noreply.github.com>
Co-authored-by: xialonglee <li.xialong@xydigit.com>
Co-authored-by: nankingjing <1079826437@qq.com>
Co-authored-by: cxbAsDev <cxbAsDev@users.noreply.github.com>
2026-07-05 11:12:55 -07:00
Peter Steinberger
c757675f34
improve: keep isolated tests under one second (#100019)
* test: speed up isolated test suite

* test: finish isolated latency cleanup

* test: eliminate remaining isolated latency spikes

* test: remove final isolated timing outliers

* test: bound full-suite tooling processes

* test: bound native test process lifetime

* test: warm isolated runtime suites

* test: eliminate final isolated timing outliers

* test: fix isolated timing fixture types

* test: make timeout cleanup timing deterministic

* test: pin media manifests to source checkout

* test: isolate provider manifest contracts

* test: eliminate residual isolated timing spikes

* test: restore final isolated timing fixes

* test: eliminate remaining isolated timing spikes

* test: warm Zalo lifecycle imports

* test: keep isolated suites below one second

* test: use readable browser response fixtures
2026-07-05 10:57:19 -07:00
Dallin Romney
c2fc7aa28a
refactor: consolidate exact keyed async queues (#99691)
* refactor: consolidate keyed async queues

* chore: refresh merge-ref CI

* refactor: encapsulate keyed queue ownership
2026-07-04 16:45:07 -07:00
grifjef
7a0188cbd2
fix(memory-core): treat dreaming fence marker lines as inside-fence in promotion guard (#83718)
The lineRangeOverlapsDreamingFence guard tracked insideFence state from
the marker lines but did not flag ranges that included the marker lines
themselves. A relocated promotion range that ended on a start marker,
began on an end marker, or covered only a marker line passed the guard,
and the snippet built from those raw lines carried the marker text into
MEMORY.md.

Treat marker lines as inside-fence content for range overlap purposes
and add unit + integration coverage. The integration test exercises the
real applyShortTermPromotions path: pre-patch a recall whose stored
snippet is the start-marker text produces a 'Promoted From Short-Term
Memory' entry containing the literal marker; post-patch the same input
yields applied=0 and no MEMORY.md write. Refs #80613.
2026-07-04 13:01:04 -07:00
Peter Steinberger
614e87cce1
chore: update dependencies (#100027) 2026-07-04 14:56:50 -04:00
Peter Steinberger
eafe2a8d0b
refactor: consolidate duplicated plugin state and doctor migration plumbing onto SDK seams (#99850)
* refactor(plugin-sdk): add createPersistentDedupeCache and migrate channel presence caches

* refactor(matrix): adopt SDK approval reaction target store

* refactor(plugin-sdk): share doctor legacy-state migration fs helpers

* refactor(memory-core): dedupe qmd cache entry envelope validation

* chore(plugin-sdk): pin surface budgets for shared dedupe and doctor helpers

* test(matrix): use future approval expiry fixtures for reaction targets

* test(matrix): use future approval expiry fixtures for reaction targets
2026-07-04 01:51:03 -07:00
Dallin Romney
c7aca4f029
refactor: consolidate async timing helpers (#99721) 2026-07-03 17:58:15 -07:00
Dallin Romney
8c5f45fc36
refactor(shared): consolidate provider and utility lazy loaders (#98749)
* refactor(shared): consolidate provider lazy loaders

* refactor(shared): leave enforcement to follow-up
2026-07-02 21:16:26 -07:00
Vincent Koc
1f38396239
test(memory): align dreaming corpus promotion expectations 2026-07-01 20:26:18 -07:00
Sahibzada
90e31be388
fix(memory-core): skip qmd zero-hit search sync 2026-07-01 04:50:59 -07:00
Yzx
39898fe91b
test(memory): cover live manager after CLI reindex (#96094) 2026-07-01 01:59:20 -07:00
tayoun
5bbd74266d
fix(memory): skip raw snippets during promotion (#94636) 2026-07-01 01:57:27 -07:00
zw-xysk
742f0c9f82
fix(memory): detect unindexed session transcripts in status mode (fixes #97814) (#97857)
* fix(memory): detect unindexed session transcripts in status mode (fixes #97814)

The status-purpose MemoryIndexManager init skips ensureSessionStartupCatchup(),
so openclaw memory status reports dirty=false while unindexed session files
exist on disk. This is a false-clean state: the operator sees no backlog,
but memory search silently misses unindexed transcripts.

Fix: run markSessionStartupCatchupDirtyFiles() in status mode. It checks
for on-disk session files without corresponding memory_index_sources rows
and sets sessionsDirty=true if found, without triggering a full sync.

The full catchup+sync runs on the next non-transient manager cycle (CLI
sync or normal runtime init).

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(memory): await status dirty detection before status() reads the flag (fixes #97814)

The status-purpose MemoryIndexManager init skips ensureSessionStartupCatchup(),
so openclaw memory status reports dirty=false while unindexed session files
exist on disk. This is a false-clean state: the operator sees no backlog,
but memory search silently misses unindexed transcripts.

Fix: move status-mode markSessionStartupCatchupDirtyFiles() from the
constructor (fire-and-forget via void) into the create() factory method
where it is awaited. This guarantees sessionsDirty is set before any
caller reads manager.status(). The detection does NOT trigger a sync,
so status remains lightweight.

Review: verified manually — unit tests 21/21 pass, compilation 0 errors.

* test(memory): add regression test for status-purpose dirty detection (fixes #97814)

Adds a regression test that exercises the actual purpose:'status' manager
flow: create a session file without index row, create status manager, verify
status().dirty is true. This addresses the ClawSweeper P1 finding requesting
a test that exercises the real status path, not only the protected helper.

Also fixes the timing issue: move dirty detection from constructor (void)
to create() factory (await), guaranteeing sessionsDirty is set before any
caller reads manager.status().

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-30 17:47:43 -07:00
Vincent Koc
3e2646a786
fix(release): use workspace host deps in release lockfile
(cherry picked from commit d377c0f910)
2026-06-30 15:54:12 -07:00
Vincent Koc
66e676d29b
chore(release): close out 2026.6.11 on main 2026-06-30 11:31:08 -07:00
Agustin Rivera
29f787f10e
fix(memory): require privileged dreaming config changes (#97869)
* fix(memory): gate dreaming config changes

* fix(memory): document dreaming privilege gate

Explain that persistent dreaming toggles require channel owner status or Gateway admin scope, while status and help remain read-only.
2026-06-29 13:03:22 -07:00
Momo
db2488b6e3
fix(memory): record structured dreaming outcomes (#97723)
Summary:
- Merged fix(memory): record structured dreaming outcomes after ClawSweeper review.

Automerge notes:
- PR branch already contained follow-up commit before automerge: chore(plugin-sdk): update surface budgets

Validation:
- ClawSweeper review passed for head 9fa7d20a969ce579ad0a39582734300a4d5292bb.
- Required merge gates passed before the squash merge.

Prepared head SHA: 9fa7d20a969ce579ad0a39582734300a4d5292bb
Review: https://github.com/openclaw/openclaw/pull/97723#issuecomment-4831902831

Co-authored-by: momothemage <niuzhengnan@163.com>
Approved-by: momothemage
2026-06-29 11:23:38 +00:00
liuhao1024
6dccb61e56
fix(memory): align session file counter denominator with indexer filter (fixes #77338) 2026-06-28 19:14:27 -07:00
Brian Potter
cd31cbcd17
fix(memory-core): don't run the LLM reranker in vsearch/search modes (#88887)
vsearch/search are documented as vector/lexical-only modes, but
runQmdSearchViaMcporter omitted `rerank` from the query tool callArgs,
so QMD's query tool (which defaults rerank:true) ran the LLM reranker
anyway. Pass rerank:false for those modes; full "query" mode keeps it.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:11:03 -07:00
qingminlong
5e1f4c1073
fix(memory): stop light dreaming from restaging stale summaries (#97446)
* fix(memory): stop restaging stale light dreams

* fix(memory): preserve cross-day light freshness
2026-06-28 11:58:24 -07:00
Bek
9636bea901
perf(memory): add QMD search diagnostics and runtime cache (#96655) 2026-06-26 16:16:12 -04:00
Shakker
1cd6f81a46
fix: close memory test failure paths 2026-06-26 14:05:07 +01:00
Shakker
338e119533
fix: preserve watcher test state 2026-06-26 13:05:44 +01:00
Shakker
e4f63577d0
test: scope manager reindex state 2026-06-26 12:56:21 +01:00
Shakker
94d93d4c85
fix: retain qmd test environment state 2026-06-26 12:48:24 +01:00
Shakker
7718e25b2a
test: preserve memory startup env state 2026-06-26 12:40:55 +01:00
Shakker
8079aa62a2
fix: isolate memory index test state 2026-06-26 12:32:39 +01:00
Shakker
6f162f321a
test: scope narrative env cleanup 2026-06-26 12:23:32 +01:00
Shakker
c05d0d5bbf
fix: restore dreaming env after setup 2026-06-26 11:12:52 +01:00
Shakker
535af4452b
test: scope dreaming env batch one 2026-06-26 11:12:04 +01:00
Josh Lehman
da50a450d2
fix(memory-core): route dreaming corpus through session corpus metadata (#96517) 2026-06-24 11:29:26 -07:00
ly-wang19
bea3d292c7
fix(memory-core): keep short protected-glossary terms past the min-length gate (#96304)
PROTECTED_GLOSSARY exists to preserve short technical terms that generic
filtering would discard, but every glossary match still flowed through
normalizeConceptToken's per-script minimum-length gate. The 2-char latin
entries "kv" and "s3" were therefore never emitted as concept tags despite
being on the protect-list. Thread a fromGlossary flag so glossary matches
bypass only that length check; all other gates still apply.

Because that bypass lets short entries through, a bare substring match would
also surface them from inside longer words ("kv" in "mkv", "s3" in "css3").
Match ONLY the short entries (those below their script's min length) as
delimiter-bounded whole tokens; longer entries keep substring containment, so
the shipped behavior of "backup" tagging inside "backups" is preserved. CJK
entries (no word delimiters) always use substring matching. Positive
(standalone kv/s3) and negative (mkv/css3 substrings) regression tests cover
both directions, and the short-term-promotion stable-tags assertion gains "s3".

Co-authored-by: ly-wang19 <ly-wang19@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 21:32:58 +08:00
mushuiyu886
414c250af9
fix #95495: [Bug]: 2026.6.9 silently relocates memory store with no migration, forcing a full re-embed (1499 files) with zero upgrade-time warning (#95631)
* fix(memory): import legacy sidecar indexes into agent db

* fix(memory): move legacy sidecar import to doctor migration

* fix(memory): restore sidecar vector rows during doctor migration

* fix(memory): keep legacy sidecar when skipping import

* fix(memory): keep legacy sidecar import within extension boundary

* fix(memory-core): keep legacy sidecar migration retry-safe

* fix(memory-core): backfill sidecar FTS rows

* fix(memory-core): preserve sidecar when vector import defers

* fix(memory-core): cover custom sidecar migrations

* fix(memory-core): keep legacy config migration under doctor

* fix(memory-core): reject sidecar metadata conflicts

* fix(memory-core): keep partial legacy config sidecars

* fix(memory-core): preserve partial config retries

* fix(memory-core): keep partial config task migrations

* fix(memory-core): avoid phantom sidecar agents

* fix(memory-core): reject incomplete sidecar indexes

* fix(memory-core): keep malformed sidecars retryable

* fix(doctor): use canonical state dir for plugin migrations

* fix(memory-core): honor disabled vector sidecar migration

* fix(memory-core): treat provider-none sidecars as fts-only

* fix(memory-core): preserve setup-failed sidecars

* test(memory-core): use non-mutating sort assertions

* test(memory-core): compare sorted chunk ids

* test(memory-core): compare sorted chunk ids

* test(memory-core): stringify sorted chunk ids

* fix(qa): skip chromium bootstrap for explicit browser channels

* fix(qa): skip chromium bootstrap for explicit browser channels

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-06-24 17:47:44 +08:00
Vincent Koc
0671c08900
chore(release): close out 2026.6.10 on main (#96271)
* chore(release): close out 2026.6.10 on main

* chore(release): align native app metadata for 2026.6.10

* chore(release): sync Android 2026.6.10 notes

* docs(changelog): preserve 2026.6.9 history

* docs(changelog): preserve 2026.6.9 history
2026-06-24 11:51:14 +08:00
Josh Lehman
8a7b3c755a
fix(memory-core): migrate dreaming cleanup lifecycle (#96193)
* fix(memory-core): migrate dreaming cleanup lifecycle

* fix(sessions): resolve lifecycle session files explicitly

* fix(ci): refresh dreaming lifecycle proof ratchets
2026-06-23 16:08:44 -07:00
Peter Steinberger
73dd758310 fix(memory): abort orphaned qmd search processes 2026-06-23 13:31:46 -07:00