Skip to content

feat: build Phase 1 internal extension runtime - #75

Merged
xiayh17 merged 34 commits into
YuLab-SMU:mainfrom
xiayh0107:agent/plugin-runtime-phase1-internal-upstream
Aug 20, 2026
Merged

feat: build Phase 1 internal extension runtime#75
xiayh17 merged 34 commits into
YuLab-SMU:mainfrom
xiayh0107:agent/plugin-runtime-phase1-internal-upstream

Conversation

@xiayh17

@xiayh17 xiayh17 commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • builds the Phase 1 compiled-in, first-party internal extension runtime;
  • completes deterministic capability contracts, scoped lifecycle/effect ownership, generations, expected-old pointer-CAS publication, bounded calls, quiesce/dispose, diagnostics, and static inventory;
  • migrates project Run History, Workspace Snapshot (workspace.snapshot unchanged), and Project File Viewer (rho.viewer_file.v1 unchanged);
  • makes the private candidate runtime the default while retaining RHO_INTERNAL_EXTENSION_RUNTIME=legacy for one later release cycle; and
  • allocates 0.4.1-dev.0 plus NEWS without creating a tag, release, updater manifest, or publication.

Phase 1 remains internal: no discovery, third-party code, Wasm/WASI, Tauri Plugin, public SDK, Execution Target, Compute Job, Conda, SSH, Slurm, schema, credential, permission, or transport expansion.

Work packages

  • P1-0 — validated IDs/descriptors, scope policy, deterministic graph/plan, stable Kahn order and canonical cycles (bb9f1e1)
  • P1-1 — activation/disposal, immediate reversible effects, task/call admission, ArcSwap generations, candidate publication and BH2 integration (f7d3da2)
  • P1-2 — bounded project Run History source backed only by Store::list_runs() (78c0493)
  • P1-3 — Workspace scope/tree, typed 2 MiB Snapshot tool, Agent adapter, application Viewer descriptor and trusted host file injection (d67c294, f16283c)
  • P1-4 — candidate default, 0.4.1-dev.0, packaged smoke, three-platform unsigned installed-app acceptance, final safety review, and implemented lifecycle reconciliation (4b92bc4, 66120a8, 481b174)

Authority and compatibility

  • Store remains Run History authority.
  • rho-server remains the sole Workspace R-expression, stale-revision, Ark, run and provenance authority.
  • Agent admission and AgentWorkspaceLane remain ahead of the exact Snapshot adapter.
  • project::read_viewer_file() remains containment, symlink, media, encoding and size authority; the plugin has no project path, DOM or Tauri handle.
  • Existing command names, arguments, response schemas, ordering and browser/mock protocols remain unchanged.
  • Legacy deletion is explicitly outside this PR.

Local acceptance

  • Rust 1.88/current runtime: 60 passed on each; runtime clippy -D warnings: passed
  • full workspace: 453 passed, 0 failed, 1 existing opt-in Keychain smoke ignored
  • rho.bridge: 575 passed; rho.agent: 120 passed
  • every tracked scripts/test-*.mjs, frontend syntax, license/MSRV/Phase-1 negative contracts, formatting, locked check/test and diff check: passed
  • default-candidate and explicit-legacy unbundled smoke: passed
  • unsigned arm64 built app and read-only mounted DMG, default + legacy smoke: passed
  • local DMG: 22,689,295 bytes; SHA-256 ee09db111ddfc54012d7c6d760e6f8eb57abb968ee746bba7324f47fb73d3c3d

Exact-head Draft Rust Fast 32127514055 passed; Rust Fast correctly skips once Ready.

Ready acceptance

The first exact product/CI head passed all six legs and all three packaged stable legs in run 32129767978. Final lifecycle-reconciliation head 481b17457fba2c50769d27759bc5c1cde237069f then passed the complete matrix again in Rust Compatibility run 32132310440:

  • macOS arm64, Windows GNU x64, Linux x64 × stable and Rust 1.88: 6/6 passed;
  • macOS stable: built app + read-only DMG, candidate/legacy smoke, integrity and cleanup passed;
  • Linux stable: final AppImage extract, candidate/legacy smoke and cleanup passed;
  • Windows stable: NSIS build, unbundled candidate/legacy smoke, silent install, installed candidate/legacy smoke, uninstall registry/executable cleanup passed;
  • exact-head Rust Fast run 32132310365 skipped as required.

Final hosted hashes:

  • Windows binary 04f287e56861eb39769fc244fd787fb289075d06e8630dfa49986ccd11f4b889; NSIS e762115f4840ec5a3c6afd9dcdf06259c8f111479bca4d1eb72975da2b5d250b
  • macOS binary 4f5cc95cd235db9d03d4daa932c214dc9cd66d6fb9b79ea3a7903fce6c0a7c2f; DMG 0f4d8ce4045bb8f52f975fad1551328f104632af897657353d73ed17bd8849ad
  • Linux binary ad3530fcfc96581a579f94ed3b323106310428e3460997faddad09c03092d903; AppImage 3af6d1e7636032d67ceab948a0fdbaef98ba4b68a9b04f2b4b9e73855cb9c0f8

