Skip to content

[BUG] Dashboard New Memory sends metadata.primary_sector, backend only reads metadata.sector, so the chosen sector is discarded #193

Description

@graysoncooper

What happened?

The New Memory dialog in the dashboard has a required Primary Sector select (semantic, episodic, procedural, emotional, reflective). Picking a value there has no effect. The memory is saved with whatever sector the keyword classifier picks, which for most content is semantic.

The cause is a key mismatch between the dashboard and the server.

The dashboard posts the choice under metadata.primary_sector:

async function handleAddMemory(content: string, sector: string, tags: string, scope: 'project' | 'global') {
try {
const res = await fetch(`${API_BASE_URL}/memory/add`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({
content,
tags: tags.split(',').map((t) => t.trim()).filter(Boolean),
metadata: { primary_sector: sector },
// Explicitly set project_id based on user selected scope
project_id: scope === 'project' ? currentProject : 'system_global'

/memory/add validates metadata as a generic object and forwards it unchanged to add_hsg_memory, which calls classify_content(content, metadata). classify_content reads only metadata.sector:

export function classify_content(
content: string,
metadata?: any,
): sector_class {
if (metadata?.sector && sectors.includes(metadata.sector)) {

metadata.primary_sector is never read as a request-side override anywhere in the tree. Every other occurrence of primary_sector is the stored column or a response field. The Python backend has the same contract: openmemory-py/src/openmemory/memory/hsg.py also reads metadata['sector'].

The write returns success, so nothing signals that the selection was dropped. The list view then renders the stored column back, which is why the card shows a sector the user did not choose.

Expected: the sector selected in the dialog is the sector the memory is stored under.

Steps to Reproduce

  1. Start the backend and open the dashboard at /memories.
  2. Click New Memory.
  3. Enter content that does not match a procedural keyword pattern, for example Prefer dark mode in the editor.
  4. Set Primary Sector to procedural.
  5. Save. The request succeeds.
  6. Look at the new card in the list, or GET /memory/list. Its sector reads semantic, not procedural.

Component

Frontend (React/UI)

Why it matters beyond the label

The stored sector is not cosmetic. It drives:

  • sector counts and filtering on the memories page, and GET /memory/list?sector=
  • procedural-only retrieval in the IDE route (routes/ide.ts filters primary_sector === 'procedural')
  • per-sector decay, since sector_configs.decay_lambda is keyed on the sector

So a memory filed under the wrong sector decays at the wrong rate and is missed by sector-scoped retrieval.

Suggested fix

The backend override already exists and works; only the client key is wrong. In handleAddMemory, send:

metadata: { sector },

Alternatively, accept both keys in classify_content if primary_sector should stay a valid input for compatibility with anything already posting it.

Attribution

The flagged line entered main in PR #143, which restored the dashboard sources that PR #138 merged without. The hsg.ts side is pre-existing and untouched.

Code of Conduct

  • I agree to follow this project's Code of Conduct

Automated report: this issue was produced and filed automatically, with no human review before posting. Two independent checks agreed it is a real bug, but if it misreads the code please say so and we will close it.

Found while running Ito (AI code review that runs your application, free for open source) against recently merged PRs. Full analysis.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions