Selecting Earlier Task Records for Coding Agents
Can a coding agent benefit from earlier work in the same repository? A small executable experiment on what gets saved, what gets shown, and what actually helps.
In brief
An earlier task may contain information a later coding agent needs. But remembering every task can bury that information in unrelated history. I studied two decisions: should an earlier record be kept before the later task is known? And should a particular later agent see it?
We tried this on ten real coding tasks. The system often filtered out an earlier issue that was related to the new task, so the coding agent never saw it. Giving agents past issue summaries did not lead to more completed fixes in these runs. But that does not mean memory is useless: these summaries were not proven solutions, and this small experiment cannot tell us what better memories would do.
1. The Problem
Imagine two coding agents working on the same software project months apart. Agent A investigates an unexpected database behavior. Agent B encounters another issue involving the same part of the codebase. Agent B starts fresh: it can read the repository, but it does not automatically know what Agent A encountered.
A memory system might preserve some history for Agent B. That raises two different questions. At the end of Agent A's work, what deserves to be retained? Later, when Agent B's task is known, what part of that retained history should enter its prompt? The first decision cannot legitimately depend on future tasks; the second can.
The aim here was not to invent a memory database. It was to put these decisions in a setting where the downstream outcome could be checked by running software tests.
2. A Simple Example
The running example is from Django, the Python web framework. Its ORM lets a program fetch database objects without writing raw SQL. Two methods are relevant: select_related() follows relationships and fetches related objects in the same query; only() restricts which fields are loaded initially.
In the later task (django__django-35356), a model refers to another instance of itself using a one-to-one relationship. The issue report gives this query, here abbreviated to its relevant lines:
class Example(models.Model):
name = models.CharField(max_length=32)
source = models.OneToOneField(
"self", related_name="destination",
on_delete=models.CASCADE
)
Example.objects.select_related(
"source", "destination"
).only(
"name", "source__name", "destination__name"
)
What goes wrong? Instead of returning the requested data, Django reports a FieldError: Example.source cannot be both deferred (not loaded immediately) and traversed using select_related(). According to the issue, fetching either relationship separately works; combining them triggers the problem.
Now look backward. About ten months earlier, task django__django-16910 described a different problem involving only(), select_related(), and a reverse one-to-one relationship: Django fetched more fields than expected. Its reference change touched django/db/models/sql/query.py.
These are related ORM problems, not identical bugs. The earlier record names a plausible area to investigate, but it does not tell Agent B how to fix the later error.
Would showing the earlier record help a coding agent? That is the question the experiment can test; the fact that the benchmark labels the pair related is not itself proof of usefulness.
3. The Dataset
I used SWE-ContextBench Lite, a benchmark of software issues with earlier experience tasks, later target tasks, and known relations between some pairs. The release contains 300 earlier experience tasks and 99 related targets.
A simple setup would give the agent the one earlier record already annotated as related to its target. But that gives away much of the retrieval problem. Instead, this study assembled a history of every strictly earlier task in the same repository. The published relation was kept out of the selectors' inputs and used only for offline analysis.
Each of the eleven clean targets had 13–114 earlier candidates. One Matplotlib target was excluded from primary analysis because the evaluator's no-change control already satisfied its failing test. The remaining ten tasks span Django, SymPy, and scikit-learn, with eight distinct resolving pull requests underlying the ten target IDs.
django__django-35356 had 114 earlier same-repository candidates—not just the annotated source django__django-16910. The selector had to operate in that larger history without being told which source the benchmark considered related.
The eleven histories contained 603 target–record entries, deduplicating to 211 distinct source records. The primary ten histories used 188 distinct sources; source-time decisions were frozen across the 211-record universe. Issue creation timestamps established ordering, although they do not prove when the corresponding repairs became available.
4. What Counts as a Memory?
The word memory needs care here. The completed pilot did not store insights extracted from a successful earlier coding agent's actions. It stored a short excerpt of an earlier issue together with file paths from its reference change. The source agent's outcome was unknown.
This is the actual record associated with our earlier Django task, rendered more readably but retaining its stored text:
Earlier task experience concerned: QuerySet.only() doesn't work with select_related() on a reverse OneToOneField relation. Description On Django 4.2 calling only() with select_related() on a query using the reverse lookup for a OneToOne relation does not generate the correct query. All the fields from the related model are still included in the….Reference change touched
django/db/models/sql/query.py
The stored claim was prefixed with “Earlier task experience concerned” and suffixed with the reference-change path. It also warned the worker to inspect current code and tests rather than treat the record as an instruction. It did not contain the earlier fix as an executable recipe or evidence that an agent learned from that task.
Why this matters: a historical issue record is not the same as reusable know-how. The experiment can tell us what happened when these records were selected; it cannot tell us that a learned, verified memory system would behave the same way.
5. The Experiment
A custom selector made a single SHARE or DO_NOT_SHARE decision for each source record before receiving any later target. For a new task, the system chose the three most recent history slots. Only retained records in those slots could reach the worker; filtered-out slots were not backfilled by older memories. A second selector could then choose EXPOSE or WITHHOLD for that specific target.
Six conditions were completed, using the same ten targets. They represent different ways to control which history reaches the agent:
The custom decisions used the Jev System-One API (jev-1.13.0) with binary prompts. They did not implement the published Jev-Mem architecture. The coding worker was GPT-6 Luna with the SWE-Edit scaffold and xhigh reasoning; its changes were graded with the canonical SWE-ContextBench tests through an Apptainer adapter. The full B–E core produced forty graded runs, ten per condition.
Jev does not write the fix. It makes two small choices about whether the earlier Django record can reach the coding agent:
The coding agent is different: it can edit and test code. The arrows below show how it receives instructions, uses tools, gets feedback, and produces a patch that is graded afterward.
django__django-16910 was among the fixed three recent history slots for django__django-35356. The source-only selector said SHARE; the target-aware selector said EXPOSE. So in condition E, the later worker really did see this earlier record.
Protocol, worker qualification, and what changed during development
The initial plan was more ambitious: fresh source-agent trajectories, stronger governance comparisons, and a fuller write/read factorial. Worker and infrastructure qualifications failed several times. The experiment was explicitly amended before treatment execution to use the available issue-derived records and a Luna signal check. That check produced three executable disagreements in ten No-Memory versus known-related pairs; it established sensitivity to context, not benefit.
The final A/F conditions came from a separate paired signal run and its test-path-filtered regrade. The B–E arms were run later under the repaired authoritative diff-collection boundary. The proposed deliberative LLM write arm G never ran. The design also lacks Share-All plus target-aware Read; therefore it cannot isolate the read filter's independent effect.
6. What Happened?
First, consider what happened to the earlier records that the benchmark had annotated as related to their later tasks.
Bars use the eight retrieved target cases as the reference width. Two other targets lost their annotated source at retrieval itself.
Across all source records, the selector admitted 123/211. On the ten primary tasks, fifteen admitted records entered read decisions, and only one was exposed. Six target-level source rejections in the related-record trace came from just two distinct SymPy source decisions reused across several targets—not six independent decisions.
How often did Jev keep or show a related record?
There is no verified answer key for which memories would actually help a repair. But the benchmark tells us which earlier issue it marked as related to each later issue. We can compare Jev's choices against those annotations.
1. Keep or drop an earlier record?
30 history slots across the ten later tasks
| Earlier record | Kept | Dropped |
|---|---|---|
| Marked related | 2 | 6 |
| Not marked related | 13 | 9 |
| Total | 15 | 15 |
2 of 8 annotated related records survived the first Jev decision.
2. Show or hide a kept record?
15 retained records that reached the read decision
| Earlier record | Shown | Hidden |
|---|---|---|
| Marked related | 1 | 1 |
| Not marked related | 0 | 13 |
| Total | 1 | 14 |
1 of 2 retained related records was shown to the worker.
These are annotation-based confusion matrices, not correctness scores. “Not marked related” means the benchmark did not label that source–target pair as related; it does not prove the record was useless. A related record is not necessarily a helpful repair instruction either. So the 13 kept-but-unannotated records cannot be called false acceptances, nor the nine dropped records correct rejections. There is no defensible true-positive/false-positive accuracy, precision, or specificity for actual memory usefulness.
How the counts were calculated
The write governor made 211 unique source decisions overall: 123 SHARE and 88 DO_NOT_SHARE. The matrix above instead evaluates the 30 candidate slots retrieved for ten later tasks (three per task): eight slots contained the benchmark's annotated related source, and 22 did not. Of those 30 slots, 15 belonged to globally shared sources. Two were annotated related (2 kept; 6 dropped); the other 13 were not annotated (13 kept; 9 dropped).
The read governor then decided on those 15 retained candidate slots. It exposed one annotated related record (the Django example) and withheld fourteen records: one annotated related and thirteen not annotated. These counts are at the target–record slot level, not 30 independent write calls: the six annotated write exclusions are repeated uses of only two rejected SymPy source records. Across all 211 unique source records, no independently verified relevance/usefulness labels are available to create a genuine global confusion matrix.
See the Round 3 results and the evidence ledger.
django-16910 → django-35356. It reached the agent, but the later Django bug remained unresolved: 0/1 designated failing tests passed. This shows exposure occurred; it does not show the information was sufficient to repair the bug.
Did the memory conditions solve more tasks?
No memory condition improved full-task resolution in these recorded runs. Partial test progress was more mixed:
| Condition | Exposed records | Resolved | Failing tests fixed | Passing tests preserved |
|---|---|---|---|---|
| No Memory (A) | 0 | 2/10* | 9/48 | 2145/2145 |
| Share-All (B) | 30 | 1/10 | 7/48 | 2025/2145 |
| Random (C) | 20 | 1/10 | 8/48 | 2025/2145 |
| Selective Write (D) | 15 | 1/10 | 13/48 | 2025/2145 |
| Write + Read (E) | 1 | 1/10 | 7/48 | 2025/2145 |
| Known-Related (F) | — | 1/10 | 8/48 | 2025/2145 |
* The No-Memory 2/10 includes one success obtained only after a separate sanitized regrade of its saved patch. The original patch on sympy-21203 did not apply. F is a relation-based diagnostic, not a genuine upper bound. F2P/P2P totals count tests grouped inside tasks, not independent experimental trials.
D fixed more designated failing tests overall (13/48), but still solved just one task. The 120 passing-test regressions in B–F were concentrated on sympy-21309. That contrast cannot automatically be attributed to memory because worker runs differed even when their prompts were identical.
The sharpest observation: the Write + Read condition E showed no memory at all to nine of ten targets—including the one it solved. Its only genuinely exposed target was the Django example, which remained unresolved.
Per-target test counts and grading details
F2P means tests that were failing before the repair and passed afterward. P2P means previously passing tests that remained passing. A task counts as resolved only when the evaluator's full criteria hold.
| Target | F2P total | A | B | C | D | E | F |
|---|---|---|---|---|---|---|---|
| django-34176 | 6 | 1 | 1 | 1 | 2 | 1 | 1 |
| django-35356 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| scikit-learn-13771 | 5 | 2 | 2 | 2 | 2 | 2 | 2 |
| sympy-16342 | 11 | 1 | 1 | 1 | 1 | 1 | 2 |
| sympy-16946 | 6 | 0 | 0 | 0 | 4 | 0 | 0 |
| sympy-16953 | 11 | 0 | 0 | 0 | 0 | 0 | 0 |
| sympy-19235 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| sympy-21203 | 3 | 3 | 1 | 2 | 2 | 1 | 1 |
| sympy-21309 | 2 | 1 | 1 | 1 | 1 | 1 | 1 |
| sympy-9384 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
The original A patch for sympy-21203 had patch_applied=false and resolved=false; after filtering test-path edits, its saved source patch applied and fixed 3/3 failing tests while preserving 124/124 passing tests. B–E were collected under the later repaired output boundary. Those are different execution/grading histories, not clean randomized replicates.
7. Why Did It Happen?
There is no single established explanation for these outcomes. The evidence does, however, show where information was removed and why attributing the final scores to the selector would be premature.
The earlier record was thin
Our Django record said that a previous issue involved only(), select_related(), and django/db/models/sql/query.py. That might point a human or agent toward relevant code. But it did not include a verified repair strategy, a successful agent trajectory, or proof that applying the earlier fix would solve the later FieldError. The same limitation applies to most of the stored history.
One early decision affected several later tasks
Six of the eight retrieved related-record cases were dropped before read filtering; those six target-level losses came from only two shared SymPy source decisions. The selector's saved rationales were empty. We can observe the exclusions, but cannot truthfully explain each rejection as an identified reasoning failure, nor assume it was incorrect.
The read filter almost eliminated memory exposure
E showed zero historical records on nine tasks. That makes E a poor test of whether using memory helps: its sole resolved task was among the nine receiving none. The Django case was the exception—its source record was shown—but exposure did not produce a resolved repair.
The worker and comparison were not stable enough for causal claims
On nine E targets, the archived worker prompts were byte-identical to No Memory, yet independently executed workers sometimes produced different patches or grades, notably on sympy-21203 and sympy-21309. The A/F runs also used a distinct regrading path. Meanwhile the memory conditions exposed unequal amounts of context: B/C/D/E used 30/20/15/1 records across the ten targets. Random admission matched the selector's global retained count, not per-target exposure.
The missing Share-All + target-aware Read cell means we cannot separately estimate the effect of the read decision, or its interaction with source admission. The available arms compare policy bundles rather than a complete factorial experiment.
8. What We Learned
The strongest finding is about the measurement problem. A study of memory admission needs to establish that useful information exists in the records being admitted. Otherwise dropping an annotated “related” issue is not necessarily a mistake. A study of memory exposure also needs evidence that the worker actually saw and could use that information.
The Django case makes the distinction concrete. A related record made it through every filter, and the later repair still failed. This says what happened to one historical issue summary; it does not refute the value of a detailed, validated memory. Conversely, when a record was dropped earlier, we could not know whether its absence caused a downstream failure.
So the correct conclusion is limited: in this exploratory pilot, the tested historical-record selection policies did not demonstrate improved task resolution. The selection trace is real, and the experimental confounds are real. There is no established causal benefit—or universal harm—from memory governance here.
9. What I'd Test Next
The next experiment should make the Django-style transfer question answerable before comparing elaborate policies:
- Record a successful earlier agent. Save the actual inspected files, attempted fixes, tests, outcome, and a narrow lesson—not only issue prose and reference paths.
- Prove the lesson can help. For the later ORM issue, compare repeated runs with no memory against runs given the verified earlier lesson directly. If it does not improve the worker, a retention policy cannot recover that benefit.
- Then test admission. Put the useful record among many plausible earlier Django records, freeze a source-only keep/drop decision, and check whether that information remains available.
- Isolate exposure and match budgets. Add the missing Share-All + Read condition and compare against equally sized random and relevance-selected context on each target.
- Repeat with one grading pipeline. Use the same patch collection and evaluator for all arms, multiple worker runs, and distinct underlying pull requests before drawing a causal conclusion.
django-35356. Then show that a future-blind admission policy retains it and a later read policy exposes it—without paying for many irrelevant records. Only then would the pipeline support a claim about effective shared memory.
10. Related Work / Where This Fits
Explore the FrontierMemory research lineage → Updated October 25, 2026: an interactive, source-audited map of FrontierMemory 1.0, the public benchmark families it adapts, its historical-trajectory inputs, the recall evaluations it contrasts, and the earlier Letta research program. Solid connections indicate directly named or linked sources; dashed ones are thematic background, not claimed citations. The page also maps 20 potential 2027 publication tracks (from our GitHub venue list and MSR Data & Tool Showcase), with deadlines and explicit caveats. The original broader 33-paper citation graph remains archived here.
This project sits between prior coding-context benchmarks and memory-management methods. The surrounding literature already establishes that agent memory and governance are active research areas; the novelty here is not the existence of a “keep” button.
The most defensible contribution is a transparent, executable pilot that traces when benchmark-related context disappears between source-only admission and later exposure—and shows why stronger controls are needed before judging the benefit of memory selection.
References & Reproducibility
The complete experiment, protocol amendments, frozen pool definitions, implementation, recorded treatment outcomes, reviewer critiques, and paper revisions are available in the experiment repository, primarily on handoff/aamas-2027-evidence.
- Actual Django source–target candidate pool
- Final exploratory manuscript draft (Round 3)
- Claim-to-evidence ledger
- Independent scientific critique
- Experiment evidence handoff, including v15 archive
Frozen versions and evidence checks
Experiment code commit: 1cedbc0035cb867cfebde398019e313c2a5b02cb. Final v15 evidence archive SHA-256: 260db688e040671dc9f2c7a095573992dc6ceda3b271ebe1852a2e90d19b4586. All 40 B–E canonical-grade hashes were independently checked in the handoff audit. The proposed deliberative LLM write arm G was not run. The work is a completed exploratory core pilot, not a confirmatory effect estimate.