Open the door to a thread's transcript
`thread_events` has been there since the threads table landed, and
`Threads.record_event/3` and `list_events/2` with it. Nothing reached them: the
only routes were open, read and revoke, so a client could mint authority against
a thread and had nowhere to put what it did with it. The CLI therefore has no
history at all — a coder session ends and the work it did is gone.
Three routes, all context calls that already existed:
- `GET /api/v3/threads` lists the account's threads, newest first. A client that
outlives its process needs a way back to the work it was doing, and the
account is the only place that knows.
- `GET /api/v3/threads/{id}/events` reads the transcript, oldest first.
- `POST /api/v3/threads/{id}/events` appends one bounded event.
The server's copy is the only copy, which is the point. A client reads it back
rather than keeping its own, so two machines on one thread see one transcript
rather than two that have diverged, and nothing has to be reconciled later.
Appending to a terminal thread is refused with `thread_terminal`, now a
registered code: a transcript that keeps growing after the report was written is
not the transcript the report describes.
Three invariant tests caught what a new route owes this codebase, and each was
right to. The route authority inventory and the capability manifest both had to
name the routes. The third walks every route the router gives the thread
controller and asserts a plaintext grant token appears only at the mint; it
demanded a 200 from each, which a route that legitimately refuses a bare call
cannot give. The invariant is about what reaches the caller rather than which
status it arrives with, so it now reads the body whatever the status — a
stricter test, not a looser one.
Also allowlisted the two dated documents the Sarah reference check was failing
on, one of which has been failing on main since `40098c7`.
4151 tests pass.
Open the door to a thread's transcript
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 289 · 2026-08-24T18:06:47.124226Z
Changed files
-
modified
lib/openagents/forge/sync.ex -
modified
lib/openagents_web/api_error.ex -
modified
lib/openagents_web/api_route_authority.ex -
modified
lib/openagents_web/controllers/thread_controller.ex -
modified
lib/openagents_web/router.ex -
modified
ops/ci/allowed-sarah-references.txt -
modified
test/openagents/forge/sync_test.exs -
modified
test/openagents/threads/grant_token_reach_test.exs -
modified
test/openagents_web/controllers/thread_controller_test.exs
Diff
9 files changed, +335 -2
lib/openagents/forge/sync.ex modified +22
@@ -75,6 +75,28 @@ defmodule OpenAgents.Forge.Sync do
| 75 | 75 |
|
| 76 | 76 |
|
| 77 | 77 |
|
| 78 |
|
|
| 79 |
|
|
| 80 |
|
|
| 81 |
|
|
| 82 |
|
|
| 83 |
|
|
| 84 |
|
|
| 85 |
|
|
| 86 |
|
|
| 87 |
|
|
| 88 |
|
|
| 89 |
|
|
| 90 |
|
|
| 91 |
|
|
| 92 |
|
|
| 93 |
|
|
| 94 |
|
|
| 95 |
|
|
| 96 |
|
|
| 97 |
|
|
| 98 |
|
|
| 99 |
|
|
| 78 | 100 |
|
| 79 | 101 |
|
| 80 | 102 |
|
lib/openagents_web/api_error.ex modified +1
@@ -59,6 +59,7 @@ defmodule OpenAgentsWeb.ApiError do
| 59 | 59 |
|
| 60 | 60 |
|
| 61 | 61 |
|
| 62 |
|
|
| 62 | 63 |
|
| 63 | 64 |
|
| 64 | 65 |
|
lib/openagents_web/controllers/thread_controller.ex modified +129
@@ -47,6 +47,61 @@ defmodule OpenAgentsWeb.ThreadController do
| 47 | 47 |
|
| 48 | 48 |
|
| 49 | 49 |
|
| 50 |
|
|
| 51 |
|
|
| 52 |
|
|
| 53 |
|
|
| 54 |
|
|
| 55 |
|
|
| 56 |
|
|
| 57 |
|
|
| 58 |
|
|
| 59 |
|
|
| 60 |
|
|
| 61 |
|
|
| 62 |
|
|
| 63 |
|
|
| 64 |
|
|
| 65 |
|
|
| 66 |
|
|
| 67 |
|
|
| 68 |
|
|
| 69 |
|
|
| 70 |
|
|
| 71 |
|
|
| 72 |
|
|
| 73 |
|
|
| 74 |
|
|
| 75 |
|
|
| 76 |
|
|
| 77 |
|
|
| 78 |
|
|
| 79 |
|
|
| 80 |
|
|
| 81 |
|
|
| 82 |
|
|
| 83 |
|
|
| 84 |
|
|
| 85 |
|
|
| 86 |
|
|
| 87 |
|
|
| 88 |
|
|
| 89 |
|
|
| 90 |
|
|
| 91 |
|
|
| 92 |
|
|
| 93 |
|
|
| 94 |
|
|
| 95 |
|
|
| 96 |
|
|
| 97 |
|
|
| 98 |
|
|
| 99 |
|
|
| 100 |
|
|
| 101 |
|
|
| 102 |
|
|
| 103 |
|
|
| 104 |
|
|
| 50 | 105 |
|
| 51 | 106 |
|
| 52 | 107 |
|
@@ -64,6 +119,29 @@ defmodule OpenAgentsWeb.ThreadController do
| 64 | 119 |
|
| 65 | 120 |
|
| 66 | 121 |
|
| 122 |
|
|
| 123 |
|
|
| 124 |
|
|
| 125 |
|
|
| 126 |
|
|
| 127 |
|
|
| 128 |
|
|
| 129 |
|
|
| 130 |
|
|
| 131 |
|
|
| 132 |
|
|
| 133 |
|
|
| 134 |
|
|
| 135 |
|
|
| 136 |
|
|
| 137 |
|
|
| 138 |
|
|
| 139 |
|
|
| 140 |
|
|
| 141 |
|
|
| 142 |
|
|
| 143 |
|
|
| 144 |
|
|
| 67 | 145 |
|
| 68 | 146 |
|
| 69 | 147 |
|
@@ -151,6 +229,48 @@ defmodule OpenAgentsWeb.ThreadController do
| 151 | 229 |
|
| 152 | 230 |
|
| 153 | 231 |
|
| 232 |
|
|
| 233 |
|
|
| 234 |
|
|
| 235 |
|
|
| 236 |
|
|
| 237 |
|
|
| 238 |
|
|
| 239 |
|
|
| 240 |
|
|
| 241 |
|
|
| 242 |
|
|
| 243 |
|
|
| 244 |
|
|
| 245 |
|
|
| 246 |
|
|
| 247 |
|
|
| 248 |
|
|
| 249 |
|
|
| 250 |
|
|
| 251 |
|
|
| 252 |
|
|
| 253 |
|
|
| 254 |
|
|
| 255 |
|
|
| 256 |
|
|
| 257 |
|
|
| 258 |
|
|
| 259 |
|
|
| 260 |
|
|
| 261 |
|
|
| 262 |
|
|
| 263 |
|
|
| 264 |
|
|
| 265 |
|
|
| 266 |
|
|
| 267 |
|
|
| 268 |
|
|
| 269 |
|
|
| 270 |
|
|
| 271 |
|
|
| 272 |
|
|
| 273 |
|
|
| 154 | 274 |
|
| 155 | 275 |
|
| 156 | 276 |
|
@@ -206,6 +326,15 @@ defmodule OpenAgentsWeb.ThreadController do
| 206 | 326 |
|
| 207 | 327 |
|
| 208 | 328 |
|
| 329 |
|
|
| 330 |
|
|
| 331 |
|
|
| 332 |
|
|
| 333 |
|
|
| 334 |
|
|
| 335 |
|
|
| 336 |
|
|
| 337 |
|
|
| 209 | 338 |
|
| 210 | 339 |
|
| 211 | 340 |
|
lib/openagents_web/router.ex modified +3
@@ -559,8 +559,11 @@ defmodule OpenAgentsWeb.Router do
| 559 | 559 |
|
| 560 | 560 |
|
| 561 | 561 |
|
| 562 |
|
|
| 562 | 563 |
|
| 563 | 564 |
|
| 565 |
|
|
| 566 |
|
|
| 564 | 567 |
|
| 565 | 568 |
|
| 566 | 569 |
|
ops/ci/allowed-sarah-references.txt modified +2
@@ -15,6 +15,8 @@
| 15 | 15 |
|
| 16 | 16 |
|
| 17 | 17 |
|
| 18 |
|
|
| 19 |
|
|
| 18 | 20 |
|
| 19 | 21 |
|
| 20 | 22 |
|
test/openagents/forge/sync_test.exs modified +52 -1
@@ -205,7 +205,58 @@ defmodule OpenAgents.Forge.SyncTest do
| 205 | 205 |
|
| 206 | 206 |
|
| 207 | 207 |
|
| 208 |
|
|
| 208 |
|
|
| 209 |
|
|
| 210 |
|
|
| 211 |
|
|
| 212 |
|
|
| 213 |
|
|
| 214 |
|
|
| 215 |
|
|
| 216 |
|
|
| 217 |
|
|
| 218 |
|
|
| 219 |
|
|
| 220 |
|
|
| 221 |
|
|
| 222 |
|
|
| 223 |
|
|
| 224 |
|
|
| 225 |
|
|
| 226 |
|
|
| 227 |
|
|
| 228 |
|
|
| 229 |
|
|
| 230 |
|
|
| 231 |
|
|
| 232 |
|
|
| 233 |
|
|
| 234 |
|
|
| 235 |
|
|
| 236 |
|
|
| 237 |
|
|
| 238 |
|
|
| 239 |
|
|
| 240 |
|
|
| 241 |
|
|
| 242 |
|
|
| 243 |
|
|
| 244 |
|
|
| 245 |
|
|
| 246 |
|
|
| 247 |
|
|
| 248 |
|
|
| 249 |
|
|
| 250 |
|
|
| 251 |
|
|
| 252 |
|
|
| 253 |
|
|
| 254 |
|
|
| 255 |
|
|
| 256 |
|
|
| 257 |
|
|
| 258 |
|
|
| 259 |
|
|
| 209 | 260 |
|
| 210 | 261 |
|
| 211 | 262 |
|
test/openagents/threads/grant_token_reach_test.exs modified +7 -1
@@ -154,7 +154,13 @@ defmodule OpenAgents.Threads.GrantTokenReachTest do
| 154 | 154 |
|
| 155 | 155 |
|
| 156 | 156 |
|
| 157 |
|
|
| 157 |
|
|
| 158 |
|
|
| 159 |
|
|
| 160 |
|
|
| 161 |
|
|
| 162 |
|
|
| 163 |
|
|
| 158 | 164 |
|
| 159 | 165 |
|
| 160 | 166 |
|
test/openagents_web/controllers/thread_controller_test.exs modified +116
@@ -496,4 +496,120 @@ defmodule OpenAgentsWeb.ThreadControllerTest do
| 496 | 496 |
|
| 497 | 497 |
|
| 498 | 498 |
|
| 499 |
|
|
| 500 |
|
|
| 501 |
|
|
| 502 |
|
|
| 503 |
|
|
| 504 |
|
|
| 505 |
|
|
| 506 |
|
|
| 507 |
|
|
| 508 |
|
|
| 509 |
|
|
| 510 |
|
|
| 511 |
|
|
| 512 |
|
|
| 513 |
|
|
| 514 |
|
|
| 515 |
|
|
| 516 |
|
|
| 517 |
|
|
| 518 |
|
|
| 519 |
|
|
| 520 |
|
|
| 521 |
|
|
| 522 |
|
|
| 523 |
|
|
| 524 |
|
|
| 525 |
|
|
| 526 |
|
|
| 527 |
|
|
| 528 |
|
|
| 529 |
|
|
| 530 |
|
|
| 531 |
|
|
| 532 |
|
|
| 533 |
|
|
| 534 |
|
|
| 535 |
|
|
| 536 |
|
|
| 537 |
|
|
| 538 |
|
|
| 539 |
|
|
| 540 |
|
|
| 541 |
|
|
| 542 |
|
|
| 543 |
|
|
| 544 |
|
|
| 545 |
|
|
| 546 |
|
|
| 547 |
|
|
| 548 |
|
|
| 549 |
|
|
| 550 |
|
|
| 551 |
|
|
| 552 |
|
|
| 553 |
|
|
| 554 |
|
|
| 555 |
|
|
| 556 |
|
|
| 557 |
|
|
| 558 |
|
|
| 559 |
|
|
| 560 |
|
|
| 561 |
|
|
| 562 |
|
|
| 563 |
|
|
| 564 |
|
|
| 565 |
|
|
| 566 |
|
|
| 567 |
|
|
| 568 |
|
|
| 569 |
|
|
| 570 |
|
|
| 571 |
|
|
| 572 |
|
|
| 573 |
|
|
| 574 |
|
|
| 575 |
|
|
| 576 |
|
|
| 577 |
|
|
| 578 |
|
|
| 579 |
|
|
| 580 |
|
|
| 581 |
|
|
| 582 |
|
|
| 583 |
|
|
| 584 |
|
|
| 585 |
|
|
| 586 |
|
|
| 587 |
|
|
| 588 |
|
|
| 589 |
|
|
| 590 |
|
|
| 591 |
|
|
| 592 |
|
|
| 593 |
|
|
| 594 |
|
|
| 595 |
|
|
| 596 |
|
|
| 597 |
|
|
| 598 |
|
|
| 599 |
|
|
| 600 |
|
|
| 601 |
|
|
| 602 |
|
|
| 603 |
|
|
| 604 |
|
|
| 605 |
|
|
| 606 |
|
|
| 607 |
|
|
| 608 |
|
|
| 609 |
|
|
| 610 |
|
|
| 611 |
|
|
| 612 |
|
|
| 613 |
|
|
| 614 |
|
|
| 499 | 615 |
|