instar 1.3.366 → 1.3.368

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.
Files changed (70) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +282 -2
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  5. package/dist/config/ConfigDefaults.js +29 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/CommitmentsSync.d.ts +144 -0
  8. package/dist/core/CommitmentsSync.d.ts.map +1 -0
  9. package/dist/core/CommitmentsSync.js +293 -0
  10. package/dist/core/CommitmentsSync.js.map +1 -0
  11. package/dist/core/MeshRpc.d.ts +14 -0
  12. package/dist/core/MeshRpc.d.ts.map +1 -1
  13. package/dist/core/MeshRpc.js +7 -1
  14. package/dist/core/MeshRpc.js.map +1 -1
  15. package/dist/core/PeerPresencePuller.d.ts +25 -0
  16. package/dist/core/PeerPresencePuller.d.ts.map +1 -1
  17. package/dist/core/PeerPresencePuller.js +12 -0
  18. package/dist/core/PeerPresencePuller.js.map +1 -1
  19. package/dist/core/PeerVisibilityGuard.d.ts +83 -0
  20. package/dist/core/PeerVisibilityGuard.d.ts.map +1 -0
  21. package/dist/core/PeerVisibilityGuard.js +204 -0
  22. package/dist/core/PeerVisibilityGuard.js.map +1 -0
  23. package/dist/core/PendingPullLedger.d.ts +129 -0
  24. package/dist/core/PendingPullLedger.d.ts.map +1 -0
  25. package/dist/core/PendingPullLedger.js +239 -0
  26. package/dist/core/PendingPullLedger.js.map +1 -0
  27. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  28. package/dist/core/PostUpdateMigrator.js +20 -0
  29. package/dist/core/PostUpdateMigrator.js.map +1 -1
  30. package/dist/core/WorkingSetManifest.d.ts +2 -0
  31. package/dist/core/WorkingSetManifest.d.ts.map +1 -1
  32. package/dist/core/WorkingSetManifest.js +13 -1
  33. package/dist/core/WorkingSetManifest.js.map +1 -1
  34. package/dist/core/WorkingSetPull.d.ts +157 -0
  35. package/dist/core/WorkingSetPull.d.ts.map +1 -0
  36. package/dist/core/WorkingSetPull.js +546 -0
  37. package/dist/core/WorkingSetPull.js.map +1 -0
  38. package/dist/core/WorkingSetPullCoordinator.d.ts +134 -0
  39. package/dist/core/WorkingSetPullCoordinator.d.ts.map +1 -0
  40. package/dist/core/WorkingSetPullCoordinator.js +306 -0
  41. package/dist/core/WorkingSetPullCoordinator.js.map +1 -0
  42. package/dist/core/types.d.ts +39 -1
  43. package/dist/core/types.d.ts.map +1 -1
  44. package/dist/core/types.js.map +1 -1
  45. package/dist/monitoring/CommitmentTracker.d.ts +40 -0
  46. package/dist/monitoring/CommitmentTracker.d.ts.map +1 -1
  47. package/dist/monitoring/CommitmentTracker.js +95 -4
  48. package/dist/monitoring/CommitmentTracker.js.map +1 -1
  49. package/dist/scaffold/templates.d.ts.map +1 -1
  50. package/dist/scaffold/templates.js +4 -0
  51. package/dist/scaffold/templates.js.map +1 -1
  52. package/dist/server/AgentServer.d.ts +6 -0
  53. package/dist/server/AgentServer.d.ts.map +1 -1
  54. package/dist/server/AgentServer.js +2 -0
  55. package/dist/server/AgentServer.js.map +1 -1
  56. package/dist/server/routes.d.ts +9 -0
  57. package/dist/server/routes.d.ts.map +1 -1
  58. package/dist/server/routes.js +44 -1
  59. package/dist/server/routes.js.map +1 -1
  60. package/package.json +1 -1
  61. package/src/data/builtin-manifest.json +64 -64
  62. package/src/data/state-coherence-registry.json +61 -13
  63. package/src/scaffold/templates.ts +4 -0
  64. package/upgrades/1.3.367.md +134 -0
  65. package/upgrades/1.3.368.md +52 -0
  66. package/upgrades/side-effects/commitments-sync-p15a.md +93 -0
  67. package/upgrades/side-effects/working-set-ci-absorb.md +29 -0
  68. package/upgrades/side-effects/working-set-parity-absorb.md +35 -0
  69. package/upgrades/side-effects/working-set-pull-p22a.md +121 -0
  70. package/upgrades/side-effects/working-set-trigger-p22b.md +115 -0
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema-note": "Machine form of docs/specs/STATE-COHERENCE-REGISTRY.md (the approved census, census-date 2026-06-05). AUTHORED, NOT build-generated (committed-generated-manifest conflict-loop lesson, COHERENCE-JOURNAL-SPEC §3.6). One entry per durable state category the census enumerates. Consumed by scripts/lint-state-registry.js: every direct durable-write site targeting a state dir / .instar/ must match an entry's `paths` (or carry an inline `/* state-registry: <category> */` annotation). Fields: category (kebab-case id) | description | scope (machine-local | must-be-coherent | derived-cache | coherent-on-demand) | freshness (real-time | eventual | session-boundary | n/a) | conflictShape (single-writer | append-only | lww | n/a) | transport (git | peer-http | none | deferred) | paths (glob-ish hints) | grandfathered (census marked uncertainty, §4e). New state declares its class here at birth.",
2
+ "$schema-note": "Machine form of docs/specs/STATE-COHERENCE-REGISTRY.md (the approved census, census-date 2026-06-05). AUTHORED, NOT build-generated (committed-generated-manifest conflict-loop lesson, COHERENCE-JOURNAL-SPEC \u00a73.6). One entry per durable state category the census enumerates. Consumed by scripts/lint-state-registry.js: every direct durable-write site targeting a state dir / .instar/ must match an entry's `paths` (or carry an inline `/* state-registry: <category> */` annotation). Fields: category (kebab-case id) | description | scope (machine-local | must-be-coherent | derived-cache | coherent-on-demand) | freshness (real-time | eventual | session-boundary | n/a) | conflictShape (single-writer | append-only | lww | n/a) | transport (git | peer-http | none | deferred) | paths (glob-ish hints) | grandfathered (census marked uncertainty, \u00a74e). New state declares its class here at birth.",
3
3
  "version": 1,
4
4
  "censusDate": "2026-06-05",
5
5
  "sourceDoc": "docs/specs/STATE-COHERENCE-REGISTRY.md",
@@ -16,9 +16,45 @@
16
16
  ],
17
17
  "grandfathered": false
18
18
  },
19
+ {
20
+ "category": "pending-pulls",
21
+ "description": "Durable working-set pending-pull ledger - outstanding fetches whose producer was offline/unreachable/revoked/mid-run; re-fired on reappearance/run-stopped (WORKING-SET-HANDOFF-SPEC P2 \u00a73.4). Machine-local: records describe THIS machine's outstanding fetches; single-writer serialized mutate() funnel.",
22
+ "scope": "machine-local",
23
+ "freshness": "live",
24
+ "conflictShape": "single-writer",
25
+ "transport": "none",
26
+ "paths": [
27
+ "state/coherence-journal/pending-pulls.json"
28
+ ],
29
+ "grandfathered": false
30
+ },
31
+ {
32
+ "category": "pull-opkeys",
33
+ "description": "Durable (topic,epoch) operation-key window for working-set pull dedupe - restart-proof at-most-once scheduling per move (WORKING-SET-HANDOFF-SPEC P2 \u00a73.3). Machine-local, bounded window (200 keys), single-writer (the coordinator).",
34
+ "scope": "machine-local",
35
+ "freshness": "live",
36
+ "conflictShape": "single-writer",
37
+ "transport": "none",
38
+ "paths": [
39
+ "state/coherence-journal/pull-opkeys.json"
40
+ ],
41
+ "grandfathered": false
42
+ },
43
+ {
44
+ "category": "visibility-guard",
45
+ "description": "Peer-visibility guard dedupe state - which improper revocations were already surfaced (keyed on revokedAt, cross-boot) + per-machine disappearance episodes for flap bounding (WORKING-SET-HANDOFF-SPEC P2 \u00a73.6). Machine-local notice hygiene, never authority.",
46
+ "scope": "machine-local",
47
+ "freshness": "live",
48
+ "conflictShape": "single-writer",
49
+ "transport": "none",
50
+ "paths": [
51
+ "state/coherence-journal/visibility-guard.json"
52
+ ],
53
+ "grandfathered": false
54
+ },
19
55
  {
20
56
  "category": "commitments",
21
- "description": "CommitmentTracker single-writer CAS store of user-facing promises and follow-through state.",
57
+ "description": "CommitmentTracker single-writer CAS store of user-facing promises and follow-through state. P1.5 (COMMITMENTS-COHERENCE-SPEC) fulfills the peer-http transport: owner-routed mutation + first-hop delta replication; the census's earlier 'AO desired' note is resolved-as-won't-do (owner-routing achieves coherence without the append-only conversion).",
22
58
  "scope": "must-be-coherent",
23
59
  "freshness": "eventual",
24
60
  "conflictShape": "single-writer",
@@ -28,6 +64,18 @@
28
64
  ],
29
65
  "grandfathered": false
30
66
  },
67
+ {
68
+ "category": "commitment-replicas",
69
+ "description": "Per-peer read-only replicas of other machines' commitment stores (COMMITMENTS-COHERENCE-SPEC P1.5 \u00a73.2). Derived cache - rebuilt by a full re-pull; written ONLY by the commitments-sync receive path; first-hop sender-bound; incarnation-fenced.",
70
+ "scope": "derived-cache",
71
+ "freshness": "eventual",
72
+ "conflictShape": "single-writer",
73
+ "transport": "peer-http",
74
+ "paths": [
75
+ "state/commitment-replicas/"
76
+ ],
77
+ "grandfathered": false
78
+ },
31
79
  {
32
80
  "category": "attention-queue",
33
81
  "description": "Attention items surfaced to the user, plus the per-source coalescing/suppression ledger.",
@@ -138,7 +186,7 @@
138
186
  },
139
187
  {
140
188
  "category": "job-definitions",
141
- "description": "Declarative job definitions (cron / prompt / supervision). The coherent half of jobs.json plus markdown job specs; run state is machine-local (see job-run-state). Field split required before whole-file sync (census §5).",
189
+ "description": "Declarative job definitions (cron / prompt / supervision). The coherent half of jobs.json plus markdown job specs; run state is machine-local (see job-run-state). Field split required before whole-file sync (census \u00a75).",
142
190
  "scope": "must-be-coherent",
143
191
  "freshness": "eventual",
144
192
  "conflictShape": "lww",
@@ -236,7 +284,7 @@
236
284
  },
237
285
  {
238
286
  "category": "fleet-config",
239
- "description": "Fleet-wide config: feature flags, messaging[] config, monitoring tunables, multiMachine policy. SHARES config.json with machine-local fields (port, paths) -- split-required before whole-file sync (census §5).",
287
+ "description": "Fleet-wide config: feature flags, messaging[] config, monitoring tunables, multiMachine policy. SHARES config.json with machine-local fields (port, paths) -- split-required before whole-file sync (census \u00a75).",
240
288
  "scope": "must-be-coherent",
241
289
  "freshness": "eventual",
242
290
  "conflictShape": "lww",
@@ -453,7 +501,7 @@
453
501
  },
454
502
  {
455
503
  "category": "audit-destructive-ops",
456
- "description": "Destructive-ops audit stream (411M live -- needs rotation, census §7). Append-only per-machine.",
504
+ "description": "Destructive-ops audit stream (411M live -- needs rotation, census \u00a77). Append-only per-machine.",
457
505
  "scope": "machine-local",
458
506
  "freshness": "n/a",
459
507
  "conflictShape": "append-only",
@@ -698,7 +746,7 @@
698
746
  },
