# PRD-108 Implementation — Shared Memory Field

**Branch:** `ralph/prd-82b-mission-intelligence` **Commit:** `674474722` **Date:** 2026-03-21 **Authors:** Gerard Kavanagh + Claude

***

## What We Built

A shared semantic vector field where agents **query by meaning** instead of passing messages through a chain. Every agent in a mission reads from and writes to the same field. Relevance is surfaced by resonance — not by who told whom what.

This kills the telephone game.

```
Before (message-passing):
  Agent A → findings → Agent B → summary → Agent C
  If B doesn't mention finding #7, C never sees it.

After (shared field):
  Agent A injects 10 findings into the field
  Agent B queries, sees findings, injects analysis
  Agent C queries "subtopic 7" → finds it directly
  No intermediary. No information loss.
```

***

## Architecture

### Core Abstraction

**`core/ports/context.py`** — `SharedContextPort` (ABC)

Defines the contract: `create_context`, `inject`, `query`, `destroy_context`. Any backend can implement it. Today we have two:

* `RedisSharedContext` (PRD-107) — key-value message passing
* `VectorFieldSharedContext` (PRD-108) — semantic vector field

Swappable. A/B testable. Same interface, fundamentally different information dynamics.

### The Field — `modules/context/adapters/vector_field.py`

Each mission gets a Qdrant collection (`field_{uuid}`). Each piece of knowledge is a point:

| Component    | Detail                                                                                                |
| ------------ | ----------------------------------------------------------------------------------------------------- |
| **Vector**   | 2048-dim embedding (via EmbeddingManager / OpenRouter)                                                |
| **Payload**  | `agent_id`, `key`, `value`, `strength`, `created_at`, `last_accessed`, `access_count`, `content_hash` |
| **Distance** | Cosine similarity                                                                                     |

### Resonance Scoring

When an agent queries the field, results are ranked by **resonance**, not raw cosine similarity:

```
R(pattern, query) = cos(θ)² × decayed_strength
```

* **Squared cosine** amplifies high-similarity matches and suppresses noise
* **Decayed strength** ensures freshness matters

### Temporal Decay

Patterns fade over time following exponential decay:

```
S(t) = S₀ × e^(-λt) × access_boost

λ = 0.1  →  half-life ≈ 6.93 hours
```

| Hours Old | No Access | 5 Accesses | 20 Accesses |
| --------- | --------- | ---------- | ----------- |
| 0         | 1.0000    | 1.2500     | 2.0000      |
| 1         | 0.9048    | 1.1310     | 1.8097      |
| 7         | 0.4966    | 0.6207     | 0.9932      |
| 24        | 0.0907    | 0.1134     | 0.1814      |
| 48        | 0.0082    | 0.0103     | 0.0165      |
| 72        | 0.0007    | —          | —           |

A pattern nobody accesses is effectively dead after 3 days.

### Hebbian Reinforcement

"Neurons that fire together wire together."

* Each time a pattern is returned in a query, its `access_count` increments
* **Access boost**: `min(1.0 + access_count × 0.05, 2.0)` — max 2× original strength
* **Co-access bonus**: When multiple patterns are retrieved together, each gets +2% per co-pattern — related ideas strengthen each other

### Deduplication

Content is hashed (SHA-256). If the same content is injected twice, the existing pattern is reinforced rather than duplicated.

### Archival Threshold

Patterns with `decayed_strength < 0.05` are filtered from query results. They still exist in the collection but are effectively archived — retrievable only if directly accessed.

### Field Stability

A convergence metric for telemetry:

```
stability = avg_strength × 0.6 + organization × 0.4
organization = 1 - (stddev / mean)
```

Stability rises as agents reference the same patterns (reinforcement) and falls as old, unreferenced patterns drag down the average.

***

## Integration Points

### Mission Coordinator (`services/coordinator_service.py`)

* **`_create_mission_field()`** — Creates the Qdrant field when a mission starts, stores `field_id` in `run.config` JSONB
* **`_inject_task_output_into_field()`** — After each task completes, its output is injected into the field for downstream agents
* **`_destroy_mission_field()`** — Cleanup on mission completion/failure
* **`_cleanup_terminal_fields()`** — Tick-based garbage collection

### Agent Platform Tools

Three tools agents can call directly during execution:

| Tool                       | Purpose                              |
| -------------------------- | ------------------------------------ |
| `platform_field_query`     | Search the field by semantic meaning |
| `platform_field_inject`    | Add a finding/analysis to the field  |
| `platform_field_stability` | Check field convergence metrics      |

Registered via the standard 3-file pattern:

* `modules/tools/discovery/actions_field.py` — ActionDefinition registrations
* `modules/tools/discovery/handlers_field.py` — Handler implementations
* `modules/tools/discovery/platform_executor.py` — Dispatch entries
* `consumers/chatbot/auto.py` — Keyword routing

### Configuration (`config.py`)

All field parameters are configurable via environment variables:

```
QDRANT_URL=http://localhost:6333
QDRANT_API_KEY=
FIELD_EMBEDDING_DIM=2048
FIELD_DECAY_RATE=0.1
FIELD_REINFORCE_BONUS=0.05
FIELD_REINFORCE_CAP=2.0
FIELD_ARCHIVAL_THRESHOLD=0.05
FIELD_BOUNDARY_PERMEABILITY=1.0
```

***

## Test Results

### Unit Tests — 57 passed

`tests/test_vector_field.py` — Mocked Qdrant + EmbeddingManager. Covers:

* Decay math (11 tests) — zero age, half-life, cap boundary, scaling
* Create/destroy lifecycle (8 tests)
* Inject with dedup (9 tests)
* Query with resonance scoring (9 tests)
* Hebbian reinforcement (7 tests)
* Stability measurement (7 tests)
* Internal helpers (6 tests)

### Integration Stress Tests — 16/16 assertions passed

`tests/demo_field_stress.py` — Real Qdrant (in-memory mode), real vectors, real math. No mocks.

**Test 1: Resonance ranking** Python ML pattern ranked in top 2 for "best language for machine learning" query. Go concurrency correctly ranked last.

**Test 2: Temporal decay** Fresh pattern strength: 1.0000. 24h-old pattern: 0.0907. That's 91% decay — the math works.

**Test 3: Hebbian reinforcement** Popular pattern (10 accesses): strength 1.50. Lonely pattern (0 accesses, 6h old): strength 0.55. Reinforcement beats decay.

**Test 4: Archival threshold** 72h-old pattern decayed to 0.000747 — well below the 0.05 threshold. Effectively dead.

**Test 5: 50-agent stress** 150 patterns (50 agents × 3 findings). 4,000 queries/sec. No degradation.

**Test 6: Field stability** Empty field: 0.0. 11 fresh patterns: 1.0. Mixed ages (old + new): 0.57. Stability correctly reflects field health.

**Test 7: The telephone game proof** Agent A injects 10 research findings. Agent B queries, references only findings 0-2, injects analysis. Agent C queries for "subtopic 7" — **finds it directly**, even though Agent B never mentioned it. This is the entire point. In message-passing, finding #7 would be lost. In the shared field, it's right there.

### Integration Demo

`tests/demo_field.py` — 3-agent EU AI Act compliance scenario. Researcher → Analyst → Writer. Shows resonance ranking, Hebbian reinforcement on accessed patterns, temporal decay table, and stability measurement.

***

## Files Changed/Created

| File                                           | Action   | Purpose                                    |
| ---------------------------------------------- | -------- | ------------------------------------------ |
| `core/ports/__init__.py`                       | Created  | Ports package init                         |
| `core/ports/context.py`                        | Created  | SharedContextPort ABC                      |
| `modules/context/adapters/__init__.py`         | Created  | Adapters package init                      |
| `modules/context/adapters/vector_field.py`     | Created  | The field implementation (356 lines)       |
| `modules/tools/discovery/actions_field.py`     | Created  | 3 tool registrations                       |
| `modules/tools/discovery/handlers_field.py`    | Created  | 3 tool handlers (151 lines)                |
| `modules/tools/discovery/platform_actions.py`  | Modified | Register field actions                     |
| `modules/tools/discovery/platform_executor.py` | Modified | Add field handlers to dispatch             |
| `consumers/chatbot/auto.py`                    | Modified | Keyword routing for field tools            |
| `services/coordinator_service.py`              | Modified | Field lifecycle in mission coordinator     |
| `config.py`                                    | Modified | 8 new FIELD\_\* and QDRANT\_\* config vars |
| `requirements.txt`                             | Modified | Added `qdrant-client>=1.12.0`              |
| `tests/test_vector_field.py`                   | Created  | 57 unit tests                              |
| `tests/demo_field.py`                          | Created  | Integration demo                           |
| `tests/demo_field_stress.py`                   | Created  | 16-assertion stress test                   |

***

## What This Proves

PRD-108's hypothesis: *"Agents sharing a continuous semantic field produce higher-quality collaborative output than agents passing discrete messages."*

> **Editorial comment:** The implementation and tests support the claim that the mechanism works and that it improves retrieval in the scenarios tested. A stricter phrasing would avoid presenting this as fully proven across all workloads until broader A/B evaluation is complete.

The stress tests confirm the mechanics work:

1. Relevance surfaces by meaning, not by chain position
2. Time naturally filters stale information
3. Frequently-used knowledge persists
4. Cross-agent visibility is total — no information loss through intermediaries
5. Performance holds at scale (4,000 qps with 150 patterns)

The telephone game is dead. Agents share a brain.

> **Editorial comment:** Strong line, but rhetorically stronger than the current evidence base. For a more defensible technical document, consider reframing this as: "In the tested scenarios, the shared field substantially reduces information loss from sequential handoff."

***

## What's Next

* **Deploy Qdrant** — Railway service is provisioned, env vars set on API + workers
* **Push to remote** — Code committed locally, ready to push
* **E2E test** — Create a real mission through the API and watch agents use the field
* **A/B comparison** — Same mission, Redis vs Vector Field, measured on context quality and task accuracy
* **Phase 3 gate** — Results determine whether PRDs 110-116 proceed
