@jr2/orchestrator 0.4.1 → 0.5.1
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.
- package/README.md +20 -2
- package/console/components/app.ts +2 -0
- package/console/components/fleet.ts +14 -1
- package/console/components/machine-pane.ts +41 -2
- package/console/main.ts +13 -1
- package/console/store.ts +102 -6
- package/console/style.css +21 -0
- package/docs/agents-block.md +5 -0
- package/docs/concepts/agents-and-turns.md +442 -0
- package/docs/concepts/architecture.md +230 -0
- package/docs/concepts/charts.md +143 -0
- package/docs/concepts/composition.md +357 -0
- package/docs/concepts/converge.md +254 -0
- package/docs/concepts/durable-runs.md +189 -0
- package/docs/concepts/effects.md +603 -0
- package/docs/concepts/gates.md +208 -0
- package/docs/concepts/machines-and-workflows.md +289 -0
- package/docs/concepts/pools-and-sources.md +230 -0
- package/docs/concepts/secrets-and-trust.md +222 -0
- package/docs/concepts/the-menu.md +378 -0
- package/docs/concepts/workspaces.md +678 -0
- package/docs/get-started/a-model-decides.md +563 -0
- package/docs/get-started/an-agent-in-a-sandbox.md +381 -0
- package/docs/get-started/connect-a-model.md +248 -0
- package/docs/get-started/create-an-instance.md +194 -0
- package/docs/get-started/have-your-assistant-write-a-machine.md +922 -0
- package/docs/get-started/install.md +126 -0
- package/docs/guides/add-tools-to-the-sandbox.md +295 -0
- package/docs/guides/answer-a-gate.md +304 -0
- package/docs/guides/bind-open-parts.md +223 -0
- package/docs/guides/cancel-a-run.md +146 -0
- package/docs/guides/clean-up.md +206 -0
- package/docs/guides/fix-a-failed-converge.md +361 -0
- package/docs/guides/give-the-cluster-git-credentials.md +222 -0
- package/docs/guides/iterate-on-a-machine-on-kind.md +190 -0
- package/docs/guides/let-an-agent-write-a-chart.md +226 -0
- package/docs/guides/look-inside-a-sandbox.md +174 -0
- package/docs/guides/mirror-the-kit-images.md +176 -0
- package/docs/guides/move-from-kind-to-a-shared-cluster.md +302 -0
- package/docs/guides/open-the-console.md +91 -0
- package/docs/guides/publish-a-machine-as-an-npm-package.md +350 -0
- package/docs/guides/push-and-sign-a-branch.md +486 -0
- package/docs/guides/run-a-chart-by-name.md +270 -0
- package/docs/guides/run-a-command-or-call-a-url.md +544 -0
- package/docs/guides/run-one-worker-per-item.md +321 -0
- package/docs/guides/set-an-agents-access-and-dials.md +375 -0
- package/docs/guides/size-a-workspace.md +204 -0
- package/docs/guides/start-a-run-from-a-run.md +237 -0
- package/docs/guides/start-a-run.md +207 -0
- package/docs/guides/upgrade-the-kit-version.md +240 -0
- package/docs/guides/use-a-hosted-provider.md +208 -0
- package/docs/guides/use-a-local-model.md +313 -0
- package/docs/guides/watch-a-run.md +326 -0
- package/docs/guides/write-a-workflow.md +318 -0
- package/docs/index.md +44 -0
- package/docs/llms.txt +216 -0
- package/docs/reference/authoring-surface/agent.md +128 -0
- package/docs/reference/authoring-surface/answer.md +140 -0
- package/docs/reference/authoring-surface/arg.md +60 -0
- package/docs/reference/authoring-surface/basic.md +62 -0
- package/docs/reference/authoring-surface/bearer.md +53 -0
- package/docs/reference/authoring-surface/chartschema.md +23 -0
- package/docs/reference/authoring-surface/chartschemafor.md +48 -0
- package/docs/reference/authoring-surface/command.md +191 -0
- package/docs/reference/authoring-surface/customize.md +64 -0
- package/docs/reference/authoring-surface/defineconfig.md +41 -0
- package/docs/reference/authoring-surface/defineevent.md +114 -0
- package/docs/reference/authoring-surface/dispatch.md +126 -0
- package/docs/reference/authoring-surface/fail.md +83 -0
- package/docs/reference/authoring-surface/file.md +122 -0
- package/docs/reference/authoring-surface/frompick.md +277 -0
- package/docs/reference/authoring-surface/http.md +159 -0
- package/docs/reference/authoring-surface/isfailure.md +58 -0
- package/docs/reference/authoring-surface/jr2setup.md +237 -0
- package/docs/reference/authoring-surface/open.md +74 -0
- package/docs/reference/authoring-surface/openbody.md +86 -0
- package/docs/reference/authoring-surface/paramsof.md +125 -0
- package/docs/reference/authoring-surface/pool.md +186 -0
- package/docs/reference/authoring-surface/push.md +112 -0
- package/docs/reference/authoring-surface/secret.md +118 -0
- package/docs/reference/authoring-surface/sentby.md +83 -0
- package/docs/reference/authoring-surface/source.md +51 -0
- package/docs/reference/authoring-surface/text.md +62 -0
- package/docs/reference/authoring-surface/type-agentdeclaration.md +27 -0
- package/docs/reference/authoring-surface/type-agentdefinition.md +80 -0
- package/docs/reference/authoring-surface/type-agentlogic.md +15 -0
- package/docs/reference/authoring-surface/type-agentslots.md +12 -0
- package/docs/reference/authoring-surface/type-answeraction.md +12 -0
- package/docs/reference/authoring-surface/type-arg.md +19 -0
- package/docs/reference/authoring-surface/type-argnames.md +12 -0
- package/docs/reference/authoring-surface/type-binding.md +62 -0
- package/docs/reference/authoring-surface/type-bindingof.md +12 -0
- package/docs/reference/authoring-surface/type-bodyacceptsdoor.md +15 -0
- package/docs/reference/authoring-surface/type-bodyacceptsslots.md +17 -0
- package/docs/reference/authoring-surface/type-ceilings.md +41 -0
- package/docs/reference/authoring-surface/type-chainlink.md +19 -0
- package/docs/reference/authoring-surface/type-chartaction.md +46 -0
- package/docs/reference/authoring-surface/type-chartagent.md +28 -0
- package/docs/reference/authoring-surface/type-chartevent.md +20 -0
- package/docs/reference/authoring-surface/type-chartguard.md +20 -0
- package/docs/reference/authoring-surface/type-chartinvoke.md +28 -0
- package/docs/reference/authoring-surface/type-chartjson.md +14 -0
- package/docs/reference/authoring-surface/type-chartstate.md +46 -0
- package/docs/reference/authoring-surface/type-charttext.md +40 -0
- package/docs/reference/authoring-surface/type-charttransition.md +22 -0
- package/docs/reference/authoring-surface/type-charttransitions.md +14 -0
- package/docs/reference/authoring-surface/type-chartvalue.md +15 -0
- package/docs/reference/authoring-surface/type-childat.md +12 -0
- package/docs/reference/authoring-surface/type-childslots.md +12 -0
- package/docs/reference/authoring-surface/type-commandenv.md +15 -0
- package/docs/reference/authoring-surface/type-commandinput.md +19 -0
- package/docs/reference/authoring-surface/type-commandoptions.md +78 -0
- package/docs/reference/authoring-surface/type-commandoutput.md +104 -0
- package/docs/reference/authoring-surface/type-customize.md +109 -0
- package/docs/reference/authoring-surface/type-dispatchdefinition.md +39 -0
- package/docs/reference/authoring-surface/type-dispatchinput.md +14 -0
- package/docs/reference/authoring-surface/type-dispatchopenparts.md +14 -0
- package/docs/reference/authoring-surface/type-dispatchoutput.md +65 -0
- package/docs/reference/authoring-surface/type-duration.md +15 -0
- package/docs/reference/authoring-surface/type-effectbinding.md +93 -0
- package/docs/reference/authoring-surface/type-effectlogic.md +12 -0
- package/docs/reference/authoring-surface/type-envopenparts.md +14 -0
- package/docs/reference/authoring-surface/type-eventaudience.md +27 -0
- package/docs/reference/authoring-surface/type-eventdef.md +45 -0
- package/docs/reference/authoring-surface/type-eventfrom.md +16 -0
- package/docs/reference/authoring-surface/type-eventsemantics.md +26 -0
- package/docs/reference/authoring-surface/type-execoutcome.md +34 -0
- package/docs/reference/authoring-surface/type-failslot.md +14 -0
- package/docs/reference/authoring-surface/type-failure.md +19 -0
- package/docs/reference/authoring-surface/type-failureinput.md +20 -0
- package/docs/reference/authoring-surface/type-filebody.md +41 -0
- package/docs/reference/authoring-surface/type-frominput.md +14 -0
- package/docs/reference/authoring-surface/type-hostinjectedinput.md +58 -0
- package/docs/reference/authoring-surface/type-httpdefinition.md +101 -0
- package/docs/reference/authoring-surface/type-httpinput.md +12 -0
- package/docs/reference/authoring-surface/type-httpmethod.md +14 -0
- package/docs/reference/authoring-surface/type-httpopenparts.md +12 -0
- package/docs/reference/authoring-surface/type-httpoutput.md +89 -0
- package/docs/reference/authoring-surface/type-httprequestparts.md +33 -0
- package/docs/reference/authoring-surface/type-jr2config.md +126 -0
- package/docs/reference/authoring-surface/type-lends.md +38 -0
- package/docs/reference/authoring-surface/type-logicat.md +12 -0
- package/docs/reference/authoring-surface/type-markedif.md +12 -0
- package/docs/reference/authoring-surface/type-mergedactors.md +12 -0
- package/docs/reference/authoring-surface/type-namedsecret.md +25 -0
- package/docs/reference/authoring-surface/type-noslotspec.md +26 -0
- package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +32 -0
- package/docs/reference/authoring-surface/type-openbodydeclaration.md +40 -0
- package/docs/reference/authoring-surface/type-openbodylogic.md +14 -0
- package/docs/reference/authoring-surface/type-openbodyoutput.md +42 -0
- package/docs/reference/authoring-surface/type-openbodyslot.md +18 -0
- package/docs/reference/authoring-surface/type-opencommandinput.md +17 -0
- package/docs/reference/authoring-surface/type-openeffect.md +12 -0
- package/docs/reference/authoring-surface/type-openeffectslots.md +12 -0
- package/docs/reference/authoring-surface/type-openof.md +12 -0
- package/docs/reference/authoring-surface/type-opensecret.md +23 -0
- package/docs/reference/authoring-surface/type-opensecretmark.md +12 -0
- package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +31 -0
- package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +32 -0
- package/docs/reference/authoring-surface/type-poolmachine.md +28 -0
- package/docs/reference/authoring-surface/type-poolspec.md +60 -0
- package/docs/reference/authoring-surface/type-pushinput.md +15 -0
- package/docs/reference/authoring-surface/type-pushoptions.md +79 -0
- package/docs/reference/authoring-surface/type-pushoutput.md +124 -0
- package/docs/reference/authoring-surface/type-pushwireoutput.md +12 -0
- package/docs/reference/authoring-surface/type-quantity.md +14 -0
- package/docs/reference/authoring-surface/type-reached.md +12 -0
- package/docs/reference/authoring-surface/type-reposlot.md +70 -0
- package/docs/reference/authoring-surface/type-reposlotsof.md +16 -0
- package/docs/reference/authoring-surface/type-sandboxoptions.md +77 -0
- package/docs/reference/authoring-surface/type-secret.md +25 -0
- package/docs/reference/authoring-surface/type-sender.md +19 -0
- package/docs/reference/authoring-surface/type-sentbyguards.md +12 -0
- package/docs/reference/authoring-surface/type-size.md +85 -0
- package/docs/reference/authoring-surface/type-slothandles.md +32 -0
- package/docs/reference/authoring-surface/type-sourcenextresult.md +17 -0
- package/docs/reference/authoring-surface/type-sourcespec.md +44 -0
- package/docs/reference/authoring-surface/type-syncstate.md +12 -0
- package/docs/reference/authoring-surface/type-text.md +19 -0
- package/docs/reference/authoring-surface/type-textpart.md +24 -0
- package/docs/reference/authoring-surface/type-thinkinglevel.md +39 -0
- package/docs/reference/authoring-surface/type-toparameterizedobject.md +14 -0
- package/docs/reference/authoring-surface/type-toprovidedactor.md +14 -0
- package/docs/reference/authoring-surface/type-unknown.md +21 -0
- package/docs/reference/authoring-surface/type-usercontainer.md +77 -0
- package/docs/reference/authoring-surface/type-withoutemptyindex.md +20 -0
- package/docs/reference/authoring-surface/type-workflowevent.md +46 -0
- package/docs/reference/authoring-surface/type-workspaceaccess.md +16 -0
- package/docs/reference/authoring-surface/type-workspaced.md +94 -0
- package/docs/reference/authoring-surface/type-workspacehandles.md +23 -0
- package/docs/reference/authoring-surface/type-workspacemachine.md +29 -0
- package/docs/reference/authoring-surface/type-workspaceof.md +13 -0
- package/docs/reference/authoring-surface/type-workspaceoptions.md +39 -0
- package/docs/reference/authoring-surface/type-workspacespec.md +37 -0
- package/docs/reference/authoring-surface/workspace.md +259 -0
- package/docs/reference/authoring-surface.md +197 -0
- package/docs/reference/cli.md +433 -0
- package/docs/reference/config.md +756 -0
- package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +113 -0
- package/docs/reference/decisions/0002-duplex-streaming-actor.md +110 -0
- package/docs/reference/decisions/0004-worktree-provisioning-model.md +124 -0
- package/docs/reference/decisions/0005-sandbox-pod-composition.md +230 -0
- package/docs/reference/decisions/0006-agent-control-surface.md +47 -0
- package/docs/reference/decisions/0007-durable-machine-state.md +109 -0
- package/docs/reference/decisions/0008-orchestrator-as-deployed-app.md +60 -0
- package/docs/reference/decisions/0009-cli-and-instance-interface.md +275 -0
- package/docs/reference/decisions/0010-bdd-acceptance-tests.md +160 -0
- package/docs/reference/decisions/0011-workflow-defined-events.md +141 -0
- package/docs/reference/decisions/0012-workspace-wrapper-machine.md +103 -0
- package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +157 -0
- package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +95 -0
- package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +265 -0
- package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +124 -0
- package/docs/reference/decisions/0017-pool-over-a-source-port.md +69 -0
- package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +111 -0
- package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +275 -0
- package/docs/reference/decisions/0020-private-ca-trust-is-a-named-concept.md +60 -0
- package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +100 -0
- package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +103 -0
- package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +176 -0
- package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +439 -0
- package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +65 -0
- package/docs/reference/decisions/0026-a-turn-that-is-over-is-never-prompted.md +62 -0
- package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +237 -0
- package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +89 -0
- package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +154 -0
- package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +100 -0
- package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +190 -0
- package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +61 -0
- package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +127 -0
- package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +57 -0
- package/docs/reference/decisions/0035-a-runaway-turn-is-ended-rerolled-once-then-a-fault.md +92 -0
- package/docs/reference/decisions/0036-a-turn-compacts-its-own-context-mid-flight.md +138 -0
- package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +196 -0
- package/docs/reference/decisions/0038-jr2-up-builds-every-image-it-deploys.md +170 -0
- package/docs/reference/decisions/0039-image-garbage-collects-by-reachability.md +115 -0
- package/docs/reference/decisions/0041-a-build-the-host-already-holds-is-not-spent-again.md +64 -0
- package/docs/reference/decisions/0042-ready-is-not-routable-an-admission-retries-its-connection.md +142 -0
- package/docs/reference/decisions/0043-the-kit-is-tested-as-installed-a-local-registry-stands-in-for-npm.md +170 -0
- package/docs/reference/decisions/0044-kit-images-live-at-a-canonical-home-a-self-host-mirrors-it.md +85 -0
- package/docs/reference/decisions/0045-the-platform-joins-the-image-address-and-the-cluster-chooses-it.md +82 -0
- package/docs/reference/decisions/0046-a-converge-failure-carries-its-diagnosis.md +34 -0
- package/docs/reference/decisions/0047-the-git-ssh-key-source-is-the-users-choice.md +47 -0
- package/docs/reference/decisions/0048-the-orchestrator-boots-without-its-repos.md +36 -0
- package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +126 -0
- package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +73 -0
- package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +227 -0
- package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +81 -0
- package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +111 -0
- package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +126 -0
- package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +107 -0
- package/docs/reference/decisions/0056-a-global-jr2-hands-off-to-the-instances-own-and-an-instance-has-one-kit-version.md +62 -0
- package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +152 -0
- package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +106 -0
- package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +384 -0
- package/docs/reference/decisions/0060-a-workspace-states-its-size-and-jr2-reserves-all-of-it.md +111 -0
- package/docs/reference/decisions/0061-a-memory-kill-ends-the-agents-processes-not-the-harness.md +83 -0
- package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +212 -0
- package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +83 -0
- package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +79 -0
- package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +65 -0
- package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +550 -0
- package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +430 -0
- package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +464 -0
- package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +180 -0
- package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +323 -0
- package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +183 -0
- package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +144 -0
- package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +122 -0
- package/docs/reference/decisions/0074-an-unrouted-mechanism-event-is-refused-at-load-and-faults-the-run.md +76 -0
- package/docs/reference/decisions.md +83 -0
- package/docs/reference/glossary.md +648 -0
- package/docs/reference/http-api.md +1348 -0
- package/docs/reference/machines.md +190 -0
- package/docs/reference/mechanism-events.md +72 -0
- package/docs/why.md +206 -0
- package/package.json +5 -3
- package/src/actor.ts +541 -79
- package/src/agent.ts +114 -38
- package/src/ambient.ts +2 -1
- package/src/assembly-checks.ts +189 -7
- package/src/cause.ts +234 -0
- package/src/chart.ts +169 -37
- package/src/charts.ts +34 -6
- package/src/config.ts +430 -178
- package/src/custodian.ts +74 -22
- package/src/customize.ts +188 -46
- package/src/dispatch-effect.ts +945 -0
- package/src/door-compat.ts +217 -0
- package/src/durability.ts +11 -4
- package/src/effect.ts +341 -44
- package/src/effector-wire.ts +160 -11
- package/src/fail.ts +209 -0
- package/src/harness-client.ts +541 -47
- package/src/http-effect.ts +495 -53
- package/src/http.ts +427 -16
- package/src/index.ts +60 -82
- package/src/instance.ts +68 -8
- package/src/internal.ts +84 -0
- package/src/machine-doc.ts +21 -3
- package/src/mechanism-routes.ts +168 -0
- package/src/model-keys.generated.ts +53 -0
- package/src/model-keys.ts +18 -58
- package/src/notices.ts +66 -13
- package/src/open-body.ts +159 -23
- package/src/open-effect.ts +81 -8
- package/src/open.ts +59 -6
- package/src/parts.ts +184 -13
- package/src/party.ts +68 -2
- package/src/pick.ts +463 -11
- package/src/pool.ts +247 -36
- package/src/registration.ts +83 -4
- package/src/repos.ts +2 -1
- package/src/run-host.ts +565 -31
- package/src/run-output.ts +38 -0
- package/src/sandbox-effect.ts +273 -38
- package/src/sandbox-kube.ts +3 -1
- package/src/secret-placement.ts +52 -17
- package/src/server.ts +3 -0
- package/src/setup.ts +239 -56
- package/src/size.ts +121 -9
- package/src/snapshot-store.ts +54 -10
- package/src/stub-harness.ts +44 -16
- package/src/timers.ts +14 -1
- package/src/vocabulary.ts +69 -14
- package/src/wire.ts +90 -16
- package/src/workspace.ts +697 -175
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Observation is a level-triggered feed, and an API before it is a page
|
|
2
|
+
|
|
3
|
+
The visualizer never updated (2026-07-19). Not slowly — structurally, in three independent ways, and each one looked
|
|
4
|
+
healthy while it failed.
|
|
5
|
+
|
|
6
|
+
**New runs could not appear.** The page's run list came from a one-shot `GET /workflows/:name/runs` at boot, with a ↻
|
|
7
|
+
button beside it. There was no push channel to subscribe to: `RunHost` held per-**run** listener sets, and `start()`
|
|
8
|
+
notified nobody, because nobody existed to notify. A run started after page load was unreachable by any means short of a
|
|
9
|
+
reload. The ↻ button was not a convenience; it was the workaround.
|
|
10
|
+
|
|
11
|
+
**A dropped stream was permanently and invisibly fatal.** The page set `feed.onerror = () => feed.close()`, defeating
|
|
12
|
+
EventSource's own reconnect. `onerror` cannot distinguish a clean terminal close from a blip, so the handler had to
|
|
13
|
+
assume the harmless case and got the other one — after which the diagram sat there, wearing its last highlight, saying
|
|
14
|
+
nothing.
|
|
15
|
+
|
|
16
|
+
**Nothing wrote when nothing happened.** Every feed wrote only on transitions. A run parked on a gate for hours wrote
|
|
17
|
+
zero bytes, so any idle intermediary dropped the connection. This is the same gap that surfaced as `error: terminated`
|
|
18
|
+
on an attached `jr2 run` — undici's message for a `fetch()` body that died mid-read, which reads like a run failure and
|
|
19
|
+
was not one. The run was fine the whole time.
|
|
20
|
+
|
|
21
|
+
The common cause is that observation had been built as a **feature of a page** rather than as a surface. A page feature
|
|
22
|
+
can get away with fetching once, because a person can press a button; an API cannot. So the fix is not a page patch.
|
|
23
|
+
|
|
24
|
+
## Decision
|
|
25
|
+
|
|
26
|
+
- **The observation API is real-time, and the page is its first consumer — not its purpose.** An external dashboard, a
|
|
27
|
+
CI annotator, or a chat bot should be able to track a workflow without running our HTML. Every choice below is weighed
|
|
28
|
+
against that reader rather than against ours.
|
|
29
|
+
- **`GET /workflows/:name/events`** (open band) — one connection carrying a whole workflow: every run of it appearing,
|
|
30
|
+
moving, emitting and leaving, for as long as the caller stays attached. It outlives every run on it.
|
|
31
|
+
- **Level-triggered, not event-sourced.** `status` always carries a whole `RunObservation`, never a patch, and the
|
|
32
|
+
opening `runs` frame carries the entire live set. A reconnecting client therefore converges with **no replay buffer,
|
|
33
|
+
no `Last-Event-ID`, and no per-client state on the server**; re-delivery of any frame is idempotent by construction,
|
|
34
|
+
so there is no gap to detect and no cursor to resume from. Same reconciliation idiom as the Lease (ADR-0021) and
|
|
35
|
+
`jr2 up` (ADR-0019): say the whole truth, repeatedly, and let the reader converge.
|
|
36
|
+
- **Two granularities, one vocabulary.** The per-run feed stays — tracking exactly one run is a legitimate thing to
|
|
37
|
+
want, and it is what `jr2 run` and `jr2 logs -f` already do. Every run-scoped frame carries `runId` even where the
|
|
38
|
+
route makes it redundant, so one parser serves both.
|
|
39
|
+
- **`gone` is a fact, not an inference.** A run can leave the live set _without_ a terminal status: `stop()`
|
|
40
|
+
deliberately leaves the stored status `"live"` so a later `restore()` picks the run back up. A client watching for
|
|
41
|
+
`status === "done"` would show a stopped run as live forever, so departure is stated outright.
|
|
42
|
+
- **The workflow's listener set belongs to the host**, keyed by name — not to any `LiveRun`. `persist()` clears a
|
|
43
|
+
settled run's own listener set, and a workflow's watcher must survive every run it watches. Placing the set on the
|
|
44
|
+
host makes that structurally true instead of a comment asking the next reader not to clear the wrong one.
|
|
45
|
+
- **A quiet feed pings**: an SSE comment frame every 15s, on all three feeds. It is deliberately **not** Lease
|
|
46
|
+
vocabulary — GLOSSARY.md puts _heartbeat_ and _keepalive_ on that entry's Avoid list, and this asserts nothing and
|
|
47
|
+
expects no answer. The write doubles as the liveness probe: a failed write is how a silently-dead peer is discovered,
|
|
48
|
+
which is why it is wired to the handler's exit.
|
|
49
|
+
- **A settled run is the client's own memory.** A run appears in the page's `settled` list iff _this page_ watched it
|
|
50
|
+
leave. After a hard reload they are gone, and that is correct rather than a defect: serving a finished run's state to
|
|
51
|
+
an unauthenticated reader is a read-through, which stays behind the Instance token on `/runs/:id` (ADR-0014).
|
|
52
|
+
- **`jr2 visualize` is deleted.** Its job was to find an orchestrator, forward a port, and open a browser. With the page
|
|
53
|
+
now useful on its own, that is one `kubectl port-forward` the reader already knows how to run — and the command's
|
|
54
|
+
ephemeral-fallback path was quietly forwarding to a _different_ instance than the deployed one. Its one unique piece
|
|
55
|
+
of value, the opaque-states warning, moves onto the page as `MachineDoc.opaqueStates`, where the person looking at the
|
|
56
|
+
diagram can read it.
|
|
57
|
+
- **A frame is rendered once, and a slow reader is closed, not queued.** Every subscriber of a feed receives the same
|
|
58
|
+
wire string, rendered once per event, never once per subscriber. A subscriber has a bounded backlog of unread writes,
|
|
59
|
+
judged at each ping: one that still leaves the bound's worth of writes unread a whole ping interval after they were
|
|
60
|
+
sent has fallen behind, and is closed. Lag, not burst size — one transition's Emits reach every subscriber in the same
|
|
61
|
+
tick, and a reader that keeps up drains them before any ping judges it. Closing is safe because the feed is
|
|
62
|
+
level-triggered: the client reconnects and receives the whole current truth, having missed no state — only activity
|
|
63
|
+
(Emits, retries) that fell in the gap. A page reconnects with EventSource's own retry; the CLI (`jr2 run`,
|
|
64
|
+
`jr2 logs -f`) re-attaches any feed that ends before a terminal status, and never reads such an end as the run's —
|
|
65
|
+
except `gone`: a run stopped before it settled (parked, ADR-0025) reads through as `active`, so its one-shot feed says
|
|
66
|
+
`gone` after the status, and the CLI ends there instead of re-attaching in a loop. The server keeps no per-client
|
|
67
|
+
queue and no slow-client accounting beyond counting the subscriber's writes (scaling review R10, 2026-09-30).
|
|
68
|
+
- **Shutdown ends feeds explicitly.** `RunHost.close()` delivers `closed` to every listener. `server.close()` waits for
|
|
69
|
+
in-flight requests and an observation feed has no end of its own, so without this a single attached watcher wedges
|
|
70
|
+
`jr2 dev` shutdown indefinitely.
|
|
71
|
+
|
|
72
|
+
The new route stays _inside_ the band ADR-0014 drew: no context, no `instanceId` and no `fault` at any depth, emit type
|
|
73
|
+
only, scoped to one workflow the caller can already name, and no store read-through.
|
|
74
|
+
|
|
75
|
+
## Considered options
|
|
76
|
+
|
|
77
|
+
- **Poll faster.** The ↻ button on an interval. Rejected because it is wrong at both ends: too slow to watch a run by,
|
|
78
|
+
and pure waste against an instance where nothing is happening — which is most of the time. It also leaves the
|
|
79
|
+
`onerror` and idle-timeout failures untouched, since those are not staleness.
|
|
80
|
+
- **A patch/delta feed with a replay buffer.** More efficient on the wire, and genuinely wrong here: it makes every
|
|
81
|
+
client stateful, forces a `Last-Event-ID` cursor and server-side retention, and turns a dropped frame into permanent
|
|
82
|
+
divergence with no way to notice. A whole observation is a few hundred bytes on transitions a human is watching. We
|
|
83
|
+
are nowhere near the volume that would justify buying complexity with correctness.
|
|
84
|
+
- **Fold the per-run feed into the workflow feed.** One route is simpler. Rejected: a consumer tracking one run would
|
|
85
|
+
have to receive and discard every sibling's traffic, and `jr2 run` — the most common consumer — is exactly that case.
|
|
86
|
+
- **Give the page a WebSocket.** Bidirectional, and nothing here needs a back-channel; control is on the guarded
|
|
87
|
+
surface, deliberately. SSE reconnects on its own, survives proxies, and needs no client library.
|
|
88
|
+
- **Keep `jr2 visualize`, deprecated.** Rejected as the worse of the two: a command whose whole remaining value is
|
|
89
|
+
opening a browser, still carrying the port-forward path that could attach to the wrong instance.
|
|
90
|
+
|
|
91
|
+
## Consequences
|
|
92
|
+
|
|
93
|
+
- **Kill-detection latency is untouched** and remains the ~5-minute Lease poll (ADR-0021). The feed reports what the
|
|
94
|
+
Orchestrator believes; a workspace lost 4 minutes ago is still believed live, and now says so in real time. Lowering
|
|
95
|
+
that interval, or watching Sandbox CRs, is a separate decision.
|
|
96
|
+
- A body machine cannot ignore `workspace.lost`: `workspace()` refuses a body with no route for it, and an event that no
|
|
97
|
+
transition takes faults the run
|
|
98
|
+
([ADR-0074](0074-an-unrouted-mechanism-event-is-refused-at-load-and-faults-the-run.md)). The feed reports the machine;
|
|
99
|
+
it does not second-guess it.
|
|
100
|
+
- The page has no reload button and no reload path for settled runs — by design, per the memory rule above.
|
|
101
|
+
- `viz/store.js` exists so the client's logic is a pure reducer testable under `node:test`. The repo still has no jsdom
|
|
102
|
+
and no browser driver, and this ADR is not an argument for adding one: the renderer is a pure function of
|
|
103
|
+
`(doc, status)`, and everything else the page believes now lives in a function that takes a store and a frame.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# The Harness prints the conversation, and the reasoning is the part that prints
|
|
2
|
+
|
|
3
|
+
A running workflow is watchable and its Agents are not. The visualizer shows which states are lit (ADR-0022); the run
|
|
4
|
+
feed carries status and Emits (ADR-0009). What an Agent is actually _doing_ — what it read, what it tried, what it
|
|
5
|
+
concluded — appears nowhere, so inspecting a live run means `kubectl exec` into the Sandbox and reading the worktree and
|
|
6
|
+
`git log`. That is outcome inspection standing in for progress inspection: it says what changed, never why, and it says
|
|
7
|
+
nothing at all until something has changed.
|
|
8
|
+
|
|
9
|
+
jr solved this with `just watch` — an fzf list of live sessions over a preview that tailed the session JSONL through a
|
|
10
|
+
jq filter rendering four things: the prompt, assistant text, `[thinking]`, and one-line tool calls. Two panes: which
|
|
11
|
+
agents exist, and what this one is saying. This ADR is that, made Kubernetes-native.
|
|
12
|
+
|
|
13
|
+
**The conversation was never missing — jr2 declined it.** The Orchestrator awaits settlement as an opaque promise, "the
|
|
14
|
+
stream carries lifecycle only" — but the Harness's event stream already carries `message_start`/`message_end` bounding
|
|
15
|
+
both user and assistant messages, plus text, thinking, and tool-call content
|
|
16
|
+
([ADR-0027](0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md)) — every line of that jq filter,
|
|
17
|
+
replayable from any offset. The gap was a read decision, not a missing capability, and the fix is not new plumbing.
|
|
18
|
+
|
|
19
|
+
## Decision
|
|
20
|
+
|
|
21
|
+
- **The Harness prints, and `kubectl logs` reads.** The Harness writes its own conversation to container stdout —
|
|
22
|
+
in-process; the loopback subscription this originally required retired with the foreign runtime (ADR-0027).
|
|
23
|
+
`kubectl logs`, `stern`, `k9s`, and any log shipper work on it the day it lands, with no jr2 surface to build, learn,
|
|
24
|
+
or version.
|
|
25
|
+
- **The Harness is the right seat because it already holds both halves of the label.** It knows its Agent's name and the
|
|
26
|
+
iid arrives per Submission. So a line is `[<agent>] [<iid>] …` with no lookup, no correlation table, and no
|
|
27
|
+
orchestrator round trip. Every line of a body carries both, the later lines of a body that spans lines too. The iid is
|
|
28
|
+
what tells two conversations of one Agent apart in one log: the Instance Harness hosts the Menu-only Agents of every
|
|
29
|
+
run ([ADR-0031](0031-menu-only-agents-run-on-the-instance-harness.md)), so the runs in flight print into one log, and
|
|
30
|
+
a reader keeps one run's lines by the prefix `<runId>/` (a run's Agents sit at more than one Machine path, and a Turn
|
|
31
|
+
that does not continue, the conversation after one jr2 faulted, and a reroll each add a part to the iid). An iid
|
|
32
|
+
always holds a `/`, and a label never does, so a reader can tell the two apart. Nothing else in the pod knows both:
|
|
33
|
+
the Custodian sees routes and names, never a conversation, and working-tool execution happens inside the Harness,
|
|
34
|
+
invisible to every other jr2 process there.
|
|
35
|
+
- **Reasoning prints, and so does each pick's answer; a Working tool's result does not.** Prompts, assistant text,
|
|
36
|
+
thinking, tool calls with truncated inputs, and the answer to each Menu pick. The file contents, command output, and
|
|
37
|
+
API responses a Working tool returns never print. This is one cut serving two purposes, which is why it is a boundary
|
|
38
|
+
and not an unfinished implementation: a Working tool's results are whatever the Agent happened to read, which is where
|
|
39
|
+
a leaked secret lands, and they are also most of the bytes. A pick's answer is one bounded text per pick, and the
|
|
40
|
+
bullet below states what it can still carry. Every user message the model reads prints as a prompt — the Frame's
|
|
41
|
+
prompt with its Turn part, a nudge, and a Turn part the Harness restated at a step boundary
|
|
42
|
+
([ADR-0029](0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md)), which prints once as
|
|
43
|
+
`[<agent>] [<iid>] [prompt] <jr2-turn>` where the model read it.
|
|
44
|
+
- **A pick's answer prints after its call, as the model received it.** A Menu call's result is jr2's own text: the
|
|
45
|
+
receipt, an outstanding pick's answer with the reply it carries (an Effect's output, a Gate's event and payload) and
|
|
46
|
+
the paragraph after a push, a refusal ([ADR-0024](0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md),
|
|
47
|
+
[ADR-0067](0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md)). It prints as
|
|
48
|
+
`[<agent>] [<iid>] [<pick> answer] <text>`, or `[<pick> error] <text>` for an answer the model reads as an error (a
|
|
49
|
+
refusal while a pick is outstanding, a pick the tool's schema refused, a pick that never reached the Orchestrator),
|
|
50
|
+
under the same bound as a call's input, cut in its middle: the print keeps the answer's head (the receipt) and its end
|
|
51
|
+
(what follows the reply: the paragraph after a push, "Allowed now"), and marks the cut with the number of characters
|
|
52
|
+
it dropped, `… [<n> characters cut] …`. The bound is the log's copy only; the model reads the whole answer, which the
|
|
53
|
+
Orchestrator (a command's output tail) and the Effector (an `http` body) already bound. It is the text the model
|
|
54
|
+
already read, so printing it changes nothing the model reads; it is what lets a reader of the log, and the `@model`
|
|
55
|
+
tier's kept evidence ([ADR-0066](0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md)),
|
|
56
|
+
see what came back where the call alone said `[publish] {}`. The print scrubs nothing of its own, as the rest of the
|
|
57
|
+
conversation print scrubs nothing. What an Effector returns is scrubbed as
|
|
58
|
+
[ADR-0068](0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md) claims, before it signs its answer: it
|
|
59
|
+
does not return a secret it holds in the forms it sent or in common encodings. The scrub does not try to catch a
|
|
60
|
+
transformed secret (a hash, a truncation, an encoding it does not list), a partial echo, or a side channel, and a
|
|
61
|
+
credentialed command's child reads the secret its command names (the argv can run a file the Agent wrote), so it can
|
|
62
|
+
print that secret in such a form; then it reaches the log as it reaches the model. A `command` Effect in the Harness
|
|
63
|
+
container runs with no credential of its own. And the answer carries what the model read: an Effect's output, an
|
|
64
|
+
`http` body, a Gate's payload. A `command` Effect's output is command output from the Agent's own container and
|
|
65
|
+
environment, with the Stand-ins the Agent's `bash` holds, so a Held value that an upstream echoed into that output
|
|
66
|
+
(the Custodian does not scrub responses,
|
|
67
|
+
[ADR-0059](0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md)) reaches the log as it reaches the
|
|
68
|
+
model, up to the bound. Those two are the residual of printing a pick's answer, stated here and in ADR-0014. A Menu
|
|
69
|
+
call that one of two cuts left with no result gets jr2's text in the history
|
|
70
|
+
([ADR-0031](0031-menu-only-agents-run-on-the-instance-harness.md)), which the model reads on every later request: a
|
|
71
|
+
call a Harness restart cut while it was out reached the workflow, and its result comes in the next message; a call an
|
|
72
|
+
abort cut while the model was still writing it did not reach the workflow, and nothing ran. A call in a message a
|
|
73
|
+
provider error ended is no cut: pi runs no call of that message and drops it from every request, so jr2 gives the call
|
|
74
|
+
no text (ADR-0031). The call's line printed at its message's end, as every call's does; no answer prints for it. A cut
|
|
75
|
+
call's answer is no message pi emits, so the Harness prints it itself, once: as `[<pick> answer] <text>`, before the
|
|
76
|
+
next prompt of the conversation that ends in the call — the first prompt of the process after a restart, or the next
|
|
77
|
+
Submission's in the same process. A message's answers print in the order of its calls, whichever came back first, and
|
|
78
|
+
every prompt prints after the answers of the calls before it (a nudge, a restated Turn part and a re-admission alike),
|
|
79
|
+
so no call's answer prints after a prompt that follows it.
|
|
80
|
+
- **Two mechanic lines print.** A Compaction prints
|
|
81
|
+
`[<agent>] [<iid>] [compacted] context <before> → ~<after> tokens (window <w>)` where it cuts
|
|
82
|
+
([ADR-0036](0036-a-turn-compacts-its-own-context-mid-flight.md)). When a model has no level of the name the Turn asked
|
|
83
|
+
for ([ADR-0018](0018-instance-agents-are-definitions-jr2-assembles-the-harness.md)), the Harness prints, once in a
|
|
84
|
+
Submission and before the first answer a provider gave, the level that the model ran at:
|
|
85
|
+
`[thinking level] <provider>/<id> has no level "<asked>"; the Harness sent "<level>"` when the Harness clamped the
|
|
86
|
+
level and sent the result, `the Harness sent effort "<word>"` when the Harness's own request sent the provider's word
|
|
87
|
+
for the level (Claude Sonnet 5.5 at `off` gets effort `high`), `the provider chose "<word>"` when the answer names it,
|
|
88
|
+
and `the provider chose the level` when the Harness does not know. At `off` the Harness sends no level, so an OpenAI
|
|
89
|
+
completions model with no `off` gets no reasoning field, and the line says that the provider chose. Neither line is on
|
|
90
|
+
the wire or in the history, and the model reads neither.
|
|
91
|
+
- **The writer structures, the reader colorizes.** Lines carry a parseable prefix and no ANSI. jr's colors were correct
|
|
92
|
+
for an fzf preview, which is a terminal; `kubectl logs` output is piped, grepped, and ingested, where escape codes are
|
|
93
|
+
corruption. A future reader may colorize on `isatty`.
|
|
94
|
+
- **A Harness also prints the run's narrative — feed events the Orchestrator pushes to an echo endpoint.** A Workspace's
|
|
95
|
+
pod log should read as the whole story of the run that owns it: not just the conversations hosted there, but the
|
|
96
|
+
decisions and Emits that happened around them — a ticket claimed before the Workspace existed, a Menu pick a
|
|
97
|
+
[Menu-only Agent](0031-menu-only-agents-run-on-the-instance-harness.md) made on the Instance Harness. The mechanism is
|
|
98
|
+
a projection of the observation feed (ADR-0022), not a second record: the Harness wire gains one endpoint ("print
|
|
99
|
+
these events"), gated like every Harness route on the placement's bearer
|
|
100
|
+
([ADR-0058](0058-a-harness-answers-the-orchestrator-alone.md)), and the Orchestrator — the feed's one subscriber —
|
|
101
|
+
tees the owning run's events to the enclosing Workspace's Harness. At attach it replays the run's feed-so-far (the log
|
|
102
|
+
opens with its preamble: why this Workspace exists); thereafter it tees live. The Harness renders — the wire payload
|
|
103
|
+
is the structured event, and printing stays this ADR's craft. Three boundaries: **markers, not mirrors** — a
|
|
104
|
+
remotely-hosted Turn echoes its admission and its pick, never its transcript (the transcript prints exactly once,
|
|
105
|
+
where the Turn ran); **fire and forget** — a failed echo never fails anything, the feed remains the record and the log
|
|
106
|
+
is a courtesy view; **Emit is the only author API** — a workflow that wants prose in the log Emits it (ADR-0011's
|
|
107
|
+
vocabulary discipline holds; no `log()` primitive exists or will). The echo's lines carry no iid: `[run] [status] …`,
|
|
108
|
+
`[run] [emit] …`, `[<agent>] [admitted] …` and `[<agent>] [pick] …`. A Workspace's Harness serves one run, so its log
|
|
109
|
+
needs no run in a line, and a marker stands for a conversation that is in another log.
|
|
110
|
+
- **A status is a level, so the echo coalesces it.** In an echo's queue, pending statuses collapse to the latest;
|
|
111
|
+
markers and Emits keep their order. A Harness that answers slowly holds at most one status plus the markers since its
|
|
112
|
+
last push, and a burst of transitions across a Pool's workers costs each Harness one push per flush, not one per
|
|
113
|
+
transition. The replay buffer follows the same rule: it keeps the markers and Emits (bounded) and the latest status,
|
|
114
|
+
so the preamble reads "the story so far, and where the run stands now" — old statuses are not interleaved between old
|
|
115
|
+
markers; the live tail keeps the interleaving (scaling review R10, 2026-09-30).
|
|
116
|
+
- **Pod-bound, and jr2 promises nothing beyond the pod.** A conversation lives as long as its Sandbox (ADR-0027,
|
|
117
|
+
ADR-0031), so a Sandbox teardown (ADR-0012) or a lost Workspace (ADR-0021) takes it with it — the same contract
|
|
118
|
+
ADR-0012 already set for the pod-local clone. A cluster that ships logs will outlive the pod anyway; that is the log
|
|
119
|
+
plane's property, not a jr2 guarantee, and no jr2 behavior may come to depend on it.
|
|
120
|
+
|
|
121
|
+
## Considered options
|
|
122
|
+
|
|
123
|
+
- **Per-`agentRun` containers, or a pod per Agent.** Rejected on lifetime before merit: the container list is fixed when
|
|
124
|
+
the CR is created, before the body has run, while `agentRun` is a per-turn invocation. Pre-declaring per _Agent_ is
|
|
125
|
+
possible but pays N resident copies of a Harness image that deliberately carries the agent toolchain (ADR-0005) to run
|
|
126
|
+
one at a time. It buys no isolation — containers in a pod share the network namespace, so it does not even fix the
|
|
127
|
+
port contention that motivates it (ADR-0005:31) — and the git contention it would address is prohibited anyway
|
|
128
|
+
(ADR-0004:95). What it actually buys is `kubectl logs -c <agent>`: a container, to avoid a prefix.
|
|
129
|
+
- **A trace from the Custodian.** Tempting, and wrong on the facts. The Custodian carries the Menu's reads and the
|
|
130
|
+
Agent's picks — a handful of deliveries per turn — and the model calls, and it logs names only, never a body
|
|
131
|
+
([ADR-0059](0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md)). The Agent's working tools execute in
|
|
132
|
+
the Harness, never touching it. A Custodian trace shows `action=intercept … method=POST` and none of the four things
|
|
133
|
+
worth watching.
|
|
134
|
+
- **Tee the stream host-side, in the Orchestrator** (the one place holding an admission and an open stream). Genuinely
|
|
135
|
+
viable, and better on governance: addressable by run, and `instanceOnly` puts it behind the band ADR-0014 already
|
|
136
|
+
enforces. Rejected as the larger build for the smaller reader — it needs an API, a CLI, and a format, to serve a
|
|
137
|
+
reader `kubectl` already serves. Not foreclosed: it reads the same stream, so it remains the answer if the exception
|
|
138
|
+
below stops being acceptable.
|
|
139
|
+
- **Persist transcripts beside the run snapshot.** Rejected: the Harness already serves the stream replayable from any
|
|
140
|
+
offset for the life of the pod (ADR-0027), and jr2 holds the coordinates in the admission ledger (`run-host.ts:651`);
|
|
141
|
+
copying the contents buys retention in exchange for owning growth, retention policy, and a redaction surface, in a
|
|
142
|
+
store defaulting to sqlite.
|
|
143
|
+
- **Print a Working tool's results, truncated.** Rejected: the first 200 bytes of a leaked config is where the good
|
|
144
|
+
stuff is, and the volume it re-admits is what kubelet's 10Mi rotation would then silently discard — losing the _start_
|
|
145
|
+
of a long turn, which is the part worth reading. A `command` Effect's output does print, inside its pick's answer and
|
|
146
|
+
under the bound: it is the output of a command the author named for the workflow, one per pick, and not what the Agent
|
|
147
|
+
happened to read. The leak this rejects is still possible through it when the author's command prints a secret, and
|
|
148
|
+
the bullet above states it.
|
|
149
|
+
|
|
150
|
+
## Consequences
|
|
151
|
+
|
|
152
|
+
- **The echo does not widen ADR-0014's open band.** The echo endpoint is authenticated wire (the placement's bearer,
|
|
153
|
+
ADR-0058), so Emit payloads may ride it — the tokenless observation band still carries Emit types alone. What it does
|
|
154
|
+
widen is the pod-log surface: a run's narrative becomes readable by whoever can read the Workspace pod's logs, the
|
|
155
|
+
same audience the conversation bullet below already grants.
|
|
156
|
+
- **A scoped exception to ADR-0014**, recorded there. Observation is open and everything sensitive sits behind
|
|
157
|
+
`instanceOnly`; this puts an Agent's reasoning, and the answers jr2 gave its picks, in front of whoever can read pod
|
|
158
|
+
logs. Excluding a Working tool's results bounds it to what an Agent reasons aloud and what jr2 told it, rather than
|
|
159
|
+
what it happened to read; what jr2 told it includes an Effect's output, so a `command` Effect's output and a Held
|
|
160
|
+
value echoed into it reach the log as they reach the model, and so does an Effect secret in a form an Effector's scrub
|
|
161
|
+
does not catch (a transformed secret, a partial echo; ADR-0068). Fine on kind; a real decision on a shared cluster.
|
|
162
|
+
- **It depends on an invariant that is documented but not enforced.** One Agent at a time per Workspace (ADR-0004:95,
|
|
163
|
+
"structural since ADR-0012") is what makes two conversations never interleave on one container's stdout. Nothing
|
|
164
|
+
refuses a body that invokes concurrent `agentRun`s; such a body corrupts a shared `default/.git` before it garbles a
|
|
165
|
+
log, so enforcement is owed on its own merits — the ambient registrar (ADR-0012:32, ADR-0016) is the one thing that
|
|
166
|
+
sees every Agent in a Workspace, and the place to refuse a second concurrent admission.
|
|
167
|
+
- **Truncation is load-bearing, not cosmetic.** Kubelet rotates container logs at 10Mi by default and drops the
|
|
168
|
+
remainder. jr's filter capped `Bash` at 100 chars and unknown tools at 150 and reduced `Write`/`Edit` to a path; that
|
|
169
|
+
was readability, and it is now also what keeps a long turn inside the window.
|
|
170
|
+
- **Live tails may miss partial output.** Text and thinking deltas are best-effort live progress, with `message_end`
|
|
171
|
+
authoritative, so a reader that attaches mid-generation can miss earlier fragments until they arrive. Correct for a
|
|
172
|
+
watcher; anything wanting exactness reads the completed message.
|
|
173
|
+
- **`jr2 logs` remains a status feed** and is now more confusingly named than before. Not renamed here — this ADR adds
|
|
174
|
+
no command — but the collision is real and belongs to whoever next touches that surface.
|
|
175
|
+
- **The visualizer's eventual extension has a source.** When it grows past the graph, it reads the same stream; a page
|
|
176
|
+
is a third reader of one feed, not a third way of collecting the data.
|