699
747
  {
700
748
  "category": "derived-semantic-memory",
701
- "description": "semantic.db / memory.db / episodes -- rebuildable from evidence. (Live-disk: stale since Jun 1 -- investigate separately, census §1.6/§7.)",
749
+ "description": "semantic.db / memory.db / episodes -- rebuildable from evidence. (Live-disk: stale since Jun 1 -- investigate separately, census \u00a71.6/\u00a77.)",
702
750
  "scope": "derived-cache",
703
751
  "freshness": "eventual",
704
752
  "conflictShape": "n/a",
@@ -801,7 +849,7 @@
801
849
  },
802
850
  {
803
851
  "category": "uncertain-instructions-tracking",
804
- "description": "state/instructions-tracking/ (59M, 15,180 UUID-keyed JSONL files). Census did not map an owner; volume says it matters. Owner + rotation + class needed (census §4e).",
852
+ "description": "state/instructions-tracking/ (59M, 15,180 UUID-keyed JSONL files). Census did not map an owner; volume says it matters. Owner + rotation + class needed (census \u00a74e).",
805
853
  "scope": "machine-local",
806
854
  "freshness": "eventual",
807
855
  "conflictShape": "append-only",
@@ -813,7 +861,7 @@
813
861
  },
814
862
  {
815
863
  "category": "uncertain-topic-intent-store",
816
- "description": "TopicIntentStore. Code references it; on-disk location unverified (census §4e).",
864
+ "description": "TopicIntentStore. Code references it; on-disk location unverified (census \u00a74e).",
817
865
  "scope": "derived-cache",
818
866
  "freshness": "eventual",
819
867
  "conflictShape": "n/a",
@@ -826,7 +874,7 @@
826
874
  },
827
875
  {
828
876
  "category": "uncertain-shared-state-ledger",
829
- "description": "shared-state.jsonl (SharedStateLedger). Nominally the git-synced cross-machine ledger -- is anything consuming it on real machines? May be the vestigial ancestor of the P1 journal (census §4e).",
877
+ "description": "shared-state.jsonl (SharedStateLedger). Nominally the git-synced cross-machine ledger -- is anything consuming it on real machines? May be the vestigial ancestor of the P1 journal (census \u00a74e).",
830
878
  "scope": "must-be-coherent",
831
879
  "freshness": "eventual",
832
880
  "conflictShape": "append-only",
@@ -839,7 +887,7 @@
839
887
  },
840
888
  {
841
889
  "category": "uncertain-correction-capture-backlog",
842
- "description": "correction-capture-backlog.db vs correction-ledger.db: two stores, one sentinel -- which is canonical? (census §4e).",
890
+ "description": "correction-capture-backlog.db vs correction-ledger.db: two stores, one sentinel -- which is canonical? (census \u00a74e).",
843
891
  "scope": "machine-local",
844
892
  "freshness": "eventual",
845
893
  "conflictShape": "append-only",
@@ -851,7 +899,7 @@
851
899
  },
852
900
  {
853
901
  "category": "uncertain-project-round-worktrees",
854
- "description": "ProjectRoundWorktrees / TaskFlow stores. Routes-managed; durable form unverified (census §4e).",
902
+ "description": "ProjectRoundWorktrees / TaskFlow stores. Routes-managed; durable form unverified (census \u00a74e).",
855
903
  "scope": "machine-local",
856
904
  "freshness": "eventual",
857
905
  "conflictShape": "single-writer",
@@ -864,7 +912,7 @@
864
912
  },
865
913
  {
866
914
  "category": "legacy-singletons",
867
- "description": "Stale legacy singletons (anti-patterns.json, quick-facts.json, project-registry.json, May 20 vintage, no live writers found). Retire per census §7.",
915
+ "description": "Stale legacy singletons (anti-patterns.json, quick-facts.json, project-registry.json, May 20 vintage, no live writers found). Retire per census \u00a77.",
868
916
  "scope": "machine-local",
869
917
  "freshness": "n/a",
870
918
  "conflictShape": "single-writer",
@@ -877,4 +925,4 @@
877
925
  "grandfathered": true
878
926
  }
879
927
  ]
