instar 1.3.571 → 1.3.573
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/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +37 -3
- package/dist/commands/server.js.map +1 -1
- package/dist/core/ws2SendWiring.d.ts +1 -1
- package/dist/core/ws2SendWiring.d.ts.map +1 -1
- package/dist/core/ws2SendWiring.js +3 -3
- package/dist/core/ws2SendWiring.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.572.md +55 -0
- package/upgrades/1.3.573.md +47 -0
- package/upgrades/side-effects/ws2-send-2-knowledge.md +51 -0
- package/upgrades/side-effects/ws2-send-2-relationships.md +52 -0
|
@@ -21,7 +21,7 @@ export declare const WS2_SEND_WIRED_STORES: ReadonlyArray<string>;
|
|
|
21
21
|
/**
|
|
22
22
|
* Stores registered for RECEIVE but whose SEND wiring is a KNOWN, enumerated
|
|
23
23
|
* follow-up — NOT a silent omission. Each is here for a stated reason:
|
|
24
|
-
* -
|
|
24
|
+
* - evolutionActions / userRegistry: fully seamed
|
|
25
25
|
* managers (emitPut + emitDelete); table-row wiring onto the same emitter (WS2-SEND-2).
|
|
26
26
|
* - topicOperator: seamed put-only (no emitDelete in its manager interface yet) (WS2-SEND-3).
|
|
27
27
|
* - preferences: NO manager emit seam yet — it rode the deprecated `preferences-sync`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws2SendWiring.d.ts","sourceRoot":"","sources":["../../src/core/ws2SendWiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;+CAE+C;AAC/C,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"ws2SendWiring.d.ts","sourceRoot":"","sources":["../../src/core/ws2SendWiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;+CAE+C;AAC/C,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC,MAAM,CAItD,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,EAAE,aAAa,CAAC,MAAM,CAKxD,CAAC;AAEH,uDAAuD;AACvD,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,GAAG,cAAc,CAAC;AAEjE,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAI1D;AAED,kFAAkF;AAClF,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,6FAA6F;IAC7F,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,EAAE,EAAE,OAAO,CAAC;CACb;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,kBAAkB,CAW9F"}
|
|
@@ -19,19 +19,19 @@
|
|
|
19
19
|
* follow on the SAME emitter (WS2-SEND-2). */
|
|
20
20
|
export const WS2_SEND_WIRED_STORES = Object.freeze([
|
|
21
21
|
'learnings',
|
|
22
|
+
'relationships',
|
|
23
|
+
'knowledge',
|
|
22
24
|
]);
|
|
23
25
|
/**
|
|
24
26
|
* Stores registered for RECEIVE but whose SEND wiring is a KNOWN, enumerated
|
|
25
27
|
* follow-up — NOT a silent omission. Each is here for a stated reason:
|
|
26
|
-
* -
|
|
28
|
+
* - evolutionActions / userRegistry: fully seamed
|
|
27
29
|
* managers (emitPut + emitDelete); table-row wiring onto the same emitter (WS2-SEND-2).
|
|
28
30
|
* - topicOperator: seamed put-only (no emitDelete in its manager interface yet) (WS2-SEND-3).
|
|
29
31
|
* - preferences: NO manager emit seam yet — it rode the deprecated `preferences-sync`
|
|
30
32
|
* verb; needs a manager emit hook before it can be wired (WS2-SEND-3).
|
|
31
33
|
*/
|
|
32
34
|
export const WS2_SEND_PENDING_STORES = Object.freeze([
|
|
33
|
-
'relationships',
|
|
34
|
-
'knowledge',
|
|
35
35
|
'evolutionActions',
|
|
36
36
|
'userRegistry',
|
|
37
37
|
'topicOperator',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws2SendWiring.js","sourceRoot":"","sources":["../../src/core/ws2SendWiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;+CAE+C;AAC/C,MAAM,CAAC,MAAM,qBAAqB,GAA0B,MAAM,CAAC,MAAM,CAAC;IACxE,WAAW;CACZ,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAA0B,MAAM,CAAC,MAAM,CAAC;IAC1E,
|
|
1
|
+
{"version":3,"file":"ws2SendWiring.js","sourceRoot":"","sources":["../../src/core/ws2SendWiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;+CAE+C;AAC/C,MAAM,CAAC,MAAM,qBAAqB,GAA0B,MAAM,CAAC,MAAM,CAAC;IACxE,WAAW;IACX,eAAe;IACf,WAAW;CACZ,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAA0B,MAAM,CAAC,MAAM,CAAC;IAC1E,kBAAkB;IAClB,cAAc;IACd,eAAe;IACf,aAAa;CACd,CAAC,CAAC;AAKH,wDAAwD;AACxD,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,IAAI,qBAAqB,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IAC1D,IAAI,uBAAuB,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9D,OAAO,cAAc,CAAC;AACxB,CAAC;AAWD;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,gBAAuC;IACxE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,gBAAgB,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,MAAM,KAAK,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;aACrC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;;YAC9C,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;AACzE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-06-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-06-15T17:50:05.433Z",
|
|
5
|
+
"instarVersion": "1.3.573",
|
|
6
6
|
"entryCount": 201,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The `relationships` memory store is now wired into the WS2 send-side, the first of the
|
|
9
|
+
four "table-row" stores the WS2-SEND-SIDE-EMISSION-SPEC enumerated as the WS2-SEND-2
|
|
10
|
+
follow-on. #1168 proved the generic `ReplicatedRecordEmitter` machinery end-to-end for
|
|
11
|
+
`learnings`; this change attaches that same emitter to the `RelationshipManager`'s
|
|
12
|
+
existing write hooks (the manager already fired `emitPut` on every saved person and
|
|
13
|
+
`emitDelete` on erase/merge — the emitter was simply never attached), and flips
|
|
14
|
+
`relationships` from PENDING to WIRED in the send-wiring ratchet (`ws2SendWiring.ts`).
|
|
15
|
+
|
|
16
|
+
No new design: the disclosure-minimized projection (`buildRelationshipRecordData` /
|
|
17
|
+
`buildRelationshipTombstoneData`), the channel-set identity surface, the receive-side
|
|
18
|
+
schema, and the no-clobber union read all already shipped with the WS2.3 relationships
|
|
19
|
+
work. This is the send attachment + its end-to-end proof. Everything stays behind the
|
|
20
|
+
per-store dark gate (`multiMachine.stateSync.relationships`, off by default — the
|
|
21
|
+
development-agent gate flips it live on a dev agent only). Records ride the existing
|
|
22
|
+
journal-sync tail and pull — no new HTTP route or mesh verb.
|
|
23
|
+
|
|
24
|
+
## What to Tell Your User
|
|
25
|
+
|
|
26
|
+
- **Cross-machine relationships now actually cross**: "If you run me on more than one
|
|
27
|
+
machine, a person I know on one is now known on the others — one shared relationship
|
|
28
|
+
graph instead of one per machine. Only a disclosure-minimized, channel-keyed
|
|
29
|
+
projection crosses (never the raw record or the local id), a copy from another machine
|
|
30
|
+
is always a hint and never the authority on who is messaging you, and an erased person
|
|
31
|
+
stays erased everywhere via a tombstone. It stays off until you ask me to turn on
|
|
32
|
+
multi-machine relationship sync." ⚗️ Experimental — ships dark; the learnings slice is
|
|
33
|
+
the proven path and the remaining stores follow on the same wiring.
|
|
34
|
+
|
|
35
|
+
## Summary of New Capabilities
|
|
36
|
+
|
|
37
|
+
| Capability | How to Use |
|
|
38
|
+
|-----------|-----------|
|
|
39
|
+
| Cross-machine replication of known people (relationships) | Automatic once `multiMachine.stateSync.relationships` is enabled (off by default) |
|
|
40
|
+
| Channel-keyed identity — same person on two machines collapses to one record | Automatic (read path) |
|
|
41
|
+
| Erasure propagates as a channel-keyed tombstone (stays erased on offline-then-rejoining peers) | Automatic (delete path) |
|
|
42
|
+
|
|
43
|
+
## Evidence
|
|
44
|
+
|
|
45
|
+
Verified by a two-instance in-process E2E
|
|
46
|
+
(`tests/e2e/ws2-relationships-cross-instance.test.ts`): a person recorded on instance A
|
|
47
|
+
(`findOrCreate`), shipped over the real journal serve/apply path, is read back on
|
|
48
|
+
instance B through the bypass-proof union reader as a foreign-origin record — and the
|
|
49
|
+
local UUID is confirmed absent from the projection; a `delete` on A replicates as a
|
|
50
|
+
channel-keyed tombstone and B's union read resolves the key to "no record"; the same
|
|
51
|
+
person (same channel set) recorded on both machines collapses to one record key across
|
|
52
|
+
origins. Before the attachment B's union read returned null; after, it returns A's
|
|
53
|
+
record. `tsc --noEmit` clean; the new e2e (3) + the learnings e2e (3) pass; the
|
|
54
|
+
ws2-send-wiring integration ratchet (4) accepts the PENDING→WIRED move; the existing
|
|
55
|
+
`relationship-replication-emit` seam unit tests (6) stay green.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The `knowledge` memory store is now wired into the WS2 send-side — the second of the
|
|
9
|
+
WS2-SEND-2 table-row stores (after `relationships`). The generic emitter from #1168 is
|
|
10
|
+
attached to `KnowledgeManager`'s existing ingest/remove hooks (the manager already fired
|
|
11
|
+
`emitPut`/`emitDelete`; the emitter was a `void` placeholder), and `knowledge` flips
|
|
12
|
+
PENDING→WIRED in the send-wiring ratchet. The knowledge union reader and the
|
|
13
|
+
disclosure-minimized projection already shipped (WS2.4); this is the send attachment +
|
|
14
|
+
its end-to-end proof. Dark by default (`multiMachine.stateSync.knowledge`). No new
|
|
15
|
+
route/verb/config-default/migration. Only catalog METADATA crosses — never the markdown
|
|
16
|
+
body, never the local id/filePath.
|
|
17
|
+
|
|
18
|
+
## What to Tell Your User
|
|
19
|
+
|
|
20
|
+
- **Cross-machine knowledge catalog now actually crosses**: "If you run me on more than
|
|
21
|
+
one machine, a source I ingest on one (an article, transcript, or doc) now shows up in
|
|
22
|
+
the catalog on the others — one shared knowledge index instead of one per machine. Only
|
|
23
|
+
the catalog entry crosses (title, link, type, tags, summary) — never the full document
|
|
24
|
+
text and never the local file path; the other machine learns the source exists and can
|
|
25
|
+
re-fetch it itself. It stays off until you ask me to turn on multi-machine knowledge
|
|
26
|
+
sync." ⚗️ Experimental — ships dark; metadata-only by design (full-content sync is a
|
|
27
|
+
separate tracked stage).
|
|
28
|
+
|
|
29
|
+
## Summary of New Capabilities
|
|
30
|
+
|
|
31
|
+
| Capability | How to Use |
|
|
32
|
+
|-----------|-----------|
|
|
33
|
+
| Cross-machine replication of the knowledge catalog (metadata only) | Automatic once `multiMachine.stateSync.knowledge` is enabled (off by default) |
|
|
34
|
+
| Content-fingerprint identity — the same source on two machines collapses to one record | Automatic (read path) |
|
|
35
|
+
| Removal propagates as a fingerprint-keyed tombstone (no resurrection of a removed source) | Automatic (remove path) |
|
|
36
|
+
|
|
37
|
+
## Evidence
|
|
38
|
+
|
|
39
|
+
Verified by a two-instance in-process E2E
|
|
40
|
+
(`tests/e2e/ws2-knowledge-cross-instance.test.ts`): a source ingested on instance A is
|
|
41
|
+
read back on B through the bypass-proof union reader as a foreign-origin record — and the
|
|
42
|
+
markdown body, local `id`, and `filePath` are confirmed ABSENT from the projection
|
|
43
|
+
(metadata only); a `remove` on A replicates as a fingerprint-keyed tombstone and B's
|
|
44
|
+
union read resolves the key to "no record" (no resurrection); the same source (same
|
|
45
|
+
url+type) ingested on both machines collapses to one record key across origins. `tsc
|
|
46
|
+
--noEmit` clean; the new e2e (3) + relationships e2e (3) pass; the ws2-send-wiring
|
|
47
|
+
integration ratchet (4) accepts the PENDING→WIRED move.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Side-Effects Review — WS2-SEND-2: knowledge send-side replication
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `ws2-send-2-knowledge`
|
|
4
|
+
**Date:** `2026-06-15`
|
|
5
|
+
**Author:** `Instar Agent (echo)`
|
|
6
|
+
**Second-pass reviewer:** `not required` (no block/allow/lifecycle authority — additive, dark-gated data-replication wiring; see §4)
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Extends WS2 send-side emission to the `knowledge` store (the second WS2-SEND-2 table-row store after `relationships`). Mirrors the proven pattern: `src/commands/server.ts` imports `buildKnowledgeRecordData` + `buildKnowledgeTombstoneData` and attaches the generic `ReplicatedRecordEmitter` to `KnowledgeManager.setKnowledgeReplicationEmitter` (replacing the prior `void` placeholder), gated `if (replicatedRecordEmitter)`; `src/core/ws2SendWiring.ts` moves `knowledge` PENDING→WIRED; a new e2e round-trip `tests/e2e/ws2-knowledge-cross-instance.test.ts`. The knowledge union reader already existed (constructed @8566). No decision-point surface added beyond the pre-existing dark gate.
|
|
11
|
+
|
|
12
|
+
## Decision-point inventory
|
|
13
|
+
|
|
14
|
+
- `ReplicatedRecordEmitter.emit` dark gate (`stateSync.knowledge.enabled`) — **pass-through** — pre-existing; `knowledge` is now a registered emit target. Default false ⇒ no-op.
|
|
15
|
+
- `KnowledgeManager.ingest`/`remove` emit funnel — **pass-through** — the manager already fires emitPut@165 / emitDelete@204; this attaches a real emitter where there was a no-op.
|
|
16
|
+
- `ws2SendWiring` ratchet — **modify** — `knowledge` reclassified PENDING→WIRED.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. Over-block
|
|
21
|
+
|
|
22
|
+
No block/allow surface — over-block not applicable. The emitter never rejects an ingest/remove; a null recordKey / null projection / over-cap source is a counted no-op and the local catalog write always succeeds.
|
|
23
|
+
|
|
24
|
+
## 2. Under-block
|
|
25
|
+
|
|
26
|
+
Not applicable (no block surface). A source with an empty identity anchor (no url AND no title) has no cross-machine fingerprint and is intentionally not replicated (by design) — local-only.
|
|
27
|
+
|
|
28
|
+
## 3. Level-of-abstraction fit
|
|
29
|
+
|
|
30
|
+
Correct layer. Table-row registration onto the generic #1168 substrate, exactly as the spec's WS2-SEND-2 prescribes. The disclosure-minimized projection lives in `KnowledgeReplicatedStore` alongside the receive-side schema.
|
|
31
|
+
|
|
32
|
+
## 4. Signal vs authority compliance
|
|
33
|
+
|
|
34
|
+
Compliant. No blocking authority. The emitter is additive/best-effort: a builder/journal failure is swallowed + counted, never propagated, so a knowledge ingest can never fail because replication did. The union read is advisory (HIGH tier append-both-and-flag). Per `docs/signal-vs-authority.md`, a replicator with no gate authority.
|
|
35
|
+
|
|
36
|
+
## 5. Interactions
|
|
37
|
+
|
|
38
|
+
- Shares `server.ts`'s single `replicatedRecordEmitter` + the existing `knowledgeUnionReader`. No double-fire: emitPut rides the single `ingest()` path, emitDelete the single `remove()` path. Distinct store key/kind from learnings + relationships.
|
|
39
|
+
- Touches the same `server.ts` + `ws2SendWiring.ts` as the other WS2-SEND stores → serialized (built on top of the merged #1169 relationships change; no parallel WS2-SEND PRs).
|
|
40
|
+
|
|
41
|
+
## 6. External surfaces
|
|
42
|
+
|
|
43
|
+
Dark by default (`multiMachine.stateSync.knowledge.enabled`). Off ⇒ byte-identical single-machine behavior. On (multi-machine, opt-in): only the catalog METADATA crosses (title, url, type, tags, summary, wordCount) — NEVER the markdown file BODY and NEVER the local id/filePath (fork #2). The peer LEARNS the source exists and may re-ingest locally; full-content sync is a separate tracked rollout stage. A received record is quoted `<replicated-untrusted-data>`, advisory reference only.
|
|
44
|
+
|
|
45
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
46
|
+
|
|
47
|
+
**Replicated.** Path: `KnowledgeManager.ingest/remove` → `ReplicatedRecordEmitter.emit` → `CoherenceJournal.emitReplicatedRecord` → peer serve/apply → `ReplicatedPeerStreamReader.loadOriginRecords` → `knowledgeUnionReader` (no-clobber union, conflict-flagged). Identity = content fingerprint (url||title + type), so the same source on two machines collapses to one recordKey. remove() propagates a fingerprint-keyed tombstone (a later `delete` hlc wins over an earlier `put` — no resurrection). No user-facing notice surface; no topic-transfer state; no generated URLs.
|
|
48
|
+
|
|
49
|
+
## 8. Rollback cost
|
|
50
|
+
|
|
51
|
+
Trivial. Dark by default; affects only agents that enable `stateSync.knowledge`. Back-out = revert the three-file change or set the flag false (instant, no migration). Receive-side + envelope schema already shipped, unaffected.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Side-Effects Review — WS2-SEND-2: relationships send-side replication
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `ws2-send-2-relationships`
|
|
4
|
+
**Date:** `2026-06-15`
|
|
5
|
+
**Author:** `Instar Agent (echo)`
|
|
6
|
+
**Second-pass reviewer:** `not required` (no block/allow/lifecycle authority — pure additive, dark-gated data-replication wiring; see §4)
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Extends the WS2 send-side emission (proven end-to-end for `learnings` in #1168) to the `relationships` store — the first of the four "table-row" stores the WS2-SEND-SIDE-EMISSION-SPEC enumerates as WS2-SEND-2. Three edits, all mirroring the learnings slice: (1) `src/commands/server.ts` imports `buildRelationshipRecordData` + `buildRelationshipTombstoneData` and attaches the journal-backed `ReplicatedRecordEmitter` to `RelationshipManager.setReplicationEmitter` (emitPut/emitDelete → build\*RecordData), gated `if (replicatedRecordEmitter && relationships)`; (2) `src/core/ws2SendWiring.ts` moves `relationships` from `WS2_SEND_PENDING_STORES` to `WS2_SEND_WIRED_STORES`; (3) a new e2e round-trip test `tests/e2e/ws2-relationships-cross-instance.test.ts`. No decision-point surface is added — the only "decision" is the pre-existing dark gate (`isStoreEmissionEnabled`) inside the generic emitter.
|
|
11
|
+
|
|
12
|
+
## Decision-point inventory
|
|
13
|
+
|
|
14
|
+
- `ReplicatedRecordEmitter.emit` dark gate (`stateSync.relationships.enabled`) — **pass-through** — already exists; this change merely makes `relationships` a registered emit target. Default `false` ⇒ strict no-op.
|
|
15
|
+
- `RelationshipManager.save`/`delete` emit funnel — **pass-through** — the manager already fires emitPut@904 / emitDelete@695,734; this change attaches a real emitter where there was `undefined` (no-op).
|
|
16
|
+
- `ws2SendWiring` ratchet classification — **modify** — `relationships` reclassified PENDING→WIRED (it is now genuinely send-wired).
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. Over-block
|
|
21
|
+
|
|
22
|
+
No block/allow surface — over-block not applicable. The emitter never rejects a manager write; a null recordKey / null projection / over-cap record is a counted no-op inside `emit()` and the local write always succeeds.
|
|
23
|
+
|
|
24
|
+
## 2. Under-block
|
|
25
|
+
|
|
26
|
+
Not applicable (no block surface). The one "miss" worth naming: a relationship with NO channels has no cross-machine identity surface (`deriveRelationshipRecordKey` → null) and is intentionally not replicated — by design (REQ-D17), not a gap; such a record is local-only and surfaces nowhere on the peer.
|
|
27
|
+
|
|
28
|
+
## 3. Level-of-abstraction fit
|
|
29
|
+
|
|
30
|
+
Correct layer. The generic `ReplicatedRecordEmitter` + `ReplicatedStoreReader` substrate (built in #1168) is the right home; this change is a table-row registration onto it, exactly as the spec's `tracked-next-work` (WS2-SEND-2) prescribes. No new parallel mechanism; the disclosure-minimized projection lives in `RelationshipsReplicatedStore` where the receive-side schema already lives.
|
|
31
|
+
|
|
32
|
+
## 4. Signal vs authority compliance
|
|
33
|
+
|
|
34
|
+
Compliant. This adds NO blocking authority. The emitter is an additive, best-effort signal-producer: a failure (builder throw, journal fault) is swallowed + counted, never propagated, so the manager's local write can never fail because replication did (`@silent-fallback-ok` documented at both call sites). The union read is advisory (HIGH tier = append-both-and-flag; it injects both variants as hints, never blocks). Per `docs/signal-vs-authority.md`, this is a detector/replicator with no gate authority.
|
|
35
|
+
|
|
36
|
+
## 5. Interactions
|
|
37
|
+
|
|
38
|
+
- Shares `server.ts`'s single `replicatedRecordEmitter` + the existing `relationshipsUnionReader` (already constructed @3927, previously unconsumed for send). No double-fire: emitPut rides the single `save()` persistence funnel; emitDelete rides the single `delete()` path.
|
|
39
|
+
- Does not shadow or race learnings — distinct store key (`relationships` vs `learnings`), distinct journal kind (`relationship-record`).
|
|
40
|
+
- Touches the same `server.ts` + `ws2SendWiring.ts` as the other five WS2-SEND stores → those PRs must SERIALIZE (stated in the run plan); no parallel WS2-SEND PRs.
|
|
41
|
+
|
|
42
|
+
## 6. External surfaces
|
|
43
|
+
|
|
44
|
+
Dark by default (`multiMachine.stateSync.relationships.enabled` defaults false). With the flag off: byte-identical single-machine behavior — nothing crosses the wire, no external surface changes. With the flag on (multi-machine, opt-in): the disclosure-minimized, channel-keyed projection of a relationship crosses to paired machines — NEVER the local UUID `id`, NEVER the raw on-disk blob (REQ-M4). A received record is rendered as quoted `<replicated-untrusted-data>`, never authoritative for inbound-principal identity resolution (which stays local-only, REQ-M14). At-rest honesty already documented in the WS2.3 spec + CLAUDE.md relationships section.
|
|
45
|
+
|
|
46
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
47
|
+
|
|
48
|
+
**Replicated** — this IS a cross-machine replication path. Replication path: `RelationshipManager.save/delete` → `ReplicatedRecordEmitter.emit` → `CoherenceJournal.emitReplicatedRecord` (own-stream) → peer serve/apply → `ReplicatedPeerStreamReader.loadOriginRecords` → `relationshipsUnionReader` (no-clobber union, conflict-flagged). Identity across machines = the CHANNEL SET (not the per-machine UUID), so the same person on two machines collapses to one recordKey. Deletes propagate as channel-keyed tombstones so an erased person stays erased even on an offline-then-rejoining peer (REQ-D4). No user-facing notice surface (no one-voice gating needed). No topic-transfer state to strand. No generated URLs.
|
|
49
|
+
|
|
50
|
+
## 8. Rollback cost
|
|
51
|
+
|
|
52
|
+
Trivial. The feature is dark by default; if wrong in production it affects only agents that explicitly enabled `stateSync.relationships`. Back-out = revert the three-file commit (or set the flag false — instant, no restart-coupled data migration). The receive-side + envelope schema already shipped and are unaffected. No data migration, no agent-state repair.
|