Skip to content

import: metadata dropped by the allow-list or a validator is dropped silently #367

Description

@kevintseng

What happens

memesh import (CLI, the MCP import tool and POST /v1/import all call importMemories()) merges a bundle's metadata through an allow-list (#359). A key that is not on the list, and a value that fails one of the four validators (forgotten_observation_hashes, pin, signal_score, replaced_history), is dropped. Nothing says so: ImportResult has no field for it, nothing reaches errors, the CLI prints Imported: N, Skipped: 0, Appended: 0 and exits 0.

Dropping is the right decision. Dropping without saying so is the defect.

Reproduced with the built CLI against a throwaway HOME/MEMESH_DIR:

  • a bundle carrying guard, demo, task_state, consolidation_depth, compacted_into, proposal_id, session_id, evidence_for and one ordinary unknown key → Imported: 1, exit 0, all nine gone;
  • ten entities, nine with one invalid value each (signal_score: 5, pin: "true", one malformed hash, 1001 hashes, an extra key in a replaced_history entry, 51 entries, a 300 KiB entry) → Imported: 10, exit 0, each field dropped whole.

The sharp case is forgotten_observation_hashes: it is what lets a user's own backup carry its own exclusions to a new machine. One corrupted element drops the whole list, and every observation the user had removed with forget can come back from a later Stop snapshot — with a successful-looking import.

Before #359 the only dropped key was guard, equally silently; #359 widened the set from one name to "everything not on the list".

The source-scan test (tests/core/import-metadata-classification.test.ts) guards keys written by THIS source tree. It cannot see a key that arrives in a bundle from a newer or older build.

Suggested direction

  • Add dropped_metadata: { entity: string; key: string; reason: 'not_importable' | 'invalid' | 'existing_entity' }[] (or a per-key count) to ImportResult.
  • CLI: print it to stderr next to the existing skipped_relations line; MCP/HTTP: return it.
  • Document it in docs/api/API_REFERENCE.md; tests for each reason.

Related, same area

  1. ExportResultSchema is the one deliberately non-strict object, so the MCP tool and the HTTP route strip an entity's metadata, created_at and status before importMemories() sees them. The API reference now says so for metadata; created_at and status are lost the same way and are not mentioned. A restore through MCP/HTTP silently loses creation time and archived state.
  2. scripts/lib/npm-latest-guard.mjs decides confirmed = seen === pkgVersion. A failed read is null; if pkgVersion were ever null too, absence would equal absence and the release would be reported confirmed with exit 0. Carried over unchanged from the pre-4.10.1 review follow-ups: four fixes before promoting to latest #359 script and very likely unreachable (earlier preconditions would stop a null version), but it is one line to fail closed: require typeof pkgVersion === 'string' && pkgVersion before comparing.
  3. tests/core/import-metadata-classification.test.ts scans src/, scripts/hooks/ and dashboard/src/ for metadata keys. scripts/audit/ is not a scan root, and scripts/audit/memory-invariants.mjs reads metadata.split_from — a key the allow-list admits on the grounds that its only reader is a one-shot, marker-guarded migration. The invariant only reports, so the impact is small, but the guard has a blind directory. Add scripts/audit (and check scripts/ more widely) to the scan roots and re-run the scrape.
  4. pin: true is accepted on every entity an import creates, with no bound at bundle scale (20,000 of 20,000 measured), which exempts all of them from consolidation permanently. The other three validated exceptions are bounded. Decide whether a per-import cap, or a line in the import result, is wanted.
  5. scripts/finish-release.mjs fails closed on a non-integer exit code only. A multiple of 256 would become 0 through process.exit() on POSIX. Not reachable today (runPostPublishFlow returns 0 or 1); restrict to 0 | 1 to keep it that way.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    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