instar 1.3.554 → 1.3.555

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.
@@ -0,0 +1,92 @@
1
+ # Side-Effects — multiMachine.stateSync memory stores → dev-gated (topic 13481)
2
+
3
+ **Change:** Re-gate the 7 `multiMachine.stateSync.*` cross-machine memory stores
4
+ (preferences, relationships, learnings, knowledge, evolutionActions, userRegistry,
5
+ topicOperator) from `DARK_GATE_EXCLUSIONS` (off for EVERYONE, including dev agents) to
6
+ `DEV_GATED_FEATURES` (live-on-dev / dark-fleet, `dryRun:false`), mirroring the
7
+ `subscriptionPool.credentialRepointing` precedent.
8
+
9
+ **Driver:** Operator directive (Justin, topic 13481, 2026-06-13): "NOTHING should ship dark
10
+ on development agents — every multi-machine feature must be live on dev agents so it
11
+ actually gets tested, not rot." A feature shipped dark everywhere never gets exercised; the
12
+ WS2 replicated-store family was in exactly that state.
13
+
14
+ **Spec:** `docs/specs/multi-machine-replicated-store-foundation.md` (the converged + approved
15
+ spec the 7 stores were built against). This is a follow-up gating fix to the merged WS2
16
+ stores, not a new feature.
17
+
18
+ ## What was wrong
19
+
20
+ The 7 stores shipped with a literal `enabled: false` in `ConfigDefaults.ts` and were
21
+ classified in `DARK_GATE_EXCLUSIONS` ("deliberate-fleet-default" — off for everyone,
22
+ including dev). That is the #1001 anti-pattern the §12.5 dark-gate lint forbids for a
23
+ dev-gated block: a written `enabled: false` literal force-darks even a development agent,
24
+ so the stores never ran ANYWHERE — they could never be dogfooded on Echo/the Mini and never
25
+ graduated.
26
+
27
+ ## What changed
28
+
29
+ - `src/core/devGatedFeatures.ts` — moved all 7 entries from `DARK_GATE_EXCLUSIONS` to
30
+ `DEV_GATED_FEATURES`, each keyed on `multiMachine.stateSync.<store>.enabled` (the wiring
31
+ tests now prove each resolves live-on-dev / dark-on-fleet).
32
+ - `src/config/ConfigDefaults.ts` — OMIT `enabled` from all 7 store blocks so the
33
+ developmentAgent gate decides; set `dryRun: false` (these stores replicate between the
34
+ operator's OWN machines with no destructive write, so unlike credentialRepointing they
35
+ need no write-safety dry-run canary — a dry-run would defeat "actually gets tested").
36
+ - `src/core/devAgentGate.ts` — NEW `resolveStateSyncStores(config)` helper: returns a new
37
+ stores map where each store's `enabled` is the gate-resolved boolean (raw `enabled` ??
38
+ `!!developmentAgent`), preserving every other per-store field (e.g. `dryRun`). Non-store
39
+ foundation knobs (numbers like `maxDriftMs`) pass through untouched.
40
+ - `src/commands/server.ts` — resolve the gate ONCE at the construction boundary
41
+ (`_stateSyncStoresResolved = resolveStateSyncStores(config)`) and feed that resolved map
42
+ into `selfStateSyncReceive`, all 7 `new ReplicatedStoreReader({ stores })` instances, and
43
+ `checkPoolFlagCoherence`. The funnels keep their unchanged `enabled === true` semantics —
44
+ they now read an already-resolved boolean, so a dev agent sees a LIVE flag. This is why
45
+ `ReplicatedStoreReader.ts`'s raw `.enabled === true` read is correct and was NOT touched.
46
+ - `src/server/routes.ts` — the `/preferences/session-context` route resolves the
47
+ `preferences` store's `enabled` via `resolveDevAgentGate(..., ctx.config)` so the route's
48
+ own gate and `ctx.preferencesUnionReader.isLive()` agree.
49
+ - `src/core/PostUpdateMigrator.ts` — NEW `migrateConfigStateSyncStoresDevGate(config)`:
50
+ strips ONLY the exact old-default signature `{ enabled:false, dryRun:true }` (2 keys, that
51
+ exact shape) per store, so `applyDefaults` backfills the new `{ dryRun:false }` and the
52
+ gate resolves `enabled`. Any divergence (operator-set `enabled:true`, a different dryRun,
53
+ extra keys) is treated as operator-touched and left ENTIRELY alone. Idempotent. Wired into
54
+ the migrate path (`upgraded`/`skipped` reporting), mirroring the credentialRepointing strip.
55
+ - `tests/unit/lint-dev-agent-dark-gate.test.ts` — the 7 stateSync `enabled:`-line entries
56
+ are GONE from the EXPECTED attribution map (the literals were removed from ConfigDefaults,
57
+ so they have no attributed enabled:false path — exactly like credentialRepointing); the
58
+ three cartographer entries below them shift up (1125→1100, 1170→1145, 1195→1170). Verified
59
+ via the attributor against the edited ConfigDefaults.
60
+
61
+ ## Behavioral impact
62
+
63
+ - **Dev agents (`developmentAgent: true`):** all 7 stores now resolve LIVE and `dryRun:false`
64
+ — replication genuinely runs so the family is dogfooded. Replication is between the
65
+ operator's OWN machines only: NO external egress, NO third-party spend. The PII stores
66
+ (relationships, userRegistry, topicOperator) carry the same at-rest honesty already
67
+ documented — at-rest plaintext per machine, transit-encrypted; an inbound-principal
68
+ RESOLUTION and "who is my verified operator?" stay LOCAL-authoritative (a replicated record
69
+ is untrusted advisory data). Fully reversible: the foundation's rollback-unmerge atomically
70
+ drops a peer's contribution on disable.
71
+ - **Fleet (`developmentAgent` unset/false):** UNCHANGED — all 7 stores resolve dark, a
72
+ strict no-op, exactly as before. A single-machine agent is a no-op regardless.
73
+ - **Reversibility:** set an explicit `multiMachine.stateSync.<store>.enabled: false` in
74
+ config to force-dark even a dev agent; an explicit `true` is the documented fleet-flip.
75
+
76
+ ## Migration parity
77
+
78
+ `applyDefaults` is add-missing-only deep-merge, so a new agent gets the omitted-`enabled` /
79
+ `dryRun:false` shape via `init`. Existing agents that already received the old
80
+ `{ enabled:false, dryRun:true }` per store would, under add-missing-only, keep that stale
81
+ shape (explicit values are not overwritten) and stay dark even on a dev agent — so
82
+ `migrateConfigStateSyncStoresDevGate` strips the exact old-default signature on update,
83
+ letting the gate resolve and `applyDefaults` backfill `dryRun:false`. An operator's
84
+ hand-edited block (any divergence from the exact signature) is never touched — reach is not
85
+ authority. The migration is idempotent (a second run finds nothing default-shaped to strip).
86
+
87
+ ## Tests
88
+
89
+ Unit: `state-sync-stores-dark-gate` (40), `PostUpdateMigrator-stateSyncStoresDevGate` (7),
90
+ the 5 ws2x wiring tests (ws22/23/24/25/26), `lint-dev-agent-dark-gate` (line-map recomputed),
91
+ `no-silent-fallbacks`, `feature-delivery-completeness` — all green locally. Typecheck clean
92
+ (`tsc --noEmit` exit 0). The full unit suite is left to CI (it is the authority).