Skip to content

Memory domain scoping is half-implemented: all sessions collapse to project:default #584

@Aaronontheweb

Description

@Aaronontheweb

Observation

While fixing #582 I discovered that the concept of per-project memory domains is not actually in effect. Although DeterministicRetrievalRequestPlanner.ResolveHardScope parses a session ID prefix and returns a derived domain like `project:{prefix}`, that code path is dead — the coordinator calls `Protocol.SessionId.ToMemoryDomain()` to derive `HardScopeOverride` before the planner runs, and `ToMemoryDomain()` unconditionally returns `SecurityPolicyDefaults.DefaultMemoryDomain` ("project:default") regardless of the session ID.

Downstream, the planner sees `HardScopeOverride` set and returns it directly, so every real session resolves to `project:default`.

Why it matters

Three concrete consequences:

  1. Domain affinity scoring (+5 points for same-domain matches) is effectively a coin flip. It only fires when a memory happens to be seeded in `project:default`. Memories written to any other domain (e.g. `project:test` in unit tests, or any future per-project seeding) never get the boost. The ranking behavior this constant was designed to produce — "prefer memories from the current project over cross-project matches" — does not actually happen.
  2. There is no real per-project memory isolation. Every session shares the same domain namespace. Any memory formed by any session is visible to any other session, modulo the audience/boundary security filters. That may be intentional for single-user daemon deployments but is surprising given the amount of planner code that parses and normalizes "per-project" scoping.
  3. Unit tests that seed memories in custom domains don't exercise the production code path. During the Memory recall unconditionally injects top-N items with no score floor, polluting unrelated sessions #582 fix the scenario test suite seeded memories in `project:test` and saw zero domain affinity boosts, while the real production bug had memories in `project:default` and full affinity boosts — the test suite was silently measuring a different scoring regime than production.

Scope

This is not the #582 fix itself — that's already landing. But while closing #582 I'm disabling `DomainAffinityWeight` from scoring entirely because (a) the concept is incomplete and (b) it adds a +5 to in-domain single-lexical collisions that makes the floor unable to discriminate them from two-lexical cross-domain matches. See the #582 PR for the math.

Resolution options

Pick one:

  1. Implement domain scoping for real. Have `ToMemoryDomain()` actually parse session IDs (or channel metadata) into meaningful project domains, then restore `DomainAffinityWeight` as a ranking boost. This is a bigger change and needs product input on what "project" means in the Netclaw mental model.
  2. Remove the concept. Delete `DomainAffinityWeight`, delete the dead `ResolveHardScope` parsing in the planner, and document that Netclaw is a single-domain system. Cleaner code, matches actual behavior.
  3. Keep the current dead code path as a placeholder with a TODO pointing at a design doc. Worst of both worlds, but avoids breaking any latent assumptions if there's a plan to revive it.

Mentioning here for tracking; no immediate action needed from this issue unless someone has strong opinions about the direction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions