fix(vt): F host-composed VtankProfiles storage replaces raw path string
Item F (slice-1 fix round). IPluginHost.VtankProfileDirectory handed the plugin a raw string path and told it to fall back to its own System.IO-based portable default when null — a plugin reading and resolving filesystem paths itself, which is exactly the seam the rest of IPluginHost.Storage deliberately avoids (Core.Plugins.ScopedPluginHost scopes/validates every key; the plugin never sees a path). - IPluginHost: VtankProfileDirectory (string?) deleted; new VtankProfiles (IPluginStorage, defaults to NoOpPluginStorage) added — a second, UNSCOPED storage instance (unlike Storage, which Core scopes per plugin manifest id) rooted at a host-composed VTank-compatible directory. - ScopedPluginHost.VtankProfiles forwards _inner.VtankProfiles directly (no scoping — it names one shared external location, not per-plugin data). New PluginSessionTests.ScopedHostForwardsVtankProfilesUnscoped proves the forwarded instance is the exact same object (Assert.Same), not a wrapper. - AppPluginHost/Program.cs: new vtankProfiles constructor parameter, composed as FilePluginStorage(runtimeOptions.VtankProfileDirectoryOverride ?? Path.Combine(applicationPaths.DataDirectory, "vtank")). - RuntimeOptions.VtankProfileDirectoryOverride: new init-only property parsed from ACDREAM_VTANK_PROFILE_DIR (row added to docs/launch-options.md, side-effects column states the redirect is the only effect and documents the NullIfEmpty whitespace-not-special-cased quirk it shares with every other path-override flag). New RuntimeOptionsTests.VtankProfileDirectoryOverrideIsNullUnlessSet. - FilePluginStorage.List(prefix): empty prefix now means "the storage root itself" instead of throwing (Resolve() rejects empty/whitespace keys, which is correct for every OTHER caller but wrong for "list everything" — VtankProfileDirectory needs exactly that). - Headless: HeadlessPluginHost gained the same VtankProfiles property/constructor param, threaded through HeadlessPluginSession.Create -> HeadlessSessionHost -> HeadlessProcessHost, composed from the new HeadlessPathSet.VtankProfilesDirectory (<DataDirectory>/vtank, no ACDREAM_VTANK_PROFILE_DIR-equivalent override — Headless path overrides are HeadlessPathOverrides/CLI flags, not env vars). A small AcDream.Headless.Plugins.FilePluginStorage duplicates the App implementation byte-for-byte (Headless does not reference AcDream.App and no shared "platform plugins" library exists yet to host one copy; documented as a reasonable future consolidation, not required here). - VtankProfileDirectory.cs rewritten: Resolve/PortableDefault deleted outright (no more System.IO, no plugin-owned portable-default fallback); ListSettingsProfiles/ListNavigationProfiles/ListMetaProfiles now take IPluginStorage and enumerate through EnumerateFileNames, which calls storage.List(string.Empty) and skips any key containing '/' (VTank's profile directory is flat; a nested key from some other IPluginStorage implementation is not a profile file). VtankProfileDirectoryTests rewritten against an in-memory IPluginStorage fake instead of real temp directories; new NestedPathKeysAreNotTreatedAsProfileFiles pins that skip. The prior Resolve/PortableDefault-specific tests (Linux-path guarantee, host-override-vs-portable-default) are superseded by RuntimeOptionsTests.VtankProfileDirectoryOverrideIsNullUnlessSet plus the RuntimeOptions.FromEnvironment Path.Combine-only composition in Program.cs. - docs/architecture/acdream-architecture.md: one sentence in the Storage/List(prefix) paragraph naming VtankProfiles as the second, unscoped storage. No production caller of VtankProfileDirectory's listing methods exists yet (A2's foundation is not wired into MossTankProfileStore/ MossTankMetaProfileStore/MossTankRouteProfileStore's own selection — per that slice's own ledger note), so this is a contract + plumbing change with no MossTank runtime behavior change. MossTank suite: 562/562. Core.Tests (Plugin filter): 50/50. App.Tests (Plugin|LaunchOptions|RuntimeOptions filter): 135/135. Headless.Tests: 173/174 (the one failure, HeadlessCredentialResolverTests. LinuxRejectsGroupOrOtherCredentialPermissions, is a pre-existing Linux-only lane gate that throws PlatformNotSupportedException on this Windows host — unrelated to this change). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
8de69b9741
commit
2040f2bcfb
18 changed files with 318 additions and 164 deletions
|
|
@ -44,16 +44,20 @@ public interface IPluginHost
|
|||
IAutomationSurface Automation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Absolute filesystem directory a VTank-compatible plugin should treat
|
||||
/// as the VTank profile folder (real <c>.usd</c>/<c>.ast</c>/<c>.af</c>
|
||||
/// files, VTank's own naming rules). <see langword="null"/> when the
|
||||
/// host has no opinion, in which case the plugin falls back to its own
|
||||
/// portable per-OS default (never a hard-coded Windows path) — see
|
||||
/// <c>AcDream.Plugins.MossTank.VtankProfileDirectory</c>. A graphical
|
||||
/// host may point this at a real installed VTank's own profile
|
||||
/// directory for direct interop; that platform-specific discovery
|
||||
/// belongs entirely to the host composing this property, never to the
|
||||
/// plugin reading it.
|
||||
/// Storage rooted at the VTank profile folder (real <c>.usd</c>/
|
||||
/// <c>.ast</c>/<c>.af</c> files, VTank's own naming rules) rather than
|
||||
/// this plugin's own scoped <see cref="Storage"/> directory — see
|
||||
/// <c>AcDream.Plugins.MossTank.VtankProfileDirectory</c>, which
|
||||
/// enumerates through this property exclusively (no <c>System.IO</c>,
|
||||
/// no per-OS portable-default fallback of its own) so directory
|
||||
/// discovery stays entirely host-composed. Defaults to the inert
|
||||
/// <see cref="NoOpPluginStorage"/> (<c>IsAvailable</c> false) when the
|
||||
/// host has no opinion. A graphical host may root this at a real
|
||||
/// installed VTank's own profile directory for direct interop, or at
|
||||
/// its own portable per-OS default under
|
||||
/// <c>ApplicationPathSet.DataDirectory</c>; that discovery belongs
|
||||
/// entirely to the host composing this property, never to the plugin
|
||||
/// reading it.
|
||||
/// </summary>
|
||||
string? VtankProfileDirectory => null;
|
||||
IPluginStorage VtankProfiles => NoOpPluginStorage.Instance;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue