本文へ移動
cccskills
無料GitHub で公開

mesh-data

Read and write mesh data correctly — the ONE mutation API (GetMeshNodeStream(path).Update), the CQRS read rules (never query for a single node content), the object-payload accessors (.As / .ContentAs instead of a cast), and the Postgres one-schema-per-partition layout. Use whenever code creates, reads, updates, moves or deletes a mesh node, waits for a node to reach a state, reads a payload that crossed a hub boundary, or touches partition schemas. The three bugs this prevents are all SILENT: a bespoke request/response that races the watcher and wedges a hub, a stale query answer that decides a write, and a cast that yields null because the value arrived as JSON.

日本語の概要は準備中です。原文の説明を表示しています。

Systemorph/MeshWeaverスター 12(GitHub 12 + cccskills 0)
連携ツールPostgreSQL

実行スコア 未検証

インストール方法を見る

含まれるファイル(1)

  • SKILL.md27.2 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

/mesh-data — one write API, one read API, and never cast a payload

Three rules, and every silent data bug on this mesh is a violation of one of them:

  1. Write through workspace.GetMeshNodeStream(path).Update(...) and nothing else.
  2. Read a specific node's content from its stream, never from a query.
  3. Convert an object/Content payload with .As<T>() / .ContentAs<T>(), never with as / is.

Canonical references:

1. GetMeshNodeStream().Update() is the ONLY mutation API

Every mesh-node mutation goes through workspace.GetMeshNodeStream(path).Update(current => modified). There is no other mutation surface — do NOT invent one: no SubmitMessageRequest-style wire messages, no completion callbacks via hub.Set<Action<...>>, no bespoke IRequest/IResponse pairs for state changes. Migrate any straggler you touch to stream.Update.

Sanctioned exceptions (NOT for state mutations):

  • CreateNodeRequest / DeleteNodeRequest / MoveNodeRequest — node lifecycle on the mesh hub. These route; they don't mutate node content.
  • Transient queries that don't belong on any node (e.g. autocomplete completions).

Why this unblocks tests: every "hub becomes unresponsive after the second compile" failure (CodeEditRecompile, NodeTypeRelease, LinkedInPullActions, ThreadAgentIntegration in CI 26036857424) traces back to bespoke request/response patterns that race the watcher → two concurrent activities → leaked callbacks → wedged hub.

Own node and external node — same API

workspace.GetMeshNodeStream(path) returns a handle that auto-dispatches:

  • path == my-hub's-address: writes go through the local data source (UpdateOwn).
  • path != my-hub's-address: writes route to the owning per-node hub via the process-wide IMeshNodeStreamCache, which opens a sync subscription + posts a JSON-merge PatchDataRequest (RFC 7396) to that hub. The owner serialises every mirror's write through its single-threaded action block — no race, no clobber.
// Own node (this hub) — Update is COLD: the trailing Subscribe runs the write.
workspace.GetMeshNodeStream().Update(node => node with { Content = ... })
    .Subscribe(_ => { }, ex => logger.LogWarning(ex, "update failed"));

// External node (anywhere in the mesh — same API):
workspace.GetMeshNodeStream(otherPath).Update(node => node with { Content = ... })
    .Subscribe(_ => { }, ex => logger.LogWarning(ex, "update failed"));

The remote variant returns the locally-computed updated snapshot optimistically; if you need the owner's reconciled state, take the next emission off the same GetMeshNodeStream(path) handle.

Eventual-consistency safe: cross-hub stream.Update does NOT send the whole node back. It diffs current vs update(current) and sends only the RFC 7396 JSON-merge patch. The owner merges the patch against its CURRENT state, so concurrent writers from different mirrors don't clobber each other's fields (Mirror A's {Content: {Field1: X}} and Mirror B's {Content: {Field2: Y}} both land — never "last write wins on whole node"). Treat your update lambda accordingly: touch only the fields you intend to change.

How the change is EXPRESSED — four shapes, and the context picks

stream.Update settles where the write goes. How you say what changed is a second decision with four answers, and picking the wrong one is how a write silently reverts a field or loses a count. Full design: ExpressingAWrite.md.

