instar 1.3.365 → 1.3.367

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 +200 -1
  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 +18 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/IntentTestHarness.d.ts +27 -0
  8. package/dist/core/IntentTestHarness.d.ts.map +1 -1
  9. package/dist/core/IntentTestHarness.js +91 -0
  10. package/dist/core/IntentTestHarness.js.map +1 -1
  11. package/dist/core/MeshRpc.d.ts +8 -0
  12. package/dist/core/MeshRpc.d.ts.map +1 -1
  13. package/dist/core/MeshRpc.js +6 -1
  14. package/dist/core/MeshRpc.js.map +1 -1
  15. package/dist/core/PeerPresencePuller.d.ts +6 -0
  16. package/dist/core/PeerPresencePuller.d.ts.map +1 -1
  17. package/dist/core/PeerPresencePuller.js +5 -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 +43 -1
  43. package/dist/core/types.d.ts.map +1 -1
  44. package/dist/core/types.js.map +1 -1
  45. package/dist/redteam/ScenarioPack.d.ts +30 -3
  46. package/dist/redteam/ScenarioPack.d.ts.map +1 -1
  47. package/dist/redteam/ScenarioPack.js +46 -1
  48. package/dist/redteam/ScenarioPack.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 +3 -0
  53. package/dist/server/AgentServer.d.ts.map +1 -1
  54. package/dist/server/AgentServer.js +1 -0
  55. package/dist/server/AgentServer.js.map +1 -1
  56. package/dist/server/routes.d.ts +5 -0
  57. package/dist/server/routes.d.ts.map +1 -1
  58. package/dist/server/routes.js +47 -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 +48 -12
  63. package/src/scaffold/templates.ts +4 -0
  64. package/upgrades/{1.3.365.md → 1.3.366.md} +35 -0
  65. package/upgrades/1.3.367.md +134 -0
  66. package/upgrades/side-effects/intent-llm-judge.md +94 -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
