Skip to content

fix(memory): team-scoped memories were never stored — null agent_id threw a swallowed TypeError - #139

Merged
escapeboy merged 1 commit into
developfrom
fix/memory-null-agent-id
Aug 4, 2026
Merged

fix(memory): team-scoped memories were never stored — null agent_id threw a swallowed TypeError#139
escapeboy merged 1 commit into
developfrom
fix/memory-null-agent-id

Conversation

@escapeboy

Copy link
Copy Markdown
Owner

The bug

StoreMemoryAction::execute() advertises ?string $agentId, but storeChunk() and every write-gate helper below it declared a non-nullable string. Any team-scoped write throws:

StoreMemoryAction::storeChunk(): Argument #2 ($agentId) must be of type string,
null given, called in .../StoreMemoryAction.php on line 88

execute() wraps the chunk loop in try/catch and logs that at WARNING, so it never surfaced anywhere: the job reports success, the distillation watermark advances past the events, and nothing is stored. Silent, permanent data loss for every team-level memory.

DistillTeamEventsAction passes agentId: null explicitly, so the nightly digest has never worked.

Reproduced on production

memories total: 0            # zero rows, ever

A live distil run for a real team:

{"team_id":"019cb001…","events":61,"stored":0,"window_start":"2026-08-03T09:09:20+00:00"}
memories before=0  after=0

…while the model had produced a perfectly good 625-character digest, and the gateway, embeddings and config were all healthy. Calling StoreMemoryAction::execute(agentId: null) directly reproduced the exact TypeError above in the swallowed warning.

Fix

Widen $agentId to ?string through storeChunk, evaluateWriteGate, handleUpdate, handleAdd, mergeContent.

The where('agent_id', $agentId) lookups need no change — Laravel's where() maps a null value to whereNull.

How it was found

By validating the failed_jobs backlog rather than accepting that the recent silence meant the failures were fixed. The nightly DistillTeamEventsJob failures stopped on 2026-07-29 — two days before the fix that supposedly addressed them (#131, 2026-08-01), so that fix could not be the reason. Chasing the real reason led here.

Worth noting: #131 made the symptom quiet by catching AiAccessUnavailableException and advancing the watermark. This PR fixes the case where there is no exception to catch at all.

Verification

  • 196 tests pass across Unit/Domain/Memory + Feature/Domain/Memory
  • Regression test asserts all five signatures accept a null $agentId
  • pint clean; phpstan reports zero errors in the touched files (the 73 in that path are pre-existing — identical count with the change stashed)

…hrew a swallowed TypeError

`StoreMemoryAction::execute()` advertises `?string $agentId`, but storeChunk()
and every write-gate helper below it declared a non-nullable `string`. Any
team-scoped write — DistillTeamEventsAction passes `agentId: null` explicitly —
threw:

  StoreMemoryAction::storeChunk(): Argument #2 ($agentId) must be of type
  string, null given, called in .../StoreMemoryAction.php on line 88

execute() wraps the loop in try/catch and logs that at WARNING, so the failure
never surfaced: the job "succeeded", the distillation watermark advanced past
the events, and nothing was stored. Reproduced on production — `memories` holds
0 rows, and a live distil run returned 61 events in / 0 stored while the model
had produced a valid 625-char digest.

Widen $agentId to ?string through storeChunk, evaluateWriteGate, handleUpdate,
handleAdd and mergeContent. The `where('agent_id', $agentId)` lookups need no
change: Laravel's where() maps a null value to `whereNull`.

Found by validating the failed_jobs backlog instead of assuming the recent
silence meant the failures were fixed.
@escapeboy
escapeboy merged commit e52bed2 into develop Aug 4, 2026
3 checks passed
@escapeboy
escapeboy deleted the fix/memory-null-agent-id branch August 4, 2026 09:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant