From 0b9834a90b20a90908acc8f698742c7218450008 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 23 Aug 2026 19:54:08 +0900 Subject: docs(plugin): bring boundary text in line with the implementation Comments that pointed at design notes kept outside the repository are dead ends for anyone reading only the tree, so what each of them explained now lives in a tagged TODO at the site it applies to. Several of those sites also stated something the implementation does not do, and the TODOs record the actual gap instead: the two halves of the codec recognize handle descriptors by different rules, the scripts Command path drops the exception class and collects output in a BufferedOutput that cannot carry an interactive command, find_shortest_path panics where PHP throws, and the package dispatch hand-rolls the variant selection AnyPackage should own. The classifier document likewise described rust-snapshot, plugin-constructible and several of the open questions as designed rather than as built. Co-Authored-By: Claude Opus 5 (1M context) --- crates/shirabe/src/plugin/php_plugin_proxy.rs | 29 ++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'crates/shirabe/src/plugin') diff --git a/crates/shirabe/src/plugin/php_plugin_proxy.rs b/crates/shirabe/src/plugin/php_plugin_proxy.rs index c9d6986b..8469593f 100644 --- a/crates/shirabe/src/plugin/php_plugin_proxy.rs +++ b/crates/shirabe/src/plugin/php_plugin_proxy.rs @@ -732,9 +732,10 @@ fn dispatch_config_method( /// The download manager's contract is asynchronous on both sides: PHP declares a /// `PromiseInterface` return, Rust an `async fn`. The Rust future is driven to completion here -/// and its value handed back as an already-settled React promise, which is the synchronous -/// fallback of the promise design (`.ken/plugin-arch/design.md` §10.1.6) rather than the -/// deferred resolution a concurrent engine would allow. +/// and its value handed back as an already-settled React promise. +/// +/// TODO(async): the boundary has no representation for a promise that is still pending, so the +/// deferred resolution the PHP contract allows collapses into a blocking wait here. fn dispatch_download_manager_method( dm: &std::rc::Rc>, method_name: &str, @@ -1006,12 +1007,15 @@ fn dispatch_event_dispatcher_method( if dispatcher.borrow_mut().has_event_listeners(&probe) { // TODO(plugin): dispatching a worker-constructed event through the Rust-side // dispatcher needs the event object (and the console input it carries) proxied - // back into this process; until then only the no-listener case — where - // upstream's dispatch is observably a no-op returning 0 — is supported. + // back into this process, so only the no-listener case is answered here. return Err(runtime_throw(format!( "dispatching `{name}` from the plugin process is not supported yet while listeners are registered for it" ))); } + // TODO(plugin): answering 0 here skips what `do_dispatch` does before it reaches the + // listener loop, and upstream does both regardless of the listener count: the + // `COMPOSER_DEBUG_EVENTS` trace line, and `push_event`'s circular-call detection + // (a nested dispatch of the same event name throws there even with no listeners). Ok(PluginValue::Int(0)) } other => Err(runtime_throw(format!( @@ -1610,6 +1614,15 @@ fn dispatch_package_method( } // `RootAliasPackage` overrides each of these to write through to its alias target, and // `RootPackage` reaches the same base state either way, so both go through the interface. + // + // TODO(type-model): choosing the body for the concrete variant belongs on `AnyPackage`, + // not here. The stub surface already decides which classes carry a method, so the + // `as_*_mut` accessors' "not available on an alias package" arms are unreachable for a + // method the alias stubs do not declare, and what is left is a per-variant dispatch that + // this guard only approximates: it covers `RootPackage` as well, where the extra hop is + // equivalent only while that impl keeps delegating to the base package, and nothing + // checks it. Method names repeated in the base-package arm below make the answer depend + // on arm order, and a new variant compiles into the wrong body without a diagnostic. "setRequires" | "setDevRequires" | "setConflicts" | "setProvides" | "setReplaces" | "setAutoload" | "setDevAutoload" | "setSuggests" | "setExtra" if package.borrow().is_root() => @@ -2497,8 +2510,10 @@ impl PhpInstallerProxy { /// The `?PromiseInterface` half of the installer contract. The Rust callers await the /// installer's effects rather than chaining continuations, so a returned promise is drained /// here: an already-settled one yields its value (or raises its rejection reason), while a - /// still-pending one is an explicit error — resolving it would need the concurrent execution - /// engine the boundary does not have (`.ken/plugin-arch/design.md` §10.1.6). + /// still-pending one is an explicit error. + /// + /// TODO(async): resolving a still-pending promise would need a concurrent execution engine + /// the boundary does not have. fn promise_result(&self, method: &str, value: PluginValue) -> anyhow::Result> { let handle = match value { PluginValue::Null => return Ok(None), -- cgit v1.3.1-4-g156e