feat: build Phase 1 internal extension runtime - #75
Conversation
b86a204 to
8bb9e9c
Compare
GuangchuangYu
left a comment
There was a problem hiding this comment.
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)
-
RunHistoryBrokerFacade::call_syncre-opens the Store on every call (main.rs~6451). The legacy path reuses the already-open store viaread_store(state), while the candidate path opens a fresh SQLite connection perlist_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. -
Leak semantics after quiesce/dispose deadline expiry deserve an explicit spec note. When the scope deadline expires, unstarted effects are marked
Failedand skipped entirely (cleanup is not attempted) — confirmed intentional bytotal_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_tasksonly reports). This bounded-before-clean design is reasonable, but the spec only implies it via report fields — stating it explicitly would help future maintainers. -
EffectStack::disposeholds the tokioMutexacross the whole dispose loop (each effect up toper_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. -
Small cleanups:
bounded_message(lifecycle.rs) duplicatesbounded_broker_text(broker.rs);ScopedDiagnosticSink::emittruncatesrelated_pluginsat 256 butcycle_pathat 257;ScopedTaskTracker::spawntakes aStdMutexlock while callingtracker.spawn(safe today since tokio spawn does not poll inline, but worth a comment).
Observations to confirm
-
list_runscandidate 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. -
A legacy-mode host is still constructed (
build_extension_host→new_with_host_capabilities) even though legacy mode never routes through it. Harmless (no plugins, no effects), but it could be constructed lazily. -
Legacy removal timeline: the PR body says the
legacymode 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.
Summary
workspace.snapshotunchanged), and Project File Viewer (rho.viewer_file.v1unchanged);RHO_INTERNAL_EXTENSION_RUNTIME=legacyfor one later release cycle; and0.4.1-dev.0plus 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
bb9f1e1)f7d3da2)Store::list_runs()(78c0493)d67c294,f16283c)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
rho-serverremains the sole Workspace R-expression, stale-revision, Ark, run and provenance authority.AgentWorkspaceLaneremain 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.Local acceptance
-D warnings: passedrho.bridge: 575 passed;rho.agent: 120 passedscripts/test-*.mjs, frontend syntax, license/MSRV/Phase-1 negative contracts, formatting, locked check/test and diff check: passedee09db111ddfc54012d7c6d760e6f8eb57abb968ee746bba7324f47fb73d3c3dExact-head Draft Rust Fast
32127514055passed; 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 head481b17457fba2c50769d27759bc5c1cde237069fthen passed the complete matrix again in Rust Compatibility run 32132310440:32132310365skipped as required.Final hosted hashes:
04f287e56861eb39769fc244fd787fb289075d06e8630dfa49986ccd11f4b889; NSISe762115f4840ec5a3c6afd9dcdf06259c8f111479bca4d1eb72975da2b5d250b4f5cc95cd235db9d03d4daa932c214dc9cd66d6fb9b79ea3a7903fce6c0a7c2f; DMG0f4d8ce4045bb8f52f975fad1551328f104632af897657353d73ed17bd8849adad3530fcfc96581a579f94ed3b323106310428e3460997faddad09c03092d903; AppImage3af6d1e7636032d67ceab948a0fdbaef98ba4b68a9b04f2b4b9e73855cb9c0f8Final 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.