itx consolidation: one define verb, fetch is just a (shadowable) cap, one context-node shape#1487
Merged
Merged
Conversation
Leaning into the symmetries — fewer concepts, no power lost: - caps.define is THE verb: a live provider stub is just another target (plain-object discrimination, checked before any property probe — capnweb stubs answer every probe). provide() survives as a one-line handle alias; the itxProvide DO verbs are gone. - fetch is demoted from kernel to a platform:project default. The handle method and globalOutbound both dispatch registry-first; the DEFAULT target is ProjectEgress.call, the terminal pipe into egressFetch (the default dials call, never fetch — that breaks the loop). Consequence: define a live `fetch` while connected and ALL project egress — scripts and bare fetch() in loaded isolates — flows through it; revoke and the default resurfaces. A shadow sees getSecret() placeholders, never material. The egress intercept tunnel is now expressible as cap shadowing (deletion is a noted follow-up). - ProjectEgress scopes by registry-injected projectId (prop renamed from `project`) and joins DIALABLE_LOOPBACKS. - Both DOs build their ContextRegistryHost through one shared buildContextRegistryHost — the duplicated wiring is gone. Kernel is now: caps, streams, fork, project, projects, describe. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # apps/os/src/itx/browser-repl.ts
Main moved the REPL examples into examples.ts (#1480) mid-flight; the live-cap examples now teach caps.define with a live target (one alias mention survives), and the REPL harness mock speaks the same verb. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…Bugbot) A child context's fetch shadow caught itx.fetch but not its isolates' bare fetch(): ProjectEgress.fetch dialed the Project DO directly, skipping the child's chain. It now routes itxInvoke through the originating context (child → project → defaults), so shadowing works identically through both doors. e2e: a fork-level shadow intercepts the fork's bare fetch while the project context stays on the real pipe. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
itx.project.fetch / itx.project.egressFetch reached the terminal pipe directly, bypassing any live fetch shadow that every other door honors. The project proxy now refuses both; itx.fetch is THE egress door for handle holders. The terminal pipe stays reachable to the default cap via direct DO stubs, which never pass through this proxy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 06c6113. Configure here.
…caps (Bugbot) A plain object with a typo'd/unknown `type` fell through the live-target discriminator and registered as an offline-looking live cap. A plain object carrying any string `type` is now a loud define-time error; objects-of-functions (no type field) stay valid live providers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jonastemplestein
added a commit
that referenced
this pull request
Jun 11, 2026
… pipe
Main's consolidation shipped egress-as-a-capability under the name `fetch`
with define absorbing provide and one shared registry host — all adopted.
This branch's layers re-applied on top of that design: the default `fetch`
target is the stateless EgressPipe (secret substitution + real fetch, no
Durable Object in the egress path) instead of ProjectEgress.call dialing
the DO's egressFetch, which this branch deletes along with the captun
intercept tunnel; ProjectEgress is now purely the registry-first
dispatcher and leaves DIALABLE_LOOPBACKS. Also re-applied: wireIsolateEnv
in the registry's loadWorker, the workers-RPC-safe onRpcBroken guard,
auth-routed id minting in ItxProjects.create, and the live-shadow test
support rewritten to caps.define({ invoke: "path-call", name: "fetch" }).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jonastemplestein
added a commit
that referenced
this pull request
Jun 11, 2026
… names, REPL reads types.ts (#1490) The four follow-ups the consolidation arc left written down in itx-next.md, in one PR. Net **−578 lines** while adding a whole new capability surface. No backcompat anywhere. --- ## 1. The egress intercept tunnel is deleted — shadowing was already the feature **Motivation.** #1487 made `fetch` an ordinary shadowable capability. At that point the captun-based intercept tunnel was a second, hand-built implementation of the same idea: "while I'm connected, route the project's egress through me." It had its own DO field, accept route, keepalive plumbing, a special `projectEgressInterceptActive` flag threaded through secret substitution, a benchmark script, and a bespoke test harness. All of it is expressible as one `caps.define`. **Before** (the tunnel era): ```ts // Client: dial a special captun endpoint on the project's ingress const tunnel = await createCaptunTunnel({ url: `${ingressUrl}/__iterate/intercept-project-egress`, headers: { Authorization: `Bearer ${adminToken}` }, fetch: myFetch, }); // Server: #projectEgressInterceptTunnel field, accept/replace/teardown // lifecycle, an egressFetch branch, and a substitution mode that withheld // real secret material while a tunnel was connected. ``` **After** (it's just a cap): ```ts using itx = connectItx({ baseUrl, token, context: projectId }); class Interceptor extends RpcTarget { async call({ args }) { return await myFetch(args[0]); } // args[0] is the Request } await itx.caps.define({ name: "fetch", invoke: "path-call", target: new Interceptor() }); // ALL project egress — itx.fetch() and bare fetch() in every loaded isolate — // now flows through myFetch. Drop the session and the default pipe resurfaces. ``` The security property came along for free and got *simpler*: the tunnel needed an explicit "withhold secrets while intercepted" mode inside substitution; a shadow provider simply never reaches the substituting pipe, so it sees `getSecret(...)` placeholders verbatim. The flag is gone; substitution always yields real material on the one path that has any. The e2e fixture's `egressFetch` option keeps its exact API (now implemented as above), and the workerd ingress test was rewritten to the cap story — which caught a real bug: probing `onRpcBroken` on a Workers-RPC live provider rejects unhandled (jsrpc proxies every property as a remote method); the registry now treats it as best-effort. ## 2. `streams` joins the platform defaults **Motivation.** After #1482/#1487 the kernel was `caps, streams, fork, project, projects, describe`. `streams` was only still hardwired because its access checks live in the handle. But split the concern in two and the blocker dissolves: on a *project* context the namespace is **forced** to the project (there is no access decision to make — registry-injected `projectId` props pin it, definers can't point it elsewhere), and only the *global* namespace genuinely needs the connect-time access set. **Before:** `ItxStreams`/`ItxStream` hardwired into `handle.ts`, reserved name, not shadowable. **After:** ```ts // platform:project (code-contexts.ts) — just another definition: caps.define({ name: "streams", target: { type: "rpc", worker: { type: "loopback" }, entrypoint: "StreamsCap" }, }); // …which means a context can now shadow its own event-stream surface: await itx.caps.define({ name: "streams", invoke: "path-call", target: myStreamsFake }); ``` The collection/stream classes moved to `src/itx/caps/streams.ts`, parameterized by an explicit `StreamsScope { access, exports }`; the handle's getter branches — project handles resolve through the registry (shadowable), global handles keep the kernel branch for the deployment-wide `"global"` namespace gated on `access === "all"`. Everything else is unchanged: absolute refs (`"ns:/path"`) still go through the one access check with NOT_FOUND masking. Two things made this safe to ship rather than scary: - **Chained calls ride RPC promise pipelining.** `itx.streams.get("/x").append(e)` crosses a boundary in every real execution mode (capnweb from browsers/Node, jsrpc from loaded isolates), and both transports pipeline follow-up calls onto returned RpcTargets — the same shape `itx.agents.create().doThing()` already proved. - **Subscriptions survive the extra hop.** `subscribe` callbacks now cross client → registry DO → StreamsCap → Stream DO; the existing dup-discipline in StreamsCapability holds, proven by the subscribe e2e suite running unchanged. ## 3. Durable-object dials are name-scoped **Motivation.** #1482 shipped `{ type: "durable-object", binding, name }` refs behind an *empty* allowlist, because raw names meant an allowlisted namespace would let any project dial any other project's instances — documented as "the open design before any namespace can join." **Resolved:** the registry now dials ```ts namespace.getByName(`itx:${projectId}:${name}`) ``` so every allowlisted namespace's itx-reachable instances are **disjoint per project by construction** — the definer's `name` is a label inside their project's slice, not a global address. Deployments can now actually use `APP_CONFIG_ITX.dialableDurableObjects` for namespaces designed for itx use. (Namespaces whose *existing* instances matter — PROJECT, STREAM — still don't belong on the list: itx dials would reach fresh, empty objects, which is exactly the point.) ## 4. The REPL editor consumes types.ts — drift is now structurally impossible **Motivation.** `apps/os/src/itx/types.ts` is the handwritten design-of-record for the whole itx surface; the browser REPL's editor carried a second, hand-maintained 353-line ambient declaration with a "keep in sync" comment — the kind that's wrong within a week. **After:** the REPL's TypeScript virtual FS loads `types.ts` **verbatim** (`import source from "~/itx/types.ts?raw"`, which works in both the vite-bundled worker and vitest). The hand-written file shrank to a 120-line prelude declaring only what types.ts can't know: the session globals (`itx`, `vars`, `projectId`, `RpcTarget`, `$_`). A bonus improvement fell out: the capability fallthrough is now declared on the official `KnownCaps` merge point, so handles returned by `itx.fork()` / `itx.projects.get()` carry it too — `(await itx.projects.get(id)).slack.chat.postMessage` typechecks in the editor, which the old ambient got wrong. Tests assert the editor sees types.ts-only markers, so regressions are loud. --- ## The kernel after this PR ```text caps, fork, project, projects, describe ← the trust kernel streams (global namespace only) ← connect-time access, by nature ───────────────────────────────────────────── ai, fetch, streams, repos, workspace, worker ← platform:project definitions, i.e. literally the data structures caps.define takes, every one of them shadowable ``` ## Verification `pnpm typecheck` / `lint` / `knip` / `format` green; apps/os unit tests 222 green; workerd `test:project-ingress` 6/6 (including the rewritten fetch-shadow-sees-placeholders test); itx e2e — 32 tests across core/fork/http/subscribe suites, exercising streams through the registry path, the example catalogue in every runtime, fork workspace isolation, and the full fetch-shadow story — green against a local dev server. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches project egress, secret substitution, and ingress/DO routing paths used in production and e2e; behavior changes are intentional but need regression on fetch shadowing and streams via the registry. > > **Overview** > Removes the **Project Egress Intercept Tunnel** (captun route on the Project DO/ingress, tunnel state, intercept-specific secret withholding, benchmark script, and e2e captun helper) and replaces interception with a **session-bound live `fetch` capability shadow** on the project itx context—interceptors see `getSecret(...)` placeholders because substitution only runs on the default egress pipe. > > **`streams` becomes a shadowable `platform:project` default** (`StreamsCap` loopback in `caps/streams.ts`); project handles resolve `itx.streams` through the registry while the global `"global"` namespace stays a kernel branch gated on admin access. **Durable-object capability dials** now use `itx:<projectId>:<name>` so allowlisted namespaces are per-project disjoint. > > The **browser REPL editor** loads `~/itx/types.ts` verbatim via `?raw` instead of a large hand-maintained ambient file; docs/ADR/context and tests are updated accordingly, including registry best-effort `onRpcBroken` for Workers-RPC live providers. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 93efa03. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- CLOUDFLARE_PREVIEW --> ## Environment Config Lease <!-- CLOUDFLARE_PREVIEW_STATE --> <!-- { "apps": { "os": { "appDisplayName": "OS", "appSlug": "os", "status": "deployed", "updatedAt": "2026-06-11T07:07:45.989Z", "headSha": "93efa03e779290348755a99b9317ae9274c20261", "message": null, "publicUrl": "https://os.iterate-preview-2.com", "runUrl": "https://github.com/iterate/iterate/actions/runs/27329834559", "shortSha": "93efa03" } }, "environmentConfigLease": { "dopplerConfig": "preview_2", "leasedUntil": 1781164984175, "leaseId": "eae024be-b4d7-4976-92e4-0013205b125e", "slug": "preview-2", "type": "environment-config-lease" } } --> <!-- /CLOUDFLARE_PREVIEW_STATE --> Lease: `preview-2` Doppler config: `preview_2` Type: `environment-config-lease` Leased until: 2026-06-11T08:03:04.175Z ### OS Status: deployed Commit: `93efa03` Preview: https://os.iterate-preview-2.com [Workflow run](https://github.com/iterate/iterate/actions/runs/27329834559) Updated: 2026-06-11T07:07:45.989Z <!-- /CLOUDFLARE_PREVIEW --> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
jonastemplestein
added a commit
that referenced
this pull request
Jun 11, 2026
…tercept dies, kernel shrinks, auth mints, legacy afterAppend deleted (#1485) ## What The remaining grand-cleanup workstreams in one deliberately breaking PR (prd gets redeployed). DECISIONS **D23** is the canonical record. Three main-side PRs landed mid-flight and overlap this work — all adopted wholesale in the merges: **#1482** (repos/workspace/worker as platform defaults with origin-carrying delegation), **#1487** (`fetch` is a shadowable cap, `define` absorbs `provide`, shared registry host), and **#1490** (intercept tunnel deleted, streams is a cap, best-effort `onRpcBroken`). This PR contributes the layers below on top of them. ### §9 finished: the egress pipe is stateless - #1487/#1490 made `fetch` a shadowable platform:project cap and deleted the tunnel, but kept the DEFAULT pipe inside the Project DO (`ProjectEgress.call` → `egressFetch`). This PR replaces that terminal with the stateless **`EgressPipe`** loopback. The Project DO still supervises every dispatch (live shadows resolve in its registry), but egress secrets are D1 rows scoped by the registry-injected `projectId`, so substitution + the real outbound fetch run in a plain isolate and **secret material never enters the DO**. - **The Project DO has no fetch surface at all** — no `fetch`, no `ingressFetch`, no `egressFetch`. ### Worker-loading unification - `itx/isolate.ts` is the ONE place the platform's trust posture (Law 4 ITERATE scoping, Law 5 egress outbound) is wired into loaded isolates; the registry's source caps and the project worker both use it. (The Workers-RPC-safe `onRpcBroken` guard this PR carried shipped independently in #1490 — main's version adopted.) ### `ProjectCapability` dissolved The hand-wired forwarder entrypoint is deleted; nothing called it. ### Auth is the ONLY project-id minter New auth internal route `POST /internal/project/mint-project-id` (service-authed); OS operator/recovery creates (project directory + `itx.projects.create`) round-trip through it. `mintProjectId` is deleted from OS — the `prj_` id space has exactly one source. ### Legacy afterAppend/runner-state deleted The agent, slack-agent, slack-integration, and repo DOs lose their `afterAppend` RPCs and fake runner shapes (delivery has been on the host model for a while). Agent runtime state is now the honest `{ agentPath, processors: { [slug]: snapshot } }`; slack `ensureReady` returns a plain snapshot; the agent-stream benchmark updated. ## Deferred to main's posture (from the original plan) - `project` stays a hardwired built-in (per #1482's kernel choice) rather than a durable-object default; `DIALABLE_DURABLE_OBJECTS` stays empty by default (config-gated). - The egress cap is named `fetch` (per #1487), not `egress`. ##⚠️ Merge order **#1489 must merge (and auth deploy) first** — this PR's create paths round-trip id minting through auth's new `/internal/project/mint-project-id`, and previews point at production auth. The preview e2e here 404s until that endpoint is live. ## Breaking changes (intended) - Agent `runtimeState` shape changed (consumers were shape-agnostic or updated). - `egressFetch` is gone from every surface; use `itx.fetch` / the `egress` cap. ## Testing - Full repo gates green (typecheck, lint, 35/35 apps/os test files). - Workers suites: project-ingress 6/6 (incl. live-shadow + revoke-restores-default), itx-stream-subscribe 13/13. - `project-mcp-server-connection` fails 2/3 **identically on the branch base** (verified in a clean worktree) — pre-existing. - Preview e2e exercises: the egress capability over capnweb (explicit + implicit doors), the new live-shadow helper, and auth-routed minting. ## Out of scope - Egress policy-as-data / hold-for-approval (the §9 follow-on). - Stream processors taking a synchronous SQL client (jam). 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **High Risk** > Breaking egress and secret-handling semantics (DO no longer substitutes secrets; interceptors see raw placeholders), new auth dependency for id minting, and changed agent runtimeState shape affect security-sensitive paths and deploy ordering. > > **Overview** > Completes **itx D23**: project egress is a shadowable **`fetch`** capability whose default terminal is the stateless **`EgressPipe`** (secret substitution + outbound fetch in a plain isolate), while the Project DO only supervises registry dispatch. **`fetch` / `egressFetch` are removed** from the Project DO; **`ProjectCapability`** is deleted. > > Adds **`itx/isolate.ts`** so project workers, source caps, and the run harness share one **ITERATE + `ProjectEgress` globalOutbound** wiring path. > > **Auth is the sole `prj_` minter**: OS drops local **`mintProjectId`**; operator/admin and **`itx.projects.create`** call auth’s **`mintProjectId`** internal route. > > Removes legacy **`afterAppend`** / runner-shaped RPCs on agent, slack, and repo DOs; agent **`runtimeState`** is **`{ agentPath, processors }`** (benchmark updated). Docs mark §8/§9 shipped; live **`fetch`** shadows see **raw** `getSecret(...)` placeholders (withheld-text mode removed). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit df5965b. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- CLOUDFLARE_PREVIEW --> ## Environment Config Lease <!-- CLOUDFLARE_PREVIEW_STATE --> <!-- { "apps": { "os": { "appDisplayName": "OS", "appSlug": "os", "status": "deployed", "updatedAt": "2026-06-11T10:23:48.699Z", "headSha": "df5965b9948016c979fa5a71ae3b991f66e8c42c", "message": null, "publicUrl": "https://os.iterate-preview-6.com", "runUrl": "https://github.com/iterate/iterate/actions/runs/27340067055", "shortSha": "df5965b" } }, "environmentConfigLease": { "dopplerConfig": "preview_6", "leasedUntil": 1781176786363, "leaseId": "9c50031d-b4ce-4f00-a8fe-66a3ff9f9df5", "slug": "preview-6", "type": "environment-config-lease" } } --> <!-- /CLOUDFLARE_PREVIEW_STATE --> Lease: `preview-6` Doppler config: `preview_6` Type: `environment-config-lease` Leased until: 2026-06-11T11:19:46.363Z ### OS Status: deployed Commit: `df5965b` Preview: https://os.iterate-preview-6.com [Workflow run](https://github.com/iterate/iterate/actions/runs/27340067055) Updated: 2026-06-11T10:23:48.699Z <!-- /CLOUDFLARE_PREVIEW --> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

A consolidation pass over itx per review direction: fewer concepts and abstractions, same expressive power, leaning into the symmetries. No backcompat anywhere.
One verb:
caps.defineabsorbsprovideA live provider stub is just another target.
define({ name, target })now takesSerializableCapTarget | LiveCapTarget— a plain data object withtype: "rpc" | "url"is stored durably; anything else (capnweb function-proxies, jsrpc stubs, RpcTargets, objects-of-functions) registers as a session-bound live provider with the existing dup/teardown discipline. The plainness check deliberately precedes any.typeprobe — property access on a capnweb stub returns a truthy pipelined stub, so probing first would misclassify every live target.caps.providesurvives as a one-line handle alias; theitxProvideverbs on both DOs are deleted.fetchis just a capability — interception is cap shadowingImplemented exactly that.
fetchleaves the kernel and becomes aplatform:projectdefault:itx.fetch(...)is sugar dispatchingitxInvoke({ name: "fetch", path: [], args: [request] }).globalOutboundfor every platform-loaded isolate (ProjectEgress.fetch) routes registry-first the same way — barefetch()in loaded code included.ProjectEgress.call, the terminal pipe into the Project DO'segressFetch(secret substitution lives there). The default dialscall, neverfetch— that's what breaks the loop.caps.define({ name: "fetch", target: liveStub, invoke: "path-call" })from any connected session intercepts ALL project egress while connected; revoke (or drop the session) and the default resurfaces. A shadow provider receivesgetSecret(...)placeholders unsubstituted — secret material only ever exists in the default pipe inside the Project DO. Same property the egress intercept tunnel had to hand-build; the tunnel is now expressible as cap shadowing and its deletion is a noted follow-up debt.ProjectEgressscopes by registry-injectedprojectId(prop renamed fromproject) and joinsDIALABLE_LOOPBACKS.New e2e proves the full loop live: fresh project shows
fetchowned byplatform:project; a Node-side live provider intercepts bothitx.fetchand bare in-isolatefetch()(via/api/itx/run); revoking restores the real pipe.One context-node shape
ProjectDurableObjectandContextDObuilt near-identicalContextRegistryHosts by hand. Both now use one sharedbuildContextRegistryHost(src/itx/registry-host.ts); the ~60 lines of duplicated wiring are gone. ContextDO's no-defaults behavior is preserved explicitly.The kernel after this PR
caps,streams,fork,project,projects,describe— the parts that ARE access checks, narrowing, and the registry itself. Everything else a fresh project has (ai,fetch,repos,workspace,worker) is an ordinary, shadowableplatform:projectdefinition: exactly the data structurescaps.definetakes.Verification
pnpm typecheck/lint/knip/formatgreen; apps/os unit tests green (217); itx e2e (itx incl. the new fetch-shadow test, fork, http, subscribe — 22 tests) green against a local dev server.🤖 Generated with Claude Code
Note
High Risk
Changes core egress and capability dispatch paths (registry-first
fetch, loop-breakingProjectEgress.call) and removesitxProvide; mistakes could break egress, secret substitution, or live-cap registration across project and child contexts.Overview
Consolidates the itx capability layer around three ideas: one registration verb, egress as a shadowable
fetchcap, and shared registry host wiring.caps.definereplacesprovideon the wire.ContextRegistry.defineaccepts serializable targets (type: "rpc" | "url"on plain objects) or live stubs (everything else). Classification checks plain-object shape before reading.type, so capnweb stubs are not mis-registered.itxProvideis removed from Project DO andContextDO;caps.provideremains a thin alias. Malformed serializable targets fail at define withunknown target type.fetchmoves from kernel reserved name toplatform:projectdefault.itx.fetchandProjectEgress(globalOutbound) resolve thefetchcap via the registry first; the default target dialsProjectEgress.call→egressFetchso.callvs.fetchavoids a loop. Livefetchshadows intercept both explicit and in-isolate egress; shadow providers get secret placeholders unsubstituted.fetchis removed from reserved cap names;handleblocks rawproject.fetch/egressFetchon the DO proxy.ProjectEgressprops useprojectId; it joinsDIALABLE_LOOPBACKS. Child-context barefetch()dispatches from the originating context node.createContextRegistryHost(registry-host.ts) deduplicates registry setup for Project DO (withplatformProjectContextdefaults) andContextDO(no defaults; chain walks to parent). Docs, examples, tests, and e2e (including fetch-shadow) are updated accordingly.Reviewed by Cursor Bugbot for commit 76472b8. Bugbot is set up for automated code reviews on this repo. Configure here.
Environment Config Lease
No active environment config lease.
OS
Status: released
Commit:
76472b8Preview: https://os.iterate-preview-2.com
Summary: Preview app released.
Workflow run
Updated: 2026-06-11T02:40:54.158Z