Chapter 13

The Olai lens

The framing in cordis-for-olai.md: Olai's plugin system is a registry — values filtered once at startup, composed into a PluginServices blob, immutable after. Cordis is a runtime — functions installing revertible effects into a shared context, activation and deactivation driven by declared dependencies, hot reload. Design judgments kept: vault authority over plugins, write-only doorbell, plugin-owned error messages, browser receives answers not rules, the fence (no cycles; no importing @olai/plugin-api). Limitations overturned: compiled-in only → loader mounts by name from config rows; no plugin-to-plugin deps → inject with PENDING; enable/disable CLI-only → a disabled row field; privileged core → driver plugins in an orchestrate profile.

Paper conceptOlai design pointChapter
Revertible effectsEvery registration carries a disposer; LIFO unwind; no uninstall path to write. Spike: disabled rows dispose cleanly; a throwing apply → FAILED, siblings unaffected (exactly §4.4's failure semantics).4, 9.1
Reactive coeffectsinject lists; absent provider = wait, not error; provider replacement reloads only dependents.5
InterceptionSubtree write fence as metadata; vault precedence = right-biased ⊕; readable without reload.5.4
Isolation realmsNode-agent scopes: same key, different binding per agent subtree; loader-managed realms move with the entry.5.3, 11.1
Confluence (Thm 80)"Profiles differ only by row selection" is sound because the quiescent state is a function of the final config, not the load/unload history. The orchestrator-as-driver-group idea rests on this.9
Ordering (Thm 70) + guardNo boot order; fetch modules concurrently; activate when satisfied.8.4, 9
Commutative keysThe live sibling registry: tagged set → incremental add/drop as commuting effects; ordered → carry order in a coeffect.7
Nominal keys + peer depsAlready where the doc lands; the paper flags it as an open gap, and npins hydration makes the peer-range check yours to run.12.2
HMRDeferred on Bun; costs no guarantee.11.2

13.1 Two runtimes: Effect and Cordis

The doc's split — Cordis controls what mounts when, Effect controls how it works — is exactly the seam the paper draws against Effect-TS in §7.1: (a) Effect tracks only inside the monadic type, Cordis is an overlay; (b) Effect's Scope / acquireRelease is structured, and a withdrawn service doesn't undo what it did, whereas Cordis pairs each effect with an inverse and re-resolves requirements as providers come and go. So the effect-cordis bridge (Phase 4) is putting Effect's acquireRelease inside a Cordis fiber's lifetime: Cordis opens and closes the scope; Effect owns what happens inside. Requirement channels R look like inject, but Effect resolves R once at provide; the reactive part (PENDING → ACTIVE → UNLOADING on provider change) has no Effect counterpart and stays on the Cordis side.

13.2 Questions the paper makes sharp

  1. Is every shared mutable location in Olai reified at a key? Anything a plugin touches outside Σ is outside the guarantees (Def 56, §6.1).
  2. Which Olai keys are commutative? Roster: yes if tagged. Hook chains: no — waterfall order is a coeffect.
  3. Where is the system boundary? Vault files on disk are emissions (other programs write them); git commits are compensable, not revertible. What does "dispose" mean for a plugin that has already written a row?
  4. Confluence excludes FAILED fibers. How does Olai surface "this plugin failed under this schedule" to the user? Plugin-owned error prose fits here.
  5. Provider replacement under exclusive binding reloads every dependent. For chat/vault services under node-agents, is a broker (§6.2) the right shape so agents don't bounce when a backend swaps?