Skip to content

Most of SemanticRouter.AspNetCore's 185 public top-level types are implementation details; trim the surface to the documented extension points before 1.0 #200

Open

Description

@siebe41

What

SemanticRouter.AspNetCore exposes 213 public types and 1562 members. The documented extension surface is much smaller:

  • README.md "Extensibility" (README.md:598-610) and docs/architecture.md:133-150 name about 20 interfaces, including IChatConnector, IChatConnectorFactory, IModelDiscovery, IRouterConfigurationStore, IEmbeddingProviderFactory, IToolCallAffinity, IWarmCacheStore, IRoutingActivityStore, IRouterConfigurationHistory, IUsageLedger, IPromptExtractor and IRouterSecretStore.
  • Add SemanticRouterBuilder, the Use* / Map* / Add* extensions and the options types.

Of the 185 top-level public types, 145 are never named in docs/, README.md or samples/. Many are helpers that only first-party code calls, and every one of those first-party callers already has InternalsVisibleTo.

Used by nothing outside AspNetCore except tests:

  • ActivityReports, LocalOnlySignals, RoutingFeedbackLog, MemoryExposureLog
  • ModelFamily, ModelFamilyBand, ModelFamilyFile
  • InMemoryEvaluationSetStore, JsonLinesEvaluationSetStore, ProtectedFileSecretStore, OpenAICompatibleEmbeddingProvider
  • ClaudeCodeMemorySource, KnowledgeGraphMemorySource, MarkdownMemorySource
  • ClientTurnFile, DashboardTheme, ThemeContrastIssue, SecretRedactor

Used only by SemanticRouter.Hosting, which has InternalsVisibleTo (SemanticRouter.AspNetCore.csproj:39):

  • RouterDoctor, RouterCheck, RouterCheckStatus
  • ModelLineup, ModelLineupEntry, ModelLineupReport
  • ConnectorProbe, ConnectorProbeResult, ConnectorProbeFailure
  • SecretReference, ModelFamilyTable

Used by Hosting and Desktop: MachinePolicyLoader, MachinePolicy.

Used by the sibling packages through InternalsVisibleTo:

  • Storage.Sqlite: UsageSummaries, WarmCacheStore, ToolCallAffinity, InMemoryAuditLog, InMemoryUsageLedger, InMemoryTuningStore, InMemoryRouterConfigurationHistory
  • Copilot: CliExecutableLocator, CliExecutableLookup

The concrete RoutingActivityLog and the mutable RoutingActivityEntry (29 public setters) are public too. That class is shared across request threads and handed to IRoutingActivityStore, so its shape becomes a contract.

Evidence

  • A generated type list for the package, with each type's usage checked by grep -rlw <Type> src docs README.md samples tests.
  • The extension tables in the docs: README.md:598-610, docs/architecture.md:133-150.

Impact

At 1.0, every one of these types and members becomes a semver commitment. Refactoring the doctor, the model-family table, the memory sources or the dashboard theme loader would then need a major version. The noise also hides the real extension points, which makes the API harder to learn.

Suggested fix

Do one deliberate API review pass before 1.0:

  • For each public type, decide:
    • a documented extension point or option: it stays public, or
    • an implementation detail: it becomes internal.
  • Hosting and Tests already have InternalsVisibleTo. Desktop would need it for MachinePolicyLoader, or the loader moves to Hosting.
  • Do not add new InternalsVisibleTo for the shipped siblings (see the sibling-package sub-issue). If Sqlite or Copilot need a type, it is public API and gets documented.
  • Record the outcome in PublicAPI.Shipped.txt (see the package-validation sub-issue), so that later additions are visible in review.

Done when

  • Every public type in SemanticRouter.AspNetCore is named in the extensibility and API docs, or is an options or result type of an API that is.
  • The helper and static utility classes listed above are internal, or documented with a reason to stay public.
  • The 1.0 release notes record the public type count, and package validation locks the API.

Activity

  1. siebe41 commented on Oct 20, 2026

    @siebe41
    OwnerAuthor

    Draft PR #252 (stacked on #250) makes 23 of the listed types internal: the 16 "tests only" helpers and the 7 types that only SemanticRouter.Hosting uses. LocalOnlySignals stays public because it is the type of the LocalOnlyWhen option. The types that samples, benchmarks, Onnx, Desktop or the sibling packages use, and RoutingActivityEntry/RoutingActivityLog, are left public for now. The PR body lists each of them as a decision with its alternative.

  2. added a commit that references this issue on Oct 20, 2026
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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions