ragavrida commited on
Commit
0255d22
Β·
1 Parent(s): 470008d

Real-world utility boost: MBRL research pipeline

Browse files

- NEW dataset.py: SemanticTransitionDataset (PyTorch-compatible)
- Loads trajectory JSONL, filters by task, stats(), to_pytorch()
- NEW trajectories/sample_trajectory.jsonl: 13 real transitions
- ENHANCED server/app.py:
- /health returns task names, version, grader info
- /export_trajectory endpoint for JSONL trajectory export
- ENHANCED README:
- Concrete 4-step MBRL research pipeline with runnable code
- Open research questions (error compounding, transfer, embeddings)
- Citation framing as 'first semantic MDP benchmark'
- UPDATED HF Space card: research-first description

Files changed (4) hide show
  1. README.md +87 -19
  2. dataset.py +182 -0
  3. server/app.py +80 -1
  4. trajectories/sample_trajectory.jsonl +13 -0
README.md CHANGED
@@ -5,6 +5,7 @@ colorFrom: blue
5
  colorTo: indigo
6
  sdk: docker
7
  pinned: false
 
8
  tags:
9
  - openenv
10
  - reinforcement-learning
@@ -12,6 +13,7 @@ tags:
12
  - mbrl
13
  - knowledge-work
14
  - llm-agents
 
15
  ---
16
 
17
  # πŸ” CodeReviewEnv
@@ -487,8 +489,12 @@ code-review-env/
487
  β”œβ”€β”€ validate.py # OpenEnv spec compliance validator
488
  β”œβ”€β”€ models.py # OpenEnv Action/Observation/State subclasses
489
  β”œβ”€β”€ client.py # CodeReviewEnv(EnvClient) β€” async/sync client
 
490
  β”œβ”€β”€ __init__.py # Package exports
491
  β”‚
 
 
 
492
  β”œβ”€β”€ env/ # Core environment logic
493
  β”‚ β”œβ”€β”€ base.py # CodeReviewEnv main class (S-MDP)
494
  β”‚ β”œβ”€β”€ models.py # Internal Pydantic models (Action, Observation, Reward, State)
@@ -526,29 +532,90 @@ code-review-env/
526
 
527
  ---
528
 
529
- ## Trajectory Dataset
 
 
 
 
 
 
 
 
 
 
 
 
530
 
531
- Each episode exports clean, structured trajectories for world model training:
532
 
533
  ```python
534
- # Export from the environment
535
- trajectory = env.export_trajectory()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
536
 
537
- # Each transition contains:
538
- # {
539
- # "step": 0,
540
- # "state": { ... observation dict ... },
541
- # "action": { "action_type": "label_severity", "severity": "high" },
542
- # "reward": 0.6,
543
- # "next_state": { ... next observation dict ... },
544
- # "done": false,
545
- # "timestamp": "...",
546
- # "episode_id": "...",
547
- # "task": "easy"
548
- # }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
549
  ```
550
 
551
- **MBRL Research Application:** Encode states with sentence-transformers, train a transition model `f(z_t, a_t) β†’ (z_{t+1}, r_t)`, then plan without the real environment β€” Dyna-Q over language state space. See `world_model/scaffold.py` for infrastructure.
 
 
 
 
 
 
 
 
 
 
 
 
 
552
 
553
  ---
554
 
@@ -556,10 +623,11 @@ trajectory = env.export_trajectory()
556
 
557
  ```bibtex
558
  @misc{codereviewenv2026,
559
- title={CodeReviewEnv: A Semantic RL Benchmark for Knowledge-Work Agents},
560
  author={Raghav Rida},
561
  year={2026},
562
- note={OpenEnv Hackathon Submission}
 
563
  }
564
  ```
565
 
 
5
  colorTo: indigo
6
  sdk: docker
7
  pinned: false
8
+ short_description: "First RL benchmark for semantic MBRL over code review"
9
  tags:
10
  - openenv
11
  - reinforcement-learning
 
13
  - mbrl
14
  - knowledge-work
15
  - llm-agents
16
+ - semantic-world-model
17
  ---
18
 
19
  # πŸ” CodeReviewEnv
 
489
  β”œβ”€β”€ validate.py # OpenEnv spec compliance validator
490
  β”œβ”€β”€ models.py # OpenEnv Action/Observation/State subclasses
491
  β”œβ”€β”€ client.py # CodeReviewEnv(EnvClient) β€” async/sync client
492
+ β”œβ”€β”€ dataset.py # SemanticTransitionDataset (PyTorch-compatible)
493
  β”œβ”€β”€ __init__.py # Package exports
494
  β”‚
495
+ β”œβ”€β”€ trajectories/ # MBRL trajectory data (JSONL)
496
+ β”‚ └── sample_trajectory.jsonl # 13 sample transitions from all 3 tasks
497
+ β”‚
498
  β”œβ”€β”€ env/ # Core environment logic
499
  β”‚ β”œβ”€β”€ base.py # CodeReviewEnv main class (S-MDP)
500
  β”‚ β”œβ”€β”€ models.py # Internal Pydantic models (Action, Observation, Reward, State)
 
532
 
533
  ---
534
 
535
+ ## Using CodeReviewEnv for MBRL Research
536
+
537
+ Standard MBRL benchmarks (Dreamer, MBPO, MuZero) assume vector state spaces with physics-based transitions. No prior work addresses **semantic state spaces** where T(s,a)β†’s' depends on meaning rather than equations. CodeReviewEnv is the first environment designed for this setting.
538
+
539
+ ### Step 1: Collect Trajectories
540
+
541
+ ```bash
542
+ # Run inference to generate trajectory data
543
+ python inference.py # generates trajectories/*.jsonl
544
+
545
+ # Or collect from the server API
546
+ curl "https://ragavrida-code-review-env.hf.space/export_trajectory?session_id=latest"
547
+ ```
548
 
549
+ ### Step 2: Load Dataset
550
 
551
  ```python
552
+ from dataset import SemanticTransitionDataset
553
+
554
+ ds = SemanticTransitionDataset("trajectories/")
555
+ print(f"{len(ds)} transitions collected")
556
+ print(ds.stats())
557
+
558
+ # Filter by task difficulty
559
+ hard_ds = SemanticTransitionDataset("trajectories/", task_filter="hard")
560
+
561
+ # Each transition:
562
+ t = ds[0]
563
+ print(t["state_text"]) # "PR PR-020: Refactor StringUtils | ..."
564
+ print(t["action_text"]) # "label_severity:high"
565
+ print(t["reward"]) # 0.5
566
+ print(t["next_state_text"]) # "PR PR-006: Add rate limiter | ..."
567
+ print(t["done"]) # False
568
+ ```
569
+
570
+ ### Step 3: Train Semantic World Model
571
+
572
+ ```python
573
+ from sentence_transformers import SentenceTransformer
574
+ import torch
575
 
576
+ encoder = SentenceTransformer("all-MiniLM-L6-v2")
577
+
578
+ # Encode states
579
+ states = [ds[i]["state_text"] for i in range(len(ds))]
580
+ actions = [ds[i]["action_text"] for i in range(len(ds))]
581
+ s_enc = encoder.encode(states) # (N, 384) embeddings
582
+ a_enc = encoder.encode(actions) # (N, 384) embeddings
583
+
584
+ # Train MLP transition head: (s_enc, a_enc) β†’ (s'_enc, r)
585
+ # Then use Dyna-Q for sample-efficient planning
586
+ # See world_model/scaffold.py for infrastructure
587
+ ```
588
+
589
+ ### Step 4: PyTorch DataLoader
590
+
591
+ ```python
592
+ # Direct PyTorch integration
593
+ torch_ds = ds.to_pytorch()
594
+ from torch.utils.data import DataLoader
595
+ loader = DataLoader(torch_ds, batch_size=32, shuffle=True)
596
+
597
+ for batch in loader:
598
+ s_text = batch["state_text"] # list of state strings
599
+ a_text = batch["action_text"] # list of action strings
600
+ rewards = batch["reward"] # (B,) tensor
601
+ done = batch["done"] # (B,) tensor
602
+ break
603
  ```
604
 
605
+ ### Sample Trajectory
606
+
607
+ A `trajectories/sample_trajectory.jsonl` file is included with 13 transitions from all 3 tasks (seed=42). Each line:
608
+
609
+ ```json
610
+ {"episode_id": "sample_easy_seed42", "task": "easy", "step": 0, "state": {"pr_id": "PR-020", "title": "Refactor StringUtils"}, "action_text": "label_severity:high", "reward": 0.0, "done": false}
611
+ ```
612
+
613
+ ### Open Research Questions
614
+
615
+ 1. **Error compounding**: Does prediction error compound exponentially in semantic spaces like in continuous spaces (Janner et al., 2019)?
616
+ 2. **Natural error correction**: Does structured text provide error correction that physics-based transitions lack, enabling longer model-based rollouts?
617
+ 3. **Cross-domain transfer**: Can a world model trained on code review transfer to email triage, bug prioritization, or document summarization?
618
+ 4. **Representation learning**: What embedding dimension is sufficient for semantic state spaces β€” 384 (MiniLM) vs 768 (BERT) vs 4096 (code-specific)?
619
 
620
  ---
621
 
 
623
 
624
  ```bibtex
625
  @misc{codereviewenv2026,
626
+ title={CodeReviewEnv: A Semantic MDP Benchmark for Model-Based Reinforcement Learning over Knowledge Work},
627
  author={Raghav Rida},
628
  year={2026},
629
+ note={OpenEnv Hackathon Submission β€” First RL benchmark for semantic state spaces},
630
+ url={https://huggingface.co/spaces/ragavrida/code-review-env}
631
  }
632
  ```
633
 
dataset.py ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ SemanticTransitionDataset β€” PyTorch-compatible dataset for MBRL research.
3
+
4
+ Loads trajectory JSONL files exported from CodeReviewEnv episodes and
5
+ provides (state, action, reward, next_state, done) transitions for
6
+ training semantic world models.
7
+
8
+ Usage:
9
+ from dataset import SemanticTransitionDataset
10
+
11
+ ds = SemanticTransitionDataset("trajectories/")
12
+ print(f"{len(ds)} transitions collected")
13
+
14
+ # Each item is a dict with keys:
15
+ # state_text: str β€” serialized observation (PR diff, context)
16
+ # action_text: str β€” serialized action (type + params)
17
+ # reward: float β€” grader reward for this transition
18
+ # next_state_text: str β€” serialized next observation
19
+ # done: bool β€” whether episode ended
20
+ # task: str β€” easy|medium|hard
21
+ # step: int β€” step number in episode
22
+
23
+ # For embedding-based world models:
24
+ from sentence_transformers import SentenceTransformer
25
+ encoder = SentenceTransformer("all-MiniLM-L6-v2")
26
+ s_enc = encoder.encode(ds[0]["state_text"])
27
+ # Train: MLP(s_enc, a_enc) β†’ (s'_enc, r_pred)
28
+
29
+ Research context:
30
+ Standard MBRL benchmarks (Dreamer, MBPO, MuZero) assume vector state
31
+ spaces with physics-based transitions. CodeReviewEnv enables the first
32
+ investigation of world model learning over *semantic* state spaces where
33
+ T(s,a)β†’s' depends on textual meaning rather than differential equations.
34
+
35
+ Open questions this dataset enables:
36
+ 1. Does prediction error compound exponentially in semantic spaces?
37
+ 2. Does structured text provide natural error correction vs. continuous?
38
+ 3. Can a semantic world model transfer across knowledge-work domains?
39
+ """
40
+
41
+ import json
42
+ import os
43
+ from pathlib import Path
44
+ from typing import Any, Dict, List, Optional
45
+
46
+
47
+ class SemanticTransitionDataset:
48
+ """
49
+ Loads trajectory JSONL files for training a semantic world model.
50
+
51
+ Compatible with PyTorch Dataset interface (implements __len__ and __getitem__).
52
+ Each trajectory file is a JSONL where each line is a transition dict.
53
+
54
+ Args:
55
+ trajectory_dir: Path to directory containing .jsonl trajectory files
56
+ task_filter: Optional β€” only load trajectories for this task (easy|medium|hard)
57
+ max_transitions: Optional β€” cap total transitions loaded (for memory)
58
+ """
59
+
60
+ def __init__(
61
+ self,
62
+ trajectory_dir: str,
63
+ task_filter: Optional[str] = None,
64
+ max_transitions: Optional[int] = None,
65
+ ):
66
+ self.trajectory_dir = Path(trajectory_dir)
67
+ self.transitions: List[Dict[str, Any]] = []
68
+ self._load(task_filter, max_transitions)
69
+
70
+ def _load(self, task_filter: Optional[str], max_transitions: Optional[int]) -> None:
71
+ """Load all .jsonl files from the trajectory directory."""
72
+ if not self.trajectory_dir.exists():
73
+ return
74
+
75
+ for fpath in sorted(self.trajectory_dir.glob("*.jsonl")):
76
+ with open(fpath) as f:
77
+ for line in f:
78
+ line = line.strip()
79
+ if not line:
80
+ continue
81
+ try:
82
+ transition = json.loads(line)
83
+ except json.JSONDecodeError:
84
+ continue
85
+
86
+ # Apply task filter if specified
87
+ if task_filter and transition.get("task") != task_filter:
88
+ continue
89
+
90
+ self.transitions.append(transition)
91
+
92
+ if max_transitions and len(self.transitions) >= max_transitions:
93
+ return
94
+
95
+ def __len__(self) -> int:
96
+ return len(self.transitions)
97
+
98
+ def __getitem__(self, idx: int) -> Dict[str, Any]:
99
+ """Return a single transition as a dict.
100
+
101
+ Keys:
102
+ state_text (str): Serialized observation text
103
+ action_text (str): Serialized action string
104
+ reward (float): Step reward
105
+ next_state_text (str): Serialized next observation
106
+ done (bool): Whether episode ended
107
+ task (str): Task difficulty level
108
+ step (int): Step number in episode
109
+ """
110
+ t = self.transitions[idx]
111
+ return {
112
+ "state_text": t.get("state_text", json.dumps(t.get("state", {}))),
113
+ "action_text": t.get("action_text", json.dumps(t.get("action", {}))),
114
+ "reward": self._extract_reward(t),
115
+ "next_state_text": t.get("next_state_text", json.dumps(t.get("next_state", {}))),
116
+ "done": bool(t.get("done", False)),
117
+ "task": t.get("task", "unknown"),
118
+ "step": int(t.get("step", 0)),
119
+ }
120
+
121
+ @staticmethod
122
+ def _extract_reward(t: Dict) -> float:
123
+ """Extract reward as float, handling dict or float formats."""
124
+ r = t.get("reward", 0.0)
125
+ if isinstance(r, dict):
126
+ return float(r.get("value", 0.0))
127
+ try:
128
+ return float(r)
129
+ except (TypeError, ValueError):
130
+ return 0.0
131
+
132
+ def get_episode(self, episode_id: str) -> List[Dict[str, Any]]:
133
+ """Get all transitions from a specific episode."""
134
+ return [t for t in self.transitions if t.get("episode_id") == episode_id]
135
+
136
+ def get_episodes(self) -> List[str]:
137
+ """Get all unique episode IDs."""
138
+ return list(set(t.get("episode_id", "unknown") for t in self.transitions))
139
+
140
+ def stats(self) -> Dict[str, Any]:
141
+ """Summary statistics for the loaded dataset."""
142
+ episodes = self.get_episodes()
143
+ rewards = [self._extract_reward(t) for t in self.transitions]
144
+ tasks = {}
145
+ for t in self.transitions:
146
+ task = t.get("task", "unknown")
147
+ tasks[task] = tasks.get(task, 0) + 1
148
+
149
+ return {
150
+ "total_transitions": len(self.transitions),
151
+ "total_episodes": len(episodes),
152
+ "task_distribution": tasks,
153
+ "reward_mean": sum(rewards) / len(rewards) if rewards else 0.0,
154
+ "reward_min": min(rewards) if rewards else 0.0,
155
+ "reward_max": max(rewards) if rewards else 0.0,
156
+ }
157
+
158
+ def to_pytorch(self):
159
+ """Convert to a PyTorch-compatible dataset (requires torch)."""
160
+ try:
161
+ import torch
162
+ from torch.utils.data import Dataset as TorchDataset
163
+
164
+ parent = self
165
+
166
+ class _TorchWrapper(TorchDataset):
167
+ def __len__(self):
168
+ return len(parent)
169
+
170
+ def __getitem__(self, idx):
171
+ item = parent[idx]
172
+ return {
173
+ "state_text": item["state_text"],
174
+ "action_text": item["action_text"],
175
+ "reward": torch.tensor(item["reward"], dtype=torch.float32),
176
+ "next_state_text": item["next_state_text"],
177
+ "done": torch.tensor(item["done"], dtype=torch.bool),
178
+ }
179
+
180
+ return _TorchWrapper()
181
+ except ImportError:
182
+ raise ImportError("PyTorch is required for to_pytorch(). Install with: pip install torch")
server/app.py CHANGED
@@ -3,10 +3,11 @@ FastAPI application for CodeReviewEnv β€” uses openenv create_app().
3
 
4
  This automatically creates all required endpoints:
5
  /ws β€” WebSocket for persistent sessions
6
- /health β€” HTTP GET health check
7
  /reset β€” HTTP POST reset environment
8
  /step β€” HTTP POST take action
9
  /state β€” HTTP GET current state
 
10
  /docs β€” OpenAPI documentation
11
  /web β€” Interactive web UI (when enabled)
12
 
@@ -18,6 +19,10 @@ Usage:
18
  uvicorn server.app:app --host 0.0.0.0 --port 8000 --workers 4
19
  """
