@jr2/orchestrator 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/README.md +20 -2
  2. package/console/components/app.ts +2 -0
  3. package/console/components/fleet.ts +14 -1
  4. package/console/components/machine-pane.ts +41 -2
  5. package/console/main.ts +13 -1
  6. package/console/store.ts +102 -6
  7. package/console/style.css +21 -0
  8. package/docs/agents-block.md +5 -0
  9. package/docs/concepts/agents-and-turns.md +478 -0
  10. package/docs/concepts/architecture.md +243 -0
  11. package/docs/concepts/charts.md +146 -0
  12. package/docs/concepts/composition.md +357 -0
  13. package/docs/concepts/converge.md +257 -0
  14. package/docs/concepts/durable-runs.md +189 -0
  15. package/docs/concepts/effects.md +658 -0
  16. package/docs/concepts/gates.md +208 -0
  17. package/docs/concepts/machines-and-workflows.md +298 -0
  18. package/docs/concepts/pools-and-sources.md +230 -0
  19. package/docs/concepts/secrets-and-trust.md +306 -0
  20. package/docs/concepts/the-menu.md +381 -0
  21. package/docs/concepts/workspaces.md +756 -0
  22. package/docs/get-started/a-model-decides.md +563 -0
  23. package/docs/get-started/an-agent-in-a-sandbox.md +383 -0
  24. package/docs/get-started/connect-a-model.md +248 -0
  25. package/docs/get-started/create-an-instance.md +194 -0
  26. package/docs/get-started/have-your-assistant-write-a-machine.md +993 -0
  27. package/docs/get-started/install.md +130 -0
  28. package/docs/guides/add-tools-to-the-sandbox.md +308 -0
  29. package/docs/guides/answer-a-gate.md +304 -0
  30. package/docs/guides/bind-open-parts.md +224 -0
  31. package/docs/guides/cancel-a-run.md +146 -0
  32. package/docs/guides/clean-up.md +206 -0
  33. package/docs/guides/cut-a-worktree.md +560 -0
  34. package/docs/guides/fix-a-failed-converge.md +361 -0
  35. package/docs/guides/give-the-cluster-git-credentials.md +222 -0
  36. package/docs/guides/iterate-on-a-machine-on-kind.md +190 -0
  37. package/docs/guides/let-an-agent-write-a-chart.md +230 -0
  38. package/docs/guides/look-inside-a-sandbox.md +177 -0
  39. package/docs/guides/mirror-the-kit-images.md +176 -0
  40. package/docs/guides/move-from-kind-to-a-shared-cluster.md +318 -0
  41. package/docs/guides/open-the-console.md +91 -0
  42. package/docs/guides/publish-a-machine-as-an-npm-package.md +350 -0
  43. package/docs/guides/push-and-sign-a-branch.md +532 -0
  44. package/docs/guides/run-a-chart-by-name.md +270 -0
  45. package/docs/guides/run-a-command-or-call-a-url.md +587 -0
  46. package/docs/guides/run-one-worker-per-item.md +322 -0
  47. package/docs/guides/set-an-agents-access-and-dials.md +420 -0
  48. package/docs/guides/size-a-workspace.md +217 -0
  49. package/docs/guides/start-a-run-from-a-run.md +237 -0
  50. package/docs/guides/start-a-run.md +207 -0
  51. package/docs/guides/upgrade-the-kit-version.md +240 -0
  52. package/docs/guides/use-a-hosted-provider.md +214 -0
  53. package/docs/guides/use-a-local-model.md +313 -0
  54. package/docs/guides/watch-a-run.md +349 -0
  55. package/docs/guides/write-a-workflow.md +318 -0
  56. package/docs/index.md +44 -0
  57. package/docs/llms.txt +237 -0
  58. package/docs/reference/authoring-surface/agent.md +151 -0
  59. package/docs/reference/authoring-surface/answer.md +156 -0
  60. package/docs/reference/authoring-surface/arg.md +82 -0
  61. package/docs/reference/authoring-surface/basic.md +62 -0
  62. package/docs/reference/authoring-surface/bearer.md +53 -0
  63. package/docs/reference/authoring-surface/branchname.md +15 -0
  64. package/docs/reference/authoring-surface/chartschema.md +23 -0
  65. package/docs/reference/authoring-surface/chartschemafor.md +48 -0
  66. package/docs/reference/authoring-surface/command.md +206 -0
  67. package/docs/reference/authoring-surface/customize.md +64 -0
  68. package/docs/reference/authoring-surface/defineconfig.md +41 -0
  69. package/docs/reference/authoring-surface/defineevent.md +114 -0
  70. package/docs/reference/authoring-surface/dispatch.md +126 -0
  71. package/docs/reference/authoring-surface/fail.md +96 -0
  72. package/docs/reference/authoring-surface/file.md +142 -0
  73. package/docs/reference/authoring-surface/frompick.md +277 -0
  74. package/docs/reference/authoring-surface/http.md +259 -0
  75. package/docs/reference/authoring-surface/isfailure.md +58 -0
  76. package/docs/reference/authoring-surface/isready.md +14 -0
  77. package/docs/reference/authoring-surface/jr2setup.md +237 -0
  78. package/docs/reference/authoring-surface/open.md +105 -0
  79. package/docs/reference/authoring-surface/openbody.md +86 -0
  80. package/docs/reference/authoring-surface/paramsof.md +143 -0
  81. package/docs/reference/authoring-surface/pool.md +186 -0
  82. package/docs/reference/authoring-surface/push.md +130 -0
  83. package/docs/reference/authoring-surface/readyof.md +21 -0
  84. package/docs/reference/authoring-surface/secret.md +139 -0
  85. package/docs/reference/authoring-surface/sentby.md +83 -0
  86. package/docs/reference/authoring-surface/source.md +51 -0
  87. package/docs/reference/authoring-surface/text.md +62 -0
  88. package/docs/reference/authoring-surface/type-agentdeclaration.md +27 -0
  89. package/docs/reference/authoring-surface/type-agentdefinition.md +80 -0
  90. package/docs/reference/authoring-surface/type-agentlogic.md +15 -0
  91. package/docs/reference/authoring-surface/type-agentslots.md +15 -0
  92. package/docs/reference/authoring-surface/type-answeraction.md +12 -0
  93. package/docs/reference/authoring-surface/type-anyframepath.md +14 -0
  94. package/docs/reference/authoring-surface/type-anyworktreepath.md +15 -0
  95. package/docs/reference/authoring-surface/type-arg.md +19 -0
  96. package/docs/reference/authoring-surface/type-argnames.md +12 -0
  97. package/docs/reference/authoring-surface/type-bindactors.md +14 -0
  98. package/docs/reference/authoring-surface/type-binding.md +61 -0
  99. package/docs/reference/authoring-surface/type-bindingof.md +12 -0
  100. package/docs/reference/authoring-surface/type-bodyacceptsdoor.md +15 -0
  101. package/docs/reference/authoring-surface/type-bodyacceptsslots.md +17 -0
  102. package/docs/reference/authoring-surface/type-ceilings.md +41 -0
  103. package/docs/reference/authoring-surface/type-chainlink.md +19 -0
  104. package/docs/reference/authoring-surface/type-chartaction.md +46 -0
  105. package/docs/reference/authoring-surface/type-chartagent.md +28 -0
  106. package/docs/reference/authoring-surface/type-chartevent.md +20 -0
  107. package/docs/reference/authoring-surface/type-chartguard.md +20 -0
  108. package/docs/reference/authoring-surface/type-chartinvoke.md +28 -0
  109. package/docs/reference/authoring-surface/type-chartjson.md +14 -0
  110. package/docs/reference/authoring-surface/type-chartstate.md +46 -0
  111. package/docs/reference/authoring-surface/type-charttext.md +40 -0
  112. package/docs/reference/authoring-surface/type-charttransition.md +22 -0
  113. package/docs/reference/authoring-surface/type-charttransitions.md +14 -0
  114. package/docs/reference/authoring-surface/type-chartvalue.md +15 -0
  115. package/docs/reference/authoring-surface/type-childat.md +12 -0
  116. package/docs/reference/authoring-surface/type-childslots.md +12 -0
  117. package/docs/reference/authoring-surface/type-commandenv.md +15 -0
  118. package/docs/reference/authoring-surface/type-commandinput.md +20 -0
  119. package/docs/reference/authoring-surface/type-commandoptions.md +56 -0
  120. package/docs/reference/authoring-surface/type-commandoutput.md +122 -0
  121. package/docs/reference/authoring-surface/type-customize.md +111 -0
  122. package/docs/reference/authoring-surface/type-dispatchdefinition.md +39 -0
  123. package/docs/reference/authoring-surface/type-dispatchinput.md +14 -0
  124. package/docs/reference/authoring-surface/type-dispatchopenparts.md +14 -0
  125. package/docs/reference/authoring-surface/type-dispatchoutput.md +72 -0
  126. package/docs/reference/authoring-surface/type-doorlessinput.md +19 -0
  127. package/docs/reference/authoring-surface/type-duration.md +15 -0
  128. package/docs/reference/authoring-surface/type-effectbinding.md +93 -0
  129. package/docs/reference/authoring-surface/type-effectlogic.md +12 -0
  130. package/docs/reference/authoring-surface/type-envopenparts.md +14 -0
  131. package/docs/reference/authoring-surface/type-eventaudience.md +27 -0
  132. package/docs/reference/authoring-surface/type-eventdef.md +45 -0
  133. package/docs/reference/authoring-surface/type-eventfrom.md +16 -0
  134. package/docs/reference/authoring-surface/type-eventsemantics.md +26 -0
  135. package/docs/reference/authoring-surface/type-execoutcome.md +34 -0
  136. package/docs/reference/authoring-surface/type-failslot.md +14 -0
  137. package/docs/reference/authoring-surface/type-failure.md +19 -0
  138. package/docs/reference/authoring-surface/type-failureinput.md +20 -0
  139. package/docs/reference/authoring-surface/type-filebody.md +37 -0
  140. package/docs/reference/authoring-surface/type-framepath.md +14 -0
  141. package/docs/reference/authoring-surface/type-frominput.md +14 -0
  142. package/docs/reference/authoring-surface/type-hostinjectedinput.md +56 -0
  143. package/docs/reference/authoring-surface/type-httpdefinition.md +104 -0
  144. package/docs/reference/authoring-surface/type-httpfileinput.md +20 -0
  145. package/docs/reference/authoring-surface/type-httpinput.md +12 -0
  146. package/docs/reference/authoring-surface/type-httpmethod.md +14 -0
  147. package/docs/reference/authoring-surface/type-httpopenparts.md +12 -0
  148. package/docs/reference/authoring-surface/type-httpoutput.md +95 -0
  149. package/docs/reference/authoring-surface/type-httprequestparts.md +33 -0
  150. package/docs/reference/authoring-surface/type-jr2config.md +126 -0
  151. package/docs/reference/authoring-surface/type-lateroutcome.md +21 -0
  152. package/docs/reference/authoring-surface/type-lends.md +38 -0
  153. package/docs/reference/authoring-surface/type-logicat.md +12 -0
  154. package/docs/reference/authoring-surface/type-markedif.md +12 -0
  155. package/docs/reference/authoring-surface/type-mergedactors.md +12 -0
  156. package/docs/reference/authoring-surface/type-namedsecret.md +25 -0
  157. package/docs/reference/authoring-surface/type-namestart.md +77 -0
  158. package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +27 -0
  159. package/docs/reference/authoring-surface/type-notworktreekeys.md +12 -0
  160. package/docs/reference/authoring-surface/type-openbodydeclaration.md +40 -0
  161. package/docs/reference/authoring-surface/type-openbodylogic.md +14 -0
  162. package/docs/reference/authoring-surface/type-openbodyoutput.md +42 -0
  163. package/docs/reference/authoring-surface/type-openbodyslot.md +18 -0
  164. package/docs/reference/authoring-surface/type-opencommandinput.md +22 -0
  165. package/docs/reference/authoring-surface/type-openeffect.md +12 -0
  166. package/docs/reference/authoring-surface/type-openeffectslots.md +12 -0
  167. package/docs/reference/authoring-surface/type-openof.md +12 -0
  168. package/docs/reference/authoring-surface/type-opensecret.md +23 -0
  169. package/docs/reference/authoring-surface/type-opensecretmark.md +12 -0
  170. package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +26 -0
  171. package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +27 -0
  172. package/docs/reference/authoring-surface/type-poolmachine.md +28 -0
  173. package/docs/reference/authoring-surface/type-poolnextinput.md +22 -0
  174. package/docs/reference/authoring-surface/type-poolspec.md +60 -0
  175. package/docs/reference/authoring-surface/type-pushinput.md +34 -0
  176. package/docs/reference/authoring-surface/type-pushoptions.md +79 -0
  177. package/docs/reference/authoring-surface/type-pushoutput.md +149 -0
  178. package/docs/reference/authoring-surface/type-pushwireoutput.md +12 -0
  179. package/docs/reference/authoring-surface/type-quantity.md +14 -0
  180. package/docs/reference/authoring-surface/type-reached.md +12 -0
  181. package/docs/reference/authoring-surface/type-reposlot.md +70 -0
  182. package/docs/reference/authoring-surface/type-reposlotsof.md +16 -0
  183. package/docs/reference/authoring-surface/type-sandboxoptions.md +84 -0
  184. package/docs/reference/authoring-surface/type-secret.md +25 -0
  185. package/docs/reference/authoring-surface/type-sender.md +19 -0
  186. package/docs/reference/authoring-surface/type-sentbyguards.md +12 -0
  187. package/docs/reference/authoring-surface/type-size.md +85 -0
  188. package/docs/reference/authoring-surface/type-slothandles.md +24 -0
  189. package/docs/reference/authoring-surface/type-sourcenextresult.md +17 -0
  190. package/docs/reference/authoring-surface/type-sourcespec.md +44 -0
  191. package/docs/reference/authoring-surface/type-syncstate.md +12 -0
  192. package/docs/reference/authoring-surface/type-text.md +19 -0
  193. package/docs/reference/authoring-surface/type-textpart.md +24 -0
  194. package/docs/reference/authoring-surface/type-thinkinglevel.md +39 -0
  195. package/docs/reference/authoring-surface/type-toparameterizedobject.md +14 -0
  196. package/docs/reference/authoring-surface/type-toprovidedactor.md +14 -0
  197. package/docs/reference/authoring-surface/type-unknown.md +21 -0
  198. package/docs/reference/authoring-surface/type-usercontainer.md +77 -0
  199. package/docs/reference/authoring-surface/type-withoutemptyindex.md +20 -0
  200. package/docs/reference/authoring-surface/type-workflowevent.md +46 -0
  201. package/docs/reference/authoring-surface/type-workspaceaccess.md +16 -0
  202. package/docs/reference/authoring-surface/type-workspaced.md +115 -0
  203. package/docs/reference/authoring-surface/type-workspacehandles.md +22 -0
  204. package/docs/reference/authoring-surface/type-workspacemachine.md +29 -0
  205. package/docs/reference/authoring-surface/type-workspaceof.md +13 -0
  206. package/docs/reference/authoring-surface/type-workspaceoptions.md +27 -0
  207. package/docs/reference/authoring-surface/type-worktreefound.md +16 -0
  208. package/docs/reference/authoring-surface/type-worktreeinput.md +56 -0
  209. package/docs/reference/authoring-surface/type-worktreekey.md +14 -0
  210. package/docs/reference/authoring-surface/type-worktreeoptions.md +29 -0
  211. package/docs/reference/authoring-surface/type-worktreeoutput.md +45 -0
  212. package/docs/reference/authoring-surface/type-worktreepath.md +16 -0
  213. package/docs/reference/authoring-surface/type-worktreeready.md +37 -0
  214. package/docs/reference/authoring-surface/type-worktreerefused.md +21 -0
  215. package/docs/reference/authoring-surface/workspace.md +287 -0
  216. package/docs/reference/authoring-surface/worktree.md +71 -0
  217. package/docs/reference/authoring-surface.md +217 -0
  218. package/docs/reference/cli.md +433 -0
  219. package/docs/reference/config.md +765 -0
  220. package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +114 -0
  221. package/docs/reference/decisions/0002-duplex-streaming-actor.md +117 -0
  222. package/docs/reference/decisions/0004-worktree-provisioning-model.md +130 -0
  223. package/docs/reference/decisions/0005-sandbox-pod-composition.md +240 -0
  224. package/docs/reference/decisions/0006-agent-control-surface.md +50 -0
  225. package/docs/reference/decisions/0007-durable-machine-state.md +109 -0
  226. package/docs/reference/decisions/0008-orchestrator-as-deployed-app.md +60 -0
  227. package/docs/reference/decisions/0009-cli-and-instance-interface.md +275 -0
  228. package/docs/reference/decisions/0010-bdd-acceptance-tests.md +160 -0
  229. package/docs/reference/decisions/0011-workflow-defined-events.md +141 -0
  230. package/docs/reference/decisions/0012-workspace-wrapper-machine.md +103 -0
  231. package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +175 -0
  232. package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +95 -0
  233. package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +271 -0
  234. package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +126 -0
  235. package/docs/reference/decisions/0017-pool-over-a-source-port.md +71 -0
  236. package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +111 -0
  237. package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +287 -0
  238. package/docs/reference/decisions/0020-private-ca-trust-is-a-named-concept.md +60 -0
  239. package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +101 -0
  240. package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +103 -0
  241. package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +175 -0
  242. package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +436 -0
  243. package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +65 -0
  244. package/docs/reference/decisions/0026-a-turn-that-is-over-is-never-prompted.md +62 -0
  245. package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +245 -0
  246. package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +90 -0
  247. package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +154 -0
  248. package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +100 -0
  249. package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +193 -0
  250. package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +61 -0
  251. package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +126 -0
  252. package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +57 -0
  253. package/docs/reference/decisions/0035-a-runaway-turn-is-ended-rerolled-once-then-a-fault.md +92 -0
  254. package/docs/reference/decisions/0036-a-turn-compacts-its-own-context-mid-flight.md +138 -0
  255. package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +196 -0
  256. package/docs/reference/decisions/0038-jr2-up-builds-every-image-it-deploys.md +170 -0
  257. package/docs/reference/decisions/0039-image-garbage-collects-by-reachability.md +115 -0
  258. package/docs/reference/decisions/0041-a-build-the-host-already-holds-is-not-spent-again.md +64 -0
  259. package/docs/reference/decisions/0042-ready-is-not-routable-an-admission-retries-its-connection.md +142 -0
  260. package/docs/reference/decisions/0043-the-kit-is-tested-as-installed-a-local-registry-stands-in-for-npm.md +170 -0
  261. package/docs/reference/decisions/0044-kit-images-live-at-a-canonical-home-a-self-host-mirrors-it.md +85 -0
  262. package/docs/reference/decisions/0045-the-platform-joins-the-image-address-and-the-cluster-chooses-it.md +82 -0
  263. package/docs/reference/decisions/0046-a-converge-failure-carries-its-diagnosis.md +34 -0
  264. package/docs/reference/decisions/0047-the-git-ssh-key-source-is-the-users-choice.md +47 -0
  265. package/docs/reference/decisions/0048-the-orchestrator-boots-without-its-repos.md +36 -0
  266. package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +126 -0
  267. package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +73 -0
  268. package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +238 -0
  269. package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +86 -0
  270. package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +123 -0
  271. package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +126 -0
  272. package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +107 -0
  273. package/docs/reference/decisions/0056-a-global-jr2-hands-off-to-the-instances-own-and-an-instance-has-one-kit-version.md +62 -0
  274. package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +152 -0
  275. package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +108 -0
  276. package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +427 -0
  277. package/docs/reference/decisions/0060-a-workspace-states-its-size-and-jr2-reserves-all-of-it.md +111 -0
  278. package/docs/reference/decisions/0061-a-memory-kill-ends-the-agents-processes-not-the-harness.md +83 -0
  279. package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +239 -0
  280. package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +82 -0
  281. package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +79 -0
  282. package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +65 -0
  283. package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +552 -0
  284. package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +458 -0
  285. package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +475 -0
  286. package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +180 -0
  287. package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +334 -0
  288. package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +183 -0
  289. package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +144 -0
  290. package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +122 -0
  291. package/docs/reference/decisions/0074-an-unrouted-mechanism-event-is-refused-at-load-and-faults-the-run.md +76 -0
  292. package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +295 -0
  293. package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +320 -0
  294. package/docs/reference/decisions/0077-jr2-requires-landlock-on-every-sandbox-node.md +79 -0
  295. package/docs/reference/decisions.md +86 -0
  296. package/docs/reference/glossary.md +687 -0
  297. package/docs/reference/http-api.md +1386 -0
  298. package/docs/reference/machines.md +189 -0
  299. package/docs/reference/mechanism-events.md +72 -0
  300. package/docs/why.md +207 -0
  301. package/package.json +5 -3
  302. package/src/actor.ts +694 -106
  303. package/src/agent.ts +114 -38
  304. package/src/ambient.ts +3 -4
  305. package/src/assembly-checks.ts +189 -7
  306. package/src/cause.ts +234 -0
  307. package/src/chart.ts +345 -46
  308. package/src/charts.ts +43 -8
  309. package/src/config.ts +440 -178
  310. package/src/custodian.lua +17 -5
  311. package/src/custodian.ts +325 -99
  312. package/src/customize.ts +199 -49
  313. package/src/dispatch-effect.ts +945 -0
  314. package/src/door-compat.ts +217 -0
  315. package/src/durability.ts +11 -4
  316. package/src/effect-checks.ts +50 -3
  317. package/src/effect.ts +641 -128
  318. package/src/effector-wire.ts +165 -13
  319. package/src/fail.ts +222 -0
  320. package/src/harness-client.ts +587 -50
  321. package/src/harness-env.ts +33 -0
  322. package/src/held-secrets.ts +125 -16
  323. package/src/holds.ts +3 -0
  324. package/src/http-effect.ts +556 -58
  325. package/src/http.ts +480 -30
  326. package/src/index.ts +74 -82
  327. package/src/instance.ts +68 -8
  328. package/src/internal.ts +85 -0
  329. package/src/kube-client.ts +6 -3
  330. package/src/machine-doc.ts +24 -7
  331. package/src/mechanism-routes.ts +168 -0
  332. package/src/model-keys.generated.ts +53 -0
  333. package/src/model-keys.ts +42 -58
  334. package/src/names.ts +19 -6
  335. package/src/notices.ts +483 -41
  336. package/src/open-body.ts +242 -40
  337. package/src/open-effect.ts +81 -8
  338. package/src/open.ts +90 -6
  339. package/src/parts.ts +213 -30
  340. package/src/party.ts +101 -2
  341. package/src/pick.ts +497 -11
  342. package/src/pool.ts +282 -50
  343. package/src/registration.ts +133 -12
  344. package/src/repo-identity.ts +7 -3
  345. package/src/repos.ts +22 -3
  346. package/src/run-host.ts +665 -45
  347. package/src/run-output.ts +38 -0
  348. package/src/sandbox-effect.ts +457 -71
  349. package/src/sandbox-kube.ts +66 -17
  350. package/src/secret-placement.ts +59 -17
  351. package/src/server.ts +3 -0
  352. package/src/setup.ts +325 -62
  353. package/src/size.ts +121 -9
  354. package/src/snapshot-store.ts +54 -10
  355. package/src/stub-harness.ts +44 -16
  356. package/src/timers.ts +14 -1
  357. package/src/tokens.ts +107 -32
  358. package/src/vocabulary.ts +88 -14
  359. package/src/wire.ts +100 -26
  360. package/src/workspace.ts +771 -238
  361. package/src/worktree.ts +249 -0
