feat(executor): thread the defining node into ExecRequest (Phase 4b C2)
Carry the resolved script's owner (its defining node) from dispatch into the executor so `import` resolution can be lexical (§5.5). The executing app (`app_id`) stays the SDK isolation boundary; `script_owner` is a separate axis — the lexical origin for imports. - `ExecRequest.script_owner: Option<ScriptOwner>` (serde default; `None` falls back to `App(app_id)` in the engine for old payloads / cluster wire). - `ScriptOwner` gains `Serialize`/`Deserialize` for the wire. - The engine computes `default_origin` and hands it to the resolver (used fully in C3; the resolve() lookup already uses it). - Every dispatch site sets it from the resolved `Script.owner()`: the 4 dispatcher arms (queue/trigger/http/invoke_async, via a new `ResolvedTrigger.script_owner`), the orchestrator id-bypass, and the `invoke()` SDK path (new `ResolvedScript.owner`, so a group script invoked by an app resolves imports from the group). Behaviour-preserving: app scripts still resolve `App(app_id)`; group scripts can't yet carry imports (lifted in C4). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,7 +26,9 @@ use std::sync::{Arc, Mutex};
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use lru::LruCache;
|
||||
use picloud_shared::{AppId, ModuleSource, ModuleSourceError, SdkCallCx, ValidatedScript};
|
||||
use picloud_shared::{
|
||||
AppId, ModuleSource, ModuleSourceError, ScriptOwner, SdkCallCx, ValidatedScript,
|
||||
};
|
||||
use rhai::module_resolvers::ModuleResolver;
|
||||
use rhai::{Engine as RhaiEngine, EvalAltResult, Module, Position, Shared, AST};
|
||||
|
||||
@@ -96,6 +98,12 @@ pub struct PicloudModuleResolver {
|
||||
/// via `PICLOUD_MODULE_IMPORT_DEPTH_MAX`. Read from `Limits` at
|
||||
/// resolver construction.
|
||||
depth_limit: u32,
|
||||
|
||||
/// Lexical origin for a top-level `import` — the defining node of the
|
||||
/// script being executed (Phase 4b, §5.5). Used when Rhai gives no
|
||||
/// `_source` (the entry AST). Nested imports inside a resolved module
|
||||
/// override this via the module AST's source (C3).
|
||||
default_origin: ScriptOwner,
|
||||
}
|
||||
|
||||
impl PicloudModuleResolver {
|
||||
@@ -105,6 +113,7 @@ impl PicloudModuleResolver {
|
||||
cx: Arc<SdkCallCx>,
|
||||
cache: Arc<ModuleCache>,
|
||||
depth_limit: u32,
|
||||
default_origin: ScriptOwner,
|
||||
) -> Self {
|
||||
Self {
|
||||
source,
|
||||
@@ -113,6 +122,7 @@ impl PicloudModuleResolver {
|
||||
in_progress: Mutex::new(Vec::new()),
|
||||
depth: Mutex::new(0),
|
||||
depth_limit,
|
||||
default_origin,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,19 +329,14 @@ impl ModuleResolver for PicloudModuleResolver {
|
||||
))
|
||||
})?;
|
||||
|
||||
// C1 (Phase 4b): resolve via the owner-aware `resolve`. Until C3
|
||||
// threads the importing script's true defining node through, the
|
||||
// origin is the calling app — behaviour-preserving for app-owned
|
||||
// scripts (group scripts can't yet carry imports). The app-rooted
|
||||
// chain walk additionally lets an app import an ancestor group's
|
||||
// modules, which is the intended Phase 4b capability.
|
||||
// Lexical resolution (§5.5): resolve `path` against the importing
|
||||
// node's chain. For the entry script that's `default_origin` (its
|
||||
// defining node); nested-import origin via `_source` lands in C3.
|
||||
// An app-rooted walk reaches ancestor group modules; a group-rooted
|
||||
// walk is sealed from app modules below it (the trust boundary).
|
||||
let origin = self.default_origin;
|
||||
let lookup_result: Result<Option<picloud_shared::ModuleScript>, ModuleSourceError> =
|
||||
tokio::task::block_in_place(|| {
|
||||
handle.block_on(
|
||||
self.source
|
||||
.resolve(picloud_shared::ScriptOwner::App(self.cx.app_id), path),
|
||||
)
|
||||
});
|
||||
tokio::task::block_in_place(|| handle.block_on(self.source.resolve(origin, path)));
|
||||
|
||||
let module_row = match lookup_result {
|
||||
Ok(Some(m)) => m,
|
||||
|
||||
Reference in New Issue
Block a user