Vote for your favorite SkillMD. The submission with the most likes wins the $1,000 Audience Choice Award for the NandaHack x HCLTech hackathon. Voting is open through October 25.Vote now →
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 avatar

@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 diff

Checkout locally

git fetch origin pull/295/head:pr-295
git checkout pr-295