Final review and decision

Trusted Kernel/raw-expression, generation/CAS, cleanup/leaks, panic containment, Agent admission, project isolation, filesystem/symlink containment, request/response bounds, diagnostics, credential/redaction, duplicate registration, fallback and downstream Issues #95/#96 suitability were reviewed with no blocking finding. The architecture and P1-0 through P1-4 contracts are marked implemented; the Rust API remains internal experimental.

Application metadata is synchronized at 0.4.1-dev.0; R package versions are unchanged. This PR is Ready but makes no signing, tag, GitHub Release, update-channel, download, publication, installation-on-user-machine, or release GO decision.

Capability-growth boundary

The implemented design now records why Phase 1 is also a safety substrate for a later Phase 2.5: an Agent may eventually distill repeated work into Recipes, Skills, and immutable plugin candidates, but Phase 1 does not implement experience capture, Agent authorship, evaluation, lineage, standing policy, or capability gardening.

Package digest remains executable identity. Candidate activation, expected-old publication, rollback, quiesce, and disposal are reusable; policy, fresh grant decisions, protected evaluation, audit, and first-party promotion stay outside the Agent. This documentation amendment changes no Phase 1 runtime behavior or acceptance evidence.

@xiayh0107
xiayh0107 force-pushed the agent/plugin-runtime-phase1-internal-upstream branch from b86a204 to 8bb9e9c Compare August 18, 2026 06:06
@xiayh17 xiayh17 changed the title docs: propose Phase 1 internal plugin runtime design feat: build Phase 1 internal extension runtime Aug 18, 2026
@xiayh17
xiayh17 marked this pull request as ready for review August 18, 2026 10:40
@xiayh17
xiayh17 requested a review from GuangchuangYu as a code owner August 18, 2026 10:40

@GuangchuangYu GuangchuangYu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — Phase 1 internal extension runtime

Reviewed all 7 source files of crates/rho-extension-runtime (~4.2k lines), the main.rs / coordinator.rs integration, the CI workflows, and the P1-0..P1-4 specs. Also re-ran cargo test -p rho-extension-runtime locally (Rust 1.97.0): 34 passed, 0 failed — consistent with the 6/6 green CI matrix.

Overall this is a very solid PR: zero-unsafe runtime, careful CAS publication with stale-generation protection, thorough panic/timeout containment, and proportional test coverage. No blocking findings. Below are improvement suggestions and a few observations I'd like to confirm.

Suggestions (non-blocking)

  1. RunHistoryBrokerFacade::call_sync re-opens the Store on every call (main.rs ~6451). The legacy path reuses the already-open store via read_store(state), while the candidate path opens a fresh SQLite connection per list_runs. Worth reusing the shared store connection, or at least a comment on why per-call open is acceptable. Note the call is also synchronous work executed inside an async context.

  2. Leak semantics after quiesce/dispose deadline expiry deserve an explicit spec note. When the scope deadline expires, unstarted effects are marked Failed and skipped entirely (cleanup is not attempted) — confirmed intentional by total_scope_deadline_marks_unstarted_effects_as_leaked. Likewise, tasks that do not drain before the quiesce deadline are not aborted; they keep running in the background (remaining_tasks only reports). This bounded-before-clean design is reasonable, but the spec only implies it via report fields — stating it explicitly would help future maintainers.

  3. EffectStack::dispose holds the tokio Mutex across the whole dispose loop (each effect up to per_effect_deadline). A concurrent second call blocks on the lock rather than returning the cached report immediately. Idempotency is fine (report cache), but a comment explaining why the lock is held across awaits would prevent future regressions.

  4. Small cleanups: bounded_message (lifecycle.rs) duplicates bounded_broker_text (broker.rs); ScopedDiagnosticSink::emit truncates related_plugins at 256 but cycle_path at 257; ScopedTaskTracker::spawn takes a StdMutex lock while calling tracker.spawn (safe today since tokio spawn does not poll inline, but worth a comment).

Observations to confirm

  1. list_runs candidate path does not fall back to legacy on handler error — it fails truthfully (list_runs_with_state, main.rs ~3838). This matches the viewer's "no silent legacy retry" principle and the spec wording, but I wanted to confirm the parity claim covers availability rather than fallback.

  2. A legacy-mode host is still constructed (build_extension_hostnew_with_host_capabilities) even though legacy mode never routes through it. Harmless (no plugins, no effects), but it could be constructed lazily.

  3. Legacy removal timeline: the PR body says the legacy mode is retained "for one later release cycle". Worth confirming which release (e.g. 0.4.2-dev) will drop it, so the removal work is tracked in advance.

No blocking issues; happy to approve once the above are either addressed or explicitly tracked.

@xiayh17
xiayh17 requested a review from GuangchuangYu August 19, 2026 08:10
@xiayh17
xiayh17 merged commit 33da024 into YuLab-SMU:main Aug 20, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants