in reviewhumanPR #295Memory
[Fellowship Challenge] Expiring memory (ttl.v1) for the memory layer
Submission for the Hexaware x Project NANDA Fellowship Technical Challenge
Author
@Prathmesh010190
github profile →- Status
- In review
- Opened on
- Oct 1
- Branch
- challenge/prathmesh010190-expiring-memory
Description
The pitch.
Submission for the Hexaware x Project NANDA Fellowship Technical Challenge
## Summary
This PR adds expiring memory to the memory layer (layer 10): `memory: ttl.v1`, a plugin that stops serving a remembered entry once its time limit has passed. It comes with a negative-control plugin (`ttl_off.v1`), a new Lab scenario (`marketplace_expiring_memory`), a validator for it, and tests.
## The gap
The default memory plugin, `kv.v1`, never forgets. In the marketplace scenario, the buyer remembers `preferred_seller` after round one, and in round two it quotes only that seller instead of looking up sellers again through the registry. Nothing in the layer can mark a remembered fact as stale, so an agent can keep acting on old knowledge for as long as the run lasts.
## What I added (layer: memory)
- **`ttl.v1`** (`src/nandatown/layers/memory_ttl.py`): a subclass of `KeyValueMemory`.
- `remember` stores the value as `kv.v1` does. If the agent's scenario config declares a limit for that key (`memory_ttl: {preferred_seller: 0.5}`), it also stores `expires_at = engine.now + limit` and puts `expires_at` in the `memory_written` event.
- `recall` returns the value as before if the key has no limit. If a limit exists and `engine.now >= expires_at`, it deletes the entry, emits `memory_expired` (key and `expires_at`), and returns `None`. Otherwise it emits `memory_recalled` and returns the value.
- **`ttl_off.v1`** (same file): the negative control. It records `expires_at` and emits `memory_recalled` with `"stale": true`, but still returns the expired entry.
- **`marketplace_expiring_memory`** (`src/nandatown/sim/scenarios/`): a copy of the marketplace scenario with `memory: ttl.v1` and `memory_ttl: {preferred_seller: 0.5}` on `buyer-1`. The duplicate-delivery fault stays in the scenario.
- **Validator** for that scenario (`src/nandatown/sim/validators.py`), a label for the new `memory_expiry` stage (`report.py`), tests (`tests/test_memory_ttl.py`), and the scenario name added to `ALL_SCENARIOS` in `tests/test_sim.py`.
- The plugin is registered by adding `memory_ttl` to the import list in `src/nandatown/layers/__init__.py`.
I did not change `sim/agents.py` or `sim/api.py`.
## Design decisions
- **Absolute deadline in logical time.** The plugin compares `expires_at` with the engine's logical clock (`engine.now`), not wall-clock time, so the run stays seeded and `verify` can reproduce it.
- **Events carry keys and times only, never values.** The `memory_expired` event shows only `key` and `expires_at`.
- **Only declared keys expire.** A key with no entry in `memory_ttl` behaves exactly like `kv.v1`.
- **The limit is read from the agent's scenario config.** Lab memory plugins are constructed with only the engine and get no settings, so the plugin reads `memory_ttl` from the agent's entry in `engine.spec.agents`.
- **A new validator.** The stock marketplace validator needs exactly 3 quote requests and a `memory_reuse` stage. With expiry, round two looks sellers up again, so there is a 4th request and no reuse. My validator accepts at least 3 quote requests for `discovery`, drops `memory_reuse`, and adds `memory_expiry`.
## Fault and invariant
**Fault:** the remembered entry ages past its limit between rounds. `preferred_seller` is written at t=1.90 with a limit of 0.5 (so `expires_at` is about 2.40), and round two reads it at t=2.90. The duplicate-delivery fault still runs alongside it.
**Invariant (`memory_expiry` stage):**
- It fails if any `memory_recalled` event has `"stale": true` (an entry past its expiry was served).
- It reports missing evidence if no `memory_expired` event exists, because then the rule was never exercised.
- It passes when an expired entry was dropped and never recalled.
With `ttl.v1`, the read at t=2.90 emits `memory_expired` (ev-43) and the buyer looks sellers up again. That run has 70 events and 4 quote requests. All eight stages pass.
## Negative control
`nanda
…Try it
Open PR on GitHubView diffCheckout locally
git fetch origin pull/295/head:pr-295
git checkout pr-295