From dc8c69ac6fc34dc042bdfdf6ae65b1a5748cae5b Mon Sep 17 00:00:00 2001 From: MechaCat02 Date: Fri, 26 Jun 2026 21:36:11 +0200 Subject: [PATCH] =?UTF-8?q?docs(design):=20mark=20extension=20points=20(?= =?UTF-8?q?=C2=A75.5)=20shipped?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- docs/design/groups-and-project-tool.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/design/groups-and-project-tool.md b/docs/design/groups-and-project-tool.md index 8e7ca65..6a2092e 100644 --- a/docs/design/groups-and-project-tool.md +++ b/docs/design/groups-and-project-tool.md @@ -552,9 +552,18 @@ trust inversion). The rule: > site; the `PicloudModuleResolver` reads the importing node from Rhai's `_source` (set to each module's > owner via `AST::set_source(encode(owner))` before `eval_ast_as_new` — the lexical chaining), and the > cache is re-keyed by resolved `ScriptId`. Group modules + group-script imports are now allowed -> (`group_scripts_api`), and the single-node apply runs the §5.5 dangling-import `plan` check. **Opt-in -> extension points** (the dynamic-resolution branch + `[extension_points]` manifest declaration) remain -> the one deferred piece of §5.5 — a clean additive follow-up on top of the now-origin-aware resolver. +> (`group_scripts_api`), and the single-node apply runs the §5.5 dangling-import `plan` check. +> +> **Extension points (✅ shipped, 2026-06-26).** The opt-in dynamic-resolution branch landed: migration +> `0051` adds an owner-polymorphic `extension_points` table (optional `default_script_id` fallback); +> `ModuleSource` gained `resolve_extension_point(origin, name)` (Some only when the NEAREST declaration +> of `name` on the importer's chain is an extension point — a peer/nearer concrete module shadows it) +> and a chain-constrained `resolve_by_id(origin, id)`. The resolver checks the importer's chain first +> and, on a hit, resolves against `App(cx.app_id)` (the inheriting app), falling back to the default +> body. The decision keys on the trusted importer `origin`, so only the declaring parent can open the +> inversion — a descendant can't make a parent's sealed import dynamic or hijack one. Declared via +> `[[extension_points]] name = "..." default = ""` (app or group manifests); reconciled +> like `vars`, gated on the script-write capability, exported by `pic pull`. ### 5.6 Tree lifecycle: delete, reparent, rename @@ -989,8 +998,8 @@ Resolved items now live inline next to their topic. What genuinely remains: > can't shadow it; verified e2e). Mechanism: owner-polymorphic `ModuleScript`, origin-rooted > `ModuleSource::resolve`, `ExecRequest.script_owner` threaded from every dispatch + `invoke()` site, > `_source`-driven lexical chaining in the resolver (cache re-keyed by `ScriptId`), and the - > single-node dangling-import `plan` check. Still deferred: **opt-in extension points** (the only - > remaining §5.5 piece) and **invoke-by-id** staying app-scoped (inheritance is by-name only); CoW + > single-node dangling-import `plan` check. **Opt-in extension points shipped (§5.5, 2026-06-26).** + > Still deferred: **invoke-by-id** staying app-scoped (inheritance is by-name only); CoW > is **redefine-in-app + re-apply** (no live auto-rebinding). Sharp edge to track: `routes.script_id` > is `ON DELETE CASCADE`, so deleting a > group script removes descendant apps' bound routes (within group-editor authority; the *group*