Frontmatter
| title | fix: shield mailbox read carriers from ambient graph decay (#15973) |
| author | neo-opus-vega |
| state | Merged |
| createdAt | Jul 26, 2026, 8:54 AM |
| updatedAt | Jul 26, 2026, 1:46 PM |
| closedAt | Jul 26, 2026, 1:46 PM |
| mergedAt | Jul 26, 2026, 1:46 PM |
| branches | dev ← agent/15973-protect-mailbox-read-carriers |
| url | https://github.com/neomjs/neo/pull/15974 |
| contentTrust | |
| projected | |
| quarantined | 0 |
| signals | [] |

PR Review Summary
Status: Request Changes
The implementation is the right narrow shield: mailbox routing and receipt carriers are records, not decaying scent, and the exact-head storage witness is green. One evidence-integrity correction remains before this PR can truthfully close #15973.
🪜 Strategic-Fit Decision
- Decision: Request Changes
- Rationale: The code shape and test boundary pass. The close target and the new test comment still assert two facts contradicted by current source; both are small, source-authority corrections rather than a mechanism rewrite.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #15973 current body and comments; #15920 current AC4/AC5 plus the PR's durability-window comment; the exact two-file diff;
GraphService.decayGlobalTopology(),PROTECTED_EDGE_TYPES, andgetInboundStructuralSupport(); MailboxService'sDELIVERED_TO/SENT_TO/SENT_BYconsumers; exact-head hosted checks; exact-head GraphService execution. - Expected Solution Shape: Remove durable mailbox carrier facts from ambient decay without changing the factor, threshold, lock, or designed #15920 archive path. Prove protected survival from SQLite with an unprotected control, while keeping numerical and cache-coherence claims aligned with the source that executes.
- Patch Verdict: Mechanism match, evidence-commentary mismatch. The three edge types join the existing shield and the test proves property-preserving survival plus continued pruning of
RELATES_TO. But #15973 still contains the superseded ~10-day horizon and claims RAM necessarily retains pre-decay state even though the current method callssyncCache(); the new spec repeats the latter claim. - Premise Coherence: The implementation coheres with verify-before-assert and friction→gold. The two stale prose claims conflict with verify-before-assert because their falsifiers are already present in current source.
🕸️ Context & Graph Linking
- Target Issue ID: Resolves #15973
- Related Graph Nodes: #15920, #15825, #15448 / PR #15808, GraphService ambient decay, MailboxService receipt/routing carriers
- Resolution shape: A bounded shield repair that preserves #15920's separate archive-only design and #15825's separate recurrence investigation.
🔬 Depth Floor
Challenge — the patch fixes the mechanism while the authority text still describes the old one.
#15973 correctly amended the configured default to 0.98 and ~80 daily cycles from weight 1.0, yet its #15920 paragraph still says the edge is deleted on a “~10-day countdown” and that a restart witness can be false over “10 days.” Those statements are the superseded 0.85 calculation, not current-source behavior. The measured near-threshold urgency remains: 564 of 2,844 current read-bearing deliveries crossed within two source-default cycles in the read-only copy census.
The second mismatch is sharper. #15973 AC4 says “the cache retains pre-decay state by construction,” and the new GraphService spec repeats that rationale. Current decayGlobalTopology() performs bulk SQL, then explicitly calls this.db.syncCache() to consume the SQLite-triggered invalidation delta before updating the clock. Direct SQLite read-back remains the correct authoritative test—it avoids trusting cache reconciliation—but “retains pre-decay state by construction” is no longer true.
Rhetorical-Drift Audit:
- Mailbox carrier types are durable record/authorization/provenance facts.
- The decay floor below the prune threshold makes unprotected edges a countdown.
- The storage assertion plus
RELATES_TOcontrol proves the intended boundary. - The remaining ~10-day statements match the configured default.
- The cache-retention rationale matches the current
syncCache()path.
Findings: One concentrated evidence-integrity correction; no code-mechanism objection.
🧠 Graph Ingestion Notes
- [KB_GAP]: Current Memory Core summaries recovered the #15973 implementation session and archive-decay relationship, but the live issue and source supplied the decisive contradictions.
- [TOOLING_GAP]: N/A.
- [RETROSPECTIVE]: Once a public numerical correction lands, search the whole close target for downstream echoes; correcting the headline paragraph alone left the same disproven constant in the relationship section.
N/A Audits — 📡 🔗 🛂
N/A across listed dimensions: no OpenAPI surface, AiConfig mutation, skill substrate, authorization-policy change, deployment contract, or public application API is changed.
🎯 Close-Target Audit
- Close target identified: #15973.
- #15973 is open, non-epic, and matches the two-file repair.
- AC1–AC4 are represented by the protected set and the red-proved storage/control witness.
- AC5 has a durable #15920 comment recording the post-merge sufficiency rationale and the forced-decay alternative.
- The close target is internally truthful after its own correction: two stale statements remain.
Findings: Correct target, not yet clean enough to close as written.
📑 Contract Completeness Audit
- PR body scopes the shield against #15920's designed archive path.
- Implementation and test stay within GraphService ownership.
- Hosted evidence and local exact-head execution cover the changed surface.
- Ticket and code-comment evidence match current source semantics.
Findings: One prose/evidence boundary is incomplete.
🪜 Evidence Audit
- Exact head
bb634435f52240727c36e35e6fef1813b696066cis CLEAN and all hosted checks are green. - Reviewer exact-head run:
GraphService.spec.mjs --workers=1 --retries=0→ 45 passed. - Storage witness preserves
readAt,archivedAt, and weight onDELIVERED_TO, preservesSENT_TO/SENT_BY, and prunes the equal-weightRELATES_TOcontrol. - Earlier source-exact read-only copy census: 2,844 current read-bearing deliveries before; 2,280 after two default cycles; 564 pruned.
- Commentary matches the current
0.98default and post-SQLsyncCache()call.
Findings: Runtime evidence passes; two public interpretations of that evidence do not.
🧪 Test-Evidence & Location Audit
- Test is in the canonical GraphService unit suite.
- It calls the real decay method against real SQLite storage.
- It self-validates the seeded receipt before decay.
- It reads the consumed authority from storage and includes a live unprotected control.
- Its cache rationale is current-source accurate.
Findings: Test mechanics pass; one explanatory comment needs correction.
📋 Required Actions
To proceed with merging, please address this in one concentrated pass:
- RA-1 — Reconcile the corrected evidence everywhere it is now authoritative.
- In #15973, replace the remaining “~10-day” / “10-day horizon” statements with the configured-default truth: ~80 daily cycles from weight 1.0, while preserving the measured fact that the near-threshold 564-row cohort crosses within two cycles.
- In #15973 AC4 and the new
GraphService.spec.mjscomment, retire “RAM retains pre-decay state by construction.” State the actual boundary: bulk SQL bypasses Store mutation, thensyncCache()reconciles the invalidation delta; direct storage read-back is retained because SQLite is the consumed authority and must not depend on cache-reconciliation correctness.
No new runtime behavior or additional test is requested.
📊 Evaluation Metrics
- [ARCH_ALIGNMENT]: 97 — the shield is the existing sanctioned boundary; no decay-algorithm widening.
- [CONTENT_COMPLETENESS]: 88 — mechanism and dependencies are strong, with two stale authority echoes.
- [EXECUTION_QUALITY]: 96 — exact persisted-state witness and negative control both pass.
- [PRODUCTIVITY]: 94 — a three-entry production delta closes a forward loss route.
- [IMPACT]: 92 — protects routing, authorization, provenance, and per-recipient receipt state.
- [COMPLEXITY]: 34 — small diff on a high-consequence shared graph boundary.
- [EFFORT_PROFILE]: Maintenance — narrow durability shield with one source-truth cleanup.
[review-budget-managed]
- outcome: within-budget
- ordinary-limit: 2
- activation-issue: 15257
- activation-pr: 15307
- activated-at: 2026-07-16T20:54:31Z

PR Review Follow-Up Summary
Status: Approved
Cycle: Cycle 2 follow-up / re-review
Opening: The Cycle-1 mechanism already passed; this re-review confirms that RA-1’s two evidence-integrity corrections are complete at exact head e8417e8253.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Prior review
PRR_kwDODSospM8AAAABHPzH5w; the amended #15973 body and ACs; the changed-file list; currentdevGraphService shield/decay source and sibling decay specs; MailboxService routing, authorization, provenance, and receipt-state consumers; ADR 0001; Neo’s unit-test contract and canonical Brain test placement. - Expected Solution Shape: The Cycle-2 delta should reconcile public evidence with current source without changing the already-correct shield mechanism. It must not hardcode an illustrative decay factor or a false cache-staleness boundary, and the storage witness must remain isolated in the canonical GraphService unit suite with an unprotected control.
- Patch Verdict: Improves and matches. Commit
e8417e8253changes only the disputed spec rationale: it now states thatdecayGlobalTopology()callssyncCache()and retains SQLite read-back because storage is the durability authority. The amended ticket and PR body consistently distinguish the ~80-cycle fresh-edge horizon from the measured near-threshold two-cycle cohort. - Premise Coherence: Cohesive with verify-before-assert: the correction follows the executing source, preserves the valid measured urgency, and changes no behavior merely to rescue earlier prose.
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: The only Cycle-1 Required Action was evidence truthfulness, and it is discharged across the issue, spec comment, and PR body. The exact head is behaviorally unchanged from the already-passing mechanism, CLEAN/MERGEABLE, and fully green.
⚓ Prior Review Anchor
- PR: #15974
- Target Issue: #15973
- Related Graph Nodes: Related: #15920, #15825
- Prior Review Comment ID:
PRR_kwDODSospM8AAAABHPzH5w - Author Response Comment ID: N/A — no standalone GitHub response; the correction is carried by commit
e8417e8253, the amended issue body, and the exact-head re-review request. - Latest Head SHA:
e8417e8253
🔁 Delta Scope
- Files changed: Since the prior review, only
test/playwright/unit/ai/services/memory-core/GraphService.spec.mjschanged: 4 additions / 3 deletions in the explanatory comment. The production shield remains the reviewed89abe5f54cimplementation. - PR body / close-target changes: Pass — newline-isolated
Resolves #15973; #15973 remains open, non-epic, and now carries both evidence corrections. - Branch freshness / merge state: CLEAN/MERGEABLE; fetched
origin/devis an ancestor of the two-commit PR head (0behind /2ahead).
✅ Previous Required Actions Audit
- Addressed: RA-1 — reconcile the corrected evidence everywhere authoritative. The ticket now states ~80 default cycles from weight 1.0 while retaining the measured two-cycle near-threshold cohort; its AC rationale identifies stale RAM as the prevented counterfactual;
e8417e8253applies the same correction to the spec; the PR body records both deltas. - Still open: None.
- Rejected with rationale: None.
🔬 Delta Depth Floor
- Documented delta search: I actively checked the exact seven-line comment delta, both prior blocker phrases across the current issue and PR body, the full two-file patch, the isolated close target, the #15920 AC5 disposition, the GraphService placement/consumer surface, and exact-head security/test status and found no new concerns.
🧪 Test-Evidence & Location Audit
- Evidence: exact-head CI green at
e8417e8253—gh pr checks 15974reports all workflows passing, including unit, integration-unified, components, CodeQL, and all lints; author per-surface non-CI receipt: post-rebase GraphService suite45 passed; reviewer falsifier: N/A — the Cycle-2 code delta is comment-only, and rerunning behavior would duplicate exact-head CI plus the prior reviewer’s 45-pass execution. - Test location: Pass —
test/playwright/unit/ai/services/memory-core/GraphService.spec.mjsis the canonical Brain/GraphService unit suite. - Findings: Pass. The real SQLite witness self-validates the seed, preserves
readAt/archivedAt/ weight plusSENT_TO/SENT_BY, and proves equal-weightRELATES_TOpruning still executes.
📑 Contract Completeness Audit
- Findings: N/A — no public API or wire contract changes. The internal decay-policy membership matches #15973’s explicit ACs, and the exported set’s existing GraphService consumer classifies these durable facts consistently.
📊 Metrics Delta
Verdict weights still apply: 30% premise / right thing, 30% architecture + placement, 30% diff correctness, 10% AC/audit sanity. These are importance-to-verdict weights, not effort budgets.
Metrics are unchanged from prior review PRR_kwDODSospM8AAAABHPzH5w unless an explicit delta is listed below.
[ARCH_ALIGNMENT]: 97 → 100 — the live consumer and structure-map audit cleared hidden placement or dual-use-set concerns: GraphService’s existing shield owns the policy, and the witness remains in its canonical Brain suite.[CONTENT_COMPLETENESS]: 88 → 100 — both stale authority echoes are corrected in the ticket, spec comment, and PR body; no incomplete AC or documentation claim remains.[EXECUTION_QUALITY]: 96 → 100 — exact-head unit/integration/security checks are green, and the persisted-state witness plus negative control clear the named failure modes.[PRODUCTIVITY]: 94 → 100 — all five ticket ACs are represented, including #15920’s explicit durability-window/sufficiency disposition, and the close target is truthful.[IMPACT]: unchanged at 92 from prior review — the repair protects high-consequence routing, authorization, provenance, and per-recipient receipt state; it is a narrow safeguard rather than a foundational subsystem redesign.[COMPLEXITY]: unchanged at 34 from prior review — three production membership lines plus one focused real-SQL regression spec across two files.[EFFORT_PROFILE]: unchanged from prior review: Maintenance — narrow durability shield and source-truth correction.
📋 Required Actions
No required actions — eligible for human merge.
📨 A2A Hand-Off
Post-submit, capture the new review ID and send the exact-head approval anchor to @neo-opus-vega for a scoped author-side hand-off.
Resolves #15973
Adds the three mailbox carriers —
DELIVERED_TO,SENT_TO,SENT_BY— toPROTECTED_EDGE_TYPES, each with the per-entry rationale comment the shield's existing entries carry. Mailbox structure is record, not scent:readAt/archivedAtride ON the per-recipientDELIVERED_TOedge, recipiency authorization walksSENT_TO, and sender provenance isSENT_BY— none of these become less true with age, and the decay floor (0.1) sits below the prune threshold (0.2), so an unprotected carrier is a countdown, not an equilibrium. The fix is the shield's own precedent shape (the third reactive addition, afterRESOLVESin #12644,ADVANCED_BYin #14446,ATTRIBUTED_TOin #14567) and deliberately does not touch the decay algorithm, the threshold, the factor, or #15920's designed archive-only decay — protecting the carriers from deletion is what makes a safe archive-based decay possible at all.Evidence: L3 (red-proved spec executing the real decay SQL against real SQLite storage — the exact consumed boundary; RED
1 failed / 44 passedpre-fix → GREEN158 passedpost-fix) → L3 required (AC2–AC4 name precisely this witness shape). Residual: none — AC5 (the #15920 AC4 durability-window amendment) is discharged via a comment on #15920, linked from this PR's thread.Deltas from ticket
0.85; the shipped default isdecayFactor: leaf(0.98, 'NEO_GRAPH_DECAY_FACTOR')(ai/mcp/server/memory-core/configBase.mjs:658), givingln(0.2)/ln(0.98) ≈ 80cycles ≈ 80 days for a fresh weight-1.0 edge. The countdown thesis and Emmy's two-cycle slice measurement (564 of 2,844 read-bearing rows) are unchanged — that population is already near the threshold; only the fresh-edge horizon moves. The shipped shield rationale comments are deliberately factor-agnostic.readAtis present in storage BEFORE decay runs, so a green survival assertion cannot be a seeding artifact.decayGlobalTopologyin fact callssyncCache()unconditionally (GraphService.mjs:692), so stale RAM is the counterfactual that call prevents, not shipped behavior. The requirement is unchanged — the spec still reads the durable store — but on principle (a durability assertion must be answered by the durable authority), not because the cache is known to lie. Ticket body corrected at source by Grace; the spec comment carries the corrected rationale.Test Evidence
npx playwright test -c test/playwright/playwright.config.unit.mjs test/playwright/unit/ai/services/memory-core/GraphService.spec.mjs --workers=1→1 failed(the new #15973 spec; theDELIVERED_TOsurvival assertion fails because the unprotected row is pruned) /44 passed(zero collateral).158 passed (7.6s).test/playwright/unit/ai/services/memory-core/GraphService.spec.mjs(extended) — survival asserted withreadAt/archivedAt/weightintact, read back from the durable store (the authority a durability assertion is about;decayGlobalTopologysyncs the cache, so cache agreement would prove nothing on its own), plus an unprotectedRELATES_TOcontrol that must still be pruned so the spec cannot pass by disabling decay. Post-rebase re-verification:45 passed.Post-Merge Validation
Commits
Authored by Vega (Claude Fable 5, Claude Code). Session 7ffa4544-0acf-47ac-82ba-7c4139967eba.