relay-dsh-plugin-events 0.1.0-internal.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +28 -0
- package/SPEC.md +82 -0
- package/contracts/decision.mjs +83 -0
- package/contracts/decision.schema.json +50 -0
- package/contracts/index.mjs +23 -0
- package/cordis.patch.yml +5 -0
- package/docs/acceptance-scenarios.md +24 -0
- package/docs/test-review.md +68 -0
- package/lib/client.js +4068 -0
- package/lib/client.js.map +1 -0
- package/lib/host-plugin.js +2199 -0
- package/lib/host-plugin.js.map +1 -0
- package/lib/typert.host.js +52 -0
- package/lib/typert.host.js.map +1 -0
- package/package.json +87 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 yangbobo2021 and Relay contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Relay Events for DeepSeek Harness
|
|
2
|
+
|
|
3
|
+
`relay-dsh-plugin-events` is the durable, provider-neutral Wait/Event/Delivery
|
|
4
|
+
core for official DeepSeek Harness. It adds Agent tools, generic JSON ingress,
|
|
5
|
+
delivery to the owning existing Session, recovery, and a Waiting Events settings
|
|
6
|
+
surface without adding an execution backend.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# After building this repository (see below):
|
|
10
|
+
dsh plugin --profile web add ./relay-dsh-plugin-events-0.1.0.tgz
|
|
11
|
+
dsh web
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Semantic routing and Monitor execution are separate plugins. Without a Router,
|
|
15
|
+
Events uses exact event-type matching. Without Monitors, Wait-only registration
|
|
16
|
+
and external ingress remain fully usable.
|
|
17
|
+
|
|
18
|
+
See [SPEC.md](SPEC.md) and
|
|
19
|
+
[delivery scenarios](docs/acceptance-scenarios.md).
|
|
20
|
+
|
|
21
|
+
Set `DSH_ROOT` to the prepared immutable official DSH checkout, then run
|
|
22
|
+
`npm ci --ignore-scripts && npm run verify && npm pack`.
|
|
23
|
+
The tarball includes built runtime files. A raw GitHub checkout intentionally does
|
|
24
|
+
not track `lib/`; do not install `#main` as if it were a built release. This delivery
|
|
25
|
+
does not claim an npm registry publication.
|
|
26
|
+
|
|
27
|
+
Tested official DSH reference:
|
|
28
|
+
`b150a551b8d465e31e418e1b2eaf5e79bbb7d28e`.
|
package/SPEC.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Relay DSH Events Plugin Specification
|
|
2
|
+
|
|
3
|
+
Status: Accepted for `0.1.0`
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
`relay-dsh-plugin-events` is the provider-neutral durable event core for official
|
|
8
|
+
DeepSeek Harness. It stores Waits and Events, selects a registered Router (or an
|
|
9
|
+
exact fallback), creates idempotent Deliveries, and admits each Delivery through
|
|
10
|
+
the owning existing DSH Session.
|
|
11
|
+
|
|
12
|
+
## Boundary
|
|
13
|
+
|
|
14
|
+
The plugin owns:
|
|
15
|
+
|
|
16
|
+
- Wait, Event, routing-attempt, routing-decision, Delivery, Activation, and Monitor
|
|
17
|
+
persistence in one local SQLite database;
|
|
18
|
+
- the `relayEvents` Cordis service and its versioned Router/Monitor provider slots;
|
|
19
|
+
- exact event-type fallback routing when no Router provider is registered;
|
|
20
|
+
- delivery to the existing DSH Session, stable Activation identity, and background
|
|
21
|
+
recovery of queued Deliveries;
|
|
22
|
+
- `relay_register_waits` and `relay_cancel_waits` Agent tools;
|
|
23
|
+
- generic JSON ingress at `POST /api/relay/events`;
|
|
24
|
+
- the Waiting Events management Remote and Settings section.
|
|
25
|
+
|
|
26
|
+
The plugin does not own:
|
|
27
|
+
|
|
28
|
+
- model calls or semantic routing policy;
|
|
29
|
+
- Monitor observation, detection, scheduling, or generated code;
|
|
30
|
+
- email, CI, or provider-specific Webhook normalization;
|
|
31
|
+
- conversation creation or an execution backend;
|
|
32
|
+
- notification delivery for escalated Events.
|
|
33
|
+
|
|
34
|
+
## Public Service Contract
|
|
35
|
+
|
|
36
|
+
`ctx.relayEvents.apiVersion` is `1`. The public service exposes high-level event
|
|
37
|
+
operations and two replaceable provider registrations:
|
|
38
|
+
|
|
39
|
+
- `registerRouter(provider)` accepts exactly one active Router with stable `id` and
|
|
40
|
+
`route({ event, eventRecord, sessions })`;
|
|
41
|
+
- `registerMonitorProvider(provider)` accepts exactly one active Monitor provider
|
|
42
|
+
with `prepare`, `checkMonitor`, and lifecycle-safe disposal;
|
|
43
|
+
- Wait/Event operations: `registerWaits`, `cancelWaits`, `listWaits`,
|
|
44
|
+
`handleEvent`, and `dispatchSession`;
|
|
45
|
+
- Monitor persistence operations: `beginMonitorCheck`, `completeMonitorCheck`,
|
|
46
|
+
`failMonitorCheck`, `abandonMonitorCheck`, and `listDueMonitors`. No SQLite
|
|
47
|
+
handle, mutable map, or DSH Agent object crosses the service boundary.
|
|
48
|
+
|
|
49
|
+
Provider registration is owned by the registering Cordis fiber. Duplicate active
|
|
50
|
+
providers fail closed. Unloading a provider restores the exact fallback Router or
|
|
51
|
+
the Monitor-unavailable state without unloading Events.
|
|
52
|
+
|
|
53
|
+
## Reliability
|
|
54
|
+
|
|
55
|
+
- Event ingestion is idempotent by source identity and fingerprint.
|
|
56
|
+
- Routing decisions are validated against the current Wait snapshot and committed
|
|
57
|
+
once.
|
|
58
|
+
- Delivery creation and Wait claim are atomic.
|
|
59
|
+
- Failed admission keeps the same Event, Delivery, and Activation IDs queued.
|
|
60
|
+
- Admission succeeds when the stable inbox message has been flushed to DSH
|
|
61
|
+
persistence, not when the model turn finishes. A retry recognizes the persisted
|
|
62
|
+
Activation message and does not enqueue another follow-up.
|
|
63
|
+
- Reappearing Monitor trigger keys do not create another Delivery or pause a
|
|
64
|
+
rearmed Monitor; its replacement Wait stays active.
|
|
65
|
+
- A background recovery scan retries queued Deliveries after failure or Host restart.
|
|
66
|
+
- Events never create DSH Sessions and never switch the selected Web Session.
|
|
67
|
+
- Shutdown stops new operations, waits for in-flight work, disposes routes/listeners,
|
|
68
|
+
and closes SQLite last.
|
|
69
|
+
|
|
70
|
+
## Security
|
|
71
|
+
|
|
72
|
+
- Loopback ingress may omit a token. Non-loopback ingress requires an exact Bearer
|
|
73
|
+
token and fails closed when no token is configured.
|
|
74
|
+
- Event fields remain untrusted content in the injected DSH envelope.
|
|
75
|
+
- Payload size is bounded before JSON parsing.
|
|
76
|
+
- Provider-specific signatures are outside this generic ingress boundary.
|
|
77
|
+
|
|
78
|
+
## Delivery Acceptance
|
|
79
|
+
|
|
80
|
+
The release must pass unit, contract, packed-package, official-DSH, and composition
|
|
81
|
+
acceptance. The executable scenario list is in
|
|
82
|
+
[`docs/acceptance-scenarios.md`](docs/acceptance-scenarios.md).
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
|
|
3
|
+
const BASE_DISPOSITIONS = new Set(["deliver", "escalate", "dismiss"]);
|
|
4
|
+
|
|
5
|
+
export function validateRoutingDecision({
|
|
6
|
+
decision,
|
|
7
|
+
sessions,
|
|
8
|
+
allowDeduplicate = false,
|
|
9
|
+
canDeduplicate = false,
|
|
10
|
+
label = "routing decision",
|
|
11
|
+
}) {
|
|
12
|
+
assert.ok(decision && typeof decision === "object", `${label}: decision is required`);
|
|
13
|
+
const dispositions = allowDeduplicate
|
|
14
|
+
? new Set([...BASE_DISPOSITIONS, "deduplicate"])
|
|
15
|
+
: BASE_DISPOSITIONS;
|
|
16
|
+
assert.ok(
|
|
17
|
+
dispositions.has(decision.disposition),
|
|
18
|
+
`${label}: invalid disposition ${decision.disposition}`,
|
|
19
|
+
);
|
|
20
|
+
assert.ok(Array.isArray(decision.deliveries), `${label}: deliveries must be an array`);
|
|
21
|
+
|
|
22
|
+
if (decision.disposition === "deduplicate") {
|
|
23
|
+
assert.ok(canDeduplicate, `${label}: deduplicate requires an existing event`);
|
|
24
|
+
assert.equal(decision.deliveries.length, 0, `${label}: duplicate cannot create deliveries`);
|
|
25
|
+
return decision;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
assert.equal(typeof decision.actionable, "boolean", `${label}: actionable must be boolean`);
|
|
29
|
+
assert.ok(Array.isArray(decision.evidence), `${label}: evidence must be an array`);
|
|
30
|
+
assert.equal(typeof decision.summary, "string", `${label}: summary must be a string`);
|
|
31
|
+
|
|
32
|
+
if (decision.disposition === "deliver") {
|
|
33
|
+
assert.equal(decision.actionable, true, `${label}: delivered event must be actionable`);
|
|
34
|
+
assert.ok(decision.deliveries.length > 0, `${label}: deliver requires a target`);
|
|
35
|
+
} else {
|
|
36
|
+
assert.equal(decision.deliveries.length, 0, `${label}: ${decision.disposition} cannot deliver`);
|
|
37
|
+
assert.equal(
|
|
38
|
+
decision.actionable,
|
|
39
|
+
decision.disposition === "escalate",
|
|
40
|
+
`${label}: actionable conflicts with ${decision.disposition}`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const sessionsById = new Map(sessions.map((session) => [session.session_id, session]));
|
|
45
|
+
const deliveredSessionIds = decision.deliveries.map((delivery) => delivery.session_id);
|
|
46
|
+
assertUnique(deliveredSessionIds, `${label}: delivered session IDs`);
|
|
47
|
+
|
|
48
|
+
const selectedWaits = [];
|
|
49
|
+
for (const delivery of decision.deliveries) {
|
|
50
|
+
const session = sessionsById.get(delivery.session_id);
|
|
51
|
+
assert.ok(session, `${label}: unknown session ${delivery.session_id}`);
|
|
52
|
+
assert.ok(Array.isArray(delivery.wait_ids), `${label}: wait_ids must be an array`);
|
|
53
|
+
assertUnique(delivery.wait_ids, `${label}: delivered wait IDs`);
|
|
54
|
+
assert.equal(typeof delivery.relation, "string", `${label}: relation must be a string`);
|
|
55
|
+
assert.ok(
|
|
56
|
+
Number.isFinite(delivery.confidence) &&
|
|
57
|
+
delivery.confidence >= 0 &&
|
|
58
|
+
delivery.confidence <= 1,
|
|
59
|
+
`${label}: confidence must be between 0 and 1`,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
for (const waitId of delivery.wait_ids) {
|
|
63
|
+
const wait = session.waits.find((candidate) => candidate.wait_id === waitId);
|
|
64
|
+
assert.ok(wait, `${label}: wait ${waitId} does not belong to ${session.session_id}`);
|
|
65
|
+
assert.equal(wait.status, "active", `${label}: wait ${waitId} is not active`);
|
|
66
|
+
selectedWaits.push(wait);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (decision.deliveries.length > 1) {
|
|
71
|
+
assert.ok(selectedWaits.length > 0, `${label}: multi-session delivery needs matched waits`);
|
|
72
|
+
assert.ok(
|
|
73
|
+
selectedWaits.every((wait) => wait.exclusive === false),
|
|
74
|
+
`${label}: exclusive event cannot target multiple sessions`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return decision;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function assertUnique(values, label) {
|
|
82
|
+
assert.equal(new Set(values).size, values.length, `${label} must be unique`);
|
|
83
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"additionalProperties": false,
|
|
5
|
+
"required": ["disposition", "actionable", "deliveries", "evidence", "summary"],
|
|
6
|
+
"properties": {
|
|
7
|
+
"disposition": {
|
|
8
|
+
"enum": ["deliver", "escalate", "dismiss"]
|
|
9
|
+
},
|
|
10
|
+
"actionable": {
|
|
11
|
+
"type": "boolean"
|
|
12
|
+
},
|
|
13
|
+
"deliveries": {
|
|
14
|
+
"type": "array",
|
|
15
|
+
"items": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"additionalProperties": false,
|
|
18
|
+
"required": ["session_id", "wait_ids", "relation", "confidence"],
|
|
19
|
+
"properties": {
|
|
20
|
+
"session_id": {
|
|
21
|
+
"type": "string"
|
|
22
|
+
},
|
|
23
|
+
"wait_ids": {
|
|
24
|
+
"type": "array",
|
|
25
|
+
"items": {
|
|
26
|
+
"type": "string"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"relation": {
|
|
30
|
+
"type": "string"
|
|
31
|
+
},
|
|
32
|
+
"confidence": {
|
|
33
|
+
"type": "number",
|
|
34
|
+
"minimum": 0,
|
|
35
|
+
"maximum": 1
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"evidence": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"items": {
|
|
43
|
+
"type": "string"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"summary": {
|
|
47
|
+
"type": "string"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export { validateRoutingDecision } from "./decision.mjs";
|
|
2
|
+
|
|
3
|
+
export const RELAY_EVENTS_API_VERSION = 1;
|
|
4
|
+
|
|
5
|
+
export function validateRouterProvider(provider) {
|
|
6
|
+
if (!provider || typeof provider !== "object") throw new TypeError("router provider is required");
|
|
7
|
+
if (!/^[a-z][a-z0-9._-]{0,63}$/u.test(provider.id ?? "")) {
|
|
8
|
+
throw new TypeError("router provider requires a lowercase stable id");
|
|
9
|
+
}
|
|
10
|
+
if (typeof provider.route !== "function") throw new TypeError("router provider requires route()");
|
|
11
|
+
return provider;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function validateMonitorProvider(provider) {
|
|
15
|
+
if (!provider || typeof provider !== "object") throw new TypeError("monitor provider is required");
|
|
16
|
+
if (!/^[a-z][a-z0-9._-]{0,63}$/u.test(provider.id ?? "")) {
|
|
17
|
+
throw new TypeError("monitor provider requires a lowercase stable id");
|
|
18
|
+
}
|
|
19
|
+
for (const method of ["prepare", "checkMonitor"]) {
|
|
20
|
+
if (typeof provider[method] !== "function") throw new TypeError(`monitor provider requires ${method}()`);
|
|
21
|
+
}
|
|
22
|
+
return provider;
|
|
23
|
+
}
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Events Delivery Acceptance Scenarios
|
|
2
|
+
|
|
3
|
+
Official DSH reference: `b150a551b8d465e31e418e1b2eaf5e79bbb7d28e`
|
|
4
|
+
|
|
5
|
+
| ID | Scenario | Required result | Evidence |
|
|
6
|
+
| --- | --- | --- | --- |
|
|
7
|
+
| EVT-001 | Events-only boot | Packed plugin installs into a pristine official DSH profile and Host boots without Codex, Claude, Router, or Monitors. | package acceptance |
|
|
8
|
+
| EVT-002 | Exact fallback delivery | An Event whose type equals one active Wait is delivered once to that existing Session. | unit + Host contract |
|
|
9
|
+
| EVT-003 | Unmatched fallback | An unmatched Event is durably dismissed with an inspectable reason and starts no Session. | unit |
|
|
10
|
+
| EVT-004 | Duplicate ingress | Repeating the same provider identity/fingerprint returns the original Event and creates no second Delivery. | unit + HTTP |
|
|
11
|
+
| EVT-005 | Router substitution | A fake registered Router receives the compact snapshot; unload restores exact fallback. | service contract |
|
|
12
|
+
| EVT-006 | Duplicate Router | A second active Router registration fails without replacing the first. | service contract |
|
|
13
|
+
| EVT-007 | Monitor provider absence | Wait-only registration works; registration containing Monitors fails before replacing prior Waits. | service contract |
|
|
14
|
+
| EVT-008 | Atomic prepared Monitor registration | A fake Monitor provider baseline succeeds and Wait/Monitor records commit together; baseline failure changes neither. | integration |
|
|
15
|
+
| EVT-009 | Delivery retry identity | First admission fails, background recovery succeeds, and Event/Delivery/Activation IDs remain unchanged. | fake clock integration |
|
|
16
|
+
| EVT-010 | Restart recovery | A database with queued Delivery is reopened and recovered without re-routing or duplicate injection. | integration |
|
|
17
|
+
| EVT-011 | Ingress authorization | Loopback is accepted; non-loopback missing/wrong token is rejected; valid token succeeds. | HTTP unit |
|
|
18
|
+
| EVT-012 | Ingress bounds | Wrong method/content type, malformed JSON, and oversized bodies receive stable errors. | HTTP unit |
|
|
19
|
+
| EVT-013 | DSH tool ownership | Tools attach to every root Agent and use the authenticated Session ID rather than a model-supplied ID. | Host contract |
|
|
20
|
+
| EVT-014 | Management operations | List, open, cancel, and provider-backed run-now operate through the typed Remote. | Host/client contract |
|
|
21
|
+
| EVT-015 | Clean unload | New operations fail during shutdown; in-flight work settles; listeners, Remote, service, timers, and SQLite are released. | lifecycle integration |
|
|
22
|
+
| EVT-016 | Backend neutrality | Events-only, Events+Codex, and Events+Claude compositions contain no backend import or backend-name branch in Events. | static + official DSH |
|
|
23
|
+
| EVT-017 | Package boundary | Tarball contains built/public artifacts only and imports in a clean directory. | `npm pack` acceptance |
|
|
24
|
+
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Events Test Review
|
|
2
|
+
|
|
3
|
+
## Review 1 — service extraction
|
|
4
|
+
|
|
5
|
+
- Preserved Runtime tests for replacement Waits, multi-Session delivery,
|
|
6
|
+
escalation, cancellation, ordering, and Activation identity.
|
|
7
|
+
- Added Router substitution/duplicate/disposal, Monitor baseline failure,
|
|
8
|
+
restart recovery, and shutdown drain coverage.
|
|
9
|
+
- The first run exposed an unhandled rejected Promise created by cleanup tracking;
|
|
10
|
+
handled success/error branches now remove in-flight Promises, and the regression
|
|
11
|
+
test passes without asynchronous activity warnings.
|
|
12
|
+
|
|
13
|
+
## Review 2 — Agent bridge
|
|
14
|
+
|
|
15
|
+
- Verified tools derive Session ownership from authenticated Agent context.
|
|
16
|
+
- Verified Events owns only Wait registration/cancellation tools; timer ownership
|
|
17
|
+
moved to Monitors.
|
|
18
|
+
- Extended and asserted Monitor proposal fields without accepting a model-supplied
|
|
19
|
+
Session id.
|
|
20
|
+
|
|
21
|
+
Packed official-DSH boot/composition and browser checks run in Relay's cross-plugin
|
|
22
|
+
delivery harness.
|
|
23
|
+
|
|
24
|
+
## Review 3 — independent checkout execution
|
|
25
|
+
|
|
26
|
+
- Verified a fresh plugin checkout can run `npm test` without relying on a parent
|
|
27
|
+
workspace installation.
|
|
28
|
+
- Added the same official-DSH peer-link preparation used by typecheck and build to
|
|
29
|
+
the test lifecycle; this prevents a false local pass caused by hoisted packages.
|
|
30
|
+
|
|
31
|
+
## Review 4 — composed Router audit identity
|
|
32
|
+
|
|
33
|
+
- The cross-plugin test showed that a substituted Router delivered correctly while
|
|
34
|
+
its routing attempt was attributed to an internal slot name.
|
|
35
|
+
- Events now reads `name` and `model` dynamically from the active provider, and the
|
|
36
|
+
service test asserts provider attribution before fallback restoration.
|
|
37
|
+
|
|
38
|
+
## Review 5 — submodule workspace type identity
|
|
39
|
+
|
|
40
|
+
- Running the plugin inside Relay exposed duplicate branded DSH types resolved from
|
|
41
|
+
the parent workspace instead of the pinned official checkout.
|
|
42
|
+
- The original wildcard peer-directory mapping did **not** fix package subpath
|
|
43
|
+
exports. The continuation replaces it with a generated map of official declaration
|
|
44
|
+
exports (including `/types` and transitive brands). Both typecheck and build now pass;
|
|
45
|
+
`dsh-type-paths.test.mjs` covers this resolution rule without suppressing errors.
|
|
46
|
+
|
|
47
|
+
## Review 6 — real composition and admission lifecycle
|
|
48
|
+
|
|
49
|
+
- Persisted Observer identity in the Monitor manifest and restored it on hydration;
|
|
50
|
+
otherwise every non-clock observation failed after baseline despite passing fake-store tests.
|
|
51
|
+
- Grouped multiple matching Waits per Session in exact routing (one Delivery per Session).
|
|
52
|
+
- Agent tool disposers now belong to the plugin as well as the Agent, preventing stale tools after unload.
|
|
53
|
+
- Admission acknowledges inbox flush, not whole model-turn completion. Stable message IDs and
|
|
54
|
+
persisted inbox/message lookup prevent duplicate follow-ups after an acknowledgement retry.
|
|
55
|
+
- Added real SQLite composition regressions for recurring rearm, Observer failure, lease exclusion,
|
|
56
|
+
atomic baseline rollback and overdue restart; added background recovery and inbox retry unit tests.
|
|
57
|
+
|
|
58
|
+
## Review 7 — packed delivery and composition
|
|
59
|
+
|
|
60
|
+
- Clean-directory tarball installation imports all public entries without parent
|
|
61
|
+
source or private runtime packages. Host-only Router/Monitors need no browser entry.
|
|
62
|
+
- Added real Cordis dependency appearance/removal/reappearance coverage; surviving
|
|
63
|
+
Agents retain no stale tools after plugin unload.
|
|
64
|
+
- Replaced misleading raw GitHub installation instructions with build-and-pack
|
|
65
|
+
instructions, since generated `lib/` is intentionally not tracked.
|
|
66
|
+
- A rearmed recurring Monitor now ignores already committed trigger keys without
|
|
67
|
+
pausing again. The regression checks disappearance/reappearance and the still-active
|
|
68
|
+
replacement Wait. Shutdown lease release is tested against real SQLite.
|