accesspatterns.dev

Two read paths, one item

The same items answer "what happened last" and "what is relevant", through two different reads.

Why

An assistant needs two different things from its history. It needs the last few messages, in order, every single turn. And occasionally it needs the one thing the user said three weeks ago that bears on what they just asked. Those are different questions, and they want different reads.

The first is a Query on the session partition, read backwards with a Limit. It is the cheapest read in the course: the key decides what to read, nothing is scanned and thrown away, and the order is exact.

The second is a vector search, and the decision that makes it work is what the index is partitioned by. The SearchSchema here declares userId as its HASH, not sessionId. Partition by session and relevance can only ever reach inside the conversation you are already in, which is the one place recency has already covered. Partition by user and it reaches across every conversation they have ever had. That is the entire reason for keeping this in DynamoDB beside the items rather than in a separate vector database.

There is no join and no synchronisation between the two. The index is maintained as part of the base write, so a message is searchable the moment it is written. Merging the two result sets is your application's job, and there is no ranking that combines a sort order with a similarity score for you. That is a judgement about your product, and DynamoDB is right not to guess at it.

A vector index is a second read path over the same items; partition it by the axis relevance needs to cross, which is usually not the one recency already covers.

AgentMemory

These rows are real and already here. Running an operation against them downloads a DynamoDB-compatible engine, about 850 KB, and executes it in this tab.

Try an example

The recency window: one session's partition, read backwards, capped at six. Cheap, exactly ordered, and completely blind to anything said in an earlier session.

pk(pk)
sk(sk)
userId
text
embedding
SESSION#s-101
TS#2026-07-31T00:00:00ZS
u-adaS
We should roll the API out to Kubernetes rather than the old VM fleetS
[-0.0109, 0.033, 0.0473, … 384]L
SESSION#s-101
TS#2026-07-31T00:15:00ZS
u-adaS
The rollout needs a readiness probe or traffic hits pods that aren't upS
[0.0838, -0.0244, 0.0637, … 384]L
SESSION#s-101
TS#2026-07-31T00:30:00ZS
u-adaS
Let's cap the rollout at 25 percent surge so a bad image can't take everything downS
[-0.0119, 0.0706, 0.0364, … 384]L
SESSION#s-101
TS#2026-07-31T00:45:00ZS
u-adaS
I've written the deployment manifest with resource requests and limitsS
[0.0373, 0.0088, 0.0379, … 384]L
SESSION#s-101
TS#2026-07-31T01:00:00ZS
u-adaS
Remember the cluster autoscaler won't scale down while a pod has no disruption budgetS
[0.0645, 0.0004, -0.0028, … 384]L
SESSION#s-101
TS#2026-07-31T01:15:00ZS
u-adaS
Rollback is a single command once the previous replica set is still aroundS
[-0.0499, 0.0065, 0.017, … 384]L
SESSION#s-102
TS#2026-08-14T00:00:00ZS
u-adaS
The invoice totals are off by a penny on multi-currency accountsS
[-0.0236, 0.0043, 0.0024, … 384]L
SESSION#s-102
TS#2026-08-14T00:15:00ZS
u-adaS
It's a rounding bug: we round each line rather than the sumS
[-0.058, 0.0524, 0.0121, … 384]L
SESSION#s-102
TS#2026-08-14T00:30:00ZS
u-adaS
Store amounts in minor units as integers and the whole class of bug goes awayS
[0.0164, 0.0939, -0.0558, … 384]L
SESSION#s-102
TS#2026-08-14T00:45:00ZS
u-adaS
I'll add a test that a three-line invoice in euros sums exactlyS
[-0.0708, -0.0262, -0.0698, … 384]L
SESSION#s-102
TS#2026-08-14T01:00:00ZS
u-adaS
Refunds have the same problem on partial amountsS
[-0.0382, 0.0442, 0.0863, … 384]L
SESSION#s-102
TS#2026-08-14T01:15:00ZS
u-adaS
Ship the integer change first, then backfill the historic rowsS
[-0.018, 0.0572, -0.0528, … 384]L
SESSION#s-103
TS#2026-08-25T00:00:00ZS
u-adaS
The settings page collapses to one column below 640 pixelsS
[0.0331, 0.0595, -0.0309, … 384]L
SESSION#s-103
TS#2026-08-25T00:15:00ZS
u-adaS
That's the grid falling back rather than a media query firingS
[0.0501, -0.021, -0.0199, … 384]L
SESSION#s-103
TS#2026-08-25T00:30:00ZS
u-adaS
Use a minmax track so it reflows instead of snappingS
[-0.0204, -0.0325, 0.0066, … 384]L
SESSION#s-103
TS#2026-08-25T00:45:00ZS
u-adaS
The sidebar still overlaps the content at exactly 641 pixelsS
[0.0259, 0.0453, 0.0465, … 384]L
SESSION#s-103
TS#2026-08-25T01:00:00ZS
u-adaS
Give the sidebar its own container query and stop guessing at breakpointsS
[0.011, 0.0554, 0.0946, … 384]L
SESSION#s-103
TS#2026-08-25T01:15:00ZS
u-adaS
Looks right on a narrow phone nowS
[-0.0193, 0.0517, 0.0483, … 384]L
SESSION#s-201
TS#2026-08-22T00:00:00ZS
u-linusS
Can you summarise last quarter's support volume by product areaS
[0.0539, -0.0202, -0.0069, … 384]L
SESSION#s-201
TS#2026-08-22T00:15:00ZS
u-linusS
Sign-in problems are the single biggest bucket by some distanceS
[0.061, 0.0376, 0.0279, … 384]L
SESSION#s-201
TS#2026-08-22T00:30:00ZS
u-linusS
Most of those are expired magic links rather than forgotten passwordsS
[-0.066, -0.0664, -0.0514, … 384]L
SESSION#s-201
TS#2026-08-22T00:45:00ZS
u-linusS
Worth shortening the link copy before we touch the auth flow itselfS
[-0.1121, 0.0116, 0.019, … 384]L

Run an operation to see the raw engine response.

table AgentMemorykeys pk / skitems 22