ShapeUse it whenTrap
1. C# lambda live => live with { … }in-process, defaultcan't cross a wire as a delegate
2. JSON Patch (+ anchored text splice)over MCP / CLI / a webhookcan't express a fold
3. Full entityyou are the SOLE authority — one-way sync source, or the buffer IS the contentevery field you omit is still WRITTEN
4. Other—not a category; it means shape 1 or 2 has a gap. File it

The two rules that actually bite:

🚨 A fold must be computed against the LIVE node, inside the lambda — never from a prior read. count + 1 where count came from a read is a lost update the moment a second writer exists. The in-process shape is the one that gets this right:

// ✅ the fold happens inside the owner-serialised lambda (RegistrationKeyService.cs:131)
stream.Update(current => current with { Content = key with { UsageCount = key.UsageCount + 1 } })

🚨 A text edit inside a long body is a SPLICE, and the splice is ANCHORED, never positional. Re-emitting a whole markdown/code document to change one line costs tokens and truncates; an offset or (row, column) is stale the moment anyone inserts a character above it and lands in the wrong place without erroring — the one silent-corruption shape here. Use the anchored form (MeshOperations.EditContent: exact oldText → newText, re-verified against live text). A positional splice is legal only carrying a base fingerprint the owner checks.

Create-if-missing plus a fold: use CreateOrUpdateNodeRequest.WithFolds<T> (#4980). The create leg uses the seed verbatim; the update leg applies Sum, KeepExisting, Min or Max to the live stored content. Carry the rule and operand, never a result computed from a query. HandleTrackActivity is the caller example: seed count one, Sum(1) thereafter, preserve first-access time, advance last-access time. This retires #1174's query-dependent create/update split. Folds retain the existing cross-mirror patch conflict semantics; they do not promise cluster-wide atomic arithmetic.

The 3 rules this unifies

  1. Writes: stream.Update(current => current with { Content = ... }). The owning hub's action block serialises; no race. State-machine semantics? Set a RequestedX field — the owning hub's watcher reacts (see ActivityControlPlane.md).
  2. Reads: workspace.GetMeshNodeStream(path) / Hub.GetMeshNodeStream(path) — server-side AND Blazor, backed by the process-wide IMeshNodeStreamCache (one shared handle per path). GetRemoteStream<MeshNode, …> is framework plumbing — never use it for a node by path. Never query for a single node's content (stale by design — section 2).
  3. Delete the request type. If you find yourself writing class XxxRequest to mutate a thread / message / NodeType, stop. Add a RequestedXxx field to the node's content and watch it from the owning hub.

Observing completion

Subscribe to workspace.GetMeshNodeStream(path) and wait for the relevant state on the node's Content (e.g. MeshThread.Messages.Count >= 2, RequestedStatus = Cancelled, Status = Completed). The GUI databinds the same way; tests do too.

Tests: any test that posts a verb-shaped request and waits for a response shape (*Request → *Response) is testing a deprecated API. Migrate to: write via stream.Update, observe via GetMeshNodeStream(path).Where(node => predicate).FirstAsync().Timeout(...).

Application code uses only stream.Update. Internal plumbing that stream.Update itself uses (PatchDataRequest for cross-hub writes, DataChangedEvent for stream fan-out) is fine where it already exists — but you never hub.Post(PatchDataRequest, ...) from application code. If you find yourself doing that, you're bypassing the API.

Thread submissions — the complete surface

Thread operations go through the canonical IMessageHub extensions in MeshWeaver.Plugins/src/MeshWeaver.AI/HubThreadExtensions.cs (the AI engine lives in the plugins repo, #2276):

hub.StartThread(namespacePath, userText, agentName: ..., contextPath: ..., onCreated: ..., onError: ...);
hub.SubmitMessage(threadPath, userText, agentName: ..., contextPath: ...);
hub.ResubmitMessage(threadPath, userMessageId, newUserText: ...);
hub.DeleteFromMessage(threadPath, atMessageId);
hub.MarkThreadDone(threadPath, done);
hub.RecordSubmissionFailure(threadPath, userMessageId, userText, errorMessage);

Every method writes the thread node via hub.GetWorkspace().GetMeshNodeStream(threadPath).Update(...) (or CreateNodeRequest for new-thread lifecycle). The per-thread submission watcher reacts to the resulting state changes, drains PendingUserMessages into Messages, allocates cells, and invokes ThreadExecution.ExecuteMessageAsync(execHub, RoundParams, AccessContext?) directly as a method — no message dispatch. It returns IObservable<Unit>; the watcher subscribes and treats completion (gated on the terminal Status write) as round-done. Tests, GUI, and agents all call these extensions — this is the complete submission surface; there is no other entry point. No wrapper class, no path→id resolution, no create-or-submit logic beyond those APIs; pass node PATHS through and let downstream load the node.

Completion: an agent reaching terminal state writes Status = Completed/Cancelled/Error to the response cell via PushToResponseMessage(...) (stream.Update), AND creates a Notification MeshNode satellite at {threadPath}/_Notification/{id} via EmitCompletionNotification. The user's notification bell databinds to this — the same source the tests assert on. Query shape: path:{threadPath}/_Notification scope:children nodeType:Notification (filter by nodeType for robustness when other satellite types live under the thread).

Full reference: ThreadOperations.md.

Activity operations

src/MeshWeaver.Mesh.Contract/HubActivityExtensions.cs:

hub.CancelActivity(activityPath);                                  // RequestedStatus = Cancelled
hub.RequestActivityStatus(activityPath, ActivityStatus.Running);   // generic flip

Both write the activity node via GetMeshNodeStream(activityPath).Update(...); the activity hub's WatchControlPlane subscription reacts. Full reference: ActivityOperations.md.

Per-user work at logon — a LogonAction, never a SQL backfill

When an EXISTING user needs something a new user gets, declare a logon action — do NOT write an IMigration that loops partition schemas patching mesh_nodes. INodePostCreationHandler fires once at account creation and can never fire again, which is why V29_PinDocsForExistingUsers and V33_SeedChatInputForExistingUsers exist; those raw UPDATEs bypass the workspace cache, run once per DEPLOYMENT rather than per user, and only someone shipping a DbVersion bump can write one.

  • Two modes. RunOnce (a migration; ledger = User.CompletedLogonActions[id], durable and replicated) or EveryLogon (a repair that must keep catching new work — and which MUST carry a cheap "nothing to do" check, or it is a per-logon storm).
  • Idempotency is the effect and the ledger entry in ONE stream.Update patch on the user's profile, with the ledger check inside the lambda so a rebased patch re-reads it and no-ops.
  • It runs as the USER — access.RunAs(identity, …). 🚨 Never Observable.Using(() => access.ImpersonateAsSystem(), …): store and restore land on different threads and the subscriber stays latched (a ratchet-guard test fails the build at any new site).
  • Deployment-specific work is DATA — a LogonAction node at Admin/_LogonAction/{id}. Zero action nodes ship, and pin targets are existence-checked, so a portal without the content pins nothing instead of writing a dangling path.

Full reference: LogonActions.md · the /logon-action skill (a Skill node shipped by the AI engine in MeshWeaver.Plugins).

🚨 CONTENT is live; the hub's BINDING is not — the grain serves old state until a DisposeRequest

"The grain keeps serving old state until we send a dispose request" (maintainer, 2026-09-17), and the line between the two halves is exactly the line this skill draws.

Live, by construction: everything stream.Update writes. The patch routes to the owning activation, which applies it on its own turn and publishes it to every mirror, and MeshDataSource holds a long-standing own-node subscription — activation only seeds the workspace. So no read, no view and no test ever needs a recycle to see a write. If you are reaching for a recycle to make a write visible, the bug is the write (an unsubscribed cold observable, a query used where a stream was needed), not the activation.

Pinned for the activation's lifetime, and re-read by nothing: the HubConfiguration the hub was born with — its NodeType binding, the compiled assembly and collectible load context that closure captured, the streams it composed — plus anything read from outside the mesh. Routing short-circuits on an already-hosted address and never resolves the path again, so a node that changes its type, or a NodeType that publishes a new build, reaches a live instance through nothing at all. The framework's own words: "the hub keeps serving the configuration it was born with for the rest of its lifetime" (NodeTypeRebindWatcher, #1104).

The one surface that makes an activation re-read is hub.RecycleNode(path, reason: "…") — cold (posts on Subscribe), the wait is the framework's own READ rather than a poll, and it defers while a package install holds that root. It is dispose-only: it requests no compile. The caller's hub must OUTLIVE the target (and must not be the root hub, whose dispose and read leave different off-router hubs, so the read can overtake the teardown). As an operator it is the recycle verb (MCP tool / Recycle menu entry / mw recycle), which additionally checks Update and — only when the target is a NodeType node — stamps a FORCED release request before the dispose, the one trigger that skips prebuilt adoption and compiles the live source (#2818). Always carry a Reason.

🚨 A dispose makes the activation RE-READ; it does not decide what the re-read FINDS, so it is never itself a fix and a second recycle proves nothing the first did not. Full reference: StaleStateUntilRecycle.md.

The data-access table

Never use IMeshStorage or IMeshCatalog directly — internal infrastructure only.

OperationAPI
Read (query)IMeshService.Query<T>(request) — reactive. 🚨 There is no QueryAsync on the production interface; it survives only as a test-only bridge in MeshWeaver.Fixture. One-shot snapshot = .Where(c => c.ChangeType == QueryChangeType.Initial).Select(c => c.Items).FirstAsync()
Read (single node)workspace.GetMeshNodeStream(path)
Create/DeletemeshService.CreateNode(node).Subscribe(...) / meshService.DeleteNode(path).Subscribe(...)
Updateworkspace.GetMeshNodeStream(path).Update(current => current with { … })
Movehub.Observe(new MoveNodeRequest(src, dst)).Subscribe(...)

Always GetRequiredService<T>() — never GetService<T>() + null check for required services.

Identity on writes: every framework write primitive carries the caller's AccessContext through .Subscribe() boundaries — see /async Rule 2 for when you must re-establish it.

2. CQRS — never query for a single node's content

Query/ObserveQuery are eventually consistent — stale after writes. To read a specific node:

// ❌ WRONG — lagged index, stale after writes
var node = await mesh.QueryAsync<MeshNode>($"path:{path}").FirstOrDefaultAsync();

// ✅ CORRECT — authoritative, live (shared IMeshNodeStreamCache handle)
workspace.GetMeshNodeStream(path)
    .Where(node => node is not null)
    .Take(1).Timeout(TimeSpan.FromSeconds(10));

Valid query uses: listing children (path/*), searching by predicate, autocomplete — anywhere a stale negative is harmless.

🚨 Existence of a SPECIFIC path is NOT one of them — use GetMeshNodeStream(path) / a direct read. A query's negative can be minutes old, so a caller that reads it as "absent" redoes work that already happened. This guidance used to sanction existence checks, and that was wrong in a way that shipped: on 2026-08-25 a search reported two just-minted tiles missing while a direct get returned both (#2229), and a create whose reply was lost plus a query that then answered "absent" gave one caller two independent reasons to conclude nothing had happened — two mesh-wide sweeps were armed 40 seconds apart on that basis. Existence-by-query is safe only where the write it guards is path-deterministic and idempotent (the redundant write lands on the same path); where the target id is minted per attempt, a stale negative produces DUPLICATE DATA, not merely duplicated work.

Wrong: reading content by exact path, reading state before a write, polling for job completion, deciding create-or-skip for a known path.

GetMeshNodeStream(path) + Where(...).Take(1) is also the right primitive for waiting for work to finish — for a node that exists.

A node that may NOT EXIST YET — the one case needing both halves

Neither half is enough on its own, and each half alone is a defect that has shipped. Do not pick a horn:

  • A point read of an ABSENT node is forbidden by the framework, not merely slow: the owner answers an authoritative routing NotFound which terminates the stream with an error (it cannot wait for the node to appear), and that NotFound opens MeshNodeStreamCache's storm-breaker window on the path — and the breaker fast-fails WRITES too, so the read suppresses the write it is waiting for. The breaker says so itself: "A point node-access to a node that does not exist is a defect — read optional nodes via GetQuery (empty-on-absent), not GetMeshNodeStream(exactPath)."
  • Reading that node's CONTENT out of a query is forbidden above — unbounded lag.

The composition, and it is the canonical pattern — listing for EXISTENCE, stream for CONTENT:

hub.GetQuery(id, $"path:{parent} scope:children nodeType:X select:path")   // EXISTENCE — empty-on-absent
    .Where(nodes => nodes.Any(n => string.Equals(n.Path, target, StringComparison.OrdinalIgnoreCase)))
    .Take(1)
    .SelectMany(_ => workspace.GetMeshNodeStream(target))                  // CONTENT — authoritative, live
    .Select(node => node.ContentAs<X>(hub.JsonSerializerOptions));

An index row can still be stale after deletion or failed hydration: "the index has seen it" is not proof that storage currently holds it. A query can gate discovery, but the subsequent point read must still handle absence. Creating the node anyway? Skip the check entirely and use CreateOrUpdateNodeRequest. For a counter bump or another live-content fold, attach WithFolds<T> rules to the seed instead of deciding create-vs-update from the query.

🚨 This is about ONE known path whose value you are GATING on — not about node counts. The worked counter-example is a token chip that reads content out of a {thread}/_Usage scope:children query, and it is correct — it sums a SET to paint a total, and a briefly-stale total is cosmetic. Converting it to N point reads would mean N per-node hub activations per render, and on a legitimately EMPTY set (a thread with no rounds yet) every one is an absent-node read tripping the breaker on the render path. So: stale answer merely looks wrong on screen → query, content and all. Stale answer DECIDES whether something proceeds, passes, or is written → the owner's stream. Full pattern: CqrsAndContentAccess.md → "An OPTIONAL node".

Free-floating words → vector search. When a query contains bare text tokens (laptop nodeType:Story) AND PG is the backend AND an IEmbeddingProvider is registered, PostgreSqlMeshQuery.QueryAsync automatically routes through the HNSW cosine index instead of an ILIKE substring scan. Structured-only queries (nodeType:Story namespace:ACME) stay on the regular SQL path. Full reference: VectorSearch.md.

3. Never cast an object payload

node.Content is MyType / payload as MyType is a TRAP-DOOR. It is correct only when the value already happens to be your CLR type, and yields a silent null in the three cases that actually happen in a running mesh:

  1. Untyped JSON — the polymorphic converter DEGRADES an unresolvable $type to a raw JsonElement instead of throwing, so any hub whose TypeRegistry lacks the discriminator hands you JSON, not an instance.
  2. The as-written DOM — application code builds content as JsonObject, and a change notification forwards that shape verbatim until the materialization pipeline re-types it.
  3. A same-named type from another assembly — every recompile of a dynamic NodeType mints a new collectible assembly, so "the same" record has a different CLR identity per build.

Every one of these has caused a production outage, and they all look identical from outside: the value reads as absent, the view renders empty, a reactive wait never completes. No exception, no log, nothing to grep.

// ❌ the trap-door
var store = node.Content as StoreContent;
if (delivery.Message.Payload is MySettings s) { … }

// ✅ bad-data tolerant, and it says why when it cannot convert
var store = node.ContentAs<StoreContent>(hub.JsonSerializerOptions);
var s = delivery.Message.Payload.As<MySettings>(hub.JsonSerializerOptions, logger);

ContentAs<T> is As<T> with the node's path in the diagnostics. Both recover a degraded JsonElement/JsonNode, recover a SAME-short-named type from another build by JSON round-trip, and return null for a DIFFERENTLY-named type so probe-dispatch call sites keep working.

🚨 FIRST, though: deserialize as close as possible to where the type IS registered — which usually means the RIGHT HUB should be handling it at all. A $type resolves against the TypeRegistry behind the options you pass, so a payload read on a hub that never registered the type is untyped by construction, and .As<T>() is then papering over a routing mistake rather than bad data. The durable fix for a repeated degradation is to move the work to the owning hub (the per-node hub for its own content; the hub that declares the type via WithType) — or to register the type where the read happens. Reach for the accessor at genuine boundaries: a cross-hub query result, a control payload, storage JSON.

type 'X' is not registered in this hub's TypeRegistry → the fix is WithType(typeof(X), nameof(X)) on the receiving hub. See DebuggingMessageFlow.md → "Type-registry mismatch".

4. Postgres: one schema per partition

public.mesh_nodes is empty by design. Data lives in per-partition schemas (acme.mesh_nodes, rbuergi.mesh_nodes, …).

Satellite table routing by path segment:

Path segmentTable
…/_Access/…access
…/_Thread/…threads
…/_Activity/…activities
…/_Comment/…, _Approval, _Trackingannotations
…/Source/… or …/Test/…code
(none)mesh_nodes

namespace keeps the partition prefix — never strip it. namespace = rbuergi/ApiToken, not ApiToken.

Never run raw psql UPDATE on a live portal — it bypasses the workspace cache. Use MoveNodeRequest or add a Repair vN migration. If you must SQL-edit, restart the portal process.

🚨 Partition schema: provision + existence are REACTIVE + POOLED — never declare a PartitionDefinition node to force a schema, never lowercase by hand. The standard surface is on IPartitionStorageProvider:

  • EnsurePartitionProvisioned(namespace) : IObservable<Unit> — the ONE entry point that creates a partition's schema + tables. Reactive, idempotent (promise-cached), and pooled on the pg:{adapter} IoPool (the PG impl lowercases the schema correctly). Subscribe it; compose with .SelectMany(_ => write…) before writing to a not-yet-provisioned partition.
  • PartitionExists(namespace) : IObservable<bool?> — reactive existence check (null = indeterminate; OR-fold across providers as PartitionWriteGuardValidator does).

The router maps a path's first segment to seg.ToLowerInvariant(); a PartitionDefinition with Schema left null provisions the schema verbatim ("Agent" capital) while writes hit "agent" → 42P01. So the way to make code that writes a not-yet-provisioned partition work is EnsurePartitionProvisioned(p).SelectMany(_ => write…) — not a partition-def node. The async schema DDL runs inside the IoPool, never Observable.FromAsync (see /async).

Full reference: PostgresSchemaArchitecture.md.

Checklist

  • Every mutation is GetMeshNodeStream(path).Update(...) — no new *Request/*Response pair for a state change.
  • Every cold write observable is .Subscribe(onNext, onError)d.
  • No Query/search used to read one node's content, decide a write, or poll for completion.
  • Node-may-not-exist waits use the listing-then-stream composition, not a bare point read.
  • No as/is on a Content/Payload — .ContentAs<T>() / .As<T>() with the hub's JsonSerializerOptions.
  • Writes to a fresh partition are gated on EnsurePartitionProvisioned.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

コメント

ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。

まだコメントはありません。最初のコメントを書いてみませんか。

送信するとすぐに公開されます。メールアドレスや電話番号などの個人情報は書かないでください。URL は 2 つまでです。

0 / 1000 文字

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

同じリポジトリのスキル

async

無料

Forwarding AccessContext through async/reactive boundaries, and the no-async rule on the actor-model mesh. Use when writing or reviewing any hub-reachable / Blazor-view / agent-round / IIoPool code that creates, reads, or updates a mesh node, OR when a write "silently does nothing" / "Access denied" appears after a .Subscribe / IIoPool / Observable.Create hop. The async/await/ToTask/.Wait/.Result/.GetAwaiter/FirstAsync family and lost AccessContext are the two ways async boundaries cause wedges and storms. Grounded in AsynchronousCalls.md, SyncedMeshNodeQueries.md, AccessContextPropagation.md.

日本語の概要は準備中です。原文の説明を表示しています。

Systemorph/MeshWeaver122026年10月29日 更新

ci

無料

What CI proves, what it cannot prove, and how to write a gate that cannot pass on no evidence. Use when authoring or changing a GitHub Actions workflow, adding a required check, wiring a satellite repo CI, or reasoning about whether a green run actually covers your change. Covers the absolute no-skip-trapdoor rule (a gate must never carry continue-on-error on its input step nor an if that asks whether a secret is set — GitHub paints a skipped job the same colour as a passed one), the reusable workflow_call jobs satellite repos must call instead of hand-rolling, why runs on main are deliberately never cancelled, and the large body of in-mesh C# that no dotnet build or test ever type-checks.

日本語の概要は準備中です。原文の説明を表示しています。

Systemorph/MeshWeaver122026年10月29日 更新

debug

無料

Debug a deadlock / hang / timeout in the mesh — a test that times out, a hub handler whose response never arrives, a GetRemoteStream / GetMeshNodeStream / GetQuery that never emits, an agent round or per-instance-hub activation that parks forever. Use whenever something times out and you need to find WHERE the message flow breaks down. The timeout is the symptom, never the bug — raising it just hangs longer. Grounded in DebuggingMessageFlow.md.

日本語の概要は準備中です。原文の説明を表示しています。

Systemorph/MeshWeaver122026年10月29日 更新

Remove / reset a user (and their partition) on a running MeshWeaver portal (AKS). Use when you need to kick out a user — e.g. a throwaway test account — so they re-onboard from scratch. The normal delete API REFUSES a user's home ("user partition root … cannot be deleted"), so deletion is a Postgres-schema drop, not an MCP call. Covers where a user's data actually lives (per-user PG schemas named by BOTH id AND email, e.g. `rbuergi` + `rbuergi@systemorph.com`), how to reach PG (the connection string is inline in the portal's `ConnectionStrings__memex` env — NOT the `POSTGRES_PASSWORD` secret), the substring-match footgun (`buergi` also matches admin `rbuergi`), the in-memory resurrection gotcha (a recycle re-saves the node — a portal restart is what actually clears it), and the half-onboarded case where the user has NO schema at all (in-memory only → restart is the whole fix).

日本語の概要は準備中です。原文の説明を表示しています。

Systemorph/MeshWeaver122026年10月29日 更新

deploy

無料

Deploy MeshWeaver — the two routes (shared AKS cluster, and Azure Container Apps via the Aspire test/prod modes) and the traps that make a deploy look done when it is not. Use when rolling a code change onto a portal, standing up or patching an environment, or verifying that what is running is what you built. FIRST RULE (maintainer, 2026-09-08): on AKS an operation is a Hosting/InstanceAction on the control instance (Roll, Restart, Suspend, Audit, Reconcile, …) executed by the in-cluster operator — az aks command invoke / kubectl are break-glass, never the procedure. Also covers the bootstrap build-image / set-image / restart sequence the operator runs for you, why an env deploy.sh is first-time setup and not a code-update path, why the database migration is a run-once Job that a helm upgrade runs — never a Deployment to roll — and the DbVersionGate that makes a portal refuse to serve ahead of its schema.

日本語の概要は準備中です。原文の説明を表示しています。

Systemorph/MeshWeaver122026年10月29日 更新

gui

無料

Build or review ANY MeshWeaver UI — layout areas, editable views, forms, tables, content editing, side-panel composers — by wiring the framework's EXISTING data-binding pieces, NEVER hand-rolling. The one rule is ALWAYS DATA-BIND, especially editable views: the backend layout area declares WHAT to render (a UiControl tree + node PATHS), and every value read / write-back happens on the GUI side through the per-node IMeshNodeStreamCache. Hand-woven binding — replicating a node into a /data/{id} copy + a save subscription, emitting HTML strings, hand-built selects/checkboxes, .Take(1) on a live stream, async/await/QueryAsync in a layout area — is the bug class behind "awaiting first data" / "renders empty" / a stuck editable view. Use when writing or reviewing a layout area, control, editor, form, table, or any data-bound view. Grounded in src/MeshWeaver.Layout/DataBinding/, Doc/GUI/DataBinding.md + Editor.md, the Edit extension (EditorExtensions.cs), and the node-bound editor controls.

日本語の概要は準備中です。原文の説明を表示しています。

Systemorph/MeshWeaver122026年10月29日 更新

Systemorph のスキルをすべて見る

このスキルの問題を報告する