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.
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +200 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +18 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/IntentTestHarness.d.ts +27 -0
- package/dist/core/IntentTestHarness.d.ts.map +1 -1
- package/dist/core/IntentTestHarness.js +91 -0
- package/dist/core/IntentTestHarness.js.map +1 -1
- package/dist/core/MeshRpc.d.ts +8 -0
- package/dist/core/MeshRpc.d.ts.map +1 -1
- package/dist/core/MeshRpc.js +6 -1
- package/dist/core/MeshRpc.js.map +1 -1
- package/dist/core/PeerPresencePuller.d.ts +6 -0
- package/dist/core/PeerPresencePuller.d.ts.map +1 -1
- package/dist/core/PeerPresencePuller.js +5 -0
- package/dist/core/PeerPresencePuller.js.map +1 -1
- package/dist/core/PeerVisibilityGuard.d.ts +83 -0
- package/dist/core/PeerVisibilityGuard.d.ts.map +1 -0
- package/dist/core/PeerVisibilityGuard.js +204 -0
- package/dist/core/PeerVisibilityGuard.js.map +1 -0
- package/dist/core/PendingPullLedger.d.ts +129 -0
- package/dist/core/PendingPullLedger.d.ts.map +1 -0
- package/dist/core/PendingPullLedger.js +239 -0
- package/dist/core/PendingPullLedger.js.map +1 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +20 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/WorkingSetManifest.d.ts +2 -0
- package/dist/core/WorkingSetManifest.d.ts.map +1 -1
- package/dist/core/WorkingSetManifest.js +13 -1
- package/dist/core/WorkingSetManifest.js.map +1 -1
- package/dist/core/WorkingSetPull.d.ts +157 -0
- package/dist/core/WorkingSetPull.d.ts.map +1 -0
- package/dist/core/WorkingSetPull.js +546 -0
- package/dist/core/WorkingSetPull.js.map +1 -0
- package/dist/core/WorkingSetPullCoordinator.d.ts +134 -0
- package/dist/core/WorkingSetPullCoordinator.d.ts.map +1 -0
- package/dist/core/WorkingSetPullCoordinator.js +306 -0
- package/dist/core/WorkingSetPullCoordinator.js.map +1 -0
- package/dist/core/types.d.ts +43 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/redteam/ScenarioPack.d.ts +30 -3
- package/dist/redteam/ScenarioPack.d.ts.map +1 -1
- package/dist/redteam/ScenarioPack.js +46 -1
- package/dist/redteam/ScenarioPack.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +4 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +3 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +1 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +5 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +47 -1
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +64 -64
- package/src/data/state-coherence-registry.json +48 -12
- package/src/scaffold/templates.ts +4 -0
- package/upgrades/{1.3.365.md → 1.3.366.md} +35 -0
- package/upgrades/1.3.367.md +134 -0
- package/upgrades/side-effects/intent-llm-judge.md +94 -0
- package/upgrades/side-effects/working-set-ci-absorb.md +29 -0
- package/upgrades/side-effects/working-set-parity-absorb.md +35 -0
- package/upgrades/side-effects/working-set-pull-p22a.md +121 -0
- 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":"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"}
|
|
@@ -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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAM7B,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAC3C,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AACrC,sFAAsF;AACtF,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAC;AAChC,mFAAmF;AACnF,MAAM,CAAC,MAAM,8BAA8B,GAAG,MAAM,CAAC;AAkDrD,MAAM,OAAO,yBAAyB;IACnB,CAAC,CAAkB;IACnB,SAAS,CAAS;IAC3B,MAAM,GAAoB,IAAI,CAAC;IACvC,+EAA+E;IACvE,QAAQ,GAAG,IAAI,GAAG,EAAiC,CAAC;IAC5D,oDAAoD;IAC5C,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,mCAAmC;IAC3B,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEjD,YAAY,IAAqB;QAC/B,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;QACd,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,CAAC,CAAC;IAC9F,CAAC;IAED,4EAA4E;IAE5E;;;;;OAKG;IACH,eAAe,CAAC,KAAa;QAC3B,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;YAC3C,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,4BAA4B,KAAK,KAAK,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACtG,CAAC,CAAC,CAAC;IACL,CAAC;IAED,uFAAuF;IACvF,KAAK,CAAC,eAAe,CAAC,KAAa;QACjC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;QACvD,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC,CAAC,uCAAuC;QACtE,IAAI,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,IAAI,8BAA8B,CAAC,EAAE,CAAC;YAClF,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;QACjE,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACpC,uEAAuE;QACvE,sEAAsE;QACtE,sDAAsD;QACtD,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAC;IAED,6EAA6E;IAE7E;;;;;OAKG;IACH,cAAc,CAAC,SAAiB;QAC9B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,OAAO,CAAC,6BAA6B;QACvE,KAAK,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;YACzC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,oBAAoB,SAAS,KAAK,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAClG,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,SAAiB;QACvC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QAC9D,IAAI,CAAC,OAAO,CAAC,MAAM;YAAE,OAAO;QAC5B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7B,IAAI,CAAC;YACH,2EAA2E;YAC3E,sEAAsE;YACtE,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;gBAC1B,wEAAwE;gBACxE,oEAAoE;gBACpE,2DAA2D;gBAC3D,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACnD,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;oBAClC,mEAAmE;oBACnE,iCAAiC;oBACjC,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;oBAC7D,SAAS;gBACX,CAAC;gBACD,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;oBACvC,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;oBAChD,SAAS;gBACX,CAAC;gBACD,MAAM,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;YACrE,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED,8EAA8E;IAEtE,KAAK,CAAC,OAAO,CAAC,KAAa,EAAE,MAAyB;QAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC,CAAC,iCAAiC;QAEhE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC/C,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY;YAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;QAC/F,IAAI,KAAK,IAAI,IAAI;YAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;QAE9E,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,8DAA8D;YAC9D,MAAM,GAAG,GAAG,GAAG,KAAK,IAAI,KAAK,EAAE,CAAC;YAChC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC;YACxF,qEAAqE;YACrE,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YACjD,IAAI,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;gBACtC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;gBACtB,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;YACjE,CAAC;YACD,IAAI,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,EAAE,EAAE,CAAC;gBAC7B,qEAAqE;gBACrE,iEAAiE;gBACjE,6DAA6D;gBAC7D,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,CAAC;YACtE,CAAC;YACD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC;YACH,OAAO,MAAM,GAAG,CAAC;QACnB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,KAAa,EAAE,KAAa;QAChD,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACrB,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACvH,CAAC;QACD,MAAM,OAAO,GAAqE,EAAE,CAAC;QACrF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACnG,CAAC;IAEO,KAAK,CAAC,eAAe,CAC3B,KAAa,EACb,KAAa,EACb,OAAe;QAEf,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QACxD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;YACjF,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YACzD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC;QAC9D,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAC7C,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;gBAC5B,oEAAoE;gBACpE,oEAAoE;gBACpE,MAAM,MAAM,GAAsB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,oBAAoB,CAAC;oBAC5F,CAAC,CAAC,aAAa;oBACf,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,eAAe,CAAC;wBACvD,CAAC,CAAC,gBAAgB;wBAClB,CAAC,CAAC,kBAAkB,CAAC;gBACzB,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC7D,IAAI,MAAM,KAAK,kBAAkB,EAAE,CAAC;oBAClC,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,uBAAuB;gBACnF,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YACnD,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAC7B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;YACjF,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YACzD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,CAAC;IACH,CAAC;IAED,6EAA6E;IAE7E;;;;;OAKG;IACH,QAAQ,CAAC,KAAa;QACpB,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,IAAI,mBAAmB,CAAC;QACrD,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC;QACvF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,oCAAoC,KAAK,KAAK,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC5G,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACtC,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,4CAA4C;YAC5C,IAAI,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;gBAAE,SAAS;YACvE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IACzE,CAAC;IAED,qFAAqF;IAC7E,WAAW,CAAC,KAAa,EAAE,KAAa;QAC9C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC;YAC3F,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;gBACxB,MAAM,IAAI,GAAG,CAAC,CAAC,IAA8C,CAAC;gBAC9D,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ;oBAAE,OAAO,IAAI,CAAC,SAAS,CAAC;YACxF,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,0JAA0J;QACpK,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,6EAA6E;IAErE,UAAU;QAChB,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC,MAAM,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAmB,CAAC;YACtF,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpG,CAAC;QAAC,MAAM,CAAC,CAAC,yLAAyL;YACjM,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACnB,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAEO,QAAQ,CAAC,GAAW;QAC1B,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC;IAEO,WAAW,CAAC,GAAW;QAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACf,OAAO,IAAI,CAAC,MAAM,GAAG,YAAY;YAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAChD,IAAI,CAAC;YACH,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAChE,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,SAAS,QAAQ,OAAO,CAAC,GAAG,EAAE,CAAC;YACnD,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAA2B,CAAC,CAAC,CAAC;YACrF,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC,CAAC,qKAAqK;YACjL,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,0BAA0B,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1F,CAAC;IACH,CAAC;IAED,6EAA6E;IAE7E;;;;;OAKG;IACH,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QACtC,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;YACtB,IAAI,GAAG,CAAC,MAAM,KAAK,aAAa;gBAAE,SAAS;YAC3C,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACnD,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;gBAClC,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC7D,SAAS;YACX,CAAC;YACD,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;gBACvC,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;gBAChD,SAAS;YACX,CAAC;YACD,MAAM,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;CACF"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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
|