Observed behavior
POST /v1/memories with a direct-content body (no messages array) hardcodes MemoryType::Pinned as the default when the caller doesn't specify memory_type. After #10, callers can pass memory_type explicitly — but the default still silently pins.
// omem-server/src/api/handlers/memory.rs (after #10)
let memory_type = match body.memory_type {
Some(s) => s.parse().map_err(OmemError::Validation)?,
None => MemoryType::Pinned, // <— this default
};
Why I think this is wrong
Pinned carries a specific behavior: stage_rrf_fusion applies a 1.5× pinned_boost multiplier. The boost only does what it's named for if Pinned is reserved for a curated few — when everything is pinned, the boost applies uniformly to the whole corpus and is effectively a no-op for relative ordering.
The default contradicts the semantic intent of the variant.
How I noticed
I migrated ~170 memories into my instance via the API (just POST /v1/memories with {"content": "..."}) and ended up with 170/170 memory_type: pinned. The retrieval misbehavior I reported in #7 was meaningfully driven by this — the "irrelevant top still scores 1.0" symptom from that issue's body had two causes, and "every memory is pinned" was a bigger driver than the normalization choice fixed in #9.
There's no way for an integrator to know they should pass memory_type=insight unless they read the handler source. The shape of CreateMemoryBody before #10 didn't even surface the field; the default was invisible.
Proposed change
Flip the default to Insight:
let memory_type = match body.memory_type {
Some(s) => s.parse().map_err(OmemError::Validation)?,
None => MemoryType::Insight,
};
One line. Existing data untouched. Callers who actually want pinning pass it explicitly.
Compat impact
- Existing callers using direct-content create: newly-created memories would no longer be boosted in search ranking. They could opt back in with
memory_type=pinned.
- Existing pinned data: untouched. Stays pinned.
- Message-mode ingestion path (
messages: [...]): unaffected. That path goes through IngestPipeline and sets types differently.
Alternative considered: keep Pinned, document the implication
Document loudly in the handler docstring and README that the default is Pinned and that callers doing bulk creation should override it. Cheaper change; relies on integrators reading docs.
I lean toward flipping the default because the principle of least surprise points that way — "what does the API give me by default" should be the normal, unboosted variant, with elevation as an explicit opt-in. But happy to write up the docs path instead if you'd rather minimize behavior change.
Happy to PR whichever direction you pick.
Observed behavior
POST /v1/memorieswith a direct-content body (nomessagesarray) hardcodesMemoryType::Pinnedas the default when the caller doesn't specifymemory_type. After #10, callers can passmemory_typeexplicitly — but the default still silently pins.Why I think this is wrong
Pinnedcarries a specific behavior:stage_rrf_fusionapplies a1.5×pinned_boostmultiplier. The boost only does what it's named for ifPinnedis reserved for a curated few — when everything is pinned, the boost applies uniformly to the whole corpus and is effectively a no-op for relative ordering.The default contradicts the semantic intent of the variant.
How I noticed
I migrated ~170 memories into my instance via the API (just
POST /v1/memorieswith{"content": "..."}) and ended up with 170/170memory_type: pinned. The retrieval misbehavior I reported in #7 was meaningfully driven by this — the "irrelevant top still scores 1.0" symptom from that issue's body had two causes, and "every memory is pinned" was a bigger driver than the normalization choice fixed in #9.There's no way for an integrator to know they should pass
memory_type=insightunless they read the handler source. The shape ofCreateMemoryBodybefore #10 didn't even surface the field; the default was invisible.Proposed change
Flip the default to
Insight:One line. Existing data untouched. Callers who actually want pinning pass it explicitly.
Compat impact
memory_type=pinned.messages: [...]): unaffected. That path goes throughIngestPipelineand sets types differently.Alternative considered: keep
Pinned, document the implicationDocument loudly in the handler docstring and README that the default is
Pinnedand that callers doing bulk creation should override it. Cheaper change; relies on integrators reading docs.I lean toward flipping the default because the principle of least surprise points that way — "what does the API give me by default" should be the normal, unboosted variant, with elevation as an explicit opt-in. But happy to write up the docs path instead if you'd rather minimize behavior change.
Happy to PR whichever direction you pick.