Skip to content

Self-owned source (b): Application-derived subscriber with a curated app-scoped source (careful clsIsApp loosening) #228

Description

@PhysShell

Split from #221 (part b of three). Parent issue has the full sweep context. This is the soundness-sensitive half — do not start it before (a) #227 and (c) land, and review it against the rejected-approaches history.

The pattern

An Application-derived subscriber (App : Application) subscribes to an app-scoped instance that is not a literal static field. The existing clsIsApp exemption already accepts a static source for an Application subscriber; here the source is resolved from application-scoped state (verified: PaletteHelper().GetThemeManager() returns an IThemeManager bound to the app's own merged ResourceDictionary, PaletteHelper.cs:22-26) — genuinely process-lifetime, just reached through a resolver call instead of a static field.

public partial class App : Application {
    protected override void OnStartup(StartupEventArgs e) {
        if (helper.GetThemeManager() is { } themeManager)
            themeManager.ThemeChanged += ThemeManager_ThemeChanged;   // <- flagged today
    }
}

Evidence: MaterialDesignInXamlToolkit src/MahMaterialDragablzMashUp/App.xaml.cs:10,22.

Design guardrails (fixed at split time — READ FIRST)

  • oracle-known-fps.md "Rejected approaches" documents why a broad clsIsStatic subscriber exemption was reverted as unsound: a static-class subscriber says nothing about a lambda capturing a shorter-lived local. This sub-issue must not reintroduce that shape.
  • The loosening applies only when the subscriber class itself derives from Application (the existing clsIsApp gate — keep it byte-for-byte); what loosens is only the source check: from "literal static" to "app-scoped resolver result".
  • "App-scoped resolver result" must be a curated list, not an inference: start with exactly PaletteHelper.GetThemeManager() (match by containing type + method name). Extending the list requires a new confirmed sibling — same policy as the Precision gap: CommandManager.RequerySuggested (weak-referenced WPF static event) flagged as a hard error #223 weak-event allowlist.
  • The handler must be a method-group of the App class itself (no lambdas capturing locals — that is the exact hole the rejected approach had).
  • Negative controls in the sample: (1) same subscription from a non-Application class → still flagged; (2) an Application subscriber whose handler is a lambda capturing a local disposable → still flagged.

Acceptance

  • Sample with the App shape (silent), plus both negative controls (flagged), CI assertions all three ways.
  • A short note update to docs/notes/oracle-known-fps.md explaining why this is NOT the rejected clsIsStatic broadening (subscriber gate unchanged, source list curated, method-group only).
  • Standard gates.

Refs: docs/notes/oracle-sweep-2026-07-10.md (MaterialDesignInXamlToolkit section), docs/notes/field-notes-patterns.md entry 15.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions