Conversation
Test Results 47 files 47 suites 22m 58s ⏱️ For more details on these failures, see this check. Results for commit c984427. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Pull request overview
This PR bundles several long-running feature and stability tracks across MeshWeaver core + Memex: social publishing foundations, in-process #r "nuget:..." compilation support (node-type + interactive markdown), move-operation performance/timeout hardening, and multiple UI/stream reliability improvements. It also standardizes the code folder naming from _Source/_Test to Source/Test across code, tests, docs, and samples.
Changes:
- Introduces
MeshWeaver.Social(options, DI wiring, publish queue, credential model) plus initial Memex wiring (LinkedIn connect entry points + user menu hooks). - Adds
MeshWeaver.NuGetresolver + directive parser and integrates it into script compilation (#r "nuget:Pkg, Version"), including cache backends and tests. - Improves operational robustness: parallelized recursive moves, default 30s mesh-op timeout, “no endless spinner” navigation status UI, and remote stream resubscribe behavior.
Reviewed changes
Copilot reviewed 159 out of 265 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/MeshWeaver.StorageImport.Test/StorageImporterTests.cs | Updates test expectations/docs to Source/ naming. |
| test/MeshWeaver.Social.Test/PostStatsRefresherTest.cs | Adds stats refresher test coverage (needs deterministic timeout handling). |
| test/MeshWeaver.Social.Test/MeshWeaver.Social.Test.csproj | Adds new Social test project referencing Social + Fixture. |
| test/MeshWeaver.Social.Test/InMemoryPublishQueueTest.cs | Adds unit tests for publish queue due-drain + dedup. |
| test/MeshWeaver.Persistence.Test/FileSystemPersistenceTest.cs | Updates partition tests to Source/ naming. |
| test/MeshWeaver.MathDemo.Test/TestPaths.cs | Adds helper paths for MathDemo sample test assets. |
| test/MeshWeaver.MathDemo.Test/MeshWeaver.MathDemo.Test.csproj | Adds MathDemo test project and copies sample graph data to output. |
| test/MeshWeaver.Hosting.PostgreSql.Test/SatelliteQueryTests.cs | Updates code-path routing tests to Source/ naming. |
| test/MeshWeaver.Hosting.Monolith.Test/UserActivityAreaTest.cs | Updates regression test docs to Source/ naming. |
| test/MeshWeaver.Hosting.Blazor.Test/NavigationServiceTest.cs | Adjusts test to assert “no 404 flash” during retries. |
| test/MeshWeaver.Graph.Test/NuGetDirectiveParserTest.cs | Adds unit tests for parsing/stripping #r "nuget:...". |
| test/MeshWeaver.Graph.Test/NuGetAssemblyResolverTest.cs | Adds networked NuGet restore end-to-end tests (skippable via env var). |
| test/MeshWeaver.Graph.Test/MeshWeaver.Graph.Test.csproj | References new MeshWeaver.NuGet project. |
| test/MeshWeaver.FutuRe.Test/MeshWeaver.FutuRe.Test.csproj | Updates compile-included sample sources to Source/ paths. |
| test/MeshWeaver.Content.Test/CompilationErrorTest.cs | Updates broken-code test to Source/ path. |
| test/MeshWeaver.AI.Test/MeshPluginTest.cs | Updates MCP tool count expectations (adds RunTests/Move/Copy). |
| src/MeshWeaver.Social/SocialOptions.cs | Adds configurable knobs for publishing/stats/ingest scheduling. |
| src/MeshWeaver.Social/SocialExtensions.cs | Adds DI wiring for social publishing subsystem and hosted services. |
| src/MeshWeaver.Social/PlatformCredential.cs | Adds credential record model (access/refresh/expiry metadata). |
| src/MeshWeaver.Social/MeshWeaver.Social.csproj | Introduces Social library project. |
| src/MeshWeaver.Social/IPublishQueue.cs | Adds publish queue abstraction + in-memory implementation. |
| src/MeshWeaver.Social/IApprovalPublishBridge.cs | Defines bridge contract and PublishableSnapshot model. |
| src/MeshWeaver.NuGet/ResolvedPackageSet.cs | Adds resolver output model (assemblies, probing dirs, versions). |
| src/MeshWeaver.NuGet/NuGetServiceCollectionExtensions.cs | Adds DI extension to register resolver + cache. |
| src/MeshWeaver.NuGet/NuGetPackageReference.cs | Adds package reference model (id + version range). |
| src/MeshWeaver.NuGet/NuGetDirectiveParser.cs | Implements #r "nuget:..." extraction + source stripping. |
| src/MeshWeaver.NuGet/MeshWeaver.NuGet.csproj | Introduces NuGet resolver project and dependencies. |
| src/MeshWeaver.NuGet/INuGetPackageCache.cs | Adds optional persistent cache interface + null implementation. |
| src/MeshWeaver.NuGet/INuGetAssemblyResolver.cs | Adds resolver interface returning ResolvedPackageSet. |
| src/MeshWeaver.NuGet.AzureBlob/MeshWeaver.NuGet.AzureBlob.csproj | Adds Azure Blob cache backend project. |
| src/MeshWeaver.NuGet.AzureBlob/BlobNuGetPackageCacheExtensions.cs | Adds DI helper to register blob-backed cache. |
| src/MeshWeaver.Mesh.Contract/Services/MeshOperationOptions.cs | Adds mesh operation timeout options (default 30s). |
| src/MeshWeaver.Mesh.Contract/Services/IStorageAdapter.cs | Updates docs/examples to Source/ naming. |
| src/MeshWeaver.Mesh.Contract/Services/INavigationService.cs | Adds Status observable contract for UI progress reporting. |
| src/MeshWeaver.Mesh.Contract/Services/IIconGenerator.cs | Adds icon generator abstraction returning an observable SVG. |
| src/MeshWeaver.Mesh.Contract/PartitionDefinition.cs | Updates standard table mappings (Source/Test → code) and clarifies semantics. |
| src/MeshWeaver.Mesh.Contract/MeshExtensions.cs | Adds timeout override + move timeout enforcement + grain dispose on delete. |
| src/MeshWeaver.Mesh.Contract/CodeConfiguration.cs | Updates docs to Source/ naming. |
| src/MeshWeaver.Kernel.Hub/MeshWeaver.Kernel.Hub.csproj | Removes Interactive package mgmt dependency; references MeshWeaver.NuGet. |
| src/MeshWeaver.Hosting/Persistence/MigrationUtility.cs | Updates migration heuristics to include Source/Test + legacy _Source/_Test. |
| src/MeshWeaver.Hosting/Persistence/FileSystemStorageAdapter.cs | Treats Source/Test as code paths + keeps legacy compatibility. |
| src/MeshWeaver.Hosting/Persistence/FileSystemPersistenceService.cs | Parallelizes descendant move I/O (with concurrency implications). |
| src/MeshWeaver.Hosting/Persistence/CachingStorageAdapter.cs | Updates code sub-namespace detection (Source/Test + legacy). |
| src/MeshWeaver.Hosting.PostgreSql/PostgreSqlPartitionedStoreFactory.cs | Guards against source/test mistakenly becoming schemas. |
| src/MeshWeaver.Hosting.PostgreSql/PostgreSqlCrossSchemaQueryProvider.cs | Filters malformed parameters to avoid NRE during SQL interpolation. |
| src/MeshWeaver.Hosting.Blazor/MeshWeaver.Hosting.Blazor.csproj | Adds NU1510 suppression. |
| src/MeshWeaver.Graph/PartitionTypeSource.cs | Updates docs to Source/ naming. |
| src/MeshWeaver.Graph/MeshWeaver.Graph.csproj | References MeshWeaver.NuGet. |
| src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs | Improves create href behavior + reactive/grouped children catalog. |
| src/MeshWeaver.Graph/MeshDataSource.cs | Updates docs to Source/ naming. |
| src/MeshWeaver.Graph/Configuration/ScriptCompilationService.cs | Integrates NuGet directive parsing + resolver into compilation. |
| src/MeshWeaver.Graph/Configuration/NodeTypeDefinition.cs | Updates docs/examples to Source/ naming. |
| src/MeshWeaver.Graph/Configuration/MeshDataSourceNodeType.cs | Changes sources namespace constant to Source. |
| src/MeshWeaver.Graph/Configuration/GraphConfigurationExtensions.cs | Registers NuGet resolver and uses Source code path. |
| src/MeshWeaver.Graph/Configuration/CodeNodeType.cs | Treats Code nodes as primary content; defines Source/Test constants. |
| src/MeshWeaver.Documentation/Data/DataMesh/UnifiedPath.md | Documents @/ semantics and HTML-href pitfalls. |
| src/MeshWeaver.Documentation/Data/DataMesh/SocialMedia/Profile/Source/SocialMediaProfileLayoutAreas.cs | Adds SocialMedia profile layout areas example. |
| src/MeshWeaver.Documentation/Data/DataMesh/SocialMedia/Profile/Source/SocialMediaProfile.cs | Adds SocialMedia profile content model example. |
| src/MeshWeaver.Documentation/Data/DataMesh/SocialMedia/Post/Source/SocialMediaPost.cs | Adds SocialMedia post content model example. |
| src/MeshWeaver.Documentation/Data/DataMesh/SocialMedia/Post/Source/Platform.cs | Adds SocialMedia platform reference-data example. |
| src/MeshWeaver.Documentation/Data/DataMesh/SocialMedia.md | Updates docs to Source/ naming and authoring guidance. |
| src/MeshWeaver.Documentation/Data/DataMesh/SatelliteEntities.md | Clarifies Source/Test are primary content, not satellites. |
| src/MeshWeaver.Documentation/Data/DataMesh/NodeTypes.md | Adds Node Types documentation index page. |
| src/MeshWeaver.Documentation/Data/DataMesh/NodeTypeConfiguration.md | Updates docs to Source/ naming. |
| src/MeshWeaver.Documentation/Data/DataMesh/NodeOperations.md | Updates docs to Source/ naming. |
| src/MeshWeaver.Documentation/Data/DataMesh/DataConfiguration.md | Updates docs to Source/ naming. |
| src/MeshWeaver.Documentation/Data/DataMesh/CreatingNodeTypes.md | Updates docs to Source/Test naming throughout. |
| src/MeshWeaver.Documentation/Data/DataMesh.md | Updates TOC links and adds NuGet packages bullet. |
| src/MeshWeaver.Documentation/Data/Architecture/PartitionedPersistence.md | Updates persistence routing docs for Source/Test. |
| src/MeshWeaver.Documentation/Data/Architecture/MeshGraph.md | Updates examples to Source/ naming. |
| src/MeshWeaver.Documentation/Data/Architecture/BusinessRules/Cession/Source/CessionSampleData.cs | Adds cession sample dataset for docs/demo. |
| src/MeshWeaver.Documentation/Data/Architecture/BusinessRules/Cession/Source/CessionResultsArea.cs | Adds reactive charting layout area example. |
| src/MeshWeaver.Documentation/Data/Architecture/BusinessRules/Cession/Source/CessionEngine.cs | Adds pure business logic sample for cession calculations. |
| src/MeshWeaver.Documentation/Data/Architecture/BusinessRules/Cession/Source/CessionData.cs | Adds content models for cession example. |
| src/MeshWeaver.Data/Serialization/SyncStreamOptions.cs | Adds configurable heartbeat interval for sync streams. |
| src/MeshWeaver.Data/Serialization/JsonSynchronizationStream.cs | Implements resubscribe-on-owner-dispose logic. |
| src/MeshWeaver.Blazor/Pages/ApplicationPage.razor | Switches to NavigationStatus-driven progress/not-found/error UI. |
| src/MeshWeaver.Blazor/Components/NavigationProgressBar.razor.css | Adds styling for full-page vs compact overlay progress bar. |
| src/MeshWeaver.Blazor/Components/NavigationProgressBar.razor | Adds reusable “spinner + message” component. |
| src/MeshWeaver.Blazor/Components/MeshSearchView.razor.cs | Adds Category grouping fallback to NodeType. |
| src/MeshWeaver.Blazor/Components/LayoutAreaView.razor.cs | Adds stream lifecycle logging and additional diagnostics. |
| src/MeshWeaver.Blazor/Components/LayoutAreaView.razor | Surfaces compilation progress indicator before first stream emission. |
| src/MeshWeaver.Blazor/Components/CompileProgressIndicator.razor.css | Adds styling for compilation progress banner. |
| src/MeshWeaver.Blazor/Components/CompileProgressIndicator.razor | Adds polling UI component for active NodeType compilation. |
| src/MeshWeaver.Blazor.Portal/MeshWeaver.Blazor.Portal.csproj | Adds NU1510 suppression. |
| src/MeshWeaver.Blazor.AI/MeshWeaver.Blazor.AI.csproj | Adds NU1510 suppression. |
| src/MeshWeaver.Blazor.AI/McpMeshPlugin.cs | Adds Patch/Move/Copy MCP tools and improves tool descriptions. |
| src/MeshWeaver.AI/ThreadLayoutAreas.cs | Adds debug logging around streaming view emission. |
| src/MeshWeaver.AI/IconGenerator.cs | Adds default AI-backed IIconGenerator implementation. |
| src/MeshWeaver.AI/DelegationCompletedEvent.cs | Removes delegation tracker/event types. |
| src/MeshWeaver.AI/Data/Agent/Worker.md | Updates @/ link guidance (no raw HTML href with @/). |
| src/MeshWeaver.AI/Data/Agent/ToolsReference.md | Updates @/ link guidance and provides correct/incorrect table. |
| src/MeshWeaver.AI/Data/Agent/Orchestrator.md | Updates @/ link guidance for agent outputs. |
| src/MeshWeaver.AI/AIExtensions.cs | Removes old type registration; registers IIconGenerator. |
| memex/aspire/Memex.Portal.Distributed/Program.cs | Registers blob-backed NuGet package cache in distributed deployment. |
| memex/aspire/Memex.Portal.Distributed/Memex.Portal.Distributed.csproj | References MeshWeaver.NuGet.AzureBlob. |
| memex/aspire/Memex.Database.Migration/Program.cs | Adds source/test to reserved schema list. |
| memex/aspire/Memex.AppHost/Program.cs | Adds LinkedIn secret/env wiring + sets NUGET_PACKAGES cache dir. |
| memex/Memex.Portal.Shared/Social/SocialMediaUserMenuProvider.cs | Adds “Social Media” shortcut on a user’s own node (lazy hub creation). |
| memex/Memex.Portal.Shared/Social/ApiCredentialNodeType.cs | Adds NodeType for PlatformCredential stored under _ApiCredentials. |
| memex/Memex.Portal.Shared/Pages/Login.razor | Adds “Connect LinkedIn for publishing” CTA on login page. |
| memex/Memex.Portal.Shared/OrganizationNodeType.cs | Switches to default layout areas registration. |
| memex/Memex.Portal.Shared/MemexConfiguration.cs | Adds LinkedIn publisher wiring, @/ redirect middleware, and routes. |
| memex/Memex.Portal.Shared/Memex.Portal.Shared.csproj | References MeshWeaver.Social. |
| memex/Memex.Portal.Monolith/appsettings.Development.json | Enables debug logging for LayoutAreaView. |
| MeshWeaver.slnx | Adds new projects (NuGet, NuGet.AzureBlob, Social, new test projects). |
| Directory.Packages.props | Adds NuGet.* package versions for resolver implementation. |
| CLAUDE.md | Documents @/ local-only rule and href/URL restrictions. |
| (Various) samples/Graph/... | Adds/updates many sample NodeTypes and content under Source/ to reflect new conventions and demos. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…+ test helpers Recursive DeleteNodeRequest handled on a node's own hub was deadlocking: the final DeleteSelfFromStorage posted Ok and DisposeRequest from the dying hub, so the Ok raced callback disposal on the caller and was lost. Introduce CommitNodeDeletionMessage and forward the terminal commit (storage delete + reply + grain dispose) to the resolved mesh hub (walking ParentHub upward) — Sender becomes the stable mesh hub, FIFO on the caller's inbound queue guarantees Ok resolves the RegisterCallback before DisposeRequest arrives. Also addresses two Copilot review comments on PR #95: - FileSystemStorageAdapter.DeleteAsync empty-directory ascent is now concurrency- tolerant: wraps the enumerate + Directory.Delete in try/catch, swallowing the DirectoryNotFoundException race and breaking on IOException (non-empty / in-use). Required because FileSystemPersistenceService.MoveNodeAsync now parallelizes descendant deletes via Task.WhenAll. - PostStatsRefresherTest.WaitUntilAsync throws TimeoutException with a descriptive message instead of returning silently on deadline, so the test cannot green-tick a stats-refresh that never happened. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@copilot resolve the merge conflicts in this pull request |
Resolved. The merge with Conflicts resolved:
|
Code review — recent stability batch
Manual review of the last ~20 commits since Correctness — should fix before merge1. ✅ foreach (var (k, v) in perParams)
{
var newKey = "@" + prefix + k.TrimStart('@');
renamedSql = renamedSql.Replace(k, newKey);
renamedParams[newKey] = v;
}
Fix: single regex pass keyed on 2. ✅ Fix: 3. ✅ Fix: parse every query in 4. ✅ Fix: Race / lifecycle hazards5. ✅ Fix: drop the time-based heuristic in favour of a structural one — skip recovery only when the thread is still an auto-execute candidate ( 6. ✅ 7. ✅ 8. ✅ Fix: pre-allocate the Style / consistency9. ✅ 10. ✅ 11. ✅ Fix: drop the per-query Limit injection. Limit is enforced post-union via ✅ Looks good (no action needed)
|
Code review — part 2: rest of the PR
Continuing review on the bulk of the PR (everything before the recent stability batch). Focused on the new projects ( Correctness — should fix before merge12. ✅ return _cache.GetOrAdd(key, _ => ResolveCoreAsync(requested, framework, ct));If Fix: evict faulted/cancelled tasks from the cache before returning. Also pass 13. ✅ Fix: switched to 14. ✅ Fix: post-hydration, the resolver opens the package folder via 15. ✅ Fix: defensive 16. ✅ Race / lifecycle hazards17. ✅ 18. ✅ 19. ✅ Fix: replaced with a single bounded Style / consistency20. ✅ Fix: register the publisher as a true singleton via 21. ✅ Fix: gate hosted-service registration on 22. ✅ 23. ✅ ✅ Looks good (no action needed)
Areas not covered in this reviewPersistence-service refactors ( |
Review fixes applied — all 23 items addressed5 commits, organised by batch. Locally committed, not pushed yet.
Verification
Notes
Ready to push when you want. |
|
Done — review item #14 is now closed in commit |
…fix DI lifetimes, redact PII, drop dynamic - ThreadExecution: collapse triple-stacked <summary> blocks on WatchForExecution and NotifyParentCompletion. Tooling kept the last one anyway; the dead scaffolding was just noise. - SocialExtensions: register LinkedInPublisher / XPublisher as TRUE singletons (factory-resolved with named HttpClient). The previous AddHttpClient<T>+AddSingleton<IPlatformPublisher> mix made the concrete type transient while the interface alias was singleton — direct vs via-interface resolution returned different instances. Also gate hosted-service registration on at least one platform being configured (the "all-or-nothing" comment was wrong; with zero platforms the four hosted services started anyway and faulted on first tick). - LinkedInPublisher: replace `(dynamic)media.shareMediaCategory` peek with two concrete payload shapes — typo turns into a compile error instead of a RuntimeBinderException. - LinkedIn / X publishers: cap error-body logs at 200 chars to bound PII exposure (the body can echo the user's post text on validation rejection). Full body still goes to PublishResult.Error for the caller. Addresses PR #95 review items #9, #20, #21, #22, #23. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… in-memory engines
PostgreSqlStorageAdapter.QueryNodesAsync(IReadOnlyList<ParsedQuery>):
- Replace order-dependent `string.Replace` parameter rename with a
single `Regex.Replace` keyed on @<name> word boundary that gates
on perParams.ContainsKey. Sequential Replace was mangling adjacent
tokens (renaming `@p` after `@p1` produced `@q0_q0_p1`) and could
clobber `@…` substrings inside string literals / JSONB paths.
- Switch from `UNION` to `UNION ALL` wrapped in
`SELECT DISTINCT ON (namespace, id) ... ORDER BY namespace, id, last_modified DESC`.
Plain UNION dedupes whole rows — two queries observing the same
node at slightly-different last_modified would BOTH appear in the
output. Path-keyed dedup (= MeshNode identity) with newest-wins
tie-break collapses them correctly.
PostgreSqlMeshQuery.ObserveQuery<T>:
- Parse EVERY query in request.EffectiveQueries and build per-query
(basePath, scope) filters; the change-notifier subscription
OR-joins them so multi-query observations get delta refreshes
triggered by ANY query's path/scope, not just query #0's. The
previous shape silently lost live updates from queries #1+.
PostgreSqlMeshQuery.QueryNodesUnionAsync + MeshQueryEngine:
- Drop the per-query `parsedList[0].Limit = request.Limit` injection.
Query #0 hit its limit before yielding the union's most relevant
rows, while queries #1+ contributed unbounded — making the result
iteration-order dependent. Limit is now enforced post-union via
MinLimit(request.Limit, firstParsed.Limit) so a request-level cap
can't be circumvented and an in-query `limit:N` still wins when
smaller.
- MeshQueryEngine: CollectMatchedAsync returns the LIST of every
query's basePath; the source:activity post-filter scans every
base path's descendants and unions activity-main-paths so
queries #1+ aren't filtered against query #0's subtree only.
Addresses PR #95 review items #1, #2, #3, #4, #11.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ThreadExecution stability fixes ThreadExecution.cs (already in commit 478fdaa — recapping here for the review-item index): - RecoverStaleExecutingThread: drop the 2-minute "fresh execution" window in favour of a structural check (skip when PendingUserMessage + ActiveMessageId are still set, i.e. the thread is an auto-execute candidate WatchForExecution will pick up). Closes the "long-running agent crashed at minute 5 → IsExecuting=true forever" gap; the time-based heuristic contradicted commit 6dc436b's "no time limits" stance. - Subject<StreamingSnapshot>: declare with `using var` so the Subject itself disposes alongside its subscription. Minor leak per execution previously. - HandleSubmitMessage: pre-allocate the per-round CancellationTokenSource and store it on the thread hub BEFORE posting SubmitMessageResponse — closes the race where an early Stop click between IsExecuting=true and ExecuteMessageAsync's `parentHub.Set(executionCts)` found a null CTS slot and silently no-op'd. ExecuteMessageAsync now reuses the pre-allocated CTS (with a fallback for the auto-execute path that bypasses HandleSubmitMessage). IsExecutingLifecycleTest.cs: - Migrate the response-text wait from text-pattern matching (skipping placeholders "Allocating agent..." etc.) to `ThreadMessage.CompletedAt is not null`, which ExecuteMessageAsync sets only on the terminal PushToResponseMessage call. Same pattern adopted in ChatHistoryTest in commit ab3af8b. - Add a regression assertion that final ThreadMessage.Status == Completed. The terminal-status guard in PushToResponseMessage prevents the late Sample(100ms)-flushed Streaming push from regressing the cell from Completed back to Streaming; this assertion catches any future regression of that guard. Addresses PR #95 review items #5, #6, #7, #8, #10. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…, parallelism, backoff)
NuGetAssemblyResolver:
- Evict faulted/cancelled tasks from the per-key cache before
returning. A transient feed failure (network, throttle, cancelled
in-flight resolve) used to poison the cache for the resolver's
lifetime — every subsequent call replayed the same exception.
- Pass CancellationToken.None to the shared core task so a single
caller's cancellation can't take down the resolution for
others; per-caller `ct` projects via `task.WaitAsync(ct)`.
- Switch DependencyBehavior from `Lowest` to `HighestMinor` so
`#r` directives pick up patch-level security fixes via
transitive dependencies without silently jumping major/minor.
- Document that hydrated cache content is trusted to match
(id, version) — flag for future content-hash verification if
cache poisoning becomes a concern.
LinkedInPublisher / XPublisher (LinkedIn already committed in batch A
for the dynamic+PII parts; this commit adds the 401 retry):
- SendWith401RetryAsync: on the FIRST 401 response from a publish,
force-refresh the token (zero ExpiresAt before EnsureFreshAsync)
and retry once. Closes the race where the access token's TTL
expired between EnsureFreshAsync and the actual API call.
PostStatsRefresher:
- Process due-refresh targets via Parallel.ForEachAsync bounded
by SocialOptions.StatsRefreshDegreeOfParallelism (default 8),
so a slow API + large refresh window can't let one tick
overshoot the next interval.
- Per-target failure backoff via a ConcurrentDictionary of
last-failure timestamps — targets that failed within
StatsRefreshFailureBackoff (default 15 min) skip the next tick.
Stops a degraded platform from generating thousands of repeat
warnings every cycle while the underlying issue is fixed.
Success clears the backoff entry.
SocialOptions: add StatsRefreshDegreeOfParallelism (8) and
StatsRefreshFailureBackoff (15 min) knobs.
Addresses PR #95 review items #12, #13, #14, #16, #17, #18.
(#15 XPublisher defensive parse + the LinkedIn dynamic / PII items
were already in commit 478fdaa.)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… file lock The MESHWEAVER_DISPOSE_TRACE=1 trace took a global lock per call (`File.AppendAllText` under `lock (DisposeTraceLogLock)`), serialising hub teardown under load when many hubs disposed concurrently. Replaced with a single bounded `Channel<string>` (capacity 4096, FullMode = DropWrite) drained by one writer task started in the type initialiser. Producers `TryWrite` non-blocking — if the disk is slow / locked, lines drop on full instead of putting back-pressure on dispose. Single-reader semantics avoid contention on the file handle. Addresses PR #95 review item #19. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the TODO from commit 512adb4. After a successful INuGetPackageCache.TryHydrateAsync, the resolver now opens the hydrated folder via PackageFolderReader and compares the package's own .nuspec-declared (id, version) against the expected (id, version). On mismatch the directory is purged and the resolver falls back to the feed. This catches the failure modes #14 was about: wrong package stored under right key (cross-tenant blob, accidental copy, drift after a manual edit). The .nuspec is the canonical NuGet source of truth, so a tampered cache entry can't fake the identity without rewriting the nuspec — which we'd then catch at hydration time. No INuGetPackageCache contract change; validation lives entirely in the resolver. Closes the last open item from PR #95 review (item #14). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
@copilot resolve the merge conflicts in this pull request |
Test Results (shard 1)1 011 tests 1 009 ✅ 5m 13s ⏱️ Results for commit c984427. ♻️ This comment has been updated with latest results. |
Test Results (shard 0)1 146 tests 1 146 ✅ 1m 45s ⏱️ Results for commit c984427. ♻️ This comment has been updated with latest results. |
Test Results (shard 3)1 113 tests 1 113 ✅ 7m 35s ⏱️ Results for commit c984427. ♻️ This comment has been updated with latest results. |
Test Results (shard 2) 13 files 13 suites 8m 25s ⏱️ For more details on these failures, see this check. Results for commit c984427. ♻️ This comment has been updated with latest results. |
…fix missing haiku price) Adds AnthropicProviderCatalogTest covering the previously-untested Anthropic provider: - AddAnthropic registers ONE BYO-key catalog source with the direct api.anthropic.com endpoint and the current Claude model ids (opus-4-8 / sonnet-4-6 / haiku-4-5-20251001). - BuiltInLanguageModelProvider materialises it into a ModelProvider node + one key-less, public LanguageModel child per Claude id (the catalog the picker shows; admin keys later). - AzureClaudeChatClientAgentFactory routes those ids; non-Claude ids do not. - every shipped Claude id has a built-in price row. That last assertion caught a real bug: ModelPricing.Defaults had the undated "claude-haiku-4-5" but AddAnthropic ships the dated "claude-haiku-4-5-20251001", and Default() only de-prefixes by '/', so deployed Haiku showed no cost. Added the dated price row (1/5 USD) to match. MeshWeaver.AI.Test now references MeshWeaver.AI.AzureFoundry (where AddAnthropic lives), alongside the existing OpenAI/ClaudeCode provider refs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d GetDataRequest
SetThreadHubIdentity (the thread hub's cold-activation initializer) self-read its own
node via hub.GetMeshNode(hub.Address) -- a GetDataRequest posted to the hub's OWN
address before any identity was established. PostPipeline correctly failed it closed
("AccessContext must never be null ... hub=Thread, GetDataRequest, target=Thread"),
reproduced deterministically by reading any NodeType-def node (`get @Thread`).
Read the own thread node's FIRST loaded emission off the local MeshNodeReference
reducer instead (GetMeshNodeStream -- posts NOTHING, so the never-null guard cannot
fire), filtering on MeshThread content so the owner (CreatedBy) is always present --
exactly the pattern InitializeThreadLifecycle already uses for cold-load recovery.
Scoped to the actual bug site: a broader GetMeshNode->GetMeshNodeStream primitive
swap deterministically regressed thread cancellation (InboxTool Cancel tests), so the
fix targets SetThreadHubIdentity, the sole trigger of the get @thread failure.
Repro: ThreadHubSelfReadTest activates the Thread hub and asserts no target=Thread
GetDataRequest AccessContext error is logged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…seeding BuiltInLanguageModelProvider now emits TWO PartitionAccessPolicy nodes — one for the Provider partition AND one for the legacy Model partition (the model picker / resolution read `model` under the user's identity, so it also needs PublicRead; restored after the catalog refactor, atioz 2026-06-23). Provider_Policy_IsPublicRead_WithLiftedWriteCaps used ContainSingle across ALL PartitionAccessPolicy nodes, so it broke (found 2). Target the Provider partition's policy by namespace, and add an assertion that the Model partition also gets a PublicRead policy (covers the new behavior). No production change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pages with public-read access were being shown to logged-out visitors. The portal requires authentication for ALL mesh content; "public access" governs what an *authenticated* user without an explicit grant may read, not what an anonymous browser may see. NavigationService.ProcessResolvedPath: a logged-out visitor (the explicit Anonymous well-known id, captured synchronously on the inbound-activity thread) is now unconditionally flipped to AccessDenied — even for a PublicRead node, which still reaches the gate because PathResolutionService resolves under a System bypass. ApplicationPage's AuthorizeView turns AccessDenied into RedirectToLogin → /login?returnUrl=<page>, so signing in bounces the visitor back to the page they originally requested. The old per-node anonymous read-gate (public passes / private → denied) is removed. ApplicationPage: skip the GetPreRenderedHtml load during the static prerender pass for a logged-out visitor, so a PublicRead node's cached HTML is not flashed before the interactive gate redirects them. Tests: NavigationServiceTest/NavigationProgressTest now run as an authenticated (System) visitor by default — System is non-anonymous and short-circuits TrackNavigationActivity before the un-proxyable hub.Post. The two anonymous cases assert AccessDenied for both private and PublicRead nodes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ested page
After completing onboarding ("Get Started"), users were dropped on "/" (and
could bounce onto /welcome) instead of returning to the page they originally
tried to open. The returnUrl already flowed correctly through the whole auth
chain (RedirectToLogin → /login → /auth/login → OAuth callback → original
page); it was lost only at the onboarding leg.
- OnboardingMiddleware: when bouncing an authenticated-but-not-onboarded user
to /onboarding, carry the page they were trying to reach as ?returnUrl=
(this request's own path+query — inherently local, no open-redirect surface).
- Onboarding.razor: read [SupplyParameterFromQuery] ReturnUrl and, on both the
existing-user and submit-success paths, navigate to it (falling back to "/").
SafeReturnUrl() accepts only same-site relative paths, rejecting absolute /
protocol-relative URLs so a crafted returnUrl can't become an open redirect.
- Welcome.razor: preserve returnUrl through its sign-in links and its
authenticated → /onboarding redirect so the chain is never dropped here.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…+ inline editing
Replace the clumsy access-control page with two query-driven sections (parent
scope and current scope) of clean rows, plus an inline add row and a collapsed
Advanced area for the partition policy.
- AccessControlLayoutArea: two MeshSearch sections from
`namespace:{path}/_Access nodeType:AccessAssignment` for the current node and
its parent; inline add row (user picker `namespace:"" nodeType:User` + role
select defaulting to Editor) that stores the bare role id; partition-policy
controls moved under "Advanced". Drops the dead "Inherited Permissions"
section (was always passed an empty list) and the hand-built HTML banner.
- AccessAssignment Thumbnail/Overview: render one clean row per assignment
(person/group thumbnail + a node-bound role editor per role + remove),
replacing the hand-built HTML role chips.
- New MeshNodeRoleEditorControl + MeshNodeRoleEditorView: a node-bound role
dropdown + Deny checkbox that read/write GetMeshNodeStream(path) directly
(same shape as MeshNodeContentEditorControl) — no /data replica, no save
subscription.
- Fix role storage to the bare role id ("Editor") that the permission evaluator
resolves, and fix the role/subject node paths (`Role/{id}`,
`namespace:"" nodeType:User`).
- Update AccessAssignmentThumbnailTest and AccessControlLayoutAreaTest to the
new row/section structure and inline add row.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The anonymous gate emitted AccessDenied and relied on ApplicationPage's
<AuthorizeView><NotAuthorized><RedirectToLogin> render-chain to navigate —
which did not fire, leaving the logged-out visitor sitting on the page.
Redirect directly from NavigationService.ProcessResolvedPath instead:
NavigateTo("/login?returnUrl=<current absolute URL>", forceLoad: true). This is
unconditional, drops any half-built interactive circuit on the gated page, 302s
during prerender, and carries returnUrl so login bounces the visitor back. The
/login?returnUrl=… target is a page route (single segment + query) that
ProcessLocationChange short-circuits, so it cannot loop.
Tests updated: the two anonymous cases now assert the /login?returnUrl= redirect
(private + PublicRead) instead of the AccessDenied status. 38/38 green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Compatible provider, bootstrap + opt-in DevLogin
Enables running memex prod-like on a local k3s (Colima) self-host:
- memex-postgres: PVC (volumeClaimTemplates) instead of emptyDir so data survives pod restarts
- memex-portal: wait-for-postgres initContainer — fixes the portal-vs-pg startup race on fresh install
- memex-portal config: OpenAICompatible__{Endpoint,Models} (self-hosted OpenAI-wire gateways: Ollama/vLLM/LM Studio) + one-shot Bootstrap__Secret
- memex-portal secret: OpenAICompatible__ApiKey + Authentication__Microsoft__ClientSecret (conditional)
- Distributed Program.cs: honor Authentication__EnableDevLogin=true for local/self-host (prod default still forces it off)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…individually Spell out the MeshNodeStreamCache read-identity rule and the failure mode it prevents: the shared per-path upstream (and any per-path sync hub's BuildupAction) MUST open under System, never the ambient user. A leaked user identity (e.g. a co-active admin's session) gets RLS-evaluated against the node, and because it faults the SHARED stream/hub it goes FAILED and wedges the node for everyone including its owner (the 2026-06-23 atioz symptom: rbuergi leaked onto sglauser/_UserActivity/sglauser; the owner's activity page blanked until restart). Per-subscriber Read is validated at the GetStream seam (isolated to that subscriber, never faulting the upstream); writes are validated at the owning hub. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…user Grain activation reads the node (to learn its HubConfiguration) via the mesh-node cache, which captures the ambient AccessContext eagerly and applies its per-subscriber RLS gate. With two users active concurrently, a grain whose activation is triggered by user A's message reads user B's node under A -> "User 'A' lacks Read permission on 'B/...'" -> the activation faults -> the per-node hub goes FAILED and the node WEDGES for its owner (the 2026-06-23 atioz cross-user "boom": sglauser's submit faulted activation of rbuergi/_Thread/...). Wrap the activation read in ImpersonateAsSystem (via Defer so System is live when GetStreamRaw captures eagerly). The activated hub still enforces per-request RLS on the data it serves; only the activation read is System. STOPGAP scope: this is the framework activation-boundary half of a broader fix. The root is that infra seams read the singleton AccessService.Context AsyncLocal, which leaks across co-active users and is lost on Rx hops -- patched today by dozens of hand-woven ImpersonateAsSystem scopes. The durable fix is framework-level access-context forwarding (carry the established identity on every stream so seams never read the bare ambient), which subsumes this wrap. See MeshNodeStreamCache.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…skipped RED) Deterministic AccessService unit repro of the 2026-06-24 atioz "boom" root cause: AccessService.CircuitContext (AccessService.cs:69) falls back to the process-wide instance field persistentCircuitContext when the circuitContext AsyncLocal is null (any scheduler/Rx hop), and SetCircuitContext writes that shared field unconditionally (:104). So user B's circuit clobbers it globally and user A's hopped read observes B -> the wrong identity enters the infra read/post seams -> a shared hub faults -> wedge. Confirmed RED (Observed ObjectId='userB', 293ms). Skipped so it doesn't break the shared branch; un-skipped when Stage 5 of the AccessContext-forwarding plan removes the persistentCircuitContext fallback. See MeshNodeStreamCache.md + the plan. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The full-page thread hero (title, context link, modified-nodes summary, Mark Done) was emitted as a sibling above the chat control, so it sat outside the message scroll area and stayed pinned at the top. Render it as its own FullHeader layout area inside .thread-chat-messages (gated by ThreadChatControl.ShowFullHeader) so it scrolls away with the conversation — same pattern as the existing compact Header area. Side panel leaves the flag false, so its title still lives in the panel chrome. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an optional `ollama` Service (selector-less Service + manual Endpoints to the host gateway) so the portal addresses a host-native Ollama by a stable name (http://ollama:11434/v1) instead of a hardcoded host-gateway IP. On macOS the GPU is reachable only from host processes (Docker/k8s have no Metal passthrough), so Ollama runs on the host; the Service keeps GPU speed while giving a clean name. Gated on `ollama.external.enabled`, off by default so cloud deploys are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ead of swallowing The chat "screen disappears" on model-select/submit was a swallowed exception: the data-binding fault arms and the combobox/selection write only logged (Debug/Warning) and rendered an empty/default value, so the user saw a silent blank with no reason. - BlazorView.DataBind: both the node-bound and Stream-branch onError arms now call SurfaceError(ex, context) (PortalErrorModal + inline SurfacedError + Error log), while still rendering the default so the control draws instead of spinning. Every data-bound view now surfaces stream faults rather than blanking. - MeshNodeBindingExtensions.Write: add an optional onError callback (the static write helper lives in Mesh.Contract and can't reach the Blazor SurfaceError); BlazorView. UpdatePointer passes ex => SurfaceError(...) so a failed combobox/selection write (e.g. the ModelProviderSelection 42P01) pops a modal instead of silently dropping. SurfaceError suppresses teardown (ObjectDisposedException) and the PortalErrorModal drains one dialog at a time, so this surfaces real faults without a modal storm. Follow-ups: ThreadChatView's own swallow points, ModelProviderService.SetSelection (its .Catch erases the cause), and a generic activity-grain MarkActivityFailed helper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…erSelection cause Finishes the GUI error-surfacing sweep for the chat-disappear: stop swallowing the direct write/submit faults that BlazorView's data-binding surfacing doesn't cover. - ThreadChatView: OpenComposerProjection, WriteComposerSelection (the /model /agent write) and the submit onError now SurfaceError / PortalErrorSink.Report instead of LogDebug/LogWarning — a failed composer load, selection write, or submit pops a modal naming the cause instead of silently blanking / clearing the spinner. - ModelProviderService.SetSelection: its final .Catch collapsed every exception to a bare `false`, so the settings tab only ever showed a generic "Failed to update selection." Re-throw instead, so the caller's onError arm surfaces the real cause (e.g. the ModelProviderSelection 42P01). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nly) The ModelProvider node detail page rendered the generic property grid, which showed ApiKey and McpApiKey in PLAINTEXT — a leak of the platform's provider keys (the Anthropic key was visible on atioz). Mark both [Browsable(false)] (same mechanism already used for Models) so the generic editor drops them from both the Overview grid and the Edit form. The key is now write-only on the GUI: set via the masked Settings -> Models card; never displayed or read back. The value still serializes for the runtime factory + persistence. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nTool] check_inbox is a high-frequency mid-round poll, not a user action — surfacing "Calling check_inbox…" on every step is pure noise (and floods the Information logs). Mark such internal-plumbing tools with a new [HiddenTool] attribute, read the same way [ToolTimeout] is (via AIFunction.UnderlyingMethod), and have AgentChatClient drop the paired FunctionCall/FunctionResult before forwarding them to ThreadExecution. The tool still runs and its result still reaches the model — only the UI tool-call chrome + tool-activity logs are suppressed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…device GPU voice Unblocks the MacCatalyst/iOS build: the BlazorWebView portal dragged in the Microsoft.AspNetCore.App shared framework, which has no maccatalyst/ios runtime pack (NETSDK1082) — that's why the Windows app built but a Mac/iPhone one couldn't. Render mesh layout areas with native MAUI views instead; the control models + the layout-area streams are Blazor-agnostic and reused unchanged. - src/MeshWeaver.Maui: native view pack (MauiViewRegistry / MauiControlRenderer / MauiView+DataBind / LayoutAreaView / AddMaui), mirroring BlazorViewRegistry but producing Microsoft.Maui.Controls views. Container + Label/Button/Html/Markdown/ Icon/Progress/NamedArea (Wave 1). - Memex.Client: drop Blazor (Sdk.Razor→Sdk, remove the Blazor RCLs + WebView.Maui, delete Components/*.razor + MainPage + wwwroot), native shell (InstanceManagerPage), native VoicePage, MauiProgram uses AddMaui(). - On-device voice on the Mac GPU via CoreML (apple-gpu flag, default on for MacCatalyst). Swiss-German model packaged (q5_0 bin + CoreML encoder, gitignored, bundled as maccatalyst MauiAssets). Apple Intelligence text layer + a phone-safe file logger. - aspire AppHost: opt-in local LGTM observability + native-Ollama Qwen (MemexLocalStack). - Docs: OnDeviceVoice.md, MacLocalStack.md. Test: MauiViewDataPathTest (net10, runs in CI). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- MeshWeaver.Maui: FormMauiView base (two-way, echo-suppressed, writes back via UpdatePointer) + TextField/TextArea/CheckBox/Switch; DataGridControl → a native header+rows table (PropertyColumnControl-driven, JSON property extraction). - Memex.Client: LocalAreaPage renders a local layout area NATIVELY via the view pack's LayoutAreaView (proves the native portal path); a demo `home` area on the local hub; Home + Voice entries on the instance-manager shell. - test: MauiViewDataPathTest extended to assert the DataGrid data path (Columns + rows the DataGridView consumes). Green headless in CI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…, not a cross-partition fan-out
A nodeType:Thread query resolves to the `threads` SATELLITE; with no concrete
partition the cross-schema provider UNIONs that satellite across EVERY searchable
schema — an unbounded, all-partition scan that can wedge the portal (it dropped
the MCP transport mid-call). The user-home "Latest Threads" used exactly that
shape: `nodeType:Thread namespace:*/_Thread content.createdBy:{id}`.
Scope it to the viewer's OWN partition (derived from the layout area's hub
address, not the URL) as `nodeType:Thread namespace:{partition}/*_Thread`. That
form has a concrete first segment, so ResolvePinnedPartition pins it to the one
partition schema — the fan-out narrows to a single schema. Pure-logic test pins
the scoped-vs-fan-out routing decision (no PG fixture).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tles
The /model picker queried nodeType:LanguageModel|ModelProvider and rendered
EVERY node as a selectable button, so a provider ("Anthropic") was pickable —
and selecting it wrote a provider PATH into the model field (a non-model
selection, the "can't select a model" symptom).
Now ModelProvider nodes render as non-selectable group titles with their nested
models listed underneath. Models group under their provider (title first, then
models by Order/Name); keyboard nav (↑/↓/Enter) and the first-highlight skip
titles; term-filtering keeps a title only when one of its models survives. The
generic /agent and /harness pickers have no provider nodes, so they are
unchanged (flat, all selectable).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- MeshWeaver.Maui: BadgeControl → pill (Border+Label), NavLinkControl → Button, MenuItemControl → Label. - test: MauiViewDataPathTest asserts NavLink + Badge reach the views. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nder the whole thread BlazorView.OnParametersSet re-runs BindData on every parent re-render, and ThreadChatView passes a fresh MarkdownControl(text) for every message bubble on every streaming tick. So each tick re-ran Markdig for EVERY chat bubble — O(bubbles × ticks) server CPU that pegs the circuit and stutters/crashes Safari. Worse, a re-parse of identical markdown can emit fresh auto-generated element ids, making the SignalR diff non-empty for every unchanged bubble each tick (large frames Safari handles worst). Memoize the parse per MarkdownView instance: when (markdown, owner, nodePath) are unchanged, reuse the cached Html/CodeSubmissions instead of re-running Markdig. The actively streaming cell's text changes each tick, so it still re-parses correctly; every completed bubble becomes a no-op (identical Html → empty diff). App-wide fix, not chat-specific. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…bobox & display options The /search page (hit Enter from the top bar) now defaults to a google-like flat grid of node cards (title + description) ordered by relevance, up to 4 per row, instead of bucketing everything by NodeType. - Implement the previously no-op Flat render mode in MeshSearchView: one relevance-ordered group, no NodeType buckets. ApplySorting now preserves the query's Score-desc order (set by ClipMergedInitial) for flat text searches instead of re-sorting by Order/Name. - Add an opt-in discreet view-options bar (ShowViewOptions): a "Group by" combobox (None / Type / Namespace / Category) that re-buckets in place, plus a display menu to show/hide the search bar and section counts at runtime. - Search.razor defaults to Flat + 4 columns + view options; ?groupBy / ?mode overrides still work (top-bar groupBy=Namespace links unaffected). Opt-in, so the other MeshSearchView usages (catalogs, pickers, dashboards, node Search areas) are untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- MeshWeaver.Maui: SelectControl → MAUI Picker (reads the selected value, writes the chosen option's item back via UpdatePointer; literal options this wave). - test: MauiViewDataPathTest asserts Select reaches the views (round-trips cleanly). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The per-bubble live timer ticked purely on the cell's Status == "Streaming", and the 1s ticker stayed alive on messageStates.Any(Status == "Streaming"). If a cell's status lagged/stuck at "Streaming" after the round ended, the clock counted forever and the ticker re-rendered every second on an idle thread. Gate both on the authoritative signal: a cell can only be live-streaming while the THREAD is executing. The per-bubble live clock now requires IsExecuting; the ticker no longer keys off cell Status (covered by IsExecuting + sub-thread IsExecuting). When the thread becomes idle the clock freezes at CompletedAt (always stamped by the terminal completion push) and the ticker goes quiet. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ound boundary The mid-round check_inbox tool bridged a TaskCompletionSource onto the hub action-block scheduler to deliver queued messages inline — a hand-woven async gate, the exact shape the actor model deadlocks on, and the suspected cause of threads crashing / "the chat disappears" when follow-up messages arrive. Stop injecting the tool. Follow-ups typed during a round queue in PendingUserMessages and are ingested ONLY after the round finishes: ThreadSubmissionServer.InstallServerWatcher already observes Status == Idle with pending messages and dispatches the next round — race-free, serialized by the owning hub, no TCS gate. The [HiddenTool] filter stays (now a no-op) for any future internal tool. A better mid-round design (a reactive notification channel, no TCS) can come later. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pairs with disabling the mid-round inbox: instead of accepting a follow-up mid-round (which now only ingests after the round ends anyway), the composer's Send button is disabled while ThreadViewModel.IsExecuting, and SendMessage early-returns on the Enter-key path. The button title explains the wait and that Esc cancels. Submit re-enables the moment the thread goes idle. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r Key" button Replaces the generic node editor for ModelProvider (which leaked the ApiKey in plaintext and showed an Edit/Copy/Move/Delete button row, and whose /Edit route was broken) with a custom Overview+Edit area: just the editable endpoint URL (node-bound, auto-persisting) and an "Enter Key" button. The key is NEVER displayed — only SET via a masked password dialog. Save inlines RotateKey's logic (encrypt via IProviderKeyProtector + own-node stream.Update + force-persist SaveMeshNodeRequest) because ModelProviderService lives in a project MeshWeaver.AI can't reference; runs under the caller's identity (RLS-gated, no ImpersonateAsSystem). Both the detail page and /Edit now render this minimal form. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
77 commits of long-running work on
bug_fix— grouped by theme:MeshWeaver.Social+ LinkedIn publisher + scheduled publishing pipeline (engine/queue/stats), LinkedIn OAuth connect + past-post ingest in Memex portal, per-user linked-account menu items.#r "nuget:Pkg, Version"at the top of_Source/*.csresolves via public NuGet.Protocol without an SDK on the container. Same resolver serves interactive markdown code cells.FileSystemPersistenceService.MoveNodeAsyncruns per-descendantWriteAsync/DeleteAsyncthroughTask.WhenAll; newMeshOperationOptions(defaultTimeout = 30s) +WithMeshOperationTimeout(TimeSpan)override;HandleMoveNodeRequestchains.Timeout()on the persistence Observable so a stuck adapter can't hang the caller. Prod repro: DAV2026 subtree move that took 240 s and killed the MCP session — now bounded.CompilationCacheService,_Source/edit re-invalidates owning NodeType, cross-silo broadcast viaMeshChangeFeed, grain-dispose on node delete, live "Compiling … (Ns)" progress inLayoutAreaView.Category(falls back toNodeType), reactive Children catalog, self-as-default create location for non-NodeType nodes, sample orgs →Markdownfor search visibility.MeshChangeFeedevents, resubscribe on owner dispose,DeleteLayoutAreaemits a placeholder immediately and times out slow streams.IAsyncEnumerableaggregator fixes (satellite-safeGatherInputsAsync), xunit methodTimeout 30 s → 60 s, Anthropic Opus bump, icon generator, etc.New test suites (selected)
test/MeshWeaver.Persistence.Test/MoveNodeRecursiveTest.cs— 10 tests: recursion, parallelism, source missing / target exists / storage throws / cancellation (all must not hang), RxTimeout()contract, default-30s config.test/MeshWeaver.Social.Test/*—InMemoryPublishQueueTest,LinkedInPublisherEngagementTest,PostStatsRefresherTest,ScheduledPostPublisherTest,FakePublisher.test/MeshWeaver.Persistence.Test/WorkspaceCacheEvictionTest.cs,ResubscribeOnOwnerDisposeTest.cs,DeleteLayoutAreaIntegrationTest.cs.test/MeshWeaver.Markdown.Test/PathUtilsTest.cs,test/MeshWeaver.MathDemo.Test/MatrixViewsTest.cs.Contributors
dist/cleanup, fix: sample orgs invisible in search due to wrong NodeType #94 sample-org search-visibility fixUpstream already merged into this branch
refactor: reactive persistence — IMeshStorage writes return IObservable(merged)Test plan
dotnet buildsucceedsdotnet test test/MeshWeaver.Persistence.Test --filter MoveNodeRecursiveTest— 10/10 green (~8 s)dotnet test test/MeshWeaver.Hosting.Monolith.Test --filter MoveNodeAsync— 5/5 green (regression guard)dotnet test test/MeshWeaver.Social.Test— publish queue / scheduling / stats green_Source/*.csusing#r "nuget:MathNet.Numerics, 5.0.0"— compiles & renders (cold + warm cache)/social/connect/linkedin→ profile linked; menu shows connected accountScheduledPostPublisher→ LinkedIn publisher posts;PostStatsRefresherpulls stats🤖 Generated with Claude Code