@@ -0,0 +1,552 @@
1
+ # A `@model` tier runs a real model, and a change to what the model reads runs the tier
2
+
3
+ Every tier fakes the model. The default e2e tier holds a stub Harness; conformance and `@kind` run the stock Harness
4
+ against a scripted provider that chooses each Turn's shape
5
+ ([ADR-0027](0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md),
6
+ [ADR-0038](0038-jr2-up-builds-every-image-it-deploys.md)); `@dist` runs `ping`. So no suite can see a change in what a
7
+ model _does_ with what jr2 shows it. The evidence that such changes are large sits in prose:
8
+ [ADR-0029](0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md) and
9
+ [ADR-0062](0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md) measured the Allowed picks by hand on the
10
+ home-lab vLLM model — 0/10 obeyed ahead of the prompt, 10/10 after it — and nothing re-runs that measurement when
11
+ `briefing.ts`, the Menu's rendering, the Working tools' descriptions, Compaction, or the pi pin changes.
12
+ `briefing.test.ts` pins the _order_ of the text; it cannot tell whether a model still obeys it. And the paths a real
13
+ Agent takes through the kit as a whole — read a Repo, edit in a Worktree, run the tests, commit, hand off, be refused,
14
+ recover, finish — are exercised only one scripted tool call at a time.
15
+
16
+ ## Decision
17
+
18
+ - **An opt-in `@model` tier: the `@kind` tier with the last fake removed.** Same shared vanilla kind cluster, same
19
+ bring-up (`just e2e-kind-up`), same `jr2 up` per scenario into a fresh namespace, same seed Repo, same Custodian path
20
+ — the endpoint's key is a Held secret bound to its host, and the Harness container holds a Stand-in
21
+ ([ADR-0059](0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md)). What changes is the provider the
22
+ Custodian swaps toward: a real model endpoint instead of the World's scripted one. The pod runs the stock Harness, the
23
+ model originates every tool call, and the wire, the container boundary, the git transport and the Machine are all the
24
+ product's own. Tagged `@model`, profile `model` in `cucumber.json`, `just e2e-model`, excluded from the default
25
+ profile and from `@kind`.
26
+ - **Two kinds of scenario: claims and the run.** A **claim** scenario re-states one ADR's measured claim as trials with
27
+ a floor: a Turn obeys its Allowed picks against a prompt that argues for another (ADR-0029, ADR-0062); an Agent works
28
+ where its Frame says ([ADR-0057](0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md)); a Menu-only Agent
29
+ picks without reaching for tools it has not got ([ADR-0031](0031-menu-only-agents-run-on-the-instance-harness.md)); a
30
+ notice changes what the next Turn does ([ADR-0061](0061-a-memory-kill-ends-the-agents-processes-not-the-harness.md),
31
+ ADR-0062); a Turn follows its modes — after a pick changes the mode, after a correction receipt, and after a model
32
+ that stopped is asked again ([ADR-0015](0015-authoring-surface-absorbs-the-mechanism.md), ADR-0029,
33
+ [ADR-0016](0016-agent-turn-mechanics-are-internal.md)); a model that stopped with nothing allowed is woken when a
34
+ Gate's answer opens a pick, and picks (the wake, ADR-0016); a Turn hears its Allowed picks change under it at a step
35
+ boundary and follows them without a refused pick (ADR-0029); and a pick that runs work is answered at Rest and the
36
+ Agent acts on the answer, after a chain of replies and after a Harness restart cut the pick
37
+ ([ADR-0024](0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md), ADR-0031); and after a signed push the
38
+ Agent continues on its branch, so its next push publishes
39
+ ([ADR-0067](0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md)). A claim qualifies
40
+ when an ADR states what a correct Agent does differently for it and a step can observe the difference from outside the
41
+ pod. **The run** is one `workspace()` workflow through to `done` on a real task: a ticket the seed Repo carries as a
42
+ failing test, a planner's pick, a coder that edits in the Worktree, runs the test, commits on the run's branch and
43
+ names the commit — a guard refuses a `submit` that names none — and a reviewer in the same Sandbox, read-only
44
+ ([ADR-0028](0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md)), that runs the test itself and
45
+ approves or rejects, bounded. Approval parks at a Gate, and the witness is the pod (parking is retention, ADR-0012):
46
+ the branch is ahead of `main`, its head is the named commit, the tree is clean, and the test passes when the suite
47
+ runs it there. Nothing is pushed — the Agent holds no credential and the push is the caller's (ADR-0005,
48
+ [ADR-0053](0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md)), as `task` says — and
49
+ the seed's `app.git` accepts none. The run asserts the pick ledger's shape and a time bound — never the diff, the
50
+ commit message, or the Turn count, which are the model's.
51
+ - **Scored, not asserted.** A claim is N trials per cell (thinking off and on are cells, set through the Dial), and a
52
+ cell fails only below the floor written in its scenario. The floors are the ADRs' numbers rounded down to what a model
53
+ at the floor can hold: 9 of 10 where the ADR measured 10/10. Every run writes a scorecard,
54
+ `features/.tmp/model-scorecard.json`, keyed by model id and cell; a committed baseline per model id sits in
55
+ `features/model-baselines/`, and a cell that fell below its baseline while still above its floor is **reported**, not
56
+ failed. Drift is a signal to read; a floor is a defect. Each cell also records what its trials spent: the tokens and
57
+ the cost summed off each trial's Settlements
58
+ ([ADR-0027](0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md)), in the scorecard and as one line of
59
+ `features/.tmp/model-usage.jsonl`, and the tier prints the cell's cost beside the cost of the month so far. A trial
60
+ whose usage cannot be read records that, and never fails.
61
+ - **The instrument is a model shown to catch the known regressions.** Today that is the home-lab vLLM model
62
+ (Qwen3.6-35B-A3B, FP8 weights). ADR-0029's numbers are why a strong model does not qualify by default: a frontier
63
+ model obeys either placement and hides the regression. A model qualifies when the known regressions, put back, take
64
+ their cells below the floor: (a) ADR-0029's, the Allowed picks stated ahead of the prompt (`obedience`; Qwen obeyed 0
65
+ of 10), and (b) a draft's Chart briefing text that Qwen admitted 5 of 10 times (`chart-refusal`, floor 7; a snapshot
66
+ kept outside the repo). On 2026-10-25 Claude Haiku 5.5 caught neither: with the picks ahead of the prompt its first
67
+ call was the allowed `hold` in 20 of 20 trials, and on the draft's text it admitted 10 of 10. So a Haiku run checks
68
+ the tier's machinery, cheaply, and never a change to what the model reads. The same model served another way is
69
+ another instrument: NVIDIA's NVFP4 checkpoint on vLLM 0.32 with MTP, about twice the throughput, took `answered` from
70
+ 10 of 10 to 6 of 10 (4 trials fixed the failing test and shipped) and `chart-refusal` to 4 of 10, so the home lab
71
+ serves the FP8 weights on the image the baselines were measured on. Any other model must clear the same floors and
72
+ cannot lower them; adding a model adds a baseline row, never a floor. The run is measured once per invocation, on
73
+ whichever endpoint is selected, because it costs minutes and its failure is a defect to read, not a rate.
74
+ - **The endpoint is a profile, selected by env, and the key never enters a file.**
75
+ `features/model-endpoints/<name>.json` carries `id`, `api`, `baseUrl` and `model`, plus the tier's own `thinking`
76
+ cells, `trials`, `parallel` and `workers` (below), and optionally a `caBundle` path for a private CA
77
+ ([ADR-0020](0020-private-ca-trust-is-a-named-concept.md)). A profile is one of two kinds, as a user's instance is. A
78
+ profile with `key` names one of pi's catalog providers (`anthropic`), and the catalog holds the model's limits and
79
+ thinking levels. Its key is a Held secret in `secrets`, under the known model key that `key` names
80
+ (`ANTHROPIC_API_KEY`, [ADR-0059](0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md)). A profile with
81
+ no `key` is a `harness.provider`, and carries its models' windows. `JR2_MODEL_ENDPOINT=<name>` selects it;
82
+ `JR2_MODEL_API_KEY` is read from env alone. Before the converge, the fixture copies the selected profile to a fixed
83
+ path inside `features/model-instance/`. The instance's config and Agents import it from there, so the in-cluster
84
+ Orchestrator reads the same values the host did. An env read in a definition is `undefined` in the pod, as the `@kind`
85
+ config notes. That path holds one profile, so a lock on it (`features/lib/model-lock.ts`) records the profile, the
86
+ suite and the pid that owns the suite. The workers of one suite share it. A second suite in the same checkout fails at
87
+ once. With another profile, the refusal names that profile, because the suite would converge against it and file its
88
+ cells under its own key with no error: two profiles at once need two worktrees. With the same profile, it fails too:
89
+ the lock names one owner, so a later suite with another profile could take it over while the second still converges,
90
+ and two suites put twice `workers` × `parallel` runs in flight. A lock whose owner is gone is taken over. Nothing in
91
+ the product learns the tier exists. Reachability from the pods is `jr2 up`'s provider preflight, for both kinds of
92
+ profile. It checks each model from a check pod with a Custodian before it writes anything
93
+ ([ADR-0019](0019-one-converging-command-against-the-current-context.md)). So a pod with no egress to the provider
94
+ fails the converge at the check pod.
95
+ - **Not in CI. Run by whoever changed what the model reads, before calling the change done.** Not in `pnpm -r test`, not
96
+ in the release job: it needs a cluster and an endpoint, it is nondeterministic by nature, and a gate that flakes is a
97
+ gate everyone re-runs. `just e2e-model` probes the profile's endpoint first and, when nothing answers, exits 0 with
98
+ one line — `skipped: no model endpoint at <url> (profile <name>) — the @model tier did not run` — so it can always be
99
+ invoked and a skip is never silent. It skips with one line in two more cases. A profile with `key` and no
100
+ `JR2_MODEL_API_KEY` prints
101
+ `skipped: JR2_MODEL_API_KEY is not set, and profile <name> needs it (<key>) — the @model tier did not run`, where
102
+ `<key>` is the profile's `key`. An endpoint that answers with a status other than 2xx prints
103
+ `skipped: the model endpoint at <url> answered HTTP <code> (profile <name>) — the @model tier did not run`. The
104
+ trigger is a change to any text or tool the model reads or is offered: the Briefing, the Menu's rendering and the
105
+ refusal, the nudge, the Working tools and their descriptions, Compaction's summary, the admit body's notices, the pi
106
+ pin, a provider adapter, or an authoring surface that changes a Frame. An agent reviewing a feature or refactor that
107
+ touched one of these runs the tier and reports the scorecard's floors and drift, or the skip, in its handoff.
108
+ CLAUDE.md states the rule. One scenario runs alone by its title, which is the scenario filter:
109
+ `cucumber-js --profile model --name "a Gate's answer during a command is followed"`.
110
+ - **A third pi canary.** Conformance and `@kind` drive the turn loop against a script; this tier drives it against a
111
+ model that can misread. Run all three before bumping the pin.
112
+
113
+ ## Considered options
114
+
115
+ - **A real model inside `@kind`.** Rejected: `@kind` proves the data plane, and its scenarios must be readable when they
116
+ fail. A model that misreads a prompt would make a Sandbox failure look like a wording one, and a laptop without an
117
+ endpoint could no longer run the data-plane tier at all.
118
+ - **In-process, in `@jr2/harness`: conformance with a real `baseUrl`.** Rejected: it measures the Harness's rendering of
119
+ an admit body the test wrote, not what the Orchestrator sends — the Allowed picks, the Frame and the notices are
120
+ composed there — and it has no Workspace, so it can never run the run.
121
+ - **Pass or fail per trial.** Rejected: a model is a distribution. A single 9/10 fails a green change once a week and
122
+ teaches everyone to re-run until it passes, which is the same as not measuring.
123
+ - **A frontier model as the instrument.** Rejected: ADR-0029 measured the regression only on the weak model; the
124
+ instrument must be the one that can fail.
125
+ - **Recorded provider transcripts, replayed.** Rejected: a replay is a scripted provider by another name, and the tier
126
+ exists precisely because a scripted provider cannot misread.
127
+ - **A hosted model in CI.** Rejected for now: a key in CI, a bill per push, and nondeterminism in the gate. The decision
128
+ is who runs it, and that is the change's author, when the endpoint is there.
129
+
130
+ ## Consequences
131
+
132
+ - ADR-0010's tier list gains `@model`; ADR-0027's canary sentence names three canaries; CLAUDE.md's testing strategy
133
+ gains the tier and the rule about when to run it.
134
+ - New: `features/model.feature`, `features/steps/model.steps.ts`, `features/model-instance/` (config, `_agents.ts`, the
135
+ claim workflows and `ticket.ts`), `features/model-endpoints/homelab.json`, `features/model-baselines/`, the `model`
136
+ and `model-warm` profiles in `cucumber.json`, `features/model-warm.feature`, `features/lib/model-lock.ts`, and
137
+ `just e2e-model` and `just e2e-model-warm`.
138
+ - The seed Repo's `main` gains a small project with one failing test, so the run has a task with a checkable outcome.
139
+ `@kind` reads the seed's refs, never its files, so it is indifferent.
140
+ - ADR-0029's and ADR-0062's measurements become scenarios; their prose keeps the numbers as the origin of the floors.
141
+ - The Menu-only claims read the model's calls off the Instance Harness's printed conversation (ADR-0023) — the one place
142
+ a refused pick, a nudge and a restated Turn part are all visible. Every line of a conversation carries its Instance
143
+ ID, which starts with the run id (ADR-0023), so a trial reads only its own run's lines of that one log, and the
144
+ Menu-only trials run `parallel` at once, as the Sandbox claims, which read their pods, do. Two claims keep fewer in
145
+ flight. `cut-pick` runs one trial at a time: each of its trials deletes the Instance Harness pod, which would cut the
146
+ Turn of every other trial in flight there. `noticed` runs at most two: on a loaded host the kernel's OOM killer takes
147
+ the container before the guard takes the hog, and that trial is void. A claim whose setup the step must race (a Gate
148
+ answered while the model works, a mode moved while it composes) voids the trials whose setup lost the race; voids are
149
+ bounded, and a void past the bound counts against the floor and prints as a void in the failure list, never as a miss.
150
+ A trial whose own prompt, the one that carries its marker, is not in its kept conversation is void too: the follow
151
+ lost it, and the calls after another prompt are not the trial's, so they are never read as its miss or its pass.
152
+ - **Scenarios run `workers` at once, set per profile.** Each scenario has its own namespace, so scenarios are
153
+ independent, as `@kind`'s are. The profile's `workers` is how many run at once: `just e2e-model` passes it to cucumber
154
+ as `--parallel` when it is above 1. It is in the profile and not in `cucumber.json`, because its limits are the
155
+ endpoint's and the host's, not the tier's. `workers` × `parallel` runs are in flight, and that product must stay
156
+ within what the endpoint serves (the home-lab vLLM serves 16 streams; a run past them waits in its queue and skews
157
+ every trial's latency and the runaway bound) and within what the host holds: about 0.85 CPU and 2.2 GiB per scenario,
158
+ plus 0.5 CPU and 1 GiB per Sandbox trial in flight, on a 16 CPU, 45 GB host that three kind clusters share. The
159
+ home-lab profile runs 4 × 4: a full run took 26.5 minutes on 2026-10-25, against about 70 one scenario at a time;
160
+ Haiku's runs 4 × 2, 10.6 minutes. Cucumber starts scenarios in file order, so `model.feature` lists its longest Rules
161
+ first. `chart-refusal` is the longest, 21 of the 26.5 minutes: its trials write long answers and call `run_chart` up
162
+ to 16 times. A step reads a run's status from the Orchestrator API that `jr2 status` uses, with the same Instance
163
+ token, over one port-forward per scenario, opened on the first read and again when it dies; a `jr2 status` process per
164
+ read every 2 s cost about 0.4 host cores per trial in flight. On a cold host, `just e2e-model-warm` runs one converge
165
+ first and serially (`features/model-warm.feature`, tagged `@warm` and excluded from the `model` profile), as
166
+ `e2e-kind-warm` does for `@kind`, so the workers do not each build the same images. Converges on two clusters at the
167
+ same moment share the host daemon, and one's sweep keeps only its own cluster's images
168
+ ([ADR-0039](0039-image-garbage-collects-by-reachability.md)), so it can take the other's fresh Sandbox image before
169
+ its use. `jr2 up` builds a ref it finds missing again from BuildKit's cache and goes on; before it did, 5 of 19
170
+ converges in one `workers: 4` run failed this way.
171
+ - Each trial's line in the failure list says how its run ended, whatever stopped the trial (a driver that threw prints
172
+ what it threw, and names the run it had started, if any: `threw: <message> (run <id>)`). A run that ended `failed`
173
+ also prints its Failure, and a run in error its fault, which carry the reason (`features/lib/model-status.ts`): the
174
+ namespace that held the pod log is gone when the list is read.
175
+ - **Every trial keeps its evidence.** Every trial, passed, missed or void, keeps one folder,
176
+ `features/.tmp/model-trials/<model>/<cell>/<runId>/` (gitignored with `.tmp`; a cell's `/` is a folder; a byte of a
177
+ name outside `[A-Za-z0-9._-]`, such as a model id's `:`, and a leading `.` are spelled `%XX`, so any model id keeps
178
+ its trials):
179
+ - `conversation.txt`: the Harness container's printed conversation (ADR-0023), timestamped. A Sandbox claim's is
180
+ followed from the moment the trial's Sandbox pod exists until the reap at settle takes the pod
181
+ ([ADR-0012](0012-workspace-wrapper-machine.md)), so a read after the settle is never needed, and it is followed
182
+ again after the container restarts. A Menu-only claim's is its own run's lines of the Instance Harness's log from
183
+ the trial's start, kept by the Instance ID's prefix `<runId>/`, and followed again after the step deletes that pod
184
+ and the StatefulSet makes it again. A driver reads its measurement from this kept conversation, never from a second
185
+ read of the log: `kubectl logs` reads only the current container, so a restart or a 10 Mi rotation loses lines that
186
+ the follow kept. It holds each pick's answer after its call, the text the model read (`[<pick> answer] <text>`, or
187
+ `[<pick> error] <text>`): the receipt, a command's outcome, a refusal, the paragraph after a signed push. An answer
188
+ longer than the print's bound (2000 characters, a call input's) is cut in its middle, with the number of characters
189
+ dropped marked at the cut (`… [<n> characters cut] …`), so the receipt at its head and the end with "Allowed now"
190
+ both stay; the model read the whole answer, and the cut is the log's copy only (ADR-0023). The Harness prints it
191
+ (ADR-0023), so the tier keeps it with the conversation, and nothing the model reads changed to keep it. `answersIn`
192
+ reads each call with its answer; a call a Harness restart cut has jr2's text, which the next container prints before
193
+ its first prompt, and a call an abort cut while the model was still writing it has jr2's text that it did not reach
194
+ the workflow, printed before the conversation's next prompt.
195
+ - `effector.txt`: the Sandbox Effector container's log, followed the same way, for a Sandbox claim; it says so when
196
+ the pod has none.
197
+ - `harness-history.txt`: the Harness history view
198
+ ([ADR-0027](0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md)) of each conversation whose prompt
199
+ printed in the kept conversation, at the Instance ID its lines carry: each settlement, with the failure text of one
200
+ that failed. The view is read while the trial runs and again each time a settlement lands, and the last one read is
201
+ kept. A Sandbox Harness exits at the reap, so the view after a Turn that settled just before it can be too late to
202
+ read: each Agent's stream is also followed, read as the Orchestrator reads it, and each `submission-settled` it
203
+ carries that the kept view does not hold is kept after the view.
204
+ - `record.json`: the Machine's final record, the last status the driver read of the run.
205
+ - `push-log.txt`, for a push claim: the push remote's log from `main` to each commit the record says was published.
206
+ - `instance/`, for a Sandbox trial whose Workspace encloses a Menu-only seat (`ticket`'s planner): that seat's
207
+ `conversation.txt` and `harness-history.txt`, read off the Instance Harness where its Turns run
208
+ ([ADR-0031](0031-menu-only-agents-run-on-the-instance-harness.md)), so that its Settlements are in the trial's
209
+ usage.
210
+
211
+ The run keeps its evidence the same way, in its cell's folder, from its start until its cell is written or its
212
+ scenario ends.
213
+
214
+ Each file is written when it changes, so a trial that hangs until its timeout leaves what it had. Every probe only
215
+ reads: a probe that fails writes `<unavailable: why>` into its file and never changes what the next trial does. A
216
+ Menu-only driver measures the kept conversation, so when that follow fails, the trial has nothing to measure and is
217
+ not measured, as before when its `kubectl logs` read failed. No other probe fails the trial. Each trial's note opens
218
+ with what the model called, read off the kept conversation in the Menu-only notes' form
219
+ (`said bash (restated) ask_approval submit`) from the lines of the Agents whose prompt printed there (the run
220
+ narrative echo, `[run] [status]` and `[run] [emit]`, is not a call), or `said <unread: why>` when it cannot be read,
221
+ and the driver's note follows. A floor failure, a void past the bound and a cell below its baseline are read from
222
+ these folders before a prompt, a floor or a step is touched. A failed `@model` scenario also writes the `@kind`
223
+ failure dump, to the same place as a `@kind` one: `features/.tmp/kind-failures/<namespace>-<scenario>/`.
224
+
225
+ - One trial may measure two claims: `push-follow` and `push-no-refusal` are two cells of one scenario's trials. After
226
+ the measured pick, a coder that picked `revise` is back in `coding`, where only the desk's answer moves it, so the
227
+ step answers the desk again each time, until the trial's time ends, and the trial can finish; the measure is still the
228
+ first pick after the first answer. Until 2026-10-23 the step answered at most three more times (below, 5d3096da). The
229
+ driver changed for this after the claim ran once (70f9cb2); the user approved the change on 2026-10-09. Those answers
230
+ never reached the Machine: the driver waited for the run's own `value` to read `coding`, and a `workspace()` run's
231
+ value is its wrapper's, which never holds its body's state, so the step never answered again. In the full run of
232
+ 2026-10-12 one trial (ba79f322) recorded its measure, `revise` right after the answer, then looped `ask_approval` and
233
+ `run_tests` in `coding`, reading "Allowed now: ask_approval, run_tests", until the run faulted, and failed "every
234
+ trial finished". The driver now reads the body's state off the children `jr2 status` reports
235
+ (`features/lib/model-status.ts`), a defect fixed and no setup change. Then a bound of the kind of the finished rule
236
+ below: a trial whose measure is recorded — its first pick after the answer; the body seen back in `coding` after it is
237
+ `revise` — and that does not finish within its time is cancelled and counts as finished. Its time is a trial's bound,
238
+ 15 minutes, counted from the desk's first answer. A measured trial whose run settles before then without its task's
239
+ final — a fault — is not cut, and fails "every trial finished". The prompt, the floor and the measure did not change.
240
+ Both were decided under the user's deferral on 2026-10-12 and confirmed by the user on 2026-10-12.
241
+ - The held-answer claims of ADR-0024 and ADR-0031 — `chain-answer` (the next pick follows the answer's last link) and
242
+ `cut-pick` (after a Harness restart cut the pick, the Agent uses the answer and does not pick it again; the step
243
+ deletes the Instance Harness pod). Each floor carries ADR-0029/0062's measurement of a list read last. The first run
244
+ (home-lab vLLM, 2026-10-07) confirmed both, 10 of 10, now baselines.
245
+ - **The refusal of a second pick while one is outstanding is not a claim.** It is jr2's mechanism, not something a model
246
+ does with what it reads. The Orchestrator refuses it from the Machine (ADR-0024). The Harness runs only the first pick
247
+ of one model answer (ADR-0024, [ADR-0027](0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md)).
248
+ Harness conformance proves it with a scripted provider that sends two picks in one message. Only the first is
249
+ delivered, and the second reads that it did not run. A claim for it (`refused-outstanding`: the refused pick is picked
250
+ again once the answer comes) ran once, on 2026-10-07: in all 15 trials of that run the model called `book_room`, read
251
+ its answer, then called `send_invite`, so no call was ever refused and its setup never happened. It left the tier with
252
+ no cell; no floor was lowered. A model that sends two picks in one model answer would need a claim of its own: what it
253
+ does after its second pick did not run.
254
+ - The command-Effect claims of ADR-0067 — `answered` (the next pick follows a command's output), `allowed-after-route`
255
+ (the next call is one the route allows, not one allowed before the pick) and `unknown-outcome` (after a Harness
256
+ restart killed the command, the Agent checks before it announces; the step restarts the Sandbox's Harness container) —
257
+ carry the borrowed floor of ADR-0029/0062's measurement of a list read last. Their first runs (home-lab vLLM,
258
+ 2026-10-07 and 08, four runs of the tier) read:
259
+ - `answered`: 10, 9, 10 and 10 of 10 with its first setup, now a baseline; 9 of 10 in the full run of 2026-10-12, and
260
+ 8 of 10 in the full run of 2026-10-13 (on 50fe7e0), below its floor of 9. The two misses (53cc7436, 253e840b) had
261
+ one shape: the coder read the right answer, the outcome `exited` with code 1, the output's line
262
+ `auth.test.ts: expected 200, got 500` and "Allowed now: report_failure, run_tests, ship", said that the output named
263
+ `auth.test.ts`, a file the Worktree did not hold, ran the Repo's own tests, fixed the `greet` tests the output did
264
+ not name, and picked `ship`. jr2 acted correctly in all ten trials. The setup was the one `allowed-after-route` had
265
+ until 2026-10-08: the test command was fixed data that printed a failure of a file the Repo did not hold, while the
266
+ Worktree (the seed's `app.git`) held real failing tests the model could fix, so a miss could not tell "ignores what
267
+ the output says" from "fixed what it was shown". The setup now is the same real case (2026-10-13): the claim binds
268
+ `billing.git`, and `run_tests` runs its suite in the Worktree (`node --test`), whose one failing test the output
269
+ names with its file and the values it compared, and the Worktree holds nothing else to fix. The prompt's subject
270
+ follows the seed ("The billing change is in." in place of "The auth fix is in."); the rest of the prompt, the floor,
271
+ the measure (the first pick after `run_tests` is `report_failure`) and the baseline are unchanged. The user approved
272
+ this setup change on 2026-10-13, before it was made. The first run with this setup (2026-10-13, on 1380dee) read 9
273
+ of 10, at its floor of 9 and below its baseline of 10, with no void: each of the ten answers named the real failing
274
+ test (`billing.test.js:9`, `2148 !== 2149`). The one miss (e3a27f22) read the failure, fixed `billing.js`, ran the
275
+ tests again and picked `ship`, against the prompt's "if they fail, report the failure": the model's choice. It is
276
+ reported below baseline, not failed; the claim is no longer open, and the baseline stays at 10.
277
+ - `unknown-outcome`: 10 of 10 in both runs that read it whole, now a baseline. The Harness container restarts in
278
+ place, and the reap when the run settles deletes the pod with every log it held, so the step follows the restarted
279
+ container's log from the moment it runs. Read after the settle, the log was gone in 5 of 10 trials of the first run,
280
+ each a model that had checked.
281
+ - `allowed-after-route`: 3, 5 (a diagnostic run), 4 and 4 of 10 with its first setup, below its floor. Every miss had
282
+ one shape: after the failing answer the coder read the seed Repo, found a failing test, fixed it with its Working
283
+ tools, saw it pass, and picked `ship`, which the newest "Allowed now" it read (`open_issue`, `run_tests`) did not
284
+ list. The setup made that failure say little: the test command was fixed data that always failed and named a file
285
+ the Repo did not hold, while the Worktree held an unrelated test the model could fix. So a miss could not tell
286
+ "ignores the newest list" from "fixed what it was shown". The setup now is the real case (2026-10-08): the claim
287
+ binds its own seed Repo (`billing.git`), whose suite has one failing test that names the defect, and `run_tests`
288
+ runs that suite in the Worktree. A correct Agent may fix the code, but only `run_tests` passing takes the workflow
289
+ back to where `ship` is allowed; the miss is a `ship` after its own fix without the workflow's check. The floor and
290
+ the measure are unchanged. Its first run with this setup (2026-10-08) read 10 of 10, now a baseline. The setup
291
+ change (86e9691) was made before the user saw it; the user approved it on 2026-10-09.
292
+ - `continue-after-signed-push` (ADR-0067): the coder fixes the seed's failing test, commits and publishes — a signed
293
+ push from the Sandbox Effector over ssh to the seed's push remote, `push.git` — then commits a second change,
294
+ publishes again, and finishes. The first push's answer carries the paragraph after a signed push. The measure is the
295
+ Machine's record of the second push: `pushed`; an Agent that rewrites the pushed commits after their ids changed makes
296
+ it `diverged`. A trial whose first push did not publish a signed copy is void, and so is a trial whose only push
297
+ already carried two or more commits from `main` (below). Its floor is `push-follow`'s, 9 of 10: the answer is the
298
+ newest thing the model read. Its first run (home-lab vLLM, 2026-10-11) read 9 of 10, none void, at its floor: now a
299
+ baseline (4316bdb). For it the tier's shared instance gained a push credentials entry
300
+ (`features/model-instance/jr2.config.ts`) and its Effector image a passwd entry for uid 1000 (9cd3935). The user
301
+ approved this on 2026-10-11 as not a setup change: the rule guards what the model is put in front of, and a credential
302
+ entry and a passwd line change nothing the model reads. No existing claim's prompt, workflow or floor changed, and
303
+ every existing cell held its baseline after the change. Its next run (2026-10-11) read 8 of 10, below its floor and
304
+ its baseline, and a diagnostic run read 6 of 10. Each of the four misses whose log was read had one shape: the model
305
+ made both commits before its first `publish`, published once, and finished. The claim measures the paragraph after a
306
+ signed push, which the model reads only after a push; in such a trial the model chose its order before it read any
307
+ post-push text and had no work left to continue, so the measured moment never occurred — the shape of the `noticed`
308
+ and `push-follow` voids. The setup changed for it (decided under the user's deferral on 2026-10-11, confirmed by the
309
+ user on 2026-10-12): when the setup holds and there is one push, the step counts the commits from `main` to that
310
+ push's published commit on `push.git`, and two or more make the trial void ("void: the first push carried <n> commits
311
+ …"). It decides from the push's content, never from the push count, so "published once, committed, finished" and
312
+ "published, reset, finished" stay misses. The prompt, the floor and the pass did not change, and the 8 of 10 stands:
313
+ the claim passes only on a new run. The void shares the claim's one bound of replacements (half the trials, rounded
314
+ up) with the setup void, and a void past it counts against the floor and prints as a void. At the diagnostic run's
315
+ rate, 4 of 10, the bound is often spent; the claim is then open, not passed. Rejected: counting the batched trial a
316
+ miss (it measures the model's reading of the claim's own prompt), raising the bound, or lowering the floor.
317
+ - **A trial that reaches either of its task's finals finished.** A claim whose workflow has two task finals (`wake`,
318
+ `chain-answer`, and the three command-Effect claims) counts a trial finished at either; its measure already counts the
319
+ wrong one a miss, and counting it unfinished too would fail the scenario on one miss — the floor 10 of 10 in all but
320
+ name. A run that ended `failed` (a claim workflow fails on a fault and on a lost Workspace), a run in `error` and an
321
+ unsettled run never finished.
322
+ - `wake` (below, under `push-wake`) has run four times, 10 of 10 each, and is a baseline.
323
+ - **A claim's setup may change; its floor and what counts as a pass may not.** A setup is the part of a trial that
324
+ brings the model to the moment the claim measures. When a claim falls below its floor because that moment seldom
325
+ happens, its workflow and its driver may change for the setup alone, and the reason is recorded here. A setup that no
326
+ honest change makes reliable leaves the claim open, and it is reported as open. The first run of the mode and
327
+ step-boundary claims (home-lab vLLM, 2026-10-05) changed two:
328
+ - `mode-stop`. Its Turn asked for a review and told the model to wait; the stop happened in about 1 trial of 3 —
329
+ models picked straight through (`ask_review submit`) or looped `ask_review`/`revise` — and the claim fell to 5 of 10
330
+ twice. `ask_review` now enters a mode whose `revise` and `submit` are closed, where the Briefing tells a model to
331
+ stop, and a timer then opens them, so the wake asks it with the nudge's text (ADR-0016). The timer has no target: it
332
+ assigns, and the picks' guards read it. A timer that moved the workflow to a mode inside the Agent's state holds
333
+ Rest (ADR-0024), so `ask_review` would stay outstanding until it fired and its answer would carry the Allowed picks
334
+ on the same call; no model would stop. The prompt is unchanged: it is the claim's fixed data. What counts is
335
+ unchanged: the trial is measured at the first ask after the model's `ask_review`, and void without one, and it
336
+ passes when the first Menu call after that ask is a pick the mode active at the ask allows. The driver reads the
337
+ modes from the workflow, not from a copy of them, and replays the model's calls through them: a mode with a
338
+ targetless timer has its picks closed from each entry until the timer fires; the driver takes the timer where a
339
+ restated Turn part shows that it fired, and follows it at the ask when the wake asked with nothing allowed.
340
+
341
+ On 2026-10-23 the setup changed again. In that day's full runs on Claude Sonnet 5.5 and Haiku 5.5 (below), the timer
342
+ was the whole review: no reviewer answer came, and a careful model would not submit notes that no reviewer had
343
+ answered. Now a reviewer, a child Machine below `reviewing`, reads the notes for 2 s and approves them. `ask_review`
344
+ is outstanding while it reads, and its answer is the reviewer's output (ADR-0024), with the Allowed picks read at
345
+ Rest: none, because the timer has not fired. So the model reads the answer that the prompt tells it to wait for, and
346
+ it still stops with nothing allowed. The timer still has no target and starts at `reviewing`'s entry, so the
347
+ reviewer holds Rest only for its 2 s, and the wake still asks the stopped model. The states that the reviewer's hold
348
+ adds (`reviewing.reading`, `reviewing.answered`) are below `reviewing`, so the modes that the driver reads do not
349
+ change. The prompt, the floor and what counts are unchanged. The one new text that the model reads is `ask_review`'s
350
+ answer:
351
+ ``The workflow took it and is back in the state that asked for this turn. Its answer: the output of `reviewer`: {"verdict":"approved","comments":"Clear and accurate."}.``,
352
+ in place of the plain receipt's "The workflow is still in the state that asked for this turn." The user approved
353
+ this change on 2026-10-23 (question 21: give the review a real answer). In the claim-setups run (below) it gave 10
354
+ of 10 on the home lab, on Haiku 5.5 and on Sonnet 5.5, and every trial finished.
355
+
356
+ - `push-wake`, since replaced by `wake`. It measured a Menu-only Turn that started with nothing allowed and picked
357
+ inside the same Submission once a Gate's answer was restated at a step boundary. The step first answered the board
358
+ as soon as the Turn's prompt printed; in two runs, 8 and 9 trials had no restatement, each with one `hold` or
359
+ `release` as its whole conversation (7 and 5 of 10). It then answered once the Turn's first model answer had ended
360
+ with a Menu call, and the claim fell to 2 of 10. The cause is the standing Briefing, rewritten after the claim was
361
+ written (ADR-0062): "If nothing is allowed, stop: the workflow prompts you again when something is." A correct model
362
+ with nothing allowed now stops, so the in-Submission moment the claim measured is rare, and the model that skips it
363
+ is the correct one. What the Briefing promises instead is the wake (ADR-0016), and `wake` measures that: the model
364
+ stopped with nothing allowed; once its Submission has settled, the step answers the board; and the first Menu call
365
+ after the wake is `release` or `hold`. A model that never stopped is void. Its floor is `push-follow`'s, 9 of 10.
366
+ `push-follow` keeps the restatement case: a list that changes while the model is still working. `push-wake` had no
367
+ baseline cell.
368
+ - `noticed`. The kill must not land while a Turn runs. The first Turn starts the server and picks `started`. Then the
369
+ body waits at the `kill` Gate, and no Turn runs. The step checks that the server answers, with a probe that it execs
370
+ in the Harness container. Then it execs the memory hog. It checks that the guard's list (`GET /memory-kills`) holds
371
+ a new kill and that the port is dead, and it answers the Gate. The second Turn continues the same conversation, and
372
+ its prompt must carry the memory-kill notice. The first Turn has ended, so it cannot see the kill. What the second
373
+ Turn knows of the kill, it knows from the notice.
374
+
375
+ Two earlier setups killed during the first Turn, and their runs showed why that is wrong. In 1 of 10 trials of two
376
+ runs of 2026-10-12 (8374be56, 9d220d92), the first Turn saw its server die and did not pick `started`. On
377
+ 2026-10-22, Haiku 5.5 often ended its first Turn before the kill, so the kill landed in the second Turn, and that
378
+ Turn was not told. A first Turn that saw the kill often started the server again. Then the second Turn's report can
379
+ come from what the first Turn saw, not from the notice. The driver made all of these trials void. The last of those
380
+ setups polled the port from the host every 3 s during the first Turn, and it killed when the port answered. It made
381
+ a trial void when the first Turn made a Working-tool call after the kill. On the home lab, 7 of 15 trials of that
382
+ setup were void for that reason. All 8 measured trials passed. But 2 voids were past the bound, so the cell was 8 of
383
+ 10, below its floor of 9. Qwen keeps working in its first Turn, sees the kill, and starts the server again. A kill
384
+ between the Turns removes this mixed cause, and it needs no timing void.
385
+
386
+ The new setup found a gap in the product. The guard put a kill on the stream of the Submission that ran. When no
387
+ Submission ran, the Orchestrator did not hear of the kill, and the next Turn got no notice. Main fixes this
388
+ (91699c24, 8c274330). The pod keeps every guard kill, and the Agent actor reads them before it admits a Turn into
389
+ the Workspace. So the next Agent in the Workspace gets the notice once.
390
+
391
+ Two voids stay, each a setup that did not happen. In the first, the first Turn does not pick `started` in its time:
392
+ the run is live, and its body is in `starting`. In the second, no server answers at the `kill` Gate: a server that
393
+ outlives its bash call is the model's job. A body that left `starting` for `faulted` (`agent.fault`) or `lost`
394
+ (`workspace.lost`) invokes `fail`, and the run ends `failed`. It is not void, and it fails "every trial finished",
395
+ as the finished rule above says. The bound stays half the trials, rounded up. Rejected: a larger bound for
396
+ `noticed`, and a fault in `starting` counted as void.
397
+
398
+ Two more voids are new. In the first, the kill does not take the server. The guard's list (`GET /memory-kills`,
399
+ 91699c24) holds no new kill, or the port still answers after the hog. Then the exec fails, or the kernel's OOM
400
+ killer takes the hog before the guard does. In the second, the kernel kills the container, not the guard. A kernel
401
+ OOM kills the whole container, and the container's restart count goes up. The kubelet counts the restart 1 to 3 s
402
+ after the kill. So the step reads the count right after the hog, and again after it reads the guard's list or that
403
+ read throws. The guard's list is the backstop. A kernel kill leaves no new guard record, so when the rise does not
404
+ show yet, the trial is the "no new kill" void. It is a void either way, never a miss. On main, a port that still
405
+ answered after the hog was a miss. A dead port with no guard kill counted as a kill, so that trial could pass. Now
406
+ each is a void, because the setup that the claim measures does not happen, and a port that is dead for another
407
+ reason is not blamed on what jr2 tells the model. Each void cancels its run before the second Turn. Only the voids
408
+ after the hog give the hog's exit code. The user approved these two voids on 2026-10-23.
409
+
410
+ The prompt and the floor did not change. The pass changed: a trial now also needs the notice in the second Turn's
411
+ prompt. Before, the step did not read the second Turn's prompt. Now the kill lands before the second Turn starts, so
412
+ jr2 must tell that Turn. A prompt with no notice is a miss, and the note names it as a defect in what jr2 shows the
413
+ model. The setup first ran on 2026-10-23, at an earlier version of this branch (09291511, not kept) on main
414
+ 8837af28. That step named the Gate `hold`, had `killed` in the pass, did not read the guard's list, and had neither
415
+ of the two new voids. It gave 10 of 10 on the home lab with no void, and 10 of 10 on Haiku 5.5. A later version of
416
+ this branch (c220d895, not kept) scores a trial as this step does. On 2026-10-23 it gave 10 of 10 on the home lab,
417
+ on Haiku 5.5 and on Sonnet 5.5, and no void fired. The user confirmed the 2026-10-12 void on 2026-10-12, and
418
+ approved the setup with the Gate between the Turns on 2026-10-23.
419
+
420
+ The Rest rule (ADR-0024) changed a third, `mode-refusal`, before any run under it. Its timer moved `reviewing` on to
421
+ `approved` while the model composed its next call; under Rest that timer holds `ask_review` outstanding until it
422
+ fires, so the stale list the claim needs never reaches the model and every trial would be void. The timer now has no
423
+ target: it shuts the review window, and the guards of `revise`, `submit` and `publish` read it, so after it fires only
424
+ `publish` is allowed in `reviewing`. The prompt, the floor and the pass are unchanged: the call after the correction
425
+ receipt is `publish`. Both setups have run: `mode-stop` and `mode-refusal` cleared their floors 10 of 10. The user
426
+ approved `mode-refusal`'s setup change (e20cc0d) on 2026-10-11: a forced change that measures nothing new, with the
427
+ prompt, the floor and the pass criterion unchanged, and 10 of 10 on 6f91bcc and on 9cd3935.
428
+
429
+ On 2026-10-23 `mode-refusal`'s setup changed as `mode-stop`'s did, for the same cause: in Haiku 5.5 trial 38368e52 the
430
+ model would not publish notes that it saw no one approve. A reviewer below `reviewing` approves the notes, and its
431
+ output is `ask_review`'s answer, with `revise` and `submit` allowed. The window's timer moved to `reviewing.answered`,
432
+ the state that the reviewer's answer enters, so it starts when the answer is fixed, as it started at the receipt
433
+ before. The answer reaches the Harness on the long-poll of the outstanding pick, not on the POST of the pick. The
434
+ prompt, the floor and the pass are unchanged. The new text that the model reads is the same answer as `mode-stop`'s,
435
+ followed by "Your turn is not over. Allowed now: `revise`, `submit`." (in the model's tool names). A model that holds
436
+ the approval and calls `publish` before the window shut is refused, and one that calls it after the window shut is
437
+ taken. Neither trial refused a pick from the list, so both are void, inside the claim's bound. The user approved this
438
+ change on 2026-10-23 (question 21). In the claim-setups run (below) it gave 10 of 10 on the home lab, on Haiku 5.5 and
439
+ on Sonnet 5.5, and every trial finished.
440
+
441
+ - **Claude Haiku 5.5 and Claude Sonnet 5.5 (Anthropic API).** The cells of
442
+ `features/model-baselines/anthropic--claude-haiku-5-5.json` (18) and
443
+ `features/model-baselines/anthropic--claude-sonnet-5-5.json` (20) come from the full runs of 2026-10-23 on main
444
+ 8837af28, except the six cells that the claim-setups run gave (below). Haiku ran from 17:30 to 18:21 UTC, and Sonnet
445
+ from 18:21 to 19:26 UTC. Both ran a version of this branch (c220d895, not kept). The later commits of the branch do
446
+ not change how a trial is scored.
447
+ - Haiku: 16 of 19 scenarios passed, every claim cell at 10 of 10 and each run at 1 of 1. Three scenarios failed at
448
+ "every trial finished" and wrote no cell. `mode-refusal`: 9 trials passed. The 1 trial that missed (38368e52) is
449
+ also the 1 that did not finish. `mode-stop`: 9 trials passed and 1 missed (0da530b9). That trial and 3 more did not
450
+ finish (71a52a32, 08f40dc7, 1ed86b01). `push-follow` and `push-no-refusal`: 10 of 10 passed both cells, and 1 of 10
451
+ did not finish (5d3096da). An earlier version of this branch (09291511, not kept) ran Haiku `push-follow` on
452
+ 2026-10-23 too, and 3 of its 10 trials did not finish.
453
+ - Sonnet: 18 of 19 scenarios passed. Sonnet 5.5 has no `off`, so its `off` cells ran at effort `high`, and in this run
454
+ its `on` cells asked for `high` too. Since 2026-10-23 the profile's `on` cell asks for `medium`, as Haiku's does
455
+ (`anthropic-sonnet.json`; at pi-ai 1.4.0 Sonnet's `thinkingLevelMap.medium` is `medium`), so `off` and `on` are two
456
+ conditions. The `obedience/on`, `ticket/on` and `ticket-modes/on` cells of this run measured `high`, so they left
457
+ the baseline file, and the claim-setups run (below) measured each again at `medium`. The user approved this on
458
+ 2026-10-23 (question 23). `obedience/off` gave 9 of 10, every other claim cell 10 of 10, and each run 1 of 1. In the
459
+ miss (b2b5a38d), the prompt asked for `ship` and only `hold` was allowed. The model stopped with text, and after the
460
+ nudge it picked `hold`. `mode-stop` failed at "every trial finished" and wrote no cell. Its 10 measured trials
461
+ passed, and none of the 10 finished.
462
+
463
+ In the unfinished `mode-stop` and `mode-refusal` trials, the model does not take a step that the claim's story says
464
+ needs a review or an approval. That review or approval never comes. Then the nudges run out, and the run faults. The
465
+ conversations show this:
466
+ - Sonnet `mode-stop` (for example 5a0ba0c1): after the nudge, the model's thinking reads "Since no reviewer feedback
467
+ has come in yet, submitting now would be premature". It picks `revise` and asks for review again. This repeats until
468
+ the run faults. The workflow's prompt says "wait for the reviewer's answer", but no reviewer answer comes: the timer
469
+ only opens the picks.
470
+ - Haiku `mode-stop`: 3 of the 4 unfinished trials (71a52a32, 08f40dc7, 1ed86b01) have the same `revise`, `ask_review`
471
+ loop. In 0da530b9, the model stops and says that neither pick fits, because the review has no answer yet.
472
+ - Haiku `mode-refusal` (38368e52): "I'm not calling `publish`. The v2.3 notes have not been approved…"
473
+
474
+ Haiku `push-follow` 5d3096da has a different cause. The desk answered four times: the ledger holds four approvals.
475
+ After each answer `submit` was allowed, but the model picked `revise` to fix and check the failing tests ("Submitting
476
+ now would ship code that fails its own tests"). The fourth `revise` came after the last answer that the step gives:
477
+ the first answer and `PUSH_REANSWERS` (3) more. In `coding`, only `ask_approval` and `run_tests` are allowed, and no
478
+ allowed pick ends the Turn. The model said "I've now requested approval four times without a response", and it
479
+ stopped. The nudges ran out before the driver's cut at TRIAL_MS, so the run faulted.
480
+
481
+ The home-lab Qwen takes the step anyway in `mode-stop` and `mode-refusal`. The "every trial finished" check counts
482
+ these trials against the scenario, but the measured cell passes. On 2026-10-23 the user decided (question 21) to
483
+ change the setups of these claims, and no floor or check. For `mode-stop` and `mode-refusal`, the review now has a
484
+ real answer (the setup notes above). For `push-follow`, the step's limit on desk answers went: the desk now answers
485
+ each time the coder is back in `coding`, until the trial's cut, TRIAL_MS from the first answer, which stays the bound.
486
+ The rule that a fault before the cut is unfinished stays. The measures (the first pick after the first answer, and the
487
+ first Menu call after the first restatement) and what the model reads do not change. These runs came before that
488
+ change.
489
+
490
+ **The claim-setups run** measured these changes on 2026-10-23, at snapshot 42433e48 of this branch on main 4cb2bc2e.
491
+ Its cells were written from 01:47 to 02:22 UTC on 2026-10-24. It ran only the scenarios that the changes touch:
492
+ - Home lab: `mode-stop/off` and `mode-refusal/off`, 10 of 10 each, equal to their baselines.
493
+ - Haiku 5.5: `mode-stop/off` and `mode-refusal/off`, 10 of 10 each, and every trial finished. Before the change, 4 and
494
+ 1 of 10 did not finish. Both are new baseline cells. `push-follow` and `push-no-refusal` passed 10 of 10 each, but 2
495
+ of 10 trials did not finish (90ab1ee4, 2b068c3a), so the scenario failed at "every trial finished" and wrote no
496
+ cell. The desk answered each time a `revise` took the coder back to `coding`: twice in 90ab1ee4 and five times in
497
+ 2b068c3a. Each run faulted within 30 s of the first answer, long before the cut, when the nudges ran out
498
+ (`agent completed its turn without a pick that ends it; still allowed: ask_approval, run_tests`). The prompt asks
499
+ only to run `sleep 20 && ls` and read the listing, and the Repo's tests fail. In 90ab1ee4 the model ran the tests,
500
+ read the 2 failures ("The work isn't done, so `submit` is wrong"), picked `revise`, did not fix them, and stopped.
501
+ In 2b068c3a the model made no change ("I won't call `submit` on empty work, and I won't request approval for a
502
+ change that doesn't exist"), and it looped on `revise` and `run_tests` until the nudges ran out. So the model will
503
+ not submit work that fails or that has no change, and it does not fix the tests.
504
+ - Sonnet 5.5: `mode-stop/off` 10 of 10, and every trial finished (before the change, none of 10 did): a new baseline
505
+ cell. `mode-refusal/off` 10 of 10 and `obedience/off` 9 of 10, equal to their baselines. At `medium`, `obedience/on`
506
+ gave 9 of 10, `ticket/on` 1 of 1 and `ticket-modes/on` 1 of 1: new baseline cells. In each `obedience` miss
507
+ (cfc238c8 off, b1c7a9a2 on), the model made no call before the nudge, then picked `hold`.
508
+
509
+ The first full Haiku run, of 2026-10-22, used main at cd6e6145, with this tier's Anthropic profiles. Later main
510
+ commits change what the model reads, among them ccd81ce9, eb76a3e4, 39a3610d, 8c274330 and 37bbf7ff. Others change how
511
+ the Harness runs the tool calls of one answer, among them be347513, ecb8c556 and 9d37d732. So the cells of that run
512
+ are not kept, and nor are the Sonnet 5.5 cells of a run on cd6e6145 (`obedience` and `ticket` only). Fourteen of
513
+ nineteen scenarios passed. Five failed: `noticed`, a defect in its step, and the four below. The causes, read off each
514
+ trial's evidence in `features/.tmp/model-trials/anthropic--claude-haiku-5-5/`:
515
+ - `noticed`. The setup of this run killed during the first Turn, and its step did not check that the kill landed
516
+ inside that Turn: a defect in the step. All the counts here come from that old setup. Haiku 5.5 often sends the
517
+ server's `bash` call and `started` in one response, so its first Turn ends before the server listens. This run
518
+ polled from the host every 3 s. Read with the later void rules of the old setup, 8 of its 10 trials are void. In 4,
519
+ the model sent the call and `started` in one response. In 4 more, the kill landed in the second Turn. The 2 measured
520
+ trials passed. Two diagnostic runs with a kill made in the pod sent the call and `started` in one response in 4 of
521
+ 14 and 7 of 15 trials. A third such run gave 10 of 10, which is not valid, because that kill let a blind Agent pass.
522
+ These trials also show a defect in what jr2 shows the model. Three of them (0e1ebfbf, 79c9a859, 92895334) and three
523
+ Qwen trials read a false answer to `started`: "the pick never reached the Orchestrator (This operation was
524
+ aborted)". Main fixes it (39a3610d).
525
+ - `mode-refusal`, 7 of 10, below its floor of 9. In the three misses the model read the correction receipt, which
526
+ named `publish` alone, and would not publish notes that it judged unreviewed: it called `revise`, which the
527
+ correction had already refused (e06c7019, ab93b886), or it stopped and the nudges ran out (393058c3, faulted). In
528
+ each, its text named `publish` as the one allowed pick, so it read the newest list; it refused the pick on the task.
529
+ - `mode-stop`, every measured trial passed, and 9 of 10 did not finish (for example 7f3ed024, cae14640, 9cb4a03a).
530
+ After the wake the model picked `revise`, an allowed pick. Then it called `ask_review` again, whose receipt allows
531
+ nothing, and it stopped each time: the loop `revise`, `ask_review`, stop ran until the nudge budget faulted the run.
532
+ - `push-follow` and `push-no-refusal`, every measured trial passed both cells, and 6 of 10 did not finish (586bdcf9,
533
+ 9eae17a0, 855dd8ce, 1e78473f, 9b1d3c83, 565587a2). After a `revise` whose receipt said "…so it is not over yet" and
534
+ allowed `ask_approval` and `run_tests`, the model ended its Submission with text ("I'll wait for the next prompt"),
535
+ and the nudges ran out (`agent completed its turn without a pick that ends it`). The scenario failed at "every trial
536
+ finished", so neither cell was written.
537
+ - `continue-after-signed-push`, 4 of 10, below its floor of 9. Six trials were void past the bound (921a5999,
538
+ 6ba4640a, a9aba70e, 600bb85a, ba0ac32c, a63db6b3): the first push published no signed copy. The Sandbox has no git
539
+ identity, so the model's first `git commit` failed, and the model sent the commit and `publish` in one response, so
540
+ `publish` pushed only `init`. The model then set an identity and committed, so its later pushes published.
541
+
542
+ After that run, main gave the Sandbox's git a default author (7d7f7f5) and changed the "…so it is not over yet"
543
+ receipt (eb76a3e). The run of 2026-10-23 measured each of the five again. `noticed` and `continue-after-signed-push`
544
+ gave 10 of 10, and `mode-refusal`, `mode-stop` and `push-follow` are the three Haiku scenarios above.
545
+
546
+ - The drivers' readings of the printed conversation, of a workflow's modes and of a restarted Harness container are
547
+ plain functions in `features/lib/model-said.ts`, the readings of a trial's kept evidence are in
548
+ `features/lib/model-evidence.ts`, and what each claim workflow means by "finished" is a table in
549
+ `features/lib/model-finished.ts`, with unit tests beside them that need no cluster and no model.
550
+ - The run has a second form, `ticket-modes`: one coder Turn walks three modes of its state to a verified commit.
551
+ - A claim whose notice no step can yet raise (Compaction's summary, a kernel group kill) is added when the step exists;
552
+ the ADR does not wait on it.