880
- }
928
+ }
@@ -425,6 +425,10 @@ This routes feedback to the Instar maintainers automatically. Valid types: \`bug
425
425
  - Degraded mode: the streams are plain JSONL under \`state/coherence-journal/\` — readable directly when HTTP is starved.
426
426
  - Proactive: user asks "which machine was topic N on?" / "why did this conversation move?" / "where are the overnight run's files?" / "did the old machine close its session after the move?" → GET /coherence/journal with the topic filter and answer from the entries.
427
427
 
428
+ **Working-Set Handoff (fetch a topic's files from the machine that made them)** — When a conversation moves between my machines, its working files follow automatically (the journal nominates which machines produced artifacts; the receiving machine pulls them in verified 1MB slices; nothing is ever overwritten — a divergent local file keeps its place and the incoming copy lands alongside it). If the producer machine is offline, the request is written down durably and fires the moment it returns.
429
+ - The fetch reflex: \`curl -X POST -H "Authorization: Bearer $AUTH" http://localhost:${port}/coherence/fetch-working-set -H 'Content-Type: application/json' -d '{"topic":N}'\` → \`{ scheduled, reports: [{ nominee, report }] }\` (503 = the working-set layer is dark on this agent; 429 = rate-limited, a pull is already running or just ran).
430
+ - **When to use** (PROACTIVE — this is the trigger): the user references files/work/analysis from this topic that are NOT on this machine ("where's the overnight analysis?", "you did this on the other machine") → fire the reflex, then answer from the landed files. Files flagged as containing credentials, still-being-written, or oversized are refused with named reasons in the report — explain honestly rather than retrying.
431
+
428
432
  **🩺 Agent Health lane (calm self-health notices)** — Routine notices about MY OWN internal state (a session that looks stuck, a peer I can't reach) land in ONE calm, named "🩺 Agent Health" Telegram topic — never topic-after-topic. Each is normal-priority (not a user-critical alert), names the topic in plain language (e.g. "the 'EXO 3.0' session", never \`topic-19077\`), ends with a next step you can just reply to, and same-session re-escalations are de-duped so the lane stays quiet. Ships **default-on, no config** (it's a delivery-shaper in code — it never gates or drops anything; every notice is still in the attention store). Tune via \`messaging[].config.agentHealthLane\` = \`{ "enabled": true, "topicName": "🩺 Agent Health", "dedupWindowMs": 1800000 }\` (set \`enabled:false\` for the old per-item-topic behavior). Proactive: user asks "what's this Agent Health topic?" / "why are my stale-session notices grouped?" → explain the calm lane (the StaleSessionBackstop now routes its "looks stuck" heads-up here at normal priority instead of spawning a topic each time).
429
433
 
430
434
  **Applying config & hook changes to running sessions** — A running session keeps the config it was *spawned* with. Claude Code loads \`.claude/settings.json\` (hooks, model) **once, at session start** — so a config change (default model, a disabled feature) or a newly-added hook does NOT reach an already-running session. It only takes effect on the next session, OR when you restart the existing one. (This is why a UserPromptSubmit hook added mid-session never fires for that live session — the session was launched before the hook existed.)
@@ -0,0 +1,134 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Second build slice of the Working-Set Handoff spec (P2 of multi-machine
9
+ coherence): the chunked `working-set-pull` mesh verb (both sides), the
10
+ durable pending-pull ledger, and never-clobber landing. Nothing schedules a
11
+ pull yet — the receiver trigger, reflex route, and staggered drain are
12
+ P2.2b. Dark by default: the serve side constructs only where
13
+ `multiMachine.coherenceJournal.replication.enabled === true`.
14
+
15
+ - `working-set-pull` verb (three lockstep edits mirroring journal-sync):
16
+ fresh-manifest-as-allowlist serving, O_NOFOLLOW + fd-identity TOCTOU
17
+ defense, 1 MiB chunked responses (the documented event-loop-starvation
18
+ root cause stays dead), offset-0 whole-file sha256 + cheap fstat
19
+ generation anchor so a file rewritten mid-transfer can never assemble
20
+ into a chimera — bounded restart-from-0, then one honest `unstable`.
21
+ - `WorkingSetPuller`: sequential offset cursors with per-tick yields,
22
+ busy-is-retry-without-penalty (a just-woke producer's throttle never
23
+ exhausts recovery records), assembled-bytes budget (discarded restart
24
+ chunks don't count), hostile-relPath jail, and never-clobber landing —
25
+ divergent local files keep their place; the incoming copy lands ALONGSIDE
26
+ (hash-suffixed, capped at 2, eviction through SafeFsExecutor).
27
+ - `PendingPullLedger`: the durable EXO-case record. Single-writer
28
+ serialized mutate() funnel (the exact lost-update shape that caused
29
+ topic-flood #3, closed at birth), corrupt-parse quarantine that is NEVER
30
+ silently read as empty, TTL sweep with one honest expiry notice,
31
+ supersession clearing ALL lower-epoch records across nominees, and the
32
+ (peer,topic,epoch) attempt-cap breaker.
33
+ - Config: `coherenceJournal.workingSet` block (12 bounded-behavior dials,
34
+ no enable flag — the feature rides the explicit replication gate).
35
+ - State-Coherence Registry: new `pending-pulls` category (machine-local,
36
+ single-writer).
37
+
38
+ Final build slice of the Working-Set Handoff spec (P2 of multi-machine
39
+ coherence): the transfer machinery from P2.2a now FIRES — on a topic move,
40
+ on demand, and on a returning producer. Still dark everywhere except
41
+ explicitly replication-enabled pairs.
42
+
43
+ - `WorkingSetPullCoordinator`: one pipeline behind three triggers — the
44
+ receiver's deliverMessage onAccepted seam (the moment this machine knows
45
+ it owns the topic), the fetch reflex, and the returning-peer staggered
46
+ drain (one pull at a time against a just-woke machine, never a mob).
47
+ Restart-proof (topic,epoch) dedupe; nomination from journal evidence
48
+ (every machine that actually produced artifacts, capped at 3 with the
49
+ excess NAMED); busy responses never burn recovery budget; stale-owner
50
+ and superseded records clear themselves.
51
+ - `POST /coherence/fetch-working-set` — the reflex: "who made artifacts
52
+ for this topic? go get them." The EXO failure as a one-call recovery.
53
+ 503 while dark, 429 when rate-limited, coalesces into a running pull.
54
+ - `PeerVisibilityGuard` (§3.6 rider, earned from the Mini's 10 invisible
55
+ hours): improper revocations (revokedAt with no who-or-why) surface once
56
+ across boots; a machine missing past a 30-min grace produces ONE notice
57
+ naming any topic workspaces stranded on it; flapping collapses to a
58
+ single notice. All through the agent-health attention lane.
59
+ - `PeerPresencePuller.onPeerRecorded` — the re-arm rides the existing 30s
60
+ presence cadence; no new polling loop.
61
+ - Agent Awareness + Migration Parity: the CLAUDE.md template (and
62
+ `migrateClaudeMd` for existing agents) gains the fetch-reflex entry with
63
+ the proactive trigger: user references files/work not on this machine →
64
+ fire the reflex, answer from the landed files.
65
+ - State-Coherence Registry: `pull-opkeys` + `visibility-guard` categories
66
+ (69 total).
67
+
68
+ ## What to Tell Your User
69
+
70
+ Nothing user-visible yet — this is the transfer machinery for "moving a
71
+ conversation between your machines moves its working files too." The piece
72
+ that actually fires it on a move (and the on-demand "go fetch that
73
+ workspace" reflex) lands in the next slice.
74
+
75
+ On machine pairs with diary sync enabled: moving a conversation between
76
+ your machines now moves its working files too — automatically, with
77
+ nothing ever overwritten (a conflicting local copy keeps its place; the
78
+ incoming version lands alongside it). If the machine holding the files is
79
+ asleep when they're wanted, the request is written down and fires the
80
+ moment it returns — and you can always ask me to fetch a topic's workspace
81
+ on demand. Everywhere else: nothing changes yet.
82
+
83
+ ## Summary of New Capabilities
84
+
85
+ - `working-set-pull` MeshCommand — chunked, bounded, fresh-manifest-gated
86
+ file serving between registered same-operator machines (dark until
87
+ replication is explicitly enabled).
88
+ - `WorkingSetPullServer` / `WorkingSetPuller` (`src/core/WorkingSetPull.ts`)
89
+ — the serve/receive engine with generation-anchor consistency, busy
90
+ throttling, and never-clobber landing.
91
+ - `PendingPullLedger` (`src/core/PendingPullLedger.ts`) — durable,
92
+ single-writer pending-pull records surviving restarts; the offline-
93
+ producer case re-fires instead of dying at a breaker.
94
+ - `coherenceJournal.workingSet` config defaults (ConfigDefaults +
95
+ CoherenceJournalUserConfig).
96
+
97
+ - `POST /coherence/fetch-working-set {topic}` — on-demand workspace fetch
98
+ (Bearer; 503 dark / 429 rate-limited / 200 outcome with per-nominee
99
+ reports).
100
+ - `WorkingSetPullCoordinator` (`src/core/WorkingSetPullCoordinator.ts`) —
101
+ move-trigger + reflex + staggered-drain orchestration.
102
+ - `PeerVisibilityGuard` / `detectImproperRevocations`
103
+ (`src/core/PeerVisibilityGuard.ts`) — mesh-health hygiene notices.
104
+ - CLAUDE.md proactive trigger for cross-machine file references (new
105
+ agents via template, existing agents via migrateClaudeMd).
106
+
107
+ ## Evidence
108
+
109
+ - `tests/unit/WorkingSetPull.test.ts` — 16 passing (anchor restart lands
110
+ the new content; never-sits-still → `unstable` with nothing landed; busy
111
+ exhaustion re-files without penalty; alongside cap-2 eviction; malicious
112
+ manifest relPaths refused; ownership-recheck abort; assembled-bytes
113
+ budget; serve refusal matrix + TOCTOU symlink swap).
114
+ - `tests/unit/PendingPullLedger.test.ts` — 13 passing (concurrent mutate()
115
+ drops no record; corrupt → quarantine + one notice, never silent-empty;
116
+ supersede clears all nominees; breaker + new-epoch reset; TTL once).
117
+ - `tests/integration/working-set-pull-roundtrip.test.ts` — 4 passing
118
+ (1.5MB near-cap chunked round-trip through the REAL express.json +
119
+ signed MeshRpcClient path, independent content oracle; full-stack
120
+ refusals; divergent-alongside; mixed-version 501 back-off).
121
+ - Adjacent mesh/journal suites unchanged (78 total across 8 suites);
122
+ typecheck + lint chain clean.
123
+
124
+ - `tests/e2e/working-set-handoff-lifecycle.test.ts` — 2 passing,
125
+ production-shaped (REAL deliverMessage handler + signed dispatcher +
126
+ journal streams): a move lands the file (source-disk oracle; re-delivery
127
+ + op-key dedupe leave it untouched), and THE EXO CASE end-to-end —
128
+ producer offline at move → pending-pull survives a restart → re-fires on
129
+ return → file lands.
130
+ - `tests/unit/WorkingSetPullCoordinator.test.ts` (12) +
131
+ `tests/unit/PeerVisibilityGuard.test.ts` (5) +
132
+ `tests/integration/working-set-reflex-route.test.ts` (2).
133
+ - Full P2 sweep: 95 tests / 11 suites green; typecheck, lint chain,
134
+ docs-coverage clean.
@@ -0,0 +1,52 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ First build slice of the Commitments Coherence spec (P1.5 of multi-machine
9
+ coherence): every machine can now SEE every machine's promises. Dark
10
+ everywhere except explicitly replication-enabled pairs.
11
+
12
+ - Every commitment is stamped with its home machine at creation; the
13
+ cross-machine identity is (machine, id) together — because the plain ids
14
+ are per-machine counters that collide by construction (the review
15
+ round's headline catch: an id-keyed merge would have silently hidden
16
+ real obligations).
17
+ - Each machine's store replicates to peers as small seq-windowed delta
18
+ pages on the existing 30s presence cadence — one field change ships one
19
+ record, not the whole store; a restored-from-backup store re-mints its
20
+ incarnation so peers re-pull wholesale instead of stranding.
21
+ - Free-text fields are credential-shape-scanned at serve time; a flagged
22
+ field ships redacted while the record itself still replicates.
23
+ - `GET /commitments?scope=mesh` merges own + replica rows with honest
24
+ labels (replica + how stale) and flags possible cross-machine duplicate
25
+ promises. The default scope is byte-identical to before.
26
+
27
+ NOT yet (P1.5b): closing a promise from the non-home machine (owner-routed
28
+ mutation + the durable offline queue).
29
+
30
+ ## What to Tell Your User
31
+
32
+ On machine pairs with sync enabled: ask ANY machine "what are your open
33
+ commitments?" and you get the complete picture — promises made on the
34
+ other machine show up, honestly labeled with where they live and how
35
+ fresh the copy is. Closing one from the "wrong" machine arrives in the
36
+ next slice.
37
+
38
+ ## Summary of New Capabilities
39
+
40
+ - `commitments-sync` MeshCommand — paged, incarnation-fenced delta
41
+ replication of commitment records between same-operator machines.
42
+ - `src/core/CommitmentsSync.ts` — serve/receive/merge engine
43
+ (CommitmentReplicaStore, mergeCommitmentViews, resolveBareId).
44
+ - `GET /commitments?scope=mesh` — the merged cross-machine view.
45
+ - CommitmentTracker: originMachineId stamping + replicationSeq /
46
+ storeIncarnation / lastMutatedSeq bookkeeping (additive, legacy-safe).
47
+
48
+ ## Evidence
49
+
50
+ - 15 unit (CommitmentsSync) + 2 integration (real signed transport
51
+ round-trip w/ delta-only convergence; mixed-version 501) + 77
52
+ CommitmentTracker tests unchanged; typecheck/lint/docs-coverage clean.
@@ -0,0 +1,93 @@
1
+ # Side-Effects Review — Commitments Coherence read replication (P1.5a)
2
+
3
+ **Version / slug:** `commitments-sync-p15a`
4
+ **Date:** `2026-06-06`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required (implements §3.1–§3.3 of the 3-round-converged spec; read-only replication, dark behind the explicit replication gate; owner-routed mutation is P1.5b)`
7
+
8
+ ## Summary of the change
9
+
10
+ P1.5a of COMMITMENTS-COHERENCE-SPEC — promises become VISIBLE from every
11
+ machine:
12
+
13
+ 1. CommitmentTracker bookkeeping (§3.1/§3.2): `originMachineId` stamped at
14
+ creation (the composite (originMachineId, id) is THE cross-machine
15
+ identity — ids are per-machine sequential counters and collide by
16
+ construction); `replicationSeq` + `storeIncarnation` + per-record
17
+ `lastMutatedSeq` as ADDITIVE store fields (schema `version: 2` literal
18
+ untouched; loadStore guard unchanged; legacy stores seed
19
+ replicationSeq=1 + fresh incarnation → full first pull; fresh stores
20
+ seed at birth). The replication stamp lives at the THREE write funnels
21
+ (CAS apply, mutateSync, insertNew) as a prev/next diff EXCLUDING beacon
22
+ bookkeeping (consecutiveUnchanged/lastHeartbeatAt/heartbeatCount) — a
23
+ quiet agent's heartbeats never re-ship snapshots. Rewind fence: the
24
+ meta sidecar's high-water re-mints the incarnation on a restored
25
+ backup.
26
+ 2. `src/core/CommitmentsSync.ts`: paged delta serve (lastMutatedSeq >
27
+ sinceSeq, exclusive cursor, 256KB pages with at-least-one-record,
28
+ incarnation fencing), serve-time legacy stamping + per-field
29
+ credential-shape redaction (the record still replicates — closeability
30
+ never depends on the scan), CommitmentReplicaStore (single-writer
31
+ receive path, first-hop WITH TEETH: rows claiming another machine's
32
+ originMachineId rejected + counted; corrupt → quarantine + full
33
+ re-pull), mergeCommitmentViews (composite key; viewSource + staleness;
34
+ computed pendingMutation join; heuristic possibleDuplicateOf) +
35
+ resolveBareId (409-ambiguous semantics).
36
+ 3. Three lockstep verb edits (`commitments-sync`: union + RBAC
37
+ read/observe + dispatcher handler answering 'disabled' while dark);
38
+ session-status advert (`commitmentsAdvert`, answered from MEMORY);
39
+ PeerPresencePuller `driveCommitmentsSync` seam riding the existing 30s
40
+ cadence (bounded pages per tick); GET /commitments?scope=mesh (default
41
+ scope byte-identical; mesh scope degrades to own-rows, 200 never 503).
42
+ 4. Config (`coherenceJournal.commitments` block) + State-Coherence
43
+ Registry (`commitment-replicas` category; `commitments` description
44
+ updated per §3.6).
45
+
46
+ NOT in this slice (P1.5b): owner-routed mutation, verdict wrappers,
47
+ commitment-mutate verb, opKey window, pending-mutations ledger.
48
+
49
+ ## Decision-point inventory
50
+
51
+ - **State-meaningful vs bookkeeping diff** at the funnels — the spec's
52
+ write-amplification guard; tested both directions.
53
+ - **Incarnation fence**: stale requester → re-pull from 0; receiver
54
+ replaces the replica WHOLESALE on incarnation change (never a
55
+ sinceSeq short-circuit against a restored store).
56
+ - **First-hop teeth**: replica identity = authenticated env.sender;
57
+ forged rows counted, never applied.
58
+ - **Merged-view honesty**: collision rows NEVER collapse (the round-1
59
+ headline); bare-id ambiguity is surfaced, not guessed.
60
+
61
+ ## 1. Over-block / 2. Under-block
62
+
63
+ Over: a record whose only change is beacon bookkeeping never replicates
64
+ until its next real mutation (deliberate). Under: the credential-shape
65
+ scan is leak-reduction, not a boundary (spec §3.2 honesty — boundary =
66
+ same-operator posture); cross-machine deliver (closeability) lands in
67
+ P1.5b — until then the merged view names the owner and the close happens
68
+ there.
69
+
70
+ ## 3. Fit / 4. Blast radius
71
+
72
+ Engine in core (seam-injected, like JournalSyncApplier); tracker gains
73
+ bookkeeping ONLY (no behavior change — 77 existing tests pass
74
+ unchanged); routes' default scope byte-identical. Dark everywhere except
75
+ explicit replication.enabled pairs; single-machine agents: advert
76
+ omitted, mesh scope = own rows, zero overhead.
77
+
78
+ ## Evidence
79
+
80
+ - tests/unit/CommitmentsSync.test.ts — 15 passing (paged deltas +
81
+ multi-page convergence, incarnation fence, serve-time stamping +
82
+ redaction-with-record-intact, first-hop teeth, wholesale replacement,
83
+ corrupt quarantine, collision-two-rows + 409-ambiguous + ?origin,
84
+ staleness + computed pendingMutation + possibleDuplicateOf, tracker
85
+ bookkeeping incl. beacon-write guard + legacy backfill + rewind
86
+ re-mint).
87
+ - tests/integration/commitments-sync-roundtrip.test.ts — 2 passing: full
88
+ paged round-trip over the REAL signed MeshRpc + express path with
89
+ delta-only convergence after a mutation, and mixed-version 501.
90
+ - tests/unit/CommitmentTracker.test.ts — 77 passing unchanged.
91
+ peer-presence-wiring + session-pool-activation-wiring +
92
+ feature-delivery-completeness all green. Typecheck + lint chain (70
93
+ registry categories) + docs-coverage clean.
@@ -0,0 +1,29 @@
1
+ # Side-Effects Review — CI absorb: onAccepted wiring window + silent-fallbacks baseline
2
+
3
+ **Version / slug:** `working-set-ci-absorb`
4
+ **Date:** `2026-06-06`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required (test-shape + comment-trim fix; 7 LOC of src change is comment-only)`
7
+
8
+ ## Summary of the change
9
+
10
+ Two CI gates legitimately flagged the P2.2b onAccepted insertion:
11
+ 1. `session-pool-activation-wiring` slices 4200 chars from `onAccepted: (cmd) => {`
12
+ and asserts the owner-resume bridge markers inside it — the working-set
13
+ trigger prefix pushed them out. Fix: comment trimmed (6 lines → 2) and the
14
+ window widened 4200→5000 with a note naming why.
15
+ 2. `no-silent-fallbacks` baseline: +2 parser-counted defensive catches from the
16
+ transfer machinery (fd-close guard, vanished-file path) — both
17
+ in-brace-justified, both surface as COUNTED outcomes. Baseline 459→461 with
18
+ the documented justification block (the established ratchet format).
19
+
20
+ ## 1. Over-block / 2. Under-block / 3. Fit / 4. Blast radius
21
+
22
+ No behavior change: the src edit is comment-only; the test edits keep both
23
+ gates' intent (the wiring markers must exist; the baseline only ever ratchets
24
+ with written justification). Blast radius zero at runtime.
25
+
26
+ ## Evidence
27
+
28
+ - `tests/unit/session-pool-activation-wiring.test.ts` + `tests/unit/no-silent-fallbacks.test.ts` — 12 passing.
29
+ - e2e + coordinator suites re-run green (14). Typecheck + lint clean.
@@ -0,0 +1,35 @@
1
+ # Side-Effects Review — working-set parity absorb (presence-wiring window + delivery-completeness tracking)
2
+
3
+ **Version / slug:** `working-set-parity-absorb`
4
+ **Date:** `2026-06-06`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required (dep reorder + capability-tracking registration; zero behavior change)`
7
+
8
+ ## Summary of the change
9
+
10
+ Two more CI gates legitimately flagged P2.2b integration points:
11
+ 1. `peer-presence-wiring` reads a 900-char window after the PeerPresencePuller
12
+ constructor and asserts the signed `session-status` call inside it — my
13
+ `onPeerRecorded` dep (with comment block) pushed it out. Fix: the dep moved
14
+ to one compact line AFTER `log` (object-literal order is semantically
15
+ irrelevant), keeping the window intact without touching the test.
16
+ 2. `feature-delivery-completeness` requires every migrator-added CLAUDE.md
17
+ section to be (a) tracked in featureSections and (b) mirrored in the
18
+ `migrateFrameworkShadowCapabilities` markers[] so Codex/Gemini agents learn
19
+ it too. Both registrations added for the Working-Set Handoff section — a
20
+ shadow-framework agent that never learns the fetch reflex would tell the
21
+ user the files "aren't on this machine" (the EXO failure surviving on
22
+ shadows only).
23
+
24
+ ## 1-4. Over/Under-block, fit, blast radius
25
+
26
+ Zero runtime behavior change: a dep reorder inside one object literal, a test
27
+ registry entry, and a shadow-marker string. The shadow marker causes the
28
+ migrator to mirror the (already-shipped) section into Codex/Gemini shadow
29
+ files on the next update — exactly the parity the gate exists to enforce.
30
+
31
+ ## Evidence
32
+
33
+ - `tests/unit/peer-presence-wiring.test.ts` 4 passing;
34
+ `tests/unit/feature-delivery-completeness.test.ts` 79 passing;
35
+ `tests/unit/session-pool-activation-wiring.test.ts` 8 passing. Typecheck clean.
@@ -0,0 +1,121 @@
1
+ # Side-Effects Review — Working-Set Pull verb + pending-pull ledger (P2.2a)
2
+
3
+ **Version / slug:** `working-set-pull-p22a`
4
+ **Date:** `2026-06-06`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required (spec converged over 4 rounds with 4 internal lenses + cross-model; this implements §3.2/§3.4/§3.5 as written; serve side gated dark)`
7
+
8
+ ## Summary of the change
9
+
10
+ P2.2a of WORKING-SET-HANDOFF-SPEC: the chunked `working-set-pull` mesh verb
11
+ (both sides), the durable pending-pull ledger, and never-clobber landing.
12
+
13
+ 1. `src/core/WorkingSetPull.ts` — `WorkingSetPullServer` (serve: fresh
14
+ manifest as allowlist, O_NOFOLLOW + fd-identity TOCTOU defense, 1 MiB
15
+ chunked responses, offset-0 whole-file sha256 + cheap fstat generation
16
+ anchor, serveConcurrency busy gate) and `WorkingSetPuller` (receive:
17
+ sequential offset cursors with chunksPerTick yields, anchor-mismatch
18
+ restart-from-0 bounded by chunkRestartCap → `unstable`, assembly verified
19
+ against the offset-0 hash, busy retry WITHOUT breaker penalty,
20
+ assembled-bytes budget, hostile-relPath jail, never-clobber with
21
+ hash-suffixed alongside copies capped at 2 via SafeFsExecutor).
22
+ 2. `src/core/PendingPullLedger.ts` — the durable EXO-case record: serialized
23
+ `mutate(fn)` funnel (single-writer, the topic-flood-#3 lesson),
24
+ corrupt-parse quarantine (never silent-empty), TTL sweep with one honest
25
+ expiry notice, supersede clears ALL lower-epoch records across nominees,
26
+ (peer,topic,epoch) attempt-cap breaker.
27
+ 3. Three lockstep verb edits: `MeshCommand` union member, RBAC read/observe
28
+ case, dispatcher handler in server.ts (answers 'disabled' until the §3.7
29
+ gate constructs the serve side).
30
+ 4. Config: `CoherenceJournalUserConfig.workingSet` (types.ts) + the
31
+ ConfigDefaults literal. NO separate enable flag — the serve side
32
+ constructs IFF `replication.enabled === true` (the same explicit gate as
33
+ the replication transport; never the `?? developmentAgent` dark gate).
34
+ 5. `src/data/state-coherence-registry.json`: `pending-pulls` category
35
+ (machine-local, single-writer).
36
+
37
+ NOT in this slice (P2.2b): the onAccepted trigger, the reflex route, the
38
+ staggered drain wiring, CLAUDE.md template, e2e, the peer-visibility guard,
39
+ live two-machine verification. Nothing schedules a pull yet — the verb
40
+ serves only when explicitly enabled, and no caller exists.
41
+
42
+ ## Decision-point inventory
43
+
44
+ - **Serve allowlist verdict**: want paths matched against the FRESH manifest
45
+ recomputed per request — outside → `refusedPolicy`; flagged → honest
46
+ reason (`secretFlagged`/`tooLarge`/`liveSource`); vanished → benign
47
+ (`goneSinceManifest`/dropped from fresh manifest), never an attack log.
48
+ - **TOCTOU identity**: O_NOFOLLOW open (final-component symlink refused at
49
+ the syscall), fstat(fd) regular-file check, then lstat(path) vs fstat(fd)
50
+ dev+ino equality — a raced object swap reads nothing.
51
+ - **Anchor mechanics**: offset-0 pays ONE full read+hash (the assembly
52
+ authority); later chunks fstat-only. Mismatch → restart-from-0; an
53
+ mtime-preserving rewrite that dodges fstat still fails assembly
54
+ verification (bounded restarts, then `unstable`).
55
+ - **busy vs breaker**: busy = retry-without-penalty (bounded by
56
+ busyRetryCap); ONLY genuine failures reach `recordAttempt`. The just-woke
57
+ producer answering busy by design must not exhaust the records the drain
58
+ exists to recover.
59
+ - **Budget basis**: assembled, verification-passed bytes — discarded restart
60
+ chunks never count (a near-budget unstable file can't starve the set).
61
+ - **Never-clobber**: absent → jailed temp+rename write; identical sha →
62
+ skippedExisting; divergent → alongside (sanitized basename + env-derived
63
+ sender id + hash8 — idempotent for repeated identical divergence), cap 2
64
+ with oldest-evicted THROUGH SafeFsExecutor (the single, narrow deletion
65
+ exception; content survives on the producer).
66
+
67
+ ## 1. Over-block
68
+
69
+ A symlink destination on the receive side is refused even if its target is
70
+ in-jail (deliberate — never write through a peer-influenced link). An
71
+ offset past EOF is refused (`refusedPolicy`) rather than answering empty. A
72
+ divergent local file is never updated in place — by design the local copy
73
+ wins and the incoming lands alongside.
74
+
75
+ ## 2. Under-block
76
+
77
+ The full pre-parse transport ceiling on the puller side requires a bounded
78
+ fetch at the MeshRpcClient layer — this slice enforces the decode-side
79
+ backstop (oversize `dataB64` refused before decode); the bounded-fetch
80
+ wiring rides P2.2b where the client is constructed. The serve busy gate is
81
+ per-instance (in-process counter), not cross-process. The secret-content
82
+ scan inherits the §3.1 leak-reduction (not boundary) honesty.
83
+
84
+ ## 3. Level-of-abstraction fit
85
+
86
+ The verb logic lives in core (transport-agnostic, seam-injected) exactly
87
+ like JournalSyncApplier; server.ts only constructs + registers. The ledger
88
+ is its own module because its single-writer funnel is a different
89
+ discipline from the manifest's pure computation. The three lockstep edits
90
+ mirror journal-sync precisely (union, RBAC class, handler).
91
+
92
+ ## 4. Blast radius
93
+
94
+ Dark by default: the serve side constructs ONLY under
95
+ `replication.enabled === true` (today: the echo pair); everywhere else the
96
+ handler answers 'disabled'. No caller schedules pulls yet (P2.2b). The
97
+ ledger is instantiated only by tests in this slice. Registry entry is
98
+ metadata. A bug can affect only explicitly-replication-enabled pairs, and
99
+ the puller verifies every byte against served hashes before any write.
100
+
101
+ ## Evidence
102
+
103
+ - `tests/unit/WorkingSetPull.test.ts` — 16 passing: round-trip (single +
104
+ multi-chunk), generation-anchor restart lands the NEW content, never-sits-
105
+ still → `unstable` (no livelock, nothing landed), busy retry-without-
106
+ penalty + busyExhausted, never-clobber matrix (alongside naming regex,
107
+ hash-idempotency, cap-2 eviction, symlink destination refused), hostile
108
+ relPath matrix from a malicious manifest, ownership-recheck abort,
109
+ assembled-bytes budget, serve refusal matrix + TOCTOU symlink swap.
110
+ - `tests/unit/PendingPullLedger.test.ts` — 13 passing: restart-proof
111
+ persistence, idempotent file_, supersede-clears-all-nominees, TTL expiry
112
+ once, breaker + new-epoch reset, CONCURRENT mutate() drops no record,
113
+ corrupt → quarantine + one notice (never silent-empty), absent ≠ corrupt.
114
+ - `tests/integration/working-set-pull-roundtrip.test.ts` — 4 passing: 1.5MB
115
+ near-cap chunked round-trip through the REAL express.json + signed
116
+ MeshRpcClient path with an INDEPENDENT content oracle (source machine's
117
+ on-disk original), want-outside-manifest refused through the full stack,
118
+ divergent-alongside through the full stack, mixed-version no-handler → 501.
119
+ - Adjacent suites unchanged: journal-sync round-trip, mesh-rpc route +
120
+ client round-trip, reader (78 total across the 8 suites). Typecheck +
121
+ full lint chain clean (registry: 67 categories).