feat(stella-plugin): the plugin manifest — participation declared, never inferred (#3245 slice A) - #3311
Draft
macanderson wants to merge 1 commit into
Draft
feat(stella-plugin): the plugin manifest — participation declared, never inferred (#3245 slice A)#3311macanderson wants to merge 1 commit into
macanderson wants to merge 1 commit into
Conversation
…ver inferred (#3245 slice A) A new leaf crate (no workspace-crate dependencies, the stella-diag shape) that parses and validates #3245's new manifest blocks as one consent document: the [loop] participation ladder (none < observer < steering < arbiter, monotone), hook grants (Stop only at arbiter, none below steering), max_holds and [requirements] as arbiter-only powers, the host-run [oracle] contract (flip = "required", tamper = "artifact-identity"), and [subloop]/[roles] as declared stages with routing intents. Unknown keys, hook names, and grades are load errors (deny_unknown_fields everywhere — the #1400 rule). LoopGrant::permits_hook is the authoritative filter behind the epic's "an undeclared hook is never invoked": it gates on both the grade and the declared list, so even a hand-built grant cannot leak a dispatch. Slice A's acceptance, as tests: fixture manifests at all four grades round-trip through TOML and serde_json, and a hook not named in the manifest is not permitted even if the process registers for it. Every cross-field rule has a typed ManifestError variant (invariant 5) and a rejection test. HookEvent mirrors stella-core::hooks::HookEvent by name because the dependency is forbidden in both directions; #3310 tracks unifying the two in a shared home. Exemplars followed: stella-tty/stella-diag for the leaf-crate shape, stella-protocol for serde-first round-trip discipline. Refs #3245 Refs #3310
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
Reviewer's GuideIntroduces a new leaf crate Sequence diagram for host loading a manifest and gating hook dispatchsequenceDiagram
actor Host
participant PluginManifest
participant LoopGrant
Host->>PluginManifest: from_toml_str(text)
PluginManifest->>PluginManifest: validate()
PluginManifest-->>Host: Result<PluginManifest, ManifestError>
alt manifest_ok
Host->>LoopGrant: permits_hook(hook_event)
LoopGrant->>LoopGrant: includes(Participation::Steering)
LoopGrant->>LoopGrant: hooks.contains(hook_event)
LoopGrant-->>Host: bool
alt permits_hook == true
Host->>Host: dispatch hook_event to plugin
else permits_hook == false
Host->>Host: skip dispatch (undeclared or under‑graded)
end
else manifest_error
Host->>Host: reject plugin load using ManifestError
end
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Slice A of #3245 (plugins as turn-loop participants): a new leaf crate,
stella-plugin, that parses and validates the epic's new manifest blocks —[loop]with the participation ladder (none<observer<steering<arbiter),[requirements],[oracle],[subloop], and[roles]— as pure functions over borrowed text. No I/O, no workspace-crate dependencies (thestella-diag/stella-ttyleaf shape): the engine never learns plugins exist, and the host that binds these grants to the engine's gates (the Stop gate PR #3302 is generalizing, the hook runner, the sub-agent primitive) arrives with slices B–E.Rules enforced, each with a typed
ManifestErrorvariant (invariant 5) and a rejection test:[loop]= gradenone; unknown keys/hook names/grades are load errors (deny_unknown_fieldseverywhere — the Epic: Stella Apps — a vendor-neutral extension platform (TOML manifest · OAuth lifecycle · host API · marketplace) #1400 rule).steering;Stoponly atarbiter; anarbitermust declareStop(an undeclared hook is never invoked, so an arbiter without it is a contradiction).max_holdsand[requirements]are arbiter-only; an arbiter requires non-empty[requirements](every hold must cite a named requirement).[oracle]is arbiter-only (conservative: widening later is compatible, narrowing is not), argv non-empty, timeout ≥ 1;flip/tamperare closed vocabularies ("required","artifact-identity") so an unknown value is a load error, never a silently weaker contract.[subloop]requires ≥steering, stages non-empty/unique;[roles]requires[subloop], tiers are non-empty open-vocabulary intents (never a credential or URL — routing stays the user's).LoopGrant::permits_hookis the authoritative filter behind "an undeclared hook is never invoked": it gates on grade and declared list, so even a hand-built grant cannot leak a dispatch.Witness
The crate is new, so the whole test surface is the witness: all 26 tests fail on
main(the crate does not exist there) and pass here. Slice A's acceptance from #3245 §6 verbatim, intests/manifest_grades.rs: fixture manifests at all four grades round-trip (through TOML andserde_json— invariant 4), and a hook not named in the manifest is not permitted even if the process registers for it.Decisions a reviewer should weigh
stella-appvsstella-plugin) is undecided; I pickedstella-pluginbecause the epic's own vocabulary is "plugin" throughout. Renaming before anything depends on it is onegit mv+ member edit; cheap to veto now, expensive later.HookEventis a by-name mirror ofstella-core::hooks::HookEvent, because the dependency is forbidden in both directions. Filed Unify the plugin manifest's HookEvent mirror with stella-core::hooks::HookEvent in a shared home #3310 for unifying the two in a shared home (likelystella-protocol) so the mirror stops being manual.[oracle]is stricter than the epic's literal text (which only marksmax_holds/[requirements]arbiter-only). Chosen because loosening later is backward-compatible while tightening breaks shipped manifests; the error variant's doc states this.Dependencies
No new workspace dependencies:
serde,toml,thiserrorwere already in[workspace.dependencies];serde_jsonis dev-only for the round-trip tests.Gate
cargo test -p stella-plugin(26 green),cargo clippy -p stella-plugin --all-targets -- -D warnings,RUSTDOCFLAGS="-D warnings" cargo doc -p stella-plugin,make guards-fastincl. god-files (README carries the no-god-files section), typed-errors, module-reachability, file-size (judged against base), doc-links, invariants — all green locally. AGENTS.md's crate count, god-file prose, and workspace table updated in the same PR.Refs #3245
Refs #3310
Summary by Sourcery
Add a new leaf crate for parsing and validating plugin manifests that declare participation in the turn loop, and wire it into the workspace metadata.
New Features:
stella-plugincrate to parse and validate plugin manifests, including participation grades, hook grants, requirements, oracle configuration, subloop stages, and role routing intents, as pure functions over borrowed text.PluginManifestAPI with a single TOML-based constructor and an authoritativeLoopGrant::permits_hookcheck for whether specific hook events are allowed.Enhancements:
stella-plugincrate, including invariants, layout, and dependency constraints, in a dedicated README.Tests: