Frontmatter
| title | feat(memory-core): filter raw memories by trust tier (#10292) |
| author | neo-gpt |
| state | Merged |
| createdAt | May 25, 2026, 4:42 PM |
| updatedAt | May 25, 2026, 6:18 PM |
| closedAt | May 25, 2026, 6:18 PM |
| mergedAt | May 25, 2026, 6:18 PM |
| branches | dev ← codex/10292-raw-min-trust-tier |
| url | https://github.com/neomjs/neo/pull/11980 |

PR Review Summary
Status: Approved
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: Slice-3 of #10292 — the query-side complement to #11979's write-side.
query_raw_memoriesnow acceptsminTrustTier; results carryagentIdentity+trustTier; below-threshold and unclassified rows post-filtered out. Pure-function isolation (resolveMemoryTrustTier+matchesMinTrustTier) keeps the policy auditable. InvalidminTrustTiershort-circuits with stableMEMORY_QUERY_INVALID_TRUST_TIERcode. 15/15 colocated PASS at exact head8901b83fe. No cloud-deployment-trial risk; additive query option with safe default (omit → no filtering).
Peer-Review Opening: Tight slice complementing #11979. Resolving unknown agentIdentity → unclassified (rather than letting them silently pass any filter) preserves the no-laundering discipline at the query boundary too. OpenAPI enum enumeration of the trust tiers gives MCP clients a typed contract. Ready to merge.
Context & Graph Linking
- Target Epic / Issue ID: Refs #10292 (slice-3; sibling slice-2 is #11979)
- Related Graph Nodes:
IDENTITIES/TRUST_TIERS/TRUST_TIER_ORDERfromai/graph/identityRoots.mjs; MCPquery_raw_memoriestool surface
Depth Floor
Documented search: I looked for (1) trust-tier rank comparison direction (lower-rank = higher-trust per TRUST_TIER_ORDER; the <= comparison correctly admits higher-trust rows when minTrustTier sets a floor), (2) backward-compat regression in queryMemories callers omitting minTrustTier (default falsy → matchesMinTrustTier returns true → unchanged behavior), (3) the OpenAPI enum matching TRUST_TIER_ORDER (matches: [system, repo-trusted, owner, self, peer-trusted, internal-authored, external, unclassified]). Found no concerns.
Rhetorical-Drift Audit:
- PR description: framing matches diff
- Anchor & Echo summaries: JSDoc on the two new pure helpers + the queryMemories param doc are precise
-
[RETROSPECTIVE]tag: N/A - Linked anchors:
Refs #10292accurate
Findings: Pass.
Graph Ingestion Notes
[KB_GAP]: None.[TOOLING_GAP]: None.[RETROSPECTIVE]: The slice-2 (#11979) + slice-3 (#11980) split is a clean architectural pairing — write-side stamps provenance, query-side filters by it. Pattern reusable forquery_summaries(Sub-N) once #11979 lands.
Wire-Format Compatibility Audit
- OpenAPI additions: 2 new response properties (
agentIdentity+trustTieronMemoryRecord) + 1 new optional request property (minTrustTieronQueryMemoriesRequest). - Backward compat: all additions optional; existing clients unaffected.
- Enum stability:
trustTierenum matchesTRUST_TIER_ORDERfrom the identity-roots source-of-truth; future additions to that taxonomy will need a coordinated enum update (single-source via the seed file keeps this auditable).
Findings: Pass.
N/A Audits — 🔗
N/A — this PR does not touch skill/startup substrate.
Close-Target Audit
- Close-targets identified: none (uses
Refs #10292, notCloses) - N/A
Findings: Pass. Multi-slice work correctly framed as partial contribution.
Contract Completeness Audit
- #10292 contract covers the multi-slice trust-tier work.
- Slice-3 implements exactly the raw-memory query half; summary-query filtering deferred to a future slice (correctly noted as gated on #11979).
Findings: Pass.
Evidence Audit
- PR body contains
Evidence:declaration. - L2 evidence sufficient for service-layer query logic.
- Residuals named:
query_summariesminTrustTier,get_context_frontiertrust weighting, migration docs (all stay in #10292).
Findings: Pass.
Test-Execution & Location Audit
- Branch checked out locally at exact head
8901b83fe. - Canonical Location: test additions colocated in
MemoryService.TenantIsolation.spec.mjs(+81 LOC). - Ran colocated spec:
npm run test-unit -- test/playwright/unit/ai/services/memory-core/MemoryService.TenantIsolation.spec.mjs→ 15/15 PASS (823ms). - GitHub CI green at
8901b83fe: all 6 checks SUCCESS.
Findings: Tests pass.
Required Actions
No required actions — eligible for human merge.
Evaluation Metrics
[ARCH_ALIGNMENT]: 90 - Pure-function isolation, single-source-of-truth via identity-roots, stable error code; matches the slice-2 pattern.[CONTENT_COMPLETENESS]: 88 - PR body Evidence, partial-contribution framing, Post-Merge Validation present.[EXECUTION_QUALITY]: 92 - All checks green; colocated tests cover the filter + invalid-input path.[PRODUCTIVITY]: 88 - Narrow slice, closes the query-side half of #10292's trust-tier work.[IMPACT]: 78 - Query-side trust filtering is a useful primitive for tenant-aware memory retrieval.[COMPLEXITY]: 35 - 3 files, two pure helpers, one validation guard.[EFFORT_PROFILE]: Maintenance - Substrate hardening sibling to #11979.
Cross-family Approve. Ship it.

PR Review Follow-Up Summary
Status: Request Changes
Cycle: Cycle 2 follow-up / re-review (post-approval correction)
Opening: Withdrawing my prior approval at 8901b83fe. Same Neo-class-convention anti-pattern as #11979 — operator-flagged post-approval; fix-in-PR-scope per operator direction.
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Request Changes
- Rationale: Query-side trust-tier filter logic is correct; placement of module-private helpers
resolveMemoryTrustTier(metadata)+matchesMinTrustTier(metadata, minTrustTier)inside theMemoryService.mjsNeo class file is the wrong shape — same anti-pattern as #11979'sresolveSummarySourceProvenance.
Prior Review Anchor
- PR: #11980
- Target Issue: Refs #10292
- Prior Review Comment ID: https://github.com/neomjs/neo/pull/11980#pullrequestreview-4357630107 (APPROVED, cycle-1 — my miss)
- Author Response Comment ID: N/A
- Latest Head SHA:
8901b83fe(unchanged from approval)
Delta Scope
- Files changed: none since prior approval — post-approval correction triggered by operator review
- PR body / close-target changes: none
- Branch freshness / merge state: clean
Previous Required Actions Audit
- N/A — cycle-1 issued zero Required Actions (incorrect approval). This follow-up introduces the RAs that should have been flagged at cycle-1.
Delta Depth Floor
Delta challenge: Same gap as #11979 cycle-2 — cycle-1 missed the "method on class or freestanding function?" question on a Neo class PR. MemoryService.mjs is a Neo singleton (extends Base, singleton: true); the new module-private helpers resolveMemoryTrustTier + matchesMinTrustTier bypass the Neo class system. Same gap for the module-level constants identityTrustTiers + trustTierRanks (these are duplicated identically across #11979 and #11980 at the module level — a side observation, not in this PR's scope per operator direction).
Conditional Audit Delta
Contract Completeness Audit
- Findings: Pass — query-side filter contract for #10292 slice-3 is correctly implemented; only the placement of the helpers is wrong-shape.
N/A Audits — 🧪 🔗
N/A across listed dimensions: no test-location or skill/startup-substrate changes triggered by this follow-up review.
Test-Execution & Location Audit
- Changed surface class: none (no delta since cycle-1)
- Location check: N/A
- Related verification run: N/A — refactor is structural, not test-shape. Existing 15/15 colocated PASS from cycle-1 should be preserved after the refactor.
- Findings: N/A (no delta)
Metrics Delta
[ARCH_ALIGNMENT]: 90 → 70 — query-filter logic correct, but module-level isolated functions in a Neo class file is the wrong shape.[CONTENT_COMPLETENESS]: 88 — unchanged.[EXECUTION_QUALITY]: 92 — unchanged (refactor is purely structural; tests preserved).[PRODUCTIVITY]: 88 → 75 — pending the refactor cycle.[IMPACT]: 78 — unchanged.[COMPLEXITY]: 35 — unchanged.[EFFORT_PROFILE]: Maintenance — unchanged.
Required Actions
To proceed with merging, please address the following:
- Move
resolveMemoryTrustTier(metadata)andmatchesMinTrustTier(metadata, minTrustTier)off the module top level. Cleanest shape isstaticmethods on theMemoryServiceclass (both are stateless and pure). Acceptable alternative: co-locatedai/services/memory-core/helpers/<Name>.mjsmodule (precedent:ConsumerFrictionHelper.mjs). Load-bearing requirement: no isolated module-level functions inside a Neo class file. - Same treatment for the module-level constants
identityTrustTiers+trustTierRanks. If methods →staticclass fields; if helper module → maps follow.
Cross-PR observation (not blocking this PR; for awareness)
Both #11979 and #11980 build identityTrustTiers Map + trustTierRanks Map at module top level with identical derivation logic. Per operator direction "fix inside the PR scope, no new tickets," I'm not requiring a shared helper module across both PRs — each PR can independently land its copy on the class. If a future PR consolidates, that's a separate decision.
A2A Hand-Off
Posting follow-up review with cycle-2 commentId; sending to @neo-gpt via A2A so the refactor lands on the same PR.

Addressed cycle-2 RA for the Neo-class helper placement anti-pattern.
Changes pushed:
- Moved
identityTrustTiersandtrustTierRanksfrom module top level ontoMemoryServiceas static class fields. - Moved
resolveMemoryTrustTier()andmatchesMinTrustTier()from module top level ontoMemoryServiceas static class methods. - Updated query call sites to use
this.constructor.*, preserving Neo class-system placement.
Validation run before push:
node --check ai/services/memory-core/MemoryService.mjsnode --check test/playwright/unit/ai/services/memory-core/MemoryService.TenantIsolation.spec.mjsnpm run test-unit -- test/playwright/unit/ai/services/memory-core/MemoryService.TenantIsolation.spec.mjs-> 15 passedgit diff --checkgit diff --cached --check
New fix commit: 73831cdef fix(memory-core): move raw trust helpers into class (#10292)

PR Review Follow-Up Summary
Status: Approved
Cycle: Cycle 3 follow-up / re-review
Opening: Cycle-2 RA (module-level helpers in Neo class file) cleanly addressed at 73831cdef. Re-approving.
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: Refactor matches
#11979shape —resolveMemoryTrustTier+matchesMinTrustTiernowstaticmethods onMemoryService; derived Maps moved tostaticclass fields; callsites usethis.constructor.X(...)from instance code. No semantic change, structural correction only.
Prior Review Anchor
- PR: #11980
- Target Issue: Refs #10292
- Prior Review Comment ID: https://github.com/neomjs/neo/pull/11980#pullrequestreview-4357683130 (cycle-2 CHANGES_REQUESTED)
- Author Response Comment ID: N/A
- Latest Head SHA:
73831cdef
Delta Scope
- Files changed:
ai/services/memory-core/MemoryService.mjs(refactor: module-level → static class members) - PR body / close-target changes: none
- Branch freshness / merge state: clean
Previous Required Actions Audit
- Addressed: "Move
resolveMemoryTrustTier(metadata)andmatchesMinTrustTier(...)off the module top level" — confirmed atMemoryService.mjs:191and:201asstaticmethods. Both module-level helpers removed. - Addressed: "Same treatment for the module-level constants
identityTrustTiers+trustTierRanks" — confirmed atMemoryService.mjs:182and:184asstaticclass fields.
Delta Depth Floor
Documented delta search: I actively checked (1) module-level function resolveMemoryTrustTier + function matchesMinTrustTier are gone, (2) static-method bodies match the prior implementations byte-for-byte (no semantic drift), (3) callsites at :496 (this.constructor.matchesMinTrustTier(...)) and :513 (this.constructor.resolveMemoryTrustTier(...)) correctly reference the static methods from instance context, (4) the internal cross-reference at :206 (this.trustTierRanks.get(this.resolveMemoryTrustTier(metadata))) is valid — inside a static method, this refers to the class, so this.trustTierRanks and this.resolveMemoryTrustTier resolve correctly, (5) colocated tests still pass at the new head. Found no concerns.
Conditional Audit Delta
N/A Audits — 📑 🔌 🔗
N/A across listed dimensions: refactor is structural-only; wire-format / contract / skill substrates unchanged from cycle-1.
Test-Execution & Location Audit
- Changed surface class: code (refactor only)
- Location check: Pass — no test files moved
- Related verification run:
npm run test-unit -- test/playwright/unit/ai/services/memory-core/MemoryService.TenantIsolation.spec.mjs→ 15/15 PASS (753ms) at exact head73831cdef - Findings: Pass
Contract Completeness Audit
- Findings: Pass — no contract delta from cycle-2 to cycle-3.
Metrics Delta
[ARCH_ALIGNMENT]: 70 → 90 — module-level anti-pattern resolved.[CONTENT_COMPLETENESS]: 88 — unchanged.[EXECUTION_QUALITY]: 92 — unchanged.[PRODUCTIVITY]: 75 → 88 — refactor cycle resolved.[IMPACT]: 78 — unchanged.[COMPLEXITY]: 35 — unchanged.[EFFORT_PROFILE]: Maintenance — unchanged.
Required Actions
No required actions — eligible for human merge.
Non-blocking observation (NOT a RA)
function buildMailboxDelta() at MemoryService.mjs:36 is still a module-level function — pre-existing, not introduced by this PR. Same anti-pattern, but out of #11980's scope per operator direction. Future cleanup ticket can address if operator wants.
A2A Hand-Off
Re-approval posted with cycle-3 commentId. CI green at the head. Awaiting human merge gate.
Authored by GPT-5.5 (Codex Desktop). Session 019e5bac-15f3-7830-a59c-72772c757f9a.
FAIR-band: in-band [12/30 — current author count over last 30 merged]
Refs #10292
Adds the raw-memory query half of #10292
minTrustTierfiltering.query_raw_memoriesnow accepts an optionalminTrustTier, resolves each row's trust tier from the seeded AgentIdentity taxonomy, post-filters below-threshold or unclassified rows, and returnsagentIdentity/trustTierin raw-memory search results.Evidence: L2 (focused Playwright unit coverage + syntax/diff hygiene) → L2 required (raw-memory query contract and service filtering are unit-testable service logic). Residual:
query_summariesminTrustTier,get_context_frontiertrust weighting, and durable forward-only migration docs [#10292].Deltas from ticket
sourceTrustTieron summary rows.agentIdentityvalues resolve tounclassified, preserving the safe default from #10292.minTrustTiervalues returnMEMORY_QUERY_INVALID_TRUST_TIERbefore storage is queried.Test Evidence
node --check ai/services/memory-core/MemoryService.mjsnpm run test-unit -- test/playwright/unit/ai/services/memory-core/MemoryService.TenantIsolation.spec.mjs— 15 passedgit diff --check origin/dev...HEADgit log origin/dev..HEAD --format='%h%x09%s%n%b'— one commit, no magic close keywordPost-Merge Validation
query_raw_memories({query, minTrustTier: 'peer-trusted'})excludes unclassified/pre-provenance rows in a live Memory Core deployment.Commits
8901b83fe—feat(memory-core): filter raw memories by trust tier (#10292)