Skip to content

Releases

v0.2.5 - the fleet's canonical wire bytes

Choose a tag to compare

@emiltsoi emiltsoi released this 24 Sep 04:04

0.2.5 - the fleet's canonical wire bytes

Our envelopes were structurally right and byte-wise wrong.

The wrap was built with JSON.stringify, which omits Python's spaces after : and , and does
not ASCII-escape above 0x7e - while the fleet's sender is:

wire_body = json.dumps({"from": sender, "text": body}, sort_keys=True)   # session_relay.py L362

Nobody noticed because a receiver verifies the signature over the bytes it received and never
re-serializes
- so a sender only has to be self-consistent. It bites a peer that does
re-serialize, which is exactly what that line's docstring names ("diploid-mesh and other Phase-5
peers"). A real, invisible gap: the worst combination.

pyjson.mjs

A Python-compatible encoder - spaced separators, ensure_ascii with lowercase hex, astral
characters as surrogate pairs, short escapes for \b \f \n \r \t, / left unescaped.

It is asserted byte-for-byte against 13 vectors generated by Python 3.14 itself - not written
by hand, because a vector I wrote would encode my own misunderstanding. The vectors are stored as
hex, since a JSON file cannot carry \u2014 through a parse without decoding it.

And the receiver now accepts both forms

It required the wrap and would 400 a bare envelope - which meant this plugin, sending raw, could
not have received from a copy of itself.

One test was too weak, and that is the lesson

mesh.test.mjs asserted "sort_keys parity with the sender" by checking key order and
expecting the compact form. The intent was exactly right; the check was too weak to catch the
thing it was named for, and it passed for as long as it existed.

216 assertions across five suites, green on Node 20, 22 and 24.

v0.2.4 - the tools teach their own use

Choose a tag to compare

@emiltsoi emiltsoi released this 23 Sep 05:32

0.2.4 - the tool descriptions teach their own use

Guidance belongs in the artifact, not in the agent's memory. Memory is per-agent and drifts;
a tool description travels with the tool and sits at the exact point of use.

mesh_send now opens with what it actually is: the live channel - it starts a turn in the
recipient's session, it is a prompt rather than a notification, durable mail is a file in your own
vault outbox, and delivered does not mean she read it, because no read receipt exists anywhere
in this system.

mesh_register now says the registry is discovery only and not on the verification path - the
mistake that cost a 401 on this plugin's first real send. mesh_list and mesh_sync carry the same
distinction from their side.

Written the day after filing a letter and reporting it as sent.

v0.2.3 - schema-complete mesh messages

Choose a tag to compare

@emiltsoi emiltsoi released this 22 Sep 15:46

0.2.3 - supersedes 0.2.2

0.2.2 could write an event that bricks a session. A mesh delivery was built as:

const message = createUserMessage({
  content: [...],
  source: { kind: 'plugin', plugin: 'dsh-fleet-mesh', form: 'mesh-receive' },
});

createUserMessage is (input) => createMessage({ ...input, role: 'user' }) - one word. When
@deepseek-ai/dsh-llm could not be resolved (a link:ed plugin resolves from its realpath, so
the walk-up never reaches profiles\node_modules), the identity fallback returned the object
without that word.

The append path does not validate. The restore path does: assertMessageEventShape rejects a
user/message whose message lacks role: "user". So the event persisted silently and the whole
session log refused to open - one event out of 14,546.

The fix. role and id are written at the construction site; createUserMessage is now an
enhancement rather than a requirement, so nothing depends on it resolving. @deepseek-ai/dsh-llm
also resolves through the anchored coreModuleUrl - the same realpath problem loadDefineTool
already solved for dsh-tools, one line away. That is the real lesson: a fix applied to one
instance is not a fix.

Tests. The delivered message carries role + id, AND the delivery path is schema-complete
with no helper at all - the assertion that would have caught this.

185 assertions across four suites, green on Node 20, 22 and 24.

v0.2.2 - resolve the core from the profile tree

Choose a tag to compare

@emiltsoi emiltsoi released this 22 Sep 13:50

0.2.2 - supersedes 0.2.1

0.2.1 loaded, but its tools never registered. import('@deepseek-ai/dsh-tools') failed with
ERR_MODULE_NOT_FOUND:

A link:ed plugin resolves from its realpath, so it sits outside the profile's node_modules
walk. From harness\plugins\dsh-fleet-mesh Node climbs through harness\plugins and harness
and never reaches harness\profiles, where the core actually lives. A normally installed plugin
under profiles\web\node_modules\<name> does reach profiles\node_modules - which is why every
other plugin in the profile can import the core and this one could not.

loadDefineTool now tries the ordinary specifier first, then resolves it with a require anchored
inside the profile tree. Verified from the plugin directory: the bare specifier fails with
ERR_MODULE_NOT_FOUND and the fallback returns a real defineTool.

180 assertions across four suites, green on Node 20, 22 and 24 - including both the
core-present and core-absent paths, since the strong assertion is guarded on a probe of the
core's location rather than on the outcome.

v0.2.1 - fix the load failure

Choose a tag to compare

@emiltsoi emiltsoi released this 22 Sep 13:28

0.2.1 - supersedes 0.2.0

0.2.0 could not load. It read ctx.tools and ctx.agents without declaring them in
inject, and Cordis's context proxy throws on an undeclared service
(cannot get property "tools" without inject) - so the plugin failed to apply and the
harness's plugin recovery removed it from the profile entirely.

inject: ['tools', 'agents'] now declares both, and they are read as plain properties.

Why the test suite did not catch it

Every stub was a plain object, so an unknown property returned undefined; the real context
throws. There was even a test named "apply() with no tools service does not throw" that passed
against the stub and was false against Cordis.

The round-trip stub is now a Proxy that throws exactly as Cordis does, and there is a direct
regression guard asserting the plugin declares every service it reads.

179 assertions across four suites, green on Node 20, 22 and 24.

v0.2.0 - the tool surface

Choose a tag to compare

@emiltsoi emiltsoi released this 22 Sep 12:56

The five agent-facing tools

mesh_list, mesh_send, mesh_sync, mesh_register, mesh_deregister - named exactly as
hermes-mesh names hers, so muscle memory transfers between substrates. Each is a thin adapter
over libraries written and tested first: envelope signing, delivery with a shared retry budget,
the peer directory, and a registry client.

What the round trip proves

A suite stands up this plugin's own receive handler on a loopback port, a real identity
store in a temp directory, and a stub registry that verifies the registration signature
rather than accepting it - then drives all five tools through it. The envelope is signed for
real, POSTed over a real socket, verified against a real public key, and delivered to a real
handler. Nothing is mocked at the boundary that matters.

It also covers the wiring: that five descriptors reach the harness, and that a missing tools
service or an unresolvable core import warns without taking the receive route down.

181 assertions across four suites, green on Node 20, 22 and 24.

Also here

  • engines.dsh declared, so plugin discovery can read compatibility from the manifest
  • README documents the delivery matrix, the envelope grammar, and the traps worth knowing
  • Publishing runs on OIDC trusted publishing - no npm token anywhere to rotate or leak

Deliberately not here

No outbound spool: a send either lands or fails informatively. No thread ledger yet. And never
session.cancel for mesh traffic.


Re-cut at 92ec7b7: the first v0.2.0 predated the wiring tests, and 0.2.0 was never
published - an npm trusted-publisher permission blocked it - so re-pointing the tag supersedes
nothing.