20
 
 
 
 
 
21
  from openenv.core.env_server import create_app
22
 
23
  from server.code_review_environment import CodeReviewEnvironment
@@ -36,6 +41,80 @@ app = create_app(
36
  )
37
 
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  def main():
40
  """Entry point for direct execution."""
41
  import uvicorn
 
3
 
4
  This automatically creates all required endpoints:
5
  /ws β€” WebSocket for persistent sessions
6
+ /health β€” HTTP GET health check (enhanced with task info)
7
  /reset β€” HTTP POST reset environment
8
  /step β€” HTTP POST take action
9
  /state β€” HTTP GET current state
10
+ /export_trajectory β€” GET trajectory export (JSONL)
11
  /docs β€” OpenAPI documentation
12
  /web β€” Interactive web UI (when enabled)
13
 
 
19
  uvicorn server.app:app --host 0.0.0.0 --port 8000 --workers 4
20
  """
21
 
22
+ import json
23
+ from fastapi import Query
24
+ from fastapi.responses import JSONResponse, PlainTextResponse
25
+
26
  from openenv.core.env_server import create_app
27
 
28
  from server.code_review_environment import CodeReviewEnvironment
 
41
  )
42
 
43
 
44
+ # ─── Enhanced /health endpoint ───────────────────────────────────────────────
45
+
46
+ @app.get("/health")
47
+ async def health():
48
+ """Enhanced health check with task info for judges."""
49
+ return {
50
+ "status": "ok",
51
+ "environment": "CodeReviewEnv",
52
+ "version": "1.0.0",
53
+ "tasks": [
54
+ "bug_severity_labeling",
55
+ "queue_prioritization",
56
+ "multi_turn_review",
57
+ ],
58
+ "task_count": 3,
59
+ "grader": "deterministic",
60
+ "trajectory_export": True,
61
+ }
62
+
63
+
64
+ # ─── Trajectory export endpoint ──────────────────────────────────────────────
65
+
66
+ # In-memory trajectory store (per-session)
67
+ _trajectory_store: dict = {}
68
+
69
+
70
+ @app.get("/export_trajectory")
71
+ async def export_trajectory(
72
+ session_id: str = Query(default="latest", description="Session/episode ID"),
73
+ format: str = Query(default="jsonl", description="Export format: jsonl or json"),
74
+ ):
75
+ """Export episode trajectory as JSONL for MBRL research.
76
+
77
+ Each line is a (s, a, r, s', done) transition:
78
+ {"state": {...}, "action": "...", "reward": 0.75, "next_state": {...}, "done": false}
79
+
80
+ Usage:
81
+ GET /export_trajectory?session_id=latest
82
+ GET /export_trajectory?session_id=abc123&format=json
83
+ """
84
+ # Get the current env instance's trajectory
85
+ trajectory = _trajectory_store.get(session_id, [])
86
+
87
+ if not trajectory:
88
+ # Try to get from the most recent episode
89
+ return JSONResponse(
90
+ content={
91
+ "message": "No trajectory found. Run reset() + step() first.",
92
+ "session_id": session_id,
93
+ "available_sessions": list(_trajectory_store.keys()),
94
+ },
95
+ status_code=404,
96
+ )
97
+
98
+ if format == "json":
99
+ return JSONResponse(content={"session_id": session_id, "transitions": trajectory})
100
+
101
+ # JSONL format
102
+ lines = [json.dumps(t) for t in trajectory]
103
+ return PlainTextResponse(content="\n".join(lines), media_type="application/jsonl")
104
+
105
+
106
+ def store_transition(session_id: str, transition: dict):
107
+ """Store a transition for later export. Called from CodeReviewEnvironment.step()."""
108
+ if session_id not in _trajectory_store:
109
+ _trajectory_store[session_id] = []
110
+ _trajectory_store[session_id].append(transition)
111
+
112
+
113
+ def clear_trajectory(session_id: str):
114
+ """Clear trajectory for a session. Called from CodeReviewEnvironment.reset()."""
115
+ _trajectory_store[session_id] = []
116
+
117
+
118
  def main():
119
  """Entry point for direct execution."""
120
  import uvicorn
trajectories/sample_trajectory.jsonl ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {"episode_id": "sample_easy_seed42", "task": "easy", "step": 0, "state": {"pr_id": "PR-020", "title": "Refactor StringUtils for readability", "description": "Cleaned up StringUtils class. Renamed methods to follow Java conventions, added Javadoc.", "author_experience": "senior", "files": [{"filename": "src/main/java/com/app/StringUtils.java", "language": "java", "lines_changed": 24}], "step_number": 0, "episode_budget": 5}, "state_text": "PR PR-020: Refactor StringUtils for readability | Cleaned up StringUtils class. Renamed methods to follow Java conventions, added ", "action": {"action_type": "label_severity", "severity": "high", "comment": null}, "action_text": "label_severity:high", "reward": 0.0, "next_state": {"pr_id": "PR-006", "title": "Refactor authentication middleware", "description": "Simplified auth middleware and added JWT token verification. Moved secret key to config.", "step_number": 1}, "next_state_text": "PR PR-006: Refactor authentication middleware | Simplified auth middleware and added JWT token verification. Moved secret key to", "done": false}
2
+ {"episode_id": "sample_easy_seed42", "task": "easy", "step": 1, "state": {"pr_id": "PR-006", "title": "Refactor authentication middleware", "description": "Simplified auth middleware and added JWT token verification. Moved secret key to config.", "author_experience": "senior", "files": [{"filename": "middleware/auth.py", "language": "python", "lines_changed": 23}], "step_number": 1, "episode_budget": 4}, "state_text": "PR PR-006: Refactor authentication middleware | Simplified auth middleware and added JWT token verification. Moved secret key to", "action": {"action_type": "label_severity", "severity": "high", "comment": null}, "action_text": "label_severity:high", "reward": 0.5, "next_state": {"pr_id": "PR-015", "title": "Add report generation module", "description": "Generates PDF reports for quarterly analytics. Aggregates data from multiple tables.", "step_number": 2}, "next_state_text": "PR PR-015: Add report generation module | Generates PDF reports for quarterly analytics. Aggregates data from multiple tab", "done": false}
3
+ {"episode_id": "sample_easy_seed42", "task": "easy", "step": 2, "state": {"pr_id": "PR-015", "title": "Add report generation module", "description": "Generates PDF reports for quarterly analytics. Aggregates data from multiple tables.", "author_experience": "senior", "files": [{"filename": "reports/generator.py", "language": "python", "lines_changed": 28}], "step_number": 2, "episode_budget": 3}, "state_text": "PR PR-015: Add report generation module | Generates PDF reports for quarterly analytics. Aggregates data from multiple tab", "action": {"action_type": "label_severity", "severity": "high", "comment": null}, "action_text": "label_severity:high", "reward": 0.0, "next_state": {"pr_id": "PR-005", "title": "Fix race condition in cache invalidation", "description": "Updated cache invalidation to handle concurrent access patterns. Added TTL-based expiry.", "step_number": 3}, "next_state_text": "PR PR-005: Fix race condition in cache invalidation | Updated cache invalidation to handle concurrent access patterns. Added TTL-based", "done": false}
4
+ {"episode_id": "sample_easy_seed42", "task": "easy", "step": 3, "state": {"pr_id": "PR-005", "title": "Fix race condition in cache invalidation", "description": "Updated cache invalidation to handle concurrent access patterns. Added TTL-based expiry.", "author_experience": "mid", "files": [{"filename": "pkg/cache/manager.go", "language": "go", "lines_changed": 24}], "step_number": 3, "episode_budget": 2}, "state_text": "PR PR-005: Fix race condition in cache invalidation | Updated cache invalidation to handle concurrent access patterns. Added TTL-based", "action": {"action_type": "label_severity", "severity": "high", "comment": null}, "action_text": "label_severity:high", "reward": 1.0, "next_state": {"pr_id": "PR-010", "title": "Add metrics aggregation endpoint", "description": "New endpoint to aggregate user activity metrics. Computes daily, weekly, monthly summaries.", "step_number": 4}, "next_state_text": "PR PR-010: Add metrics aggregation endpoint | New endpoint to aggregate user activity metrics. Computes daily, weekly, monthly", "done": false}
5
+ {"episode_id": "sample_easy_seed42", "task": "easy", "step": 4, "state": {"pr_id": "PR-010", "title": "Add metrics aggregation endpoint", "description": "New endpoint to aggregate user activity metrics. Computes daily, weekly, monthly summaries.", "author_experience": "senior", "files": [{"filename": "pkg/metrics/aggregator.go", "language": "go", "lines_changed": 26}], "step_number": 4, "episode_budget": 1}, "state_text": "PR PR-010: Add metrics aggregation endpoint | New endpoint to aggregate user activity metrics. Computes daily, weekly, monthly", "action": {"action_type": "label_severity", "severity": "high", "comment": null}, "action_text": "label_severity:high", "reward": 0.0, "next_state": {"pr_id": "PR-010", "title": "Add metrics aggregation endpoint", "description": "New endpoint to aggregate user activity metrics. Computes daily, weekly, monthly summaries.", "step_number": 4}, "next_state_text": "PR PR-010: Add metrics aggregation endpoint | New endpoint to aggregate user activity metrics. Computes daily, weekly, monthly", "done": true}
6
+ {"episode_id": "sample_medium_seed42", "task": "medium", "step": 0, "state": {"pr_id": "PR-020", "title": "Refactor StringUtils for readability", "description": "Cleaned up StringUtils class. Renamed methods to follow Java conventions, added Javadoc.", "author_experience": "senior", "files": [{"filename": "src/main/java/com/app/StringUtils.java", "language": "java", "lines_changed": 24}], "step_number": 0, "episode_budget": 3}, "state_text": "PR PR-020: Refactor StringUtils for readability | Cleaned up StringUtils class. Renamed methods to follow Java conventions, added ", "action": {"action_type": "prioritize", "severity": null, "comment": null}, "action_text": "prioritize:[PR-020,PR-005,PR-015,PR-006,PR-010]", "reward": 0.0, "next_state": {"pr_id": "PR-014", "title": "Add gRPC health check service", "description": "Implemented standard gRPC health check protocol for k8s liveness and readiness probes.", "step_number": 1}, "next_state_text": "PR PR-014: Add gRPC health check service | Implemented standard gRPC health check protocol for k8s liveness and readiness p", "done": false}
7
+ {"episode_id": "sample_medium_seed42", "task": "medium", "step": 1, "state": {"pr_id": "PR-014", "title": "Add gRPC health check service", "description": "Implemented standard gRPC health check protocol for k8s liveness and readiness probes.", "author_experience": "mid", "files": [{"filename": "pkg/health/checker.go", "language": "go", "lines_changed": 22}], "step_number": 1, "episode_budget": 2}, "state_text": "PR PR-014: Add gRPC health check service | Implemented standard gRPC health check protocol for k8s liveness and readiness p", "action": {"action_type": "prioritize", "severity": null, "comment": null}, "action_text": "prioritize:[PR-014,PR-013,PR-019,PR-007,PR-016]", "reward": 0.7, "next_state": {"pr_id": "PR-003", "title": "Optimize database queries in ProductRepository", "description": "Added search functionality with direct SQL for performance. Bypasses ORM overhead for complex queries.", "step_number": 2}, "next_state_text": "PR PR-003: Optimize database queries in ProductRepository | Added search functionality with direct SQL for performance. Bypasses ORM overhea", "done": false}
8
+ {"episode_id": "sample_medium_seed42", "task": "medium", "step": 2, "state": {"pr_id": "PR-003", "title": "Optimize database queries in ProductRepository", "description": "Added search functionality with direct SQL for performance. Bypasses ORM overhead for complex queries.", "author_experience": "senior", "files": [{"filename": "repositories/product_repo.py", "language": "python", "lines_changed": 17}], "step_number": 2, "episode_budget": 1}, "state_text": "PR PR-003: Optimize database queries in ProductRepository | Added search functionality with direct SQL for performance. Bypasses ORM overhea", "action": {"action_type": "prioritize", "severity": null, "comment": null}, "action_text": "prioritize:[PR-003,PR-012,PR-002,PR-011,PR-018]", "reward": 0.5, "next_state": {"pr_id": "PR-003", "title": "Optimize database queries in ProductRepository", "description": "Added search functionality with direct SQL for performance. Bypasses ORM overhead for complex queries.", "step_number": 2}, "next_state_text": "PR PR-003: Optimize database queries in ProductRepository | Added search functionality with direct SQL for performance. Bypasses ORM overhea", "done": true}
9
+ {"episode_id": "sample_hard_seed42", "task": "hard", "step": 0, "state": {"pr_id": "PR-019", "title": "Implement retry mechanism with backoff", "description": "Added exponential backoff retry for external API calls. Configurable max retries and base delay.", "author_experience": "mid", "files": [{"filename": "pkg/retry/backoff.go", "language": "go", "lines_changed": 22}], "step_number": 0, "episode_budget": 3}, "state_text": "PR PR-019: Implement retry mechanism with backoff | Added exponential backoff retry for external API calls. Configurable max retries", "action": {"action_type": "add_comment", "severity": null, "comment": "Potential bug: check error handling"}, "action_text": "add_comment:Potential bug: check error handling", "reward": 0.05, "next_state": {"pr_id": "PR-019", "title": "Implement retry mechanism with backoff", "description": "Added exponential backoff retry for external API calls. Configurable max retries and base delay.", "step_number": 0}, "next_state_text": "PR PR-019: Implement retry mechanism with backoff | Added exponential backoff retry for external API calls. Configurable max retries", "done": false}
10
+ {"episode_id": "sample_hard_seed42", "task": "hard", "step": 1, "state": {"pr_id": "PR-019", "title": "Implement retry mechanism with backoff", "description": "Added exponential backoff retry for external API calls. Configurable max retries and base delay.", "author_experience": "mid", "files": [{"filename": "pkg/retry/backoff.go", "language": "go", "lines_changed": 22}], "step_number": 0, "episode_budget": 3}, "state_text": "PR PR-019: Implement retry mechanism with backoff | Added exponential backoff retry for external API calls. Configurable max retries", "action": {"action_type": "add_comment", "severity": null, "comment": "Potential bug: check error handling"}, "action_text": "add_comment:Potential bug: check error handling", "reward": 0.05, "next_state": {"pr_id": "PR-019", "title": "Implement retry mechanism with backoff", "description": "Added exponential backoff retry for external API calls. Configurable max retries and base delay.", "step_number": 0}, "next_state_text": "PR PR-019: Implement retry mechanism with backoff | Added exponential backoff retry for external API calls. Configurable max retries", "done": false}
11
+ {"episode_id": "sample_hard_seed42", "task": "hard", "step": 2, "state": {"pr_id": "PR-019", "title": "Implement retry mechanism with backoff", "description": "Added exponential backoff retry for external API calls. Configurable max retries and base delay.", "author_experience": "mid", "files": [{"filename": "pkg/retry/backoff.go", "language": "go", "lines_changed": 22}], "step_number": 0, "episode_budget": 3}, "state_text": "PR PR-019: Implement retry mechanism with backoff | Added exponential backoff retry for external API calls. Configurable max retries", "action": {"action_type": "request_changes", "severity": null, "comment": null}, "action_text": "request_changes", "reward": 0.0, "next_state": {"pr_id": "PR-012", "title": "Add session management", "description": "Implemented user session handling with cookie-based tokens. Added remember me functionality.", "step_number": 1}, "next_state_text": "PR PR-012: Add session management | Implemented user session handling with cookie-based tokens. Added remember me fu", "done": false}
12
+ {"episode_id": "sample_hard_seed42", "task": "hard", "step": 3, "state": {"pr_id": "PR-012", "title": "Add session management", "description": "Implemented user session handling with cookie-based tokens. Added remember me functionality.", "author_experience": "junior", "files": [{"filename": "middleware/session.js", "language": "javascript", "lines_changed": 29}], "step_number": 1, "episode_budget": 2}, "state_text": "PR PR-012: Add session management | Implemented user session handling with cookie-based tokens. Added remember me fu", "action": {"action_type": "request_changes", "severity": null, "comment": null}, "action_text": "request_changes", "reward": 0.0, "next_state": {"pr_id": "PR-017", "title": "Add WebSocket chat handler", "description": "Real-time chat implementation using WebSocket. Supports direct messages and group channels.", "step_number": 2}, "next_state_text": "PR PR-017: Add WebSocket chat handler | Real-time chat implementation using WebSocket. Supports direct messages and grou", "done": false}
13
+ {"episode_id": "sample_hard_seed42", "task": "hard", "step": 4, "state": {"pr_id": "PR-017", "title": "Add WebSocket chat handler", "description": "Real-time chat implementation using WebSocket. Supports direct messages and group channels.", "author_experience": "junior", "files": [{"filename": "handlers/chat.js", "language": "javascript", "lines_changed": 30}], "step_number": 2, "episode_budget": 1}, "state_text": "PR PR-017: Add WebSocket chat handler | Real-time chat implementation using WebSocket. Supports direct messages and grou", "action": {"action_type": "request_changes", "severity": null, "comment": null}, "action_text": "request_changes", "reward": 0.0, "next_state": {"pr_id": "PR-017", "title": "Add WebSocket chat handler", "description": "Real-time chat implementation using WebSocket. Supports direct messages and group channels.", "step_number": 2}, "next_state_text": "PR PR-017: Add WebSocket chat handler | Real-time chat implementation using WebSocket. Supports direct messages and grou", "done": true}