@@ -0,0 +1,134 @@
1
+ /**
2
+ * WorkingSetPullCoordinator — P2.2b of multi-machine coherence: the
3
+ * orchestration layer that makes the working-set transfer FIRE — on a topic
4
+ * move (the receiver's deliverMessage onAccepted seam), on demand (the
5
+ * reflex route), and on a returning producer (the staggered pending-pull
6
+ * drain).
7
+ *
8
+ * Spec: docs/specs/WORKING-SET-HANDOFF-SPEC.md §3.3 (trigger — receiver-side,
9
+ * epoch-gated, single-flight), §3.4 (durable pending-pull + staggered drain).
10
+ *
11
+ * Discipline (all inherited-invariant applications):
12
+ * - Operation key (topic, epoch): at most one pull scheduled per key,
13
+ * deduped against a DURABLE recent-key window (restart-proof).
14
+ * - Skips: owner !== self (we are not the owner), owner === prevOwner
15
+ * (placing-confirm, no real move), prevOwner === self (nothing to fetch
16
+ * from ourselves).
17
+ * - Single-flight per topic; ownership is rechecked inside the puller
18
+ * before EVERY write (the stillCurrent seam).
19
+ * - Nomination is PLURAL + bounded: every machine the journal (own +
20
+ * replicas) shows as an artifact-producer for the topic, deduped, capped
21
+ * at 3, most-recent-first — NOT "the prior owner". Replicas NOMINATE
22
+ * only; each nominee's LIVE manifest is the authority.
23
+ * - Staggered drain (§3.4): at most `rearmConcurrency` (default 1)
24
+ * topic-pull in flight per returning peer — the EXO shape is ONE machine
25
+ * holding MANY topics' files; N simultaneous pulls would slam a box that
26
+ * just woke.
27
+ * - Load-aware: scheduling defers under host pressure; the pull is always
28
+ * async, NEVER in the message-delivery path.
29
+ */
30
+ import type { CoherenceJournalReader } from './CoherenceJournalReader.js';
31
+ import type { PendingPullLedger } from './PendingPullLedger.js';
32
+ import type { PullReport, WorkingSetPuller } from './WorkingSetPull.js';
33
+ export declare const DEFAULT_REARM_CONCURRENCY = 1;
34
+ export declare const DEFAULT_NOMINEE_CAP = 3;
35
+ /** Durable (topic,epoch) op-key window size — mirrors the journal's DEDUPE_WINDOW. */
36
+ export declare const OPKEY_WINDOW = 200;
37
+ /** Reflex route min interval per topic (rate limit; concurrent calls coalesce). */
38
+ export declare const DEFAULT_REFLEX_MIN_INTERVAL_MS = 30000;
39
+ export interface CoordinatorDeps {
40
+ /** Absolute path to the agent's `.instar/` directory. */
41
+ stateDir: string;
42
+ ownMachineId: string;
43
+ /** Merged own+replica journal reads — NOMINATION ONLY (Signal vs Authority). */
44
+ reader: CoherenceJournalReader;
45
+ ledger: PendingPullLedger;
46
+ /**
47
+ * Build a puller for one nominee peer (resolves its URL + signed client),
48
+ * or null when the peer is unknown/unreachable right now. topic+epoch are
49
+ * provided so the wiring can close the puller's stillCurrent recheck over
50
+ * the SCHEDULED epoch (§3.3 — ownership advanced → abort quietly).
51
+ */
52
+ makePuller: (nomineeMachineId: string, topic: number, epoch: number) => WorkingSetPuller | null;
53
+ /** Live ownership read — the ONLY actuation authority (§3.3). */
54
+ ownerOf: (topic: number) => {
55
+ owner: string | null;
56
+ epoch: number | null;
57
+ };
58
+ /** Host-pressure signal (§3.3 load-aware defer). Default: never. */
59
+ underPressure?: () => boolean;
60
+ rearmConcurrency?: number;
61
+ nomineeCap?: number;
62
+ reflexMinIntervalMs?: number;
63
+ now?: () => Date;
64
+ logger?: (msg: string) => void;
65
+ }
66
+ export interface FetchOutcome {
67
+ topic: number;
68
+ scheduled: boolean;
69
+ /** Why nothing was scheduled (dedupe/skip/pressure) — honest, counted. */
70
+ skipReason?: 'not-owner' | 'opkey-deduped' | 'no-producers' | 'in-flight-coalesced' | 'rate-limited' | 'pressure-deferred' | 'no-epoch';
71
+ /** Per-nominee pull reports (when the pull ran). */
72
+ reports?: {
73
+ nominee: string;
74
+ report: PullReport | null;
75
+ error?: string;
76
+ }[];
77
+ /** Journal-nominated producers that the cap excluded — named, not silent (§3.3). */
78
+ cappedNominees?: string[];
79
+ }
80
+ export declare class WorkingSetPullCoordinator {
81
+ private readonly d;
82
+ private readonly opKeyFile;
83
+ private opKeys;
84
+ /** Single-flight per topic — concurrent triggers coalesce onto one promise. */
85
+ private inFlight;
86
+ /** Per-peer drain gate (staggered re-arm, §3.4). */
87
+ private draining;
88
+ /** Reflex rate limit per topic. */
89
+ private lastReflexAt;
90
+ constructor(deps: CoordinatorDeps);
91
+ /**
92
+ * A forwarded message landed and THIS machine is (about to be) the owner.
93
+ * Fire-and-forget: never blocks message delivery. The epoch is read from
94
+ * the live ownership store; prevOwner evidence comes from the journal's
95
+ * placement history.
96
+ */
97
+ onTopicAccepted(topic: number): void;
98
+ /** The reflex (§3.3): POST /coherence/fetch-working-set — same pipeline, on demand. */
99
+ fetchWorkingSet(topic: number): Promise<FetchOutcome>;
100
+ /**
101
+ * Called when the presence pull records a peer online (every pass — the
102
+ * drain itself dedupes). Re-fires outstanding pending-pulls for that peer
103
+ * as a STAGGERED drain: at most rearmConcurrency in flight, the rest
104
+ * queued behind it most-recent-epoch-first.
105
+ */
106
+ onPeerRecorded(machineId: string): void;
107
+ private drainPeer;
108
+ private trigger;
109
+ private runPull;
110
+ private pullFromNominee;
111
+ /**
112
+ * Every machine the journal (own + replicas) shows as an autonomous-run
113
+ * producer for the topic, excluding self, deduped, most-recent-first,
114
+ * capped. Replicas NOMINATE only — the nominee's live manifest is the
115
+ * authority when the pull runs.
116
+ */
117
+ nominate(topic: number): {
118
+ nominees: string[];
119
+ capped: string[];
120
+ };
121
+ /** Previous owner from the journal's placement history (evidence, not authority). */
122
+ private prevOwnerOf;
123
+ private loadOpKeys;
124
+ private hasOpKey;
125
+ private recordOpKey;
126
+ /**
127
+ * TTL sweep + the run-stopped re-arm (§3.4): live-source records re-fire on
128
+ * a cadence — the pull itself is the live-ness check (a still-live run
129
+ * answers `liveSource` again and the record simply stays, attempt-free).
130
+ * Bounded: only existing live-source records for topics we still own.
131
+ */
132
+ sweep(): Promise<void>;
133
+ }
134
+ //# sourceMappingURL=WorkingSetPullCoordinator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkingSetPullCoordinator.d.ts","sourceRoot":"","sources":["../../src/core/WorkingSetPullCoordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAqB,MAAM,wBAAwB,CAAC;AACnF,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAExE,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAC3C,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,sFAAsF;AACtF,eAAO,MAAM,YAAY,MAAM,CAAC;AAChC,mFAAmF;AACnF,eAAO,MAAM,8BAA8B,QAAS,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,MAAM,EAAE,sBAAsB,CAAC;IAC/B,MAAM,EAAE,iBAAiB,CAAC;IAC1B;;;;;OAKG;IACH,UAAU,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAChG,iEAAiE;IACjE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK;QAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC3E,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,0EAA0E;IAC1E,UAAU,CAAC,EACP,WAAW,GACX,eAAe,GACf,cAAc,GACd,qBAAqB,GACrB,cAAc,GACd,mBAAmB,GACnB,UAAU,CAAC;IACf,oDAAoD;IACpD,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3E,oFAAoF;IACpF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAOD,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAkB;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,MAAM,CAAyB;IACvC,+EAA+E;IAC/E,OAAO,CAAC,QAAQ,CAA4C;IAC5D,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAqB;IACrC,mCAAmC;IACnC,OAAO,CAAC,YAAY,CAA6B;gBAErC,IAAI,EAAE,eAAe;IAOjC;;;;;OAKG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAMpC,uFAAuF;IACjF,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAiB3D;;;;;OAKG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;YAOzB,SAAS;YA+BT,OAAO;YAoCP,OAAO;YAaP,eAAe;IAsC7B;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IAoBjE,qFAAqF;IACrF,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,WAAW;IAgBnB;;;;;OAKG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAiB7B"}
@@ -0,0 +1,306 @@
1
+ /**
2
+ * WorkingSetPullCoordinator — P2.2b of multi-machine coherence: the
3
+ * orchestration layer that makes the working-set transfer FIRE — on a topic
4
+ * move (the receiver's deliverMessage onAccepted seam), on demand (the
5
+ * reflex route), and on a returning producer (the staggered pending-pull
6
+ * drain).
7
+ *
8
+ * Spec: docs/specs/WORKING-SET-HANDOFF-SPEC.md §3.3 (trigger — receiver-side,
9
+ * epoch-gated, single-flight), §3.4 (durable pending-pull + staggered drain).
10
+ *
11
+ * Discipline (all inherited-invariant applications):
12
+ * - Operation key (topic, epoch): at most one pull scheduled per key,
13
+ * deduped against a DURABLE recent-key window (restart-proof).
14
+ * - Skips: owner !== self (we are not the owner), owner === prevOwner
15
+ * (placing-confirm, no real move), prevOwner === self (nothing to fetch
16
+ * from ourselves).
17
+ * - Single-flight per topic; ownership is rechecked inside the puller
18
+ * before EVERY write (the stillCurrent seam).
19
+ * - Nomination is PLURAL + bounded: every machine the journal (own +
20
+ * replicas) shows as an artifact-producer for the topic, deduped, capped
21
+ * at 3, most-recent-first — NOT "the prior owner". Replicas NOMINATE
22
+ * only; each nominee's LIVE manifest is the authority.
23
+ * - Staggered drain (§3.4): at most `rearmConcurrency` (default 1)
24
+ * topic-pull in flight per returning peer — the EXO shape is ONE machine
25
+ * holding MANY topics' files; N simultaneous pulls would slam a box that
26
+ * just woke.
27
+ * - Load-aware: scheduling defers under host pressure; the pull is always
28
+ * async, NEVER in the message-delivery path.
29
+ */
30
+ import fs from 'node:fs';
31
+ import path from 'node:path';
32
+ export const DEFAULT_REARM_CONCURRENCY = 1;
33
+ export const DEFAULT_NOMINEE_CAP = 3;
34
+ /** Durable (topic,epoch) op-key window size — mirrors the journal's DEDUPE_WINDOW. */
35
+ export const OPKEY_WINDOW = 200;
36
+ /** Reflex route min interval per topic (rate limit; concurrent calls coalesce). */
37
+ export const DEFAULT_REFLEX_MIN_INTERVAL_MS = 30_000;
38
+ export class WorkingSetPullCoordinator {
39
+ d;
40
+ opKeyFile;
41
+ opKeys = null;
42
+ /** Single-flight per topic — concurrent triggers coalesce onto one promise. */
43
+ inFlight = new Map();
44
+ /** Per-peer drain gate (staggered re-arm, §3.4). */
45
+ draining = new Set();
46
+ /** Reflex rate limit per topic. */
47
+ lastReflexAt = new Map();
48
+ constructor(deps) {
49
+ this.d = deps;
50
+ this.opKeyFile = path.join(deps.stateDir, 'state', 'coherence-journal', 'pull-opkeys.json');
51
+ }
52
+ // ── The move trigger (§3.3) — called from the onAccepted seam ────────────
53
+ /**
54
+ * A forwarded message landed and THIS machine is (about to be) the owner.
55
+ * Fire-and-forget: never blocks message delivery. The epoch is read from
56
+ * the live ownership store; prevOwner evidence comes from the journal's
57
+ * placement history.
58
+ */
59
+ onTopicAccepted(topic) {
60
+ void this.trigger(topic, 'move').catch((e) => {
61
+ this.d.logger?.(`trigger failed for topic ${topic}: ${e instanceof Error ? e.message : String(e)}`);
62
+ });
63
+ }
64
+ /** The reflex (§3.3): POST /coherence/fetch-working-set — same pipeline, on demand. */
65
+ async fetchWorkingSet(topic) {
66
+ const nowMs = (this.d.now?.() ?? new Date()).getTime();
67
+ const last = this.lastReflexAt.get(topic) ?? 0;
68
+ const inflight = this.inFlight.get(topic);
69
+ if (inflight)
70
+ return inflight; // coalesce into the single-flight pull
71
+ if (nowMs - last < (this.d.reflexMinIntervalMs ?? DEFAULT_REFLEX_MIN_INTERVAL_MS)) {
72
+ return { topic, scheduled: false, skipReason: 'rate-limited' };
73
+ }
74
+ this.lastReflexAt.set(topic, nowMs);
75
+ // The reflex bypasses the (topic,epoch) op-key dedupe (an explicit ask
76
+ // re-fetches even when the move already pulled) but keeps every other
77
+ // gate — ownership, single-flight, nomination bounds.
78
+ return this.trigger(topic, 'reflex');
79
+ }
80
+ // ── The returning-peer drain (§3.4) ───────────────────────────────────────
81
+ /**
82
+ * Called when the presence pull records a peer online (every pass — the
83
+ * drain itself dedupes). Re-fires outstanding pending-pulls for that peer
84
+ * as a STAGGERED drain: at most rearmConcurrency in flight, the rest
85
+ * queued behind it most-recent-epoch-first.
86
+ */
87
+ onPeerRecorded(machineId) {
88
+ if (this.draining.has(machineId))
89
+ return; // a drain is already running
90
+ void this.drainPeer(machineId).catch((e) => {
91
+ this.d.logger?.(`drain failed for ${machineId}: ${e instanceof Error ? e.message : String(e)}`);
92
+ });
93
+ }
94
+ async drainPeer(machineId) {
95
+ const pending = await this.d.ledger.pendingForPeer(machineId);
96
+ if (!pending.length)
97
+ return;
98
+ this.draining.add(machineId);
99
+ try {
100
+ // Sequential (rearmConcurrency 1) most-recent-epoch-first — pendingForPeer
101
+ // pre-sorts. A >1 setting would batch; the default stays single-file.
102
+ for (const rec of pending) {
103
+ // Live-source records re-arm only when the producer's run has stopped —
104
+ // checked against the nominee's LIVE manifest by the pull itself (a
105
+ // still-live run answers liveSource and the record stays).
106
+ const { owner, epoch } = this.d.ownerOf(rec.topic);
107
+ if (owner !== this.d.ownMachineId) {
108
+ // We no longer own the topic — the current owner's own pull covers
109
+ // truth; clear our stale record.
110
+ await this.d.ledger.clear(rec.topic, rec.epoch, rec.nominee);
111
+ continue;
112
+ }
113
+ if (epoch != null && epoch > rec.epoch) {
114
+ await this.d.ledger.supersede(rec.topic, epoch);
115
+ continue;
116
+ }
117
+ await this.pullFromNominee(rec.topic, rec.epoch ?? 0, rec.nominee);
118
+ }
119
+ }
120
+ finally {
121
+ this.draining.delete(machineId);
122
+ }
123
+ }
124
+ // ── The shared pipeline ────────────────────────────────────────────────────
125
+ async trigger(topic, source) {
126
+ const existing = this.inFlight.get(topic);
127
+ if (existing)
128
+ return existing; // single-flight per topic (§3.3)
129
+ const { owner, epoch } = this.d.ownerOf(topic);
130
+ if (owner !== this.d.ownMachineId)
131
+ return { topic, scheduled: false, skipReason: 'not-owner' };
132
+ if (epoch == null)
133
+ return { topic, scheduled: false, skipReason: 'no-epoch' };
134
+ if (source === 'move') {
135
+ // Durable (topic,epoch) op-key dedupe — restart-proof (§3.3).
136
+ const key = `${topic}:${epoch}`;
137
+ if (this.hasOpKey(key))
138
+ return { topic, scheduled: false, skipReason: 'opkey-deduped' };
139
+ // Skip placing-confirms + self-moves via journal placement evidence.
140
+ const prevOwner = this.prevOwnerOf(topic, epoch);
141
+ if (prevOwner === this.d.ownMachineId) {
142
+ this.recordOpKey(key);
143
+ return { topic, scheduled: false, skipReason: 'no-producers' };
144
+ }
145
+ if (this.d.underPressure?.()) {
146
+ // Deferred, not dropped: file a pending-pull per nominee below would
147
+ // need nomination; the cheap honest defer is to leave the op-key
148
+ // unrecorded so the next accept (or the reflex) re-triggers.
149
+ return { topic, scheduled: false, skipReason: 'pressure-deferred' };
150
+ }
151
+ this.recordOpKey(key);
152
+ }
153
+ const run = this.runPull(topic, epoch);
154
+ this.inFlight.set(topic, run);
155
+ try {
156
+ return await run;
157
+ }
158
+ finally {
159
+ this.inFlight.delete(topic);
160
+ }
161
+ }
162
+ async runPull(topic, epoch) {
163
+ const { nominees, capped } = this.nominate(topic);
164
+ if (!nominees.length) {
165
+ return { topic, scheduled: false, skipReason: 'no-producers', ...(capped.length ? { cappedNominees: capped } : {}) };
166
+ }
167
+ const reports = [];
168
+ for (const nominee of nominees) {
169
+ const r = await this.pullFromNominee(topic, epoch, nominee);
170
+ reports.push(r);
171
+ }
172
+ return { topic, scheduled: true, reports, ...(capped.length ? { cappedNominees: capped } : {}) };
173
+ }
174
+ async pullFromNominee(topic, epoch, nominee) {
175
+ const puller = this.d.makePuller(nominee, topic, epoch);
176
+ if (!puller) {
177
+ await this.d.ledger.file_({ topic, epoch, nominee, reason: 'peer-unreachable' });
178
+ await this.d.ledger.recordAttempt(topic, epoch, nominee);
179
+ return { nominee, report: null, error: 'peer unreachable' };
180
+ }
181
+ try {
182
+ const report = await puller.pullTopic(topic);
183
+ if (report.needsPendingPull) {
184
+ // liveSource / busyExhausted / transport — durable record, re-fired
185
+ // on reappearance or run-stopped. busy does NOT consume an attempt.
186
+ const reason = report.files.some((f) => f.outcome === 'liveSourceDeferred')
187
+ ? 'live-source'
188
+ : report.files.some((f) => f.outcome === 'busyExhausted')
189
+ ? 'busy-exhausted'
190
+ : 'peer-unreachable';
191
+ await this.d.ledger.file_({ topic, epoch, nominee, reason });
192
+ if (reason === 'peer-unreachable') {
193
+ await this.d.ledger.recordAttempt(topic, epoch, nominee); // genuine failure only
194
+ }
195
+ }
196
+ else {
197
+ await this.d.ledger.clear(topic, epoch, nominee);
198
+ }
199
+ return { nominee, report };
200
+ }
201
+ catch (e) {
202
+ await this.d.ledger.file_({ topic, epoch, nominee, reason: 'peer-unreachable' });
203
+ await this.d.ledger.recordAttempt(topic, epoch, nominee);
204
+ return { nominee, report: null, error: e instanceof Error ? e.message : String(e) };
205
+ }
206
+ }
207
+ // ── Nomination (§3.3 — plural, bounded, journal-evidenced) ────────────────
208
+ /**
209
+ * Every machine the journal (own + replicas) shows as an autonomous-run
210
+ * producer for the topic, excluding self, deduped, most-recent-first,
211
+ * capped. Replicas NOMINATE only — the nominee's live manifest is the
212
+ * authority when the pull runs.
213
+ */
214
+ nominate(topic) {
215
+ const cap = this.d.nomineeCap ?? DEFAULT_NOMINEE_CAP;
216
+ let entries;
217
+ try {
218
+ entries = this.d.reader.query({ kind: 'autonomous-run', topic, limit: 100 }).entries;
219
+ }
220
+ catch (e) {
221
+ this.d.logger?.(`nomination read failed for topic ${topic}: ${e instanceof Error ? e.message : String(e)}`);
222
+ return { nominees: [], capped: [] };
223
+ }
224
+ const seen = new Set();
225
+ const ordered = [];
226
+ for (const e of entries) {
227
+ // newest-first already (reader merge order)
228
+ if (e.machine === this.d.ownMachineId || seen.has(e.machine))
229
+ continue;
230
+ seen.add(e.machine);
231
+ ordered.push(e.machine);
232
+ }
233
+ return { nominees: ordered.slice(0, cap), capped: ordered.slice(cap) };
234
+ }
235
+ /** Previous owner from the journal's placement history (evidence, not authority). */
236
+ prevOwnerOf(topic, epoch) {
237
+ try {
238
+ const entries = this.d.reader.query({ kind: 'topic-placement', topic, limit: 20 }).entries;
239
+ for (const e of entries) {
240
+ const data = e.data;
241
+ if (data.epoch === epoch && typeof data.prevOwner === 'string')
242
+ return data.prevOwner;
243
+ }
244
+ }
245
+ catch { /* @silent-fallback-ok: missing placement evidence means no prevOwner skip — the pull proceeds and the manifest decides (WORKING-SET-HANDOFF-SPEC §3.3) */
246
+ }
247
+ return null;
248
+ }
249
+ // ── Durable (topic,epoch) op-key window (§3.3 — restart-proof) ────────────
250
+ loadOpKeys() {
251
+ if (this.opKeys)
252
+ return this.opKeys;
253
+ try {
254
+ const parsed = JSON.parse(fs.readFileSync(this.opKeyFile, 'utf-8'));
255
+ this.opKeys = Array.isArray(parsed?.keys) ? parsed.keys.filter((k) => typeof k === 'string') : [];
256
+ }
257
+ catch { /* @silent-fallback-ok: an absent/corrupt op-key window only weakens dedupe for one pull (re-pull is idempotent via skippedExisting) — never a failure (WORKING-SET-HANDOFF-SPEC §3.3) */
258
+ this.opKeys = [];
259
+ }
260
+ return this.opKeys;
261
+ }
262
+ hasOpKey(key) {
263
+ return this.loadOpKeys().includes(key);
264
+ }
265
+ recordOpKey(key) {
266
+ const keys = this.loadOpKeys();
267
+ keys.push(key);
268
+ while (keys.length > OPKEY_WINDOW)
269
+ keys.shift();
270
+ try {
271
+ fs.mkdirSync(path.dirname(this.opKeyFile), { recursive: true });
272
+ const tmp = `${this.opKeyFile}.tmp-${process.pid}`;
273
+ fs.writeFileSync(tmp, JSON.stringify({ version: 1, keys }));
274
+ fs.renameSync(tmp, this.opKeyFile);
275
+ }
276
+ catch (e) { /* @silent-fallback-ok: a failed op-key persist only weakens dedupe across a restart (re-pull is idempotent); logged, never thrown (WORKING-SET-HANDOFF-SPEC §3.3) */
277
+ this.d.logger?.(`op-key persist failed: ${e instanceof Error ? e.message : String(e)}`);
278
+ }
279
+ }
280
+ // ── The slow tick (the server calls this every ~10 min) ───────────────────
281
+ /**
282
+ * TTL sweep + the run-stopped re-arm (§3.4): live-source records re-fire on
283
+ * a cadence — the pull itself is the live-ness check (a still-live run
284
+ * answers `liveSource` again and the record simply stays, attempt-free).
285
+ * Bounded: only existing live-source records for topics we still own.
286
+ */
287
+ async sweep() {
288
+ await this.d.ledger.sweepExpired();
289
+ const all = await this.d.ledger.all();
290
+ for (const rec of all) {
291
+ if (rec.reason !== 'live-source')
292
+ continue;
293
+ const { owner, epoch } = this.d.ownerOf(rec.topic);
294
+ if (owner !== this.d.ownMachineId) {
295
+ await this.d.ledger.clear(rec.topic, rec.epoch, rec.nominee);
296
+ continue;
297
+ }
298
+ if (epoch != null && epoch > rec.epoch) {
299
+ await this.d.ledger.supersede(rec.topic, epoch);
300
+ continue;
301
+ }
302
+ await this.pullFromNominee(rec.topic, rec.epoch, rec.nominee);
303
+ }
304
+ }
305
+ }
306
+ //# sourceMappingURL=WorkingSetPullCoordinator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkingSetPullCoordinator.js","sourceRoot":"","sources":["../../src/core/WorkingSetPullCoordinator.ts"],"names":[],"mappings":"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"}
@@ -1795,11 +1795,36 @@ export interface CoherenceJournalUserConfig {
1795
1795
  flushIntervalMs?: number;
1796
1796
  /** Autonomous-run journal scanner cadence (§3.3). Default 60s. */
1797
1797
  scannerIntervalMs?: number;
1798
- /** Replication tunables; `enabled` follows the same dark-ship gate. */
1798
+ /**
1799
+ * Replication tunables. NOTE: replication SEND/drive requires the EXPLICIT
1800
+ * `enabled === true` (never the `?? developmentAgent` dark-ship gate) — and
1801
+ * the working-set feature below activates IFF this same gate is on
1802
+ * (WORKING-SET-HANDOFF-SPEC §3.7: the pull is meaningless without
1803
+ * replication's mesh path and must never out-activate it).
1804
+ */
1799
1805
  replication?: {
1800
1806
  enabled?: boolean;
1801
1807
  maxBatchBytes?: number;
1802
1808
  };
1809
+ /**
1810
+ * Working-Set Handoff tunables (WORKING-SET-HANDOFF-SPEC §3.7). All
1811
+ * optional; ConfigDefaults carries the shipped literal. Gated on
1812
+ * `replication.enabled === true` — there is no separate enable flag.
1813
+ */
1814
+ workingSet?: {
1815
+ maxFileBytes?: number;
1816
+ headlineFileBytes?: number;
1817
+ maxFiles?: number;
1818
+ maxTotalBytes?: number;
1819
+ pullMaxBatchBytes?: number;
1820
+ pullOnMove?: boolean;
1821
+ pendingPullTtlDays?: number;
1822
+ chunkRestartCap?: number;
1823
+ chunksPerTick?: number;
1824
+ serveConcurrency?: number;
1825
+ rearmConcurrency?: number;
1826
+ busyRetryCap?: number;
1827
+ };
1803
1828
  /**
1804
1829
  * Per-kind retention. rotateKeep N>0 = rotate at maxFileBytes, keep N
1805
1830
  * archives, delete older; 0 = rotate at maxFileBytes but NEVER delete
@@ -3520,6 +3545,23 @@ export interface MonitoringConfig {
3520
3545
  /** Master kill switch (default: false). Gates the observe-only check entirely. */
3521
3546
  enabled: boolean;
3522
3547
  };
3548
+ /**
3549
+ * Phase-2 LLM judge for ORG-INTENT governance verdicts (CMT-1128). When
3550
+ * enabled AND an intelligence provider is configured, a keyword-heuristic
3551
+ * MISS on POST /intent/org/test-action escalates to one bounded LLM call
3552
+ * that judges the action against the constraints by MEANING — closing the
3553
+ * keyword matcher's false-negative side (semantically-related constraints
3554
+ * whose wording differs). Verdicts carry their method ('llm-judge' only for
3555
+ * a real, parsed LLM verdict; judge problems keep the heuristic verdict and
3556
+ * say so). Signal-only — the route answers a question, never blocks. Ships
3557
+ * DARK (default false).
3558
+ */
3559
+ orgIntentLlmJudge?: {
3560
+ /** Master kill switch (default: false). */
3561
+ enabled: boolean;
3562
+ /** Per-judge-call timeout in ms (default: 8000). */
3563
+ timeoutMs?: number;
3564
+ };
3523
3565
  /**
3524
3566
  * ApprenticeshipCycleSlaMonitor — observe-only signal for open apprenticeship
3525
3567
  * differential cycles older than the configured SLA. Ships OFF; when enabled