Decide what a coder session persists, and give the transcript a cursor Two questions were open: what a client writes into a thread's transcript, and how it gets back to one. Both turn out to be questions about limits. A payload is capped at 16,384 bytes and a listing returns at most fifty events. Measured against four real coder sessions from one afternoon, the payload cap is not the binding one — the largest tool result observed was 8.4 KB, and the model transcript already bounds a result to 4,000 characters, so the same bound keeps every event well inside it. The listing cap is: turn-level persistence fits in fifty with room to spare, and tool-level passes it on an ordinary session of thirteen turns and forty-two tool calls. So `list_events/2` takes an `:after` cursor and the route publishes each event's id. A history that cannot be read back is not persistence, and this was the one server change the decision required. What a session records: `turn.user`, one `tool.ran` per call carrying the bounded result, and `turn.assistant` with the turn's usage. Call and result are one event rather than two — they are one fact, and splitting them doubles the count against the cap for nothing. Deltas and reasoning are not recorded: deltas are how a reply arrives rather than what it is, and reasoning is display-only for the same reason it is absent from the model transcript. This is roughly ATIF's granularity, which is deliberate, since `/export` already writes a session that way and the two should not disagree about what a session was. Resume follows Codex, whose shape this vocabulary already follows: no argument shows recent threads filtered to the repository, a uuid takes one directly, `--last` skips the picker, `--all` drops the filter. `GET /api/v3/threads` is the list and the events route is the transcript; neither needs anything new. The audit records one question deliberately left open: what a resumed session sends to the model. A transcript is evidence rather than a provider-shaped chat history, and replaying a long one verbatim would reintroduce the context problem that bounding tool results just solved. 4153 tests pass.
Decide what a coder session persists, and give the transcript a cursor
Deploy story
What this commit did to the running system — joined from the forge receipt chain, the part a commit page elsewhere cannot show.
- pushed
- by user · WAL seq 290 · 2026-08-24T18:27:18.278229Z
Changed files
-
modified
docs/2026-08-24-coder-account-integration-audit.md -
modified
docs/forge-exit-rehearsals.md -
modified
lib/openagents/threads.ex -
modified
lib/openagents_web/controllers/thread_controller.ex -
modified
test/openagents/forge/sync_test.exs -
modified
test/openagents_web/controllers/thread_controller_test.exs
Diff
6 files changed, +171 -18
docs/2026-08-24-coder-account-integration-audit.md modified +95 -5
@@ -3,7 +3,8 @@
| 3 | 3 |
|
| 4 | 4 |
|
| 5 | 5 |
|
| 6 |
|
|
| 6 |
|
|
| 7 |
|
|
| 7 | 8 |
|
| 8 | 9 |
|
| 9 | 10 |
|
@@ -124,16 +125,105 @@ costs nothing. What costs something is deciding what happens when the login is
| 124 | 125 |
|
| 125 | 126 |
|
| 126 | 127 |
|
| 128 |
|
|
| 129 |
|
|
| 130 |
|
|
| 131 |
|
|
| 132 |
|
|
| 133 |
|
|
| 134 |
|
|
| 135 |
|
|
| 136 |
|
|
| 137 |
|
|
| 138 |
|
|
| 139 |
|
|
| 140 |
|
|
| 141 |
|
|
| 142 |
|
|
| 143 |
|
|
| 144 |
|
|
| 145 |
|
|
| 146 |
|
|
| 147 |
|
|
| 148 |
|
|
| 149 |
|
|
| 150 |
|
|
| 151 |
|
|
| 152 |
|
|
| 153 |
|
|
| 154 |
|
|
| 155 |
|
|
| 156 |
|
|
| 157 |
|
|
| 158 |
|
|
| 159 |
|
|
| 160 |
|
|
| 161 |
|
|
| 162 |
|
|
| 163 |
|
|
| 164 |
|
|
| 165 |
|
|
| 166 |
|
|
| 167 |
|
|
| 168 |
|
|
| 169 |
|
|
| 170 |
|
|
| 171 |
|
|
| 172 |
|
|
| 173 |
|
|
| 174 |
|
|
| 175 |
|
|
| 176 |
|
|
| 177 |
|
|
| 178 |
|
|
| 179 |
|
|
| 180 |
|
|
| 181 |
|
|
| 182 |
|
|
| 183 |
|
|
| 184 |
|
|
| 185 |
|
|
| 186 |
|
|
| 187 |
|
|
| 188 |
|
|
| 189 |
|
|
| 190 |
|
|
| 191 |
|
|
| 192 |
|
|
| 193 |
|
|
| 194 |
|
|
| 195 |
|
|
| 196 |
|
|
| 197 |
|
|
| 198 |
|
|
| 199 |
|
|
| 200 |
|
|
| 201 |
|
|
| 202 |
|
|
| 203 |
|
|
| 204 |
|
|
| 205 |
|
|
| 206 |
|
|
| 207 |
|
|
| 208 |
|
|
| 209 |
|
|
| 210 |
|
|
| 211 |
|
|
| 127 | 212 |
|
| 128 | 213 |
|
| 129 | 214 |
|
| 130 | 215 |
|
| 131 | 216 |
|
| 132 |
|
|
| 217 |
|
|
| 218 |
|
|
| 219 |
|
|
| 220 |
|
|
| 221 |
|
|
| 133 | 222 |
|
| 134 |
|
|
| 135 |
|
|
| 136 |
|
|
| 223 |
|
|
| 224 |
|
|
| 225 |
|
|
| 226 |
|
|
| 137 | 227 |
|
| 138 | 228 |
|
| 139 | 229 |
|
docs/forge-exit-rehearsals.md modified +7 -2
@@ -182,8 +182,13 @@ reported rather than reconciled silently.
| 182 | 182 |
|
| 183 | 183 |
|
| 184 | 184 |
|
| 185 |
|
|
| 186 |
|
|
| 185 |
|
|
| 186 |
|
|
| 187 |
|
|
| 188 |
|
|
| 189 |
|
|
| 190 |
|
|
| 191 |
|
|
| 187 | 192 |
|
| 188 | 193 |
|
| 189 | 194 |
|
lib/openagents/threads.ex modified +23 -1
@@ -192,7 +192,14 @@ defmodule OpenAgents.Threads do
| 192 | 192 |
|
| 193 | 193 |
|
| 194 | 194 |
|
| 195 |
|
|
| 195 |
|
|
| 196 |
|
|
| 197 |
|
|
| 198 |
|
|
| 199 |
|
|
| 200 |
|
|
| 201 |
|
|
| 202 |
|
|
| 196 | 203 |
|
| 197 | 204 |
|
| 198 | 205 |
|
@@ -202,9 +209,24 @@ defmodule OpenAgents.Threads do
| 202 | 209 |
|
| 203 | 210 |
|
| 204 | 211 |
|
| 212 |
|
|
| 205 | 213 |
|
| 206 | 214 |
|
| 207 | 215 |
|
| 216 |
|
|
| 217 |
|
|
| 218 |
|
|
| 219 |
|
|
| 220 |
|
|
| 221 |
|
|
| 222 |
|
|
| 223 |
|
|
| 224 |
|
|
| 225 |
|
|
| 226 |
|
|
| 227 |
|
|
| 228 |
|
|
| 229 |
|
|
| 208 | 230 |
|
| 209 | 231 |
|
| 210 | 232 |
|
lib/openagents_web/controllers/thread_controller.ex modified +11
@@ -242,6 +242,14 @@ defmodule OpenAgentsWeb.ThreadController do
| 242 | 242 |
|
| 243 | 243 |
|
| 244 | 244 |
|
| 245 |
|
|
| 246 |
|
|
| 247 |
|
|
| 248 |
|
|
| 249 |
|
|
| 250 |
|
|
| 251 |
|
|
| 252 |
|
|
| 245 | 253 |
|
| 246 | 254 |
|
| 247 | 255 |
|
@@ -326,8 +334,11 @@ defmodule OpenAgentsWeb.ThreadController do
| 326 | 334 |
|
| 327 | 335 |
|
| 328 | 336 |
|
| 337 |
|
|
| 338 |
|
|
| 329 | 339 |
|
| 330 | 340 |
|
| 341 |
|
|
| 331 | 342 |
|
| 332 | 343 |
|
| 333 | 344 |
|
test/openagents/forge/sync_test.exs modified +12 -10
@@ -205,10 +205,10 @@ defmodule OpenAgents.Forge.SyncTest do
| 205 | 205 |
|
| 206 | 206 |
|
| 207 | 207 |
|
| 208 |
|
|
| 208 |
|
|
| 209 | 209 |
|
| 210 | 210 |
|
| 211 |
|
|
| 211 |
|
|
| 212 | 212 |
|
| 213 | 213 |
|
| 214 | 214 |
|
@@ -236,27 +236,29 @@ defmodule OpenAgents.Forge.SyncTest do
| 236 | 236 |
|
| 237 | 237 |
|
| 238 | 238 |
|
| 239 |
|
|
| 240 | 239 |
|
| 241 | 240 |
|
| 242 |
|
|
| 243 | 241 |
|
| 244 |
|
|
| 245 |
|
|
| 242 |
|
|
| 243 |
|
|
| 244 |
|
|
| 245 |
|
|
| 246 |
|
|
| 246 | 247 |
|
| 247 | 248 |
|
| 248 | 249 |
|
| 249 | 250 |
|
| 251 |
|
|
| 250 | 252 |
|
| 253 |
|
|
| 251 | 254 |
|
| 252 |
|
|
| 253 |
|
|
| 255 |
|
|
| 256 |
|
|
| 254 | 257 |
|
| 255 | 258 |
|
| 256 |
|
|
| 257 | 259 |
|
| 258 | 260 |
|
| 259 |
|
|
| 261 |
|
|
| 260 | 262 |
|
| 261 | 263 |
|
| 262 | 264 |
|
test/openagents_web/controllers/thread_controller_test.exs modified +23
@@ -548,6 +548,29 @@ defmodule OpenAgentsWeb.ThreadControllerTest do
| 548 | 548 |
|
| 549 | 549 |
|
| 550 | 550 |
|
| 551 |
|
|
| 552 |
|
|
| 553 |
|
|
| 554 |
|
|
| 555 |
|
|
| 556 |
|
|
| 557 |
|
|
| 558 |
|
|
| 559 |
|
|
| 560 |
|
|
| 561 |
|
|
| 562 |
|
|
| 563 |
|
|
| 564 |
|
|
| 565 |
|
|
| 566 |
|
|
| 567 |
|
|
| 568 |
|
|
| 569 |
|
|
| 570 |
|
|
| 571 |
|
|
| 572 |
|
|
| 573 |
|
|
| 551 | 574 |
|
| 552 | 575 |
|
| 553 | 576 |
|